From 90ad58f17feec67ea4a50c859ba472e94ef8a595 Mon Sep 17 00:00:00 2001 From: Diego Armando de Freitas Matos Date: Wed, 6 Mar 2019 21:55:47 -0300 Subject: [PATCH 1/2] CPQ 1 CPQ 2 CASAMENTO --- scripts/npc/1012112.js | 232 +- scripts/npc/1012113.js | 118 +- scripts/npc/2042000.js | 290 +- scripts/npc/2042002.js | 508 +- scripts/npc/2042003.js | 30 + scripts/npc/2042004.js | 16 + scripts/npc/2042005.js | 83 + scripts/npc/2042007.js | 132 + scripts/npc/2042008.js | 30 + scripts/npc/2042009.js | 30 + scripts/npc/9201002.js | 185 +- scripts/npc/9201006.js | 3 +- scripts/npc/9201014.js | 68 +- scripts/npc/cpqchallenge.js | 54 + scripts/npc/cpqchallenge2.js | 48 + scripts/portal/MC2revive.js | 8 + scripts/portal/MCRevive1.js | 10 + scripts/portal/MCRevive2.js | 10 + scripts/portal/MCRevive3.js | 19 + scripts/portal/MCRevive4.js | 19 + scripts/portal/MCRevive5.js | 10 + scripts/portal/MCRevive6.js | 10 + scripts/portal/mc_out.js | 47 +- scripts/reactor/9980000.js | 27 +- scripts/reactor/9980001.js | 27 +- src/client/MapleCharacter.java | 3360 ++-- src/client/MapleClient.java | 2827 +-- src/client/MapleDisease.java | 48 +- .../command/commands/gm5/DebugCommand.java | 1 + src/constants/LinguaConstants.java | 74 + src/constants/ServerConstants.java | 4 +- .../channel/handlers/ChangeMapHandler.java | 279 +- .../handlers/MonsterCarnivalHandler.java | 335 +- .../channel/handlers/RingActionHandler.java | 22 +- .../channel/handlers/WeddingHandler.java | 107 +- src/net/server/world/MapleParty.java | 142 +- src/net/server/world/MaplePartyCharacter.java | 96 + src/scripting/AbstractPlayerInteraction.java | 1994 +- src/scripting/event/EventScriptManager.java | 53 +- .../event/worker/EventScriptScheduler.java | 99 +- src/scripting/item/ItemScriptMethods.java | 35 + src/scripting/npc/NPCConversationManager.java | 1352 +- src/scripting/npc/NPCScriptManager.java | 73 +- .../reactor/ReactorActionManager.java | 18 + src/server/MapleStatEffect.java | 366 +- src/server/life/MapleMonster.java | 704 +- .../life/MapleMonsterInformationProvider.java | 580 +- src/server/life/MobSkill.java | 199 +- src/server/maps/MapleMap.java | 1395 +- src/server/maps/MapleMapFactory.java | 115 +- src/server/maps/MapleReactor.java | 131 +- src/server/maps/MapleReactorFactory.java | 55 + src/server/maps/MapleReactorStats.java | 7 + src/server/maps/SavedLocationType.java | 1 + src/server/partyquest/GuardianSpawnPoint.java | 43 + .../partyquest/MapleCarnivalFactory.java | 76 + src/server/partyquest/MonsterCarnival.java | 617 +- src/tools/MaplePacketCreator.java | 15304 ++++++++-------- .../output/GenericLittleEndianWriter.java | 2 +- src/tools/packets/Wedding.java | 56 +- 60 files changed, 17442 insertions(+), 15142 deletions(-) create mode 100644 scripts/npc/2042003.js create mode 100644 scripts/npc/2042004.js create mode 100644 scripts/npc/2042005.js create mode 100644 scripts/npc/2042007.js create mode 100644 scripts/npc/2042008.js create mode 100644 scripts/npc/2042009.js create mode 100644 scripts/npc/cpqchallenge.js create mode 100644 scripts/npc/cpqchallenge2.js create mode 100644 scripts/portal/MC2revive.js create mode 100644 scripts/portal/MCRevive1.js create mode 100644 scripts/portal/MCRevive2.js create mode 100644 scripts/portal/MCRevive3.js create mode 100644 scripts/portal/MCRevive4.js create mode 100644 scripts/portal/MCRevive5.js create mode 100644 scripts/portal/MCRevive6.js create mode 100644 src/constants/LinguaConstants.java create mode 100644 src/scripting/item/ItemScriptMethods.java create mode 100644 src/server/partyquest/GuardianSpawnPoint.java create mode 100644 src/server/partyquest/MapleCarnivalFactory.java diff --git a/scripts/npc/1012112.js b/scripts/npc/1012112.js index 0ebfe39966..ca0f753f7e 100644 --- a/scripts/npc/1012112.js +++ b/scripts/npc/1012112.js @@ -1,24 +1,24 @@ /* - 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 . -*/ + This file is part of the OdinMS Maple Story Server + Copyright (C) 2008 Patrick Huy + Matthias Butz + Jan Christian Meyer + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ /** * @author BubblesDev * @author Ronan @@ -29,104 +29,104 @@ var status = 0; var em = null; function start() { - status = -1; - action(1, 0, 0); + status = -1; + action(1, 0, 0); } function action(mode, type, selection) { - if (mode == -1) { - cm.dispose(); - } else { - if (mode == 0 && status == 0) { - cm.dispose(); - return; - } - if (mode == 1) - status++; - else - status--; - - if(cm.getMapId() == 100000200) { - if (status == 0) { - em = cm.getEventManager("HenesysPQ"); - if(em == null) { - cm.sendOk("The Henesys PQ has encountered an error."); - cm.dispose(); - return; - } else if(cm.isUsingOldPqNpcStyle()) { - action(1, 0, 0); - return; - } - - cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nI'm Tory. Inside here is a beautiful hill where the primrose blooms. There's a tiger that lives in the hill, Growlie, and he seems to be looking for something to eat. Would you like to head over to the hill of primrose and join forces with your party members to help Growlie out?#b\r\n#L0#I want to participate in the party quest.\r\n#L1#I want to find party members.\r\n#L2#I would like to hear more details.\r\n#L3#I would like to redeem an instance hat."); - } else if (status == 1) { - if (selection == 0) { - if (cm.getParty() == null) { - cm.sendOk("Hi there! I'm Tory. This place is covered with mysterious aura of the full moon, and no one person can enter here by him/herself."); - cm.dispose(); - } else if(!cm.isLeader()) { - cm.sendOk("If you'd like to enter here, the leader of your party will have to talk to me. Talk to your party leader about this."); - cm.dispose(); - } else { - var eli = em.getEligibleParty(cm.getParty()); - if(eli.size() > 0) { - if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) { - cm.sendOk("Someone is already attempting the PQ. Please wait for them to finish, or find another channel."); - } - } - else { - cm.sendOk("You cannot start this party quest yet, because either your party is not in the range size, some of your party members are not eligible to attempt it or they are not in this map. If you're having trouble finding party members, try Party Search."); - } - - cm.dispose(); - } - } else if (selection == 1) { - cm.sendOk("Try using a Super Megaphone or asking your buddies or guild to join!"); - cm.dispose(); - } else if (selection == 2) { - cm.sendOk("#e#b#k#n\r\nCollect primrose seeds from the flowers at the bottom part of the map and drop them by the platforms above the stage. Primrose seed color must match to grow the seeds, so test until you find the correct combination. When all the seeds have been planted, that is, starting second part of the mission, scout the Moon Bunny while it prepares Rice Cakes for the hungry Growlie. Once Growlie becomes satisfied, your mission is complete."); - cm.dispose(); - } else { - cm.sendYesNo("So you want to exchange #b20 #b#t4001158##k for the instance-designed hat?"); - } - } else { - if(cm.hasItem(4001158, 20)) { - if(cm.canHold(1002798)) { - cm.gainItem(4001158, -20); - cm.gainItem(1002798, 20); - cm.sendNext("Here it is. Enjoy!"); - } - } else { - cm.sendNext("You don't have enough #t4001158# to buy it yet!"); - } - - cm.dispose(); - } - } else if (cm.getMapId() == 910010100) { - if (status == 0) { - cm.sendYesNo("Thank you for aiding in the effort of feeding the Growlie. As a matter of fact, your team has already been rewarded for reaching this far. With this problem now solved, there is another issue happening right now, if you are interessed check #bTommy#k there for the info. So, are you returning straight to Henesys now?"); - } else if (status == 1) { - if(cm.getEventInstance().giveEventReward(cm.getPlayer())) { - cm.warp(100000200); - } - else { - cm.sendOk("It seems you are short on space in one of your inventories. Please check that first to get rewarded properly."); - } - cm.dispose(); - } - } else if (cm.getMapId() == 910010400) { - if (status == 0) { - cm.sendYesNo("So, are you returning to Henesys now?"); - } else if (status == 1) { - if(cm.getEventInstance() == null) { - cm.warp(100000200); - } else if(cm.getEventInstance().giveEventReward(cm.getPlayer())) { - cm.warp(100000200); - } else { - cm.sendOk("It seems you are short on space in one of your inventories. Please check that first to get rewarded properly."); - } - cm.dispose(); - } - } + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 0 && status == 0) { + cm.dispose(); + return; } + if (mode == 1) + status++; + else + status--; + + if (cm.getMapId() == 100000200) { + if (status == 0) { + em = cm.getEventManager("HenesysPQ"); + if (em == null) { + cm.sendOk("The Henesys PQ has encountered an error."); + cm.dispose(); + return; + } else if (cm.isUsingOldPqNpcStyle()) { + action(1, 0, 0); + return; + } + + cm.sendSimple("#e#b\r\n#k#n" + em.getProperty("party") + "\r\n\r\nI'm Tory. Inside here is a beautiful hill where the primrose blooms. There's a tiger that lives in the hill, Growlie, and he seems to be looking for something to eat. Would you like to head over to the hill of primrose and join forces with your party members to help Growlie out?#b\r\n#L0#I want to participate in the party quest.\r\n#L1#I want to find party members.\r\n#L2#I would like to hear more details.\r\n#L3#I would like to redeem an instance hat."); + } else if (status == 1) { + if (selection == 0) { + if (cm.getParty() == null) { + cm.sendOk("Hi there! I'm Tory. This place is covered with mysterious aura of the full moon, and no one person can enter here by him/herself."); + cm.dispose(); + } else if (!cm.isLeader()) { + cm.sendOk("If you'd like to enter here, the leader of your party will have to talk to me. Talk to your party leader about this."); + cm.dispose(); + } else { + var eli = em.getEligibleParty(cm.getParty()); + if (eli.size() > 0) { + if (!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) { + cm.sendOk("Someone is already attempting the PQ. Please wait for them to finish, or find another channel."); + } + } + else { + cm.sendOk("You cannot start this party quest yet, because either your party is not in the range size, some of your party members are not eligible to attempt it or they are not in this map. If you're having trouble finding party members, try Party Search."); + } + + cm.dispose(); + } + } else if (selection == 1) { + cm.sendOk("Try using a Super Megaphone or asking your buddies or guild to join!"); + cm.dispose(); + } else if (selection == 2) { + cm.sendOk("#e#b#k#n\r\nCollect primrose seeds from the flowers at the bottom part of the map and drop them by the platforms above the stage. Primrose seed color must match to grow the seeds, so test until you find the correct combination. When all the seeds have been planted, that is, starting second part of the mission, scout the Moon Bunny while it prepares Rice Cakes for the hungry Growlie. Once Growlie becomes satisfied, your mission is complete."); + cm.dispose(); + } else { + cm.sendYesNo("So you want to exchange #b20 #b#t4001158##k for the instance-designed hat?"); + } + } else { + if (cm.hasItem(4001158, 20)) { + if (cm.canHold(1002798)) { + cm.gainItem(4001158, -20); + cm.gainItem(1002798, 20); + cm.sendNext("Here it is. Enjoy!"); + } + } else { + cm.sendNext("You don't have enough #t4001158# to buy it yet!"); + } + + cm.dispose(); + } + } else if (cm.getMapId() == 910010100) { + if (status == 0) { + cm.sendYesNo("Thank you for aiding in the effort of feeding the Growlie. As a matter of fact, your team has already been rewarded for reaching this far. With this problem now solved, there is another issue happening right now, if you are interessed check #bTommy#k there for the info. So, are you returning straight to Henesys now?"); + } else if (status == 1) { + if (cm.getEventInstance().giveEventReward(cm.getPlayer())) { + cm.warp(100000200); + } + else { + cm.sendOk("It seems you are short on space in one of your inventories. Please check that first to get rewarded properly."); + } + cm.dispose(); + } + } else if (cm.getMapId() == 910010400) { + if (status == 0) { + cm.sendYesNo("So, are you returning to Henesys now?"); + } else if (status == 1) { + if (cm.getEventInstance() == null) { + cm.warp(100000200); + } else if (cm.getEventInstance().giveEventReward(cm.getPlayer())) { + cm.warp(100000200); + } else { + cm.sendOk("It seems you are short on space in one of your inventories. Please check that first to get rewarded properly."); + } + cm.dispose(); + } + } + } } \ No newline at end of file diff --git a/scripts/npc/1012113.js b/scripts/npc/1012113.js index 542f6c75be..d07fdd6504 100644 --- a/scripts/npc/1012113.js +++ b/scripts/npc/1012113.js @@ -1,24 +1,24 @@ /* - 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 . -*/ + This file is part of the OdinMS Maple Story Server + Copyright (C) 2008 Patrick Huy + Matthias Butz + Jan Christian Meyer + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ /** * @author BubblesDev * @author Ronan @@ -31,45 +31,45 @@ function start() { } function action(mode, type, selection) { - if (mode < 1) { - cm.dispose(); - } else { - status++; - if (cm.getPlayer().getMap().getId() == 910010100) { //Clear map - if (status == 0) { - cm.sendNext("Hello, there! I'm Tommy. There's a Pig Town nearby where we're standing. The pigs there are rowdy and uncontrollable to the point where they have stolen numerous weapons from travelers. They were kicked out from their towns, and are currently hiding out at the Pig Town."); - } else if (status == 1) { - if(cm.isEventLeader()) { - cm.sendYesNo("What do you think about making your way there with your party members and teach those rowdy pigs a lesson?"); - } - else { - cm.sendOk("Interessed? Tell your party leader to talk to me to head there!"); - cm.dispose(); - return; - } - } else if (status == 2) { - cm.getEventInstance().startEventTimer(5 * 60000); - cm.getEventInstance().warpEventTeam(910010200); - - cm.dispose(); - return; - } - } else if (cm.getPlayer().getMap().getId() == 910010200) { //Bonus map - if (status == 0) { - cm.sendYesNo("Would you like to exit the bonus now?"); - } else { - cm.warp(910010400); - cm.dispose(); - return; - } - } else if (cm.getPlayer().getMap().getId() == 910010300) { //Exit map - if (status == 0) { - cm.sendOk("You will now be warped out, thank you for helping us!"); - } else { - cm.warp(100000200); - cm.dispose(); - return; - } + if (mode < 1) { + cm.dispose(); + } else { + status++; + if (cm.getPlayer().getMap().getId() == 910010100) { //Clear map + if (status == 0) { + cm.sendNext("Hello, there! I'm Tommy. There's a Pig Town nearby where we're standing. The pigs there are rowdy and uncontrollable to the point where they have stolen numerous weapons from travelers. They were kicked out from their towns, and are currently hiding out at the Pig Town."); + } else if (status == 1) { + if (cm.isEventLeader()) { + cm.sendYesNo("What do you think about making your way there with your party members and teach those rowdy pigs a lesson?"); } + else { + cm.sendOk("Interessed? Tell your party leader to talk to me to head there!"); + cm.dispose(); + return; + } + } else if (status == 2) { + cm.getEventInstance().startEventTimer(5 * 60000); + cm.getEventInstance().warpEventTeam(910010200); + + cm.dispose(); + return; + } + } else if (cm.getPlayer().getMap().getId() == 910010200) { //Bonus map + if (status == 0) { + cm.sendYesNo("Would you like to exit the bonus now?"); + } else { + cm.warp(910010400); + cm.dispose(); + return; + } + } else if (cm.getPlayer().getMap().getId() == 910010300) { //Exit map + if (status == 0) { + cm.sendOk("You will now be warped out, thank you for helping us!"); + } else { + cm.warp(100000200); + cm.dispose(); + return; + } } + } } diff --git a/scripts/npc/2042000.js b/scripts/npc/2042000.js index 45d5ef912b..726519e0b7 100644 --- a/scripts/npc/2042000.js +++ b/scripts/npc/2042000.js @@ -1,232 +1,84 @@ -/* - This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2016 - 2018 RonanLana +var map = 980000000; +var minLvl = 0; +var maxLvl = 255; +var minAmt = 0; +var maxAmt = 6; - 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 . -*/ -/* Spiegelmann - Refining NPC: - * Auto ore refiner - * - * @author RonanLana -*/ - -var status; -var refineRocks = true; // enables moon rock, star rock -var refineCrystals = true; // enables common crystals -var refineSpecials = true; // enables lithium, special crystals -var feeMultiplier = 7.0; - function start() { - status = -1; - action(1, 0, 0); + status = -1; + action(1, 0, 0); } function action(mode, type, selection) { - if (mode == -1) { - cm.dispose(); - } else { - if (mode == 0 && type > 0) { - cm.dispose(); - return; - } - if (mode == 1) - status++; - else - status--; - - if(status == 0) { - if (!Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { - cm.sendOk("The Monster Carnival is currently unavailable."); - cm.dispose(); - return; - } - - var selStr = "The Monster Carnival is currently unavailable, but instead I offer a steadfast #bore refining#k service for you, taxing #r" + ((feeMultiplier * 100) | 0) + "%#k over the usual fee to synthetize them. What will you do?#b"; - - var options = new Array("Refine mineral ores","Refine jewel ores"); - if(refineCrystals) { - options.push("Refine crystal ores"); - } - if(refineRocks) { - options.push("Refine plates/jewels"); - } - - for (var i = 0; i < options.length; i++){ - selStr += "\r\n#L" + i + "# " + options[i] + "#l"; - } - - cm.sendSimple(selStr); - } else if(status == 1) { - var allDone; - - if (selection == 0) { - allDone = refineItems(0); // minerals - } else if (selection == 1) { - allDone = refineItems(1); // jewels - } else if (selection == 2 && refineCrystals) { - allDone = refineItems(2); // crystals - } else if (selection == 2 && !refineCrystals || selection == 3) { - allDone = refineRockItems(); // moon/star rock - } - - if(allDone) { - cm.sendOk("Done. Thanks for showing up~."); - } else { - cm.sendOk("Done. Be aware some of the items #rcould not be synthetized#k because either you have a lack of space on your ETC inventory or there's not enough mesos to cover the fee."); - } - cm.dispose(); - } + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 0 && status == 0) { + cm.dispose(); + return; } -} - -function getRefineFee(fee) { - return ((feeMultiplier * fee) | 0); -} - -function isRefineTarget(refineType, refineItemid) { - if(refineType == 0) { //mineral refine - return refineItemid >= 4010000 && refineItemid <= 4010007 && !(refineItemid == 4010007 && !refineSpecials); - } else if(refineType == 1) { //jewel refine - return refineItemid >= 4020000 && refineItemid <= 4020008 && !(refineItemid == 4020008 && !refineSpecials); - } else if(refineType == 2) { //crystal refine - return refineItemid >= 4004000 && refineItemid <= 4004004 && !(refineItemid == 4004004 && !refineSpecials); - } - - return false; -} - -function getRockRefineTarget(refineItemid) { - if(refineItemid >= 4011000 && refineItemid <= 4011006) { - return 0; - } else if(refineItemid >= 4021000 && refineItemid <= 4021008) { - return 1; - } - - return -1; -} - -function refineItems(refineType) { - var allDone = true; - - var refineFees = [[300,300,300,500,500,500,800,270],[500,500,500,500,500,500,500,1000,3000],[5000,5000,5000,5000,1000000]]; - var itemCount = {}; - - var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator(); - while (iter.hasNext()) { - var it = iter.next(); - var itemid = it.getItemId(); - - if(isRefineTarget(refineType, itemid)) { - var ic = itemCount[itemid]; - - if(ic != undefined) { - itemCount[itemid] += it.getQuantity(); + if (mode == 1) + status++; + else + status--; + if (status == 0) { + if (cm.getParty() == null) { + status = 10; + cm.sendOk("#eÉ necessário criar um grupo antes de começar o Festival de Monstros!#k"); + } else if (!cm.isLeader()) { + status = 10; + cm.sendOk("Se você quer começar o Festival, avise o #blíder do grupo#k para falar comigo."); } else { - itemCount[itemid] = it.getQuantity(); - } - } - } - - for(var key in itemCount) { - var itemqty = itemCount[key]; - var itemid = parseInt(key); - - var refineQty = ((itemqty / 10) | 0); - if(refineQty <= 0) continue; - - while(true) { - itemqty = refineQty * 10; - - var fee = getRefineFee(refineFees[refineType][(itemid % 100) | 0] * refineQty); - if(cm.canHold(itemid + 1000, refineQty, itemid, itemqty) && cm.getMeso() >= fee) { - cm.gainMeso(-fee); - cm.gainItem(itemid, -itemqty); - cm.gainItem(itemid + (itemid != 4010007 ? 1000 : 1001), refineQty); - - break; - } else if(refineQty <= 1) { - allDone = false; - break; - } else { - refineQty--; - } - } - } - - return allDone; -} - -function refineRockItems() { - var allDone = true; - var minItems = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]]; - var minRocks = [2147483647, 2147483647]; - - var rockItems = [4011007, 4021009]; - var rockFees = [10000, 15000]; - - var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator(); - while (iter.hasNext()) { - var it = iter.next(); - var itemid = it.getItemId(); - var rockRefine = getRockRefineTarget(itemid); - if(rockRefine >= 0) { - var rockItem = ((itemid % 100) | 0); - var itemqty = it.getQuantity(); - - minItems[rockRefine][rockItem] += itemqty; - } - } - - for(var i = 0; i < minRocks.length; i++) { - for(var j = 0; j < minItems[i].length; j++) { - if(minRocks[i] > minItems[i][j]) { - minRocks[i] = minItems[i][j]; - } - } - if(minRocks[i] <= 0 || minRocks[i] == 2147483647) continue; - - var refineQty = minRocks[i]; - while(true) { - var fee = getRefineFee(rockFees[i] * refineQty); - if(cm.canHold(rockItems[i], refineQty) && cm.getMeso() >= fee) { - cm.gainMeso(-fee); - - var j; - if(i == 0) { - for(j = 4011000; j < 4011007; j++) { - cm.gainItem(j, -refineQty); + var party = cm.getParty().getMembers(); + var inMap = cm.partyMembersInMap(); + var lvlOk = 0; + var isInMap = 0; + for (var i = 0; i < party.size(); i++) { + if (party.get(i).getLevel() >= minLvl && party.get(i).getLevel() <= maxLvl) { + lvlOk++; } - cm.gainItem(j, refineQty); + if (party.get(i).getPlayer().getMapId() != 980000000) { + //isInMap = false; + isInMap++ + } + } + + if (party >= 1) { + status = 10; + cm.sendOk("Você não tem número suficiente de pessoas em seu grupo. Você precisa de um grupo com #b" + minAmt + "#k - #r" + maxAmt + "#k membros e eles devem estar no mapa com você."); + } else if (lvlOk != inMap) { + status = 10; + cm.sendOk("Certifique se todos em seu grupo estão dentre os níveis corretos (" + minLvl + "~" + maxLvl + ")!"); + } else if (isInMap > 0) { + status = 10; + cm.sendOk("Existe alguém do grupo que não esta no mapa!"); } else { - for(j = 4021000; j < 4021009; j++) { - cm.gainItem(j, -refineQty); - } - cm.gainItem(j, refineQty); + cm.sendCPQMapLists(); } - - break; - } else if(refineQty <= 1) { - allDone = false; - break; - } else { - refineQty--; } + } else if (status == 1) { + + if (cm.fieldTaken(selection)) { + if (cm.fieldLobbied(selection)) { + cm.challengeParty(selection); + cm.dispose(); + } else { + cm.sendOk("A sala esta cheia."); + cm.dispose(); + } + } else { + var party = cm.getParty().getMembers(); + if ((selection === 0 || selection === 1 || selection === 2 || selection === 3) && party.size() < 2) { + cm.sendOk("Você precisa de no mínimo 2 player para entrar na competição."); + } else if ((selection === 4 || selection === 5) && party.size() < 3) { + cm.sendOk("Você precisa de no mínimo 3 player para entrar na competição."); + } else { + cm.cpqLobby(selection); + } + cm.dispose(); + } + } else if (status == 11) { + cm.dispose(); } } - - return allDone; -} +} \ No newline at end of file diff --git a/scripts/npc/2042002.js b/scripts/npc/2042002.js index 1d539fa0b3..4f7ae7d9c3 100644 --- a/scripts/npc/2042002.js +++ b/scripts/npc/2042002.js @@ -1,226 +1,320 @@ -/* - This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2016 - 2018 RonanLana +importPackage(Packages.server.maps); - 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. +var status = 0; +var rnk = -1; +var n1 = 50; //??? +var n2 = 40; //??? ??? +var n3 = 7; //35 +var n4 = 10; //40 +var n5 = 20; //50 - 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 . -*/ -/* Spiegelmann - Refining NPC: - * Auto ore refiner - * - * @author RonanLana -*/ - -var status; -var refineRocks = true; // enables moon rock, star rock -var refineCrystals = true; // enables common crystals -var refineSpecials = true; // enables lithium, special crystals -var feeMultiplier = 7.0; - function start() { - status = -1; - action(1, 0, 0); + status = -1; + action(1, 0, 0); } function action(mode, type, selection) { - if (mode == -1) { + if (mode == -1) { + cm.dispose(); + } else { + if (status >= 0 && mode == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + if (cm.getPlayer().getMapId() == 980000010) { + if (status == 0) { + cm.sendNext("Eu espero que você tinha divertido na Folia dos Monstros!"); + } else if (status > 0) { + cm.warp(980000000, 0); cm.dispose(); + } + } else if (cm.getChar().getMap().isCPQLoserMap()) { + if (status == 0) { + if (cm.getChar().getParty() != null) { + var shiu = ""; + if (cm.getPlayer().getFestivalPoints() >= 100) { + shiu += "#rA#k"; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha, apesar da sua excelente performance. A vitória pode ser sua da próxima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + rnk = 10; + } else if (cm.getPlayer().getFestivalPoints() >= 50 && cm.getPlayer().getFestivalPoints() < 100) { + shiu += "#rB#k"; + rnk = 20; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha, mesmo com sua ótima performance. Só mais um pouquinho, e a vitória poderia ter sido sua.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + } else if (cm.getPlayer().getFestivalPoints() >= 30 && cm.getPlayer().getFestivalPoints() < 50) { + shiu += "#rC#k"; + rnk = 30; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha. A vitória está para aqueles que se esforçam. Vejo seus esforços, então a vitória não está tão longe do seu alcance. Continue assim!\r\n\r\n#bNota da Folia de Monstros : " + shiu); + } else { + shiu += "#rD#k"; + rnk = 40; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha, e sua performance claramente reflete nisso. Espero mais de você da próxima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + } + } else { + cm.warp(980000000, 0); + cm.dispose(); + } + } else if (status == 1) { + switch (rnk) { + case 10: + cm.warp(980000000, 0); + cm.gainExp(17500); + cm.dispose(); + break; + case 20: + cm.warp(980000000, 0); + cm.gainExp(1200); + cm.dispose(); + break; + case 30: + cm.warp(980000000, 0); + cm.gainExp(5000); + cm.dispose(); + break; + case 40: + cm.warp(980000000, 0); + cm.gainExp(2500); + cm.dispose(); + break; + default: + cm.warp(980000000, 0); + cm.dispose(); + break; + } + } + } else if (cm.getChar().getMap().isCPQWinnerMap()) { + if (status == 0) { + if (cm.getChar().getParty() != null) { + var shi = ""; + if (cm.getPlayer().getFestivalPoints() >= 300) { + shi += "#rA#k"; + rnk = 1; + cm.sendOk("Parabéns pela sua vitória!!! Que ótima performance! O grupo adversário não pôde fazer nada! Espero o mesmo bom trabalho da próxima vez!\r\n\r\n#bNota da Folia de Monstros : " + shi); + } else if (cm.getPlayer().getFestivalPoints() >= 100 && cm.getPlayer().getFestivalPoints() < 300) { + shi += "#rB#k"; + rnk = 2; + cm.sendOk("Parabéns pela sua vitória! Isso foi impressionante! Você fez um bom trabalho contra o grupo adversário! Só mais um pouco, e você definitivamente vai conseguir um A na próxima vez. \r\n\r\n#bNota da Folia de Monstros : " + shi); + } else if (cm.getPlayer().getFestivalPoints() >= 50 && cm.getPlayer().getFestivalPoints() < 100) { + shi += "#rC#k"; + rnk = 3; + cm.sendOk("Parabéns pela sua vitória. Você fez algumas coisas cá e lá, mas essa não pode ser considerada uma boa vitória. Espero mais de ti da próxima vez.\r\n\r\n#bNota da Folia de Monstros : " + shi); + } else { + shi += "#rD#k"; + rnk = 4; + cm.sendOk("Parabéns pela sua vitória, entretanto sua performance não refletiu muito bem isso. Seja mais ativo na sua próxima participação da Folia de Monstros!\r\n\r\n#bNota da Folia de Monstros : " + shi); + } + } else { + cm.warp(980000000, 0); + cm.dispose(); + } + } else if (status == 1) { + switch (rnk) { + case 1: + cm.warp(980000000, 0); + cm.gainExp(50000); + cm.dispose(); + break; + case 2: + cm.warp(980000000, 0); + cm.gainExp(25500); + cm.dispose(); + break; + case 3: + cm.warp(980000000, 0); + cm.gainExp(21000); + cm.dispose(); + break; + case 4: + cm.warp(980000000, 0); + cm.gainExp(19505); + cm.dispose(); + break; + default: + cm.warp(980000000, 0); + cm.dispose(); + break; + } + } } else { - if (mode == 0 && type > 0) { + if (status == 0) { + // cm.sendSimple("O que gostaria de fazer? Se você nunca participou da Folia de Monstros, você precisará saber de algumas coisas antes de participar.\r\n#b#L0# Ir para o campo da Folia de Monstros 1.#l\r\n#L1# Aprender sobre a Folia de Monstros.#l\r\n#L2# Trocar #t4001129#.#l"); + cm.sendSimple("O que gostaria de fazer? Se você nunca participou da Folia de Monstros, você precisará saber de algumas coisas antes de participar.\r\n#b#L0# Ir para o campo da Folia de Monstros 1.#l\r\n#L3# Ir para o campo da Folia de Monstros 2.#l\r\n#L1# Aprender sobre a Folia de Monstros.#l\r\n#L2# Trocar #t4001129#.#l"); + } else if (status == 1) { + if (selection == 0) { + if ((cm.getLevel() > 29 && cm.getLevel() < 51) || cm.getPlayer().isGM()) { + cm.getChar().saveLocation("MONSTER_CARNIVAL"); + cm.warp(980000000, 0); cm.dispose(); return; - } - if (mode == 1) - status++; - else - status--; - - if(status == 0) { - var selStr = "The Monster Carnival is currently unavailable, but instead I offer a steadfast #bore refining#k service for you, taxing #r" + ((feeMultiplier * 100) | 0) + "%#k over the usual fee to synthetize them. What will you do?#b"; - - var options = new Array("Refine mineral ores","Refine jewel ores"); - if(refineCrystals) { - options.push("Refine crystal ores"); - } - if(refineRocks) { - options.push("Refine plates/jewels"); - } - - for (var i = 0; i < options.length; i++){ - selStr += "\r\n#L" + i + "# " + options[i] + "#l"; - } - - cm.sendSimple(selStr); - } else if(status == 1) { - var allDone; - - if (selection == 0) { - allDone = refineItems(0); // minerals - } else if (selection == 1) { - allDone = refineItems(1); // jewels - } else if (selection == 2 && refineCrystals) { - allDone = refineItems(2); // crystals - } else if (selection == 2 && !refineCrystals || selection == 3) { - allDone = refineRockItems(); // moon/star rock - } - - if(allDone) { - cm.sendOk("Done. Thanks for showing up~."); - } else { - cm.sendOk("Done. Be aware some of the items could not be synthetized because either you have a lack of space on your ETC inventory or there's not enough mesos to cover the fee."); - } + } else if (cm.getLevel() < 30) { + cm.sendOk("Você precisa ser no mínimo nível 30 para participar da Folia de Monstros. Fale comigo quando for forte o bastante."); cm.dispose(); - } - } -} - -function getRefineFee(fee) { - return ((feeMultiplier * fee) | 0); -} - -function isRefineTarget(refineType, refineItemid) { - if(refineType == 0) { //mineral refine - return refineItemid >= 4010000 && refineItemid <= 4010007 && !(refineItemid == 4010007 && !refineSpecials); - } else if(refineType == 1) { //jewel refine - return refineItemid >= 4020000 && refineItemid <= 4020008 && !(refineItemid == 4020008 && !refineSpecials); - } else if(refineType == 2) { //crystal refine - return refineItemid >= 4004000 && refineItemid <= 4004004 && !(refineItemid == 4004004 && !refineSpecials); - } - - return false; -} - -function getRockRefineTarget(refineItemid) { - if(refineItemid >= 4011000 && refineItemid <= 4011006) { - return 0; - } else if(refineItemid >= 4021000 && refineItemid <= 4021008) { - return 1; - } - - return -1; -} - -function refineItems(refineType) { - var allDone = true; - - var refineFees = [[300,300,300,500,500,500,800,270],[500,500,500,500,500,500,500,1000,3000],[5000,5000,5000,5000,1000000]]; - var itemCount = {}; - - var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator(); - while (iter.hasNext()) { - var it = iter.next(); - var itemid = it.getItemId(); - - if(isRefineTarget(refineType, itemid)) { - var ic = itemCount[itemid]; - - if(ic != undefined) { - itemCount[itemid] += it.getQuantity(); - } else { - itemCount[itemid] = it.getQuantity(); - } - } - } - - for(var key in itemCount) { - var itemqty = itemCount[key]; - var itemid = parseInt(key); - - var refineQty = ((itemqty / 10) | 0); - if(refineQty <= 0) continue; - - while(true) { - itemqty = refineQty * 10; - - var fee = getRefineFee(refineFees[refineType][(itemid % 100) | 0] * refineQty); - if(cm.canHold(itemid + 1000, refineQty, itemid, itemqty) && cm.getMeso() >= fee) { - cm.gainMeso(-fee); - cm.gainItem(itemid, -itemqty); - cm.gainItem(itemid + (itemid != 4010007 ? 1000 : 1001), refineQty); - - break; - } else if(refineQty <= 1) { - allDone = false; - break; - } else { - refineQty--; - } - } - } - - return allDone; -} - -function refineRockItems() { - var allDone = true; - var minItems = [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]]; - var minRocks = [2147483647, 2147483647]; - - var rockItems = [4011007, 4021009]; - var rockFees = [10000, 15000]; - - var iter = cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).iterator(); - while (iter.hasNext()) { - var it = iter.next(); - var itemid = it.getItemId(); - var rockRefine = getRockRefineTarget(itemid); - if(rockRefine >= 0) { - var rockItem = ((itemid % 100) | 0); - var itemqty = it.getQuantity(); - - minItems[rockRefine][rockItem] += itemqty; - } - } - - for(var i = 0; i < minRocks.length; i++) { - for(var j = 0; j < minItems[i].length; j++) { - if(minRocks[i] > minItems[i][j]) { - minRocks[i] = minItems[i][j]; - } - } - if(minRocks[i] <= 0 || minRocks[i] == 2147483647) continue; - - var refineQty = minRocks[i]; - while(true) { - var fee = getRefineFee(rockFees[i] * refineQty); - if(cm.canHold(rockItems[i], refineQty) && cm.getMeso() >= fee) { - cm.gainMeso(-fee); - - var j; - if(i == 0) { - for(j = 4011000; j < 4011007; j++) { - cm.gainItem(j, -refineQty); + return; + } else { + cm.sendOk("Sinto muito, mas apenas os jogadores de nível 30~50 podem participar da Folia de Monstros."); + cm.dispose(); + return; } - cm.gainItem(j, refineQty); + } else if (selection == 1) { + status = 60; + cm.sendSimple("O que gostaria de fazer?\r\n#b#L0# O que é a Folia de Monstros?#l\r\n#L1# Visão geral sobre a Folia de Monstros#l\r\n#L2# Informações detalhadas sobre a Folia de Monstros#l\r\n#L3# Nada, de verdade. Mudei de ideia.#l"); + } else if (selection == 2) { + cm.sendSimple("Lembre-se se você possui #t4001129#, você pode trocá-las por itens. Tenha certeza que você possui #t4001129# suficientes para o item que você deseja. Selecione o item que você gostaria de trocá-las! \r\n#b#L0# #t1122007#(" + n1 + " moedas)#l\r\n#L1# #t2041211#(" + n2 + " moedas)#l\r\n#L2# Armas para Guerreiros#l\r\n#L3# Armas para Bruxos#l\r\n#L4# Armas para Arqueiros#l\r\n#L5# Armas para Gatunos#l"); + } else if (selection == 3) { + cm.getChar().saveLocation("MONSTER_CARNIVAL"); + cm.warp(980030000, 0); + cm.dispose(); + return; + } + + } else if (status == 2) { + select = selection; + if (select == 0) { + if (cm.haveItem(4001129, n1) && cm.canHold(4001129)) { + cm.gainItem(1122007, 1); + cm.gainItem(4001129, -n1); + cm.dispose(); + } else { + cm.sendOk("Verifique e veja se estão faltando #b#t4001129##k ou se seu inventário de Equipamentos está cheio."); + cm.dispose(); + } + } else if (select == 1) { + if (cm.haveItem(4001129, n2) && cm.canHold(2041211)) { + cm.gainItem(2041211, 1); + cm.gainItem(4001129, -n2); + cm.dispose(); + } else { + cm.sendOk("Verifique e veja se estão faltando #b#t4001129##k ou se seu inventário de Uso está cheio."); + cm.dispose(); + } + } else if (select == 2) {//S2 Warrior 26 S3 Magician 6 S4 Bowman 6 S5 Thief 8 + status = 10; + cm.sendSimple("Por favor tenha certeza que você possui #t4001129# para a arma que você deseja. Selecione a arma que você gostaria de trocar #t4001129# por. As opções que tenho são realmente boas, e eu não sou eu que falo é o povo que diz! \r\n#b#L0# #z1302004#(" + n3 + " moedas)#l\r\n#L1# #z1402006#(" + n3 + " moedas)#l\r\n#L2# #z1302009#(" + n4 + " moedas)#l\r\n#L3# #z1402007#(" + n4 + " moedas)#l\r\n#L4# #z1302010#(" + n5 + " moedas)#l\r\n#L5# #z1402003#(" + n5 + " moedas)#l\r\n#L6# #z1312006#(" + n3 + " moedas)#l\r\n#L7# #z1412004#(" + n3 + " moedas)#l\r\n#L8# #z1312007#(" + n4 + " moedas)#l\r\n#L9# #z1412005#(" + n4 + " moedas)#l\r\n#L10# #z1312008#(" + n5 + " moedas)#l\r\n#L11# #z1412003#(" + n5 + " moedas)#l\r\n#L12# Ir para a próxima página(1/2)#l"); + } else if (select == 3) { + status = 20; + cm.sendSimple("Selecione a arma que você gostaria de trocar. As armas que eu tenho aqui são extremamente atraentes. Veja você mesmo! \r\n#b#L0# #z1372001#(" + n3 + " moedas)#l\r\n#L1# #z1382018#(" + n3 + " moedas)#l\r\n#L2# #z1372012#(" + n4 + "moedas)#l\r\n#L3# #z1382019#(" + n4 + "moedas)#l\r\n#L4# #z1382001#(" + n5 + " moedas)#l\r\n#L5# #z1372007#(" + n5 + " moedas)#l"); + } else if (select == 4) { + status = 30; + cm.sendSimple("Selecione a arma que você gostaria de trocar. As armas que eu tenho aqui são extremamente atraentes. Veja você mesmo! \r\n#b#L0# #z1452006#(" + n3 + " moedas)#l\r\n#L1# #z1452007#(" + n4 + " moedas)#l\r\n#L2# #z1452008#(" + n5 + " moedas)#l\r\n#L3# #z1462005#(" + n3 + " moedas)#l\r\n#L4# #z1462006#(" + n4 + " moedas)#l\r\n#L5# #z1462007#(" + n5 + " moedas)#l"); + } else if (select == 5) { + status = 40; + cm.sendSimple("Selecione a arma que você gostaria de trocar por. As armas que eu tenho são da maior qualidade. Seleciona a mais atraente para você! \r\n#b#L0# #z1472013#(" + n3 + " moedas)#l\r\n#L1# #z1472017#(" + n4 + "moedas)#l\r\n#L2# #z1472021#(" + n5 + " moedas)#l\r\n#L3# #z1332014#(" + n3 + " moedas)#l\r\n#L4# #z1332031#(" + n4 + "moedas)#l\r\n#L5# #z1332011#(" + n4 + "moedas)#l\r\n#L6# #z1332016#(" + n5 + " moedas)#l\r\n#L7# #z1332003#(" + n5 + " moedas)#l"); + } + } else if (status == 11) { + if (selection == 12) { + cm.sendSimple("Selecione a arma que você gostaria de trocar. As armas que eu tenho aqui são extremamente úteis. Dá uma olhada! \r\n#b#L0# #z1322015#(" + n3 + " moedas)#l\r\n#L1# #z1422008#(" + n3 + " moedas)#l\r\n#L2# #z1322016#(" + n4 + "moedas)#l\r\n#L3# #z1422007#(" + n4 + "moedas)#l\r\n#L4# #z1322017#(" + n5 + " moedas)#l\r\n#L5# #z1422005#(" + n5 + " moedas)#l\r\n#L6# #z1432003#(" + n3 + " moedas)#l\r\n#L7# #z1442003#(" + n3 + " moedas)#l\r\n#L8# #z1432005#(" + n4 + "moedas)#l\r\n#L9# #z1442009#(" + n4 + "moedas)#l\r\n#L10# #z1442005#(" + n5 + " moedas)#l\r\n#L11# #z1432004#(" + n5 + " moedas)#l\r\n#L12# Voltar para a página inicial(2/2)#l"); } else { - for(j = 4021000; j < 4021009; j++) { - cm.gainItem(j, -refineQty); + var item = new Array(1302004, 1402006, 1302009, 1402007, 1302010, 1402003, 1312006, 1412004, 1312007, 1412005, 1312008, 1412003); + var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("Você ou não possui #b#t4001129##k suficientes, ou seu inventário está cheio. Verifique novamente."); + cm.dispose(); } - cm.gainItem(j, refineQty); } - - break; - } else if(refineQty <= 1) { - allDone = false; - break; - } else { - refineQty--; + } else if (status == 12) { + if (selection == 12) { + status = 10; + cm.sendSimple("Por favor tenha certeza que você possui #t4001129# para a arma que você deseja. Selecione a arma que você gostaria de trocar #t4001129# por. As opções que tenho são realmente boas, e eu não sou eu que falo é o povo que diz! \r\n#b#L0# #z1302004#(" + n3 + " moedas)#l\r\n#L1# #z1402006#(" + n3 + " moedas)#l\r\n#L2# #z1302009#(" + n4 + " moedas)#l\r\n#L3# #z1402007#(" + n4 + " moedas)#l\r\n#L4# #z1302010#(" + n5 + " moedas)#l\r\n#L5# #z1402003#(" + n5 + " moedas)#l\r\n#L6# #z1312006#(" + n3 + " moedas)#l\r\n#L7# #z1412004#(" + n3 + " moedas)#l\r\n#L8# #z1312007#(" + n4 + " moedas)#l\r\n#L9# #z1412005#(" + n4 + " moedas)#l\r\n#L10# #z1312008#(" + n5 + " moedas)#l\r\n#L11# #z1412003#(" + n5 + " moedas)#l\r\n#L12# Ir para a próxima página(1/2)#l"); + } else { + var item = new Array(1322015, 1422008, 1322016, 1422007, 1322017, 1422005, 1432003, 1442003, 1432005, 1442009, 1442005, 1432004); + var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("Você ou não possui #b#t4001129##k suficientes, ou seu inventário está cheio. Verifique novamente."); + cm.dispose(); + } + } + } else if (status == 21) { + var item = new Array(1372001, 1382018, 1372012, 1382019, 1382001, 1372007); + var cost = new Array(n3, n3, n4, n4, n5, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("Ou você não possui #b#t4001129##k suficientes, ou seu inventário está cheio. Verifique novamente."); + cm.dispose(); + } + } else if (status == 31) { + var item = new Array(1452006, 1452007, 1452008, 1462005, 1462006, 1462007); + var cost = new Array(n3, n4, n5, n3, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("Ou você não possui #b#t4001129##k suficientes, ou seu inventário está cheio. Verifique novamente."); + cm.dispose(); + } + } else if (status == 41) { + var item = new Array(1472013, 1472017, 1472021, 1332014, 1332031, 1332011, 1332016, 1332003); + var cost = new Array(n3, n4, n5, n3, n4, n4, n5, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("Ou você não possui #b#t4001129##k suficientes, ou seu inventário está cheio. Verifique novamente."); + cm.dispose(); + } + } else if (status == 61) { + select = selection; + if (selection == 0) { + cm.sendNext("Haha! Eu sou Spiegelmann, o líder dessa Folia. Eu comecei a primeira #bFolia de Monstros#k aqui, aguardando por viajantes como você para participar dessa extravaganza!"); + } else if (selection == 1) { + cm.sendNext("#bFolia de Monstros#k consiste em 2 grupos entrando no campo de batalha, e caçando os monstros invocados pelo outro grupo. É uma #bmissão de combate que determina o vitorioso pela quantia de Pontos de Folia (CP) recebidos#k."); + } else if (selection == 2) { + cm.sendNext("Quando entrar no Campo da Folia, você verá a janela da Folia de Monstros aparecer. Tudo que precisa fazer é #bselecionar o que vocêe quer usar, e pressionar OK#k. Muito fácil, né?"); + } else { + cm.dispose(); + } + } else if (status == 62) { + if (select == 0) { + cm.sendNext("O que é a #bFolia de Monstros#k? Hahaha! Vamos dizer que é uma experiência que jamais esquecerá! É uma #bbatalha contra outros viajantes assim como você!#k"); + } else if (select == 1) { + cm.sendNext("Quando entrar no Campo da Folia, sua tarefa é #breceber CP caçando os monstros do grupo oposto, e usar estes CP's para distrair o grupo oposto de caçar monstros.#k."); + } else if (select == 2) { + cm.sendNext("Assim que se acostumar com os comandos, tente usar #bas teclas TAB e F1 ~ F12#k. #bTAB alterna entre Invocação de Monstros/Habilidades/Protetor,#k e, #bF1~ F12 possibilita-o de acessar uma das janelas diretamente#k."); + } + } else if (status == 63) { + if (select == 0) { + cm.sendNext("Eu sei que é muito perigoso para vocês lutarem uns com os outros usando armas de verdade; e eu não sugeriria um ato tão barbárico. Não meu amigo, o que eu ofereço é competição. A emoção da batalha e a emoção de competir contra pessoas tão fortes e motivadas. Eu ofereço a premissa de que seu grupo e o grupo oposto ambos #binvoquem os monstros, e derrote os monstros invocados pelo grupo adversário. Essa é a essência da Folia de Monstros. Além disso, você pode usar Maple Coins ganhos durante a Folia de Monstros para obter novos itens e armas! #k"); + } else if (select == 1) { + cm.sendNext("Existem 3 maneiras de distrair o grupo adversário: #bInvodar um monstro, Habilidade, and Protetor#k. Vou dar-lhe um olhar mais aprofundado, se você quiser saber mais sobre 'Instruções detalhadas'."); + } else if (select == 2) { + cm.sendNext("#bInvocar um Monstro#k chama um monstro que ataca o grupo adversário, sob seu controle. Use CP para trazer um Monstro Invocado, e ele irá aparecer na mesma área, atacando o grupo oposto."); + } + } else if (status == 64) { + if (select == 0) { + cm.sendNext("Claro, não é tão simples assim. Existem outras maneiras de prevenir o outro grupo de caçar monstros, e cabe a você descobrir como fazê-lo. O que acha? Interessado em uma competição amigável?"); + cm.dispose(); + } else if (select == 1) { + cm.sendNext("Por favor lembre-se. Nunca é uma boa ideia guardar seus CP's. #bOs CP's que você usou irão ajudar a determinar o vencedor e o perdedor da Folia."); + } else if (select == 2) { + cm.sendNext("#bHabilidade#k é uma opção de usar habilidades tais como Escuridão, Fraqueza, e outras para prevenir o grupo oposto de matar outros monstros. São necessários muitos CP's, mas vale muito a pena. O único problema é que eles não duram muito. Use essa tática com sabedoria!"); + } + } else if (status == 65) { + if (select == 1) { + cm.sendNext("Oh, e não se preocupe em tranformar-se em um fantasma. Na Folia de Monstros, #bvocê não perderá EXP após a morte#k. É realmente uma experência como nenhuma outra!"); + cm.dispose(); + } else if (select == 2) { + cm.sendNext("#bProtetor#k é basicamente um item invocado que aumenta drásticamente as habilidades dos monstros invocados pelo seu grupo. Protetor funciona enquanto não for demolido pelo grupo oposto, então eu surigo que você invoque vários monstros primeiro, e então traga o Protetor."); + } + } else if (status == 66) { + cm.sendNext("Por último, enquanto estiver na Folia de Monstros, #bvocê não pode usar items/poções de recuperação que você leva por ai contigo.#k Entretanto, os monstros deixam esses items cair de vez em quando, e #bassim que pegá-los, o item ativará imediatamente#k. É por isso que é importante saber quando pegar estes items."); + cm.dispose(); } } } - - return allDone; } + diff --git a/scripts/npc/2042003.js b/scripts/npc/2042003.js new file mode 100644 index 0000000000..4a475a35ff --- /dev/null +++ b/scripts/npc/2042003.js @@ -0,0 +1,30 @@ +var status = 0; +var request; + +function start() { + status = -1; + action(1, 0, 0); +} + + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 0 && status == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + if (status == 0) { + cm.warpParty(980000000); + cm.cancelarSaida(); + cm.dispose(); + } + } +} + + diff --git a/scripts/npc/2042004.js b/scripts/npc/2042004.js new file mode 100644 index 0000000000..fa5965c5bf --- /dev/null +++ b/scripts/npc/2042004.js @@ -0,0 +1,16 @@ +var status = 0; +var request; + +function start() { + status = -1; + action(1, 0, 0); +} + + +function action(mode, type, selection) { + cm.warpParty(980000000); + cm.cancelarSaida(); + cm.dispose(); +} + + diff --git a/scripts/npc/2042005.js b/scripts/npc/2042005.js new file mode 100644 index 0000000000..0cf77cbf77 --- /dev/null +++ b/scripts/npc/2042005.js @@ -0,0 +1,83 @@ +var map = 980030000; +var minLvl = 30; +var maxLvl = 255; +var minAmt = 0; +var maxAmt = 6; + +function start() { + status = -1; + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 0 && status == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + if (status == 0) { + if (cm.getParty() == null) { + status = 10; + cm.sendOk("#eÉ necessário criar um grupo antes de começar o Festival de Monstros!#k"); + } else if (!cm.isLeader()) { + status = 10; + cm.sendOk("Se você quer começar o Festival, avise o #blíder do grupo#k para falar comigo."); + } else { + var party = cm.getParty().getMembers(); + var inMap = cm.partyMembersInMap(); + var lvlOk = 0; + var isInMap = 0; + for (var i = 0; i < party.size(); i++) { + if (party.get(i).getLevel() >= minLvl && party.get(i).getLevel() <= maxLvl) { + lvlOk++; + } + if (party.get(i).getPlayer().getMapId()!= 980030000) { + //isInMap = false; + isInMap++ + } + } + + if (party >= 1) { + status = 10; + cm.sendOk("Você não tem número suficiente de pessoas em seu grupo. Você precisa de um grupo com #b" + minAmt + "#k - #r" + maxAmt + "#k membros e eles devem estar no mapa com você."); + } else if (lvlOk != inMap) { + status = 10; + cm.sendOk("Certifique se todos em seu grupo estão dentre os níveis corretos (" + minLvl + "~" + maxLvl + ")!"); + } else if (isInMap > 0) { + status = 10; + cm.sendOk("Existe alguém do grupo que não esta no mapa!"); + } else { + cm.sendCPQMapLists2(); + } + } + } else if (status == 1) { + if (cm.fieldTaken2(selection)) { + if (cm.fieldLobbied2(selection)) { + cm.challengeParty2(selection); + cm.dispose(); + } else { + cm.sendOk("A sala esta cheia."); + cm.dispose(); + } + } else { + var party = cm.getParty().getMembers(); + if ((selection === 0 || selection === 1 ) && party.size() < 2) { + cm.sendOk("Você precisa de no mínimo 2 player para entrar na competição."); + } else if ((selection === 2 ) && party.size() < 3) { + cm.sendOk("Você precisa de no mínimo 3 player para entrar na competição."); + } else { + cm.cpqLobby2(selection); + } + cm.dispose(); + } + } else if (status == 11) { + cm.dispose(); + } + } +} \ No newline at end of file diff --git a/scripts/npc/2042007.js b/scripts/npc/2042007.js new file mode 100644 index 0000000000..722f0229dc --- /dev/null +++ b/scripts/npc/2042007.js @@ -0,0 +1,132 @@ +importPackage(net.sf.odinms.server.maps); + +var status = 0; +var rnk = -1; + +function start() { + status = -1; + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + } else { + if (status >= 0 && mode == 0) { + cm.sendOk("Alright then, I hope we can chat later next time."); + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + if (cm.getChar().getMap().isCPQLoserMap()) { + if (status == 0) { + if (cm.getChar().getParty() != null) { + var shiu = ""; + if (cm.getPlayer().getFestivalPoints() >= 100) { + shiu += "#rA#k"; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha, apesar da sua excelente performance. A vitória pode ser sua da próxima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + rnk = 10; + } else if (cm.getPlayer().getFestivalPoints() >= 50 && cm.getPlayer().getFestivalPoints() < 100) { + shiu += "#rB#k"; + rnk = 20; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha, mesmo com sua ótima performance. Só mais um pouquinho, e a vitória poderia ter sido sua.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + } else if (cm.getPlayer().getFestivalPoints() >= 30 && cm.getPlayer().getFestivalPoints() < 50) { + shiu += "#rC#k"; + rnk = 30; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha. A vitória está para aqueles que se esforçam. Vejo seus esforços, então a vitória não está tão longe do seu alcance. Continue assim!\r\n\r\n#bNota da Folia de Monstros : " + shiu); + } else { + shiu += "#rD#k"; + rnk = 40; + cm.sendOk("Infelizmente, você ou empatou ou perdeu a batalha, e sua performance claramente reflete nisso. Espero mais de você da próxima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + } + } else { + cm.warp(980030000, 0); + cm.dispose(); + } + } else if (status == 1) { + switch (rnk) { + case 10: + cm.warp(980030000, 0); + cm.gainExp(35000); + cm.dispose(); + break; + case 20: + cm.warp(980030000, 0); + cm.gainExp(25000); + cm.dispose(); + break; + case 30: + cm.warp(980030000, 0); + cm.gainExp(12500); + cm.dispose(); + break; + case 40: + cm.warp(980030000, 0); + cm.gainExp(3500); + cm.dispose(); + break; + default: + cm.warp(980030000, 0); + cm.dispose(); + break; + } + } + } else if (cm.getChar().getMap().isCPQWinnerMap()) { + if (status == 0) { + if (cm.getChar().getParty() != null) { + var shi = ""; + if (cm.getPlayer().getFestivalPoints() >= 300) { + shi += "#rA#k"; + rnk = 1; + cm.sendOk("Parabéns pela sua vitória!!! Que ótima performance! O grupo adversário não pôde fazer nada! Espero o mesmo bom trabalho da próxima vez!\r\n\r\n#bNota da Folia de Monstros : " + shi); + } else if (cm.getPlayer().getFestivalPoints() >= 100 && cm.getPlayer().getFestivalPoints() < 300) { + shi += "#rB#k"; + rnk = 2; + cm.sendOk("Parabéns pela sua vitória! Isso foi impressionante! Você fez um bom trabalho contra o grupo adversário! Só mais um pouco, e você definitivamente vai conseguir um A na próxima vez. \r\n\r\n#bNota da Folia de Monstros : " + shi); + } else if (cm.getPlayer().getFestivalPoints() >= 50 && cm.getPlayer().getFestivalPoints() < 100) { + shi += "#rC#k"; + rnk = 3; + cm.sendOk("Parabéns pela sua vitória. Você fez algumas coisas cá e lá, mas essa não pode ser considerada uma boa vitória. Espero mais de ti da próxima vez.\r\n\r\n#bNota da Folia de Monstros : " + shi); + } else { + shi += "#rD#k"; + rnk = 4; + cm.sendOk("Parabéns pela sua vitória, entretanto sua performance não refletiu muito bem isso. Seja mais ativo na sua próxima participação da Folia de Monstros!\r\n\r\n#bNota da Folia de Monstros : " + shi); + } + } else { + cm.warp(980030000, 0); + cm.dispose(); + } + } else if (status == 1) { + switch (rnk) { + case 1: + cm.warp(980030000, 0); + cm.gainExp(875000); + cm.dispose(); + break; + case 2: + cm.warp(980030000, 0); + cm.gainExp(700000); + cm.dispose(); + break; + case 3: + cm.warp(980030000, 0); + cm.gainExp(555000); + cm.dispose(); + break; + case 4: + cm.warp(980030000, 0); + cm.gainExp(100000); + cm.dispose(); + break; + default: + cm.warp(980030000, 0); + cm.dispose(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/scripts/npc/2042008.js b/scripts/npc/2042008.js new file mode 100644 index 0000000000..d8ec8d8465 --- /dev/null +++ b/scripts/npc/2042008.js @@ -0,0 +1,30 @@ +var status = 0; +var request; + +function start() { + status = -1; + action(1, 0, 0); +} + + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 0 && status == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + if (status == 0) { + cm.warpParty(980030000, 4); + cm.cancelarSaida(); + cm.dispose(); + } + } +} + + diff --git a/scripts/npc/2042009.js b/scripts/npc/2042009.js new file mode 100644 index 0000000000..d8ec8d8465 --- /dev/null +++ b/scripts/npc/2042009.js @@ -0,0 +1,30 @@ +var status = 0; +var request; + +function start() { + status = -1; + action(1, 0, 0); +} + + +function action(mode, type, selection) { + if (mode == -1) { + cm.dispose(); + } else { + if (mode == 0 && status == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + if (status == 0) { + cm.warpParty(980030000, 4); + cm.cancelarSaida(); + cm.dispose(); + } + } +} + + diff --git a/scripts/npc/9201002.js b/scripts/npc/9201002.js index b7e8d3b4f3..aa7e970fee 100644 --- a/scripts/npc/9201002.js +++ b/scripts/npc/9201002.js @@ -1,24 +1,24 @@ /* - This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2017 RonanLana - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation version 3 as published by - the Free Software Foundation. You may not use, modify or distribute - this program under any other version of the GNU Affero General Public - License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ + This file is part of the HeavenMS MapleStory Server + Copyleft (L) 2017 RonanLana + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ /* High Priest John - Marriage NPC + Marriage NPC */ importPackage(Packages.constants); @@ -40,14 +40,14 @@ function isWeddingIndoors(mapid) { function getMarriageInstance(player) { var em = cm.getEventManager(weddingEventName); - - for (var iterator = em.getInstances().iterator(); iterator.hasNext();) { + + for (var iterator = em.getInstances().iterator(); iterator.hasNext(); ) { var eim = iterator.next(); - if(eim.isEventLeader(player)) { + if (eim.isEventLeader(player)) { return eim; } } - + return null; } @@ -57,7 +57,7 @@ function detectPlayerItemid(player) { return x; } } - + return -1; } @@ -67,31 +67,35 @@ function getRingId(boxItemId) { function isSuitedForWedding(player, equipped) { var baseid = (player.getGender() == 0) ? 1050131 : 1051150; - - if(equipped) { - for(var i = 0; i < 4; i++) { - if(player.haveItemEquipped(baseid + i)) { + + if (equipped) { + for (var i = 0; i < 4; i++) { + if (player.haveItemEquipped(baseid + i)) { return true; } } } else { - for(var i = 0; i < 4; i++) { - if(player.haveItemWithId(baseid + i, true)) { + for (var i = 0; i < 4; i++) { + if (player.haveItemWithId(baseid + i, true)) { return true; } } } - + return false; } function getWeddingPreparationStatus(player, partner) { - if(!player.haveItem(4000313)) return -3; - if(!partner.haveItem(4000313)) return 3; - - if(!isSuitedForWedding(player, true)) return -4; - if(!isSuitedForWedding(partner, true)) return 4; - + if (!player.haveItem(4000313)) + return -3; + if (!partner.haveItem(4000313)) + return 3; + + if (!isSuitedForWedding(player, true)) + return -4; + if (!isSuitedForWedding(partner, true)) + return 4; + var hasEngagement = false; for (var x = 4031357; x <= 4031364; x++) { if (player.haveItem(x)) { @@ -99,7 +103,8 @@ function getWeddingPreparationStatus(player, partner) { break; } } - if(!hasEngagement) return -1; + if (!hasEngagement) + return -1; hasEngagement = false; for (var x = 4031357; x <= 4031364; x++) { @@ -108,24 +113,28 @@ function getWeddingPreparationStatus(player, partner) { break; } } - if(!hasEngagement) return -2; + if (!hasEngagement) + return -2; - if(!player.canHold(1112803)) return 1; - if(!partner.canHold(1112803)) return 2; + if (!player.canHold(1112803)) + return 1; + if (!partner.canHold(1112803)) + return 2; return 0; } function giveCoupleBlessings(eim, player, partner) { var blessCount = eim.gridSize(); - + player.gainExp(blessCount * weddingBlessingExp); partner.gainExp(blessCount * weddingBlessingExp); } -function start() { +function start() { weddingIndoors = isWeddingIndoors(cm.getMapId()); - if(weddingIndoors) eim = cm.getEventInstance(); + if (weddingIndoors) + eim = cm.getEventInstance(); status = -1; action(1, 0, 0); @@ -144,8 +153,8 @@ function action(mode, type, selection) { else status--; - if(!weddingIndoors) { - if(status == 0) { + if (!weddingIndoors) { + if (status == 0) { var hasEngagement = false; for (var x = 4031357; x <= 4031364; x++) { if (cm.haveItem(x, 1)) { @@ -154,7 +163,7 @@ function action(mode, type, selection) { } } - if(hasEngagement) { + if (hasEngagement) { var text = "Hi there. How can I help you?"; var choice = new Array("We're ready to get married."); for (x = 0; x < choice.length; x++) { @@ -165,32 +174,32 @@ function action(mode, type, selection) { cm.sendOk("Hmm, today two fluttering hearts are about to be joined together by the blessings of love!"); cm.dispose(); } - } else if(status == 1) { + } else if (status == 1) { var wid = cm.getClient().getWorldServer().getRelationshipId(cm.getPlayer().getId()); var cserv = cm.getClient().getChannelServer(); - if(cserv.isWeddingReserved(wid)) { - if(wid == cserv.getOngoingWedding(cathedralWedding)) { + if (cserv.isWeddingReserved(wid)) { + if (wid == cserv.getOngoingWedding(cathedralWedding)) { var partner = cserv.getPlayerStorage().getCharacterById(cm.getPlayer().getPartnerId()); - if(!(partner == null || !cm.getMap().equals(partner.getMap()))) { - if(!cm.canHold(4000313)) { + if (!(partner == null || !cm.getMap().equals(partner.getMap()))) { + if (!cm.canHold(4000313)) { cm.sendOk("Please have a free ETC slot available to get the #b#t4000313##k."); cm.dispose(); return; - } else if(!partner.canHold(4000313)) { + } else if (!partner.canHold(4000313)) { cm.sendOk("Please let your partner know they must have a free ETC slot available to get the #b#t4000313##k."); cm.dispose(); return; - } else if(!isSuitedForWedding(cm.getPlayer(), false)) { + } else if (!isSuitedForWedding(cm.getPlayer(), false)) { cm.sendOk("Please purchase a #rwedding garment#k for the ceremony, quickly! Without it I am not able to marry you."); cm.dispose(); return; - } else if(!isSuitedForWedding(partner, false)) { + } else if (!isSuitedForWedding(partner, false)) { cm.sendOk("Please let your partner know they must have a #rwedding garment#k ready for the ceremony."); cm.dispose(); return; } - + cm.sendOk("Very well, the preparatives here are finished too. This indeed is a beautiful day, you two are truly blessed to marry on such a day. Let us begin the marriage!!"); } else { cm.sendOk("Hmm, it seems your partner is elsewhere... Please let them come here before starting the ceremony."); @@ -206,19 +215,19 @@ function action(mode, type, selection) { cm.sendOk("Hmm, I'm sorry but there are no reservations made for you at this channel for the time being."); cm.dispose(); } - } else if(status == 2) { + } else if (status == 2) { var cserv = cm.getClient().getChannelServer(); var wtype = cserv.getOngoingWeddingType(cathedralWedding); - + var partner = cserv.getPlayerStorage().getCharacterById(cm.getPlayer().getPartnerId()); - if(!(partner == null || !cm.getMap().equals(partner.getMap()))) { - if(cserv.acceptOngoingWedding(cathedralWedding)) { + if (!(partner == null || !cm.getMap().equals(partner.getMap()))) { + if (cserv.acceptOngoingWedding(cathedralWedding)) { var wid = cm.getClient().getWorldServer().getRelationshipId(cm.getPlayer().getId()); - if(wid > 0) { + if (wid > 0) { var em = cm.getEventManager(weddingEventName); - if(em.startInstance(cm.getPlayer())) { + if (em.startInstance(cm.getPlayer())) { eim = getMarriageInstance(cm.getPlayer()); - if(eim != null) { + if (eim != null) { eim.setIntProperty("weddingId", wid); eim.setIntProperty("groomId", cm.getPlayer().getId()); eim.setIntProperty("brideId", cm.getPlayer().getPartnerId()); @@ -248,20 +257,20 @@ function action(mode, type, selection) { } } else { if (status == 0) { - if(eim == null) { - cm.warp(680000000,0); + if (eim == null) { + cm.warp(680000000, 0); cm.dispose(); return; } - + var playerId = cm.getPlayer().getId(); - if(playerId == eim.getIntProperty("groomId") || playerId == eim.getIntProperty("brideId")) { + if (playerId == eim.getIntProperty("groomId") || playerId == eim.getIntProperty("brideId")) { var wstg = eim.getIntProperty("weddingStage"); - - if(wstg == 2) { + + if (wstg == 2) { cm.sendYesNo("Very well, the guests has bestowed all their blessings to you now. The time has come, #rshould I make you Husband and Wife#k?"); state = 1; - } else if(wstg == 1) { + } else if (wstg == 1) { cm.sendOk("While you two are making your wedding vows to each other, your guests are currently giving their blessings to you. This is a time of happiness for both of you, please rejoice the ceremony."); cm.dispose(); } else { @@ -270,12 +279,12 @@ function action(mode, type, selection) { } } else { var wstg = eim.getIntProperty("weddingStage"); - if(wstg == 1) { - if(eim.gridCheck(cm.getPlayer()) != -1) { + if (wstg == 1) { + if (eim.gridCheck(cm.getPlayer()) != -1) { cm.sendOk("Everyone give your blessings to this lovely couple!"); cm.dispose(); } else { - if(eim.getIntProperty("guestBlessings") == 1) { + if (eim.getIntProperty("guestBlessings") == 1) { cm.sendYesNo("Do you want to bless this couple?"); state = 0; } else { @@ -283,7 +292,7 @@ function action(mode, type, selection) { cm.dispose(); } } - } else if(wstg == 3) { + } else if (wstg == 3) { cm.sendOk("The two loving birds are now married. What a lively day! Please #rget ready for the afterparty#k, it should start soon. Follow the married couple's lead."); cm.dispose(); } else { @@ -292,10 +301,10 @@ function action(mode, type, selection) { } } } else if (status == 1) { - if(state == 0) { // give player blessings + if (state == 0) { // give player blessings eim.gridInsert(cm.getPlayer(), 1); - - if(ServerConstants.WEDDING_BLESSER_SHOWFX) { + + if (ServerConstants.WEDDING_BLESSER_SHOWFX) { var target = cm.getPlayer(); target.announce(MaplePacketCreator.showSpecialEffect(9)); target.getMap().broadcastMessage(target, MaplePacketCreator.showForeignEffect(target.getId(), 9), false); @@ -308,15 +317,15 @@ function action(mode, type, selection) { target.announce(MaplePacketCreator.showSpecialEffect(9)); target.getMap().broadcastMessage(target, MaplePacketCreator.showForeignEffect(target.getId(), 9), false); } - + cm.sendOk("Your blessings have been added to their love. What a noble act for a lovely couple!"); cm.dispose(); } else { // couple wants to complete the wedding var wstg = eim.getIntProperty("weddingStage"); - - if(wstg == 2) { + + if (wstg == 2) { var pid = cm.getPlayer().getPartnerId(); - if(pid <= 0) { + if (pid <= 0) { cm.sendOk("It seems you are no longer engaged to your partner, just before the altar... Where did all that happiness you two had sported a while ago went?"); cm.dispose(); return; @@ -324,14 +333,14 @@ function action(mode, type, selection) { var player = cm.getPlayer(); var partner = cm.getMap().getCharacterById(cm.getPlayer().getPartnerId()); - if(partner != null) { + if (partner != null) { state = getWeddingPreparationStatus(player, partner); - switch(state) { + switch (state) { case 0: var pid = eim.getIntProperty("confirmedVows"); - if(pid != -1) { - if(pid == player.getId()) { + if (pid != -1) { + if (pid == player.getId()) { cm.sendOk("You have already confirmed your vows. All that is left is for your partner to confirm now."); } else { eim.setIntProperty("weddingStage", 3); @@ -362,7 +371,7 @@ function action(mode, type, selection) { eim.setIntProperty("confirmedVows", player.getId()); cm.getMap().dropMessage(6, "Wedding Assistant: " + player.getName() + " has confirmed vows! Alright, one step away to make it official. Tighten your seatbelts!"); } - + break; case -1: @@ -376,7 +385,7 @@ function action(mode, type, selection) { case -3: cm.sendOk("It seems you don't have the #r#t4000313##k given at the entrance... Please find it, I can't marry you without that item in hands."); break; - + case -4: cm.sendOk("Pardon my rudiness, but the garments are a essential part of the ceremony. Please #rsuit yourself properly#k for a wedding."); break; @@ -392,7 +401,7 @@ function action(mode, type, selection) { case 3: cm.sendOk("It seems your partner don't have the #r#t4000313##k given at the entrance... Please find it, I can't marry you without that item in hands."); break; - + case 4: cm.sendOk("It seems your partner is not properly dressed for the wedding... Pardon my rudiness, but the garments are a essential part of the ceremony."); break; diff --git a/scripts/npc/9201006.js b/scripts/npc/9201006.js index 2a37253361..ec23bcf5fb 100644 --- a/scripts/npc/9201006.js +++ b/scripts/npc/9201006.js @@ -50,6 +50,7 @@ function action(mode, type, selection) { var eim = cm.getEventInstance(); if(eim == null) { cm.warp(680000000,0); + //cm.criarLista(); cm.dispose(); return; } @@ -71,7 +72,7 @@ function action(mode, type, selection) { cm.sendOk("Congratulations on your wedding. Please talk to #b#p9201007##k to start the afterparty."); cm.dispose(); } else if(hasEngagement) { - cm.sendOk("Please continue with the wedding."); + cm.criarLista(); cm.dispose(); } else { cm.sendOk("You do not have the required item to continue through this wedding. Unfortunately, it's over..."); diff --git a/scripts/npc/9201014.js b/scripts/npc/9201014.js index 9fd36866af..7d1bc9da2f 100644 --- a/scripts/npc/9201014.js +++ b/scripts/npc/9201014.js @@ -27,75 +27,25 @@ 1.0 - First Version by Angel 2.0 - Second Version by happydud3 & XotiCraze 3.0 - Third Version by RonanLana (HeavenMS) + 4.0 - Four Version bby Drago(MapleStorySA) --------------------------------------------------------------------------------------------------- **/ - -var bgPrizes = [[2022179,10], [2022282,10], [2210005,5], [2210003,5]]; -var cmPrizes = [[2022011,10], [2000005,50], [2022273,10], [2022179,3]]; - -var status; +var status = -1; function start() { status = -1; action(1, 0, 0); } -function action(mode, type, selection) { - if (mode == -1 || mode == 0) { - cm.sendOk("Goodbye then."); - cm.dispose(); - return; - } else if (mode == 1) { +function action(mode, type, selection) { + if (mode == 1) { status++; } else { - status--; + cm.dispose(); + return; } - if (status == 0) { - var msg = "Hello I exchange Onyx Chest for Bride and Groom and the Onyx Chest for prizes!#b"; - var choice1 = new Array("I have an Onyx Chest for Bride and Groom", "I have an Onyx Chest"); - for (var i = 0; i < choice1.length; i++) { - msg += "\r\n#L" + i + "#" + choice1[i] + "#l"; - } - cm.sendSimple(msg); - } else if (status == 1) { - if (selection == 0) { - if (cm.haveItem(4031424)) { - if (cm.getPlayer().isMarried()) { // thanks MedicOP for solving an issue here - if(cm.getInventory(2).getNextFreeSlot() >= 0) { - var rand = Math.floor(Math.random() * bgPrizes.length); - cm.gainItem(bgPrizes[rand][0], bgPrizes[rand][1]); - - cm.gainItem(4031424,-1); - cm.dispose(); - } else { - cm.sendOk("You don't have a free USE slot right now."); - cm.dispose(); - } - } else { - cm.sendOk("You must be married to claim the prize for this box."); - cm.dispose(); - } - } else { - cm.sendOk("You don't have an Onyx Chest for Bride and Groom."); - cm.dispose(); - } - } else if (selection == 1) { - if (cm.haveItem(4031423)) { - if(cm.getInventory(2).getNextFreeSlot() >= 0) { - var rand = Math.floor(Math.random() * cmPrizes.length); - cm.gainItem(cmPrizes[rand][0], cmPrizes[rand][1]); - - cm.gainItem(4031423,-1); - cm.dispose(); - } else { - cm.sendOk("You don't have a free USE slot right now."); - cm.dispose(); - } - } else { - cm.sendOk("You don't have an Onyx Chest."); - cm.dispose(); - } - } + cm.enviarLista(); + cm.dispose(); } -} +} \ No newline at end of file diff --git a/scripts/npc/cpqchallenge.js b/scripts/npc/cpqchallenge.js new file mode 100644 index 0000000000..2a1fe89c04 --- /dev/null +++ b/scripts/npc/cpqchallenge.js @@ -0,0 +1,54 @@ +/* global cm */ + +var status = 0; +var party; + +function start(chrs) { + status = -1; + party = chrs; + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.getChar().setChallenged(false); + cm.dispose(); + } else { + if (mode == 0) { + cm.sendOk("Come back once you have thought about it some more."); + cm.getChar().setChallenged(false); + cm.dispose(); + return; + } + } + if (mode == -1) + cm.dispose(); + else { + if (mode == 1) + status++; + else + status--; + if (status == 0) { + if (cm.getParty().getMembers().size() == party.size()) { + cm.getPlayer().setChallenged(true); + var snd = ""; + for (var i = 0; i < party.size(); i++) + snd += "#bNome: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + party.get(i).getJobNameById(party.get(i).getJobId()) + "#k\r\n\r\n"; + cm.sendAcceptDecline(snd + "Gostaria de lutar contra este grupo no Festival de Monstros?"); + } else { + return; + } + } else if (status == 1) { + var ch = cm.getChrById(party.get(0).getId()); + if (party.size() == cm.getParty().getMembers().size()) { + cm.startCPQ(ch, ch.getMapId() + 1); + ch.getParty().setEnemy(cm.getPlayer().getParty()); + cm.getChar().getParty().setEnemy(ch.getParty()); + cm.getChar().setChallenged(false); + } else { + cm.sendOk("O numero de players entre os times não esta igual."); + } + cm.dispose(); + } + } +} \ No newline at end of file diff --git a/scripts/npc/cpqchallenge2.js b/scripts/npc/cpqchallenge2.js new file mode 100644 index 0000000000..8795e8467a --- /dev/null +++ b/scripts/npc/cpqchallenge2.js @@ -0,0 +1,48 @@ +var status = 0; +var party; + +function start(chrs) { + status = -1; + party = chrs; + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == -1) { + cm.getChar().setChallenged(false); + cm.dispose(); + } else { + if (mode == 0) { + cm.sendOk("Come back once you have thought about it some more."); + cm.getChar().setChallenged(false); + cm.dispose(); + return; + } + } + if (mode == -1) + cm.dispose(); + else { + if (mode == 1) + status++; + else + status--; + if (status == 0) { + if (cm.getParty().getMembers().size() == party.size()) { + cm.getPlayer().setChallenged(true); + var snd = ""; + for (var i = 0; i < party.size(); i++) + snd += "#bNome: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + party.get(i).getJobNameById(party.get(i).getJobId()) + "#k\r\n\r\n"; + cm.sendAcceptDecline(snd + "Gostaria de lutar contra este grupo no Festival de Monstros?"); + } else { + return; + } + } else if (status == 1) { + var ch = cm.getChrById(party.get(0).getId()); + cm.startCPQ2(ch, ch.getMapId() + 1); + ch.getParty().setEnemy(cm.getPlayer().getParty()); + cm.getChar().getParty().setEnemy(ch.getParty()); + cm.getChar().setChallenged(false); + cm.dispose(); + } + } +} \ No newline at end of file diff --git a/scripts/portal/MC2revive.js b/scripts/portal/MC2revive.js new file mode 100644 index 0000000000..07e4002729 --- /dev/null +++ b/scripts/portal/MC2revive.js @@ -0,0 +1,8 @@ +function enter(pi) { + if ( pi.getPlayer().getTeam() == 0 ) { + pi.warp( pi.getMapId() - 100); + } else { + pi.warp( pi.getMapId() - 100); + } + return true; +} \ No newline at end of file diff --git a/scripts/portal/MCRevive1.js b/scripts/portal/MCRevive1.js new file mode 100644 index 0000000000..6b83b15910 --- /dev/null +++ b/scripts/portal/MCRevive1.js @@ -0,0 +1,10 @@ +importPackage(Packages.server.maps); + +/* + [CelticMS] Monster Carnival Reviving Field 1 + */ + +function enter(pi) { + pi.warp(980000101, 0); + return true; +} diff --git a/scripts/portal/MCRevive2.js b/scripts/portal/MCRevive2.js new file mode 100644 index 0000000000..333958c6d2 --- /dev/null +++ b/scripts/portal/MCRevive2.js @@ -0,0 +1,10 @@ +importPackage(Packages.server.maps); + +/* + [CelticMS] Monster Carnival Reviving Field 1 + */ + +function enter(pi) { + pi.warp(980000201, 0); + return true; +} diff --git a/scripts/portal/MCRevive3.js b/scripts/portal/MCRevive3.js new file mode 100644 index 0000000000..2ec50bacda --- /dev/null +++ b/scripts/portal/MCRevive3.js @@ -0,0 +1,19 @@ +importPackage(Packages.server.maps); + +/* +[CelticMS] Monster Carnival Reviving Field 1 +*/ + +function enter(pi) { + var portal = 0; + switch (pi.getPlayer().getTeam()) { + case 0: + portal = 4; + break; + case 1: + portal = 3; + break; + } + pi.warp(980000301, portal); + return true; +} diff --git a/scripts/portal/MCRevive4.js b/scripts/portal/MCRevive4.js new file mode 100644 index 0000000000..95fc0f1ad7 --- /dev/null +++ b/scripts/portal/MCRevive4.js @@ -0,0 +1,19 @@ +importPackage(Packages.server.maps); + +/* +[CelticMS] Monster Carnival Reviving Field 1 +*/ + +function enter(pi) { + var portal = 0; + switch (pi.getPlayer().getTeam()) { + case 0: + portal = 4; + break; + case 1: + portal = 3; + break; + } + pi.warp(980000401, portal); + return true; +} diff --git a/scripts/portal/MCRevive5.js b/scripts/portal/MCRevive5.js new file mode 100644 index 0000000000..7ced4ab4be --- /dev/null +++ b/scripts/portal/MCRevive5.js @@ -0,0 +1,10 @@ +importPackage(Packages.server.maps); + +/* +[CelticMS] Monster Carnival Reviving Field 1 +*/ + +function enter(pi) { + pi.warp(980000501, 0); + return true; +} diff --git a/scripts/portal/MCRevive6.js b/scripts/portal/MCRevive6.js new file mode 100644 index 0000000000..26c1a63ca0 --- /dev/null +++ b/scripts/portal/MCRevive6.js @@ -0,0 +1,10 @@ +importPackage(Packages.server.maps); + +/* +[CelticMS] Monster Carnival Reviving Field 1 +*/ + +function enter(pi) { + pi.warp(980000601, 0); + return true; +} diff --git a/scripts/portal/mc_out.js b/scripts/portal/mc_out.js index 28ab17cf5b..cc38a8f14b 100644 --- a/scripts/portal/mc_out.js +++ b/scripts/portal/mc_out.js @@ -1,28 +1,35 @@ /* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + 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 . + */ - 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. +importPackage(Packages.server.maps); - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ /* -Author: kevintjuh93 -*/ + */ function enter(pi) { - pi.playPortalSound(); pi.warp(pi.getPlayer().getSavedLocation("MIRROR")); + var returnMap = pi.getPlayer().getSavedLocation("MONSTER_CARNIVAL"); + if (returnMap < 0) { + returnMap = 102000000; // Just Incase there is no saved location. + } + var target = pi.getPlayer().getClient().getChannelServer().getMapFactory().getMap(returnMap); + pi.getPlayer().changeMap(target); return true; } \ No newline at end of file diff --git a/scripts/reactor/9980000.js b/scripts/reactor/9980000.js index 2524923a6e..278c67dfea 100644 --- a/scripts/reactor/9980000.js +++ b/scripts/reactor/9980000.js @@ -1,28 +1,3 @@ -/* - * 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 . - */ - -/* -@Author kevintjuh93 -*/ - function act() { - rm.getReactor().removeMonsterStatus(); + rm.dispelAllMonsters(parseInt(rm.getReactor().getName().substring(1,2)), parseInt(rm.getReactor().getName().substring(0,1))); } \ No newline at end of file diff --git a/scripts/reactor/9980001.js b/scripts/reactor/9980001.js index 2524923a6e..278c67dfea 100644 --- a/scripts/reactor/9980001.js +++ b/scripts/reactor/9980001.js @@ -1,28 +1,3 @@ -/* - * 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 . - */ - -/* -@Author kevintjuh93 -*/ - function act() { - rm.getReactor().removeMonsterStatus(); + rm.dispelAllMonsters(parseInt(rm.getReactor().getName().substring(1,2)), parseInt(rm.getReactor().getName().substring(0,1))); } \ No newline at end of file diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index a481d7c72a..b36adb2f85 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -98,8 +98,6 @@ import server.life.MaplePlayerNPC; import server.life.MonsterDropEntry; import server.maps.SavedLocation; import server.maps.SavedLocationType; -import server.partyquest.MonsterCarnival; -import server.partyquest.MonsterCarnivalParty; import server.partyquest.PartyQuest; import server.quest.MapleQuest; import tools.DatabaseConnection; @@ -128,6 +126,7 @@ import client.newyear.NewYearCardRecord; import constants.ExpTable; import constants.GameConstants; import constants.ItemConstants; +import constants.LinguaConstants; import constants.ServerConstants; import constants.skills.Aran; import constants.skills.Beginner; @@ -163,14 +162,16 @@ import server.life.MobSkillFactory; import server.maps.MapleMapItem; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; +import server.partyquest.MonsterCarnival; public class MapleCharacter extends AbstractMapleCharacterObject { + private static final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); private static final String LEVEL_200 = "[Congrats] %s has reached Level %d! Congratulate %s on such an amazing achievement!"; private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay", "nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm", "operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "yata", "AsiaSoft", "henesys"}; - + private int world; private int accountid, id, level; private int rank, rankMove, jobRank, jobRankMove; @@ -273,6 +274,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private ScheduledFuture extraRecoveryTask = null; private ScheduledFuture chairRecoveryTask = null; private ScheduledFuture pendantOfSpirit = null; //1122017 + public ScheduledFuture timer; private Lock chrLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CHR, true); private Lock evtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EVT, true); private Lock petLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PET, true); @@ -318,14 +320,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private int banishSp = -1; private long banishTime = 0; private long lastExpGainTime; - + private MapleCharacter() { super.setListener(new AbstractCharacterListener() { @Override public void onHpChanged(int oldHp) { hpChangeAction(oldHp); } - + @Override public void onHpmpPoolUpdate() { List> hpmpupdate = recalcLocalStats(); @@ -343,7 +345,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { statUpdates.put(MapleStat.MP, mp); } } - + @Override public void onAnnounceStatPoolUpdate() { List> statup = new ArrayList<>(8); @@ -354,13 +356,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { announce(MaplePacketCreator.updatePlayerStats(statup, true, MapleCharacter.this)); } }); - + useCS = false; - + setStance(0); inventory = new MapleInventory[MapleInventoryType.values().length]; savedLocations = new SavedLocation[SavedLocationType.values().length]; - + for (MapleInventoryType type : MapleInventoryType.values()) { byte b = 24; if (type == MapleInventoryType.CASH) { @@ -369,48 +371,46 @@ public class MapleCharacter extends AbstractMapleCharacterObject { inventory[type.ordinal()] = new MapleInventory(this, type, (byte) b); } inventory[MapleInventoryType.CANHOLD.ordinal()] = new MapleInventoryProof(this); - + for (int i = 0; i < SavedLocationType.values().length; i++) { savedLocations[i] = null; } quests = new LinkedHashMap<>(); setPosition(new Point(0, 0)); - + petLootCd = Server.getInstance().getCurrentTime(); } - + private static MapleJob getJobStyleInternal(int jobid, byte opt) { int jobtype = jobid / 100; - - if(jobtype == MapleJob.WARRIOR.getId() / 100 || jobtype == MapleJob.DAWNWARRIOR1.getId() / 100 || jobtype == MapleJob.ARAN1.getId() / 100) { - return(MapleJob.WARRIOR); + + if (jobtype == MapleJob.WARRIOR.getId() / 100 || jobtype == MapleJob.DAWNWARRIOR1.getId() / 100 || jobtype == MapleJob.ARAN1.getId() / 100) { + return (MapleJob.WARRIOR); + } else if (jobtype == MapleJob.MAGICIAN.getId() / 100 || jobtype == MapleJob.BLAZEWIZARD1.getId() / 100 || jobtype == MapleJob.EVAN1.getId() / 100) { + return (MapleJob.MAGICIAN); + } else if (jobtype == MapleJob.BOWMAN.getId() / 100 || jobtype == MapleJob.WINDARCHER1.getId() / 100) { + if (jobid / 10 == MapleJob.CROSSBOWMAN.getId() / 10) { + return (MapleJob.CROSSBOWMAN); + } else { + return (MapleJob.BOWMAN); + } + } else if (jobtype == MapleJob.THIEF.getId() / 100 || jobtype == MapleJob.NIGHTWALKER1.getId() / 100) { + return (MapleJob.THIEF); + } else if (jobtype == MapleJob.PIRATE.getId() / 100 || jobtype == MapleJob.THUNDERBREAKER1.getId() / 100) { + if (opt == (byte) 0x80) { + return (MapleJob.BRAWLER); + } else { + return (MapleJob.GUNSLINGER); + } } - - else if(jobtype == MapleJob.MAGICIAN.getId() / 100 || jobtype == MapleJob.BLAZEWIZARD1.getId() / 100 || jobtype == MapleJob.EVAN1.getId() / 100) { - return(MapleJob.MAGICIAN); - } - - else if(jobtype == MapleJob.BOWMAN.getId() / 100 || jobtype == MapleJob.WINDARCHER1.getId() / 100) { - if(jobid / 10 == MapleJob.CROSSBOWMAN.getId() / 10) return(MapleJob.CROSSBOWMAN); - else return(MapleJob.BOWMAN); - } - - else if(jobtype == MapleJob.THIEF.getId() / 100 || jobtype == MapleJob.NIGHTWALKER1.getId() / 100) { - return(MapleJob.THIEF); - } - - else if(jobtype == MapleJob.PIRATE.getId() / 100 || jobtype == MapleJob.THUNDERBREAKER1.getId() / 100) { - if(opt == (byte) 0x80) return(MapleJob.BRAWLER); - else return(MapleJob.GUNSLINGER); - } - - return(MapleJob.BEGINNER); + + return (MapleJob.BEGINNER); } - + public MapleJob getJobStyle(byte opt) { return getJobStyleInternal(this.getJob().getId(), opt); } - + public MapleJob getJobStyle() { return getJobStyle((byte) ((this.getStr() > this.getDex()) ? 0x80 : 0x40)); } @@ -437,28 +437,26 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.getInventory(MapleInventoryType.USE).setSlotLimit(24); ret.getInventory(MapleInventoryType.SETUP).setSlotLimit(24); ret.getInventory(MapleInventoryType.ETC).setSlotLimit(24); - + // Select a keybinding method int[] selectedKey; int[] selectedType; int[] selectedAction; - - if(ServerConstants.USE_CUSTOM_KEYSET) { + + if (ServerConstants.USE_CUSTOM_KEYSET) { selectedKey = GameConstants.getCustomKey(true); selectedType = GameConstants.getCustomType(true); selectedAction = GameConstants.getCustomAction(true); - } - else { + } else { selectedKey = GameConstants.getCustomKey(false); selectedType = GameConstants.getCustomType(false); selectedAction = GameConstants.getCustomAction(false); } - + for (int i = 0; i < selectedKey.length; i++) { ret.keymap.put(selectedKey[i], new MapleKeyBinding(selectedType[i], selectedAction[i])); } - - + //to fix the map 0 lol for (int i = 0; i < 5; i++) { ret.trockmaps.add(999999999); @@ -469,66 +467,66 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return ret; } - + public boolean isLoggedinWorld() { return this.isLoggedin() && !this.isAwayFromWorld(); } - + public boolean isAwayFromWorld() { return awayFromWorld.get(); } - + public void setEnteredChannelWorld() { awayFromWorld.set(false); client.getChannelServer().removePlayerAway(id); } - + public void setAwayFromChannelWorld() { setAwayFromChannelWorld(false); } - + public void setDisconnectedFromChannelWorld() { setAwayFromChannelWorld(true); } - + private void setAwayFromChannelWorld(boolean disconnect) { awayFromWorld.set(true); - - if(!disconnect) { + + if (!disconnect) { client.getChannelServer().insertPlayerAway(id); } else { client.getChannelServer().removePlayerAway(id); } } - + public long getPetLootCd() { return petLootCd; } - + public void setPetLootCd(long cd) { petLootCd = cd; } - + public boolean getCS() { return useCS; } - + public void setCS(boolean cs) { useCS = cs; } - + public long getNpcCooldown() { return npcCd; } - + public void setNpcCooldown(long d) { npcCd = d; } - + public void setOwlSearch(int id) { owlSearch = id; } - + public int getOwlSearch() { return owlSearch; } @@ -559,8 +557,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return ring; } } - - if(marriageRing != null) { + + if (marriageRing != null) { if (marriageRing.getRingId() == id) { return marriageRing; } @@ -568,43 +566,43 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return null; } - + public int getMarriageItemId() { return marriageItemid; } - + public void setMarriageItemId(int itemid) { marriageItemid = itemid; } - + public int getPartnerId() { return partnerId; } - + public void setPartnerId(int partnerid) { partnerId = partnerid; } - + public int getRelationshipId() { return getWorldServer().getRelationshipId(id); } - + public boolean isMarried() { return marriageRing != null && partnerId > 0; } - + public boolean hasJustMarried() { EventInstanceManager eim = getEventInstance(); - if(eim != null) { + if (eim != null) { String prop = eim.getProperty("groomId"); - - if(prop != null) { - if((Integer.parseInt(prop) == id || eim.getIntProperty("brideId") == id) && (mapid == 680000110 || mapid == 680000210)) { + + if (prop != null) { + if ((Integer.parseInt(prop) == id || eim.getIntProperty("brideId") == id) && (mapid == 680000110 || mapid == 680000210)) { return true; } } } - + return false; } @@ -619,7 +617,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return pts; } - + public void addFame(int famechange) { this.fame += famechange; } @@ -627,15 +625,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void addFriendshipRing(MapleRing r) { friendshipRings.add(r); } - + public void addMarriageRing(MapleRing r) { marriageRing = r; } - + public void addMesosTraded(int gain) { this.mesosTraded += gain; } - + public void addPet(MaplePet pet) { petLock.lock(); try { @@ -649,10 +647,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { petLock.unlock(); } } - + public void addSummon(int id, MapleSummon summon) { summons.put(id, summon); - + if (summon.isPuppet()) { map.addPlayerPuppet(this); } @@ -684,7 +682,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { Connection con = null; try { con = DatabaseConnection.getConnection(); - + if (id.matches("/[0-9]{1,3}\\..*")) { ps = con.prepareStatement("INSERT INTO ipbans VALUES (DEFAULT, ?)"); ps.setString(1, id); @@ -702,18 +700,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setString(1, id); rs = ps.executeQuery(); if (rs.next()) { - Connection con2 = DatabaseConnection.getConnection(); + Connection con2 = DatabaseConnection.getConnection(); - try (PreparedStatement psb = con2.prepareStatement("UPDATE accounts SET banned = 1, banreason = ? WHERE id = ?")) { - psb.setString(1, reason); - psb.setInt(2, rs.getInt(1)); - psb.executeUpdate(); - } finally { - con2.close(); - } - ret = true; + try (PreparedStatement psb = con2.prepareStatement("UPDATE accounts SET banned = 1, banreason = ? WHERE id = ?")) { + psb.setString(1, reason); + psb.setInt(2, rs.getInt(1)); + psb.executeUpdate(); + } finally { + con2.close(); + } + ret = true; } - + rs.close(); ps.close(); con.close(); @@ -725,7 +723,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (ps != null && !ps.isClosed()) { ps.close(); } - if (rs != null && !rs.isClosed()) { + if (rs != null && !rs.isClosed()) { rs.close(); } if (con != null && !con.isClosed()) { @@ -804,15 +802,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setLastMobCount(byte count) { lastmobcount = count; } - + public boolean cannotEnterCashShop() { return blockCashShop; } - + public void toggleBlockCashShop() { blockCashShop = !blockCashShop; } - + public void toggleExpGain() { allowExpGain = !allowExpGain; } @@ -820,7 +818,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setClient(MapleClient c) { this.client = c; } - + public void newClient(MapleClient c) { this.loggedIn = true; c.setAccountName(this.client.getAccountName());//No null's for accountName @@ -851,8 +849,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { List dsstat = Collections.singletonList(MapleBuffStat.DARKSIGHT); getMap().broadcastGMMessage(this, MaplePacketCreator.cancelForeignBuff(id, dsstat), false); getMap().broadcastSpawnPlayerMapObjectMessage(this, this, false); - - for(MapleSummon ms: this.getSummonsValues()) { + + for (MapleSummon ms : this.getSummonsValues()) { getMap().broadcastNONGMMessage(this, MaplePacketCreator.spawnSummon(ms, false), false); } } else { @@ -868,7 +866,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { announce(MaplePacketCreator.enableActions()); } } - + public void Hide(boolean hide) { Hide(hide, false); } @@ -910,22 +908,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public boolean canDoor() { return canDoor; } - + public void setHasSandboxItem() { hasSandboxItem = true; } - + public void removeSandboxItems() { // sandbox idea thanks to Morty - if(!hasSandboxItem) return; - + if (!hasSandboxItem) { + return; + } + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - for(MapleInventoryType invType : MapleInventoryType.values()) { + for (MapleInventoryType invType : MapleInventoryType.values()) { MapleInventory inv = this.getInventory(invType); - + inv.lockInventory(); try { - for(Item item : new ArrayList<>(inv.list())) { - if(MapleInventoryManipulator.isSandboxItem(item)) { + for (Item item : new ArrayList<>(inv.list())) { + if (MapleInventoryManipulator.isSandboxItem(item)) { MapleInventoryManipulator.removeFromSlot(client, invType, item.getPosition(), item.getQuantity(), false); dropMessage(5, "[" + ii.getName(item.getItemId()) + "] has passed its trial conditions and will be removed from your inventory."); } @@ -934,7 +934,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { inv.unlockInventory(); } } - + hasSandboxItem = false; } @@ -1024,8 +1024,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (skillId != 0) { Skill skill = SkillFactory.getSkill(skillId); final int skilllevel = getSkillLevel(skill); - if(skilllevel > 0) continue; - + if (skilllevel > 0) { + continue; + } + changeSkillLevel(skill, (byte) 0, 10, -1); } } @@ -1035,9 +1037,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (newJob == null) { return;//the fuck you doing idiot! } - + this.job = newJob; - + int spGain = 1; if (GameConstants.hasSPTable(newJob)) { spGain += 2; @@ -1045,26 +1047,26 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (newJob.getId() % 10 == 2) { spGain += 2; } - + if (ServerConstants.USE_ENFORCE_JOB_SP_RANGE) { spGain = getChangedJobSp(newJob); } } - + if (spGain > 0) { gainSp(spGain, GameConstants.getSkillBook(newJob.getId()), true); } - + if (newJob.getId() % 10 > 1) { gainAp(5, true); } - + if (!isGM()) { for (byte i = 1; i < 5; i++) { gainSlots(i, 4, true); } } - + int addhp = 0, addmp = 0; int job_ = job.getId() % 1000; // lame temp "fix" if (job_ == 100) { // 1st warrior @@ -1082,21 +1084,20 @@ public class MapleCharacter extends AbstractMapleCharacterObject { addhp += Randomizer.rand(300, 350); addmp += Randomizer.rand(150, 200); } - + /* - //aran perks? - int newJobId = newJob.getId(); - if(newJobId == 2100) { // become aran1 - addhp += 275; - addmp += 15; - } else if(newJobId == 2110) { // become aran2 - addmp += 275; - } else if(newJobId == 2111) { // become aran3 - addhp += 275; - addmp += 275; - } - */ - + //aran perks? + int newJobId = newJob.getId(); + if(newJobId == 2100) { // become aran1 + addhp += 275; + addmp += 15; + } else if(newJobId == 2110) { // become aran2 + addmp += 275; + } else if(newJobId == 2111) { // become aran3 + addhp += 275; + addmp += 275; + } + */ effLock.lock(); statWlock.lock(); try { @@ -1116,57 +1117,57 @@ public class MapleCharacter extends AbstractMapleCharacterObject { statWlock.unlock(); effLock.unlock(); } - + silentPartyUpdate(); - + if (dragon != null) { getMap().broadcastMessage(MaplePacketCreator.removeDragon(dragon.getObjectId())); dragon = null; } - + if (this.guildid > 0) { getGuild().broadcast(MaplePacketCreator.jobMessage(0, job.getId(), name), this.getId()); } setMasteries(this.job.getId()); guildUpdate(); - + getMap().broadcastMessage(this, MaplePacketCreator.showForeignEffect(this.getId(), 8), false); - + if (GameConstants.hasSPTable(newJob) && newJob.getId() != 2001) { if (getBuffedValue(MapleBuffStat.MONSTER_RIDING) != null) { cancelBuffStats(MapleBuffStat.MONSTER_RIDING); } createDragon(); } - + if (ServerConstants.USE_ANNOUNCE_CHANGEJOB) { if (!this.isGM()) { broadcastAcquaintances(6, "[" + GameConstants.ordinal(GameConstants.getJobBranch(newJob)) + " Job] " + name + " has just become a " + newJob.name() + "."); } } } - + public void broadcastAcquaintances(int type, String message) { broadcastAcquaintances(MaplePacketCreator.serverNotice(type, message)); } - + public void broadcastAcquaintances(byte[] packet) { buddylist.broadcast(packet, getWorldServer().getPlayerStorage()); - - if(family != null) { + + if (family != null) { //family.broadcast(packet, id); not yet implemented } - + MapleGuild guild = getGuild(); - if(guild != null) { + if (guild != null) { guild.broadcast(packet, id); } - + /* - if(partnerid > 0) { - partner.announce(packet); not yet implemented - } - */ + if(partnerid > 0) { + partner.announce(packet); not yet implemented + } + */ announce(packet); } @@ -1177,99 +1178,107 @@ public class MapleCharacter extends AbstractMapleCharacterObject { keymap.remove(Integer.valueOf(key)); } } - + public void broadcastStance(int newStance) { setStance(newStance); broadcastStance(); } - + public void broadcastStance() { map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, this.getIdleMovement()), false); } - + public MapleMap getWarpMap(int map) { - MapleMap target; + MapleMap target; EventInstanceManager eim = getEventInstance(); - if (eim == null) { + if (eim == null) { target = client.getChannelServer().getMapFactory().getMap(map); - } else { + } else { target = eim.getMapInstance(map); - } - return target; + } + return target; } - + // for use ONLY inside OnUserEnter map scripts that requires a player to change map while still moving between maps. public void warpAhead(int map) { newWarpMap = map; } - + private void eventChangedMap(int map) { EventInstanceManager eim = getEventInstance(); - if (eim != null) eim.changedMap(this, map); + if (eim != null) { + eim.changedMap(this, map); + } } - + private void eventAfterChangedMap(int map) { EventInstanceManager eim = getEventInstance(); - if (eim != null) eim.afterChangedMap(this, map); + if (eim != null) { + eim.afterChangedMap(this, map); + } } - + public boolean canRecoverLastBanish() { return System.currentTimeMillis() - this.banishTime < 5 * 60 * 1000; } - + public Pair getLastBanishData() { return new Pair<>(this.banishMap, this.banishSp); } - + public void clearBanishPlayerData() { this.banishMap = -1; this.banishSp = -1; this.banishTime = 0; } - + public void setBanishPlayerData(int banishMap, int banishSp, long banishTime) { this.banishMap = banishMap; this.banishSp = banishSp; this.banishTime = banishTime; } - + public void changeMapBanish(int mapid, String portal, String msg) { - if(ServerConstants.USE_SPIKES_AVOID_BANISH) { - for(Item it: this.getInventory(MapleInventoryType.EQUIPPED).list()) { - if((it.getFlag() & ItemConstants.SPIKES) == ItemConstants.SPIKES) return; + if (ServerConstants.USE_SPIKES_AVOID_BANISH) { + for (Item it : this.getInventory(MapleInventoryType.EQUIPPED).list()) { + if ((it.getFlag() & ItemConstants.SPIKES) == ItemConstants.SPIKES) { + return; + } } } - + int banMap = this.getMapId(); int banSp = this.getMap().findClosestPlayerSpawnpoint(this.getPosition()).getId(); long banTime = System.currentTimeMillis(); - - if (msg != null) dropMessage(5, msg); - + + if (msg != null) { + dropMessage(5, msg); + } + MapleMap map_ = getWarpMap(mapid); MaplePortal portal_ = map_.getPortal(portal); changeMap(map_, portal_ != null ? portal_ : map_.getRandomPlayerSpawnpoint()); - + setBanishPlayerData(banMap, banSp, banTime); } public void changeMap(int map) { MapleMap warpMap; EventInstanceManager eim = getEventInstance(); - + if (eim != null) { warpMap = eim.getMapInstance(map); } else { warpMap = client.getChannelServer().getMapFactory().getMap(map); } - + changeMap(warpMap, warpMap.getRandomPlayerSpawnpoint()); } public void changeMap(int map, int portal) { MapleMap warpMap; EventInstanceManager eim = getEventInstance(); - + if (eim != null) { warpMap = eim.getMapInstance(map); } else { @@ -1282,7 +1291,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void changeMap(int map, String portal) { MapleMap warpMap; EventInstanceManager eim = getEventInstance(); - + if (eim != null) { warpMap = eim.getMapInstance(map); } else { @@ -1295,7 +1304,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void changeMap(int map, MaplePortal portal) { MapleMap warpMap; EventInstanceManager eim = getEventInstance(); - + if (eim != null) { warpMap = eim.getMapInstance(map); } else { @@ -1312,250 +1321,256 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void changeMap(MapleMap to, int portal) { changeMap(to, to.getPortal(portal)); } - + public void changeMap(final MapleMap target, final MaplePortal pto) { canWarpCounter++; - + eventChangedMap(target.getId()); // player can be dropped from an event here, hence the new warping target. MapleMap to = getWarpMap(target.getId()); changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this)); canWarpMap = false; - + canWarpCounter--; - if(canWarpCounter == 0) canWarpMap = true; - + if (canWarpCounter == 0) { + canWarpMap = true; + } + eventAfterChangedMap(this.getMapId()); } public void changeMap(final MapleMap target, final Point pos) { canWarpCounter++; - + eventChangedMap(target.getId()); MapleMap to = getWarpMap(target.getId()); changeMapInternal(to, pos, MaplePacketCreator.getWarpToMap(to, 0x80, pos, this)); canWarpMap = false; - + canWarpCounter--; - if(canWarpCounter == 0) canWarpMap = true; - + if (canWarpCounter == 0) { + canWarpMap = true; + } + eventAfterChangedMap(this.getMapId()); } - + public void forceChangeMap(final MapleMap target, final MaplePortal pto) { // will actually enter the map given as parameter, regardless of being an eventmap or whatnot - + canWarpCounter++; eventChangedMap(999999999); - + EventInstanceManager mapEim = target.getEventInstance(); - if(mapEim != null) { + if (mapEim != null) { EventInstanceManager playerEim = this.getEventInstance(); - if(playerEim != null) { + if (playerEim != null) { playerEim.exitPlayer(this); - if(playerEim.getPlayerCount() == 0) { + if (playerEim.getPlayerCount() == 0) { playerEim.dispose(); } } - + // thanks Thora for finding an issue with players not being actually warped into the target event map (rather sent to the event starting map) mapEim.registerPlayer(this, false); } - + MapleMap to = target; // warps directly to the target intead of the target's map id, this allows GMs to patrol players inside instances. changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this)); canWarpMap = false; - + canWarpCounter--; - if(canWarpCounter == 0) canWarpMap = true; - + if (canWarpCounter == 0) { + canWarpMap = true; + } + eventAfterChangedMap(this.getMapId()); } - + private boolean buffMapProtection() { int thisMapid = mapid; int returnMapid = client.getChannelServer().getMapFactory().getMap(thisMapid).getReturnMapId(); - + effLock.lock(); chrLock.lock(); try { - for(Entry mbs : effects.entrySet()) { - if(mbs.getKey() == MapleBuffStat.MAP_PROTECTION) { - byte value = (byte)mbs.getValue().value; - - if(value == 1 && ((returnMapid == 211000000 && thisMapid != 200082300) || returnMapid == 193000000)) { + for (Entry mbs : effects.entrySet()) { + if (mbs.getKey() == MapleBuffStat.MAP_PROTECTION) { + byte value = (byte) mbs.getValue().value; + + if (value == 1 && ((returnMapid == 211000000 && thisMapid != 200082300) || returnMapid == 193000000)) { return true; //protection from cold - } else if(value == 2 && (returnMapid == 230000000 || thisMapid == 200082300)) { + } else if (value == 2 && (returnMapid == 230000000 || thisMapid == 200082300)) { return true; //breathing underwater } else { return false; } } - } + } } finally { chrLock.unlock(); effLock.unlock(); } - - for(Item it: this.getInventory(MapleInventoryType.EQUIPPED).list()) { - if((it.getFlag() & ItemConstants.COLD) == ItemConstants.COLD && ((returnMapid == 211000000 && thisMapid != 200082300) || returnMapid == 193000000)) { + + for (Item it : this.getInventory(MapleInventoryType.EQUIPPED).list()) { + if ((it.getFlag() & ItemConstants.COLD) == ItemConstants.COLD && ((returnMapid == 211000000 && thisMapid != 200082300) || returnMapid == 193000000)) { return true; //protection from cold } } - + return false; } - + public List getLastVisitedMapids() { List lastVisited = new ArrayList<>(5); - + petLock.lock(); try { - for(WeakReference lv : lastVisitedMaps) { + for (WeakReference lv : lastVisitedMaps) { MapleMap lvm = lv.get(); - - if(lvm != null) { + + if (lvm != null) { lastVisited.add(lvm.getId()); } } } finally { petLock.unlock(); } - + return lastVisited; } - + public void partyOperationUpdate(MapleParty party, List exPartyMembers) { List> mapids; - + petLock.lock(); try { mapids = new LinkedList<>(lastVisitedMaps); } finally { petLock.unlock(); } - + List partyMembers = new LinkedList<>(); - for(MapleCharacter mc : (exPartyMembers != null) ? exPartyMembers : this.getPartyMembers()) { - if(mc.isLoggedinWorld()) { + for (MapleCharacter mc : (exPartyMembers != null) ? exPartyMembers : this.getPartyMembers()) { + if (mc.isLoggedinWorld()) { partyMembers.add(mc); } } - + MapleCharacter partyLeaver = null; - if(exPartyMembers != null) { + if (exPartyMembers != null) { partyMembers.remove(this); partyLeaver = this; } - + int partyId = exPartyMembers != null ? 0 : this.getPartyId(); - for(WeakReference mapRef : mapids) { + for (WeakReference mapRef : mapids) { MapleMap mapObj = mapRef.get(); - - if(mapObj != null) { + + if (mapObj != null) { mapObj.updatePlayerItemDrops(partyId, id, partyMembers, partyLeaver); } } - + updatePartyTownDoors(party, this, partyLeaver, partyMembers); } - + private static void addPartyPlayerDoor(MapleCharacter target) { MapleDoor targetDoor = target.getPlayerDoor(); - if(targetDoor != null) { + if (targetDoor != null) { target.applyPartyDoor(targetDoor, true); } } - + private static void removePartyPlayerDoor(MapleParty party, MapleCharacter target) { target.removePartyDoor(party); } - + private static void updatePartyTownDoors(MapleParty party, MapleCharacter target, MapleCharacter partyLeaver, List partyMembers) { - if(partyLeaver != null) { + if (partyLeaver != null) { removePartyPlayerDoor(party, target); } else { addPartyPlayerDoor(target); } - + Map partyDoors = null; - if(!partyMembers.isEmpty()) { + if (!partyMembers.isEmpty()) { partyDoors = party.getDoors(); - - for(MapleCharacter pchr : partyMembers) { + + for (MapleCharacter pchr : partyMembers) { MapleDoor door = partyDoors.get(pchr.getId()); - if(door != null) { + if (door != null) { door.updateDoorPortal(pchr); } } - - for(MapleDoor door : partyDoors.values()) { - for(MapleCharacter pchar : partyMembers) { + + for (MapleDoor door : partyDoors.values()) { + for (MapleCharacter pchar : partyMembers) { door.getTownDoor().sendDestroyData(pchar.getClient(), true); } } - - if(partyLeaver != null) { + + if (partyLeaver != null) { Collection leaverDoors = partyLeaver.getDoors(); - for(MapleDoor door : leaverDoors) { - for(MapleCharacter pchar : partyMembers) { + for (MapleDoor door : leaverDoors) { + for (MapleCharacter pchar : partyMembers) { door.getTownDoor().sendDestroyData(pchar.getClient(), true); } } } - + List histMembers = party.getMembersSortedByHistory(); - for(Integer chrid : histMembers) { + for (Integer chrid : histMembers) { MapleDoor door = partyDoors.get(chrid); - if(door != null) { - for(MapleCharacter pchar : partyMembers) { + if (door != null) { + for (MapleCharacter pchar : partyMembers) { door.getTownDoor().sendSpawnData(pchar.getClient()); } } } } - - if(partyLeaver != null) { + + if (partyLeaver != null) { Collection leaverDoors = partyLeaver.getDoors(); - - if(partyDoors != null) { - for(MapleDoor door : partyDoors.values()) { + + if (partyDoors != null) { + for (MapleDoor door : partyDoors.values()) { door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true); } } - - for(MapleDoor door : leaverDoors) { + + for (MapleDoor door : leaverDoors) { door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true); } - - for(MapleDoor door : leaverDoors) { + + for (MapleDoor door : leaverDoors) { door.updateDoorPortal(partyLeaver); door.getTownDoor().sendSpawnData(partyLeaver.getClient()); } } } - + private Integer getVisitedMapIndex(MapleMap map) { int idx = 0; - - for(WeakReference mapRef : lastVisitedMaps) { - if(map.equals(mapRef.get())) { + + for (WeakReference mapRef : lastVisitedMaps) { + if (map.equals(mapRef.get())) { return idx; } - + idx++; } - + return -1; } - + public void visitMap(MapleMap map) { petLock.lock(); try { int idx = getVisitedMapIndex(map); - - if(idx == -1) { - if(lastVisitedMaps.size() == ServerConstants.MAP_VISITED_SIZE) { + + if (idx == -1) { + if (lastVisitedMaps.size() == ServerConstants.MAP_VISITED_SIZE) { lastVisitedMaps.remove(0); } } else { @@ -1571,23 +1586,30 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public void notifyMapTransferToPartner(int mapid) { - if(partnerId > 0) { + if (partnerId > 0) { final MapleCharacter partner = getWorldServer().getPlayerStorage().getCharacterById(partnerId); - if(partner != null && !partner.isAwayFromWorld()) { + if (partner != null && !partner.isAwayFromWorld()) { partner.announce(Wedding.OnNotifyWeddingPartnerTransfer(id, mapid)); } } } private void changeMapInternal(final MapleMap to, final Point pos, final byte[] warpPacket) { - if(!canWarpMap) return; - + if (!canWarpMap) { + return; + } + this.mapTransitioning.set(true); - + this.unregisterChairBuff(); this.clearBanishPlayerData(); this.closePlayerInteractions(); - + + MapleParty e = null; + if (this.getParty() != null && this.getParty().getEnemy() != null) { + e = this.getParty().getEnemy(); + } + final MapleParty k = e; client.announce(warpPacket); map.removePlayer(this); if (client.getChannelServer().getPlayerStorage().getCharacterById(getId()) != null) { @@ -1595,7 +1617,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { setPosition(pos); map.addPlayer(this); visitMap(map); - + prtLock.lock(); try { if (party != null) { @@ -1606,26 +1628,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { prtLock.unlock(); } + if (MapleCharacter.this.getParty() != null) { + MapleCharacter.this.getParty().setEnemy(k); + } silentPartyUpdateInternal(getParty()); // EIM script calls inside - - if (getMap().getHPDec() > 0) resetHpDecreaseTask(); + + if (getMap().getHPDec() > 0) { + resetHpDecreaseTask(); + } } else { FilePrinter.printError(FilePrinter.MAPLE_MAP, "Character " + this.getName() + " got stuck when moving to map " + map.getId() + "."); } - + notifyMapTransferToPartner(map.getId()); - + //alas, new map has been specified when a warping was being processed... - if(newWarpMap != -1) { + if (newWarpMap != -1) { canWarpMap = true; - + int temp = newWarpMap; newWarpMap = -1; changeMap(temp); } else { // if this event map has a gate already opened, render it EventInstanceManager eim = getEventInstance(); - if(eim != null) { + if (eim != null) { eim.recoverOpenedGate(this, map.getId()); } @@ -1633,11 +1660,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { announce(MaplePacketCreator.environmentMoveList(map.getEnvironment().entrySet())); } } - + public boolean isChangingMaps() { return this.mapTransitioning.get(); } - + public void setMapTransitionComplete() { this.mapTransitioning.set(false); } @@ -1691,11 +1718,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { berserkSchedule = TimerManager.getInstance().register(new Runnable() { @Override public void run() { - if(awayFromWorld.get()) return; - + if (awayFromWorld.get()) { + return; + } + client.announce(MaplePacketCreator.showOwnBerserk(skilllevel, berserk)); - if(!isHidden) getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showBerserk(getId(), skilllevel, berserk), false); - else getMap().broadcastGMMessage(MapleCharacter.this, MaplePacketCreator.showBerserk(getId(), skilllevel, berserk), false); + if (!isHidden) { + getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showBerserk(getId(), skilllevel, berserk), false); + } else { + getMap().broadcastGMMessage(MapleCharacter.this, MaplePacketCreator.showBerserk(getId(), skilllevel, berserk), false); + } } }, 5000, 3000); } @@ -1719,7 +1751,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + public void stopControllingMonster(MapleMonster monster) { if (cpnLock.tryLock()) { try { @@ -1729,7 +1761,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + public int getNumControlledMonsters() { cpnLock.lock(); try { @@ -1738,7 +1770,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { cpnLock.unlock(); } } - + public Collection getControlledMonsters() { cpnLock.lock(); try { @@ -1747,10 +1779,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { cpnLock.unlock(); } } - + public void releaseControlledMonsters() { Collection controlledMonsters; - + cpnLock.lock(); try { controlledMonsters = new ArrayList<>(controlled); @@ -1758,22 +1790,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { cpnLock.unlock(); } - + for (MapleMonster monster : controlledMonsters) { monster.aggroRedirectController(); } } - + private boolean useItem(final int id) { if (id / 1000000 == 2) { if (ii.isConsumeOnPickup(id)) { if (ItemConstants.isPartyItem(id)) { List pchr = this.getPartyMembersOnSameMap(); - - if(!ItemConstants.isPartyAllcure(id)) { + + if (!ItemConstants.isPartyAllcure(id)) { MapleStatEffect mse = ii.getItemEffect(id); - - if(!pchr.isEmpty()) { + + if (!pchr.isEmpty()) { for (MapleCharacter mc : pchr) { mse.applyTo(mc); } @@ -1781,7 +1813,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { mse.applyTo(this); } } else { - if(!pchr.isEmpty()) { + if (!pchr.isEmpty()) { for (MapleCharacter mc : pchr) { mc.dispelDebuffs(); } @@ -1797,28 +1829,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return false; } - + public final void pickupItem(MapleMapObject ob) { pickupItem(ob, -1); } - + public final void pickupItem(MapleMapObject ob, int petIndex) { // yes, one picks the MapleMapObject, not the MapleMapItem if (ob == null) { // pet index refers to the one picking up the item return; } - + if (ob instanceof MapleMapItem) { MapleMapItem mapitem = (MapleMapItem) ob; if (System.currentTimeMillis() - mapitem.getDropTime() < 400 || !mapitem.canBePickedBy(this)) { client.announce(MaplePacketCreator.enableActions()); return; } - + List mpcs = new LinkedList<>(); - if (mapitem.getMeso() > 0 && !mapitem.isPickedUp()) { + if (mapitem.getMeso() > 0 && !mapitem.isPickedUp()) { mpcs = getPartyMembersOnSameMap(); } - + ScriptedItem itemScript = null; mapitem.lockItem(); try { @@ -1827,7 +1859,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { client.announce(MaplePacketCreator.enableActions()); return; } - + boolean isPet = petIndex > -1; final byte[] pickupPacket = MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), (isPet) ? 5 : 2, this.getId(), isPet, petIndex); @@ -1835,10 +1867,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { boolean hasSpaceInventory = true; if (mapitem.getItemId() == 4031865 || mapitem.getItemId() == 4031866 || mapitem.getMeso() > 0 || ii.isConsumeOnPickup(mapitem.getItemId()) || (hasSpaceInventory = MapleInventoryManipulator.checkSpace(client, mapitem.getItemId(), mItem.getQuantity(), mItem.getOwner()))) { int mapId = this.getMapId(); - + if ((mapId > 209000000 && mapId < 209000016) || (mapId >= 990000500 && mapId <= 990000502)) {//happyville trees and guild PQ if (!mapitem.isPlayerDrop() || mapitem.getDropper().getObjectId() == client.getPlayer().getObjectId()) { - if(mapitem.getMeso() > 0) { + if (mapitem.getMeso() > 0) { if (!mpcs.isEmpty()) { int mesosamm = mapitem.getMeso() / mpcs.size(); for (MapleCharacter partymem : mpcs) { @@ -1849,9 +1881,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } else { this.gainMeso(mapitem.getMeso(), true, true, false); } - + this.getMap().pickItemDrop(pickupPacket, mapitem); - } else if(mapitem.getItemId() == 4031865 || mapitem.getItemId() == 4031866) { + } else if (mapitem.getItemId() == 4031865 || mapitem.getItemId() == 4031866) { // Add NX to account, show effect and make item disappear int nxGain = mapitem.getItemId() == 4031865 ? 100 : 250; this.getCashShop().gainCash(1, nxGain); @@ -1873,13 +1905,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { client.announce(MaplePacketCreator.enableActions()); return; } - + if (!this.needQuestItem(mapitem.getQuest(), mapitem.getItemId())) { client.announce(MaplePacketCreator.showItemUnavailable()); client.announce(MaplePacketCreator.enableActions()); return; } - + if (mapitem.getMeso() > 0) { if (!mpcs.isEmpty()) { int mesosamm = mapitem.getMeso() / mpcs.size(); @@ -1901,11 +1933,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return; } } - } else if(mapitem.getItemId() == 4031865 || mapitem.getItemId() == 4031866) { + } else if (mapitem.getItemId() == 4031865 || mapitem.getItemId() == 4031866) { // Add NX to account, show effect and make item disappear int nxGain = mapitem.getItemId() == 4031865 ? 100 : 250; this.getCashShop().gainCash(1, nxGain); - + showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(1) + " NX)", 300); } else if (useItem(mItem.getItemId())) { if (mItem.getItemId() / 10000 == 238) { @@ -1918,16 +1950,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { client.announce(MaplePacketCreator.enableActions()); return; } - + this.getMap().pickItemDrop(pickupPacket, mapitem); - } else if(!hasSpaceInventory) { + } else if (!hasSpaceInventory) { client.announce(MaplePacketCreator.getInventoryFull()); client.announce(MaplePacketCreator.getShowInventoryFull()); } } finally { mapitem.unlockItem(); } - + if (itemScript != null) { ItemScriptManager ism = ItemScriptManager.getInstance(); ism.runItemScript(client, itemScript); @@ -1939,11 +1971,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public int countItem(int itemid) { return inventory[ItemConstants.getInventoryType(itemid).ordinal()].countById(itemid); } - + public boolean canHold(int itemid) { return canHold(itemid, 1); } - + public boolean canHold(int itemid, int quantity) { return client.getAbstractPlayerInteraction().canHold(itemid, quantity); } @@ -1952,18 +1984,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject { Integer bv = getBuffedValue(MapleBuffStat.MONSTER_RIDING); return bv != null && bv.equals(Corsair.BATTLE_SHIP); } - + public void announceBattleshipHp() { announce(MaplePacketCreator.skillCooldown(5221999, battleshipHp)); } - + public void decreaseBattleshipHp(int decrease) { this.battleshipHp -= decrease; if (battleshipHp <= 0) { Skill battleship = SkillFactory.getSkill(Corsair.BATTLE_SHIP); int cooldown = battleship.getEffect(getSkillLevel(battleship)).getCooldown(); announce(MaplePacketCreator.skillCooldown(Corsair.BATTLE_SHIP, cooldown)); - addCooldown(Corsair.BATTLE_SHIP, Server.getInstance().getCurrentTime(), (long)(cooldown * 1000)); + addCooldown(Corsair.BATTLE_SHIP, Server.getInstance().getCurrentTime(), (long) (cooldown * 1000)); removeCooldown(5221999); cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING); } else { @@ -1971,7 +2003,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { addCooldown(5221999, 0, Long.MAX_VALUE); } } - + public void decreaseReports() { this.possibleReports--; } @@ -1995,24 +2027,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ex.printStackTrace(); } } - + private void nextPendingRequest(MapleClient c) { CharacterNameAndId pendingBuddyRequest = c.getPlayer().getBuddylist().pollPendingRequest(); if (pendingBuddyRequest != null) { c.announce(MaplePacketCreator.requestBuddylistAdd(pendingBuddyRequest.getId(), c.getPlayer().getId(), pendingBuddyRequest.getName())); } } - + private void notifyRemoteChannel(MapleClient c, int remoteChannel, int otherCid, BuddyList.BuddyOperation operation) { MapleCharacter player = c.getPlayer(); if (remoteChannel != -1) { c.getWorldServer().buddyChanged(otherCid, player.getId(), player.getName(), c.getChannel(), operation); } } - + public void deleteBuddy(int otherCid) { BuddyList bl = getBuddylist(); - + if (bl.containsVisible(otherCid)) { notifyRemoteChannel(client, getWorldServer().find(otherCid), otherCid, BuddyList.BuddyOperation.DELETED); } @@ -2020,185 +2052,186 @@ public class MapleCharacter extends AbstractMapleCharacterObject { client.announce(MaplePacketCreator.updateBuddylist(getBuddylist().getBuddies())); nextPendingRequest(client); } - + public static boolean deleteCharFromDB(MapleCharacter player, int senderAccId) { - int cid = player.getId(); - if(!Server.getInstance().haveCharacterEntry(senderAccId, cid)) { // thanks zera (EpiphanyMS) for pointing a critical exploit with non-authored character deletion request - return false; + int cid = player.getId(); + if (!Server.getInstance().haveCharacterEntry(senderAccId, cid)) { // thanks zera (EpiphanyMS) for pointing a critical exploit with non-authored character deletion request + return false; + } + + int accId = senderAccId, world = 0; + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + + try (PreparedStatement ps = con.prepareStatement("SELECT world FROM characters WHERE id = ?")) { + ps.setInt(1, cid); + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + world = rs.getInt("world"); + } + } } - - int accId = senderAccId, world = 0; - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - - try (PreparedStatement ps = con.prepareStatement("SELECT world FROM characters WHERE id = ?")) { - ps.setInt(1, cid); - try (ResultSet rs = ps.executeQuery()) { - if(rs.next()) { - world = rs.getInt("world"); - } - } - } - - try (PreparedStatement ps = con.prepareStatement("SELECT buddyid FROM buddies WHERE characterid = ?")) { - ps.setInt(1, cid); + try (PreparedStatement ps = con.prepareStatement("SELECT buddyid FROM buddies WHERE characterid = ?")) { + ps.setInt(1, cid); - try (ResultSet rs = ps.executeQuery()) { - while(rs.next()) { - int buddyid = rs.getInt("buddyid"); - MapleCharacter buddy = Server.getInstance().getWorld(world).getPlayerStorage().getCharacterById(buddyid); - - if(buddy != null) { - buddy.deleteBuddy(cid); - } - } - } - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM buddies WHERE characterid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - - try (PreparedStatement ps = con.prepareStatement("SELECT threadid FROM bbs_threads WHERE postercid = ?")) { - ps.setInt(1, cid); - - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - int tid = rs.getInt("threadid"); - - try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM bbs_replies WHERE threadid = ?")) { - ps2.setInt(1, tid); - ps2.executeUpdate(); - } - } - } - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM bbs_threads WHERE postercid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - - try (PreparedStatement ps = con.prepareStatement("SELECT id, guildid, guildrank, name, allianceRank FROM characters WHERE id = ? AND accountid = ?")) { - ps.setInt(1, cid); - ps.setInt(2, accId); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next() && rs.getInt("guildid") > 0) { - Server.getInstance().deleteGuildCharacter(new MapleGuildCharacter(player, cid, 0, rs.getString("name"), (byte) -1, (byte) -1, 0, rs.getInt("guildrank"), rs.getInt("guildid"), false, rs.getInt("allianceRank"))); - } - } - } - - if(con.isClosed()) con = DatabaseConnection.getConnection(); //wtf tho + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + int buddyid = rs.getInt("buddyid"); + MapleCharacter buddy = Server.getInstance().getWorld(world).getPlayerStorage().getCharacterById(buddyid); - try (PreparedStatement ps = con.prepareStatement("DELETE FROM wishlists WHERE charid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); + if (buddy != null) { + buddy.deleteBuddy(cid); + } } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM cooldowns WHERE charid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM playerdiseases WHERE charid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM area_info WHERE charid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM monsterbook WHERE charid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM characters WHERE id = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM famelog WHERE characterid_to = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - - try (PreparedStatement ps = con.prepareStatement("SELECT inventoryitemid, petid FROM inventoryitems WHERE characterid = ?")) { - ps.setInt(1, cid); - - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - int inventoryitemid = rs.getInt("inventoryitemid"); - - try (PreparedStatement ps2 = con.prepareStatement("SELECT ringid FROM inventoryequipment WHERE inventoryitemid = ?")) { - ps2.setInt(1, inventoryitemid); - - try (ResultSet rs2 = ps2.executeQuery()) { - while (rs2.next()) { - int ringid = rs2.getInt("ringid"); - - if(ringid > -1) { - try (PreparedStatement ps3 = con.prepareStatement("DELETE FROM rings WHERE id = ?")) { - ps3.setInt(1, ringid); - ps3.executeUpdate(); - } - - MapleCashidGenerator.freeCashId(ringid); - } - } - } - } - - try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM inventoryequipment WHERE inventoryitemid = ?")) { - ps2.setInt(1, inventoryitemid); - ps2.executeUpdate(); - } - - int petid = rs.getInt("petid"); - if(petid > -1) { - try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM pets WHERE petid = ?")) { - ps2.setInt(1, petid); - ps2.executeUpdate(); - } - MapleCashidGenerator.freeCashId(petid); - } - } - } - } - - deleteQuestProgressWhereCharacterId(con, cid); - - try (PreparedStatement ps = con.prepareStatement("SELECT id FROM mts_cart WHERE cid = ?")) { - ps.setInt(1, cid); - - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - int mtsid = rs.getInt("id"); - - try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM mts_items WHERE id = ?")) { - ps2.setInt(1, mtsid); - ps2.executeUpdate(); - } - } - } - } - try (PreparedStatement ps = con.prepareStatement("DELETE FROM mts_cart WHERE cid = ?")) { - ps.setInt(1, cid); - ps.executeUpdate(); - } - - String[] toDel = {"famelog", "inventoryitems", "keymap", "queststatus", "savedlocations", "trocklocations", "skillmacros", "skills", "eventstats", "server_queue"}; - for (String s : toDel) { - MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM `" + s + "` WHERE characterid = ?", cid); - } - - con.close(); - Server.getInstance().deleteCharacterEntry(accId, cid); - return true; - } catch (SQLException e) { - e.printStackTrace(); - return false; + } } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM buddies WHERE characterid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + + try (PreparedStatement ps = con.prepareStatement("SELECT threadid FROM bbs_threads WHERE postercid = ?")) { + ps.setInt(1, cid); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + int tid = rs.getInt("threadid"); + + try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM bbs_replies WHERE threadid = ?")) { + ps2.setInt(1, tid); + ps2.executeUpdate(); + } + } + } + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM bbs_threads WHERE postercid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + + try (PreparedStatement ps = con.prepareStatement("SELECT id, guildid, guildrank, name, allianceRank FROM characters WHERE id = ? AND accountid = ?")) { + ps.setInt(1, cid); + ps.setInt(2, accId); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next() && rs.getInt("guildid") > 0) { + Server.getInstance().deleteGuildCharacter(new MapleGuildCharacter(player, cid, 0, rs.getString("name"), (byte) -1, (byte) -1, 0, rs.getInt("guildrank"), rs.getInt("guildid"), false, rs.getInt("allianceRank"))); + } + } + } + + if (con.isClosed()) { + con = DatabaseConnection.getConnection(); //wtf tho + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM wishlists WHERE charid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM cooldowns WHERE charid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM playerdiseases WHERE charid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM area_info WHERE charid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM monsterbook WHERE charid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM characters WHERE id = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM famelog WHERE characterid_to = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + + try (PreparedStatement ps = con.prepareStatement("SELECT inventoryitemid, petid FROM inventoryitems WHERE characterid = ?")) { + ps.setInt(1, cid); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + int inventoryitemid = rs.getInt("inventoryitemid"); + + try (PreparedStatement ps2 = con.prepareStatement("SELECT ringid FROM inventoryequipment WHERE inventoryitemid = ?")) { + ps2.setInt(1, inventoryitemid); + + try (ResultSet rs2 = ps2.executeQuery()) { + while (rs2.next()) { + int ringid = rs2.getInt("ringid"); + + if (ringid > -1) { + try (PreparedStatement ps3 = con.prepareStatement("DELETE FROM rings WHERE id = ?")) { + ps3.setInt(1, ringid); + ps3.executeUpdate(); + } + + MapleCashidGenerator.freeCashId(ringid); + } + } + } + } + + try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM inventoryequipment WHERE inventoryitemid = ?")) { + ps2.setInt(1, inventoryitemid); + ps2.executeUpdate(); + } + + int petid = rs.getInt("petid"); + if (petid > -1) { + try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM pets WHERE petid = ?")) { + ps2.setInt(1, petid); + ps2.executeUpdate(); + } + MapleCashidGenerator.freeCashId(petid); + } + } + } + } + + deleteQuestProgressWhereCharacterId(con, cid); + + try (PreparedStatement ps = con.prepareStatement("SELECT id FROM mts_cart WHERE cid = ?")) { + ps.setInt(1, cid); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + int mtsid = rs.getInt("id"); + + try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM mts_items WHERE id = ?")) { + ps2.setInt(1, mtsid); + ps2.executeUpdate(); + } + } + } + } + try (PreparedStatement ps = con.prepareStatement("DELETE FROM mts_cart WHERE cid = ?")) { + ps.setInt(1, cid); + ps.executeUpdate(); + } + + String[] toDel = {"famelog", "inventoryitems", "keymap", "queststatus", "savedlocations", "trocklocations", "skillmacros", "skills", "eventstats", "server_queue"}; + for (String s : toDel) { + MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM `" + s + "` WHERE characterid = ?", cid); + } + + con.close(); + Server.getInstance().deleteCharacterEntry(accId, cid); + return true; + } catch (SQLException e) { + e.printStackTrace(); + return false; + } } - + private static void deleteQuestProgressWhereCharacterId(Connection con, int cid) throws SQLException { try (PreparedStatement ps = con.prepareStatement("DELETE FROM medalmaps WHERE characterid = ?")) { ps.setInt(1, cid); @@ -2209,7 +2242,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setInt(1, cid); ps.executeUpdate(); } - + try (PreparedStatement ps = con.prepareStatement("DELETE FROM queststatus WHERE characterid = ?")) { ps.setInt(1, cid); ps.executeUpdate(); @@ -2241,20 +2274,20 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + private static Pair> getChairTaskIntervalRate(int maxhp, int maxmp) { float toHeal = Math.max(maxhp, maxmp); float maxDuration = ServerConstants.CHAIR_EXTRA_HEAL_MAX_DELAY * 1000; - + int rate = 0; int minRegen = 1, maxRegen = (256 * ServerConstants.CHAIR_EXTRA_HEAL_MULTIPLIER) - 1, midRegen = 1; while (minRegen < maxRegen) { midRegen = (int) ((minRegen + maxRegen) * 0.94); - + float procs = toHeal / midRegen; float newRate = maxDuration / procs; rate = (int) newRate; - + if (newRate < 420) { minRegen = (int) (1.2 * midRegen); } else if (newRate > 5000) { @@ -2263,7 +2296,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { break; } } - + float procs = maxDuration / rate; int hpRegen, mpRegen; if (maxhp > maxmp) { @@ -2273,10 +2306,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { hpRegen = (int) Math.ceil(maxhp / procs); mpRegen = midRegen; } - + return new Pair<>(rate, new Pair<>(hpRegen, mpRegen)); } - + private void updateChairHealStats() { statRlock.lock(); try { @@ -2286,7 +2319,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { statRlock.unlock(); } - + effLock.lock(); statWlock.lock(); try { @@ -2300,10 +2333,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + private void startChairTask() { - if (chair.get() == 0) return; - + if (chair.get() == 0) { + return; + } + int healInterval; effLock.lock(); try { @@ -2312,23 +2347,23 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { effLock.unlock(); } - + chrLock.lock(); try { if (chairRecoveryTask != null) { stopChairTask(); } - + chairRecoveryTask = TimerManager.getInstance().register(new Runnable() { @Override public void run() { updateChairHealStats(); final int healHP = localchairhp; final int healMP = localchairmp; - - if(MapleCharacter.this.getHp() < localmaxhp) { + + if (MapleCharacter.this.getHp() < localmaxhp) { byte recHP = (byte) (healHP / ServerConstants.CHAIR_EXTRA_HEAL_MULTIPLIER); - + client.announce(MaplePacketCreator.showOwnRecovery(recHP)); getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showRecovery(id, recHP), false); } else if (MapleCharacter.this.getMp() >= localmaxmp) { @@ -2342,7 +2377,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + private void stopExtraTask() { chrLock.lock(); try { @@ -2354,7 +2389,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + private void startExtraTask(final byte healHP, final byte healMP, final short healInterval) { chrLock.lock(); try { @@ -2363,7 +2398,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + private void startExtraTaskInternal(final byte healHP, final byte healMP, final short healInterval) { extraRecInterval = healInterval; @@ -2374,9 +2409,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { stopExtraTask(); return; } - - if(MapleCharacter.this.getHp() < localmaxhp) { - if(healHP > 0) { + + if (MapleCharacter.this.getHp() < localmaxhp) { + if (healHP > 0) { client.announce(MaplePacketCreator.showOwnRecovery(healHP)); getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showRecovery(id, healHP), false); } @@ -2389,14 +2424,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void disableDoorSpawn() { canDoor = false; - + Runnable r = new Runnable() { @Override public void run() { canDoor = true; } }; - + client.getChannelServer().registerOverallAction(mapid, r, 5000); } @@ -2412,7 +2447,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public void dispel() { - if(!(ServerConstants.USE_UNDISPEL_HOLY_SHIELD && this.isActiveBuffedValue(Bishop.HOLY_SHIELD))) { + if (!(ServerConstants.USE_UNDISPEL_HOLY_SHIELD && this.isActiveBuffedValue(Bishop.HOLY_SHIELD))) { List mbsvhList = getAllStatups(); for (MapleBuffStatValueHolder mbsvh : mbsvhList) { if (mbsvh.effect.isSkill()) { @@ -2432,7 +2467,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public final int getDiseasesSize() { chrLock.lock(); try { @@ -2447,28 +2482,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject { try { long curtime = Server.getInstance().getCurrentTime(); Map> ret = new LinkedHashMap<>(); - - for(Entry de : diseaseExpires.entrySet()) { + + for (Entry de : diseaseExpires.entrySet()) { Pair dee = diseases.get(de.getKey()); MapleDiseaseValueHolder mdvh = dee.getLeft(); - + ret.put(de.getKey(), new Pair<>(mdvh.length - (curtime - mdvh.startTime), dee.getRight())); } - + return ret; } finally { chrLock.unlock(); } } - + public void silentApplyDiseases(Map> diseaseMap) { chrLock.lock(); try { long curTime = Server.getInstance().getCurrentTime(); - - for(Entry> di : diseaseMap.entrySet()) { + + for (Entry> di : diseaseMap.entrySet()) { long expTime = curTime + di.getValue().getLeft(); - + diseaseExpires.put(di.getKey(), expTime); diseases.put(di.getKey(), new Pair<>(new MapleDiseaseValueHolder(curTime, di.getValue().getLeft()), di.getValue().getRight())); } @@ -2476,30 +2511,35 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public void announceDiseases() { Set>> chrDiseases; - + chrLock.lock(); try { // Poison damage visibility and diseases status visibility, extended through map transitions thanks to Ronan - if(!this.isLoggedinWorld()) return; - + if (!this.isLoggedinWorld()) { + return; + } + chrDiseases = new LinkedHashSet<>(diseases.entrySet()); } finally { chrLock.unlock(); } - - for(Entry> di : chrDiseases) { + + for (Entry> di : chrDiseases) { MapleDisease disease = di.getKey(); MobSkill skill = di.getValue().getRight(); final List> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX()))); - if(disease != MapleDisease.SLOW) map.broadcastMessage(MaplePacketCreator.giveForeignDebuff(id, debuff, skill)); - else map.broadcastMessage(MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill)); + if (disease != MapleDisease.SLOW) { + map.broadcastMessage(MaplePacketCreator.giveForeignDebuff(id, debuff, skill)); + } else { + map.broadcastMessage(MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill)); + } } } - + public void giveDebuff(final MapleDisease disease, MobSkill skill) { if (!hasDisease(disease) && getDiseasesSize() < 2) { if (!(disease == MapleDisease.SEDUCE || disease == MapleDisease.STUN)) { @@ -2507,7 +2547,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return; } } - + chrLock.lock(); try { long curTime = Server.getInstance().getCurrentTime(); @@ -2516,16 +2556,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { chrLock.unlock(); } - + if (disease == MapleDisease.SEDUCE && chair.get() != 0) { sitChair(0); } - + final List> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX()))); client.announce(MaplePacketCreator.giveDebuff(debuff, skill)); - - if(disease != MapleDisease.SLOW) map.broadcastMessage(this, MaplePacketCreator.giveForeignDebuff(id, debuff, skill), false); - else map.broadcastMessage(this, MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill), false); + + if (disease != MapleDisease.SLOW) { + map.broadcastMessage(this, MaplePacketCreator.giveForeignDebuff(id, debuff, skill), false); + } else { + map.broadcastMessage(this, MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill), false); + } } } @@ -2533,9 +2576,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (hasDisease(debuff)) { long mask = debuff.getValue(); announce(MaplePacketCreator.cancelDebuff(mask)); - - if(debuff != MapleDisease.SLOW) map.broadcastMessage(this, MaplePacketCreator.cancelForeignDebuff(id, mask), false); - else map.broadcastMessage(this, MaplePacketCreator.cancelForeignSlowDebuff(id), false); + + if (debuff != MapleDisease.SLOW) { + map.broadcastMessage(this, MaplePacketCreator.cancelForeignDebuff(id, mask), false); + } else { + map.broadcastMessage(this, MaplePacketCreator.cancelForeignSlowDebuff(id), false); + } chrLock.lock(); try { @@ -2565,7 +2611,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public void dispelSkill(int skillid) { List allBuffs = getAllStatups(); for (MapleBuffStatValueHolder mbsvh : allBuffs) { @@ -2596,10 +2642,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return false; } } - + public void changeFaceExpression(int emote) { long timeNow = Server.getInstance().getCurrentTime(); - if(timeNow - lastExpression > 2000) { + if (timeNow - lastExpression > 2000) { lastExpression = timeNow; client.getChannelServer().registerFaceExpression(map, this, emote); } @@ -2611,7 +2657,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { lastHpDec = Server.getInstance().getCurrentTime(); } } - + private void startHpDecreaseTask(long lastHpTask) { hpDecreaseTask = TimerManager.getInstance().register(new Runnable() { @Override @@ -2620,16 +2666,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } }, ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL, ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL - lastHpTask); } - + public void resetHpDecreaseTask() { if (hpDecreaseTask != null) { hpDecreaseTask.cancel(false); } - + long lastHpTask = Server.getInstance().getCurrentTime() - lastHpDec; startHpDecreaseTask((lastHpTask > ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL) ? ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL : lastHpTask); } - + public void dropMessage(String message) { dropMessage(0, message); } @@ -2637,7 +2683,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void dropMessage(int type, String message) { client.announce(MaplePacketCreator.serverNotice(type, message)); } - + public void enteredScript(String script, int mapid) { if (!entered.containsKey(mapid)) { entered.put(mapid, script); @@ -2652,7 +2698,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { getWorldServer().updateMessenger(getMessenger(), getName(), getWorld(), client.getChannel()); } } - + public void cancelDiseaseExpireTask() { if (diseaseExpireTask != null) { diseaseExpireTask.cancel(false); @@ -2666,28 +2712,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject { @Override public void run() { Set toExpire = new LinkedHashSet<>(); - + chrLock.lock(); try { long curTime = Server.getInstance().getCurrentTime(); - - for(Entry de : diseaseExpires.entrySet()) { - if(de.getValue() < curTime) { + + for (Entry de : diseaseExpires.entrySet()) { + if (de.getValue() < curTime) { toExpire.add(de.getKey()); } } } finally { chrLock.unlock(); } - - for(MapleDisease d : toExpire) { + + for (MapleDisease d : toExpire) { dispelDebuff(d); } } }, 1500); } } - + public void cancelBuffExpireTask() { if (buffExpireTask != null) { buffExpireTask.cancel(false); @@ -2702,15 +2748,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void run() { Set> es; List toCancel = new ArrayList<>(); - + effLock.lock(); chrLock.lock(); try { es = new LinkedHashSet<>(buffExpires.entrySet()); - + long curTime = Server.getInstance().getCurrentTime(); - for(Entry bel : es) { - if(curTime >= bel.getValue()) { + for (Entry bel : es) { + if (curTime >= bel.getValue()) { toCancel.add(buffEffects.get(bel.getKey()).entrySet().iterator().next().getValue()); //rofl } } @@ -2718,15 +2764,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); effLock.unlock(); } - - for(MapleBuffStatValueHolder mbsvh : toCancel) { + + for (MapleBuffStatValueHolder mbsvh : toCancel) { cancelEffect(mbsvh.effect, false, mbsvh.startTime); } } }, 1500); } } - + public void cancelSkillCooldownTask() { if (skillCooldownTask != null) { skillCooldownTask.cancel(false); @@ -2740,7 +2786,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { @Override public void run() { Set> es; - + effLock.lock(); chrLock.lock(); try { @@ -2749,11 +2795,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); effLock.unlock(); } - + long curTime = Server.getInstance().getCurrentTime(); - for(Entry bel : es) { + for (Entry bel : es) { MapleCoolDownValueHolder mcdvh = bel.getValue(); - if(curTime >= mcdvh.startTime + mcdvh.length) { + if (curTime >= mcdvh.startTime + mcdvh.length) { removeCooldown(mcdvh.skillId); client.announce(MaplePacketCreator.skillCooldown(mcdvh.skillId, 0)); } @@ -2762,7 +2808,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { }, 1500); } } - + public void cancelExpirationTask() { if (itemExpireTask != null) { itemExpireTask.cancel(false); @@ -2776,7 +2822,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { @Override public void run() { boolean deletedCoupon = false; - + long expiration, currenttime = System.currentTimeMillis(); Set keys = getSkills().keySet(); for (Iterator i = keys.iterator(); i.hasNext();) { @@ -2791,7 +2837,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { for (MapleInventory inv : inventory) { for (Item item : inv.list()) { expiration = item.getExpiration(); - + if (expiration != -1 && (expiration < currenttime) && ((item.getFlag() & ItemConstants.LOCK) == ItemConstants.LOCK)) { byte aids = item.getFlag(); aids &= ~(ItemConstants.LOCK); @@ -2816,8 +2862,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - - if(!toberemove.isEmpty()) { + + if (!toberemove.isEmpty()) { for (Item item : toberemove) { MapleInventoryManipulator.removeFromSlot(client, inv.getType(), item.getPosition(), item.getQuantity(), true); } @@ -2839,8 +2885,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { toberemove.clear(); } - - if(deletedCoupon) { + + if (deletedCoupon) { updateCouponRates(); } } @@ -2850,6 +2896,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public enum FameStatus { + OK, NOT_TODAY, NOT_THIS_MONTH } @@ -2880,7 +2927,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void gainGachaExp(int gain) { updateSingleStat(MapleStat.GACHAEXP, gachaexp.addAndGet(gain)); } - + public void gainExp(int gain) { gainExp(gain, true, true); } @@ -2888,47 +2935,51 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void gainExp(int gain, boolean show, boolean inChat) { gainExp(gain, show, inChat, true); } - + public void gainExp(int gain, boolean show, boolean inChat, boolean white) { gainExp(gain, 0, show, inChat, white); } - + public void gainExp(int gain, int party, boolean show, boolean inChat, boolean white) { if (hasDisease(MapleDisease.CURSE)) { gain *= 0.5; party *= 0.5; } - - if(gain < 0) gain = Integer.MAX_VALUE; // integer overflow, heh. - if(party < 0) party = Integer.MAX_VALUE; // integer overflow, heh. - int equip = (int) Math.min((long)(gain / 10) * pendantExp, Integer.MAX_VALUE); - + + if (gain < 0) { + gain = Integer.MAX_VALUE; // integer overflow, heh. + } + if (party < 0) { + party = Integer.MAX_VALUE; // integer overflow, heh. + } + int equip = (int) Math.min((long) (gain / 10) * pendantExp, Integer.MAX_VALUE); + long total = (long) gain + equip + party; gainExpInternal(total, equip, party, show, inChat, white); } - + public void loseExp(int loss, boolean show, boolean inChat) { loseExp(loss, show, inChat, true); } - + public void loseExp(int loss, boolean show, boolean inChat, boolean white) { gainExpInternal(-loss, 0, 0, show, inChat, white); } - + private synchronized void gainExpInternal(long gain, int equip, int party, boolean show, boolean inChat, boolean white) { // need of method synchonization here detected thanks to MedicOP long total = Math.max(gain, -exp.get()); - + if (level < getMaxLevel() && (allowExpGain || this.getEventInstance() != null)) { long leftover = 0; long nextExp = exp.get() + total; - + if (nextExp > (long) Integer.MAX_VALUE) { total = Integer.MAX_VALUE - exp.get(); leftover = nextExp - Integer.MAX_VALUE; } updateSingleStat(MapleStat.EXP, exp.addAndGet((int) total)); if (show && gain != 0) { - client.announce(MaplePacketCreator.getShowExpGain((int)Math.min(gain, Integer.MAX_VALUE), equip, party, inChat, white)); + client.announce(MaplePacketCreator.getShowExpGain((int) Math.min(gain, Integer.MAX_VALUE), equip, party, inChat, white)); } while (exp.get() >= ExpTable.getExpNeededForLevel(level)) { levelUp(true); @@ -2938,8 +2989,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { break; } } - - if(leftover > 0) { + + if (leftover > 0) { gainExpInternal(leftover, equip, party, false, inChat, white); } else { lastExpGainTime = System.currentTimeMillis(); @@ -2963,36 +3014,36 @@ public class MapleCharacter extends AbstractMapleCharacterObject { petLock.unlock(); } } - + public void gainFame(int delta) { gainFame(delta, null, 0); } - + public boolean gainFame(int delta, MapleCharacter fromPlayer, int mode) { Pair fameRes = applyFame(delta); delta = fameRes.getRight(); if (delta != 0) { int thisFame = fameRes.getLeft(); updateSingleStat(MapleStat.FAME, thisFame); - + if (fromPlayer != null) { fromPlayer.announce(MaplePacketCreator.giveFameResponse(mode, getName(), thisFame)); announce(MaplePacketCreator.receiveFame(mode, fromPlayer.getName())); } else { announce(MaplePacketCreator.getShowFameGain(delta)); } - + return true; } else { return false; } } - + public boolean canHoldMeso(int gain) { // thanks lucasziron found pointing out a need to check space availability for mesos on player transactions long nextMeso = (long) meso.get() + gain; return nextMeso <= Integer.MAX_VALUE; } - + public void gainMeso(int gain) { gainMeso(gain, true, false, true); } @@ -3015,7 +3066,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { petLock.unlock(); } - + if (gain != 0) { updateSingleStat(MapleStat.MESO, (int) nextMeso, enableActions); if (show) { @@ -3036,7 +3087,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public List getAllCooldowns() { List ret = new ArrayList<>(); - + effLock.lock(); chrLock.lock(); try { @@ -3047,7 +3098,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); effLock.unlock(); } - + return ret; } @@ -3076,7 +3127,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { try { Connection con = DatabaseConnection.getConnection(); - + try (PreparedStatement ps = con.prepareStatement("SELECT `id`, `accountid`, `name` FROM `characters` WHERE `name` = ?")) { ps.setString(1, name); try (ResultSet rs = ps.executeQuery()) { @@ -3171,14 +3222,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + private List getAllStatups() { effLock.lock(); chrLock.lock(); try { List ret = new ArrayList<>(); - for(Map bel : buffEffects.values()) { - for(MapleBuffStatValueHolder mbsvh : bel.values()) { + for (Map bel : buffEffects.values()) { + for (MapleBuffStatValueHolder mbsvh : bel.values()) { ret.add(mbsvh); } } @@ -3188,19 +3239,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public List getAllBuffs() { // buff values will be stored in an arbitrary order effLock.lock(); chrLock.lock(); try { long curtime = Server.getInstance().getCurrentTime(); - + Map ret = new LinkedHashMap<>(); - for(Map bel : buffEffects.values()) { - for(MapleBuffStatValueHolder mbsvh : bel.values()) { + for (Map bel : buffEffects.values()) { + for (MapleBuffStatValueHolder mbsvh : bel.values()) { int srcid = mbsvh.effect.getBuffSourceId(); - if(!ret.containsKey(srcid)) { - ret.put(srcid, new PlayerBuffValueHolder((int)(curtime - mbsvh.startTime), mbsvh.effect)); + if (!ret.containsKey(srcid)) { + ret.put(srcid, new PlayerBuffValueHolder((int) (curtime - mbsvh.startTime), mbsvh.effect)); } } } @@ -3226,7 +3277,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public boolean hasBuffFromSourceid(int sourceid) { effLock.lock(); chrLock.lock(); @@ -3237,100 +3288,102 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + private List> getActiveStatupsFromSourceid(int sourceid) { // already under effLock & chrLock List> ret = new ArrayList<>(); - - for(Entry bel : buffEffects.get(sourceid).entrySet()) { + + for (Entry bel : buffEffects.get(sourceid).entrySet()) { MapleBuffStat mbs = bel.getKey(); MapleBuffStatValueHolder mbsvh = effects.get(bel.getKey()); - - if(mbsvh != null) { + + if (mbsvh != null) { ret.add(new Pair<>(mbs, mbsvh.value)); } else { ret.add(new Pair<>(mbs, 0)); } } - + Collections.sort(ret, new Comparator>() { @Override public int compare(Pair p1, Pair p2) { return p1.getLeft().compareTo(p2.getLeft()); } }); - + return ret; } - + private void addItemEffectHolder(Integer sourceid, long expirationtime, Map statups) { buffEffects.put(sourceid, statups); buffExpires.put(sourceid, expirationtime); } - + private boolean removeEffectFromItemEffectHolder(Integer sourceid, MapleBuffStat buffStat) { Map lbe = buffEffects.get(sourceid); - - if(lbe.remove(buffStat) != null) { - buffEffectsCount.put(buffStat, (byte)(buffEffectsCount.get(buffStat) - 1)); - - if(lbe.isEmpty()) { + + if (lbe.remove(buffStat) != null) { + buffEffectsCount.put(buffStat, (byte) (buffEffectsCount.get(buffStat) - 1)); + + if (lbe.isEmpty()) { buffEffects.remove(sourceid); buffExpires.remove(sourceid); } - + return true; } - + return false; } - + private void removeItemEffectHolder(Integer sourceid) { Map be = buffEffects.remove(sourceid); - if(be != null) { - for(Entry bei : be.entrySet()) { - buffEffectsCount.put(bei.getKey(), (byte)(buffEffectsCount.get(bei.getKey()) - 1)); + if (be != null) { + for (Entry bei : be.entrySet()) { + buffEffectsCount.put(bei.getKey(), (byte) (buffEffectsCount.get(bei.getKey()) - 1)); } } - + buffExpires.remove(sourceid); } - + private void dropWorstEffectFromItemEffectHolder(MapleBuffStat mbs) { Integer min = Integer.MAX_VALUE; Integer srcid = -1; - for(Entry> bpl: buffEffects.entrySet()) { + for (Entry> bpl : buffEffects.entrySet()) { MapleBuffStatValueHolder mbsvh = bpl.getValue().get(mbs); - if(mbsvh != null) { - if(mbsvh.value < min) { + if (mbsvh != null) { + if (mbsvh.value < min) { min = mbsvh.value; srcid = bpl.getKey(); } } } - + removeEffectFromItemEffectHolder(srcid, mbs); } - + private MapleBuffStatValueHolder fetchBestEffectFromItemEffectHolder(MapleBuffStat mbs) { Pair max = new Pair<>(Integer.MIN_VALUE, 0); MapleBuffStatValueHolder mbsvh = null; - for(Entry> bpl: buffEffects.entrySet()) { + for (Entry> bpl : buffEffects.entrySet()) { MapleBuffStatValueHolder mbsvhi = bpl.getValue().get(mbs); - if(mbsvhi != null) { - if(mbsvhi.value > max.left) { + if (mbsvhi != null) { + if (mbsvhi.value > max.left) { max = new Pair<>(mbsvhi.value, mbsvhi.effect.getStatups().size()); mbsvh = mbsvhi; - } else if(mbsvhi.value == max.left && mbsvhi.effect.getStatups().size() > max.right) { + } else if (mbsvhi.value == max.left && mbsvhi.effect.getStatups().size() > max.right) { max = new Pair<>(mbsvhi.value, mbsvhi.effect.getStatups().size()); mbsvh = mbsvhi; } } } - - if(mbsvh != null) effects.put(mbs, mbsvh); + + if (mbsvh != null) { + effects.put(mbs, mbsvh); + } return mbsvh; } - + private void extractBuffValue(int sourceid, MapleBuffStat stat) { chrLock.lock(); try { @@ -3339,24 +3392,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public void debugListAllBuffs() { effLock.lock(); chrLock.lock(); try { System.out.println("-------------------"); System.out.println("CACHED BUFFS: "); - for(Entry> bpl : buffEffects.entrySet()) { + for (Entry> bpl : buffEffects.entrySet()) { System.out.print(bpl.getKey() + ": "); - for(Entry pble : bpl.getValue().entrySet()) { + for (Entry pble : bpl.getValue().entrySet()) { System.out.print(pble.getKey().name() + pble.getValue().value + ", "); } System.out.println(); } System.out.println("-------------------"); - + System.out.println("IN ACTION:"); - for(Entry bpl : effects.entrySet()) { + for (Entry bpl : effects.entrySet()) { System.out.println(bpl.getKey().name() + " -> " + MapleItemInformationProvider.getInstance().getName(bpl.getValue().effect.getSourceId())); } } finally { @@ -3364,12 +3417,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public void debugListAllBuffsCount() { effLock.lock(); chrLock.lock(); try { - for(Entry mbsl : buffEffectsCount.entrySet()) { + for (Entry mbsl : buffEffectsCount.entrySet()) { System.out.println(mbsl.getKey().name() + " -> " + mbsl.getValue()); } } finally { @@ -3377,7 +3430,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public void cancelAllBuffs(boolean softcancel) { if (softcancel) { effLock.lock(); @@ -3386,10 +3439,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { cancelEffectFromBuffStat(MapleBuffStat.SUMMON); cancelEffectFromBuffStat(MapleBuffStat.PUPPET); cancelEffectFromBuffStat(MapleBuffStat.COMBO); - + effects.clear(); - - for(Integer srcid : new ArrayList<>(buffEffects.keySet())) { + + for (Integer srcid : new ArrayList<>(buffEffects.keySet())) { removeItemEffectHolder(srcid); } } finally { @@ -3402,8 +3455,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.lock(); chrLock.lock(); try { - for(Entry> bpl : buffEffects.entrySet()) { - for(Entry mbse : bpl.getValue().entrySet()) { + for (Entry> bpl : buffEffects.entrySet()) { + for (Entry mbse : bpl.getValue().entrySet()) { mseBuffs.put(mbse.getValue().effect, mbse.getValue().startTime); } } @@ -3421,15 +3474,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private void dropBuffStats(List> effectsToCancel) { for (Pair cancelEffectCancelTasks : effectsToCancel) { //boolean nestedCancel = false; - + chrLock.lock(); try { /* - if (buffExpires.get(cancelEffectCancelTasks.getRight().effect.getBuffSourceId()) != null) { - nestedCancel = true; - }*/ - - if(cancelEffectCancelTasks.getRight().bestApplied) { + if (buffExpires.get(cancelEffectCancelTasks.getRight().effect.getBuffSourceId()) != null) { + nestedCancel = true; + }*/ + + if (cancelEffectCancelTasks.getRight().bestApplied) { fetchBestEffectFromItemEffectHolder(cancelEffectCancelTasks.getLeft()); } } finally { @@ -3437,31 +3490,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } /* - if (nestedCancel) { - this.cancelEffect(cancelEffectCancelTasks.getRight().effect, false, -1, false); - }*/ + if (nestedCancel) { + this.cancelEffect(cancelEffectCancelTasks.getRight().effect, false, -1, false); + }*/ } } - + private List> deregisterBuffStats(Map stats) { chrLock.lock(); try { List> effectsToCancel = new ArrayList<>(stats.size()); for (Entry stat : stats.entrySet()) { int sourceid = stat.getValue().effect.getBuffSourceId(); - - if(!buffEffects.containsKey(sourceid)) { + + if (!buffEffects.containsKey(sourceid)) { buffExpires.remove(sourceid); } - + MapleBuffStat mbs = stat.getKey(); effectsToCancel.add(new Pair<>(mbs, stat.getValue())); - + MapleBuffStatValueHolder mbsvh = effects.get(mbs); if (mbsvh != null && mbsvh.effect.getBuffSourceId() == sourceid) { mbsvh.bestApplied = true; effects.remove(mbs); - + if (mbs == MapleBuffStat.RECOVERY) { if (recoveryTask != null) { recoveryTask.cancel(false); @@ -3475,7 +3528,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { getMap().broadcastMessage(MaplePacketCreator.removeSummon(summon, true), summon.getPosition()); getMap().removeMapObject(summon); removeVisibleMapObject(summon); - + summons.remove(summonId); if (summon.isPuppet()) { map.removePlayerPuppet(this); @@ -3494,18 +3547,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject { dragonBloodSchedule.cancel(false); dragonBloodSchedule = null; } else if (mbs == MapleBuffStat.HPREC || mbs == MapleBuffStat.MPREC) { - if(mbs == MapleBuffStat.HPREC) { + if (mbs == MapleBuffStat.HPREC) { extraHpRec = 0; } else { extraMpRec = 0; } - + if (extraRecoveryTask != null) { extraRecoveryTask.cancel(false); extraRecoveryTask = null; } - - if(extraHpRec != 0 || extraMpRec != 0) { + + if (extraHpRec != 0 || extraMpRec != 0) { startExtraTaskInternal(extraHpRec, extraMpRec, extraRecInterval); } } @@ -3517,7 +3570,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public void cancelEffect(int itemId) { cancelEffect(ii.getItemEffect(itemId), false, -1); } @@ -3530,59 +3583,61 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + private void updateEffects(Set removedStats) { chrLock.lock(); try { Map> retrievedEffects = new LinkedHashMap<>(); Map> maxStatups = new LinkedHashMap<>(); - - for(Entry> bel : buffEffects.entrySet()) { - for(Entry belv : bel.getValue().entrySet()) { - if(removedStats.contains(belv.getKey())) { - if(!retrievedEffects.containsKey(bel.getKey())) { + + for (Entry> bel : buffEffects.entrySet()) { + for (Entry belv : bel.getValue().entrySet()) { + if (removedStats.contains(belv.getKey())) { + if (!retrievedEffects.containsKey(bel.getKey())) { retrievedEffects.put(bel.getKey(), new Pair<>(belv.getValue().effect, belv.getValue().startTime)); } - + Pair thisStat = maxStatups.get(belv.getKey()); - if(thisStat == null || belv.getValue().value > thisStat.getRight()) { + if (thisStat == null || belv.getValue().value > thisStat.getRight()) { maxStatups.put(belv.getKey(), new Pair<>(bel.getKey(), belv.getValue().value)); } } } } - + Map> bestEffects = new LinkedHashMap<>(); Set retrievedStats = new LinkedHashSet<>(); - for(Entry> lmsee: maxStatups.entrySet()) { - if(isSingletonStatup(lmsee.getKey())) continue; - + for (Entry> lmsee : maxStatups.entrySet()) { + if (isSingletonStatup(lmsee.getKey())) { + continue; + } + Integer srcid = lmsee.getValue().getLeft(); - if(!bestEffects.containsKey(srcid)) { + if (!bestEffects.containsKey(srcid)) { Pair msel = retrievedEffects.get(srcid); - + bestEffects.put(srcid, msel); - for(Pair mbsi : msel.getLeft().getStatups()) { + for (Pair mbsi : msel.getLeft().getStatups()) { retrievedStats.add(mbsi.getLeft()); } } } - + propagateBuffEffectUpdates(bestEffects, retrievedStats); } finally { chrLock.unlock(); } } - + private boolean cancelEffect(MapleStatEffect effect, boolean overwrite, long startTime, boolean firstCancel) { Set removedStats = new LinkedHashSet<>(); dropBuffStats(cancelEffectInternal(effect, overwrite, startTime, removedStats)); updateLocalStats(); updateEffects(removedStats); - + return !removedStats.isEmpty(); } - + private List> cancelEffectInternal(MapleStatEffect effect, boolean overwrite, long startTime, Set removedStats) { Map buffstats = null; MapleBuffStat ombs; @@ -3590,26 +3645,26 @@ public class MapleCharacter extends AbstractMapleCharacterObject { buffstats = extractCurrentBuffStats(effect); } else if ((ombs = getSingletonStatupFromEffect(effect)) != null) { // removing all effects of a buff having non-shareable buff stat. MapleBuffStatValueHolder mbsvh = effects.get(ombs); - if(mbsvh != null) { + if (mbsvh != null) { buffstats = extractCurrentBuffStats(mbsvh.effect); } } - + if (buffstats == null) { // all else, is dropping ALL current statups that uses same stats as the given effect buffstats = extractLeastRelevantStatEffectsIfFull(effect); } - + if (effect.isMagicDoor()) { MapleDoor destroyDoor = removePartyDoor(false); - + if (destroyDoor != null) { destroyDoor.getTarget().removeMapObject(destroyDoor.getAreaDoor()); destroyDoor.getTown().removeMapObject(destroyDoor.getTownDoor()); - + for (MapleCharacter chr : destroyDoor.getTarget().getCharacters()) { destroyDoor.getAreaDoor().sendDestroyData(chr.getClient()); } - + Collection townChars = destroyDoor.getTown().getCharacters(); for (MapleCharacter chr : townChars) { destroyDoor.getTownDoor().sendDestroyData(chr.getClient()); @@ -3626,7 +3681,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } else if (effect.isMapChair()) { stopChairTask(); } - + List> toCancel = deregisterBuffStats(buffstats); if (effect.isMonsterRiding()) { if (effect.getSourceId() != Corsair.BATTLE_SHIP) { @@ -3634,29 +3689,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject { this.getMount().setActive(false); } } - + if (!overwrite) { List cancelStats = new LinkedList<>(); - + chrLock.lock(); try { - for(Entry mbsl : buffstats.entrySet()) { + for (Entry mbsl : buffstats.entrySet()) { cancelStats.add(mbsl.getKey()); } } finally { chrLock.unlock(); } - - for(MapleBuffStat mbs : cancelStats) removedStats.add(mbs); + + for (MapleBuffStat mbs : cancelStats) { + removedStats.add(mbs); + } cancelPlayerBuffs(cancelStats); } - + return toCancel; } public void cancelEffectFromBuffStat(MapleBuffStat stat) { MapleBuffStatValueHolder effect; - + effLock.lock(); chrLock.lock(); try { @@ -3669,17 +3726,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject { cancelEffect(effect.effect, false, -1); } } - + public void cancelBuffStats(MapleBuffStat stat) { effLock.lock(); try { List> cancelList = new LinkedList<>(); - + chrLock.lock(); try { - for(Entry> bel : this.buffEffects.entrySet()) { + for (Entry> bel : this.buffEffects.entrySet()) { MapleBuffStatValueHolder beli = bel.getValue().get(stat); - if(beli != null) { + if (beli != null) { cancelList.add(new Pair<>(bel.getKey(), beli)); } } @@ -3688,7 +3745,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } Map buffStatList = new LinkedHashMap<>(); - for(Pair p : cancelList) { + for (Pair p : cancelList) { buffStatList.put(stat, p.getRight()); extractBuffValue(p.getLeft(), stat); dropBuffStats(deregisterBuffStats(buffStatList)); @@ -3696,183 +3753,191 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { effLock.unlock(); } - + cancelPlayerBuffs(Arrays.asList(stat)); } - + private Map extractCurrentBuffStats(MapleStatEffect effect) { chrLock.lock(); try { Map stats = new LinkedHashMap<>(); Map buffList = buffEffects.remove(effect.getBuffSourceId()); - - if(buffList != null) { + + if (buffList != null) { for (Entry stateffect : buffList.entrySet()) { stats.put(stateffect.getKey(), stateffect.getValue()); - buffEffectsCount.put(stateffect.getKey(), (byte)(buffEffectsCount.get(stateffect.getKey()) - 1)); + buffEffectsCount.put(stateffect.getKey(), (byte) (buffEffectsCount.get(stateffect.getKey()) - 1)); } } - + return stats; } finally { chrLock.unlock(); } } - + private Map extractLeastRelevantStatEffectsIfFull(MapleStatEffect effect) { Map extractedStatBuffs = new LinkedHashMap<>(); - + chrLock.lock(); try { Map stats = new LinkedHashMap<>(); Map minStatBuffs = new LinkedHashMap<>(); - - for(Entry> mbsvhi : buffEffects.entrySet()) { - for(Entry mbsvhe : mbsvhi.getValue().entrySet()) { + + for (Entry> mbsvhi : buffEffects.entrySet()) { + for (Entry mbsvhe : mbsvhi.getValue().entrySet()) { MapleBuffStat mbs = mbsvhe.getKey(); Byte b = stats.get(mbs); - - if(b != null) { + + if (b != null) { stats.put(mbs, (byte) (b + 1)); - if(mbsvhe.getValue().value < minStatBuffs.get(mbs).value) minStatBuffs.put(mbs, mbsvhe.getValue()); + if (mbsvhe.getValue().value < minStatBuffs.get(mbs).value) { + minStatBuffs.put(mbs, mbsvhe.getValue()); + } } else { stats.put(mbs, (byte) 1); minStatBuffs.put(mbs, mbsvhe.getValue()); } } } - + Set effectStatups = new LinkedHashSet<>(); - for(Pair efstat : effect.getStatups()) { + for (Pair efstat : effect.getStatups()) { effectStatups.add(efstat.getLeft()); } - - for(Entry it : stats.entrySet()) { + + for (Entry it : stats.entrySet()) { boolean uniqueBuff = isSingletonStatup(it.getKey()); - - if(it.getValue() >= (!uniqueBuff ? ServerConstants.MAX_MONITORED_BUFFSTATS : 1) && effectStatups.contains(it.getKey())) { + + if (it.getValue() >= (!uniqueBuff ? ServerConstants.MAX_MONITORED_BUFFSTATS : 1) && effectStatups.contains(it.getKey())) { MapleBuffStatValueHolder mbsvh = minStatBuffs.get(it.getKey()); - + Map lpbe = buffEffects.get(mbsvh.effect.getBuffSourceId()); lpbe.remove(it.getKey()); - buffEffectsCount.put(it.getKey(), (byte)(buffEffectsCount.get(it.getKey()) - 1)); - - if(lpbe.isEmpty()) buffEffects.remove(mbsvh.effect.getBuffSourceId()); + buffEffectsCount.put(it.getKey(), (byte) (buffEffectsCount.get(it.getKey()) - 1)); + + if (lpbe.isEmpty()) { + buffEffects.remove(mbsvh.effect.getBuffSourceId()); + } extractedStatBuffs.put(it.getKey(), mbsvh); } } } finally { chrLock.unlock(); } - + return extractedStatBuffs; } - + private void propagateBuffEffectUpdates(Map> retrievedEffects, Set retrievedStats) { - if(retrievedStats.isEmpty()) return; - + if (retrievedStats.isEmpty()) { + return; + } + Map> maxBuffValue = new LinkedHashMap<>(); - for(MapleBuffStat mbs : retrievedStats) { + for (MapleBuffStat mbs : retrievedStats) { MapleBuffStatValueHolder mbsvh = effects.get(mbs); - if(mbsvh != null) { + if (mbsvh != null) { retrievedEffects.put(mbsvh.effect.getBuffSourceId(), new Pair<>(mbsvh.effect, mbsvh.startTime)); } - + maxBuffValue.put(mbs, new Pair<>(Integer.MIN_VALUE, (MapleStatEffect) null)); } - + Map> updateEffects = new LinkedHashMap<>(); - + List recalcMseList = new LinkedList<>(); - for(Entry> re : retrievedEffects.entrySet()) { + for (Entry> re : retrievedEffects.entrySet()) { recalcMseList.add(re.getValue().getLeft()); } - + boolean mageJob = this.getJobStyle() == MapleJob.MAGICIAN; do { List mseList = recalcMseList; recalcMseList = new LinkedList<>(); - - for(MapleStatEffect mse : mseList) { + + for (MapleStatEffect mse : mseList) { int mseAmount = 0; int maxEffectiveStatup = Integer.MIN_VALUE; - for(Pair st : mse.getStatups()) { + for (Pair st : mse.getStatups()) { MapleBuffStat mbs = st.getLeft(); - + boolean relevantStatup = true; - if(mbs == MapleBuffStat.WATK) { // not relevant for mages - if(mageJob) relevantStatup = false; - } else if(mbs == MapleBuffStat.MATK) { // not relevant for non-mages - if(!mageJob) relevantStatup = false; + if (mbs == MapleBuffStat.WATK) { // not relevant for mages + if (mageJob) { + relevantStatup = false; + } + } else if (mbs == MapleBuffStat.MATK) { // not relevant for non-mages + if (!mageJob) { + relevantStatup = false; + } } - + Pair mbv = maxBuffValue.get(mbs); - if(mbv == null) { + if (mbv == null) { continue; } - - if(mbv.getLeft() < st.getRight()) { + + if (mbv.getLeft() < st.getRight()) { MapleStatEffect msbe = mbv.getRight(); - if(msbe != null) { + if (msbe != null) { recalcMseList.add(msbe); } - + maxBuffValue.put(mbs, new Pair<>(st.getRight(), mse)); - - if(relevantStatup) { - if(maxEffectiveStatup < st.getRight()) { + + if (relevantStatup) { + if (maxEffectiveStatup < st.getRight()) { maxEffectiveStatup = st.getRight(); } } } - - if(relevantStatup) { + + if (relevantStatup) { mseAmount += st.getRight(); } } - + updateEffects.put(mse, new Pair<>(maxEffectiveStatup, mseAmount)); } - } while(!recalcMseList.isEmpty()); - + } while (!recalcMseList.isEmpty()); + List>> updateEffectsList = new ArrayList<>(); - for(Entry> ue : updateEffects.entrySet()) { + for (Entry> ue : updateEffects.entrySet()) { updateEffectsList.add(new Pair<>(ue.getKey(), ue.getValue())); } - - Collections.sort(updateEffectsList, new Comparator>>() - { - @Override - public int compare( Pair> o1, Pair> o2 ) - { - if(o1.getRight().getLeft().equals(o2.getRight().getLeft())) { - return o1.getRight().getRight().compareTo(o2.getRight().getRight()); - } else { - return o1.getRight().getLeft().compareTo(o2.getRight().getLeft()); - } + + Collections.sort(updateEffectsList, new Comparator>>() { + @Override + public int compare(Pair> o1, Pair> o2) { + if (o1.getRight().getLeft().equals(o2.getRight().getLeft())) { + return o1.getRight().getRight().compareTo(o2.getRight().getRight()); + } else { + return o1.getRight().getLeft().compareTo(o2.getRight().getLeft()); } - }); - + } + }); + List>> toUpdateEffects = new LinkedList<>(); - for(Pair> msep : updateEffectsList) { + for (Pair> msep : updateEffectsList) { MapleStatEffect mse = msep.getLeft(); toUpdateEffects.add(new Pair<>(mse.getBuffSourceId(), retrievedEffects.get(mse.getBuffSourceId()))); } - + List> activeStatups = new LinkedList<>(); - for(Pair> lmse: toUpdateEffects) { + for (Pair> lmse : toUpdateEffects) { Pair msel = lmse.getRight(); - - for(Pair statup : getActiveStatupsFromSourceid(lmse.getLeft())) { - if(!isSingletonStatup(statup.getLeft())) { + + for (Pair statup : getActiveStatupsFromSourceid(lmse.getLeft())) { + if (!isSingletonStatup(statup.getLeft())) { activeStatups.add(statup); } } - + msel.getLeft().updateBuffEffect(this, activeStatups, msel.getRight()); activeStatups.clear(); } - + if (this.isRidingBattleship()) { List> statups = new ArrayList<>(1); statups.add(new Pair<>(MapleBuffStat.MONSTER_RIDING, 0)); @@ -3880,19 +3945,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { this.announceBattleshipHp(); } } - + private static MapleBuffStat getSingletonStatupFromEffect(MapleStatEffect mse) { - for(Pair mbs : mse.getStatups()) { - if(isSingletonStatup(mbs.getLeft())) { + for (Pair mbs : mse.getStatups()) { + if (isSingletonStatup(mbs.getLeft())) { return mbs.getLeft(); } } - + return null; } - + private static boolean isSingletonStatup(MapleBuffStat mbs) { - switch(mbs) { //HPREC and MPREC are supposed to be singleton + switch (mbs) { //HPREC and MPREC are supposed to be singleton case COUPON_EXP1: case COUPON_EXP2: case COUPON_EXP3: @@ -3909,12 +3974,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { case SPEED: case JUMP: return false; - + default: return true; } } - + public void registerEffect(MapleStatEffect effect, long starttime, long expirationtime, boolean isSilent) { if (effect.isDragonBlood()) { prepareDragonBlood(effect); @@ -3936,8 +4001,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { beholderHealingSchedule = TimerManager.getInstance().register(new Runnable() { @Override public void run() { - if(awayFromWorld.get()) return; - + if (awayFromWorld.get()) { + return; + } + addHP(healEffect.getHp()); client.announce(MaplePacketCreator.showOwnBuffEffect(beholder, 2)); getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.summonSkill(getId(), beholder, 5), true); @@ -3952,8 +4019,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { beholderBuffSchedule = TimerManager.getInstance().register(new Runnable() { @Override public void run() { - if(awayFromWorld.get()) return; - + if (awayFromWorld.get()) { + return; + } + buffEffect.applyTo(MapleCharacter.this); client.announce(MaplePacketCreator.showOwnBuffEffect(beholder, 2)); getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.summonSkill(getId(), beholder, (int) (Math.random() * 3) + 6), true); @@ -3964,13 +4033,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } else if (effect.isRecovery()) { int healInterval = (ServerConstants.USE_ULTRA_RECOVERY) ? 2000 : 5000; final byte heal = (byte) effect.getX(); - + chrLock.lock(); try { - if(recoveryTask != null) { + if (recoveryTask != null) { recoveryTask.cancel(false); } - + recoveryTask = TimerManager.getInstance().register(new Runnable() { @Override public void run() { @@ -3997,16 +4066,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } else if (effect.getHpRRate() > 0 || effect.getMpRRate() > 0) { - if(effect.getHpRRate() > 0) { + if (effect.getHpRRate() > 0) { extraHpRec = effect.getHpR(); extraRecInterval = effect.getHpRRate(); } - - if(effect.getMpRRate() > 0) { + + if (effect.getMpRRate() > 0) { extraMpRec = effect.getMpR(); extraRecInterval = effect.getMpRRate(); } - + chrLock.lock(); try { stopExtraTask(); @@ -4014,70 +4083,76 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { chrLock.unlock(); } - + } else if (effect.isMapChair()) { startChairTask(); } - + effLock.lock(); chrLock.lock(); try { Integer sourceid = effect.getBuffSourceId(); Map toDeploy; Map appliedStatups = new LinkedHashMap<>(); - - for(Pair ps : effect.getStatups()) { + + for (Pair ps : effect.getStatups()) { appliedStatups.put(ps.getLeft(), new MapleBuffStatValueHolder(effect, starttime, ps.getRight())); } - - if(ServerConstants.USE_BUFF_MOST_SIGNIFICANT) { + + if (ServerConstants.USE_BUFF_MOST_SIGNIFICANT) { toDeploy = new LinkedHashMap<>(); Map> retrievedEffects = new LinkedHashMap<>(); Set retrievedStats = new LinkedHashSet<>(); - + for (Entry statup : appliedStatups.entrySet()) { MapleBuffStatValueHolder mbsvh = effects.get(statup.getKey()); MapleBuffStatValueHolder statMbsvh = statup.getValue(); - - if(mbsvh == null || mbsvh.value < statMbsvh.value || (mbsvh.value == statMbsvh.value && mbsvh.effect.getStatups().size() <= statMbsvh.effect.getStatups().size())) { + + if (mbsvh == null || mbsvh.value < statMbsvh.value || (mbsvh.value == statMbsvh.value && mbsvh.effect.getStatups().size() <= statMbsvh.effect.getStatups().size())) { toDeploy.put(statup.getKey(), statMbsvh); } else { - if(!isSingletonStatup(statup.getKey())) { + if (!isSingletonStatup(statup.getKey())) { retrievedEffects.put(mbsvh.effect.getBuffSourceId(), new Pair<>(mbsvh.effect, mbsvh.startTime)); - for(Pair mbs : mbsvh.effect.getStatups()) { + for (Pair mbs : mbsvh.effect.getStatups()) { retrievedStats.add(mbs.getLeft()); } } } - + Byte val = buffEffectsCount.get(statup.getKey()); - if(val != null) val = (byte)(val + 1); - else val = (byte) 1; - + if (val != null) { + val = (byte) (val + 1); + } else { + val = (byte) 1; + } + buffEffectsCount.put(statup.getKey(), val); } - - if(!isSilent) { + + if (!isSilent) { addItemEffectHolder(sourceid, expirationtime, appliedStatups); for (Entry statup : toDeploy.entrySet()) { effects.put(statup.getKey(), statup.getValue()); } - + retrievedEffects.put(sourceid, new Pair<>(effect, starttime)); propagateBuffEffectUpdates(retrievedEffects, retrievedStats); } } else { for (Entry statup : appliedStatups.entrySet()) { Byte val = buffEffectsCount.get(statup.getKey()); - if(val != null) val = (byte)(val + 1); - else val = (byte) 1; - + if (val != null) { + val = (byte) (val + 1); + } else { + val = (byte) 1; + } + buffEffectsCount.put(statup.getKey(), val); } - + toDeploy = appliedStatups; } - + addItemEffectHolder(sourceid, expirationtime, appliedStatups); for (Entry statup : toDeploy.entrySet()) { effects.put(statup.getKey(), statup.getValue()); @@ -4086,12 +4161,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); effLock.unlock(); } - + updateLocalStats(); } - + private static int getJobMapChair(MapleJob job) { - switch(job.getId() / 1000) { + switch (job.getId() / 1000) { case 0: return Beginner.MAP_CHAIR; case 1: @@ -4100,34 +4175,38 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return Legend.MAP_CHAIR; } } - + public boolean unregisterChairBuff() { - if(!ServerConstants.USE_CHAIR_EXTRAHEAL) return false; - + if (!ServerConstants.USE_CHAIR_EXTRAHEAL) { + return false; + } + int skillId = getJobMapChair(job); int skillLv = getSkillLevel(skillId); - if(skillLv > 0) { + if (skillLv > 0) { MapleStatEffect mapChairSkill = SkillFactory.getSkill(skillId).getEffect(skillLv); return cancelEffect(mapChairSkill, false, -1); } - + return false; } - + public boolean registerChairBuff() { - if(!ServerConstants.USE_CHAIR_EXTRAHEAL) return false; - + if (!ServerConstants.USE_CHAIR_EXTRAHEAL) { + return false; + } + int skillId = getJobMapChair(job); int skillLv = getSkillLevel(skillId); - if(skillLv > 0) { + if (skillLv > 0) { MapleStatEffect mapChairSkill = SkillFactory.getSkill(skillId).getEffect(skillLv); mapChairSkill.applyTo(this); return true; } - + return false; } - + public int getChair() { return chair.get(); } @@ -4148,11 +4227,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.add(q); } } - + return Collections.unmodifiableList(ret); } } - + public List getCrushRings() { Collections.sort(crushRings); return crushRings; @@ -4198,7 +4277,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { prtLock.unlock(); } } - + public MapleDoor getPlayerDoor() { prtLock.lock(); try { @@ -4207,7 +4286,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { prtLock.unlock(); } } - + public MapleDoor getMainTownDoor() { for (MapleDoor door : getDoors()) { if (door.getTownPortal().getId() == 0x80) { @@ -4217,7 +4296,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return null; } - + public void applyPartyDoor(MapleDoor door, boolean partyUpdate) { MapleParty chrParty; prtLock.lock(); @@ -4225,7 +4304,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (!partyUpdate) { pdoor = door; } - + chrParty = getParty(); if (chrParty != null) { chrParty.addDoor(id, door); @@ -4233,21 +4312,21 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { prtLock.unlock(); } - + silentPartyUpdateInternal(chrParty); } - + private MapleDoor removePartyDoor(boolean partyUpdate) { MapleDoor ret = null; MapleParty chrParty; - + prtLock.lock(); try { chrParty = getParty(); if (chrParty != null) { chrParty.removeDoor(id); } - + if (!partyUpdate) { ret = pdoor; pdoor = null; @@ -4255,11 +4334,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { prtLock.unlock(); } - + silentPartyUpdateInternal(chrParty); return ret; } - + private void removePartyDoor(MapleParty formerParty) { // player is no longer registered at this party formerParty.removeDoor(id); } @@ -4281,14 +4360,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.lock(); try { Set petExclude = excluded.get(petId); - - if(petExclude != null) petExclude.clear(); - else excluded.put(petId, new LinkedHashSet()); + + if (petExclude != null) { + petExclude.clear(); + } else { + excluded.put(petId, new LinkedHashSet()); + } } finally { chrLock.unlock(); } } - + public void addExcluded(int petId, int x) { chrLock.lock(); try { @@ -4297,20 +4379,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public void commitExcludedItems() { Map> petExcluded = this.getExcluded(); - + chrLock.lock(); try { excludedItems.clear(); } finally { chrLock.unlock(); } - - for(Map.Entry> pe : petExcluded.entrySet()) { + + for (Map.Entry> pe : petExcluded.entrySet()) { byte petIndex = this.getPetIndex(pe.getKey()); - if(petIndex < 0) continue; + if (petIndex < 0) { + continue; + } Set exclItems = pe.getValue(); if (!exclItems.isEmpty()) { @@ -4318,7 +4402,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.lock(); try { - for(Integer itemid: exclItems) { + for (Integer itemid : exclItems) { excludedItems.add(itemid); } } finally { @@ -4327,12 +4411,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + public void exportExcludedItems(MapleClient c) { Map> petExcluded = this.getExcluded(); - for(Map.Entry> pe : petExcluded.entrySet()) { + for (Map.Entry> pe : petExcluded.entrySet()) { byte petIndex = this.getPetIndex(pe.getKey()); - if(petIndex < 0) continue; + if (petIndex < 0) { + continue; + } Set exclItems = pe.getValue(); if (!exclItems.isEmpty()) { @@ -4340,7 +4426,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + public Map> getExcluded() { chrLock.lock(); try { @@ -4349,7 +4435,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); } } - + public Set getExcludedItems() { chrLock.lock(); try { @@ -4370,62 +4456,62 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public boolean hasNoviceExpRate() { return ServerConstants.USE_ENFORCE_NOVICE_EXPRATE && isBeginnerJob() && level < 11; } - + public int getExpRate() { if (hasNoviceExpRate()) { // base exp rate 1x for early levels idea thanks to Vcoc return 1; } - + return expRate; } - + public int getCouponExpRate() { return expCoupon; } - + public int getRawExpRate() { return expRate / (expCoupon * getWorldServer().getExpRate()); } - + public int getDropRate() { return dropRate; } - + public int getCouponDropRate() { return dropCoupon; } - + public int getRawDropRate() { return dropRate / (dropCoupon * getWorldServer().getDropRate()); } - + public int getBossDropRate() { World w = getWorldServer(); return (dropRate / w.getDropRate()) * w.getBossDropRate(); } - + public int getMesoRate() { return mesoRate; } - + public int getCouponMesoRate() { return mesoCoupon; } - + public int getRawMesoRate() { return mesoRate / (mesoCoupon * getWorldServer().getMesoRate()); } - + public int getQuestExpRate() { World w = getWorldServer(); return w.getExpRate() * w.getQuestRate(); } - + public int getQuestMesoRate() { World w = getWorldServer(); return w.getMesoRate() * w.getQuestRate(); } - + public int getFace() { return face; } @@ -4449,11 +4535,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public boolean getFinishedDojoTutorial() { return finishedDojoTutorial; } - + public void setUsedStorage() { usedStorage = true; } - + public List getFriendshipRings() { Collections.sort(friendshipRings); return friendshipRings; @@ -4475,16 +4561,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return null; } } - + public MapleAlliance getAlliance() { - if(mgc != null) { + if (mgc != null) { try { return Server.getInstance().getAlliance(getGuild().getAllianceId()); } catch (Exception ex) { ex.printStackTrace(); } } - + return null; } @@ -4512,7 +4598,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { try { int id; Connection con = DatabaseConnection.getConnection(); - + try (PreparedStatement ps = con.prepareStatement("SELECT accountid FROM characters WHERE name = ?")) { ps.setString(1, name); try (ResultSet rs = ps.executeQuery()) { @@ -4532,7 +4618,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return -1; } - + public static int getIdByName(String name) { try { int id; @@ -4594,17 +4680,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public boolean haveItemWithId(int itemid, boolean checkEquipped) { - return (inventory[ItemConstants.getInventoryType(itemid).ordinal()].findById(itemid) != null) || - (checkEquipped && inventory[MapleInventoryType.EQUIPPED.ordinal()].findById(itemid) != null); + return (inventory[ItemConstants.getInventoryType(itemid).ordinal()].findById(itemid) != null) + || (checkEquipped && inventory[MapleInventoryType.EQUIPPED.ordinal()].findById(itemid) != null); } - + public boolean haveItemEquipped(int itemid) { return (inventory[MapleInventoryType.EQUIPPED.ordinal()].findById(itemid) != null); } - + public boolean haveWeddingRing() { int rings[] = {1112806, 1112803, 1112807, 1112809}; - + for (int ringid : rings) { if (haveItemWithId(ringid, true)) { return true; @@ -4613,7 +4699,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return false; } - + public int getItemQuantity(int itemid, boolean checkEquipped) { int count = inventory[ItemConstants.getInventoryType(itemid).ordinal()].countById(itemid); if (checkEquipped) { @@ -4621,7 +4707,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return count; } - + public int getCleanItemQuantity(int itemid, boolean checkEquipped) { int count = inventory[ItemConstants.getInventoryType(itemid).ordinal()].countNotOwnedById(itemid); if (checkEquipped) { @@ -4661,11 +4747,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public int getLevel() { return level; } - + public int getFh() { Point pos = this.getPosition(); pos.y -= 6; - + if (map.getFootholds().findBelow(pos) == null) { return 0; } else { @@ -4694,7 +4780,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return skills.get(skill).masterlevel; } - + public int getTotalStr() { return localstr; } @@ -4718,19 +4804,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public int getTotalWatk() { return localwatk; } - + public int getMaxClassLevel() { return isCygnus() ? 120 : 200; } - + public int getMaxLevel() { - if(!ServerConstants.USE_ENFORCE_JOB_LEVEL_RANGE || isGmJob()) { + if (!ServerConstants.USE_ENFORCE_JOB_LEVEL_RANGE || isGmJob()) { return getMaxClassLevel(); } - + return GameConstants.getJobMaxLevel(job); } - + public int getMeso() { return meso.get(); } @@ -4750,7 +4836,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public MapleGuildCharacter getMGC() { return mgc; } - + public void setMGC(MapleGuildCharacter mgc) { this.mgc = mgc; } @@ -4765,37 +4851,37 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setMPC(MaplePartyCharacter mpc) { this.mpc = mpc; } - + public int getTargetHpBarHash() { return this.targetHpBarHash; } - + public void setTargetHpBarHash(int mobHash) { this.targetHpBarHash = mobHash; } - + public long getTargetHpBarTime() { return this.targetHpBarTime; } - + public void setTargetHpBarTime(long timeNow) { this.targetHpBarTime = timeNow; } - + public void setPlayerAggro(int mobHash) { setTargetHpBarHash(mobHash); setTargetHpBarTime(System.currentTimeMillis()); } - + public void resetPlayerAggro() { - if(getWorldServer().unregisterDisabledServerMessage(id)) { + if (getWorldServer().unregisterDisabledServerMessage(id)) { client.announceServerMessage(); } - + setTargetHpBarHash(0); setTargetHpBarTime(0); } - + public MapleMiniGame getMiniGame() { return miniGame; } @@ -4888,35 +4974,35 @@ public class MapleCharacter extends AbstractMapleCharacterObject { prtLock.unlock(); } } - + public List getPartyMembers() { List list = new LinkedList<>(); - + prtLock.lock(); try { - if(party != null) { - for(MaplePartyCharacter partyMembers: party.getMembers()) { + if (party != null) { + for (MaplePartyCharacter partyMembers : party.getMembers()) { list.add(partyMembers.getPlayer()); } } } finally { prtLock.unlock(); } - + return list; } - + public List getPartyMembersOnSameMap() { List list = new LinkedList<>(); int thisMapHash = this.getMap().hashCode(); - + prtLock.lock(); try { - if(party != null) { - for(MaplePartyCharacter partyMembers: party.getMembers()) { + if (party != null) { + for (MaplePartyCharacter partyMembers : party.getMembers()) { MapleCharacter chr = partyMembers.getPlayer(); MapleMap chrMap = chr.getMap(); - if(chrMap != null && chrMap.hashCode() == thisMapHash && chr.isLoggedinWorld()) { + if (chrMap != null && chrMap.hashCode() == thisMapHash && chr.isLoggedinWorld()) { list.add(chr); } } @@ -4924,24 +5010,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { prtLock.unlock(); } - + return list; } - + public boolean isPartyMember(MapleCharacter chr) { return isPartyMember(chr.getId()); } - + public boolean isPartyMember(int cid) { - for(MapleCharacter mpcu: getPartyMembers()) { - if(mpcu.getId() == cid) { + for (MapleCharacter mpcu : getPartyMembers()) { + if (mpcu.getId() == cid) { return true; } } - + return false; } - + public List retrieveRelevantDrops(int monsterId) { List pchars = new LinkedList<>(); for (MapleCharacter chr : getPartyMembers()) { @@ -4949,20 +5035,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject { pchars.add(chr); } } - - if(pchars.isEmpty()) pchars.add(this); + + if (pchars.isEmpty()) { + pchars.add(this); + } return MapleLootManager.retrieveRelevantDrops(monsterId, pchars); } public MaplePlayerShop getPlayerShop() { return playerShop; } - + public void setGMLevel(int level) { this.gmLevel = Math.min(level, 6); this.gmLevel = Math.max(level, 0); } - + public void closePlayerInteractions() { closeNpcShop(); closeTrade(); @@ -4970,27 +5058,29 @@ public class MapleCharacter extends AbstractMapleCharacterObject { closeMiniGame(); closeHiredMerchant(false); closePlayerMessenger(); - + client.closePlayerScriptInteractions(); resetPlayerAggro(); } - + public void closeNpcShop() { setShop(null); } - + public void closeTrade() { MapleTrade.cancelTrade(this); } - + public void closePlayerShop() { MaplePlayerShop mps = this.getPlayerShop(); - if(mps == null) return; - + if (mps == null) { + return; + } + if (mps.isOwner(this)) { mps.setOpen(false); getWorldServer().unregisterPlayerShop(mps); - + for (MaplePlayerShopItem mpsi : mps.getItems()) { if (mpsi.getBundles() >= 2) { Item iItem = mpsi.getItem().copy(); @@ -5006,11 +5096,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } this.setPlayerShop(null); } - + public void closeMiniGame() { MapleMiniGame game = this.getMiniGame(); - if(game == null) return; - + if (game == null) { + return; + } + this.setMiniGame(null); if (game.isOwner(this)) { this.getMap().broadcastMessage(MaplePacketCreator.removeMinigameBox(this)); @@ -5019,12 +5111,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { game.removeVisitor(this); } } - + public void closeHiredMerchant(boolean closeMerchant) { MapleHiredMerchant merchant = this.getHiredMerchant(); - if(merchant == null) return; - - if(closeMerchant) { + if (merchant == null) { + return; + } + + if (closeMerchant) { merchant.removeVisitor(this); this.setHiredMerchant(null); } else { @@ -5041,14 +5135,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + public void closePlayerMessenger() { MapleMessenger m = this.getMessenger(); - if(m == null) return; - + if (m == null) { + return; + } + World w = getWorldServer(); MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(this, this.getMessengerPosition()); - + w.leaveMessenger(m.getId(), messengerplayer); this.setMessenger(null); this.setMessengerPosition(4); @@ -5064,8 +5160,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public MaplePet getPet(int index) { - if(index < 0) return null; - + if (index < 0) { + return null; + } + petLock.lock(); try { return pets[index]; @@ -5089,7 +5187,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { petLock.unlock(); } } - + public byte getPetIndex(MaplePet pet) { petLock.lock(); try { @@ -5120,7 +5218,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return 0; } } - + public final MapleQuestStatus getMapleQuestStatus(final int quest) { synchronized (quests) { for (final MapleQuestStatus q : quests.values()) { @@ -5140,13 +5238,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return quests.get(quest.getId()); } } - + //---- \/ \/ \/ \/ \/ \/ \/ NOT TESTED \/ \/ \/ \/ \/ \/ \/ \/ \/ ---- - public final void setQuestAdd(final MapleQuest quest, final byte status, final String customData) { synchronized (quests) { if (!quests.containsKey(quest.getId())) { - final MapleQuestStatus stat = new MapleQuestStatus(quest, MapleQuestStatus.Status.getById((int)status)); + final MapleQuestStatus stat = new MapleQuestStatus(quest, MapleQuestStatus.Status.getById((int) status)); stat.setCustomData(customData); quests.put(quest.getId(), stat); } @@ -5177,10 +5274,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } //---- /\ /\ /\ /\ /\ /\ /\ NOT TESTED /\ /\ /\ /\ /\ /\ /\ /\ /\ ---- - public boolean needQuestItem(int questid, int itemid) { - if (questid <= 0) return true; //For non quest items :3 - + if (questid <= 0) { + return true; //For non quest items :3 + } int amountNeeded, questStatus = this.getQuestStatus(questid); if (questStatus == 0) { amountNeeded = MapleQuest.getInstance(questid).getStartItemAmountNeeded(itemid); @@ -5189,7 +5286,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } else { amountNeeded = MapleQuest.getInstance(questid).getCompleteItemAmountNeeded(itemid); } - + return amountNeeded > 0 && getInventory(ItemConstants.getInventoryType(itemid)).countById(itemid) < amountNeeded; } @@ -5204,7 +5301,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void clearSavedLocation(SavedLocationType type) { savedLocations[type.ordinal()] = null; } - + public int peekSavedLocation(String type) { SavedLocation sl = savedLocations[SavedLocationType.fromString(type).ordinal()]; if (sl == null) { @@ -5212,11 +5309,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return sl.getMapId(); } - + public int getSavedLocation(String type) { int m = peekSavedLocation(type); clearSavedLocation(SavedLocationType.fromString(type)); - + return m; } @@ -5231,7 +5328,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public Map getSkills() { return Collections.unmodifiableMap(skills); } - + public int getSkillLevel(int skill) { SkillEntry ret = skills.get(SkillFactory.getSkill(skill)); if (ret == null) { @@ -5319,19 +5416,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public Collection getSummonsValues() { return summons.values(); } - + public void clearSummons() { summons.clear(); } - + public MapleSummon getSummonByKey(int id) { return summons.get(id); } - + public boolean isSummonsEmpty() { return summons.isEmpty(); } - + public boolean containsSummon(MapleSummon summon) { return summons.containsValue(summon); } @@ -5355,7 +5452,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public int getWorld() { return world; } - + public World getWorldServer() { return Server.getInstance().getWorld(world); } @@ -5370,7 +5467,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { addCooldown(skillid, timeNow, time); } } - + public int gmLevel() { return gmLevel; } @@ -5378,11 +5475,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private void guildUpdate() { mgc.setLevel(level); mgc.setJobId(job.getId()); - + if (this.guildid < 1) { return; } - + try { Server.getInstance().memberLevelJobUpdate(this.mgc); //Server.getInstance().getGuild(guildid, world, mgc).gainGP(40); @@ -5394,7 +5491,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { e.printStackTrace(); } } - + public void handleEnergyChargeGain() { // to get here energychargelevel has to be > 0 Skill energycharge = isCygnus() ? SkillFactory.getSkill(ThunderBreaker.ENERGY_CHARGE) : SkillFactory.getSkill(Marauder.ENERGY_CHARGE); MapleStatEffect ceffect; @@ -5479,28 +5576,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public boolean haveItem(int itemid) { return getItemQuantity(itemid, false) > 0; } - + public boolean haveCleanItem(int itemid) { return getCleanItemQuantity(itemid, false) > 0; } - + public boolean hasEmptySlot(int itemId) { return getInventory(ItemConstants.getInventoryType(itemId)).getNextFreeSlot() > -1; } - + public boolean hasEmptySlot(byte invType) { return getInventory(MapleInventoryType.getByType(invType)).getNextFreeSlot() > -1; } public void increaseGuildCapacity() { int cost = MapleGuild.getIncreaseGuildCost(getGuild().getCapacity()); - + if (getMeso() < cost) { dropMessage(1, "You don't have enough mesos."); return; } - - if(Server.getInstance().increaseGuildCapacity(guildid)) { + + if (Server.getInstance().increaseGuildCapacity(guildid)) { gainMeso(-cost, true, false, true); } else { dropMessage(1, "Your guild already reached the maximum capacity of players."); @@ -5509,7 +5606,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public boolean isActiveBuffedValue(int skillid) { LinkedList allBuffs; - + effLock.lock(); chrLock.lock(); try { @@ -5518,7 +5615,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { chrLock.unlock(); effLock.unlock(); } - + for (MapleBuffStatValueHolder mbsvh : allBuffs) { if (mbsvh.effect.isSkill() && mbsvh.effect.getSourceId() == skillid) { return true; @@ -5526,11 +5623,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return false; } - + private boolean canBuyback(int fee, boolean usingMesos) { return (usingMesos ? this.getMeso() : cashshop.getCash(1)) >= fee; } - + private void applyBuybackFee(int fee, boolean usingMesos) { if (usingMesos) { this.gainMeso(-fee); @@ -5538,28 +5635,30 @@ public class MapleCharacter extends AbstractMapleCharacterObject { cashshop.gainCash(1, -fee); } } - + private long getNextBuybackTime() { return lastBuyback + ServerConstants.BUYBACK_COOLDOWN_MINUTES * 60 * 1000; } - + private boolean isBuybackInvincible() { return Server.getInstance().getCurrentTime() - lastBuyback < 4200; } - + private int getBuybackFee() { float fee = ServerConstants.BUYBACK_FEE; int grade = Math.min(Math.max(level, 30), 120) - 30; - + fee += (grade * ServerConstants.BUYBACK_LEVEL_STACK_FEE); - if (ServerConstants.USE_BUYBACK_WITH_MESOS) fee *= ServerConstants.BUYBACK_MESO_MULTIPLIER; - + if (ServerConstants.USE_BUYBACK_WITH_MESOS) { + fee *= ServerConstants.BUYBACK_MESO_MULTIPLIER; + } + return (int) Math.floor(fee); } - + public void showBuybackInfo() { String s = "#eBUYBACK STATUS#n\r\n\r\nCurrent buyback fee: #b" + getBuybackFee() + " " + (ServerConstants.USE_BUYBACK_WITH_MESOS ? "mesos" : "NX") + "#k\r\n\r\n"; - + long timeNow = Server.getInstance().getCurrentTime(); boolean avail = true; if (!isAlive()) { @@ -5573,45 +5672,45 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } s += "\r\n"; } - + if (timeNow < getNextBuybackTime() && avail) { s += "Buyback available in #r" + getTimeRemaining(getNextBuybackTime() - timeNow) + "#k"; s += "\r\n"; } - + this.showHint(s); } - + private static String getTimeRemaining(long timeLeft) { int seconds = (int) Math.floor(timeLeft / 1000) % 60; - int minutes = (int) Math.floor(timeLeft / (1000*60)) % 60; - + int minutes = (int) Math.floor(timeLeft / (1000 * 60)) % 60; + return (minutes > 0 ? (String.format("%02d", minutes) + " minutes, ") : "") + String.format("%02d", seconds) + " seconds"; } - + public boolean couldBuyback() { // Ronan's buyback system long timeNow = Server.getInstance().getCurrentTime(); - + if (timeNow - lastDeathtime > ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000) { this.dropMessage(5, "The period of time to decide has expired, therefore you are unable to buyback."); return false; } - + long nextBuybacktime = getNextBuybackTime(); if (timeNow < nextBuybacktime) { long timeLeft = nextBuybacktime - timeNow; this.dropMessage(5, "Next buyback available in " + getTimeRemaining(timeLeft) + "."); return false; } - + boolean usingMesos = ServerConstants.USE_BUYBACK_WITH_MESOS; int fee = getBuybackFee(); - + if (!canBuyback(fee, usingMesos)) { this.dropMessage(5, "You don't have " + fee + " " + (usingMesos ? "mesos" : "NX") + " to buyback."); return false; } - + lastBuyback = timeNow; applyBuybackFee(fee, usingMesos); return true; @@ -5631,12 +5730,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public boolean isGmJob() { int jn = job.getJobNiche(); return jn >= 8 && jn <= 9; } - + public boolean isCygnus() { return getJobType() == 1; } @@ -5669,11 +5768,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { prtLock.unlock(); } } - + public boolean isGuildLeader() { // true on guild master or jr. master return guildid > 0 && guildRank < 3; } - + public void leaveMap() { releaseControlledMonsters(); visibleMapObjects.clear(); @@ -5682,7 +5781,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { hpDecreaseTask.cancel(false); } } - + private int getChangedJobSp(MapleJob newJob) { int curSp = getUsedSp(newJob) + getJobRemainingSp(newJob); int spGain = 0; @@ -5690,54 +5789,54 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (curSp < expectedSp) { spGain += (expectedSp - curSp); } - + return getSpGain(spGain, curSp, job); } - + private int getUsedSp(MapleJob job) { int jobId = job.getId(); int spUsed = 0; - + for (Entry s : this.getSkills().entrySet()) { Skill skill = s.getKey(); if (GameConstants.isInJobTree(skill.getId(), jobId) && !skill.isBeginnerSkill()) { spUsed += s.getValue().skillevel; } } - + return spUsed; } - + private int getJobLevelSp(int level, MapleJob job, int jobBranch) { if (getJobStyleInternal(job.getId(), (byte) 0x40) == MapleJob.MAGICIAN) { level += 2; // starts earlier, level 8 } - + return 3 * level + GameConstants.getChangeJobSpUpgrade(jobBranch); } - + private int getJobMaxSp(MapleJob job) { int jobBranch = GameConstants.getJobBranch(job); int jobRange = GameConstants.getJobUpgradeLevelRange(jobBranch); return getJobLevelSp(jobRange, job, jobBranch); } - + private int getJobRemainingSp(MapleJob job) { int skillBook = GameConstants.getSkillBook(job.getId()); - + int ret = 0; for (int i = 0; i <= skillBook; i++) { ret += this.getRemainingSp(i); } - + return ret; } - + private int getSpGain(int spGain, MapleJob job) { int curSp = getUsedSp(job) + getJobRemainingSp(job); return getSpGain(spGain, curSp, job); } - + private int getSpGain(int spGain, int curSp, MapleJob job) { int maxSp = getJobMaxSp(job); @@ -5745,22 +5844,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject { int jobBranch = GameConstants.getJobBranch(job); return spGain; } - + private void levelUpGainSp() { if (GameConstants.getJobBranch(job) == 0) { return; } - + int spGain = 3; if (ServerConstants.USE_ENFORCE_JOB_SP_RANGE && !GameConstants.hasSPTable(job)) { spGain = getSpGain(spGain, job); } - + if (spGain > 0) { gainSp(spGain, GameConstants.getSkillBook(job.getId()), true); } } - + public synchronized void levelUp(boolean takeexp) { Skill improvingMaxHP = null; Skill improvingMaxMP = null; @@ -5773,7 +5872,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { statWlock.lock(); try { gainAp(5, true); - + int str = 0, dex = 0; if (level < 6) { str += 5; @@ -5792,7 +5891,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (isCygnus() && level > 10 && level < 70) { remainingAp++; } - + gainAp(remainingAp, true); } @@ -5878,9 +5977,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { level = maxClassLevel; //To prevent levels past the maximum } - + levelUpGainSp(); - + effLock.lock(); statWlock.lock(); try { @@ -5898,7 +5997,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { statup.add(new Pair<>(MapleStat.MAXMP, clientmaxmp)); statup.add(new Pair<>(MapleStat.STR, str)); statup.add(new Pair<>(MapleStat.DEX, dex)); - + client.announce(MaplePacketCreator.updatePlayerStats(statup, true, this)); } finally { statWlock.unlock(); @@ -5921,7 +6020,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } this.yellowMessage("You reached level " + level + ". Congratulations! As a token of your success, your inventory has been expanded a little bit."); - } + } } if (ServerConstants.USE_ADD_RATES_BY_LEVEL == true) { //For the rate upgrade revertLastPlayerRates(); @@ -5941,7 +6040,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void run() { MapleParty party; boolean partyLeader; - + prtLock.lock(); try { party = getParty(); @@ -5949,9 +6048,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { prtLock.unlock(); } - + if (party != null) { - if(partyLeader) party.assignNewLeader(client); + if (partyLeader) { + party.assignNewLeader(client); + } PartyOperationHandler.leaveParty(party, mpc, client); showHint("You have reached #blevel 10#k, therefore you must leave your #rstarter party#k."); @@ -6052,42 +6153,42 @@ public class MapleCharacter extends AbstractMapleCharacterObject { yellowMessage("Very nicely done! You have reached the so-long dreamed LEVEL 200!!! You are truly a hero among men, cheers upon you!"); } } - + public void setPlayerRates() { - this.expRate *= GameConstants.getPlayerBonusExpRate(this.level / 20); + this.expRate *= GameConstants.getPlayerBonusExpRate(this.level / 20); this.mesoRate *= GameConstants.getPlayerBonusMesoRate(this.level / 20); this.dropRate *= GameConstants.getPlayerBonusDropRate(this.level / 20); } public void revertLastPlayerRates() { - this.expRate /= GameConstants.getPlayerBonusExpRate((this.level - 1) / 20); + this.expRate /= GameConstants.getPlayerBonusExpRate((this.level - 1) / 20); this.mesoRate /= GameConstants.getPlayerBonusMesoRate((this.level - 1) / 20); this.dropRate /= GameConstants.getPlayerBonusDropRate((this.level - 1) / 20); } - + public void revertPlayerRates() { - this.expRate /= GameConstants.getPlayerBonusExpRate(this.level / 20); + this.expRate /= GameConstants.getPlayerBonusExpRate(this.level / 20); this.mesoRate /= GameConstants.getPlayerBonusMesoRate(this.level / 20); this.dropRate /= GameConstants.getPlayerBonusDropRate(this.level / 20); } - + public void setWorldRates() { World worldz = getWorldServer(); this.expRate *= worldz.getExpRate(); this.mesoRate *= worldz.getMesoRate(); this.dropRate *= worldz.getDropRate(); } - + public void revertWorldRates() { World worldz = getWorldServer(); this.expRate /= worldz.getExpRate(); this.mesoRate /= worldz.getMesoRate(); this.dropRate /= worldz.getDropRate(); } - + private void setCouponRates() { List couponEffects; - + Collection cashItems = this.getInventory(MapleInventoryType.CASH).list(); chrLock.lock(); try { @@ -6096,20 +6197,20 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { chrLock.unlock(); } - - for(Integer couponId: couponEffects) { + + for (Integer couponId : couponEffects) { commitBuffCoupon(couponId); } } - + private void revertCouponRates() { revertCouponsEffects(); } - + public void updateCouponRates() { if (cpnLock.tryLock()) { MapleInventory cashInv = this.getInventory(MapleInventoryType.CASH); - + effLock.lock(); chrLock.lock(); cashInv.lockInventory(); @@ -6118,98 +6219,103 @@ public class MapleCharacter extends AbstractMapleCharacterObject { setCouponRates(); } finally { cpnLock.unlock(); - + cashInv.unlockInventory(); chrLock.unlock(); effLock.unlock(); } } } - + public void resetPlayerRates() { expRate = 1; mesoRate = 1; dropRate = 1; - + expCoupon = 1; mesoCoupon = 1; dropCoupon = 1; } - + private int getCouponMultiplier(int couponId) { return activeCouponRates.get(couponId); } - + private void setExpCouponRate(int couponId, int couponQty) { this.expCoupon *= (getCouponMultiplier(couponId) * couponQty); } - + private void setDropCouponRate(int couponId, int couponQty) { this.dropCoupon *= (getCouponMultiplier(couponId) * couponQty); this.mesoCoupon *= (getCouponMultiplier(couponId) * couponQty); } - + private void revertCouponsEffects() { dispelBuffCoupons(); - + this.expRate /= this.expCoupon; this.dropRate /= this.dropCoupon; this.mesoRate /= this.mesoCoupon; - + this.expCoupon = 1; this.dropCoupon = 1; this.mesoCoupon = 1; } - + private List activateCouponsEffects() { List toCommitEffect = new LinkedList<>(); - - if(ServerConstants.USE_STACK_COUPON_RATES) { - for(Entry coupon: activeCoupons.entrySet()) { + + if (ServerConstants.USE_STACK_COUPON_RATES) { + for (Entry coupon : activeCoupons.entrySet()) { int couponId = coupon.getKey(); int couponQty = coupon.getValue(); toCommitEffect.add(couponId); - - if(ItemConstants.isExpCoupon(couponId)) setExpCouponRate(couponId, couponQty); - else setDropCouponRate(couponId, couponQty); + + if (ItemConstants.isExpCoupon(couponId)) { + setExpCouponRate(couponId, couponQty); + } else { + setDropCouponRate(couponId, couponQty); + } } - } - else { + } else { int maxExpRate = 1, maxDropRate = 1, maxExpCouponId = -1, maxDropCouponId = -1; - - for(Entry coupon: activeCoupons.entrySet()) { + + for (Entry coupon : activeCoupons.entrySet()) { int couponId = coupon.getKey(); - if(ItemConstants.isExpCoupon(couponId)) { - if(maxExpRate < getCouponMultiplier(couponId)) { + if (ItemConstants.isExpCoupon(couponId)) { + if (maxExpRate < getCouponMultiplier(couponId)) { maxExpCouponId = couponId; maxExpRate = getCouponMultiplier(couponId); } - } - else { - if(maxDropRate < getCouponMultiplier(couponId)) { + } else { + if (maxDropRate < getCouponMultiplier(couponId)) { maxDropCouponId = couponId; maxDropRate = getCouponMultiplier(couponId); } } } - - if(maxExpCouponId > -1) toCommitEffect.add(maxExpCouponId); - if(maxDropCouponId > -1) toCommitEffect.add(maxDropCouponId); - + + if (maxExpCouponId > -1) { + toCommitEffect.add(maxExpCouponId); + } + if (maxDropCouponId > -1) { + toCommitEffect.add(maxDropCouponId); + } + this.expCoupon = maxExpRate; this.dropCoupon = maxDropRate; this.mesoCoupon = maxDropRate; } - + this.expRate *= this.expCoupon; this.dropRate *= this.dropCoupon; this.mesoRate *= this.mesoCoupon; - + return toCommitEffect; } - + private void setActiveCoupons(Collection cashItems) { activeCoupons.clear(); activeCouponRates.clear(); @@ -6217,43 +6323,46 @@ public class MapleCharacter extends AbstractMapleCharacterObject { Map coupons = Server.getInstance().getCouponRates(); List active = Server.getInstance().getActiveCoupons(); - for (Item it: cashItems) { + for (Item it : cashItems) { if (ItemConstants.isRateCoupon(it.getItemId()) && active.contains(it.getItemId())) { Integer count = activeCoupons.get(it.getItemId()); - if(count != null) activeCoupons.put(it.getItemId(), count + 1); - else { + if (count != null) { + activeCoupons.put(it.getItemId(), count + 1); + } else { activeCoupons.put(it.getItemId(), 1); activeCouponRates.put(it.getItemId(), coupons.get(it.getItemId())); } } } } - + private void commitBuffCoupon(int couponid) { - if (!isLoggedin() || getCashShop().isOpened()) return; - + if (!isLoggedin() || getCashShop().isOpened()) { + return; + } + MapleStatEffect mse = ii.getItemEffect(couponid); mse.applyTo(this); } - + public void dispelBuffCoupons() { List allBuffs = getAllStatups(); - + for (MapleBuffStatValueHolder mbsvh : allBuffs) { if (ItemConstants.isRateCoupon(mbsvh.effect.getSourceId())) { cancelEffect(mbsvh.effect, false, mbsvh.startTime); } } } - + public Set getActiveCoupons() { chrLock.lock(); try { return Collections.unmodifiableSet(activeCoupons.keySet()); } finally { chrLock.unlock(); - } + } } public void addPlayerRing(MapleRing ring) { @@ -6266,10 +6375,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { this.addCrushRing(ring); } } - + public static MapleCharacter loadCharacterEntryFromDB(ResultSet rs, List equipped) { MapleCharacter ret = new MapleCharacter(); - + try { ret.accountid = rs.getInt("accountid"); ret.id = rs.getInt("id"); @@ -6280,7 +6389,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.hair = rs.getInt("hair"); // skipping pets, probably unneeded here - ret.level = rs.getInt("level"); ret.job = MapleJob.getById(rs.getInt("job")); ret.str = rs.getInt("str"); @@ -6298,15 +6406,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.gachaexp.set(rs.getInt("gachaexp")); ret.mapid = rs.getInt("map"); ret.initialSpawnPoint = rs.getInt("spawnpoint"); - + ret.gmLevel = rs.getInt("gm"); ret.world = rs.getByte("world"); ret.rank = rs.getInt("rank"); ret.rankMove = rs.getInt("rankMove"); ret.jobRank = rs.getInt("jobRank"); ret.jobRankMove = rs.getInt("jobRankMove"); - - if(equipped != null) { // players can have no equipped items at all, ofc + + if (equipped != null) { // players can have no equipped items at all, ofc MapleInventory inv = ret.inventory[MapleInventoryType.EQUIPPED.ordinal()]; for (Item item : equipped) { inv.addItemFromDB(item); @@ -6315,13 +6423,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } catch (SQLException sqle) { sqle.printStackTrace(); } - + return ret; } - + public MapleCharacter generateCharacterEntry() { MapleCharacter ret = new MapleCharacter(); - + ret.accountid = this.getAccountID(); ret.id = this.getId(); ret.name = this.getName(); @@ -6329,9 +6437,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.skinColor = this.getSkinColor(); ret.face = this.getFace(); ret.hair = this.getHair(); - + // skipping pets, probably unneeded here - ret.level = this.getLevel(); ret.job = this.getJob(); ret.str = this.getStr(); @@ -6349,42 +6456,42 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.gachaexp.set(this.getGachaExp()); ret.mapid = this.getMapId(); ret.initialSpawnPoint = this.getInitialSpawnpoint(); - + ret.inventory[MapleInventoryType.EQUIPPED.ordinal()] = this.getInventory(MapleInventoryType.EQUIPPED); - + ret.gmLevel = this.gmLevel(); ret.world = this.getWorld(); ret.rank = this.getRank(); ret.rankMove = this.getRankMove(); ret.jobRank = this.getJobRank(); ret.jobRankMove = this.getJobRankMove(); - + return ret; } - + private void loadCharSkillPoints(String[] skillPoints) { int sps[] = new int[skillPoints.length]; for (int i = 0; i < skillPoints.length; i++) { sps[i] = Integer.parseInt(skillPoints[i]); } - + setRemainingSp(sps); } - + public int getRemainingSp() { return getRemainingSp(job.getId()); //default } - + public void updateRemainingSp(int remainingSp) { updateRemainingSp(remainingSp, GameConstants.getSkillBook(job.getId())); } - + public static MapleCharacter loadCharFromDB(int charid, MapleClient client, boolean channelserver) throws SQLException { try { MapleCharacter ret = new MapleCharacter(); ret.client = client; ret.id = charid; - + Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM characters WHERE id = ?"); ps.setInt(1, charid); @@ -6455,16 +6562,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { int buddyCapacity = rs.getInt("buddyCapacity"); ret.buddylist = new BuddyList(buddyCapacity); ret.lastExpGainTime = rs.getTimestamp("lastExpGainTime").getTime(); - + ret.getInventory(MapleInventoryType.EQUIP).setSlotLimit(rs.getByte("equipslots")); ret.getInventory(MapleInventoryType.USE).setSlotLimit(rs.getByte("useslots")); ret.getInventory(MapleInventoryType.SETUP).setSlotLimit(rs.getByte("setupslots")); ret.getInventory(MapleInventoryType.ETC).setSlotLimit(rs.getByte("etcslots")); - + byte sandboxCheck = 0x0; for (Pair item : ItemFactory.INVENTORY.loadItems(ret.id, !channelserver)) { sandboxCheck |= item.getLeft().getFlag(); - + ret.getInventory(item.getRight()).addItemFromDB(item.getLeft()); Item itemz = item.getLeft(); if (itemz.getPetId() > -1) { @@ -6474,7 +6581,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } continue; } - + MapleInventoryType mit = item.getRight(); if (mit.equals(MapleInventoryType.EQUIP) || mit.equals(MapleInventoryType.EQUIPPED)) { Equip equip = (Equip) item.getLeft(); @@ -6483,33 +6590,35 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (item.getRight().equals(MapleInventoryType.EQUIPPED)) { ring.equip(); } - + ret.addPlayerRing(ring); } } } - if((sandboxCheck & ItemConstants.SANDBOX) == ItemConstants.SANDBOX) ret.setHasSandboxItem(); - + if ((sandboxCheck & ItemConstants.SANDBOX) == ItemConstants.SANDBOX) { + ret.setHasSandboxItem(); + } + World wserv = Server.getInstance().getWorld(ret.world); - + ret.partnerId = rs.getInt("partnerId"); ret.marriageItemid = rs.getInt("marriageItemId"); - if(ret.marriageItemid > 0 && ret.partnerId <= 0) { + if (ret.marriageItemid > 0 && ret.partnerId <= 0) { ret.marriageItemid = -1; - } else if(ret.partnerId > 0 && wserv.getRelationshipId(ret.id) <= 0) { + } else if (ret.partnerId > 0 && wserv.getRelationshipId(ret.id) <= 0) { ret.marriageItemid = -1; ret.partnerId = -1; } - + NewYearCardRecord.loadPlayerNewYearCards(ret); - + PreparedStatement ps2, ps3; ResultSet rs2, rs3; - + ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1"); ps3.setInt(1, charid); rs3 = ps3.executeQuery(); - while(rs3.next()) { + while (rs3.next()) { int petId = rs3.getInt("petid"); ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?"); @@ -6518,7 +6627,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.resetExcluded(petId); rs2 = ps2.executeQuery(); - while(rs2.next()) { + while (rs2.next()) { ret.addExcluded(petId, rs2.getInt("itemid")); } @@ -6527,13 +6636,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps3.close(); rs3.close(); - + ret.commitExcludedItems(); - + if (channelserver) { MapleMapFactory mapFactory = client.getChannelServer().getMapFactory(); ret.map = mapFactory.getMap(ret.mapid); - + if (ret.map == null) { ret.map = mapFactory.getMap(100000000); } @@ -6594,7 +6703,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { rs = ps.executeQuery(); if (rs.next()) { MapleClient retClient = ret.getClient(); - + retClient.setAccountName(rs.getString("name")); retClient.setCharacterSlots(rs.getByte("characterslots")); } @@ -6635,7 +6744,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps = con.prepareStatement("SELECT * FROM queststatus WHERE characterid = ?"); ps.setInt(1, charid); rs = ps.executeQuery(); - + Map loadedQuestStatus = new LinkedHashMap<>(); while (rs.next()) { MapleQuest q = MapleQuest.getInstance(rs.getShort("quest")); @@ -6656,34 +6765,34 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } rs.close(); ps.close(); - + // opportunity for improvement on questprogress/medalmaps calls to DB try (PreparedStatement pse = con.prepareStatement("SELECT * FROM questprogress WHERE characterid = ?")) { pse.setInt(1, charid); try (ResultSet rsProgress = pse.executeQuery()) { - while(rsProgress.next()) { + while (rsProgress.next()) { MapleQuestStatus status = loadedQuestStatus.get(rsProgress.getInt("queststatusid")); - if(status != null) { + if (status != null) { status.setProgress(rsProgress.getInt("progressid"), rsProgress.getString("progress")); } } } } - + try (PreparedStatement pse = con.prepareStatement("SELECT * FROM medalmaps WHERE characterid = ?")) { pse.setInt(1, charid); try (ResultSet rsMedalMaps = pse.executeQuery()) { - while(rsMedalMaps.next()) { + while (rsMedalMaps.next()) { MapleQuestStatus status = loadedQuestStatus.get(rsMedalMaps.getInt("queststatusid")); - if(status != null) { + if (status != null) { status.addMedalMap(rsMedalMaps.getInt("mapid")); } } } } - + loadedQuestStatus.clear(); - + ps = con.prepareStatement("SELECT skillid,skilllevel,masterlevel,expiration FROM skills WHERE characterid = ?"); ps.setInt(1, charid); rs = ps.executeQuery(); @@ -6716,13 +6825,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { rs = ps.executeQuery(); while (rs.next()) { final MapleDisease disease = MapleDisease.ordinal(rs.getInt("disease")); - if(disease == MapleDisease.NULL) continue; - + if (disease == MapleDisease.NULL) { + continue; + } + final int skillid = rs.getInt("mobskillid"), skilllv = rs.getInt("mobskilllv"); final long length = rs.getInt("length"); - + MobSkill ms = MobSkillFactory.getMobSkill(skillid, skilllv); - if(ms != null) { + if (ms != null) { loadedDiseases.put(disease, new Pair<>(length, ms)); } } @@ -6732,7 +6843,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setInt(1, ret.getId()); ps.executeUpdate(); ps.close(); - if(!loadedDiseases.isEmpty()) Server.getInstance().getPlayerBuffStorage().addDiseasesToStorage(ret.id, loadedDiseases); + if (!loadedDiseases.isEmpty()) { + Server.getInstance().getPlayerBuffStorage().addDiseasesToStorage(ret.id, loadedDiseases); + } ps = con.prepareStatement("SELECT * FROM skillmacros WHERE characterid = ?"); ps.setInt(1, charid); rs = ps.executeQuery(); @@ -6775,7 +6888,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.close(); ret.buddylist.loadFromDb(charid); ret.storage = MapleStorage.loadOrCreateFromDB(ret.accountid, ret.world); - + int startHp = ret.hp, startMp = ret.mp; ret.reapplyLocalStats(); ret.changeHpMp(startHp, startMp, true); @@ -6791,7 +6904,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ret.maplemount.setLevel(mountlevel); ret.maplemount.setTiredness(mounttiredness); ret.maplemount.setActive(false); - + con.close(); return ret; } catch (SQLException | RuntimeException e) { @@ -6799,10 +6912,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } return null; } - + public void reloadQuestExpirations() { - for(MapleQuestStatus mqs: quests.values()) { - if(mqs.getExpirationTime() > 0) { + for (MapleQuestStatus mqs : quests.values()) { + if (mqs.getExpirationTime() > 0) { questTimeLimit2(mqs.getQuest(), mqs.getExpirationTime()); } } @@ -6814,7 +6927,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { i = i.replace("rn", "Rn"); i = i.replace("vv", "Vv"); i = i.replace("VV", "Vv"); - + return i; } @@ -6835,6 +6948,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public static class MapleCoolDownValueHolder { + public int skillId; public long startTime, length; @@ -6864,7 +6978,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } else if (id == 1140100 || id == 1140130) { updateQuestMobCount(9101002); } - + int lastQuestProcessed = 0; try { synchronized (quests) { @@ -6892,10 +7006,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } private void playerDead() { + if (this.getMap().isCPQMap()) { + int lost = getCP(); + if (lost > 6) { + lost = 6; + } + getMap().broadcastMessage(MaplePacketCreator.playerDiedMessage(getName(), lost, getTeam())); + gainCP(-lost); + return; + } cancelAllBuffs(false); dispelDebuffs(); lastDeathtime = Server.getInstance().getCurrentTime(); - + EventInstanceManager eim = getEventInstance(); if (eim != null) { eim.playerKilled(this); @@ -6915,8 +7038,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject { MapleInventoryManipulator.removeById(client, ItemConstants.getInventoryType(charmID[i]), charmID[i], 1, true, false); } else if (mapid > 925020000 && mapid < 925030000) { this.dojoStage = 0; - } else if (mapid > 980000100 && mapid < 980000700) { - getMap().broadcastMessage(this, MaplePacketCreator.CPQDied(this)); } else if (getJob() != MapleJob.BEGINNER) { //Hmm... int XPdummy = ExpTable.getExpNeededForLevel(getLevel()); if (getMap().isTown()) { @@ -6948,7 +7069,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { unsitChairInternal(); client.announce(MaplePacketCreator.enableActions()); } - + private void unsitChairInternal() { if (chair.get() != 0) { setChair(0); @@ -6961,7 +7082,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { announce(MaplePacketCreator.cancelChair(-1)); } - + public void sitChair(int itemId) { if (client.tryacquireClient()) { try { @@ -6987,19 +7108,21 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + private void setChair(int chair) { this.chair.set(chair); } - + public void respawn(int returnMap) { respawn(null, returnMap); // unspecified EIM, don't force EIM unregister in this case } - + public void respawn(EventInstanceManager eim, int returnMap) { - if (eim != null) eim.unregisterPlayer(this); // some event scripts uses this... + if (eim != null) { + eim.unregisterPlayer(this); // some event scripts uses this... + } changeMap(returnMap); - + cancelAllBuffs(false); // thanks Oblivium91 for finding out players still could revive in area and take damage before returning to town updateHp(50); setStance(0); @@ -7012,8 +7135,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { dragonBloodSchedule = TimerManager.getInstance().register(new Runnable() { @Override public void run() { - if(awayFromWorld.get()) return; - + if (awayFromWorld.get()) { + return; + } + addHP(-bloodEffect.getX()); announce(MaplePacketCreator.showOwnBuffEffect(bloodEffect.getSourceId(), 5)); getMap().broadcastMessage(MapleCharacter.this, MaplePacketCreator.showBuffeffect(getId(), bloodEffect.getSourceId(), 5), false); @@ -7033,7 +7158,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { equipwatk = 0; //equipspeed = 0; //equipjump = 0; - + for (Item item : getInventory(MapleInventoryType.EQUIPPED)) { Equip equip = (Equip) item; equipmaxhp += equip.getHp(); @@ -7047,10 +7172,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { //equipspeed += equip.getSpeed(); //equipjump += equip.getJump(); } - + equipchanged = false; } - + localmaxhp += equipmaxhp; localmaxmp += equipmaxmp; localdex += equipdex; @@ -7060,7 +7185,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { localmagic += equipmagic; localwatk += equipwatk; } - + private void reapplyLocalStats() { effLock.lock(); chrLock.lock(); @@ -7135,16 +7260,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } /* - Integer speedbuff = getBuffedValue(MapleBuffStat.SPEED); - if (speedbuff != null) { - localspeed += speedbuff.intValue(); - } - Integer jumpbuff = getBuffedValue(MapleBuffStat.JUMP); - if (jumpbuff != null) { - localjump += jumpbuff.intValue(); - } - */ - + Integer speedbuff = getBuffedValue(MapleBuffStat.SPEED); + if (speedbuff != null) { + localspeed += speedbuff.intValue(); + } + Integer jumpbuff = getBuffedValue(MapleBuffStat.JUMP); + if (jumpbuff != null) { + localjump += jumpbuff.intValue(); + } + */ Integer blessing = getSkillLevel(10000000 * getJobType() + 12); if (blessing > 0) { localwatk += blessing; @@ -7184,7 +7308,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + private List> recalcLocalStats() { effLock.lock(); chrLock.lock(); @@ -7193,9 +7317,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { List> hpmpupdate = new ArrayList<>(2); int oldlocalmaxhp = localmaxhp; int oldlocalmaxmp = localmaxmp; - + reapplyLocalStats(); - + if (ServerConstants.USE_FIXED_RATIO_HPMP_UPDATE) { if (localmaxhp != oldlocalmaxhp) { Pair hpUpdate; @@ -7229,7 +7353,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + private void updateLocalStats() { effLock.lock(); statWlock.lock(); @@ -7335,10 +7459,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public synchronized void resetStats() { - if(!ServerConstants.USE_AUTOASSIGN_STARTERS_AP) { + if (!ServerConstants.USE_AUTOASSIGN_STARTERS_AP) { return; } - + effLock.lock(); statWlock.lock(); try { @@ -7386,11 +7510,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public void resetBattleshipHp() { this.battleshipHp = 400 * getSkillLevel(SkillFactory.getSkill(Corsair.BATTLE_SHIP)) + ((getLevel() - 120) * 200); } - + public void resetEnteredScript() { if (entered.containsKey(map.getId())) { entered.remove(map.getId()); @@ -7413,7 +7537,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public synchronized void saveCooldowns() { List listcd = getAllCooldowns(); - + if (!listcd.isEmpty()) { try { Connection con = DatabaseConnection.getConnection(); @@ -7428,13 +7552,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); } - + con.close(); } catch (SQLException se) { se.printStackTrace(); } } - + Map> listds = getAllDiseases(); if (!listds.isEmpty()) { try { @@ -7442,20 +7566,20 @@ public class MapleCharacter extends AbstractMapleCharacterObject { deleteWhereCharacterId(con, "DELETE FROM playerdiseases WHERE charid = ?"); try (PreparedStatement ps = con.prepareStatement("INSERT INTO playerdiseases (charid, disease, mobskillid, mobskilllv, length) VALUES (?, ?, ?, ?, ?)")) { ps.setInt(1, getId()); - + for (Entry> e : listds.entrySet()) { ps.setInt(2, e.getKey().ordinal()); - + MobSkill ms = e.getValue().getRight(); ps.setInt(3, ms.getSkillId()); ps.setInt(4, ms.getSkillLevel()); ps.setInt(5, e.getValue().getLeft().intValue()); ps.addBatch(); } - + ps.executeBatch(); } - + con.close(); } catch (SQLException se) { se.printStackTrace(); @@ -7473,7 +7597,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setInt(4, id); ps.executeUpdate(); } - + con.close(); } catch (SQLException se) { se.printStackTrace(); @@ -7483,19 +7607,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void saveLocationOnWarp() { // suggestion to remember the map before warp command thanks to Lei MaplePortal closest = map.findClosestPortal(getPosition()); int curMapid = getMapId(); - + for (int i = 0; i < savedLocations.length; i++) { if (savedLocations[i] == null) { savedLocations[i] = new SavedLocation(curMapid, closest != null ? closest.getId() : 0); } } } - + public void saveLocation(String type) { MaplePortal closest = map.findClosestPortal(getPosition()); savedLocations[SavedLocationType.fromString(type).ordinal()] = new SavedLocation(getMapId(), closest != null ? closest.getId() : 0); } - + public final boolean insertNewChar(CharacterFactoryRecipe recipe) { str = recipe.getStr(); dex = recipe.getDex(); @@ -7512,24 +7636,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject { meso.set(recipe.getMeso()); List> startingSkills = recipe.getStartingSkillLevel(); - for(Pair skEntry : startingSkills) { + for (Pair skEntry : startingSkills) { Skill skill = skEntry.getLeft(); this.changeSkillLevel(skill, skEntry.getRight().byteValue(), skill.getMaxLevel(), -1); } List> itemsWithType = recipe.getStartingItems(); - for(Pair itEntry : itemsWithType) { + for (Pair itEntry : itemsWithType) { this.getInventory(itEntry.getRight()).addItem(itEntry.getLeft()); } - + this.events.put("rescueGaga", new RescueGaga(0)); - + Connection con = null; PreparedStatement ps = null; try { con = DatabaseConnection.getConnection(); - + con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); con.setAutoCommit(false); ps = con.prepareStatement("INSERT INTO characters (str, dex, luk, `int`, gm, skincolor, gender, job, hair, face, map, meso, spawnpoint, accountid, name, world, hp, mp, maxhp, maxmp, level, ap, sp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); @@ -7555,7 +7679,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setInt(20, maxmp); ps.setInt(21, level); ps.setInt(22, remainingAp); - + StringBuilder sps = new StringBuilder(); for (int i = 0; i < remainingSp.length; i++) { sps.append(remainingSp[i]); @@ -7587,17 +7711,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { int[] selectedType; int[] selectedAction; - if(ServerConstants.USE_CUSTOM_KEYSET) { + if (ServerConstants.USE_CUSTOM_KEYSET) { selectedKey = GameConstants.getCustomKey(true); selectedType = GameConstants.getCustomType(true); selectedAction = GameConstants.getCustomAction(true); - } - else { + } else { selectedKey = GameConstants.getCustomKey(false); selectedType = GameConstants.getCustomType(false); selectedAction = GameConstants.getCustomAction(false); } - + ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)"); ps.setInt(1, id); for (int i = 0; i < selectedKey.length; i++) { @@ -7616,8 +7739,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ItemFactory.INVENTORY.saveItems(itemsWithType, id, con); - - if(!skills.isEmpty()) { + + if (!skills.isEmpty()) { ps = con.prepareStatement("INSERT INTO skills (characterid, skillid, skilllevel, masterlevel, expiration) VALUES (?, ?, ?, ?, ?)"); ps.setInt(1, id); for (Entry skill : skills.entrySet()) { @@ -7630,7 +7753,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.executeBatch(); ps.close(); } - + con.commit(); return true; } catch (Throwable t) { @@ -7656,31 +7779,36 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public void saveCharToDB() { - if(ServerConstants.USE_AUTOSAVE) { + if (ServerConstants.USE_AUTOSAVE) { Runnable r = new Runnable() { @Override public void run() { saveCharToDB(true); } }; - + ThreadManager.getInstance().newTask(r); //spawns a new thread to deal with this } else { saveCharToDB(true); } } - + //ItemFactory saveItems and monsterbook.saveCards are the most time consuming here. public synchronized void saveCharToDB(boolean notAutosave) { - if(!loggedIn) return; - + if (!loggedIn) { + return; + } + Calendar c = Calendar.getInstance(); - - if(notAutosave) FilePrinter.print(FilePrinter.SAVING_CHARACTER, "Attempting to save " + name + " at " + c.getTime().toString()); - else FilePrinter.print(FilePrinter.AUTOSAVING_CHARACTER, "Attempting to autosave " + name + " at " + c.getTime().toString()); - + + if (notAutosave) { + FilePrinter.print(FilePrinter.SAVING_CHARACTER, "Attempting to save " + name + " at " + c.getTime().toString()); + } else { + FilePrinter.print(FilePrinter.AUTOSAVING_CHARACTER, "Attempting to autosave " + name + " at " + c.getTime().toString()); + } + Server.getInstance().updateCharacterEntry(this); - + Connection con = null; try { con = DatabaseConnection.getConnection(); @@ -7694,7 +7822,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setInt(1, level); } ps.setInt(2, fame); - + effLock.lock(); statWlock.lock(); try { @@ -7720,7 +7848,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { statWlock.unlock(); effLock.unlock(); } - + ps.setInt(15, gmLevel); ps.setInt(16, skinColor.getId()); ps.setInt(17, gender); @@ -7748,7 +7876,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { ps.setInt(24, 0); } } - + prtLock.lock(); try { if (party != null) { @@ -7759,7 +7887,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { prtLock.unlock(); } - + ps.setInt(26, buddylist.getCapacity()); if (messenger != null) { ps.setInt(27, messenger.getId()); @@ -7780,9 +7908,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { for (int i = 1; i < 5; i++) { ps.setInt(i + 31, getSlots(i)); } - + monsterbook.saveCards(getId()); - + ps.setInt(36, bookCover); ps.setInt(37, vanquisherStage); ps.setInt(38, dojoPoints); @@ -7805,11 +7933,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { int updateRows = ps.executeUpdate(); ps.close(); - + if (updateRows < 1) { throw new RuntimeException("Character not in database (" + id + ")"); } - + List petList = new LinkedList<>(); petLock.lock(); try { @@ -7821,31 +7949,31 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } finally { petLock.unlock(); } - + for (MaplePet pet : petList) { pet.saveToDb(); } - - for(Entry> es: getExcluded().entrySet()) { // this set is already protected + + for (Entry> es : getExcluded().entrySet()) { // this set is already protected try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM petignores WHERE petid=?")) { ps2.setInt(1, es.getKey()); ps2.executeUpdate(); } - + try (PreparedStatement ps2 = con.prepareStatement("INSERT INTO petignores (petid, itemid) VALUES (?, ?)")) { ps2.setInt(1, es.getKey()); - for(Integer x: es.getValue()) { + for (Integer x : es.getValue()) { ps2.setInt(2, x); ps2.addBatch(); } ps2.executeBatch(); } } - + deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)"); ps.setInt(1, id); - + Set> keybindingItems = Collections.unmodifiableSet(keymap.entrySet()); for (Entry keybinding : keybindingItems) { ps.setInt(2, keybinding.getKey()); @@ -7855,7 +7983,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + deleteWhereCharacterId(con, "DELETE FROM skillmacros WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO skillmacros (characterid, skill1, skill2, skill3, name, shout, position) VALUES (?, ?, ?, ?, ?, ?, ?)"); ps.setInt(1, getId()); @@ -7873,16 +8001,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + List> itemsWithType = new ArrayList<>(); for (MapleInventory iv : inventory) { for (Item item : iv.list()) { itemsWithType.add(new Pair<>(item, iv.getType())); } } - + ItemFactory.INVENTORY.saveItems(itemsWithType, id, con); - + deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO skills (characterid, skillid, skilllevel, masterlevel, expiration) VALUES (?, ?, ?, ?, ?)"); ps.setInt(1, id); @@ -7895,7 +8023,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + deleteWhereCharacterId(con, "DELETE FROM savedlocations WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO savedlocations (characterid, `locationtype`, `map`, `portal`) VALUES (?, ?, ?, ?)"); ps.setInt(1, id); @@ -7909,7 +8037,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + deleteWhereCharacterId(con, "DELETE FROM trocklocations WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO trocklocations(characterid, mapid, vip) VALUES (?, ?, 0)"); for (int i = 0; i < getTrockSize(); i++) { @@ -7921,7 +8049,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + ps = con.prepareStatement("INSERT INTO trocklocations(characterid, mapid, vip) VALUES (?, ?, 1)"); for (int i = 0; i < getVipTrockSize(); i++) { if (viptrockmaps.get(i) != 999999999) { @@ -7932,7 +8060,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + deleteWhereCharacterId(con, "DELETE FROM buddies WHERE characterid = ? AND pending = 0"); ps = con.prepareStatement("INSERT INTO buddies (characterid, `buddyid`, `pending`, `group`) VALUES (?, ?, 0, ?)"); ps.setInt(1, id); @@ -7945,7 +8073,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + deleteWhereCharacterId(con, "DELETE FROM area_info WHERE charid = ?"); ps = con.prepareStatement("INSERT INTO area_info (id, charid, area, info) VALUES (DEFAULT, ?, ?, ?)"); ps.setInt(1, id); @@ -7956,28 +8084,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } ps.executeBatch(); ps.close(); - + deleteWhereCharacterId(con, "DELETE FROM eventstats WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO eventstats (characterid, name, info) VALUES (?, ?, ?)"); ps.setInt(1, id); - + for (Map.Entry entry : events.entrySet()) { ps.setString(2, entry.getKey()); ps.setInt(3, entry.getValue().getInfo()); ps.addBatch(); } - + ps.executeBatch(); ps.close(); - + deleteQuestProgressWhereCharacterId(con, id); - + ps = con.prepareStatement("INSERT INTO queststatus (`queststatusid`, `characterid`, `quest`, `status`, `time`, `expires`, `forfeited`) VALUES (DEFAULT, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); PreparedStatement psf; try (PreparedStatement pse = con.prepareStatement("INSERT INTO questprogress VALUES (DEFAULT, ?, ?, ?, ?)")) { psf = con.prepareStatement("INSERT INTO medalmaps VALUES (DEFAULT, ?, ?, ?)"); ps.setInt(1, id); - + synchronized (quests) { for (MapleQuestStatus q : quests.values()) { ps.setInt(2, q.getQuest().getId()); @@ -8006,24 +8134,23 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + } psf.close(); ps.close(); - + con.commit(); con.setAutoCommit(true); - - + if (cashshop != null) { cashshop.save(con); } - + if (storage != null && usedStorage) { storage.saveToDB(con); usedStorage = false; } - + } catch (SQLException | RuntimeException t) { FilePrinter.printError(FilePrinter.SAVE_CHAR, t, "Error saving " + name + " Level: " + level + " Job: " + job.getId()); try { @@ -8133,7 +8260,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setChalkboard(String text) { this.chalktext = text; } - + public void setDojoEnergy(int x) { this.dojoEnergy = Math.min(x, 10000); } @@ -8198,7 +8325,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setGuildRank(int _rank) { guildRank = _rank; } - + public void setAllianceRank(int _rank) { allianceRank = _rank; } @@ -8210,13 +8337,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setHasMerchant(boolean set) { try { Connection con = DatabaseConnection.getConnection(); - + try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = ? WHERE id = ?")) { ps.setInt(1, set ? 1 : 0); ps.setInt(2, id); ps.executeUpdate(); } - + con.close(); } catch (SQLException e) { e.printStackTrace(); @@ -8226,17 +8353,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void addMerchantMesos(int add) { int newAmount; - + try { newAmount = (int) Math.min((long) merchantmeso + add, Integer.MAX_VALUE); - + Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET MerchantMesos = ? WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) { ps.setInt(1, newAmount); ps.setInt(2, id); ps.executeUpdate(); } - + con.close(); } catch (SQLException e) { e.printStackTrace(); @@ -8260,12 +8387,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } merchantmeso = set; } - + public synchronized void withdrawMerchantMesos() { int merchantMeso = this.getMerchantMeso(); if (merchantMeso > 0) { int possible = Integer.MAX_VALUE - merchantMeso; - + if (possible > 0) { if (possible < merchantMeso) { this.gainMeso(possible, false); @@ -8281,12 +8408,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setHiredMerchant(MapleHiredMerchant merchant) { this.hiredMerchant = merchant; } - + private void hpChangeAction(int oldHp) { boolean playerDied = false; if (hp <= 0) { if (oldHp > hp) { - if(!isBuybackInvincible()) { + if (!isBuybackInvincible()) { playerDied = true; } else { hp = 1; @@ -8302,63 +8429,63 @@ public class MapleCharacter extends AbstractMapleCharacterObject { checkBerserk(isHidden()); } } - + private Pair calcHpRatioUpdate(int newHp, int oldHp) { int delta = newHp - oldHp; this.hp = calcHpRatioUpdate(hp, oldHp, delta); - + hpChangeAction(Short.MIN_VALUE); return new Pair<>(MapleStat.HP, hp); } - + private Pair calcMpRatioUpdate(int newMp, int oldMp) { int delta = newMp - oldMp; this.mp = calcMpRatioUpdate(mp, oldMp, delta); return new Pair<>(MapleStat.MP, mp); } - + private static int calcTransientRatio(float transientpoint) { int ret = (int) transientpoint; return !(ret <= 0 && transientpoint > 0.0f) ? ret : 1; } - + private Pair calcHpRatioTransient() { this.hp = calcTransientRatio(transienthp * localmaxhp); - + hpChangeAction(Short.MIN_VALUE); return new Pair<>(MapleStat.HP, hp); } - + private Pair calcMpRatioTransient() { this.mp = calcTransientRatio(transientmp * localmaxmp); return new Pair<>(MapleStat.MP, mp); } - + private int calcHpRatioUpdate(int curpoint, int maxpoint, int diffpoint) { int curMax = maxpoint; int nextMax = Math.min(30000, maxpoint + diffpoint); - + float temp = curpoint * nextMax; int ret = (int) Math.ceil(temp / curMax); - + transienthp = (maxpoint > nextMax) ? ((float) curpoint) / maxpoint : ((float) ret) / nextMax; return ret; } - + private int calcMpRatioUpdate(int curpoint, int maxpoint, int diffpoint) { int curMax = maxpoint; int nextMax = Math.min(30000, maxpoint + diffpoint); - + float temp = curpoint * nextMax; int ret = (int) Math.ceil(temp / curMax); - + transientmp = (maxpoint > nextMax) ? ((float) curpoint) / maxpoint : ((float) ret) / nextMax; return ret; } - + public boolean applyHpMpChange(int hpCon, int hpchange, int mpchange) { boolean zombify = hasDisease(MapleDisease.ZOMBIFY); - + effLock.lock(); statWlock.lock(); try { @@ -8371,7 +8498,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return false; } - if (cannotApplyHp) nextHp = 1; + if (cannotApplyHp) { + nextHp = 1; + } } updateHpMp(nextHp, nextMp); @@ -8381,7 +8510,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } } - + public void setInventory(MapleInventoryType type, MapleInventory inv) { inventory[type.ordinal()] = inv; } @@ -8405,7 +8534,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setLevel(int level) { this.level = level; } - + public void setMap(int PmapId) { this.mapid = PmapId; } @@ -8413,7 +8542,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setMap(MapleMap newmap) { this.map = newmap; } - + public void setMessenger(MapleMessenger messenger) { this.messenger = messenger; } @@ -8474,12 +8603,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { e.printStackTrace(); } } - + public int getDoorSlot() { - if(doorSlot != -1) return doorSlot; + if (doorSlot != -1) { + return doorSlot; + } return fetchDoorSlot(); } - + public int fetchDoorSlot() { prtLock.lock(); try { @@ -8489,7 +8620,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { prtLock.unlock(); } } - + public void setParty(MapleParty p) { prtLock.lock(); try { @@ -8509,7 +8640,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setPlayerShop(MaplePlayerShop playerShop) { this.playerShop = playerShop; } - + public void setSearch(String find) { search = find; } @@ -8541,64 +8672,66 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return false; } - + public int sellAllItemsFromName(byte invTypeId, String name) { //player decides from which inventory items should be sold. MapleInventoryType type = MapleInventoryType.getByType(invTypeId); - + MapleInventory inv = getInventory(type); inv.lockInventory(); try { Item it = inv.findByName(name); - if(it == null) { - return(-1); + if (it == null) { + return (-1); } - return(sellAllItemsFromPosition(ii, type, it.getPosition())); + return (sellAllItemsFromPosition(ii, type, it.getPosition())); } finally { inv.unlockInventory(); } } - + public int sellAllItemsFromPosition(MapleItemInformationProvider ii, MapleInventoryType type, short pos) { int mesoGain = 0; - + MapleInventory inv = getInventory(type); inv.lockInventory(); try { - for(short i = pos; i <= inv.getSlotLimit(); i++) { - if(inv.getItem(i) == null) continue; + for (short i = pos; i <= inv.getSlotLimit(); i++) { + if (inv.getItem(i) == null) { + continue; + } mesoGain += standaloneSell(getClient(), ii, type, i, inv.getItem(i).getQuantity()); } } finally { inv.unlockInventory(); } - - return(mesoGain); + + return (mesoGain); } private int standaloneSell(MapleClient c, MapleItemInformationProvider ii, MapleInventoryType type, short slot, short quantity) { if (quantity == 0xFFFF || quantity == 0) { quantity = 1; } - + MapleInventory inv = getInventory(type); inv.lockInventory(); try { Item item = inv.getItem((short) slot); - if (item == null){ //Basic check - return(0); + if (item == null) { //Basic check + return (0); } int itemid = item.getItemId(); if (ItemConstants.isRechargeable(itemid)) { quantity = item.getQuantity(); } else if (ItemConstants.isWeddingToken(itemid) || ItemConstants.isWeddingRing(itemid)) { - return(0); + return (0); } if (quantity < 0) { - return(0); + return (0); } short iQuant = item.getQuantity(); if (iQuant == 0xFFFF) { @@ -8610,59 +8743,59 @@ public class MapleCharacter extends AbstractMapleCharacterObject { int recvMesos = ii.getPrice(itemid, quantity); if (recvMesos > 0) { gainMeso(recvMesos, false); - return(recvMesos); + return (recvMesos); } } - return(0); + return (0); } finally { inv.unlockInventory(); } } - + private static boolean hasMergeFlag(Item item) { return (item.getFlag() & ItemConstants.MERGE_UNTRADEABLE) == ItemConstants.MERGE_UNTRADEABLE; } - + private static void setMergeFlag(Item item) { int flag = item.getFlag(); flag |= ItemConstants.MERGE_UNTRADEABLE; flag |= ItemConstants.UNTRADEABLE; item.setFlag((byte) flag); } - + private List getUpgradeableEquipped() { List list = new LinkedList<>(); - + for (Item item : getInventory(MapleInventoryType.EQUIPPED)) { if (ii.isUpgradeable(item.getItemId())) { list.add((Equip) item); } } - + return list; } - + private static List getEquipsWithStat(List>> equipped, StatUpgrade stat) { List equippedWithStat = new LinkedList<>(); - + for (Pair> eq : equipped) { if (eq.getRight().containsKey(stat)) { equippedWithStat.add(eq.getLeft()); } } - + return equippedWithStat; } - + public boolean mergeAllItemsFromName(String name) { MapleInventoryType type = MapleInventoryType.EQUIP; - + MapleInventory inv = getInventory(type); inv.lockInventory(); try { Item it = inv.findByName(name); - if(it == null) { + if (it == null) { return false; } @@ -8677,17 +8810,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } /* - for (Entry es : statups.entrySet()) { - System.out.println(es); - } - */ - + for (Entry es : statups.entrySet()) { + System.out.println(es); + } + */ for (Entry e : statups.entrySet()) { Double ev = Math.sqrt(e.getValue()); Set extraEquipped = new LinkedHashSet<>(equipUpgrades.keySet()); List statEquipped = getEquipsWithStat(upgradeableEquipped, e.getKey()); - float extraRate = (float)(0.2 * Math.random()); + float extraRate = (float) (0.2 * Math.random()); if (!statEquipped.isEmpty()) { float statRate = 1.0f - extraRate; @@ -8725,18 +8857,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject { dropMessage(6, showStr); } } - + return true; } finally { inv.unlockInventory(); } } - + public void mergeAllItemsFromPosition(Map statups, short pos) { MapleInventory inv = getInventory(MapleInventoryType.EQUIP); inv.lockInventory(); try { - for(short i = pos; i <= inv.getSlotLimit(); i++) { + for (short i = pos; i <= inv.getSlotLimit(); i++) { standaloneMerge(statups, getClient(), MapleInventoryType.EQUIP, i, inv.getItem(i)); } } finally { @@ -8746,14 +8878,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private void standaloneMerge(Map statups, MapleClient c, MapleInventoryType type, short slot, Item item) { short quantity; - if (item == null || (quantity = item.getQuantity()) < 1 || ii.isCash(item.getItemId()) || !ii.isUpgradeable(item.getItemId()) || hasMergeFlag(item)){ + if (item == null || (quantity = item.getQuantity()) < 1 || ii.isCash(item.getItemId()) || !ii.isUpgradeable(item.getItemId()) || hasMergeFlag(item)) { return; } - + Equip e = (Equip) item; for (Entry s : e.getStats().entrySet()) { Float newVal = statups.get(s.getKey()); - + float incVal = s.getValue().floatValue(); switch (s.getKey()) { case incPAD: @@ -8763,19 +8895,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { incVal = (float) Math.log(incVal); break; } - + if (newVal != null) { newVal += incVal; } else { newVal = incVal; } - + statups.put(s.getKey(), newVal); } - + MapleInventoryManipulator.removeFromSlot(c, type, (byte) slot, quantity, false); } - + public void setShop(MapleShop shop) { this.shop = shop; } @@ -8783,7 +8915,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setSlot(int slotid) { slots = slotid; } - + public void setTrade(MapleTrade trade) { this.trade = trade; } @@ -8816,41 +8948,41 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private long getDojoTimeLeft() { return client.getChannelServer().getDojoFinishTime(map.getId()) - Server.getInstance().getCurrentTime(); } - + public void showDojoClock() { if (map.isDojoFightMap()) { client.announce(MaplePacketCreator.getClock((int) (getDojoTimeLeft() / 1000))); } } - + public void timeoutFromDojo() { - if(map.isDojoMap()) { + if (map.isDojoMap()) { client.getPlayer().changeMap(client.getChannelServer().getMapFactory().getMap(925020002)); } } - + public void showUnderleveledInfo(MapleMonster mob) { chrLock.lock(); try { long curTime = Server.getInstance().getCurrentTime(); - if(nextUnderlevelTime < curTime) { + if (nextUnderlevelTime < curTime) { nextUnderlevelTime = curTime + (60 * 1000); // show underlevel info again after 1 minute - + showHint("You have gained #rno experience#k from defeating #e#b" + mob.getName() + "#k#n (lv. #b" + mob.getLevel() + "#k)! Take note you must have around the same level as the mob to start earning EXP from it."); } } finally { chrLock.unlock(); } } - + public void showHint(String msg) { showHint(msg, 500); } - + public void showHint(String msg, int length) { client.announceHint(msg, length); } - + public void showNote() { try { Connection con = DatabaseConnection.getConnection(); @@ -8863,7 +8995,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { client.announce(MaplePacketCreator.showNotes(rs, count)); } } - + con.close(); } catch (SQLException e) { e.printStackTrace(); @@ -8880,7 +9012,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void silentPartyUpdate() { silentPartyUpdateInternal(getParty()); } - + private void silentPartyUpdateInternal(MapleParty chrParty) { if (chrParty != null) { getWorldServer().updateParty(chrParty.getId(), PartyOperation.SILENT_UPDATE, getMPC()); @@ -8918,8 +9050,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void runFullnessSchedule(int petSlot) { MaplePet pet = getPet(petSlot); - if(pet == null) return; - + if (pet == null) { + return; + } + int newFullness = pet.getFullness() - PetDataFactory.getHunger(pet.getItemId()); if (newFullness <= 5) { pet.setFullness(15); @@ -8935,11 +9069,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } - + public boolean runTirednessSchedule() { - if(maplemount != null) { + if (maplemount != null) { int tiredness = maplemount.incrementAndGetTiredness(); - + this.getMap().broadcastMessage(MaplePacketCreator.updateMount(this.getId(), maplemount, false)); if (tiredness > 99) { maplemount.setTiredness(99); @@ -8948,7 +9082,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return false; } } - + return true; } @@ -8966,7 +9100,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } }, duration); } - + public void unequipAllPets() { for (int i = 0; i < 3; i++) { MaplePet pet = getPet(i); @@ -8983,18 +9117,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void unequipPet(MaplePet pet, boolean shift_left, boolean hunger) { byte petIdx = this.getPetIndex(pet); MaplePet chrPet = this.getPet(petIdx); - + if (chrPet != null) { chrPet.setSummoned(false); chrPet.saveToDb(); } - + this.getClient().getWorldServer().unregisterPetHunger(this, petIdx); getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true); - + removePet(pet, shift_left); commitExcludedItems(); - + client.announce(MaplePacketCreator.petStatUpdate(this)); client.announce(MaplePacketCreator.enableActions()); } @@ -9011,7 +9145,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { prtLock.unlock(); } } - + private void updatePartyMemberHPInternal() { if (party != null) { int curmaxhp = getCurrentMaxHp(); @@ -9042,23 +9176,25 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } announce(MaplePacketCreator.updateQuestInfo((short) qs.getQuest().getId(), qs.getNpc())); } - + public void awardQuestPoint(int awardedPoints) { - if (ServerConstants.QUEST_POINT_REQUIREMENT < 1 || awardedPoints < 1) return; - + if (ServerConstants.QUEST_POINT_REQUIREMENT < 1 || awardedPoints < 1) { + return; + } + int delta; synchronized (quests) { quest_fame += awardedPoints; - + delta = quest_fame / ServerConstants.QUEST_POINT_REQUIREMENT; quest_fame %= ServerConstants.QUEST_POINT_REQUIREMENT; } - - if(delta > 0) { + + if (delta > 0) { gainFame(delta); } } - + public void updateQuest(MapleQuestStatus quest) { synchronized (quests) { quests.put(quest.getQuestID(), quest); @@ -9072,10 +9208,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) { MapleQuest mquest = quest.getQuest(); short questid = mquest.getId(); - if(!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) { + if (!mquest.isSameDayRepeatable() && !MapleQuest.isExploitableQuest(questid)) { awardQuestPoint(ServerConstants.QUEST_POINT_PER_QUEST_COMPLETE); } - + announce(MaplePacketCreator.completeQuest(questid, quest.getCompletionTime())); } else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) { announce(MaplePacketCreator.updateQuest(quest, false)); @@ -9086,15 +9222,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } private void expireQuest(MapleQuest quest) { - if(getQuestStatus(quest.getId()) == MapleQuestStatus.Status.COMPLETED.getId()) return; - if(System.currentTimeMillis() < getMapleQuestStatus(quest.getId()).getExpirationTime()) return; - + if (getQuestStatus(quest.getId()) == MapleQuestStatus.Status.COMPLETED.getId()) { + return; + } + if (System.currentTimeMillis() < getMapleQuestStatus(quest.getId()).getExpirationTime()) { + return; + } + announce(MaplePacketCreator.questExpire(quest.getId())); MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); newStatus.setForfeited(getQuest(quest).getForfeited() + 1); updateQuest(newStatus); } - + public void cancelQuestExpirationTask() { evtLock.lock(); try { @@ -9106,25 +9246,25 @@ public class MapleCharacter extends AbstractMapleCharacterObject { evtLock.unlock(); } } - + public void forfeitExpirableQuests() { evtLock.lock(); try { - for(MapleQuest quest : questExpirations.keySet()) { + for (MapleQuest quest : questExpirations.keySet()) { quest.forfeit(this); } - + questExpirations.clear(); } finally { evtLock.unlock(); } } - + public void questExpirationTask() { evtLock.lock(); try { - if(!questExpirations.isEmpty()) { - if(questExpireTask == null) { + if (!questExpirations.isEmpty()) { + if (questExpireTask == null) { questExpireTask = TimerManager.getInstance().register(new Runnable() { @Override public void run() { @@ -9137,24 +9277,26 @@ public class MapleCharacter extends AbstractMapleCharacterObject { evtLock.unlock(); } } - + private void runQuestExpireTask() { evtLock.lock(); try { long timeNow = Server.getInstance().getCurrentTime(); List expireList = new LinkedList<>(); - - for(Entry qe : questExpirations.entrySet()) { - if(qe.getValue() <= timeNow) expireList.add(qe.getKey()); + + for (Entry qe : questExpirations.entrySet()) { + if (qe.getValue() <= timeNow) { + expireList.add(qe.getKey()); + } } - - if(!expireList.isEmpty()) { - for(MapleQuest quest : expireList) { + + if (!expireList.isEmpty()) { + for (MapleQuest quest : expireList) { expireQuest(quest); questExpirations.remove(quest); } - - if(questExpirations.isEmpty()) { + + if (questExpirations.isEmpty()) { questExpireTask.cancel(false); questExpireTask = null; } @@ -9163,11 +9305,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { evtLock.unlock(); } } - + private void registerQuestExpire(MapleQuest quest, long time) { evtLock.lock(); try { - if(questExpireTask == null) { + if (questExpireTask == null) { questExpireTask = TimerManager.getInstance().register(new Runnable() { @Override public void run() { @@ -9175,22 +9317,22 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } }, 10 * 1000); } - + questExpirations.put(quest, Server.getInstance().getCurrentTime() + time); } finally { evtLock.unlock(); } } - + public void questTimeLimit(final MapleQuest quest, int seconds) { registerQuestExpire(quest, seconds * 1000); announce(MaplePacketCreator.addQuestTimeLimit(quest.getId(), seconds * 1000)); } - + public void questTimeLimit2(final MapleQuest quest, long expires) { long timeLeft = expires - System.currentTimeMillis(); - - if(timeLeft <= 0) { + + if (timeLeft <= 0) { expireQuest(quest); } else { registerQuestExpire(quest, timeLeft); @@ -9228,7 +9370,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void sendSpawnData(MapleClient client) { if (!this.isHidden() || client.getPlayer().gmLevel() > 1) { client.announce(MaplePacketCreator.spawnPlayerMapObject(client, this, false)); - + if (buffEffects.containsKey(getJobMapChair(job))) { // mustn't effLock, chrLock this function client.announce(MaplePacketCreator.giveForeignChairSkillEffect(id)); } @@ -9241,7 +9383,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } @Override - public void setObjectId(int id) {} + public void setObjectId(int id) { + } @Override public String toString() { @@ -9259,37 +9402,37 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public CashShop getCashShop() { return cashshop; } - + public Set getNewYearRecords() { return newyears; } - + public Set getReceivedNewYearRecords() { Set received = new LinkedHashSet<>(); - - for(NewYearCardRecord nyc : newyears) { - if(nyc.isReceiverCardReceived()) { + + for (NewYearCardRecord nyc : newyears) { + if (nyc.isReceiverCardReceived()) { received.add(nyc); } } - + return received; } - + public NewYearCardRecord getNewYearRecord(int cardid) { - for(NewYearCardRecord nyc : newyears) { - if(nyc.getId() == cardid) { + for (NewYearCardRecord nyc : newyears) { + if (nyc.getId() == cardid) { return nyc; } } - + return null; } - + public void addNewYearRecord(NewYearCardRecord newyear) { newyears.add(newyear); } - + public void removeNewYearRecord(NewYearCardRecord newyear) { newyears.remove(newyear); } @@ -9349,7 +9492,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { client.disconnect(false, false); } }, 5000); - + Server.getInstance().broadcastGMMessage(this.getWorld(), MaplePacketCreator.serverNotice(6, MapleCharacter.makeMapleReadable(this.name) + " was autobanned for " + reason)); } @@ -9449,12 +9592,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return false; } - + //EVENTS private byte team = 0; private MapleFitness fitness; private MapleOla ola; private long snowballattack; + private int lingua = 0;// 0 PTB 1 ESP 2 ENG + public static final List itens = new ArrayList(); + public static final List item = new ArrayList(); public byte getTeam() { return team; @@ -9487,69 +9633,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setLastSnowballAttack(long time) { this.snowballattack = time; } - - //Monster Carnival - private int cp = 0; - private int obtainedcp = 0; - private MonsterCarnivalParty carnivalparty; - private MonsterCarnival carnival; - - public MonsterCarnivalParty getCarnivalParty() { - return carnivalparty; - } - - public void setCarnivalParty(MonsterCarnivalParty party) { - this.carnivalparty = party; - } - - public MonsterCarnival getCarnival() { - return carnival; - } - - public void setCarnival(MonsterCarnival car) { - this.carnival = car; - } - - public int getCP() { - return cp; - } - - public int getObtainedCP() { - return obtainedcp; - } - - public void addCP(int cp) { - this.cp += cp; - this.obtainedcp += cp; - } - - public void useCP(int cp) { - this.cp -= cp; - } - - public void setObtainedCP(int cp) { - this.obtainedcp = cp; - } - - public int getAndRemoveCP() { - int rCP = 10; - if (cp < 9) { - rCP = cp; - cp = 0; - } else { - cp -= 10; - } - - return rCP; - } public AutobanManager getAutobanManager() { return autoban; } - + public void equippedItem(Equip equip) { int itemid = equip.getItemId(); - + if (itemid == 1122017) { this.equipPendantOfSpirit(); } else if (itemid == 1812000) { // meso magnet @@ -9560,10 +9651,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject { equippedPetItemIgnore = true; } } - + public void unequippedItem(Equip equip) { int itemid = equip.getItemId(); - + if (itemid == 1122017) { this.unequipPendantOfSpirit(); } else if (itemid == 1812000) { // meso magnet @@ -9574,19 +9665,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject { equippedPetItemIgnore = false; } } - + public boolean isEquippedMesoMagnet() { return equippedMesoMagnet; } - + public boolean isEquippedItemPouch() { return equippedItemPouch; } - + public boolean isEquippedPetItemIgnore() { return equippedPetItemIgnore; } - + private void equipPendantOfSpirit() { if (pendantOfSpirit == null) { pendantOfSpirit = TimerManager.getInstance().register(new Runnable() { @@ -9610,13 +9701,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } pendantExp = 0; } - + private Collection getUpgradeableEquipList() { Collection fullList = getInventory(MapleInventoryType.EQUIPPED).list(); if (ServerConstants.USE_EQUIPMNT_LVLUP_CASH) { return fullList; } - + Collection eqpList = new LinkedHashSet<>(); for (Item it : fullList) { if (!ii.isCash(it.getItemId())) { @@ -9626,47 +9717,49 @@ public class MapleCharacter extends AbstractMapleCharacterObject { return eqpList; } - + public void increaseEquipExp(int expGain) { - if(expGain < 0) expGain = Integer.MAX_VALUE; - + if (expGain < 0) { + expGain = Integer.MAX_VALUE; + } + for (Item item : getUpgradeableEquipList()) { Equip nEquip = (Equip) item; String itemName = ii.getName(nEquip.getItemId()); if (itemName == null) { continue; } - + nEquip.gainItemExp(client, expGain); } } - + public void showAllEquipFeatures() { String showMsg = ""; - + for (Item item : getInventory(MapleInventoryType.EQUIPPED).list()) { Equip nEquip = (Equip) item; String itemName = ii.getName(nEquip.getItemId()); if (itemName == null) { continue; } - + showMsg += nEquip.showEquipFeatures(client); } - - if(!showMsg.isEmpty()) { + + if (!showMsg.isEmpty()) { this.showHint("#ePLAYER EQUIPMENTS:#n\r\n\r\n" + showMsg, 400); } } - + public void broadcastMarriageMessage() { MapleGuild guild = this.getGuild(); - if(guild != null) { + if (guild != null) { guild.broadcast(MaplePacketCreator.marriageMessage(0, name)); } - + MapleFamily family = this.getFamily(); - if(family != null) { + if (family != null) { family.broadcast(MaplePacketCreator.marriageMessage(1, name)); } } @@ -9684,19 +9777,29 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public final void empty(final boolean remove) { - if (dragonBloodSchedule != null) { dragonBloodSchedule.cancel(true); } + if (dragonBloodSchedule != null) { + dragonBloodSchedule.cancel(true); + } dragonBloodSchedule = null; - if (hpDecreaseTask != null) { hpDecreaseTask.cancel(true); } + if (hpDecreaseTask != null) { + hpDecreaseTask.cancel(true); + } hpDecreaseTask = null; - if (beholderHealingSchedule != null) { beholderHealingSchedule.cancel(true); } + if (beholderHealingSchedule != null) { + beholderHealingSchedule.cancel(true); + } beholderHealingSchedule = null; - if (beholderBuffSchedule != null) { beholderBuffSchedule.cancel(true); } + if (beholderBuffSchedule != null) { + beholderBuffSchedule.cancel(true); + } beholderBuffSchedule = null; - if (berserkSchedule != null) { berserkSchedule.cancel(true); } + if (berserkSchedule != null) { + berserkSchedule.cancel(true); + } berserkSchedule = null; unregisterChairBuff(); @@ -9705,35 +9808,47 @@ public class MapleCharacter extends AbstractMapleCharacterObject { cancelSkillCooldownTask(); cancelExpirationTask(); - if (questExpireTask != null) { questExpireTask.cancel(true); } + if (questExpireTask != null) { + questExpireTask.cancel(true); + } questExpireTask = null; - if (recoveryTask != null) { recoveryTask.cancel(true); } + if (recoveryTask != null) { + recoveryTask.cancel(true); + } recoveryTask = null; - if (extraRecoveryTask != null) { extraRecoveryTask.cancel(true); } + if (extraRecoveryTask != null) { + extraRecoveryTask.cancel(true); + } extraRecoveryTask = null; // already done on unregisterChairBuff /* if (chairRecoveryTask != null) { chairRecoveryTask.cancel(true); } - chairRecoveryTask = null; */ - - if (pendantOfSpirit != null) { pendantOfSpirit.cancel(true); } + chairRecoveryTask = null; */ + if (pendantOfSpirit != null) { + pendantOfSpirit.cancel(true); + } pendantOfSpirit = null; - + + if (timer != null) { + timer.cancel(true); + } + timer = null; + evtLock.lock(); try { if (questExpireTask != null) { questExpireTask.cancel(false); questExpireTask = null; - + questExpirations.clear(); questExpirations = null; } } finally { evtLock.unlock(); } - + if (maplemount != null) { maplemount.empty(); maplemount = null; @@ -9745,7 +9860,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { mgc = null; party = null; family = null; - + getWorldServer().registerTimedMapObject(new Runnable() { @Override public void run() { @@ -9756,7 +9871,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { }, 5 * 60 * 1000); } } - + public void logOff() { this.loggedIn = false; @@ -9778,7 +9893,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public boolean getWhiteChat() { - return !isGM() ? false : whiteChat; + return !isGM() ? false : whiteChat; } public void toggleWhiteChat() { @@ -9825,22 +9940,25 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public void setDragon(MapleDragon dragon) { this.dragon = dragon; } - + public long getJailExpirationTimeLeft() { return jailExpiration - System.currentTimeMillis(); } - + private void setFutureJailExpiration(long time) { jailExpiration = System.currentTimeMillis() + time; } - + public void addJailExpirationTime(long time) { long timeLeft = getJailExpirationTimeLeft(); - if(timeLeft <= 0) setFutureJailExpiration(time); - else setFutureJailExpiration(timeLeft + time); + if (timeLeft <= 0) { + setFutureJailExpiration(time); + } else { + setFutureJailExpiration(timeLeft + time); + } } - + public void removeJailExpirationTime() { jailExpiration = 0; } @@ -9861,8 +9979,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } catch (SQLException e) { e.printStackTrace(); } finally { - try { ps.close(); } catch (Exception e) { /* ignored */ } - try { con.close(); } catch (Exception e) { /* ignored */ } + try { + ps.close(); + } catch (Exception e) { /* ignored */ } + try { + con.close(); + } catch (Exception e) { /* ignored */ } } return -1; } @@ -9879,8 +10001,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } catch (SQLException e) { e.printStackTrace(); } finally { - try { ps.close(); } catch (Exception e) { /* ignored */ } - try { con.close(); } catch (Exception e) { /* ignored */ } + try { + ps.close(); + } catch (Exception e) { /* ignored */ } + try { + con.close(); + } catch (Exception e) { /* ignored */ } } } @@ -9900,8 +10026,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } catch (SQLException e) { e.printStackTrace(); } finally { - try { ps.close(); } catch (Exception e) { /* ignored */ } - try { con.close(); } catch (Exception e) { /* ignored */ } + try { + ps.close(); + } catch (Exception e) { /* ignored */ } + try { + con.close(); + } catch (Exception e) { /* ignored */ } } } @@ -9926,8 +10056,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } catch (SQLException e) { e.printStackTrace(); } finally { - try { ps.close(); } catch (Exception e) { /* ignored */ } - try { con.close(); } catch (Exception e) { /* ignored */ } + try { + ps.close(); + } catch (Exception e) { /* ignored */ } + try { + con.close(); + } catch (Exception e) { /* ignored */ } } throw new RuntimeException(); } @@ -9945,4 +10079,140 @@ public class MapleCharacter extends AbstractMapleCharacterObject { setLevel(0); levelUp(true); } + + private int cp = 0; + private int totCP = 0; + private MonsterCarnival monsterCarnival; + private int FestivalPoints; + private boolean challenged = false; + + public void gainFestivalPoints(int gain) { + this.FestivalPoints += gain; + } + + public int getFestivalPoints() { + return this.FestivalPoints; + } + + public void setFestivalPoints(int pontos) { + this.FestivalPoints = pontos; + } + + public int getCP() { + return cp; + } + + public short totalCP, availableCP; + + public void addCP(int ammount) { + totalCP += ammount; + availableCP += ammount; + } + + public void useCP(int ammount) { + availableCP -= ammount; + } + + public void gainCP(int gain) { + if (this.getMonsterCarnival() != null) { + if (gain > 0) { + this.setTotalCP(this.getTotalCP() + gain); + } + this.setCP(this.getCP() + gain); + if (this.getParty() != null) { + this.getMonsterCarnival().setCP(this.getMonsterCarnival().getCP(team) + gain, team); + if (gain > 0) { + this.getMonsterCarnival().setTotalCP(this.getMonsterCarnival().getTotalCP(team) + gain, team); + } + } + if (this.getCP() > this.getTotalCP()) { + this.setTotalCP(this.getCP()); + } + this.getClient().announce(MaplePacketCreator.CPUpdate(false, this.getCP(), this.getTotalCP(), getTeam())); + if (this.getParty() != null && getTeam() != -1) { + this.getMap().broadcastMessage(MaplePacketCreator.CPUpdate(true, this.getMonsterCarnival().getCP(team), this.getMonsterCarnival().getTotalCP(team), getTeam())); + } else { + } + } + } + + public void setTotalCP(int a) { + this.totCP = a; + } + + public void setCP(int a) { + this.cp = a; + } + + public int getTotalCP() { + return totCP; + } + + public int getAvailableCP() { + return availableCP; + } + + public void resetCP() { + this.cp = 0; + this.totCP = 0; + this.monsterCarnival = null; + } + + public MonsterCarnival getMonsterCarnival() { + return monsterCarnival; + } + + public void setMonsterCarnival(MonsterCarnival monsterCarnival) { + this.monsterCarnival = monsterCarnival; + } + + public boolean isChallenged() { + return challenged; + } + + public void setChallenged(boolean challenged) { + this.challenged = challenged; + } + + public void setLingua(int a) { + this.lingua = a; + } + + public int getLingua() { + return lingua; + } + + public void setItens(String item) { + if (!itens.contains(item)) { + this.itens.add(item); + } + } + + public static List getItens() { + return itens; + } + + public void setEquips(Item item) { + this.item.add(item); + } + + public static List getItem() { + return item; + } + + public Item getItemid(int numb) { + return this.item.get(numb); + } + + public void removeItem(Item item) { + if (this.item.contains(item)) { + this.item.remove(item); + } + } + + public void obterItens() { + for (Item item : getItem()) { + getClient().getAbstractPlayerInteraction().gainItem(item.getItemId(), item.getQuantity()); + } + } } diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java index 55089dd751..ec62f10fe8 100644 --- a/src/client/MapleClient.java +++ b/src/client/MapleClient.java @@ -1,23 +1,23 @@ /* -This file is part of the OdinMS Maple Story Server -Copyright (C) 2008 Patrick Huy -Matthias Butz -Jan Christian Meyer + 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 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. + 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 . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ package client; @@ -84,1437 +84,1448 @@ import net.server.coordinator.MapleLoginBypassCoordinator; public class MapleClient { - public static final int LOGIN_NOTLOGGEDIN = 0; - public static final int LOGIN_SERVER_TRANSITION = 1; - public static final int LOGIN_LOGGEDIN = 2; - public static final String CLIENT_KEY = "CLIENT"; - public static final String CLIENT_HWID = "HWID"; - public static final String CLIENT_NIBBLEHWID = "HWID2"; - private MapleAESOFB send; - private MapleAESOFB receive; - private final IoSession session; - private MapleCharacter player; - private int channel = 1; - private int accId = 0; - private boolean loggedIn = false; - private boolean serverTransition = false; - private Calendar birthday = null; - private String accountName = null; - private int world; - private long lastPong; - private int gmlevel; - private Set macs = new HashSet<>(); - private Map engines = new HashMap<>(); - private byte characterSlots = 3; - private byte loginattempt = 0; - private String pin = null; - private int pinattempt = 0; - private String pic = null; - private String hwid = null; - private int picattempt = 0; - private byte csattempt = 0; - private byte gender = -1; - private boolean disconnecting = false; - private final Semaphore actionsSemaphore = new Semaphore(7); - private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true); - private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true); - private static final Lock loginLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true); - private int votePoints; - private int voteTime = -1; - private int visibleWorlds; - private long lastNpcClick; - private long sessionId; + public static final int LOGIN_NOTLOGGEDIN = 0; + public static final int LOGIN_SERVER_TRANSITION = 1; + public static final int LOGIN_LOGGEDIN = 2; + public static final String CLIENT_KEY = "CLIENT"; + public static final String CLIENT_HWID = "HWID"; + public static final String CLIENT_NIBBLEHWID = "HWID2"; + private MapleAESOFB send; + private MapleAESOFB receive; + private final IoSession session; + private MapleCharacter player; + private int channel = 1; + private int accId = 0; + private boolean loggedIn = false; + private boolean serverTransition = false; + private Calendar birthday = null; + private String accountName = null; + private int world; + private long lastPong; + private int gmlevel; + private Set macs = new HashSet<>(); + private Map engines = new HashMap<>(); + private byte characterSlots = 3; + private byte loginattempt = 0; + private String pin = null; + private int pinattempt = 0; + private String pic = null; + private String hwid = null; + private int picattempt = 0; + private byte csattempt = 0; + private byte gender = -1; + private boolean disconnecting = false; + private final Semaphore actionsSemaphore = new Semaphore(7); + private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true); + private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true); + private static final Lock loginLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true); + private int votePoints; + private int voteTime = -1; + private int visibleWorlds; + private long lastNpcClick; + private long sessionId; - public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) { - this.send = send; - this.receive = receive; - this.session = session; - } + public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) { + this.send = send; + this.receive = receive; + this.session = session; + } - public MapleAESOFB getReceiveCrypto() { - return receive; - } + public MapleAESOFB getReceiveCrypto() { + return receive; + } - public MapleAESOFB getSendCrypto() { - return send; - } + public MapleAESOFB getSendCrypto() { + return send; + } - public IoSession getSession() { - return session; - } - - public EventManager getEventManager(String event) { - return getChannelServer().getEventSM().getEventManager(event); + public IoSession getSession() { + return session; + } + + public EventManager getEventManager(String event) { + return getChannelServer().getEventSM().getEventManager(event); + } + + public MapleCharacter getPlayer() { + return player; + } + + public void setPlayer(MapleCharacter player) { + this.player = player; + } + + public AbstractPlayerInteraction getAbstractPlayerInteraction() { + return new AbstractPlayerInteraction(this); + } + + public void sendCharList(int server) { + this.announce(MaplePacketCreator.getCharList(this, server, 0)); + } + + public List loadCharacters(int serverId) { + List chars = new ArrayList<>(15); + try { + for (CharNameAndId cni : loadCharactersInternal(serverId)) { + chars.add(MapleCharacter.loadCharFromDB(cni.id, this, false)); + } + } catch (Exception e) { + e.printStackTrace(); } + return chars; + } - public MapleCharacter getPlayer() { - return player; - } - - public void setPlayer(MapleCharacter player) { - this.player = player; - } - - public AbstractPlayerInteraction getAbstractPlayerInteraction() { - return new AbstractPlayerInteraction(this); + public List loadCharacterNames(int worldId) { + List chars = new ArrayList<>(15); + for (CharNameAndId cni : loadCharactersInternal(worldId)) { + chars.add(cni.name); } + return chars; + } - public void sendCharList(int server) { - this.announce(MaplePacketCreator.getCharList(this, server, 0)); - } - - public List loadCharacters(int serverId) { - List chars = new ArrayList<>(15); - try { - for (CharNameAndId cni : loadCharactersInternal(serverId)) { - chars.add(MapleCharacter.loadCharFromDB(cni.id, this, false)); - } - } catch (Exception e) { - e.printStackTrace(); - } - return chars; - } - - public List loadCharacterNames(int worldId) { - List chars = new ArrayList<>(15); - for (CharNameAndId cni : loadCharactersInternal(worldId)) { - chars.add(cni.name); - } - return chars; - } - - private List loadCharactersInternal(int worldId) { - PreparedStatement ps; - List chars = new ArrayList<>(15); - try { - Connection con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?"); - ps.setInt(1, this.getAccID()); - ps.setInt(2, worldId); - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id"))); - } - } - ps.close(); - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return chars; - } - - public boolean isLoggedIn() { - return loggedIn; - } - - public boolean hasBannedIP() { - boolean ret = false; - try { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')")) { - ps.setString(1, session.getRemoteAddress().toString()); - try (ResultSet rs = ps.executeQuery()) { - rs.next(); - if (rs.getInt(1) > 0) { - ret = true; - } - } - } - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return ret; - } - - public int getVoteTime(){ - if (voteTime != -1){ - return voteTime; - } - try { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("SELECT date FROM bit_votingrecords WHERE UPPER(account) = UPPER(?)")) { - ps.setString(1, accountName); - try (ResultSet rs = ps.executeQuery()) { - if (!rs.next()) { - return -1; - } - voteTime = rs.getInt("date"); - } - } - con.close(); - } catch (SQLException e) { - FilePrinter.printError("hasVotedAlready.txt", e); - return -1; - } - return voteTime; - } - - public void resetVoteTime() { - voteTime = -1; + private List loadCharactersInternal(int worldId) { + PreparedStatement ps; + List chars = new ArrayList<>(15); + try { + Connection con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?"); + ps.setInt(1, this.getAccID()); + ps.setInt(2, worldId); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id"))); + } + } + ps.close(); + con.close(); + } catch (SQLException e) { + e.printStackTrace(); } + return chars; + } - public boolean hasVotedAlready(){ - Date currentDate = new Date(); - int timeNow = (int) (currentDate.getTime() / 1000); - int difference = (timeNow - getVoteTime()); - return difference < 86400 && difference > 0; - } - - public boolean hasBannedHWID() { - if(hwid == null) - return false; - - boolean ret = false; - PreparedStatement ps = null; - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT COUNT(*) FROM hwidbans WHERE hwid LIKE ?"); - ps.setString(1, hwid); - ResultSet rs = ps.executeQuery(); - if(rs != null && rs.next()) { - if(rs.getInt(1) > 0) - ret = true; - } - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if(ps != null && !ps.isClosed()) { - ps.close(); - } - - if(con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException e){ - e.printStackTrace(); - } - } - - return ret; - } + public boolean isLoggedIn() { + return loggedIn; + } - public boolean hasBannedMac() { - if (macs.isEmpty()) { - return false; - } - boolean ret = false; - int i; - try { - StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN ("); - for (i = 0; i < macs.size(); i++) { - sql.append("?"); - if (i != macs.size() - 1) { - sql.append(", "); - } - } - sql.append(")"); - - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement(sql.toString())) { - i = 0; - for (String mac : macs) { - i++; - ps.setString(i, mac); - } - try (ResultSet rs = ps.executeQuery()) { - rs.next(); - if (rs.getInt(1) > 0) { - ret = true; - } - } - } finally { - con.close(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return ret; - } - - private void loadHWIDIfNescessary() throws SQLException { - if(hwid == null) { - Connection con = DatabaseConnection.getConnection(); - try(PreparedStatement ps = con.prepareStatement("SELECT hwid FROM accounts WHERE id = ?")) { - ps.setInt(1, accId); - try(ResultSet rs = ps.executeQuery()) { - if(rs.next()) { - hwid = rs.getString("hwid"); - } - } - } finally { - con.close(); - } - } - } - - // TODO: Recode to close statements... - private void loadMacsIfNescessary() throws SQLException { - if (macs.isEmpty()) { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?")) { - ps.setInt(1, accId); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - for (String mac : rs.getString("macs").split(", ")) { - if (!mac.equals("")) { - macs.add(mac); - } - } - } - } - } finally { - con.close(); - } - } - } - - public void banHWID() { - PreparedStatement ps = null; - Connection con = null; - try { - loadHWIDIfNescessary(); - - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("INSERT INTO hwidbans (hwid) VALUES (?)"); - ps.setString(1, hwid); - ps.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if(ps != null && !ps.isClosed()) { - ps.close(); - } - if(con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - } - - public void banMacs() { - Connection con = null; - try { - loadMacsIfNescessary(); - - con = DatabaseConnection.getConnection(); - List filtered = new LinkedList<>(); - try (PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters"); ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - filtered.add(rs.getString("filter")); - } - } - try (PreparedStatement ps = con.prepareStatement("INSERT INTO macbans (mac, aid) VALUES (?, ?)")) { - for (String mac : macs) { - boolean matched = false; - for (String filter : filtered) { - if (mac.matches(filter)) { - matched = true; - break; - } - } - if (!matched) { - ps.setString(1, mac); - ps.setString(2, String.valueOf(getAccID())); - ps.executeUpdate(); - } - } - } - - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - public int finishLogin() { - loginLock.lock(); - try { - if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN - loggedIn = false; - return 7; + public boolean hasBannedIP() { + boolean ret = false; + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')")) { + ps.setString(1, session.getRemoteAddress().toString()); + try (ResultSet rs = ps.executeQuery()) { + rs.next(); + if (rs.getInt(1) > 0) { + ret = true; } - updateLoginState(LOGIN_LOGGEDIN); - } finally { - loginLock.unlock(); - } - - return 0; - } - - public void setPin(String pin) { - this.pin = pin; - try { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pin = ? WHERE id = ?")) { - ps.setString(1, pin); - ps.setInt(2, accId); - ps.executeUpdate(); - } finally { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - public String getPin() { - return pin; - } - - public boolean checkPin(String other) { - pinattempt++; - if (pinattempt > 5) { - MapleSessionCoordinator.getInstance().closeSession(session, false); - } - if (pin.equals(other)) { - pinattempt = 0; - MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, false); - return true; - } - return false; - } - - public void setPic(String pic) { - this.pic = pic; - try { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pic = ? WHERE id = ?")) { - ps.setString(1, pic); - ps.setInt(2, accId); - ps.executeUpdate(); - } finally { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - public String getPic() { - return pic; - } - - public boolean checkPic(String other) { - if(!(ServerConstants.ENABLE_PIC && !canBypassPic())) return true; - - picattempt++; - if (picattempt > 5) { - MapleSessionCoordinator.getInstance().closeSession(session, false); - } - if (pic.equals(other)) { - picattempt = 0; - MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, true); - return true; - } - return false; - } - - public int login(String login, String pwd, String nibbleHwid) { - int loginok = 5; - - loginattempt++; - if (loginattempt > 4) { - loggedIn = false; - MapleSessionCoordinator.getInstance().closeSession(session, false); - return loginok; - } - - Connection con = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?"); - ps.setString(1, login); - rs = ps.executeQuery(); - if (rs.next()) { - boolean banned = (rs.getByte("banned") == 1); - accId = rs.getInt("id"); - gmlevel = 0; - pin = rs.getString("pin"); - pic = rs.getString("pic"); - gender = rs.getByte("gender"); - characterSlots = rs.getByte("characterslots"); - String passhash = rs.getString("password"); - byte tos = rs.getByte("tos"); - - ps.close(); - rs.close(); - - if (banned) { - return 3; - } - - if (getLoginState() > LOGIN_NOTLOGGEDIN) { // already loggedin - loggedIn = false; - loginok = 7; - } else if (passhash.charAt(0) == '$' && passhash.charAt(1) == '2' && BCrypt.checkpw(pwd, passhash)) { - loginok = (tos == 0) ? 23 : 0; - } else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) { - // thanks GabrielSin for detecting some no-bcrypt inconsistencies here - loginok = (tos == 0) ? (!ServerConstants.BCRYPT_MIGRATION ? 23 : -23) : (!ServerConstants.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt - } else { - loggedIn = false; - loginok = 4; - } - } - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if (ps != null && !ps.isClosed()) { - ps.close(); - } - if (rs != null && !rs.isClosed()) { - rs.close(); - } - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - if (loginok == 0 || loginok == 4) { - AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptLoginSession(session, nibbleHwid, accId, loginok == 4); - - switch (res) { - case SUCCESS: - if (loginok == 0) { - loginattempt = 0; - } - - return loginok; - - case REMOTE_LOGGEDIN: - return 17; - - case REMOTE_REACHED_LIMIT: - return 13; - - case REMOTE_PROCESSING: - return 10; - - case MANY_ACCOUNT_ATTEMPTS: - return 16; - - default: - return 8; - } - } else { - return loginok; - } - } - - public Calendar getTempBanCalendar() { - Connection con = null; - PreparedStatement ps = null; - ResultSet rs = null; - final Calendar lTempban = Calendar.getInstance(); - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT `tempban` FROM accounts WHERE id = ?"); - ps.setInt(1, getAccID()); - rs = ps.executeQuery(); - if (!rs.next()) { - return null; - } - long blubb = rs.getLong("tempban"); - if (blubb == 0) { // basically if timestamp in db is 0000-00-00 - return null; - } - lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime()); - return lTempban; - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if (ps != null) { - ps.close(); - } - if (rs != null) { - rs.close(); - } - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - return null;//why oh why!?! - } - - public static long dottedQuadToLong(String dottedQuad) throws RuntimeException { - String[] quads = dottedQuad.split("\\."); - if (quads.length != 4) { - throw new RuntimeException("Invalid IP Address format."); - } - long ipAddress = 0; - for (int i = 0; i < 4; i++) { - int quad = Integer.parseInt(quads[i]); - ipAddress += (long) (quad % 256) * (long) Math.pow(256, (double) (4 - i)); - } - return ipAddress; - } - - public void updateHWID(String newHwid) { - String[] split = newHwid.split("_"); - if(split.length > 1 && split[1].length() == 8) { - StringBuilder hwid = new StringBuilder(); - String convert = split[1]; - - int len = convert.length(); - for(int i=len-2; i>=0; i -= 2) { - hwid.append(convert.substring(i, i + 2)); - } - hwid.insert(4, "-"); - - this.hwid = hwid.toString(); - - PreparedStatement ps = null; - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("UPDATE accounts SET hwid = ? WHERE id = ?"); - ps.setString(1, this.hwid); - ps.setInt(2, accId); - ps.executeUpdate(); - ps.close(); - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if(ps != null && !ps.isClosed()) { - ps.close(); - } - if(con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - } else { - this.disconnect(false, false); // Invalid HWID... - } - } - - public void updateMacs(String macData) { - macs.addAll(Arrays.asList(macData.split(", "))); - StringBuilder newMacData = new StringBuilder(); - Iterator iter = macs.iterator(); - PreparedStatement ps = null; - while (iter.hasNext()) { - String cur = iter.next(); - newMacData.append(cur); - if (iter.hasNext()) { - newMacData.append(", "); - } - } - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?"); - ps.setString(1, newMacData.toString()); - ps.setInt(2, accId); - ps.executeUpdate(); - ps.close(); - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if (ps != null && !ps.isClosed()) { - ps.close(); - } - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException ex) { - ex.printStackTrace(); - } - } - } - - public void setAccID(int id) { - this.accId = id; - } - - public int getAccID() { - return accId; - } - - public void updateLoginState(int newstate) { - // rules out possibility of multiple account entries - if (newstate == LOGIN_LOGGEDIN) { - MapleSessionCoordinator.getInstance().updateOnlineSession(this.getSession()); - } - - try { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) { - // using sql currenttime here could potentially break the login, thanks Arnah for pointing this out - - ps.setInt(1, newstate); - ps.setTimestamp(2, new java.sql.Timestamp(Server.getInstance().getCurrentTime())); - ps.setInt(3, getAccID()); - ps.executeUpdate(); - } - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - - if (newstate == LOGIN_NOTLOGGEDIN) { - loggedIn = false; - serverTransition = false; - setAccID(0); - } else { - serverTransition = (newstate == LOGIN_SERVER_TRANSITION); - loggedIn = !serverTransition; - } - } - - public int getLoginState() { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN - try { - Connection con = DatabaseConnection.getConnection(); - PreparedStatement ps = con.prepareStatement("SELECT loggedin, lastlogin, birthday FROM accounts WHERE id = ?"); - ps.setInt(1, getAccID()); - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - rs.close(); - ps.close(); - throw new RuntimeException("getLoginState - MapleClient AccID: " + getAccID()); - } - - birthday = Calendar.getInstance(); - try { - birthday.setTime(rs.getDate("birthday")); - } catch(SQLException e) {} - - int state = rs.getInt("loggedin"); - if (state == LOGIN_SERVER_TRANSITION) { - if (rs.getTimestamp("lastlogin").getTime() + 30000 < Server.getInstance().getCurrentTime()) { - state = LOGIN_NOTLOGGEDIN; - MapleSessionCoordinator.getInstance().closeSession(session, null); - updateLoginState(LOGIN_NOTLOGGEDIN); - } - } - rs.close(); - ps.close(); - if (state == LOGIN_LOGGEDIN) { - loggedIn = true; - } else if (state == LOGIN_SERVER_TRANSITION) { - ps = con.prepareStatement("UPDATE accounts SET loggedin = 0 WHERE id = ?"); - ps.setInt(1, getAccID()); - ps.executeUpdate(); - ps.close(); - } else { - loggedIn = false; - } - - con.close(); - return state; - } catch (SQLException e) { - loggedIn = false; - e.printStackTrace(); - throw new RuntimeException("login state"); - } - } - - public boolean checkBirthDate(Calendar date) { - return date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH); - } - - private void removePartyPlayer(World wserv) { - MapleMap map = player.getMap(); - final MapleParty party = player.getParty(); - final int idz = player.getId(); - final MaplePartyCharacter chrp = new MaplePartyCharacter(player); - - if (party != null) { - chrp.setOnline(false); - wserv.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp); - if (party.getLeader().getId() == idz && map != null) { - MaplePartyCharacter lchr = null; - for (MaplePartyCharacter pchr : party.getMembers()) { - if (pchr != null && pchr.getId() != idz && (lchr == null || lchr.getLevel() <= pchr.getLevel()) && map.getCharacterById(pchr.getId()) != null) { - lchr = pchr; - } - } - if (lchr != null) { - wserv.updateParty(party.getId(), PartyOperation.CHANGE_LEADER, lchr); - } - } } + } + con.close(); + } catch (SQLException e) { + e.printStackTrace(); } - - private void removePlayer(World wserv, boolean serverTransition) { - try { - player.setDisconnectedFromChannelWorld(); - player.notifyMapTransferToPartner(-1); - player.cancelAllBuffs(true); - - player.closePlayerInteractions(); - QuestScriptManager.getInstance().dispose(this); - - if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels - removePartyPlayer(wserv); + return ret; + } - EventInstanceManager eim = player.getEventInstance(); - if (eim != null) { - eim.playerDisconnected(player); - } - } - - if (player.getMap() != null) { - int mapId = player.getMapId(); - player.getMap().removePlayer(player); - if(GameConstants.isDojo(mapId)) { - this.getChannelServer().freeDojoSectionIfEmpty(mapId); - } - } - - } catch (final Throwable t) { - FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, t); - } - } - - public final void disconnect(final boolean shutdown, final boolean cashshop) { - if (canDisconnect()) { - ThreadManager.getInstance().newTask(new Runnable() { - @Override - public void run() { - disconnectInternal(shutdown, cashshop); - } - }); - } + public int getVoteTime() { + if (voteTime != -1) { + return voteTime; } - - public final void forceDisconnect() { - if (canDisconnect()) { - disconnectInternal(true, false); + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("SELECT date FROM bit_votingrecords WHERE UPPER(account) = UPPER(?)")) { + ps.setString(1, accountName); + try (ResultSet rs = ps.executeQuery()) { + if (!rs.next()) { + return -1; + } + voteTime = rs.getInt("date"); } + } + con.close(); + } catch (SQLException e) { + FilePrinter.printError("hasVotedAlready.txt", e); + return -1; } - - private synchronized boolean canDisconnect() { - if (disconnecting) { - return false; - } - - disconnecting = true; - return true; + return voteTime; + } + + public void resetVoteTime() { + voteTime = -1; + } + + public boolean hasVotedAlready() { + Date currentDate = new Date(); + int timeNow = (int) (currentDate.getTime() / 1000); + int difference = (timeNow - getVoteTime()); + return difference < 86400 && difference > 0; + } + + public boolean hasBannedHWID() { + if (hwid == null) { + return false; } - - private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per MapleClient instance - if (player != null && player.isLoggedin() && player.getClient() != null) { - final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId(); - //final int fid = player.getFamilyId(); - final BuddyList bl = player.getBuddylist(); - final MapleMessengerCharacter chrm = new MapleMessengerCharacter(player, 0); - final MapleGuildCharacter chrg = player.getMGC(); - final MapleGuild guild = player.getGuild(); - - player.cancelMagicDoor(); - - final World wserv = getWorldServer(); // obviously wserv is NOT null if this player was online on it - try { - removePlayer(wserv, this.serverTransition); - - if (!(channel == -1 || shutdown)) { - if (!cashshop) { - if (!this.serverTransition) { // meaning not changing channels - if (messengerid > 0) { - wserv.leaveMessenger(messengerid, chrm); - } - /* - if (fid > 0) { - final MapleFamily family = worlda.getFamily(fid); - family. - } - */ - for (MapleQuestStatus status : player.getStartedQuests()) { //This is for those quests that you have to stay logged in for a certain amount of time - MapleQuest quest = status.getQuest(); - if (quest.getTimeLimit() > 0) { - MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); - newStatus.setForfeited(player.getQuest(quest).getForfeited() + 1); - player.updateQuest(newStatus); - } - } - if (guild != null) { - final Server server = Server.getInstance(); - server.setGuildMemberOnline(player, false, player.getClient().getChannel()); - player.getClient().announce(MaplePacketCreator.showGuildInfo(player)); - } - if (bl != null) { - wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds()); - } - } - } else { - if (!this.serverTransition) { // if dc inside of cash shop. - if (bl != null) { - wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds()); - } - } - } - } - } catch (final Exception e) { - FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, e); - } finally { - if (!this.serverTransition) { - if(chrg != null) chrg.setCharacter(null); - wserv.removePlayer(player); - //getChannelServer().removePlayer(player); already being done - - player.saveCooldowns(); - player.cancelAllDebuffs(); - player.saveCharToDB(true); - - player.logOff(); - clear(); - } else { - getChannelServer().removePlayer(player); - player.saveCooldowns(); - player.cancelAllDebuffs(); - player.saveCharToDB(); - } - } - } - if (!serverTransition && isLoggedIn()) { - MapleSessionCoordinator.getInstance().closeSession(session, false); - updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); - session.removeAttribute(MapleClient.CLIENT_KEY); // prevents double dcing during login - - clear(); - } else { - if (session.containsAttribute(MapleClient.CLIENT_KEY)) { - MapleSessionCoordinator.getInstance().closeSession(session, false); - session.removeAttribute(MapleClient.CLIENT_KEY); - } - - engines.clear(); + boolean ret = false; + PreparedStatement ps = null; + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT COUNT(*) FROM hwidbans WHERE hwid LIKE ?"); + ps.setString(1, hwid); + ResultSet rs = ps.executeQuery(); + if (rs != null && rs.next()) { + if (rs.getInt(1) > 0) { + ret = true; } - } - - private void clear() { - // player hard reference removal thanks to Steve (kaito1410) - if (this.player != null) { - this.player.empty(true); // clears schedules and stuff + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); } - - Server.getInstance().unregisterLoginState(this); - - this.accountName = null; - this.macs = null; - this.hwid = null; - this.birthday = null; - this.engines = null; - this.player = null; - this.receive = null; - this.send = null; - //this.session = null; - } - public int getChannel() { - return channel; - } - - public Channel getChannelServer() { - return Server.getInstance().getChannel(world, channel); - } - - public World getWorldServer() { - return Server.getInstance().getWorld(world); - } - - public Channel getChannelServer(byte channel) { - return Server.getInstance().getChannel(world, channel); - } - - public boolean deleteCharacter(int cid, int senderAccId) { - try { - return MapleCharacter.deleteCharFromDB(MapleCharacter.loadCharFromDB(cid, this, false), senderAccId); - } catch(SQLException ex) { - ex.printStackTrace(); - return false; + if (con != null && !con.isClosed()) { + con.close(); } - } - - public String getAccountName() { - return accountName; - } - - public void setAccountName(String a) { - this.accountName = a; - } - - public void setChannel(int channel) { - this.channel = channel; - } - - public int getWorld() { - return world; - } - - public void setWorld(int world) { - this.world = world; - } - - public void pongReceived() { - lastPong = Server.getInstance().getCurrentTime(); - } - - public void testPing(long timeThen) { - try { - if (lastPong < timeThen) { - if (session != null && session.isConnected()) { - MapleSessionCoordinator.getInstance().closeSession(session, false); - updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); - session.removeAttribute(MapleClient.CLIENT_KEY); - } - } - } catch (NullPointerException e) { - e.printStackTrace(); - } - } - - public String getHWID() { - return hwid; - } - - public void setHWID(String hwid) { - this.hwid = hwid; - } - - public Set getMacs() { - return Collections.unmodifiableSet(macs); - } - - public int getGMLevel() { - return gmlevel; - } - - public void setGMLevel(int level) { - gmlevel = level; - } - - public void setScriptEngine(String name, ScriptEngine e) { - engines.put(name, e); - } - - public ScriptEngine getScriptEngine(String name) { - return engines.get(name); - } - - public void removeScriptEngine(String name) { - engines.remove(name); - } - - public NPCConversationManager getCM() { - return NPCScriptManager.getInstance().getCM(this); - } - - public QuestActionManager getQM() { - return QuestScriptManager.getInstance().getQM(this); - } - - public boolean acceptToS() { - boolean disconnectForBeingAFaggot = false; - if (accountName == null) { - return true; - } - try { - Connection con = DatabaseConnection.getConnection(); - PreparedStatement ps = con.prepareStatement("SELECT `tos` FROM accounts WHERE id = ?"); - ps.setInt(1, accId); - ResultSet rs = ps.executeQuery(); - - if (rs.next()) { - if (rs.getByte("tos") == 1) { - disconnectForBeingAFaggot = true; - } - } - ps.close(); - rs.close(); - ps = con.prepareStatement("UPDATE accounts SET tos = 1 WHERE id = ?"); - ps.setInt(1, accId); - ps.executeUpdate(); - ps.close(); - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return disconnectForBeingAFaggot; - } - - public int getVotePoints(){ - int points = 0; - try { - Connection con = DatabaseConnection.getConnection(); - PreparedStatement ps = con.prepareStatement("SELECT `votepoints` FROM accounts WHERE id = ?"); - ps.setInt(1, accId); - ResultSet rs = ps.executeQuery(); - - if (rs.next()) { - points = rs.getInt("votepoints"); - } - ps.close(); - rs.close(); - - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - votePoints = points; - return votePoints; - } - - public void addVotePoints(int points) { - votePoints += points; - saveVotePoints(); - } - - public void useVotePoints(int points){ - if (points > votePoints){ - //Should not happen, should probably log this - return; - } - votePoints -= points; - saveVotePoints(); - LogHelper.logLeaf(player, false, Integer.toString(points)); - } - - private void saveVotePoints() { - try { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET votepoints = ? WHERE id = ?")) { - ps.setInt(1, votePoints); - ps.setInt(2, accId); - ps.executeUpdate(); - } - - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - public void lockClient() { - lock.lock(); - } - - public void unlockClient() { - lock.unlock(); - } - - public boolean tryacquireClient() { - if (actionsSemaphore.tryAcquire()) { - lockClient(); - return true; - } else { - return false; - } - } - - public void releaseClient() { - unlockClient(); - actionsSemaphore.release(); - } - - public void lockEncoder() { - encoderLock.lock(); - } - - public void unlockEncoder() { - encoderLock.unlock(); - } - - private static class CharNameAndId { - - public String name; - public int id; - - public CharNameAndId(String name, int id) { - super(); - this.name = name; - this.id = id; - } - } - - private static boolean checkHash(String hash, String type, String password) { - try { - MessageDigest digester = MessageDigest.getInstance(type); - digester.update(password.getBytes("UTF-8"), 0, password.length()); - return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase().equals(hash); - } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { - throw new RuntimeException("Encoding the string failed", e); - } - } - - public short getAvailableCharacterSlots() { - return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId)); - } - - public short getAvailableCharacterWorldSlots() { - return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world)); - } - - public short getCharacterSlots() { - return characterSlots; - } - - public void setCharacterSlots(byte slots) { - characterSlots = slots; - } - - public synchronized boolean gainCharacterSlot() { - if (characterSlots < 15) { - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET characterslots = ? WHERE id = ?")) { - ps.setInt(1, this.characterSlots += 1); - ps.setInt(2, accId); - ps.executeUpdate(); - } - - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return true; - } - return false; - } - - public final byte getGReason() { - Connection con = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT `greason` FROM `accounts` WHERE id = ?"); - ps.setInt(1, accId); - rs = ps.executeQuery(); - if (rs.next()) { - return rs.getByte("greason"); - } - } catch (SQLException e) { - e.printStackTrace(); - } finally { - try { - if (ps != null) { - ps.close(); - } - if (rs != null) { - rs.close(); - } - if (con != null) { - con.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - return 0; - } - - public byte getGender() { - return gender; - } - - public void setGender(byte m) { - this.gender = m; - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) { - ps.setByte(1, gender); - ps.setInt(2, accId); - ps.executeUpdate(); - } - - con.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private void announceDisableServerMessage() { - if(!this.getWorldServer().registerDisabledServerMessage(player.getId())) { - announce(MaplePacketCreator.serverMessage("")); + } catch (SQLException e) { + e.printStackTrace(); } } - - public void announceServerMessage() { - announce(MaplePacketCreator.serverMessage(this.getChannelServer().getServerMessage())); + + return ret; + } + + public boolean hasBannedMac() { + if (macs.isEmpty()) { + return false; } - - public synchronized void announceBossHpBar(MapleMonster mm, final int mobHash, final byte[] packet) { - long timeNow = System.currentTimeMillis(); - int targetHash = player.getTargetHpBarHash(); - - if(mobHash != targetHash) { - if(timeNow - player.getTargetHpBarTime() >= 5 * 1000) { - // is there a way to INTERRUPT this annoying thread running on the client that drops the boss bar after some time at every attack? - announceDisableServerMessage(); - announce(packet); - - player.setTargetHpBarHash(mobHash); - player.setTargetHpBarTime(timeNow); + boolean ret = false; + int i; + try { + StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN ("); + for (i = 0; i < macs.size(); i++) { + sql.append("?"); + if (i != macs.size() - 1) { + sql.append(", "); + } + } + sql.append(")"); + + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement(sql.toString())) { + i = 0; + for (String mac : macs) { + i++; + ps.setString(i, mac); + } + try (ResultSet rs = ps.executeQuery()) { + rs.next(); + if (rs.getInt(1) > 0) { + ret = true; + } + } + } finally { + con.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return ret; + } + + private void loadHWIDIfNescessary() throws SQLException { + if (hwid == null) { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("SELECT hwid FROM accounts WHERE id = ?")) { + ps.setInt(1, accId); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + hwid = rs.getString("hwid"); + } + } + } finally { + con.close(); + } + } + } + + // TODO: Recode to close statements... + private void loadMacsIfNescessary() throws SQLException { + if (macs.isEmpty()) { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?")) { + ps.setInt(1, accId); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + for (String mac : rs.getString("macs").split(", ")) { + if (!mac.equals("")) { + macs.add(mac); + } } + } + } + } finally { + con.close(); + } + } + } + + public void banHWID() { + PreparedStatement ps = null; + Connection con = null; + try { + loadHWIDIfNescessary(); + + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("INSERT INTO hwidbans (hwid) VALUES (?)"); + ps.setString(1, hwid); + ps.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); + } + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + + public void banMacs() { + Connection con = null; + try { + loadMacsIfNescessary(); + + con = DatabaseConnection.getConnection(); + List filtered = new LinkedList<>(); + try (PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters"); ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + filtered.add(rs.getString("filter")); + } + } + try (PreparedStatement ps = con.prepareStatement("INSERT INTO macbans (mac, aid) VALUES (?, ?)")) { + for (String mac : macs) { + boolean matched = false; + for (String filter : filtered) { + if (mac.matches(filter)) { + matched = true; + break; + } + } + if (!matched) { + ps.setString(1, mac); + ps.setString(2, String.valueOf(getAccID())); + ps.executeUpdate(); + } + } + } + + con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public int finishLogin() { + loginLock.lock(); + try { + if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN + loggedIn = false; + return 7; + } + updateLoginState(LOGIN_LOGGEDIN); + } finally { + loginLock.unlock(); + } + + return 0; + } + + public void setPin(String pin) { + this.pin = pin; + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pin = ? WHERE id = ?")) { + ps.setString(1, pin); + ps.setInt(2, accId); + ps.executeUpdate(); + } finally { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public String getPin() { + return pin; + } + + public boolean checkPin(String other) { + pinattempt++; + if (pinattempt > 5) { + MapleSessionCoordinator.getInstance().closeSession(session, false); + } + if (pin.equals(other)) { + pinattempt = 0; + MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, false); + return true; + } + return false; + } + + public void setPic(String pic) { + this.pic = pic; + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pic = ? WHERE id = ?")) { + ps.setString(1, pic); + ps.setInt(2, accId); + ps.executeUpdate(); + } finally { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public String getPic() { + return pic; + } + + public boolean checkPic(String other) { + if (!(ServerConstants.ENABLE_PIC && !canBypassPic())) { + return true; + } + + picattempt++; + if (picattempt > 5) { + MapleSessionCoordinator.getInstance().closeSession(session, false); + } + if (pic.equals(other)) { + picattempt = 0; + MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, true); + return true; + } + return false; + } + + public int login(String login, String pwd, String nibbleHwid) { + int loginok = 5; + + loginattempt++; + if (loginattempt > 4) { + loggedIn = false; + MapleSessionCoordinator.getInstance().closeSession(session, false); + return loginok; + } + + Connection con = null; + PreparedStatement ps = null; + ResultSet rs = null; + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?"); + ps.setString(1, login); + rs = ps.executeQuery(); + if (rs.next()) { + boolean banned = (rs.getByte("banned") == 1); + accId = rs.getInt("id"); + gmlevel = 0; + pin = rs.getString("pin"); + pic = rs.getString("pic"); + gender = rs.getByte("gender"); + characterSlots = rs.getByte("characterslots"); + String passhash = rs.getString("password"); + byte tos = rs.getByte("tos"); + + ps.close(); + rs.close(); + + if (banned) { + return 3; + } + + if (getLoginState() > LOGIN_NOTLOGGEDIN) { // already loggedin + loggedIn = false; + loginok = 7; + } else if (passhash.charAt(0) == '$' && passhash.charAt(1) == '2' && BCrypt.checkpw(pwd, passhash)) { + loginok = (tos == 0) ? 23 : 0; + } else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) { + // thanks GabrielSin for detecting some no-bcrypt inconsistencies here + loginok = (tos == 0) ? (!ServerConstants.BCRYPT_MIGRATION ? 23 : -23) : (!ServerConstants.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt } else { - announceDisableServerMessage(); - announce(packet); - - player.setTargetHpBarTime(timeNow); + loggedIn = false; + loginok = 4; } - } - - public synchronized void announce(final byte[] packet) {//MINA CORE IS A FUCKING BITCH AND I HATE IT <3 - session.write(packet); - } - - public void announceHint(String msg, int length) { - announce(MaplePacketCreator.sendHint(msg, length, 10)); - announce(MaplePacketCreator.enableActions()); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); + } + if (rs != null && !rs.isClosed()) { + rs.close(); + } + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } } - public void changeChannel(int channel) { - Server server = Server.getInstance(); - if (player.isBanned()) { - disconnect(false, false); - return; - } - if (!player.isAlive() || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) { - announce(MaplePacketCreator.enableActions()); - return; - } else if(MapleMiniDungeonInfo.isDungeonMap(player.getMapId())) { - announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon.")); - announce(MaplePacketCreator.enableActions()); - return; - } - - String[] socket = Server.getInstance().getInetSocket(getWorld(), channel); - if(socket == null) { - announce(MaplePacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel.")); - announce(MaplePacketCreator.enableActions()); - return; - } - - if (player.getTrade() != null) { - MapleTrade.cancelTrade(getPlayer()); - } + if (loginok == 0 || loginok == 4) { + AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptLoginSession(session, nibbleHwid, accId, loginok == 4); - MapleHiredMerchant merchant = player.getHiredMerchant(); - if (merchant != null) { - if (merchant.isOwner(getPlayer())) { - merchant.setOpen(true); - } else { - merchant.removeVisitor(getPlayer()); - } - } - player.unregisterChairBuff(); - server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs()); - server.getPlayerBuffStorage().addDiseasesToStorage(player.getId(), player.getAllDiseases()); - player.setDisconnectedFromChannelWorld(); - player.notifyMapTransferToPartner(-1); - player.cancelAllBuffs(true); - player.cancelAllDebuffs(); - player.cancelBuffExpireTask(); - player.cancelDiseaseExpireTask(); - player.cancelSkillCooldownTask(); - player.cancelQuestExpirationTask(); - //Cancelling magicdoor? Nope - //Cancelling mounts? Noty - - player.getInventory(MapleInventoryType.EQUIPPED).checked(false); //test - player.getMap().removePlayer(player); - player.clearBanishPlayerData(); - player.getClient().getChannelServer().removePlayer(player); - player.getClient().updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - try { - announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); - } catch (IOException e) { + switch (res) { + case SUCCESS: + if (loginok == 0) { + loginattempt = 0; + } + + return loginok; + + case REMOTE_LOGGEDIN: + return 17; + + case REMOTE_REACHED_LIMIT: + return 13; + + case REMOTE_PROCESSING: + return 10; + + case MANY_ACCOUNT_ATTEMPTS: + return 16; + + default: + return 8; + } + } else { + return loginok; + } + } + + public Calendar getTempBanCalendar() { + Connection con = null; + PreparedStatement ps = null; + ResultSet rs = null; + final Calendar lTempban = Calendar.getInstance(); + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT `tempban` FROM accounts WHERE id = ?"); + ps.setInt(1, getAccID()); + rs = ps.executeQuery(); + if (!rs.next()) { + return null; + } + long blubb = rs.getLong("tempban"); + if (blubb == 0) { // basically if timestamp in db is 0000-00-00 + return null; + } + lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime()); + return lTempban; + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null) { + ps.close(); + } + if (rs != null) { + rs.close(); + } + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + return null;//why oh why!?! + } + + public static long dottedQuadToLong(String dottedQuad) throws RuntimeException { + String[] quads = dottedQuad.split("\\."); + if (quads.length != 4) { + throw new RuntimeException("Invalid IP Address format."); + } + long ipAddress = 0; + for (int i = 0; i < 4; i++) { + int quad = Integer.parseInt(quads[i]); + ipAddress += (long) (quad % 256) * (long) Math.pow(256, (double) (4 - i)); + } + return ipAddress; + } + + public void updateHWID(String newHwid) { + String[] split = newHwid.split("_"); + if (split.length > 1 && split[1].length() == 8) { + StringBuilder hwid = new StringBuilder(); + String convert = split[1]; + + int len = convert.length(); + for (int i = len - 2; i >= 0; i -= 2) { + hwid.append(convert.substring(i, i + 2)); + } + hwid.insert(4, "-"); + + this.hwid = hwid.toString(); + + PreparedStatement ps = null; + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("UPDATE accounts SET hwid = ? WHERE id = ?"); + ps.setString(1, this.hwid); + ps.setInt(2, accId); + ps.executeUpdate(); + ps.close(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); + } + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (SQLException e) { e.printStackTrace(); - } - } - - public long getSessionId() { - return this.sessionId; - } - - public void setSessionId(long sessionId) { - this.sessionId = sessionId; - } - - public boolean canRequestCharlist(){ - return lastNpcClick + 877 < Server.getInstance().getCurrentTime(); - } - - public boolean canClickNPC(){ - return lastNpcClick + 500 < Server.getInstance().getCurrentTime(); - } - - public void setClickedNPC(){ - lastNpcClick = Server.getInstance().getCurrentTime(); - } - - public void removeClickedNPC(){ - lastNpcClick = 0; - } - - public int getVisibleWorlds(){ - return visibleWorlds; - } - - public void requestedServerlist(int worlds) { - visibleWorlds = worlds; - setClickedNPC(); - } - - public void closePlayerScriptInteractions() { - this.removeClickedNPC(); - NPCScriptManager.getInstance().dispose(this); - } - - public boolean attemptCsCoupon() { - if (csattempt > 2) { - resetCsCoupon(); - return false; } - - csattempt++; - return true; + } + } else { + this.disconnect(false, false); // Invalid HWID... } - - public void resetCsCoupon() { - csattempt = 0; + } + + public void updateMacs(String macData) { + macs.addAll(Arrays.asList(macData.split(", "))); + StringBuilder newMacData = new StringBuilder(); + Iterator iter = macs.iterator(); + PreparedStatement ps = null; + while (iter.hasNext()) { + String cur = iter.next(); + newMacData.append(cur); + if (iter.hasNext()) { + newMacData.append(", "); + } } - - public void enableCSActions() { - announce(MaplePacketCreator.enableCSUse(player)); + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?"); + ps.setString(1, newMacData.toString()); + ps.setInt(2, accId); + ps.executeUpdate(); + ps.close(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); + } + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (SQLException ex) { + ex.printStackTrace(); + } } - - public String getNibbleHWID() { - return (String) session.getAttribute(MapleClient.CLIENT_NIBBLEHWID); + } + + public void setAccID(int id) { + this.accId = id; + } + + public int getAccID() { + return accId; + } + + public void updateLoginState(int newstate) { + // rules out possibility of multiple account entries + if (newstate == LOGIN_LOGGEDIN) { + MapleSessionCoordinator.getInstance().updateOnlineSession(this.getSession()); } - - public boolean canBypassPin() { - return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, false); + + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) { + // using sql currenttime here could potentially break the login, thanks Arnah for pointing this out + + ps.setInt(1, newstate); + ps.setTimestamp(2, new java.sql.Timestamp(Server.getInstance().getCurrentTime())); + ps.setInt(3, getAccID()); + ps.executeUpdate(); + } + con.close(); + } catch (SQLException e) { + e.printStackTrace(); } - - public boolean canBypassPic() { - return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, true); + + if (newstate == LOGIN_NOTLOGGEDIN) { + loggedIn = false; + serverTransition = false; + setAccID(0); + } else { + serverTransition = (newstate == LOGIN_SERVER_TRANSITION); + loggedIn = !serverTransition; } + } + + public int getLoginState() { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN + try { + Connection con = DatabaseConnection.getConnection(); + PreparedStatement ps = con.prepareStatement("SELECT loggedin, lastlogin, birthday FROM accounts WHERE id = ?"); + ps.setInt(1, getAccID()); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + rs.close(); + ps.close(); + throw new RuntimeException("getLoginState - MapleClient AccID: " + getAccID()); + } + + birthday = Calendar.getInstance(); + try { + birthday.setTime(rs.getDate("birthday")); + } catch (SQLException e) { + } + + int state = rs.getInt("loggedin"); + if (state == LOGIN_SERVER_TRANSITION) { + if (rs.getTimestamp("lastlogin").getTime() + 30000 < Server.getInstance().getCurrentTime()) { + state = LOGIN_NOTLOGGEDIN; + MapleSessionCoordinator.getInstance().closeSession(session, null); + updateLoginState(LOGIN_NOTLOGGEDIN); + } + } + rs.close(); + ps.close(); + if (state == LOGIN_LOGGEDIN) { + loggedIn = true; + } else if (state == LOGIN_SERVER_TRANSITION) { + ps = con.prepareStatement("UPDATE accounts SET loggedin = 0 WHERE id = ?"); + ps.setInt(1, getAccID()); + ps.executeUpdate(); + ps.close(); + } else { + loggedIn = false; + } + + con.close(); + return state; + } catch (SQLException e) { + loggedIn = false; + e.printStackTrace(); + throw new RuntimeException("login state"); + } + } + + public boolean checkBirthDate(Calendar date) { + return date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH); + } + + private void removePartyPlayer(World wserv) { + MapleMap map = player.getMap(); + final MapleParty party = player.getParty(); + final int idz = player.getId(); + final MaplePartyCharacter chrp = new MaplePartyCharacter(player); + + if (party != null) { + chrp.setOnline(false); + wserv.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp); + if (party.getLeader().getId() == idz && map != null) { + MaplePartyCharacter lchr = null; + for (MaplePartyCharacter pchr : party.getMembers()) { + if (pchr != null && pchr.getId() != idz && (lchr == null || lchr.getLevel() <= pchr.getLevel()) && map.getCharacterById(pchr.getId()) != null) { + lchr = pchr; + } + } + if (lchr != null) { + wserv.updateParty(party.getId(), PartyOperation.CHANGE_LEADER, lchr); + } + } + } + } + + private void removePlayer(World wserv, boolean serverTransition) { + try { + player.setDisconnectedFromChannelWorld(); + player.notifyMapTransferToPartner(-1); + player.cancelAllBuffs(true); + + player.closePlayerInteractions(); + QuestScriptManager.getInstance().dispose(this); + + if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels + removePartyPlayer(wserv); + + EventInstanceManager eim = player.getEventInstance(); + if (eim != null) { + eim.playerDisconnected(player); + } + + if (player.getMonsterCarnival() != null) { + player.getMonsterCarnival().playerDisconnected(getPlayer().getId()); + } + } + + if (player.getMap() != null) { + int mapId = player.getMapId(); + player.getMap().removePlayer(player); + if (GameConstants.isDojo(mapId)) { + this.getChannelServer().freeDojoSectionIfEmpty(mapId); + } + } + + } catch (final Throwable t) { + FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, t); + } + } + + public final void disconnect(final boolean shutdown, final boolean cashshop) { + if (canDisconnect()) { + ThreadManager.getInstance().newTask(new Runnable() { + @Override + public void run() { + disconnectInternal(shutdown, cashshop); + } + }); + } + } + + public final void forceDisconnect() { + if (canDisconnect()) { + disconnectInternal(true, false); + } + } + + private synchronized boolean canDisconnect() { + if (disconnecting) { + return false; + } + + disconnecting = true; + return true; + } + + private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per MapleClient instance + if (player != null && player.isLoggedin() && player.getClient() != null) { + final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId(); + //final int fid = player.getFamilyId(); + final BuddyList bl = player.getBuddylist(); + final MapleMessengerCharacter chrm = new MapleMessengerCharacter(player, 0); + final MapleGuildCharacter chrg = player.getMGC(); + final MapleGuild guild = player.getGuild(); + + player.cancelMagicDoor(); + + final World wserv = getWorldServer(); // obviously wserv is NOT null if this player was online on it + try { + removePlayer(wserv, this.serverTransition); + + if (!(channel == -1 || shutdown)) { + if (!cashshop) { + if (!this.serverTransition) { // meaning not changing channels + if (messengerid > 0) { + wserv.leaveMessenger(messengerid, chrm); + } + /* + if (fid > 0) { + final MapleFamily family = worlda.getFamily(fid); + family. + } + */ + for (MapleQuestStatus status : player.getStartedQuests()) { //This is for those quests that you have to stay logged in for a certain amount of time + MapleQuest quest = status.getQuest(); + if (quest.getTimeLimit() > 0) { + MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); + newStatus.setForfeited(player.getQuest(quest).getForfeited() + 1); + player.updateQuest(newStatus); + } + } + if (guild != null) { + final Server server = Server.getInstance(); + server.setGuildMemberOnline(player, false, player.getClient().getChannel()); + player.getClient().announce(MaplePacketCreator.showGuildInfo(player)); + } + if (bl != null) { + wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds()); + } + } + } else { + if (!this.serverTransition) { // if dc inside of cash shop. + if (bl != null) { + wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds()); + } + } + } + } + } catch (final Exception e) { + FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, e); + } finally { + if (!this.serverTransition) { + if (chrg != null) { + chrg.setCharacter(null); + } + wserv.removePlayer(player); + //getChannelServer().removePlayer(player); already being done + + player.saveCooldowns(); + player.cancelAllDebuffs(); + player.saveCharToDB(true); + + player.logOff(); + clear(); + } else { + getChannelServer().removePlayer(player); + + player.saveCooldowns(); + player.cancelAllDebuffs(); + player.saveCharToDB(); + } + } + } + if (!serverTransition && isLoggedIn()) { + MapleSessionCoordinator.getInstance().closeSession(session, false); + updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); + session.removeAttribute(MapleClient.CLIENT_KEY); // prevents double dcing during login + + clear(); + } else { + if (session.containsAttribute(MapleClient.CLIENT_KEY)) { + MapleSessionCoordinator.getInstance().closeSession(session, false); + session.removeAttribute(MapleClient.CLIENT_KEY); + } + + engines.clear(); + } + } + + private void clear() { + // player hard reference removal thanks to Steve (kaito1410) + if (this.player != null) { + this.player.empty(true); // clears schedules and stuff + } + + Server.getInstance().unregisterLoginState(this); + + this.accountName = null; + this.macs = null; + this.hwid = null; + this.birthday = null; + this.engines = null; + this.player = null; + this.receive = null; + this.send = null; + //this.session = null; + } + + public int getChannel() { + return channel; + } + + public Channel getChannelServer() { + return Server.getInstance().getChannel(world, channel); + } + + public World getWorldServer() { + return Server.getInstance().getWorld(world); + } + + public Channel getChannelServer(byte channel) { + return Server.getInstance().getChannel(world, channel); + } + + public boolean deleteCharacter(int cid, int senderAccId) { + try { + return MapleCharacter.deleteCharFromDB(MapleCharacter.loadCharFromDB(cid, this, false), senderAccId); + } catch (SQLException ex) { + ex.printStackTrace(); + return false; + } + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String a) { + this.accountName = a; + } + + public void setChannel(int channel) { + this.channel = channel; + } + + public int getWorld() { + return world; + } + + public void setWorld(int world) { + this.world = world; + } + + public void pongReceived() { + lastPong = Server.getInstance().getCurrentTime(); + } + + public void testPing(long timeThen) { + try { + if (lastPong < timeThen) { + if (session != null && session.isConnected()) { + MapleSessionCoordinator.getInstance().closeSession(session, false); + updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); + session.removeAttribute(MapleClient.CLIENT_KEY); + } + } + } catch (NullPointerException e) { + e.printStackTrace(); + } + } + + public String getHWID() { + return hwid; + } + + public void setHWID(String hwid) { + this.hwid = hwid; + } + + public Set getMacs() { + return Collections.unmodifiableSet(macs); + } + + public int getGMLevel() { + return gmlevel; + } + + public void setGMLevel(int level) { + gmlevel = level; + } + + public void setScriptEngine(String name, ScriptEngine e) { + engines.put(name, e); + } + + public ScriptEngine getScriptEngine(String name) { + return engines.get(name); + } + + public void removeScriptEngine(String name) { + engines.remove(name); + } + + public NPCConversationManager getCM() { + return NPCScriptManager.getInstance().getCM(this); + } + + public QuestActionManager getQM() { + return QuestScriptManager.getInstance().getQM(this); + } + + public boolean acceptToS() { + boolean disconnectForBeingAFaggot = false; + if (accountName == null) { + return true; + } + try { + Connection con = DatabaseConnection.getConnection(); + PreparedStatement ps = con.prepareStatement("SELECT `tos` FROM accounts WHERE id = ?"); + ps.setInt(1, accId); + ResultSet rs = ps.executeQuery(); + + if (rs.next()) { + if (rs.getByte("tos") == 1) { + disconnectForBeingAFaggot = true; + } + } + ps.close(); + rs.close(); + ps = con.prepareStatement("UPDATE accounts SET tos = 1 WHERE id = ?"); + ps.setInt(1, accId); + ps.executeUpdate(); + ps.close(); + con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return disconnectForBeingAFaggot; + } + + public int getVotePoints() { + int points = 0; + try { + Connection con = DatabaseConnection.getConnection(); + PreparedStatement ps = con.prepareStatement("SELECT `votepoints` FROM accounts WHERE id = ?"); + ps.setInt(1, accId); + ResultSet rs = ps.executeQuery(); + + if (rs.next()) { + points = rs.getInt("votepoints"); + } + ps.close(); + rs.close(); + + con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + votePoints = points; + return votePoints; + } + + public void addVotePoints(int points) { + votePoints += points; + saveVotePoints(); + } + + public void useVotePoints(int points) { + if (points > votePoints) { + //Should not happen, should probably log this + return; + } + votePoints -= points; + saveVotePoints(); + LogHelper.logLeaf(player, false, Integer.toString(points)); + } + + private void saveVotePoints() { + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET votepoints = ? WHERE id = ?")) { + ps.setInt(1, votePoints); + ps.setInt(2, accId); + ps.executeUpdate(); + } + + con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public void lockClient() { + lock.lock(); + } + + public void unlockClient() { + lock.unlock(); + } + + public boolean tryacquireClient() { + if (actionsSemaphore.tryAcquire()) { + lockClient(); + return true; + } else { + return false; + } + } + + public void releaseClient() { + unlockClient(); + actionsSemaphore.release(); + } + + public void lockEncoder() { + encoderLock.lock(); + } + + public void unlockEncoder() { + encoderLock.unlock(); + } + + private static class CharNameAndId { + + public String name; + public int id; + + public CharNameAndId(String name, int id) { + super(); + this.name = name; + this.id = id; + } + } + + private static boolean checkHash(String hash, String type, String password) { + try { + MessageDigest digester = MessageDigest.getInstance(type); + digester.update(password.getBytes("UTF-8"), 0, password.length()); + return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase().equals(hash); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + throw new RuntimeException("Encoding the string failed", e); + } + } + + public short getAvailableCharacterSlots() { + return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId)); + } + + public short getAvailableCharacterWorldSlots() { + return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world)); + } + + public short getCharacterSlots() { + return characterSlots; + } + + public void setCharacterSlots(byte slots) { + characterSlots = slots; + } + + public synchronized boolean gainCharacterSlot() { + if (characterSlots < 15) { + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET characterslots = ? WHERE id = ?")) { + ps.setInt(1, this.characterSlots += 1); + ps.setInt(2, accId); + ps.executeUpdate(); + } + + con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return true; + } + return false; + } + + public final byte getGReason() { + Connection con = null; + PreparedStatement ps = null; + ResultSet rs = null; + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT `greason` FROM `accounts` WHERE id = ?"); + ps.setInt(1, accId); + rs = ps.executeQuery(); + if (rs.next()) { + return rs.getByte("greason"); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + try { + if (ps != null) { + ps.close(); + } + if (rs != null) { + rs.close(); + } + if (con != null) { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + return 0; + } + + public byte getGender() { + return gender; + } + + public void setGender(byte m) { + this.gender = m; + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) { + ps.setByte(1, gender); + ps.setInt(2, accId); + ps.executeUpdate(); + } + + con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private void announceDisableServerMessage() { + if (!this.getWorldServer().registerDisabledServerMessage(player.getId())) { + announce(MaplePacketCreator.serverMessage("")); + } + } + + public void announceServerMessage() { + announce(MaplePacketCreator.serverMessage(this.getChannelServer().getServerMessage())); + } + + public synchronized void announceBossHpBar(MapleMonster mm, final int mobHash, final byte[] packet) { + long timeNow = System.currentTimeMillis(); + int targetHash = player.getTargetHpBarHash(); + + if (mobHash != targetHash) { + if (timeNow - player.getTargetHpBarTime() >= 5 * 1000) { + // is there a way to INTERRUPT this annoying thread running on the client that drops the boss bar after some time at every attack? + announceDisableServerMessage(); + announce(packet); + + player.setTargetHpBarHash(mobHash); + player.setTargetHpBarTime(timeNow); + } + } else { + announceDisableServerMessage(); + announce(packet); + + player.setTargetHpBarTime(timeNow); + } + } + + public synchronized void announce(final byte[] packet) {//MINA CORE IS A FUCKING BITCH AND I HATE IT <3 + session.write(packet); + } + + public void announceHint(String msg, int length) { + announce(MaplePacketCreator.sendHint(msg, length, 10)); + announce(MaplePacketCreator.enableActions()); + } + + public void changeChannel(int channel) { + Server server = Server.getInstance(); + if (player.isBanned()) { + disconnect(false, false); + return; + } + if (!player.isAlive() || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) { + announce(MaplePacketCreator.enableActions()); + return; + } else if (MapleMiniDungeonInfo.isDungeonMap(player.getMapId())) { + announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon.")); + announce(MaplePacketCreator.enableActions()); + return; + } + + String[] socket = Server.getInstance().getInetSocket(getWorld(), channel); + if (socket == null) { + announce(MaplePacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel.")); + announce(MaplePacketCreator.enableActions()); + return; + } + + if (player.getTrade() != null) { + MapleTrade.cancelTrade(getPlayer()); + } + + MapleHiredMerchant merchant = player.getHiredMerchant(); + if (merchant != null) { + if (merchant.isOwner(getPlayer())) { + merchant.setOpen(true); + } else { + merchant.removeVisitor(getPlayer()); + } + } + player.unregisterChairBuff(); + server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs()); + server.getPlayerBuffStorage().addDiseasesToStorage(player.getId(), player.getAllDiseases()); + player.setDisconnectedFromChannelWorld(); + player.notifyMapTransferToPartner(-1); + player.cancelAllBuffs(true); + player.cancelAllDebuffs(); + player.cancelBuffExpireTask(); + player.cancelDiseaseExpireTask(); + player.cancelSkillCooldownTask(); + player.cancelQuestExpirationTask(); + //Cancelling magicdoor? Nope + //Cancelling mounts? Noty + + player.getInventory(MapleInventoryType.EQUIPPED).checked(false); //test + player.getMap().removePlayer(player); + player.clearBanishPlayerData(); + player.getClient().getChannelServer().removePlayer(player); + player.getClient().updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); + try { + announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public long getSessionId() { + return this.sessionId; + } + + public void setSessionId(long sessionId) { + this.sessionId = sessionId; + } + + public boolean canRequestCharlist() { + return lastNpcClick + 877 < Server.getInstance().getCurrentTime(); + } + + public boolean canClickNPC() { + return lastNpcClick + 500 < Server.getInstance().getCurrentTime(); + } + + public void setClickedNPC() { + lastNpcClick = Server.getInstance().getCurrentTime(); + } + + public void removeClickedNPC() { + lastNpcClick = 0; + } + + public int getVisibleWorlds() { + return visibleWorlds; + } + + public void requestedServerlist(int worlds) { + visibleWorlds = worlds; + setClickedNPC(); + } + + public void closePlayerScriptInteractions() { + this.removeClickedNPC(); + NPCScriptManager.getInstance().dispose(this); + } + + public boolean attemptCsCoupon() { + if (csattempt > 2) { + resetCsCoupon(); + return false; + } + + csattempt++; + return true; + } + + public void resetCsCoupon() { + csattempt = 0; + } + + public void enableCSActions() { + announce(MaplePacketCreator.enableCSUse(player)); + } + + public String getNibbleHWID() { + return (String) session.getAttribute(MapleClient.CLIENT_NIBBLEHWID); + } + + public boolean canBypassPin() { + return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, false); + } + + public boolean canBypassPic() { + return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, true); + } } diff --git a/src/client/MapleDisease.java b/src/client/MapleDisease.java index 784be02d6e..f84ad4f1d9 100644 --- a/src/client/MapleDisease.java +++ b/src/client/MapleDisease.java @@ -21,34 +21,34 @@ */ package client; -import java.util.ArrayList; -import java.util.List; +import tools.Randomizer; public enum MapleDisease { NULL(0x0), - SLOW(0x1), - SEDUCE(0x80), + SLOW(0x1, 126), + SEDUCE(0x80, 128), FISHABLE(0x100), ZOMBIFY(0x4000), CONFUSE(0x80000), - STUN(0x2000000000000L), - POISON(0x4000000000000L), - SEAL(0x8000000000000L), - DARKNESS(0x10000000000000L), - WEAKEN(0x4000000000000000L), - CURSE(0x8000000000000000L); + STUN(0x2000000000000L, 123), + POISON(0x4000000000000L, 125), + SEAL(0x8000000000000L, 120), + DARKNESS(0x10000000000000L, 121), + WEAKEN(0x4000000000000000L, 122), + CURSE(0x8000000000000000L, 124); private long i; private boolean first; + private int disease; private MapleDisease(long i) { this.i = i; this.first = false; } - private MapleDisease(long i, boolean first) { + private MapleDisease(long i, int disease) { this.i = i; - this.first = first; + this.disease = disease; } public long getValue() { @@ -58,6 +58,10 @@ public enum MapleDisease { public boolean isFirst() { return first; } + + public int getDisease() { + return disease; + } public static MapleDisease ordinal(int ord) { try { @@ -66,4 +70,24 @@ public enum MapleDisease { return NULL; } } + + public static final MapleDisease getRandom() { + while (true) { + for (MapleDisease dis : MapleDisease.values()) { + if (Randomizer.nextInt(MapleDisease.values().length) == 0) { + return dis; + } + } + } + } + + public static final MapleDisease getBySkill(final int skill) { + for (MapleDisease d : MapleDisease.values()) { + if (d.getDisease() == skill && d.getDisease() != 0) { + return d; + } + } + return null; + } + } diff --git a/src/client/command/commands/gm5/DebugCommand.java b/src/client/command/commands/gm5/DebugCommand.java index 7346f522cb..96f2eb132a 100644 --- a/src/client/command/commands/gm5/DebugCommand.java +++ b/src/client/command/commands/gm5/DebugCommand.java @@ -39,6 +39,7 @@ import tools.MaplePacketCreator; import java.awt.*; import java.util.Arrays; import java.util.List; +import tools.packets.Wedding; public class DebugCommand extends Command { private final static String debugTypes[] = {"monster", "packet", "portal", "spawnpoint", "pos", "map", "mobsp", "event", "areas", "reactors", "servercoupons", "playercoupons", "timer", "marriage", ""}; diff --git a/src/constants/LinguaConstants.java b/src/constants/LinguaConstants.java new file mode 100644 index 0000000000..f583c24b05 --- /dev/null +++ b/src/constants/LinguaConstants.java @@ -0,0 +1,74 @@ +/* + * 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 constants; + +import client.MapleCharacter; + +/** + * + * @author Drago + */ +public class LinguaConstants { + // Portugues + public static String CPQAzul; + public static String CPQErro; + public static String CPQEntrada; + public static String CPQEscolha; + public static String CPQVermelho; + public static String CPQPlayerExit; + public static String CPQEntradaLobby; + public static String CPQInicioEscolha; + public static String CPQTempoExtendido; + public static String CPQLiderNaoEncontrado; + public static String CPQInicioEscolhaEmEscolha; + + public static LinguaConstants Linguas(MapleCharacter chr) { + if (chr.getLingua() == 0) { + LinguaConstants.CPQAzul = "Maple Azul"; + LinguaConstants.CPQVermelho = "Maple Vermelho"; + LinguaConstants.CPQTempoExtendido = "O tempo foi estendido."; + LinguaConstants.CPQPlayerExit = " deixou o Carnaval de Monstros."; + LinguaConstants.CPQErro = "Ocorreu um problema. Favor recriar a sala."; + LinguaConstants.CPQLiderNaoEncontrado = "Não foi possível encontrar o Lider."; + LinguaConstants.CPQInicioEscolha = "Inscreva-se no Festival de Monstros!\\r\\n"; + LinguaConstants.CPQInicioEscolhaEmEscolha = "O grupo esta respondendo um desafio no momento."; + LinguaConstants.CPQEscolha = "Não foi possí­vel encontrar um grupo nesta sala.\\r\\nProvavelmente o grupo foi desfeito dentro da sala!"; + LinguaConstants.CPQEntradaLobby = "[CPQ MapleStorySA] Agora você irá receber desafios de outros grupos. Se você não aceitar um desafio em 3 minutos, você será levado para fora."; + LinguaConstants.CPQEntrada = "Você pode selecionar \"Invocar Monstros\", \"Habilidade\", ou \"Protetor\" como sua tática durante o Carnaval dos Monstros. Use Tab a F1~F12 para acesso rápido!"; + + + + } else if (chr.getLingua() == 1) { + LinguaConstants.CPQAzul = "Maple Azul"; + LinguaConstants.CPQVermelho = "Maple Rojo"; + LinguaConstants.CPQTempoExtendido = "El tiempo se ha ampliado."; + LinguaConstants.CPQPlayerExit = " ha dejado el Carnaval de Monstruos."; + LinguaConstants.CPQLiderNaoEncontrado = "No se pudo encontrar el Lider."; + LinguaConstants.CPQInicioEscolha = "¡Inscríbete en el Festival de Monstruos!\\r\\n"; + LinguaConstants.CPQErro = "Se ha producido un problema. Por favor, volver a crear una sala."; + LinguaConstants.CPQInicioEscolhaEmEscolha = "El grupo esta respondiendo un desafío en el momento."; + LinguaConstants.CPQEscolha = "No se pudo encontrar un grupo en esta sala.\\r\\nProbablemente el grupo fue deshecho dentro de la sala!"; + LinguaConstants.CPQEntradaLobby = "[CPQ MapleStorySA] Ahora usted recibirá los retos de otros grupos. Si usted no acepta un desafío en 3 minutos, usted será llevado hacia fuera."; + LinguaConstants.CPQEntrada = "Usted puede seleccionar \"Invocar Monstruos \", \"Habilidad \", o \"Protector \" como su táctica durante el Carnaval de los Monstruos. Utilice Tab y F1 ~ F12 para acceso rápido!"; + + + } else if (chr.getLingua() == 2) { + LinguaConstants.CPQAzul = "Maple Blue"; + LinguaConstants.CPQVermelho = "Maple Red"; + LinguaConstants.CPQPlayerExit = " left the Carnival of Monsters."; + LinguaConstants.CPQTempoExtendido = "The time has been extended."; + LinguaConstants.CPQLiderNaoEncontrado = "Could not find the Leader."; + LinguaConstants.CPQErro = "There was a problem. Please re-create a room."; + LinguaConstants.CPQInicioEscolha = "Sign up for the Monster Festival!\\r\\n"; + LinguaConstants.CPQInicioEscolhaEmEscolha = "The group is currently facing a challenge."; + LinguaConstants.CPQEscolha = "We could not find a group in this room.\\r\\nProbably the group was scrapped inside the room!"; + LinguaConstants.CPQEntradaLobby = "[CPQ MapleStorySA] You will now receive challenges from other groups. If you do not accept a challenge within 3 minutes, you will be taken out."; + LinguaConstants.CPQEntrada = "You can select \"Summon Monsters \", \"Ability \", or \"Protector \" as your tactic during the Monster Carnival. Use Tab and F1 ~ F12 for quick access!"; + + } + return null; + } +} diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java index 554dc7f76b..fd36f5b093 100644 --- a/src/constants/ServerConstants.java +++ b/src/constants/ServerConstants.java @@ -33,7 +33,7 @@ public class ServerConstants { public static final int BYPASS_PIC_EXPIRATION = 20; //Enables PIC bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable. public static final int BYPASS_PIN_EXPIRATION = 15; //Enables PIN bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable. - public static final boolean AUTOMATIC_REGISTER = true; //Automatically register players when they login with a nonexistent username. + public static final boolean AUTOMATIC_REGISTER = false; //Automatically register players when they login with a nonexistent username. public static final boolean BCRYPT_MIGRATION = true; //Performs a migration from old SHA-1 and SHA-512 password to bcrypt. public static final boolean COLLECTIVE_CHARSLOT = false; //Available character slots are contabilized globally rather than per world server. public static final boolean DETERRED_MULTICLIENT = false; //Enables multi-client and suspicious remote IP detection on the login system. @@ -58,7 +58,7 @@ public class ServerConstants { public static final boolean USE_CUSTOM_KEYSET = true; //Enables auto-setup of the HeavenMS's custom keybindings when creating characters. public static final boolean USE_DEBUG = false; //Will enable some text prints on the client, oriented for debugging purposes. public static final boolean USE_DEBUG_SHOW_INFO_EQPEXP = false; //Prints on the cmd all equip exp gain info. - public static boolean USE_DEBUG_SHOW_RCVD_PACKET = false; //Prints on the cmd all received packet ids. + public static boolean USE_DEBUG_SHOW_RCVD_PACKET = true; //Prints on the cmd all received packet ids. public static boolean USE_DEBUG_SHOW_RCVD_MVLIFE = false; //Prints on the cmd all received move life content. public static boolean USE_SUPPLY_RATE_COUPONS = true; //Allows rate coupons to be sold through the Cash Shop. diff --git a/src/net/server/channel/handlers/ChangeMapHandler.java b/src/net/server/channel/handlers/ChangeMapHandler.java index 746716040a..b74df3538c 100644 --- a/src/net/server/channel/handlers/ChangeMapHandler.java +++ b/src/net/server/channel/handlers/ChangeMapHandler.java @@ -1,23 +1,23 @@ /* -This file is part of the OdinMS Maple Story Server -Copyright (C) 2008 Patrick Huy -Matthias Butz -Jan Christian Meyer + 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 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. + 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 . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ package net.server.channel.handlers; @@ -39,131 +39,130 @@ import tools.data.input.SeekableLittleEndianAccessor; public final class ChangeMapHandler extends AbstractMaplePacketHandler { - @Override - public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - MapleCharacter chr = c.getPlayer(); + @Override + public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { + MapleCharacter chr = c.getPlayer(); - if (chr.isChangingMaps() || chr.isBanned()) { - if(chr.isChangingMaps()) { - FilePrinter.printError(FilePrinter.PORTAL_STUCK + chr.getName() + ".txt", "Player " + chr.getName() + " got stuck when changing maps. Timestamp: " + Calendar.getInstance().getTime().toString() + " Last visited mapids: " + chr.getLastVisitedMapids()); - } - - c.announce(MaplePacketCreator.enableActions()); - return; - } - if (chr.getTrade() != null) { - MapleTrade.cancelTrade(chr); - } - if (slea.available() == 0) { //Cash Shop :) - if(!chr.getCashShop().isOpened()) { - c.disconnect(false, false); - return; - } - String[] socket = c.getChannelServer().getIP().split(":"); - chr.getCashShop().open(false); - c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - try { - c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); - } catch (UnknownHostException ex) { - ex.printStackTrace(); - } - } else { - if(chr.getCashShop().isOpened()) { - c.disconnect(false, false); - return; - } - try { - slea.readByte(); // 1 = from dying 0 = regular portals - int targetid = slea.readInt(); - String startwp = slea.readMapleAsciiString(); - MaplePortal portal = chr.getMap().getPortal(startwp); - slea.readByte(); - boolean wheel = slea.readShort() > 0; - if (targetid != -1 && !chr.isAlive()) { - MapleMap map = chr.getMap(); - if (wheel && chr.haveItemWithId(5510000, false)) { + if (chr.isChangingMaps() || chr.isBanned()) { + if (chr.isChangingMaps()) { + FilePrinter.printError(FilePrinter.PORTAL_STUCK + chr.getName() + ".txt", "Player " + chr.getName() + " got stuck when changing maps. Timestamp: " + Calendar.getInstance().getTime().toString() + " Last visited mapids: " + chr.getLastVisitedMapids()); + } + + c.announce(MaplePacketCreator.enableActions()); + return; + } + if (chr.getTrade() != null) { + MapleTrade.cancelTrade(chr); + } + if (slea.available() == 0) { //Cash Shop :) + if (!chr.getCashShop().isOpened()) { + c.disconnect(false, false); + return; + } + String[] socket = c.getChannelServer().getIP().split(":"); + chr.getCashShop().open(false); + c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); + try { + c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); + } catch (UnknownHostException ex) { + ex.printStackTrace(); + } + } else { + if (chr.getCashShop().isOpened()) { + c.disconnect(false, false); + return; + } + try { + slea.readByte(); // 1 = from dying 0 = regular portals + int targetid = slea.readInt(); + String startwp = slea.readMapleAsciiString(); + MaplePortal portal = chr.getMap().getPortal(startwp); + slea.readByte(); + boolean wheel = slea.readShort() > 0; + if (targetid != -1 && !chr.isAlive()) { + MapleMap map = chr.getMap(); + if (wheel && chr.haveItemWithId(5510000, false)) { // thanks lucasziron for showing revivePlayer() also being triggered by Wheel - - MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5510000, 1, true, false); - chr.announce(MaplePacketCreator.showWheelsLeft(chr.getItemQuantity(5510000, false))); - chr.updateHp(50); - chr.changeMap(map, map.findClosestPlayerSpawnpoint(chr.getPosition())); - } else { - boolean executeStandardPath = true; - if (chr.getEventInstance() != null) { - executeStandardPath = chr.getEventInstance().revivePlayer(chr); - } - if (executeStandardPath) { - chr.respawn(map.getReturnMapId()); - } - } - } else if (targetid != -1) { - if(chr.isGM()) { - MapleMap to = chr.getWarpMap(targetid); - chr.changeMap(to, to.getPortal(0)); - } - else { - final int divi = chr.getMapId() / 100; - boolean warp = false; - if (divi == 0) { - if (targetid == 10000) { - warp = true; - } - } else if (divi == 20100) { - if (targetid == 104000000) { - c.announce(MaplePacketCreator.lockUI(false)); - c.announce(MaplePacketCreator.disableUI(false)); - warp = true; - } - } else if (divi == 9130401) { // Only allow warp if player is already in Intro map, or else = hack - if (targetid == 130000000 || targetid / 100 == 9130401) { // Cygnus introduction - warp = true; - } - } else if (divi == 9140900) { // Aran Introduction - if (targetid == 914090011 || targetid == 914090012 || targetid == 914090013 || targetid == 140090000) { - warp = true; - } - } else if (divi / 10 == 1020) { // Adventurer movie clip Intro - if (targetid == 1020000) { - warp = true; - } - } else if(divi / 10 >= 980040 && divi / 10 <= 980045) { - if(targetid == 980040000) { - warp = true; - } - } - if (warp) { - final MapleMap to = chr.getWarpMap(targetid); - chr.changeMap(to, to.getPortal(0)); - } - } - } - if (portal != null && !portal.getPortalStatus()) { - c.announce(MaplePacketCreator.blockedMessage(1)); - c.announce(MaplePacketCreator.enableActions()); - return; - } - - if (chr.getMapId() == 109040004) { - chr.getFitness().resetTimes(); - } else if (chr.getMapId() == 109030003 || chr.getMapId() == 109030103) { - chr.getOla().resetTimes(); - } - - if (portal != null) { - if(portal.getPosition().distanceSq(chr.getPosition()) > 400000) { - c.announce(MaplePacketCreator.enableActions()); - return; - } - - portal.enterPortal(c); - } else { - c.announce(MaplePacketCreator.enableActions()); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } + MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5510000, 1, true, false); + chr.announce(MaplePacketCreator.showWheelsLeft(chr.getItemQuantity(5510000, false))); + + chr.updateHp(50); + chr.changeMap(map, map.findClosestPlayerSpawnpoint(chr.getPosition())); + } else { + boolean executeStandardPath = true; + if (chr.getEventInstance() != null) { + executeStandardPath = chr.getEventInstance().revivePlayer(chr); + } + if (executeStandardPath) { + chr.respawn(map.getReturnMapId()); + } + } + } else if (targetid != -1) { + if (chr.isGM()) { + MapleMap to = chr.getWarpMap(targetid); + chr.changeMap(to, to.getPortal(0)); + } else { + final int divi = chr.getMapId() / 100; + boolean warp = false; + if (divi == 0) { + if (targetid == 10000) { + warp = true; + } + } else if (divi == 20100) { + if (targetid == 104000000) { + c.announce(MaplePacketCreator.lockUI(false)); + c.announce(MaplePacketCreator.disableUI(false)); + warp = true; + } + } else if (divi == 9130401) { // Only allow warp if player is already in Intro map, or else = hack + if (targetid == 130000000 || targetid / 100 == 9130401) { // Cygnus introduction + warp = true; + } + } else if (divi == 9140900) { // Aran Introduction + if (targetid == 914090011 || targetid == 914090012 || targetid == 914090013 || targetid == 140090000) { + warp = true; + } + } else if (divi / 10 == 1020) { // Adventurer movie clip Intro + if (targetid == 1020000) { + warp = true; + } + } else if (divi / 10 >= 980040 && divi / 10 <= 980045) { + if (targetid == 980040000) { + warp = true; + } + } + if (warp) { + final MapleMap to = chr.getWarpMap(targetid); + chr.changeMap(to, to.getPortal(0)); + } + } + } + if (portal != null && !portal.getPortalStatus()) { + c.announce(MaplePacketCreator.blockedMessage(1)); + c.announce(MaplePacketCreator.enableActions()); + return; + } + + if (chr.getMapId() == 109040004) { + chr.getFitness().resetTimes(); + } else if (chr.getMapId() == 109030003 || chr.getMapId() == 109030103) { + chr.getOla().resetTimes(); + } + + if (portal != null) { + if (portal.getPosition().distanceSq(chr.getPosition()) > 400000) { + c.announce(MaplePacketCreator.enableActions()); + return; + } + + portal.enterPortal(c); + } else { + c.announce(MaplePacketCreator.enableActions()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } } diff --git a/src/net/server/channel/handlers/MonsterCarnivalHandler.java b/src/net/server/channel/handlers/MonsterCarnivalHandler.java index ccf29d9a38..fe18b82532 100644 --- a/src/net/server/channel/handlers/MonsterCarnivalHandler.java +++ b/src/net/server/channel/handlers/MonsterCarnivalHandler.java @@ -1,223 +1,154 @@ /* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + 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 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 . -*/ + 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 net.server.channel.handlers; import client.MapleCharacter; import client.MapleClient; +import client.MapleDisease; import java.awt.Point; +import java.util.List; import net.AbstractMaplePacketHandler; -import server.partyquest.MonsterCarnival; +import net.server.world.MapleParty; +import net.server.world.MaplePartyCharacter; import server.life.MapleLifeFactory; -import server.maps.MapleReactor; -import server.maps.MapleReactorFactory; +import server.life.MapleMonster; +import server.partyquest.MapleCarnivalFactory; +import server.partyquest.MapleCarnivalFactory.MCSkill; import tools.MaplePacketCreator; +import tools.Pair; import tools.data.input.SeekableLittleEndianAccessor; + /** - * - * @author kevintjuh93 - */ -public final class MonsterCarnivalHandler extends AbstractMaplePacketHandler{ + *@author Drago/Dragohe4rt +*/ + +public final class MonsterCarnivalHandler extends AbstractMaplePacketHandler { + + @Override public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - MapleCharacter chr = c.getPlayer(); - MonsterCarnival carnival = chr.getCarnival(); - int tab = slea.readByte(); - int number = slea.readShort(); - if (carnival != null) { - if (chr.getCarnivalParty() != carnival.getPartyRed() || chr.getCarnivalParty() != carnival.getPartyBlue()) { - chr.getMap().broadcastMessage(MaplePacketCreator.leaveCPQ(chr)); - chr.changeMap(980000010); - } - if (chr.getCP() > getPrice(tab, number)) { - if (tab == 0) { //SPAWNING - if (chr.getCarnivalParty().canSummon()) { - chr.getMap().spawnCPQMonster(MapleLifeFactory.getMonster(getMonster(number)), new Point(1, 1), carnival.oppositeTeam(chr.getCarnivalParty()).getTeam()); - chr.getCarnivalParty().summon(); - } else - chr.announce(MaplePacketCreator.CPQMessage((byte) 2)); - - } else if (tab == 1) { - - } else if (tab == 2) { - int rid = 9980000 + chr.getTeam(); - MapleReactor reactor = new MapleReactor(MapleReactorFactory.getReactor(rid), rid); - /*switch (number) { - case 0: - reactor.setMonsterStatus(tab, MonsterStatus.WEAPON_ATTACK_UP, MobSkillFactory.getMobSkill(150, 1)); - break; - case 1: - reactor.setMonsterStatus(tab, MonsterStatus.WEAPON_DEFENSE_UP, MobSkillFactory.getMobSkill(151, 1)); - break; - case 2: - reactor.setMonsterStatus(tab, MonsterStatus.MAGIC_ATTACK_UP, MobSkillFactory.getMobSkill(152, 1)); - break; - case 3: - reactor.setMonsterStatus(tab, MonsterStatus.MAGIC_DEFENSE_UP, MobSkillFactory.getMobSkill(153, 1)); - break; - case 4: - reactor.setMonsterStatus(tab, MonsterStatus.ACC, MobSkillFactory.getMobSkill(154, 1)); - break; - case 5: - reactor.setMonsterStatus(tab, MonsterStatus.AVOID, MobSkillFactory.getMobSkill(155, 1)); - break; - case 6: - reactor.setMonsterStatus(tab, MonsterStatus.SPEED, MobSkillFactory.getMobSkill(156, 1)); - break; - case 7: - reactor.setMonsterStatus(tab, MonsterStatus.WEAPON_IMMUNITY, MobSkillFactory.getMobSkill(140, 1)); - break; - case 8: - reactor.setMonsterStatus(tab, MonsterStatus.MAGIC_IMMUNITY, MobSkillFactory.getMobSkill(141, 1)); - break; - } */ - chr.getMap().spawnReactor(reactor); + try { + int tab = slea.readByte(); + int num = slea.readByte(); + int neededCP = 0; + if (tab == 0) { + final List> mobs = c.getPlayer().getMap().getMobsToSpawn(); + if (num >= mobs.size() || c.getPlayer().getCP() < mobs.get(num).right) { + c.announce(MaplePacketCreator.CPQMessage((byte) 1)); + c.getSession().write(MaplePacketCreator.enableActions()); + return; } - } else { - chr.getMap().broadcastMessage(MaplePacketCreator.CPQMessage((byte) 1)); - } - } else { - chr.announce(MaplePacketCreator.CPQMessage((byte) 5)); - } - chr.announce(MaplePacketCreator.enableActions()); - } - public int getMonster(int num) { - int mid = 0; - num++; - switch (num) { - case 1: - mid = 9300127; - break; - case 2: - mid = 9300128; - break; - case 3: - mid = 9300129; - break; - case 4: - mid = 9300130; - break; - case 5: - mid = 9300131; - break; - case 6: - mid = 9300132; - break; - case 7: - mid = 9300133; - break; - case 8: - mid = 9300134; - break; - case 9: - mid = 9300135; - break; - case 10: - mid = 9300136; - break; + final MapleMonster mob = MapleLifeFactory.getMonster(mobs.get(num).left); + if (c.getPlayer().getMonsterCarnival() != null) { + Point spawnPos = c.getPlayer().getMap().getRandomSP(c.getPlayer().getTeam()); + if (!c.getPlayer().getMonsterCarnival().canSummon() && c.getPlayer().getTeam() == 0 || !c.getPlayer().getMonsterCarnival().canSummons() && c.getPlayer().getTeam() == 1) { + c.announce(MaplePacketCreator.CPQMessage((byte) 2)); + c.getSession().write(MaplePacketCreator.enableActions()); + return; + } + mob.setPosition(spawnPos); + if (c.getPlayer().getTeam() == 0) { + c.getPlayer().getMonsterCarnival().summon(); + } else { + c.getPlayer().getMonsterCarnival().summons(); + } + c.getPlayer().getMap().addMonsterSpawn(mob, 1, c.getPlayer().getTeam()); + c.getSession().write(MaplePacketCreator.enableActions()); + } + neededCP = mobs.get(num).right; + } else if (tab == 1) { //debuffs + final List skillid = c.getPlayer().getMap().getSkillIds(); + if (num >= skillid.size()) { + c.getPlayer().dropMessage(5, "Ocorreu um erro."); + c.getSession().write(MaplePacketCreator.enableActions()); + return; + } + final MCSkill skil = MapleCarnivalFactory.getInstance().getSkill(skillid.get(num)); //ugh wtf + if (skil == null || c.getPlayer().getCP() < skil.cpLoss) { + c.announce(MaplePacketCreator.CPQMessage((byte) 1)); + c.getSession().write(MaplePacketCreator.enableActions()); + return; + } + final MapleDisease dis = skil.getDisease(); + MapleParty inimigos = c.getPlayer().getParty().getEnemy(); + if (skil.targetsAll) { + int chanceAcerto = 0; + if (dis.getDisease() == 121 || dis.getDisease() == 122 || dis.getDisease() == 125 || dis.getDisease() == 126) { + chanceAcerto = (int) (Math.random() * 100); + } + if (chanceAcerto <= 80) { + for (MaplePartyCharacter chrS : inimigos.getPartyMembers()) { + if (dis == null) { + chrS.getPlayer().dispel(); + } else { + chrS.getPlayer().giveDebuff(dis, skil.getSkill()); + } + if (!skil.targetsAll) { + break; + } + } + } + } else { + int amount = inimigos.getMembers().size() - 1; + int randd = (int) Math.floor(Math.random() * amount); + MapleCharacter chrApp = c.getChannelServer().getPlayerStorage().getCharacterById(inimigos.getMemberByPos(randd).getId()); + if (chrApp != null && chrApp.getMap().isCPQMap()) { + if (dis == null) { + chrApp.dispel(); + } else { + chrApp.giveDebuff(dis, skil.getSkill()); + } + } + } + neededCP = skil.cpLoss; + c.getSession().write(MaplePacketCreator.enableActions()); + } else if (tab == 2) { //protectors + final MCSkill skil = MapleCarnivalFactory.getInstance().getGuardian(num); + if (skil == null || c.getPlayer().getCP() < skil.cpLoss) { + c.announce(MaplePacketCreator.CPQMessage((byte) 1)); + c.getSession().write(MaplePacketCreator.enableActions()); + return; + } + int success = c.getPlayer().getMap().spawnGuardian(c.getPlayer().getTeam(), num); + if (success == -1 || success == 0 || success == 2) { + if (success == -1) { + c.announce(MaplePacketCreator.CPQMessage((byte) 3)); + } else if (success == 0) { + c.announce(MaplePacketCreator.CPQMessage((byte) 4)); + } else if (success == 2) { + c.announce(MaplePacketCreator.CPQMessage((byte) 3)); + } + c.getSession().write(MaplePacketCreator.enableActions()); + return; + } else { + neededCP = skil.cpLoss; + } + } + c.getPlayer().gainCP(-neededCP); + c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.playerSummoned(c.getPlayer().getName(), tab, num)); + }catch (Exception e) { + e.printStackTrace(); } - return mid; - } - - public int getPrice(int num, int tab) { - int price = 0; - num++; - - if (tab == 0) { - switch (num) { - case 1: - case 2: - price = 7; - break; - case 3: - case 4: - price = 8; - break; - case 5: - case 6: - price = 9; - break; - case 7: - price = 10; - break; - case 8: - price = 11; - break; - case 9: - price = 12; - break; - case 10: - price = 30; - break; - } - } else if (tab == 1) { - switch (num) { - case 1: - price = 17; - break; - case 2: - case 4: - price = 19; - break; - case 3: - price = 12; - break; - case 5: - price = 16; - break; - case 6: - price = 14; - break; - case 7: - price = 22; - break; - case 8: - price = 18; - break; - } - } else { - switch (num) { - case 1: - case 3: - price = 17; - break; - case 2: - case 4: - case 6: - price = 16; - break; - case 5: - price = 13; - break; - case 7: - price = 12; - break; - case 8: - case 9: - price = 35; - break; - } } - return price; + } -} diff --git a/src/net/server/channel/handlers/RingActionHandler.java b/src/net/server/channel/handlers/RingActionHandler.java index aaab19a914..33a9f29648 100644 --- a/src/net/server/channel/handlers/RingActionHandler.java +++ b/src/net/server/channel/handlers/RingActionHandler.java @@ -21,8 +21,6 @@ */ package net.server.channel.handlers; -//import java.sql.Connection; -//import java.sql.PreparedStatement; import client.MapleClient; import client.MapleCharacter; import client.inventory.MapleInventoryType; @@ -31,14 +29,10 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -//import tools.DatabaseConnection; import net.AbstractMaplePacketHandler; import client.inventory.manipulator.MapleInventoryManipulator; import tools.DatabaseConnection; import tools.data.input.SeekableLittleEndianAccessor; -//import scripting.npc.NPCScriptManager; import tools.Pair; import tools.MaplePacketCreator; import tools.packets.Wedding; @@ -52,6 +46,7 @@ import client.inventory.Item; /** * @author Jvlaple * @author Ronan - major overhaul on Ring handling mechanics + * @author Drago/Dragohe4rt on Wishlist */ public final class RingActionHandler extends AbstractMaplePacketHandler { private static int getBoxId(int useItemId) { @@ -467,11 +462,16 @@ public final class RingActionHandler extends AbstractMaplePacketHandler { break; - case 9: // Groom and Bride's Wishlist - short size = slea.readShort(); - List itemnames = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - itemnames.add(slea.readMapleAsciiString()); + case 9: + // By Drago/Dragohe4rt + // Groom and Bride's Wishlist + //short size = slea.readShort(); + int amount = slea.readShort(); + if (amount > 10) { + amount = 10; + } + for (int i = 0; i < amount; i++) { + c.getPlayer().setItens(slea.readMapleAsciiString()); } //System.out.println("G&B WISHLIST: " + itemnames); diff --git a/src/net/server/channel/handlers/WeddingHandler.java b/src/net/server/channel/handlers/WeddingHandler.java index 903fadb363..301c3ce5db 100644 --- a/src/net/server/channel/handlers/WeddingHandler.java +++ b/src/net/server/channel/handlers/WeddingHandler.java @@ -10,84 +10,61 @@ import client.inventory.Item; import client.inventory.MapleInventoryType; import client.MapleCharacter; import client.MapleClient; +import client.inventory.Equip; import constants.ItemConstants; -import tools.DatabaseConnection; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; import net.AbstractMaplePacketHandler; import client.inventory.manipulator.MapleInventoryManipulator; +import net.server.channel.Channel; +import scripting.event.EventInstanceManager; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; import tools.packets.Wedding; /** * - * @author Eric + * @author By Drago/Dragohe4rt */ public final class WeddingHandler extends AbstractMaplePacketHandler { - /* - public static final void OnWeddingProgress(byte action, MapleClient c) { - // -- Pelvis Bebop: - // 0x00: "We are gathered here today..." - // 0x01: "Very well! I pronounce you..." - // 0x02: "You two truly are a sight to..." - // 0x03: Wedding Ceremony Ended, initialize the Wedding Effect upon the two married characters - // -- High Priest John: (Unknown action bytes) - // 0x00: " " - // 0x01: " " - // 0x02: "Do you wish to bless this couple?..." - // 0x03: Wedding Ceremony Ended, initialize the Wedding Effect upon the two married characters - if (c.getPlayer().getWedding() != null) { - if (c.getPlayer().getGender() == 0 ? c.getPlayer().getWedding().isExistantGroom(c.getPlayer().getId()) : c.getPlayer().getWedding().isExistantBride(c.getPlayer().getId())) { - c.getPlayer().getMap().broadcastMessage(Wedding.OnWeddingProgress(action == 2, c.getPlayer().getId(), c.getPlayer().getPartnerId(), (byte)(action+1))); - c.getPlayer().getWedding().incrementStage(); - c.getPlayer().getPartner().getWedding().incrementStage(); // pls don't b a bitch and throw npe ):< - if (action == 2) { - c.getPlayer().setMarried(true); - c.getChannelServer().getPlayerStorage().getCharacterById(c.getPlayer().getPartnerId()).setMarried(true); - } - } - } - c.announce(MaplePacketCreator.enableActions()); - } - - public static final void OnWeddingGiftResult(SeekableLittleEndianAccessor slea, MapleClient c) { - System.out.println("New WEDDING_GIFT_RESULT: " + slea.toString()); - byte mode = slea.readByte(); - switch(mode) { - case 0x06: // "SEND ITEM" - short slot = slea.readShort(); // isn't this a byte? o.O - int itemId = slea.readInt(); - short quantity = slea.readShort(); - if (c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).getItem((byte)slot).getItemId() == itemId && c.getPlayer().getInventory(InventoryConstants.getInventoryType(itemId)).getItem((byte)slot).getQuantity() >= quantity) { - if (c.getPlayer().getWedding() == null) { - c.getPlayer().startWedding(); // TODO - } - List itemnames = new ArrayList<>(); - Item item = c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).getItem((byte)slot); - boolean bride = false; - c.getPlayer().getWedding().registerWishlistItem(item, bride); - c.announce(Wedding.OnWeddingGiftResult((byte)11, itemnames, c.getPlayer().getWedding().getWishlistItems(bride))); // todo: remove item from inventory if success - } - case 0x08: // "EXIT" - if (slea.available() != 0) { - System.out.println("WEDDING_GIFT_RESULT: " + slea.toString()); - } - c.announce(MaplePacketCreator.enableActions()); - break; - default: { - System.out.println("Unknown Mode Found: " + mode + " : " + slea.toString()); - } - } - } - */ @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - c.announce(MaplePacketCreator.enableActions()); + MapleCharacter chr = c.getPlayer(); + final byte mode = slea.readByte(); + Channel cs = c.getChannelServer(); + + if (mode == 6) { //additem + short slot = slea.readShort(); + int itemid = slea.readInt(); + short quantity = slea.readShort(); + EventInstanceManager eim = c.getPlayer().getEventInstance(); + if (eim != null) { + String name = eim.getProperty("brideId"); + MapleCharacter chrs = cs.getPlayerStorage().getCharacterById(Integer.parseInt(name)); + //MapleCharacter chrs = cs.getPlayerStorage().getCharacterById(3); + MapleInventoryType type = ItemConstants.getInventoryType(itemid); + Item item = chr.getInventory(type).getItem((byte) slot); + if (itemid == item.getItemId() && quantity <= item.getQuantity()) { + if(!(item instanceof Equip)) { + item = new Item(itemid, slot, quantity); + } + chrs.setEquips(item); + MapleInventoryManipulator.removeById(chr.getClient(), type, itemid, quantity, false, false); + c.announce(Wedding.OnWeddingGiftResult((byte) 0xB, chrs.getItens(), chrs.getItem())); + } + } + } else if (mode == 7) { // noiva abre e pega itens + byte inventId = slea.readByte(); + int itemPos = slea.readByte(); + MapleInventoryType inv = MapleInventoryType.getByType(inventId); + Item item = chr.getItemid(itemPos); + c.getAbstractPlayerInteraction().gainItem(item.getItemId(), item.getQuantity()); + chr.removeItem(item); + c.announce(Wedding.OnWeddingGiftResult((byte) 0xF, chr.getItens(), chr.getItem())); + } else if (mode == 8) { // sair update? + + c.announce(MaplePacketCreator.enableActions()); + } else { + System.out.println(mode); + } } } \ No newline at end of file diff --git a/src/net/server/world/MapleParty.java b/src/net/server/world/MapleParty.java index 721a5e1131..a3f155d8cc 100644 --- a/src/net/server/world/MapleParty.java +++ b/src/net/server/world/MapleParty.java @@ -1,24 +1,24 @@ /* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + 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 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. + 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 . -*/ + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ package net.server.world; import client.MapleClient; @@ -37,19 +37,20 @@ import net.server.audit.locks.factory.MonitoredReentrantLockFactory; import server.maps.MapleDoor; public class MapleParty { + private int id; - + private MapleParty enemy = null; private int leaderId; private List members = new LinkedList<>(); private List pqMembers = null; - + private Map histMembers = new HashMap<>(); private int nextEntry = 0; - + private Map doors = new HashMap<>(); - + private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PARTY, true); - + public MapleParty(int id, MaplePartyCharacter chrfor) { this.leaderId = chrfor.getId(); this.id = id; @@ -103,7 +104,7 @@ public class MapleParty { lock.unlock(); } } - + public MaplePartyCharacter getMemberById(int id) { lock.lock(); try { @@ -126,7 +127,7 @@ public class MapleParty { lock.unlock(); } } - + public List getPartyMembers() { lock.lock(); try { @@ -135,16 +136,16 @@ public class MapleParty { lock.unlock(); } } - + // used whenever entering PQs: will draw every party member that can attempt a target PQ while ingnoring those unfit. public Collection getEligibleMembers() { return Collections.unmodifiableList(pqMembers); } - + public void setEligibleMembers(List eliParty) { pqMembers = eliParty; } - + public int getId() { return id; } @@ -152,7 +153,7 @@ public class MapleParty { public void setId(int id) { this.id = id; } - + public int getLeaderId() { return leaderId; } @@ -160,8 +161,8 @@ public class MapleParty { public MaplePartyCharacter getLeader() { lock.lock(); try { - for(MaplePartyCharacter mpc: members) { - if(mpc.getId() == leaderId) { + for (MaplePartyCharacter mpc : members) { + if (mpc.getId() == leaderId) { return mpc; } } @@ -171,45 +172,53 @@ public class MapleParty { lock.unlock(); } } - + + public MapleParty getEnemy() { + return enemy; + } + + public void setEnemy(MapleParty enemy) { + this.enemy = enemy; + } + public List getMembersSortedByHistory() { List> histList; - + lock.lock(); try { histList = new LinkedList<>(histMembers.entrySet()); } finally { lock.unlock(); } - - Collections.sort(histList, new Comparator>() - { - @Override - public int compare( Entry o1, Entry o2 ) - { - return ( o1.getValue() ).compareTo( o2.getValue() ); - } - }); - + + Collections.sort(histList, new Comparator>() { + @Override + public int compare(Entry o1, Entry o2) { + return (o1.getValue()).compareTo(o2.getValue()); + } + }); + List histSort = new LinkedList<>(); - for(Entry e : histList) { + for (Entry e : histList) { histSort.add(e.getKey()); } - + return histSort; } - + public byte getPartyDoor(int cid) { List histList = getMembersSortedByHistory(); byte slot = 0; - for(Integer e: histList) { - if(e == cid) break; + for (Integer e : histList) { + if (e == cid) { + break; + } slot++; } return slot; } - + public void addDoor(Integer owner, MapleDoor door) { lock.lock(); try { @@ -218,33 +227,33 @@ public class MapleParty { lock.unlock(); } } - + public void removeDoor(Integer owner) { - lock.lock(); + lock.lock(); try { this.doors.remove(owner); } finally { lock.unlock(); } } - + public Map getDoors() { - lock.lock(); + lock.lock(); try { return Collections.unmodifiableMap(doors); } finally { lock.unlock(); } } - + public void assignNewLeader(MapleClient c) { World world = c.getWorldServer(); MaplePartyCharacter newLeadr = null; - + lock.lock(); try { - for(MaplePartyCharacter mpc : members) { - if(mpc.getId() != leaderId && (newLeadr == null || newLeadr.getLevel() < mpc.getLevel())) { + for (MaplePartyCharacter mpc : members) { + if (mpc.getId() != leaderId && (newLeadr == null || newLeadr.getLevel() < mpc.getLevel())) { newLeadr = mpc; } } @@ -252,9 +261,11 @@ public class MapleParty { lock.unlock(); } - if(newLeadr != null) world.updateParty(this.getId(), PartyOperation.CHANGE_LEADER, newLeadr); + if (newLeadr != null) { + world.updateParty(this.getId(), PartyOperation.CHANGE_LEADER, newLeadr); + } } - + public void disposeLocks() { LockCollector.getInstance().registerDisposeAction(new Runnable() { @Override @@ -263,11 +274,11 @@ public class MapleParty { } }); } - + private void emptyLocks() { lock = lock.dispose(); } - + @Override public int hashCode() { final int prime = 31; @@ -276,6 +287,17 @@ public class MapleParty { return result; } + public MaplePartyCharacter getMemberByPos(int pos) { + int i = 0; + for (MaplePartyCharacter chr : members) { + if (pos == i) { + return chr; + } + i++; + } + return null; + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/net/server/world/MaplePartyCharacter.java b/src/net/server/world/MaplePartyCharacter.java index 70d4f50cab..d2c4096c51 100644 --- a/src/net/server/world/MaplePartyCharacter.java +++ b/src/net/server/world/MaplePartyCharacter.java @@ -141,4 +141,100 @@ public class MaplePartyCharacter { public int getWorld() { return world; } + + public String getJobNameById(int job) { + switch (job) { + case 0: + return "Aprendiz"; + case 100: + return "Guerreiro";// Warrior + case 110: + return "Soldado"; + case 111: + return "Templario"; + case 112: + return "Heroi"; + case 120: + return "Escudeiro"; + case 121: + return "Cavaleiro Branco"; + case 122: + return "Paladino"; + case 130: + return "Lanceiro"; + case 131: + return "Cavaleiro Draconiano"; + case 132: + return "Cavaleiro Negro"; + + case 200: + return "Bruxo"; + case 210: + return "Feiticeiro (Fogo, Veneno)"; + case 211: + return "Mago (Fogo, Veneno)"; + case 212: + return "Arquimago (Fogo, Veneno)"; + case 220: + return "Feiticeiro (Gelo, Raio)"; + case 221: + return "Mago (Gelo, Raio)"; + case 222: + return "Arquimago (Gelo, Raio)"; + case 230: + return "Clérigo"; + case 231: + return "Sacerdote"; + case 232: + return "Sumo Sacerdote"; + + case 300: + return "Arqueiro"; + case 310: + return "Caçador"; + case 311: + return "Rastreador"; + case 312: + return "Mestre Arqueiro"; + case 320: + return "Balestreiro"; + case 321: + return "Atirador"; + case 322: + return "Atirador De Elite"; + + case 400: + return "Gatuno"; + case 410: + return "Mercenario"; + case 411: + return "Andarilho"; + case 412: + return "Lorde Negro"; + case 420: + return "Arruaceiro"; + case 421: + return "Mestre Arruaceiro"; + case 422: + return "Mestre Das Sombras"; + + case 500: + return "Pirata"; + case 510: + return "Lutador"; + case 511: + return "Saqueador"; + case 512: + return "Foragido"; + case 520: + return "Pistoleiro"; + case 521: + return "Bucaneiro"; + case 522: + return "Captain"; + + default: + return "Unknown Job"; + } + } } diff --git a/src/scripting/AbstractPlayerInteraction.java b/src/scripting/AbstractPlayerInteraction.java index da8d4d6b31..83952bff2e 100644 --- a/src/scripting/AbstractPlayerInteraction.java +++ b/src/scripting/AbstractPlayerInteraction.java @@ -73,784 +73,792 @@ import tools.Pair; public class AbstractPlayerInteraction { - public MapleClient c; + public MapleClient c; - public AbstractPlayerInteraction(MapleClient c) { - this.c = c; - } - - public MapleClient getClient() { - return c; - } - - public MapleCharacter getPlayer() { - return c.getPlayer(); - } - - public MapleCharacter getChar() { - return c.getPlayer(); - } - - public MapleMap getMap() { - return c.getPlayer().getMap(); - } - - public static int getHourOfDay() { - return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); - } - - public int getMarketPortalId(int mapId) { - return getMarketPortalId(getWarpMap(mapId)); - } - - private static int getMarketPortalId(MapleMap map) { - return (map.findMarketPortal() != null) ? map.findMarketPortal().getId() : map.getRandomPlayerSpawnpoint().getId(); - } - - public void warp(int mapid) { - getPlayer().changeMap(mapid); - } - - public void warp(int map, int portal) { - getPlayer().changeMap(map, portal); - } - - public void warp(int map, String portal) { - getPlayer().changeMap(map, portal); - } - - public void warpMap(int map) { - getPlayer().getMap().warpEveryone(map); - } - - public void warpParty(int id) { - warpParty(id, 0); - } - - public void warpParty(int id, int portalId) { - int mapid = getMapId(); - warpParty(id, portalId, mapid, mapid); - } - - public void warpParty(int id, int fromMinId, int fromMaxId) { - warpParty(id, 0, fromMinId, fromMaxId); - } - - public void warpParty(int id, int portalId, int fromMinId, int fromMaxId) { - for (MapleCharacter mc : getPartyMembers()) { - if(mc.getMapId() >= fromMinId && mc.getMapId() <= fromMaxId) { - mc.changeMap(id, portalId); - } - } - } - - public List getPartyMembers() { - if (getPlayer().getParty() == null) { - return null; - } - List chars = new LinkedList<>(); - for (Channel channel : Server.getInstance().getChannelsFromWorld(getPlayer().getWorld())) { - for (MapleCharacter chr : channel.getPartyMembers(getPlayer().getParty())) { - if (chr != null) { - chars.add(chr); - } - } - } - return chars; - } - - public MapleMap getWarpMap(int map) { - return getPlayer().getWarpMap(map); - } - - public MapleMap getMap(int map) { - return getWarpMap(map); - } - - public int countAllMonstersOnMap(int map) { - return getMap(map).countMonsters(); - } - - public int countMonster() { - return getPlayer().getMap().countMonsters(); - } - - public void resetMapObjects(int mapid) { - getWarpMap(mapid).resetMapObjects(); - } - - public EventManager getEventManager(String event) { - return getClient().getEventManager(event); - } - - public EventInstanceManager getEventInstance() { - return getPlayer().getEventInstance(); - } - - public MapleInventory getInventory(int type) { - return getPlayer().getInventory(MapleInventoryType.getByType((byte) type)); - } - - public MapleInventory getInventory(MapleInventoryType type) { - return getPlayer().getInventory(type); - } - - public boolean hasItem(int itemid) { - return haveItem(itemid, 1); - } - - public boolean hasItem(int itemid, int quantity) { - return haveItem(itemid, quantity); - } - - public boolean haveItem(int itemid) { - return haveItem(itemid, 1); - } - - public boolean haveItem(int itemid, int quantity) { - return getPlayer().getItemQuantity(itemid, false) >= quantity; - } - - public int getItemQuantity(int itemid) { - return getPlayer().getItemQuantity(itemid, false); - } - - public boolean haveItemWithId(int itemid) { - return haveItemWithId(itemid, false); - } - - public boolean haveItemWithId(int itemid, boolean checkEquipped) { - return getPlayer().haveItemWithId(itemid, checkEquipped); - } - - public boolean canHold(int itemid) { - return canHold(itemid, 1); - } - - public boolean canHold(int itemid, int quantity) { - return canHoldAll(Collections.singletonList(itemid), Collections.singletonList(quantity), true); - } - - public boolean canHold(int itemid, int quantity, int removeItemid, int removeQuantity) { - return canHoldAllAfterRemoving(Collections.singletonList(itemid), Collections.singletonList(quantity), Collections.singletonList(removeItemid), Collections.singletonList(removeQuantity)); - } - - private static List convertToIntegerArray(List list) { - List intList = new LinkedList<>(); - for(Double d: list) intList.add(d.intValue()); - - return intList; - } - - public boolean canHoldAll(List itemids) { - List quantity = new LinkedList<>(); - for (int i = 0; i < itemids.size(); i++) { - quantity.add(1.0); - } - - return canHoldAll(itemids, quantity); - } - - public boolean canHoldAll(List itemids, List quantity) { - return canHoldAll(convertToIntegerArray(itemids), convertToIntegerArray(quantity), true); - } - - private boolean canHoldAll(List itemids, List quantity, boolean isInteger) { - int size = Math.min(itemids.size(), quantity.size()); - - List> addedItems = new LinkedList<>(); - for(int i = 0; i < size; i++) { - Item it = new Item(itemids.get(i), (short) 0, quantity.get(i).shortValue()); - addedItems.add(new Pair<>(it, ItemConstants.getInventoryType(itemids.get(i)))); - } - - return MapleInventory.checkSpots(c.getPlayer(), addedItems, false); - } - - private static List> prepareProofInventoryItems(List> items) { - List> addedItems = new LinkedList<>(); - for(Pair p : items) { - Item it = new Item(p.getLeft(), (short) 0, p.getRight().shortValue()); - addedItems.add(new Pair<>(it, MapleInventoryType.CANHOLD)); - } - - return addedItems; - } - - private static List>> prepareInventoryItemList(List itemids, List quantity) { - int size = Math.min(itemids.size(), quantity.size()); - - List>> invList = new ArrayList<>(6); - for(int i = MapleInventoryType.UNDEFINED.getType(); i < MapleInventoryType.CASH.getType(); i++) { - invList.add(new LinkedList>()); - } - - for(int i = 0; i < size; i++) { - int itemid = itemids.get(i); - invList.get(ItemConstants.getInventoryType(itemid).getType()).add(new Pair<>(itemid, quantity.get(i))); - } - - return invList; - } - - public boolean canHoldAllAfterRemoving(List toAddItemids, List toAddQuantity, List toRemoveItemids, List toRemoveQuantity) { - List>> toAddItemList = prepareInventoryItemList(toAddItemids, toAddQuantity); - List>> toRemoveItemList = prepareInventoryItemList(toRemoveItemids, toRemoveQuantity); - - MapleInventoryProof prfInv = (MapleInventoryProof) this.getInventory(MapleInventoryType.CANHOLD); - prfInv.lockInventory(); - try { - for(int i = MapleInventoryType.EQUIP.getType(); i < MapleInventoryType.CASH.getType(); i++) { - List> toAdd = toAddItemList.get(i); - - if(!toAdd.isEmpty()) { - List> toRemove = toRemoveItemList.get(i); - - MapleInventory inv = this.getInventory(i); - prfInv.cloneContents(inv); - - for(Pair p : toRemove) { - MapleInventoryManipulator.removeById(c, MapleInventoryType.CANHOLD, p.getLeft(), p.getRight(), false, false); - } - - List> addItems = prepareProofInventoryItems(toAdd); - - boolean canHold = MapleInventory.checkSpots(c.getPlayer(), addItems, true); - if(!canHold) { - return false; - } - } - } - } finally { - prfInv.flushContents(); - prfInv.unlockInventory(); - } - - return true; - } - - //---- \/ \/ \/ \/ \/ \/ \/ NOT TESTED \/ \/ \/ \/ \/ \/ \/ \/ \/ ---- - - public final MapleQuestStatus getQuestRecord(final int id) { - return c.getPlayer().getQuestNAdd(MapleQuest.getInstance(id)); - } - - public final MapleQuestStatus getQuestNoRecord(final int id) { - return c.getPlayer().getQuestNoAdd(MapleQuest.getInstance(id)); - } - - //---- /\ /\ /\ /\ /\ /\ /\ NOT TESTED /\ /\ /\ /\ /\ /\ /\ /\ /\ ---- - - public void openNpc(int npcid) { - openNpc(npcid, null); - } - - public void openNpc(int npcid, String script) { - if(c.getCM() != null) return; - - c.removeClickedNPC(); - NPCScriptManager.getInstance().dispose(c); - NPCScriptManager.getInstance().start(c, npcid, script, null); - } - - public void updateQuest(int questid, int data) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid)); - updateQuest(questid, status.getAnyProgressKey(), data); - } - - public void updateQuest(int questid, String data) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid)); - updateQuest(questid, status.getAnyProgressKey(), data); - } - - public void updateQuest(int questid, int pid, int data) { - updateQuest(questid, pid, String.valueOf(data)); - } - - public void updateQuest(int questid, int pid, String data) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid)); - status.setStatus(MapleQuestStatus.Status.STARTED); - status.setProgress(pid, data);//override old if exists - c.getPlayer().updateQuest(status); - } - - public int getQuestStatus(int id) { - return c.getPlayer().getQuest(MapleQuest.getInstance(id)).getStatus().getId(); - } - - private MapleQuestStatus.Status getQuestStat(int id) { - return c.getPlayer().getQuest(MapleQuest.getInstance(id)).getStatus(); - } - - public boolean isQuestCompleted(int quest) { - try { - return getQuestStat(quest) == MapleQuestStatus.Status.COMPLETED; - } catch (NullPointerException e) { - e.printStackTrace(); - return false; - } - } - - public boolean isQuestActive(int quest) { - return isQuestStarted(quest); - } - - public boolean isQuestStarted(int quest) { - try { - return getQuestStat(quest) == MapleQuestStatus.Status.STARTED; - } catch (NullPointerException e) { - e.printStackTrace(); - return false; - } - } - - public void setQuestProgress(int qid, int progress) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); - status.setProgress(status.getAnyProgressKey(), String.valueOf(progress)); - } - - public void setQuestProgress(int qid, int pid, int progress) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); - status.setProgress(pid, String.valueOf(progress)); - } - - public void setStringQuestProgress(int qid, int pid, String progress) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); - status.setProgress(pid, progress); - } - - public int getQuestProgress(int qid) { - MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); - String progress = status.getProgress(status.getAnyProgressKey()); - - if(progress.isEmpty()) return 0; - return Integer.parseInt(progress); - } - - public int getQuestProgress(int qid, int pid) { - if(getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid).isEmpty()) return 0; - return Integer.parseInt(getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid)); - } - - public String getStringQuestProgress(int qid, int pid) { - if(getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid).isEmpty()) return ""; - return getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid); - } - - public void resetAllQuestProgress(int qid) { - getPlayer().getQuest(MapleQuest.getInstance(qid)).resetAllProgress(); - getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false)); - } - - public void resetQuestProgress(int qid, int pid) { - getPlayer().getQuest(MapleQuest.getInstance(qid)).resetProgress(pid); - getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false)); - } - - public Item evolvePet(byte slot, int afterId) { - MaplePet evolved = null; - MaplePet target; - - long period = (long) 90 * 24 * 60 * 60 * 1000; //refreshes expiration date: 90 days - - target = getPlayer().getPet(slot); - if(target == null) { - getPlayer().message("Pet could not be evolved..."); - return(null); - } - - Item tmp = gainItem(afterId, (short) 1, false, true, period, target); - - /* - evolved = MaplePet.loadFromDb(tmp.getItemId(), tmp.getPosition(), tmp.getPetId()); - - evolved = tmp.getPet(); - if(evolved == null) { - getPlayer().message("Pet structure non-existent for " + tmp.getItemId() + "..."); - return(null); - } - else if(tmp.getPetId() == -1) { - getPlayer().message("Pet id -1"); - return(null); - } - - getPlayer().addPet(evolved); - - getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), evolved, false, false), true); - c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer())); - c.announce(MaplePacketCreator.enableActions()); - chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(evolved)); - */ - - MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.CASH, target.getPosition(), (short) 1, false); - - return evolved; - } - - public void gainItem(int id, short quantity) { - gainItem(id, quantity, false, true); - } - - public void gainItem(int id, short quantity, boolean show) {//this will fk randomStats equip :P - gainItem(id, quantity, false, show); - } - - public void gainItem(int id, boolean show) { - gainItem(id, (short) 1, false, show); - } - - public void gainItem(int id) { - gainItem(id, (short) 1, false, true); - } - - public Item gainItem(int id, short quantity, boolean randomStats, boolean showMessage) { - return gainItem(id, quantity, randomStats, showMessage, -1); - } - - public Item gainItem(int id, short quantity, boolean randomStats, boolean showMessage, long expires) { - return gainItem(id, quantity, randomStats, showMessage, expires, null); - } - - public Item gainItem(int id, short quantity, boolean randomStats, boolean showMessage, long expires, MaplePet from) { - Item item = null; - MaplePet evolved; - int petId = -1; - - if (quantity >= 0) { - if (ItemConstants.isPet(id)) { - petId = MaplePet.createPet(id); - - if(from != null) { - evolved = MaplePet.loadFromDb(id, (short) 0, petId); - - Point pos = getPlayer().getPosition(); - pos.y -= 12; - evolved.setPos(pos); - evolved.setFh(getPlayer().getMap().getFootholds().findBelow(evolved.getPos()).getId()); - evolved.setStance(0); - evolved.setSummoned(true); - - evolved.setName(from.getName().compareTo(MapleItemInformationProvider.getInstance().getName(from.getItemId())) != 0 ? from.getName() : MapleItemInformationProvider.getInstance().getName(id)); - evolved.setCloseness(from.getCloseness()); - evolved.setFullness(from.getFullness()); - evolved.setLevel(from.getLevel()); - evolved.setExpiration(System.currentTimeMillis() + expires); - evolved.saveToDb(); - } - - //MapleInventoryManipulator.addById(c, id, (short) 1, null, petId, expires == -1 ? -1 : System.currentTimeMillis() + expires); - } - - MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - - if (ItemConstants.getInventoryType(id).equals(MapleInventoryType.EQUIP)) { - item = ii.getEquipById(id); - - if(item != null) { - Equip it = (Equip)item; - if(ItemConstants.isAccessory(item.getItemId()) && it.getUpgradeSlots() <= 0) it.setUpgradeSlots(3); - - if(ServerConstants.USE_ENHANCED_CRAFTING == true && c.getPlayer().getCS() == true) { - Equip eqp = (Equip)item; - if(!(c.getPlayer().isGM() && ServerConstants.USE_PERFECT_GM_SCROLL)) { - eqp.setUpgradeSlots((byte)(eqp.getUpgradeSlots() + 1)); - } - item = MapleItemInformationProvider.getInstance().scrollEquipWithId(item, 2049100, true, 2049100, c.getPlayer().isGM()); - } - } - } else { - item = new Item(id, (short) 0, quantity, petId); - } - - if(expires >= 0) - item.setExpiration(System.currentTimeMillis() + expires); - - if (!MapleInventoryManipulator.checkSpace(c, id, quantity, "")) { - c.getPlayer().dropMessage(1, "Your inventory is full. Please remove an item from your " + ItemConstants.getInventoryType(id).name() + " inventory."); - return null; - } - if (ItemConstants.getInventoryType(id) == MapleInventoryType.EQUIP) { - if (randomStats) { - MapleInventoryManipulator.addFromDrop(c, ii.randomizeStats((Equip) item), false, petId); - } else { - MapleInventoryManipulator.addFromDrop(c, (Equip) item, false, petId); - } - } else { - MapleInventoryManipulator.addFromDrop(c, item, false, petId); - } - } else { - MapleInventoryManipulator.removeById(c, ItemConstants.getInventoryType(id), id, -quantity, true, false); - } - if (showMessage) { - c.announce(MaplePacketCreator.getShowItemGain(id, quantity, true)); - } - - return item; - } - - public void gainFame(int delta) { - getPlayer().gainFame(delta); - } - - public void changeMusic(String songName) { - getPlayer().getMap().broadcastMessage(MaplePacketCreator.musicChange(songName)); - } - - public void playerMessage(int type, String message) { - c.announce(MaplePacketCreator.serverNotice(type, message)); - } - - public void message(String message) { - getPlayer().message(message); - } - - public void mapMessage(int type, String message) { - getPlayer().getMap().broadcastMessage(MaplePacketCreator.serverNotice(type, message)); - } - - public void mapEffect(String path) { - c.announce(MaplePacketCreator.mapEffect(path)); - } - - public void mapSound(String path) { - c.announce(MaplePacketCreator.mapSound(path)); - } - - public void displayAranIntro() { - String intro = ""; - switch (c.getPlayer().getMapId()) { - case 914090010: - intro = "Effect/Direction1.img/aranTutorial/Scene0"; - break; - case 914090011: - intro = "Effect/Direction1.img/aranTutorial/Scene1" + (c.getPlayer().getGender() == 0 ? "0" : "1"); - break; - case 914090012: - intro = "Effect/Direction1.img/aranTutorial/Scene2" + (c.getPlayer().getGender() == 0 ? "0" : "1"); - break; - case 914090013: - intro = "Effect/Direction1.img/aranTutorial/Scene3"; - break; - case 914090100: - intro = "Effect/Direction1.img/aranTutorial/HandedPoleArm" + (c.getPlayer().getGender() == 0 ? "0" : "1"); - break; - case 914090200: - intro = "Effect/Direction1.img/aranTutorial/Maha"; - break; - } - showIntro(intro); - } - - - - public void showIntro(String path) { - c.announce(MaplePacketCreator.showIntro(path)); - } - - public void showInfo(String path) { - c.announce(MaplePacketCreator.showInfo(path)); - c.announce(MaplePacketCreator.enableActions()); - } - - public void guildMessage(int type, String message) { - if (getGuild() != null) { - getGuild().guildMessage(MaplePacketCreator.serverNotice(type, message)); - } - } - - public MapleGuild getGuild() { - try { - return Server.getInstance().getGuild(getPlayer().getGuildId(), getPlayer().getWorld(), null); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public MapleParty getParty() { - return getPlayer().getParty(); - } - - public boolean isLeader() { - return isPartyLeader(); - } - - public boolean isGuildLeader() { - return getPlayer().isGuildLeader(); - } - - public boolean isPartyLeader() { - if(getParty() == null) - return false; - - return getParty().getLeaderId() == getPlayer().getId(); - } - - public boolean isEventLeader() { - return getEventInstance() != null && getPlayer().getId() == getEventInstance().getLeaderId(); - } - - public void givePartyItems(int id, short quantity, List party) { - for (MapleCharacter chr : party) { - MapleClient cl = chr.getClient(); - if (quantity >= 0) { - MapleInventoryManipulator.addById(cl, id, quantity); - } else { - MapleInventoryManipulator.removeById(cl, ItemConstants.getInventoryType(id), id, -quantity, true, false); - } - cl.announce(MaplePacketCreator.getShowItemGain(id, quantity, true)); - } - } - - public void removeHPQItems() { - int[] items = {4001095, 4001096, 4001097, 4001098, 4001099, 4001100, 4001101}; - for (int i = 0; i < items.length; i ++) { - removePartyItems(items[i]); - } - } - - public void removePartyItems(int id) { - if (getParty() == null) { - removeAll(id); - return; - } - for (MaplePartyCharacter chr : getParty().getMembers()) { - if (chr != null && chr.isOnline() && chr.getPlayer().getClient() != null){ - removeAll(id, chr.getPlayer().getClient()); - } - } - } - - public void giveCharacterExp(int amount, MapleCharacter chr) { - chr.gainExp((amount * chr.getExpRate()), true, true); - } - - public void givePartyExp(int amount, List party) { - for (MapleCharacter chr : party) { - giveCharacterExp(amount, chr); - } - } - - public void givePartyExp(String PQ) { - givePartyExp(PQ, true); - } - - - public void givePartyExp(String PQ, boolean instance) { - //1 player = +0% bonus (100) - //2 players = +0% bonus (100) - //3 players = +0% bonus (100) - //4 players = +10% bonus (110) - //5 players = +20% bonus (120) - //6 players = +30% bonus (130) - MapleParty party = getPlayer().getParty(); - int size = party.getMembers().size(); - - if(instance) { - for(MaplePartyCharacter member: party.getMembers()) { - if(member == null || !member.isOnline() || member.getPlayer().getEventInstance() == null){ - size--; - } - } - } - - int bonus = size < 4 ? 100 : 70 + (size * 10); - for (MaplePartyCharacter member : party.getMembers()) { - if(member == null || !member.isOnline()){ - continue; - } - MapleCharacter player = member.getPlayer(); - if(instance && player.getEventInstance() == null){ - continue; // They aren't in the instance, don't give EXP. - } - int base = PartyQuest.getExp(PQ, player.getLevel()); - int exp = base * bonus / 100; - player.gainExp(exp, true, true); - if(ServerConstants.PQ_BONUS_EXP_RATE > 0 && System.currentTimeMillis() <= ServerConstants.EVENT_END_TIMESTAMP) { - player.gainExp((int) (exp * ServerConstants.PQ_BONUS_EXP_RATE), true, true); - } - } - } - - public void removeFromParty(int id, List party) { - for (MapleCharacter chr : party) { - MapleInventoryType type = ItemConstants.getInventoryType(id); - MapleInventory iv = chr.getInventory(type); - int possesed = iv.countById(id); - if (possesed > 0) { - MapleInventoryManipulator.removeById(c, ItemConstants.getInventoryType(id), id, possesed, true, false); - chr.announce(MaplePacketCreator.getShowItemGain(id, (short) -possesed, true)); - } - } - } - - public void removeAll(int id) { - removeAll(id, c); - } - - public void removeAll(int id, MapleClient cl) { - MapleInventoryType invType = ItemConstants.getInventoryType(id); - int possessed = cl.getPlayer().getInventory(invType).countById(id); - if (possessed > 0) { - MapleInventoryManipulator.removeById(cl, ItemConstants.getInventoryType(id), id, possessed, true, false); - cl.announce(MaplePacketCreator.getShowItemGain(id, (short) -possessed, true)); - } - - if(invType == MapleInventoryType.EQUIP) { - if(cl.getPlayer().getInventory(MapleInventoryType.EQUIPPED).countById(id) > 0) { - MapleInventoryManipulator.removeById(cl, MapleInventoryType.EQUIPPED, id, 1, true, false); - cl.announce(MaplePacketCreator.getShowItemGain(id, (short) -1, true)); - } - } - } - - public int getMapId() { - return c.getPlayer().getMap().getId(); - } - - public int getPlayerCount(int mapid) { - return c.getChannelServer().getMapFactory().getMap(mapid).getCharacters().size(); - } - - public void showInstruction(String msg, int width, int height) { - c.announce(MaplePacketCreator.sendHint(msg, width, height)); - c.announce(MaplePacketCreator.enableActions()); - } - - public void disableMinimap() { - c.announce(MaplePacketCreator.disableMinimap()); - } - - public boolean isAllReactorState(final int reactorId, final int state) { - return c.getPlayer().getMap().isAllReactorState(reactorId, state); - } - - public void resetMap(int mapid) { - getMap(mapid).resetReactors(); - getMap(mapid).killAllMonsters(); - for (MapleMapObject i : getMap(mapid).getMapObjectsInRange(c.getPlayer().getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.ITEM))) { - getMap(mapid).removeMapObject(i); - getMap(mapid).broadcastMessage(MaplePacketCreator.removeItemFromMap(i.getObjectId(), 0, c.getPlayer().getId())); - } - } - - public void useItem(int id) { - MapleItemInformationProvider.getInstance().getItemEffect(id).applyTo(c.getPlayer()); - c.announce(MaplePacketCreator.getItemMessage(id));//Useful shet :3 - } - - public void cancelItem(final int id) { - getPlayer().cancelEffect(MapleItemInformationProvider.getInstance().getItemEffect(id), false, -1); - } - - public void teachSkill(int skillid, byte level, byte masterLevel, long expiration) { - teachSkill(skillid, level, masterLevel, expiration, false); + public AbstractPlayerInteraction(MapleClient c) { + this.c = c; } - public void teachSkill(int skillid, byte level, byte masterLevel, long expiration, boolean force) { - Skill skill = SkillFactory.getSkill(skillid); - - if (!force && level > -1) { + public MapleClient getClient() { + return c; + } + + public MapleCharacter getPlayer() { + return c.getPlayer(); + } + + public MapleCharacter getChar() { + return c.getPlayer(); + } + + public MapleMap getMap() { + return c.getPlayer().getMap(); + } + + public static int getHourOfDay() { + return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + } + + public int getMarketPortalId(int mapId) { + return getMarketPortalId(getWarpMap(mapId)); + } + + private static int getMarketPortalId(MapleMap map) { + return (map.findMarketPortal() != null) ? map.findMarketPortal().getId() : map.getRandomPlayerSpawnpoint().getId(); + } + + public void warp(int mapid) { + getPlayer().changeMap(mapid); + } + + public void warp(int map, int portal) { + getPlayer().changeMap(map, portal); + } + + public void warp(int map, String portal) { + getPlayer().changeMap(map, portal); + } + + public void warpMap(int map) { + getPlayer().getMap().warpEveryone(map); + } + + public void warpParty(int id) { + warpParty(id, 0); + } + + public void warpParty(int id, int portalId) { + int mapid = getMapId(); + warpParty(id, portalId, mapid, mapid); + } + + public void warpParty(int id, int fromMinId, int fromMaxId) { + warpParty(id, 0, fromMinId, fromMaxId); + } + + public void warpParty(int id, int portalId, int fromMinId, int fromMaxId) { + for (MapleCharacter mc : getPartyMembers()) { + if (mc.getMapId() >= fromMinId && mc.getMapId() <= fromMaxId) { + mc.changeMap(id, portalId); + } + } + } + + public List getPartyMembers() { + if (getPlayer().getParty() == null) { + return null; + } + List chars = new LinkedList<>(); + for (Channel channel : Server.getInstance().getChannelsFromWorld(getPlayer().getWorld())) { + for (MapleCharacter chr : channel.getPartyMembers(getPlayer().getParty())) { + if (chr != null) { + chars.add(chr); + } + } + } + return chars; + } + + public MapleMap getWarpMap(int map) { + return getPlayer().getWarpMap(map); + } + + public MapleMap getMap(int map) { + return getWarpMap(map); + } + + public int countAllMonstersOnMap(int map) { + return getMap(map).countMonsters(); + } + + public int countMonster() { + return getPlayer().getMap().countMonsters(); + } + + public void resetMapObjects(int mapid) { + getWarpMap(mapid).resetMapObjects(); + } + + public EventManager getEventManager(String event) { + return getClient().getEventManager(event); + } + + public EventInstanceManager getEventInstance() { + return getPlayer().getEventInstance(); + } + + public MapleInventory getInventory(int type) { + return getPlayer().getInventory(MapleInventoryType.getByType((byte) type)); + } + + public MapleInventory getInventory(MapleInventoryType type) { + return getPlayer().getInventory(type); + } + + public boolean hasItem(int itemid) { + return haveItem(itemid, 1); + } + + public boolean hasItem(int itemid, int quantity) { + return haveItem(itemid, quantity); + } + + public boolean haveItem(int itemid) { + return haveItem(itemid, 1); + } + + public boolean haveItem(int itemid, int quantity) { + return getPlayer().getItemQuantity(itemid, false) >= quantity; + } + + public int getItemQuantity(int itemid) { + return getPlayer().getItemQuantity(itemid, false); + } + + public boolean haveItemWithId(int itemid) { + return haveItemWithId(itemid, false); + } + + public boolean haveItemWithId(int itemid, boolean checkEquipped) { + return getPlayer().haveItemWithId(itemid, checkEquipped); + } + + public boolean canHold(int itemid) { + return canHold(itemid, 1); + } + + public boolean canHold(int itemid, int quantity) { + return canHoldAll(Collections.singletonList(itemid), Collections.singletonList(quantity), true); + } + + public boolean canHold(int itemid, int quantity, int removeItemid, int removeQuantity) { + return canHoldAllAfterRemoving(Collections.singletonList(itemid), Collections.singletonList(quantity), Collections.singletonList(removeItemid), Collections.singletonList(removeQuantity)); + } + + private static List convertToIntegerArray(List list) { + List intList = new LinkedList<>(); + for (Double d : list) { + intList.add(d.intValue()); + } + + return intList; + } + + public boolean canHoldAll(List itemids) { + List quantity = new LinkedList<>(); + for (int i = 0; i < itemids.size(); i++) { + quantity.add(1.0); + } + + return canHoldAll(itemids, quantity); + } + + public boolean canHoldAll(List itemids, List quantity) { + return canHoldAll(convertToIntegerArray(itemids), convertToIntegerArray(quantity), true); + } + + private boolean canHoldAll(List itemids, List quantity, boolean isInteger) { + int size = Math.min(itemids.size(), quantity.size()); + + List> addedItems = new LinkedList<>(); + for (int i = 0; i < size; i++) { + Item it = new Item(itemids.get(i), (short) 0, quantity.get(i).shortValue()); + addedItems.add(new Pair<>(it, ItemConstants.getInventoryType(itemids.get(i)))); + } + + return MapleInventory.checkSpots(c.getPlayer(), addedItems, false); + } + + private static List> prepareProofInventoryItems(List> items) { + List> addedItems = new LinkedList<>(); + for (Pair p : items) { + Item it = new Item(p.getLeft(), (short) 0, p.getRight().shortValue()); + addedItems.add(new Pair<>(it, MapleInventoryType.CANHOLD)); + } + + return addedItems; + } + + private static List>> prepareInventoryItemList(List itemids, List quantity) { + int size = Math.min(itemids.size(), quantity.size()); + + List>> invList = new ArrayList<>(6); + for (int i = MapleInventoryType.UNDEFINED.getType(); i < MapleInventoryType.CASH.getType(); i++) { + invList.add(new LinkedList>()); + } + + for (int i = 0; i < size; i++) { + int itemid = itemids.get(i); + invList.get(ItemConstants.getInventoryType(itemid).getType()).add(new Pair<>(itemid, quantity.get(i))); + } + + return invList; + } + + public boolean canHoldAllAfterRemoving(List toAddItemids, List toAddQuantity, List toRemoveItemids, List toRemoveQuantity) { + List>> toAddItemList = prepareInventoryItemList(toAddItemids, toAddQuantity); + List>> toRemoveItemList = prepareInventoryItemList(toRemoveItemids, toRemoveQuantity); + + MapleInventoryProof prfInv = (MapleInventoryProof) this.getInventory(MapleInventoryType.CANHOLD); + prfInv.lockInventory(); + try { + for (int i = MapleInventoryType.EQUIP.getType(); i < MapleInventoryType.CASH.getType(); i++) { + List> toAdd = toAddItemList.get(i); + + if (!toAdd.isEmpty()) { + List> toRemove = toRemoveItemList.get(i); + + MapleInventory inv = this.getInventory(i); + prfInv.cloneContents(inv); + + for (Pair p : toRemove) { + MapleInventoryManipulator.removeById(c, MapleInventoryType.CANHOLD, p.getLeft(), p.getRight(), false, false); + } + + List> addItems = prepareProofInventoryItems(toAdd); + + boolean canHold = MapleInventory.checkSpots(c.getPlayer(), addItems, true); + if (!canHold) { + return false; + } + } + } + } finally { + prfInv.flushContents(); + prfInv.unlockInventory(); + } + + return true; + } + + //---- \/ \/ \/ \/ \/ \/ \/ NOT TESTED \/ \/ \/ \/ \/ \/ \/ \/ \/ ---- + public final MapleQuestStatus getQuestRecord(final int id) { + return c.getPlayer().getQuestNAdd(MapleQuest.getInstance(id)); + } + + public final MapleQuestStatus getQuestNoRecord(final int id) { + return c.getPlayer().getQuestNoAdd(MapleQuest.getInstance(id)); + } + + //---- /\ /\ /\ /\ /\ /\ /\ NOT TESTED /\ /\ /\ /\ /\ /\ /\ /\ /\ ---- + public void openNpc(int npcid) { + openNpc(npcid, null); + } + + public void openNpc(int npcid, String script) { + if (c.getCM() != null) { + return; + } + + c.removeClickedNPC(); + NPCScriptManager.getInstance().dispose(c); + NPCScriptManager.getInstance().start(c, npcid, script, null); + } + + public void updateQuest(int questid, int data) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid)); + updateQuest(questid, status.getAnyProgressKey(), data); + } + + public void updateQuest(int questid, String data) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid)); + updateQuest(questid, status.getAnyProgressKey(), data); + } + + public void updateQuest(int questid, int pid, int data) { + updateQuest(questid, pid, String.valueOf(data)); + } + + public void updateQuest(int questid, int pid, String data) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(questid)); + status.setStatus(MapleQuestStatus.Status.STARTED); + status.setProgress(pid, data);//override old if exists + c.getPlayer().updateQuest(status); + } + + public int getQuestStatus(int id) { + return c.getPlayer().getQuest(MapleQuest.getInstance(id)).getStatus().getId(); + } + + private MapleQuestStatus.Status getQuestStat(int id) { + return c.getPlayer().getQuest(MapleQuest.getInstance(id)).getStatus(); + } + + public boolean isQuestCompleted(int quest) { + try { + return getQuestStat(quest) == MapleQuestStatus.Status.COMPLETED; + } catch (NullPointerException e) { + e.printStackTrace(); + return false; + } + } + + public boolean isQuestActive(int quest) { + return isQuestStarted(quest); + } + + public boolean isQuestStarted(int quest) { + try { + return getQuestStat(quest) == MapleQuestStatus.Status.STARTED; + } catch (NullPointerException e) { + e.printStackTrace(); + return false; + } + } + + public void setQuestProgress(int qid, int progress) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); + status.setProgress(status.getAnyProgressKey(), String.valueOf(progress)); + } + + public void setQuestProgress(int qid, int pid, int progress) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); + status.setProgress(pid, String.valueOf(progress)); + } + + public void setStringQuestProgress(int qid, int pid, String progress) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); + status.setProgress(pid, progress); + } + + public int getQuestProgress(int qid) { + MapleQuestStatus status = c.getPlayer().getQuest(MapleQuest.getInstance(qid)); + String progress = status.getProgress(status.getAnyProgressKey()); + + if (progress.isEmpty()) { + return 0; + } + return Integer.parseInt(progress); + } + + public int getQuestProgress(int qid, int pid) { + if (getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid).isEmpty()) { + return 0; + } + return Integer.parseInt(getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid)); + } + + public String getStringQuestProgress(int qid, int pid) { + if (getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid).isEmpty()) { + return ""; + } + return getPlayer().getQuest(MapleQuest.getInstance(qid)).getProgress(pid); + } + + public void resetAllQuestProgress(int qid) { + getPlayer().getQuest(MapleQuest.getInstance(qid)).resetAllProgress(); + getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false)); + } + + public void resetQuestProgress(int qid, int pid) { + getPlayer().getQuest(MapleQuest.getInstance(qid)).resetProgress(pid); + getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false)); + } + + public Item evolvePet(byte slot, int afterId) { + MaplePet evolved = null; + MaplePet target; + + long period = (long) 90 * 24 * 60 * 60 * 1000; //refreshes expiration date: 90 days + + target = getPlayer().getPet(slot); + if (target == null) { + getPlayer().message("Pet could not be evolved..."); + return (null); + } + + Item tmp = gainItem(afterId, (short) 1, false, true, period, target); + + /* + evolved = MaplePet.loadFromDb(tmp.getItemId(), tmp.getPosition(), tmp.getPetId()); + + evolved = tmp.getPet(); + if(evolved == null) { + getPlayer().message("Pet structure non-existent for " + tmp.getItemId() + "..."); + return(null); + } + else if(tmp.getPetId() == -1) { + getPlayer().message("Pet id -1"); + return(null); + } + + getPlayer().addPet(evolved); + + getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), evolved, false, false), true); + c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer())); + c.announce(MaplePacketCreator.enableActions()); + chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(evolved)); + */ + MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.CASH, target.getPosition(), (short) 1, false); + + return evolved; + } + + public void gainItem(int id, short quantity) { + gainItem(id, quantity, false, true); + } + + public void gainItem(int id, short quantity, boolean show) {//this will fk randomStats equip :P + gainItem(id, quantity, false, show); + } + + public void gainItem(int id, boolean show) { + gainItem(id, (short) 1, false, show); + } + + public void gainItem(int id) { + gainItem(id, (short) 1, false, true); + } + + public Item gainItem(int id, short quantity, boolean randomStats, boolean showMessage) { + return gainItem(id, quantity, randomStats, showMessage, -1); + } + + public Item gainItem(int id, short quantity, boolean randomStats, boolean showMessage, long expires) { + return gainItem(id, quantity, randomStats, showMessage, expires, null); + } + + public Item gainItem(int id, short quantity, boolean randomStats, boolean showMessage, long expires, MaplePet from) { + Item item = null; + MaplePet evolved; + int petId = -1; + + if (quantity >= 0) { + if (ItemConstants.isPet(id)) { + petId = MaplePet.createPet(id); + + if (from != null) { + evolved = MaplePet.loadFromDb(id, (short) 0, petId); + + Point pos = getPlayer().getPosition(); + pos.y -= 12; + evolved.setPos(pos); + evolved.setFh(getPlayer().getMap().getFootholds().findBelow(evolved.getPos()).getId()); + evolved.setStance(0); + evolved.setSummoned(true); + + evolved.setName(from.getName().compareTo(MapleItemInformationProvider.getInstance().getName(from.getItemId())) != 0 ? from.getName() : MapleItemInformationProvider.getInstance().getName(id)); + evolved.setCloseness(from.getCloseness()); + evolved.setFullness(from.getFullness()); + evolved.setLevel(from.getLevel()); + evolved.setExpiration(System.currentTimeMillis() + expires); + evolved.saveToDb(); + } + + //MapleInventoryManipulator.addById(c, id, (short) 1, null, petId, expires == -1 ? -1 : System.currentTimeMillis() + expires); + } + + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + + if (ItemConstants.getInventoryType(id).equals(MapleInventoryType.EQUIP)) { + item = ii.getEquipById(id); + + if (item != null) { + Equip it = (Equip) item; + if (ItemConstants.isAccessory(item.getItemId()) && it.getUpgradeSlots() <= 0) { + it.setUpgradeSlots(3); + } + + if (ServerConstants.USE_ENHANCED_CRAFTING == true && c.getPlayer().getCS() == true) { + Equip eqp = (Equip) item; + if (!(c.getPlayer().isGM() && ServerConstants.USE_PERFECT_GM_SCROLL)) { + eqp.setUpgradeSlots((byte) (eqp.getUpgradeSlots() + 1)); + } + item = MapleItemInformationProvider.getInstance().scrollEquipWithId(item, 2049100, true, 2049100, c.getPlayer().isGM()); + } + } + } else { + item = new Item(id, (short) 0, quantity, petId); + } + + if (expires >= 0) { + item.setExpiration(System.currentTimeMillis() + expires); + } + + if (!MapleInventoryManipulator.checkSpace(c, id, quantity, "")) { + c.getPlayer().dropMessage(1, "Your inventory is full. Please remove an item from your " + ItemConstants.getInventoryType(id).name() + " inventory."); + return null; + } + if (ItemConstants.getInventoryType(id) == MapleInventoryType.EQUIP) { + if (randomStats) { + MapleInventoryManipulator.addFromDrop(c, ii.randomizeStats((Equip) item), false, petId); + } else { + MapleInventoryManipulator.addFromDrop(c, (Equip) item, false, petId); + } + } else { + MapleInventoryManipulator.addFromDrop(c, item, false, petId); + } + } else { + MapleInventoryManipulator.removeById(c, ItemConstants.getInventoryType(id), id, -quantity, true, false); + } + if (showMessage) { + c.announce(MaplePacketCreator.getShowItemGain(id, quantity, true)); + } + + return item; + } + + public void gainFame(int delta) { + getPlayer().gainFame(delta); + } + + public void changeMusic(String songName) { + getPlayer().getMap().broadcastMessage(MaplePacketCreator.musicChange(songName)); + } + + public void playerMessage(int type, String message) { + c.announce(MaplePacketCreator.serverNotice(type, message)); + } + + public void message(String message) { + getPlayer().message(message); + } + + public void mapMessage(int type, String message) { + getPlayer().getMap().broadcastMessage(MaplePacketCreator.serverNotice(type, message)); + } + + public void mapEffect(String path) { + c.announce(MaplePacketCreator.mapEffect(path)); + } + + public void mapSound(String path) { + c.announce(MaplePacketCreator.mapSound(path)); + } + + public void displayAranIntro() { + String intro = ""; + switch (c.getPlayer().getMapId()) { + case 914090010: + intro = "Effect/Direction1.img/aranTutorial/Scene0"; + break; + case 914090011: + intro = "Effect/Direction1.img/aranTutorial/Scene1" + (c.getPlayer().getGender() == 0 ? "0" : "1"); + break; + case 914090012: + intro = "Effect/Direction1.img/aranTutorial/Scene2" + (c.getPlayer().getGender() == 0 ? "0" : "1"); + break; + case 914090013: + intro = "Effect/Direction1.img/aranTutorial/Scene3"; + break; + case 914090100: + intro = "Effect/Direction1.img/aranTutorial/HandedPoleArm" + (c.getPlayer().getGender() == 0 ? "0" : "1"); + break; + case 914090200: + intro = "Effect/Direction1.img/aranTutorial/Maha"; + break; + } + showIntro(intro); + } + + public void showIntro(String path) { + c.announce(MaplePacketCreator.showIntro(path)); + } + + public void showInfo(String path) { + c.announce(MaplePacketCreator.showInfo(path)); + c.announce(MaplePacketCreator.enableActions()); + } + + public void guildMessage(int type, String message) { + if (getGuild() != null) { + getGuild().guildMessage(MaplePacketCreator.serverNotice(type, message)); + } + } + + public MapleGuild getGuild() { + try { + return Server.getInstance().getGuild(getPlayer().getGuildId(), getPlayer().getWorld(), null); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public MapleParty getParty() { + return getPlayer().getParty(); + } + + public boolean isLeader() { + return isPartyLeader(); + } + + public boolean isGuildLeader() { + return getPlayer().isGuildLeader(); + } + + public boolean isPartyLeader() { + if (getParty() == null) { + return false; + } + + return getParty().getLeaderId() == getPlayer().getId(); + } + + public boolean isEventLeader() { + return getEventInstance() != null && getPlayer().getId() == getEventInstance().getLeaderId(); + } + + public void givePartyItems(int id, short quantity, List party) { + for (MapleCharacter chr : party) { + MapleClient cl = chr.getClient(); + if (quantity >= 0) { + MapleInventoryManipulator.addById(cl, id, quantity); + } else { + MapleInventoryManipulator.removeById(cl, ItemConstants.getInventoryType(id), id, -quantity, true, false); + } + cl.announce(MaplePacketCreator.getShowItemGain(id, quantity, true)); + } + } + + public void removeHPQItems() { + int[] items = {4001095, 4001096, 4001097, 4001098, 4001099, 4001100, 4001101}; + for (int i = 0; i < items.length; i++) { + removePartyItems(items[i]); + } + } + + public void removePartyItems(int id) { + if (getParty() == null) { + removeAll(id); + return; + } + for (MaplePartyCharacter chr : getParty().getMembers()) { + if (chr != null && chr.isOnline() && chr.getPlayer().getClient() != null) { + removeAll(id, chr.getPlayer().getClient()); + } + } + } + + public void giveCharacterExp(int amount, MapleCharacter chr) { + chr.gainExp((amount * chr.getExpRate()), true, true); + } + + public void givePartyExp(int amount, List party) { + for (MapleCharacter chr : party) { + giveCharacterExp(amount, chr); + } + } + + public void givePartyExp(String PQ) { + givePartyExp(PQ, true); + } + + public void givePartyExp(String PQ, boolean instance) { + //1 player = +0% bonus (100) + //2 players = +0% bonus (100) + //3 players = +0% bonus (100) + //4 players = +10% bonus (110) + //5 players = +20% bonus (120) + //6 players = +30% bonus (130) + MapleParty party = getPlayer().getParty(); + int size = party.getMembers().size(); + + if (instance) { + for (MaplePartyCharacter member : party.getMembers()) { + if (member == null || !member.isOnline() || member.getPlayer().getEventInstance() == null) { + size--; + } + } + } + + int bonus = size < 4 ? 100 : 70 + (size * 10); + for (MaplePartyCharacter member : party.getMembers()) { + if (member == null || !member.isOnline()) { + continue; + } + MapleCharacter player = member.getPlayer(); + if (instance && player.getEventInstance() == null) { + continue; // They aren't in the instance, don't give EXP. + } + int base = PartyQuest.getExp(PQ, player.getLevel()); + int exp = base * bonus / 100; + player.gainExp(exp, true, true); + if (ServerConstants.PQ_BONUS_EXP_RATE > 0 && System.currentTimeMillis() <= ServerConstants.EVENT_END_TIMESTAMP) { + player.gainExp((int) (exp * ServerConstants.PQ_BONUS_EXP_RATE), true, true); + } + } + } + + public void removeFromParty(int id, List party) { + for (MapleCharacter chr : party) { + MapleInventoryType type = ItemConstants.getInventoryType(id); + MapleInventory iv = chr.getInventory(type); + int possesed = iv.countById(id); + if (possesed > 0) { + MapleInventoryManipulator.removeById(c, ItemConstants.getInventoryType(id), id, possesed, true, false); + chr.announce(MaplePacketCreator.getShowItemGain(id, (short) -possesed, true)); + } + } + } + + public void removeAll(int id) { + removeAll(id, c); + } + + public void removeAll(int id, MapleClient cl) { + MapleInventoryType invType = ItemConstants.getInventoryType(id); + int possessed = cl.getPlayer().getInventory(invType).countById(id); + if (possessed > 0) { + MapleInventoryManipulator.removeById(cl, ItemConstants.getInventoryType(id), id, possessed, true, false); + cl.announce(MaplePacketCreator.getShowItemGain(id, (short) -possessed, true)); + } + + if (invType == MapleInventoryType.EQUIP) { + if (cl.getPlayer().getInventory(MapleInventoryType.EQUIPPED).countById(id) > 0) { + MapleInventoryManipulator.removeById(cl, MapleInventoryType.EQUIPPED, id, 1, true, false); + cl.announce(MaplePacketCreator.getShowItemGain(id, (short) -1, true)); + } + } + } + + public int getMapId() { + return c.getPlayer().getMap().getId(); + } + + public int getPlayerCount(int mapid) { + return c.getChannelServer().getMapFactory().getMap(mapid).getCharacters().size(); + } + + public void showInstruction(String msg, int width, int height) { + c.announce(MaplePacketCreator.sendHint(msg, width, height)); + c.announce(MaplePacketCreator.enableActions()); + } + + public void disableMinimap() { + c.announce(MaplePacketCreator.disableMinimap()); + } + + public boolean isAllReactorState(final int reactorId, final int state) { + return c.getPlayer().getMap().isAllReactorState(reactorId, state); + } + + public void resetMap(int mapid) { + getMap(mapid).resetReactors(); + getMap(mapid).killAllMonsters(); + for (MapleMapObject i : getMap(mapid).getMapObjectsInRange(c.getPlayer().getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.ITEM))) { + getMap(mapid).removeMapObject(i); + getMap(mapid).broadcastMessage(MaplePacketCreator.removeItemFromMap(i.getObjectId(), 0, c.getPlayer().getId())); + } + } + + public void useItem(int id) { + MapleItemInformationProvider.getInstance().getItemEffect(id).applyTo(c.getPlayer()); + c.announce(MaplePacketCreator.getItemMessage(id));//Useful shet :3 + } + + public void cancelItem(final int id) { + getPlayer().cancelEffect(MapleItemInformationProvider.getInstance().getItemEffect(id), false, -1); + } + + public void teachSkill(int skillid, byte level, byte masterLevel, long expiration) { + teachSkill(skillid, level, masterLevel, expiration, false); + } + + public void teachSkill(int skillid, byte level, byte masterLevel, long expiration, boolean force) { + Skill skill = SkillFactory.getSkill(skillid); + + if (!force && level > -1) { MapleCharacter.SkillEntry skillEntry = getPlayer().getSkills().get(skill); if (skillEntry != null) { @@ -858,239 +866,239 @@ public class AbstractPlayerInteraction { return; } } - + getPlayer().changeSkillLevel(skill, level, masterLevel, expiration); - } + } - public void removeEquipFromSlot(short slot) { - Item tempItem = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(slot); - MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIPPED, slot, tempItem.getQuantity(), false, false); - } + public void removeEquipFromSlot(short slot) { + Item tempItem = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(slot); + MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIPPED, slot, tempItem.getQuantity(), false, false); + } - public void gainAndEquip(int itemid, short slot) { - final Item old = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(slot); - if (old != null) { - MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIPPED, slot, old.getQuantity(), false, false); - } - final Item newItem = MapleItemInformationProvider.getInstance().getEquipById(itemid); - newItem.setPosition(slot); - c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addItemFromDB(newItem); - c.announce(MaplePacketCreator.modifyInventory(false, Collections.singletonList(new ModifyInventory(0, newItem)))); - } - - public static void spawnNpc(int npcId, Point pos, MapleMap map) { - MapleNPC npc = MapleLifeFactory.getNPC(npcId); - if (npc != null) { - npc.setPosition(pos); - npc.setCy(pos.y); - npc.setRx0(pos.x + 50); - npc.setRx1(pos.x - 50); - npc.setFh(map.getFootholds().findBelow(pos).getId()); - map.addMapObject(npc); - map.broadcastMessage(MaplePacketCreator.spawnNPC(npc)); - } - } - - public void spawnMonster(int id, int x, int y) { - MapleMonster monster = MapleLifeFactory.getMonster(id); - monster.setPosition(new Point(x, y)); - getPlayer().getMap().spawnMonster(monster); - } - - public static MapleMonster getMonsterLifeFactory(int mid) { - return MapleLifeFactory.getMonster(mid); - } - - public static MobSkill getMobSkill(int skill, int level) { - return MobSkillFactory.getMobSkill(skill, level); - } - - public void spawnGuide() { - c.announce(MaplePacketCreator.spawnGuide(true)); - } - - public void removeGuide() { - c.announce(MaplePacketCreator.spawnGuide(false)); - } - - public void displayGuide(int num) { - c.announce(MaplePacketCreator.showInfo("UI/tutorial.img/" + num)); - } - - public void goDojoUp() { - c.announce(MaplePacketCreator.dojoWarpUp()); - } - - public void resetDojoEnergy() { - c.getPlayer().setDojoEnergy(0); - } - - public void resetPartyDojoEnergy() { - for(MapleCharacter pchr: c.getPlayer().getPartyMembersOnSameMap()) { - pchr.setDojoEnergy(0); + public void gainAndEquip(int itemid, short slot) { + final Item old = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(slot); + if (old != null) { + MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIPPED, slot, old.getQuantity(), false, false); + } + final Item newItem = MapleItemInformationProvider.getInstance().getEquipById(itemid); + newItem.setPosition(slot); + c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addItemFromDB(newItem); + c.announce(MaplePacketCreator.modifyInventory(false, Collections.singletonList(new ModifyInventory(0, newItem)))); + } + + public static void spawnNpc(int npcId, Point pos, MapleMap map) { + MapleNPC npc = MapleLifeFactory.getNPC(npcId); + if (npc != null) { + npc.setPosition(pos); + npc.setCy(pos.y); + npc.setRx0(pos.x + 50); + npc.setRx1(pos.x - 50); + npc.setFh(map.getFootholds().findBelow(pos).getId()); + map.addMapObject(npc); + map.broadcastMessage(MaplePacketCreator.spawnNPC(npc)); + } + } + + public void spawnMonster(int id, int x, int y) { + MapleMonster monster = MapleLifeFactory.getMonster(id); + monster.setPosition(new Point(x, y)); + getPlayer().getMap().spawnMonster(monster); + } + + public static MapleMonster getMonsterLifeFactory(int mid) { + return MapleLifeFactory.getMonster(mid); + } + + public static MobSkill getMobSkill(int skill, int level) { + return MobSkillFactory.getMobSkill(skill, level); + } + + public void spawnGuide() { + c.announce(MaplePacketCreator.spawnGuide(true)); + } + + public void removeGuide() { + c.announce(MaplePacketCreator.spawnGuide(false)); + } + + public void displayGuide(int num) { + c.announce(MaplePacketCreator.showInfo("UI/tutorial.img/" + num)); + } + + public void goDojoUp() { + c.announce(MaplePacketCreator.dojoWarpUp()); + } + + public void resetDojoEnergy() { + c.getPlayer().setDojoEnergy(0); + } + + public void resetPartyDojoEnergy() { + for (MapleCharacter pchr : c.getPlayer().getPartyMembersOnSameMap()) { + pchr.setDojoEnergy(0); + } + } + + public void enableActions() { + c.announce(MaplePacketCreator.enableActions()); + } + + public void showEffect(String effect) { + c.announce(MaplePacketCreator.showEffect(effect)); + } + + public void dojoEnergy() { + c.announce(MaplePacketCreator.getEnergy("energy", getPlayer().getDojoEnergy())); + } + + public void talkGuide(String message) { + c.announce(MaplePacketCreator.talkGuide(message)); + } + + public void guideHint(int hint) { + c.announce(MaplePacketCreator.guideHint(hint)); + } + + public void updateAreaInfo(Short area, String info) { + c.getPlayer().updateAreaInfo(area, info); + c.announce(MaplePacketCreator.enableActions());//idk, nexon does the same :P + } + + public boolean containsAreaInfo(short area, String info) { + return c.getPlayer().containsAreaInfo(area, info); + } + + public void earnTitle(String msg) { + c.announce(MaplePacketCreator.earnTitleMessage(msg)); + } + + public void showInfoText(String msg) { + c.announce(MaplePacketCreator.showInfoText(msg)); + } + + public void openUI(byte ui) { + c.announce(MaplePacketCreator.openUI(ui)); + } + + public void lockUI() { + c.announce(MaplePacketCreator.disableUI(true)); + c.announce(MaplePacketCreator.lockUI(true)); + } + + public void unlockUI() { + c.announce(MaplePacketCreator.disableUI(false)); + c.announce(MaplePacketCreator.lockUI(false)); + } + + public void playSound(String sound) { + getPlayer().getMap().broadcastMessage(MaplePacketCreator.environmentChange(sound, 4)); + } + + public void environmentChange(String env, int mode) { + getPlayer().getMap().broadcastMessage(MaplePacketCreator.environmentChange(env, mode)); + } + + public String numberWithCommas(int number) { + return GameConstants.numberWithCommas(number); + } + + public Pyramid getPyramid() { + return (Pyramid) getPlayer().getPartyQuest(); + } + + public void createExpedition(MapleExpeditionType type) { + MapleExpedition exped = new MapleExpedition(getPlayer(), type); + getPlayer().getClient().getChannelServer().getExpeditions().add(exped); + } + + public void endExpedition(MapleExpedition exped) { + exped.dispose(true); + getPlayer().getClient().getChannelServer().getExpeditions().remove(exped); + } + + public MapleExpedition getExpedition(MapleExpeditionType type) { + for (MapleExpedition exped : getPlayer().getClient().getChannelServer().getExpeditions()) { + if (exped.getType().equals(type)) { + return exped; + } + } + return null; + } + + public long getJailTimeLeft() { + return getPlayer().getJailExpirationTimeLeft(); + } + + public List getDriedPets() { + List list = new LinkedList<>(); + + long curTime = System.currentTimeMillis(); + for (Item it : getPlayer().getInventory(MapleInventoryType.CASH).list()) { + if (ItemConstants.isPet(it.getItemId()) && it.getExpiration() < curTime) { + MaplePet pet = it.getPet(); + if (pet != null) { + list.add(pet); } + } } - public void enableActions() { - c.announce(MaplePacketCreator.enableActions()); - } + return list; + } - public void showEffect(String effect){ - c.announce(MaplePacketCreator.showEffect(effect)); - } + public boolean startDungeonInstance(int dungeonid) { + return c.getChannelServer().addMiniDungeon(dungeonid); + } - public void dojoEnergy() { - c.announce(MaplePacketCreator.getEnergy("energy", getPlayer().getDojoEnergy())); - } - - public void talkGuide(String message) { - c.announce(MaplePacketCreator.talkGuide(message)); - } - - public void guideHint(int hint) { - c.announce(MaplePacketCreator.guideHint(hint)); - } - - public void updateAreaInfo(Short area, String info) { - c.getPlayer().updateAreaInfo(area, info); - c.announce(MaplePacketCreator.enableActions());//idk, nexon does the same :P - } - - public boolean containsAreaInfo(short area, String info) { - return c.getPlayer().containsAreaInfo(area, info); - } - - public void earnTitle(String msg) { - c.announce(MaplePacketCreator.earnTitleMessage(msg)); - } - - public void showInfoText(String msg) { - c.announce(MaplePacketCreator.showInfoText(msg)); - } - - public void openUI(byte ui) { - c.announce(MaplePacketCreator.openUI(ui)); - } - - public void lockUI() { - c.announce(MaplePacketCreator.disableUI(true)); - c.announce(MaplePacketCreator.lockUI(true)); - } - - public void unlockUI() { - c.announce(MaplePacketCreator.disableUI(false)); - c.announce(MaplePacketCreator.lockUI(false)); - } - - public void playSound(String sound) { - getPlayer().getMap().broadcastMessage(MaplePacketCreator.environmentChange(sound, 4)); - } - - public void environmentChange(String env, int mode) { - getPlayer().getMap().broadcastMessage(MaplePacketCreator.environmentChange(env, mode)); - } - - public String numberWithCommas(int number) { - return GameConstants.numberWithCommas(number); + public boolean canGetFirstJob(int jobType) { + if (ServerConstants.USE_AUTOASSIGN_STARTERS_AP) { + return true; } - public Pyramid getPyramid() { - return (Pyramid) getPlayer().getPartyQuest(); - } + MapleCharacter chr = this.getPlayer(); - public void createExpedition(MapleExpeditionType type) { - MapleExpedition exped = new MapleExpedition(getPlayer(), type); - getPlayer().getClient().getChannelServer().getExpeditions().add(exped); - } + switch (jobType) { + case 1: + return chr.getStr() >= 35; - public void endExpedition(MapleExpedition exped) { - exped.dispose(true); - getPlayer().getClient().getChannelServer().getExpeditions().remove(exped); - } + case 2: + return chr.getInt() >= 20; - public MapleExpedition getExpedition(MapleExpeditionType type) { - for (MapleExpedition exped : getPlayer().getClient().getChannelServer().getExpeditions()) { - if (exped.getType().equals(type)) { - return exped; - } - } - return null; - } - - public long getJailTimeLeft() { - return getPlayer().getJailExpirationTimeLeft(); + case 3: + case 4: + return chr.getDex() >= 25; + + case 5: + return chr.getDex() >= 20; + + default: + return true; } - - public List getDriedPets() { - List list = new LinkedList<>(); - - long curTime = System.currentTimeMillis(); - for(Item it : getPlayer().getInventory(MapleInventoryType.CASH).list()) { - if(ItemConstants.isPet(it.getItemId()) && it.getExpiration() < curTime) { - MaplePet pet = it.getPet(); - if (pet != null) { - list.add(pet); - } - } - } - - return list; - } - - public boolean startDungeonInstance(int dungeonid) { - return c.getChannelServer().addMiniDungeon(dungeonid); - } - - public boolean canGetFirstJob(int jobType) { - if (ServerConstants.USE_AUTOASSIGN_STARTERS_AP) { - return true; - } - - MapleCharacter chr = this.getPlayer(); - - switch(jobType) { - case 1: - return chr.getStr() >= 35; - - case 2: - return chr.getInt() >= 20; - - case 3: - case 4: - return chr.getDex() >= 25; - - case 5: - return chr.getDex() >= 20; - - default: - return true; - } - } - - public static String getFirstJobStatRequirement(int jobType) { - switch(jobType) { - case 1: - return "STR " + 35; - - case 2: - return "INT " + 20; - - case 3: - case 4: - return "DEX " + 25; - - case 5: - return "DEX " + 20; - } - - return null; - } - - public void npcTalk(int npcid, String message) { - c.announce(MaplePacketCreator.getNPCTalk(npcid, (byte) 0, message, "00 00", (byte) 0)); + } + + public static String getFirstJobStatRequirement(int jobType) { + switch (jobType) { + case 1: + return "STR " + 35; + + case 2: + return "INT " + 20; + + case 3: + case 4: + return "DEX " + 25; + + case 5: + return "DEX " + 20; } + return null; + } + + public void npcTalk(int npcid, String message) { + c.announce(MaplePacketCreator.getNPCTalk(npcid, (byte) 0, message, "00 00", (byte) 0)); + } + public long getCurrentTime() { - return System.currentTimeMillis(); - } + return System.currentTimeMillis(); + } } diff --git a/src/scripting/event/EventScriptManager.java b/src/scripting/event/EventScriptManager.java index 56c05d5f6a..2d7d16d905 100644 --- a/src/scripting/event/EventScriptManager.java +++ b/src/scripting/event/EventScriptManager.java @@ -1,24 +1,24 @@ /* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + 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 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. + 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 . -*/ + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ package scripting.event; import java.util.LinkedHashMap; @@ -38,8 +38,9 @@ import scripting.AbstractScriptManager; * @author Matze */ public class EventScriptManager extends AbstractScriptManager { - + private class EventEntry { + public EventEntry(Invocable iv, EventManager em) { this.iv = iv; this.em = em; @@ -78,10 +79,12 @@ public class EventScriptManager extends AbstractScriptManager { } } } - + private void reloadScripts() { - if (events.isEmpty()) return; - + if (events.isEmpty()) { + return; + } + Channel cserv = events.values().iterator().next().em.getChannelServer(); for (Entry entry : events.entrySet()) { String script = entry.getKey(); @@ -89,11 +92,11 @@ public class EventScriptManager extends AbstractScriptManager { events.put(script, new EventEntry(iv, new EventManager(cserv, iv, script))); } } - + public void reload() { - cancel(); + cancel(); reloadScripts(); - init(); + init(); } public void cancel() { @@ -101,4 +104,4 @@ public class EventScriptManager extends AbstractScriptManager { entry.em.cancel(); } } -} \ No newline at end of file +} diff --git a/src/scripting/event/worker/EventScriptScheduler.java b/src/scripting/event/worker/EventScriptScheduler.java index c762ae5b07..a9b1f4b421 100644 --- a/src/scripting/event/worker/EventScriptScheduler.java +++ b/src/scripting/event/worker/EventScriptScheduler.java @@ -1,22 +1,22 @@ /* - This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2016 - 2018 RonanLana + This file is part of the HeavenMS MapleStory Server + Copyleft (L) 2016 - 2018 RonanLana - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation version 3 as published by - the Free Software Foundation. You may not use, modify or distribute - this program under any other version of the GNU Affero General Public - License. + This program is 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. + 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 . -*/ + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ package scripting.event.worker; import constants.ServerConstants; @@ -39,63 +39,64 @@ import server.ThreadManager; * @author Ronan */ public class EventScriptScheduler { + private boolean disposed = false; private int idleProcs = 0; private Map registeredEntries = new HashMap<>(); - + private ScheduledFuture schedulerTask = null; private MonitoredReentrantLock schedulerLock; private Runnable monitorTask = new Runnable() { - @Override - public void run() { - runBaseSchedule(); - } - }; - + @Override + public void run() { + runBaseSchedule(); + } + }; + public EventScriptScheduler() { schedulerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_SCHDL, true); } - + private void runBaseSchedule() { List toRemove; Map registeredEntriesCopy; - + schedulerLock.lock(); try { - if(registeredEntries.isEmpty()) { + if (registeredEntries.isEmpty()) { idleProcs++; - - if(idleProcs >= ServerConstants.MOB_STATUS_MONITOR_LIFE) { - if(schedulerTask != null) { + + if (idleProcs >= ServerConstants.MOB_STATUS_MONITOR_LIFE) { + if (schedulerTask != null) { schedulerTask.cancel(false); schedulerTask = null; } } - + return; } - + idleProcs = 0; registeredEntriesCopy = new HashMap<>(registeredEntries); } finally { schedulerLock.unlock(); } - + long timeNow = Server.getInstance().getCurrentTime(); toRemove = new LinkedList<>(); - for(Entry rmd : registeredEntriesCopy.entrySet()) { - if(rmd.getValue() < timeNow) { + for (Entry rmd : registeredEntriesCopy.entrySet()) { + if (rmd.getValue() < timeNow) { Runnable r = rmd.getKey(); - + r.run(); // runs the scheduled action toRemove.add(r); } } - - if(!toRemove.isEmpty()) { + + if (!toRemove.isEmpty()) { schedulerLock.lock(); try { - for(Runnable r : toRemove) { + for (Runnable r : toRemove) { registeredEntries.remove(r); } } finally { @@ -103,17 +104,19 @@ public class EventScriptScheduler { } } } - + public void registerEntry(final Runnable scheduledAction, final long duration) { - + ThreadManager.getInstance().newTask(new Runnable() { @Override public void run() { schedulerLock.lock(); try { idleProcs = 0; - if(schedulerTask == null) { - if(disposed) return; + if (schedulerTask == null) { + if (disposed) { + return; + } schedulerTask = TimerManager.getInstance().register(monitorTask, ServerConstants.MOB_STATUS_MONITOR_PROC, ServerConstants.MOB_STATUS_MONITOR_PROC); } @@ -125,9 +128,9 @@ public class EventScriptScheduler { } }); } - + public void cancelEntry(final Runnable scheduledAction) { - + ThreadManager.getInstance().newTask(new Runnable() { @Override public void run() { @@ -140,15 +143,15 @@ public class EventScriptScheduler { } }); } - + public void dispose() { - + ThreadManager.getInstance().newTask(new Runnable() { @Override public void run() { schedulerLock.lock(); try { - if(schedulerTask != null) { + if (schedulerTask != null) { schedulerTask.cancel(false); schedulerTask = null; } @@ -163,7 +166,7 @@ public class EventScriptScheduler { } }); } - + private void disposeLocks() { LockCollector.getInstance().registerDisposeAction(new Runnable() { @Override @@ -172,7 +175,7 @@ public class EventScriptScheduler { } }); } - + private void emptyLocks() { schedulerLock = schedulerLock.dispose(); } diff --git a/src/scripting/item/ItemScriptMethods.java b/src/scripting/item/ItemScriptMethods.java new file mode 100644 index 0000000000..206a7105bc --- /dev/null +++ b/src/scripting/item/ItemScriptMethods.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 scripting.item; + +import client.MapleClient; +import scripting.AbstractPlayerInteraction; + +/** + * + * @author kevintjuh93 + */ +public class ItemScriptMethods extends AbstractPlayerInteraction { + public ItemScriptMethods(MapleClient c) { + super(c); + } +} diff --git a/src/scripting/npc/NPCConversationManager.java b/src/scripting/npc/NPCConversationManager.java index e5c7a41bf9..c2353f3e45 100644 --- a/src/scripting/npc/NPCConversationManager.java +++ b/src/scripting/npc/NPCConversationManager.java @@ -1,23 +1,23 @@ /* -This file is part of the OdinMS Maple Story Server -Copyright (C) 2008 Patrick Huy -Matthias Butz -Jan Christian Meyer + 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 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. + 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 . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ package scripting.npc; @@ -58,538 +58,924 @@ import client.inventory.Item; import client.inventory.ItemFactory; import client.inventory.MaplePet; import constants.ItemConstants; +import constants.LinguaConstants; import java.awt.Point; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import net.server.channel.Channel; +import scripting.event.EventInstanceManager; import server.MapleSkillbookInformationProvider; import server.MapleSkillbookInformationProvider.SkillBookEntry; +import server.TimerManager; import server.maps.MapleMapObject; import server.maps.MapleMapObjectType; +import server.partyquest.MonsterCarnival; +import tools.FilePrinter; +import tools.packets.Wedding; /** * * @author Matze */ public class NPCConversationManager extends AbstractPlayerInteraction { - private int npc; - private int npcOid; - private String scriptName; - private String getText; - private boolean itemScript; - - public NPCConversationManager(MapleClient c, int npc, String scriptName) { - this(c, npc, -1, scriptName, false); - } - - public NPCConversationManager(MapleClient c, int npc, int oid, String scriptName, boolean itemScript) { - super(c); - this.npc = npc; - this.npcOid = oid; - this.scriptName = scriptName; - this.itemScript = itemScript; - } - public int getNpc() { - return npc; - } - - public int getNpcObjectId() { - return npcOid; - } + private int npc; + private int npcOid; + private String scriptName; + private String getText; + private boolean itemScript; + private List otherParty; - public String getScriptName() { - return scriptName; - } - - public boolean isItemScript() { - return itemScript; + public NPCConversationManager(MapleClient c, int npc, String scriptName) { + this(c, npc, -1, scriptName, false); + } + + public NPCConversationManager(MapleClient c, int npc, List otherParty, boolean test) { + super(c); + this.c = c; + this.npc = npc; + this.otherParty = otherParty; + } + + public NPCConversationManager(MapleClient c, int npc, int oid, String scriptName, boolean itemScript) { + super(c); + this.npc = npc; + this.npcOid = oid; + this.scriptName = scriptName; + this.itemScript = itemScript; + } + + public int getNpc() { + return npc; + } + + public int getNpcObjectId() { + return npcOid; + } + + public String getScriptName() { + return scriptName; + } + + public boolean isItemScript() { + return itemScript; + } + + public void resetItemScript() { + this.itemScript = false; + } + + public void dispose() { + NPCScriptManager.getInstance().dispose(this); + getClient().announce(MaplePacketCreator.enableActions()); + } + + public void sendNext(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 01", (byte) 0)); + } + + public void sendPrev(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 00", (byte) 0)); + } + + public void sendNextPrev(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 01", (byte) 0)); + } + + public void sendOk(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 00", (byte) 0)); + } + + public void sendYesNo(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 1, text, "", (byte) 0)); + } + + public void sendAcceptDecline(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0x0C, text, "", (byte) 0)); + } + + public void sendSimple(String text) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 4, text, "", (byte) 0)); + } + + public void sendNext(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 01", speaker)); + } + + public void sendPrev(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 00", speaker)); + } + + public void sendNextPrev(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 01", speaker)); + } + + public void sendOk(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 00", speaker)); + } + + public void sendYesNo(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 1, text, "", speaker)); + } + + public void sendAcceptDecline(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0x0C, text, "", speaker)); + } + + public void sendSimple(String text, byte speaker) { + getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 4, text, "", speaker)); + } + + public void sendStyle(String text, int styles[]) { + getClient().announce(MaplePacketCreator.getNPCTalkStyle(npc, text, styles)); + } + + public void sendGetNumber(String text, int def, int min, int max) { + getClient().announce(MaplePacketCreator.getNPCTalkNum(npc, text, def, min, max)); + } + + public void sendGetText(String text) { + getClient().announce(MaplePacketCreator.getNPCTalkText(npc, text, "")); + } + + /* + * 0 = ariant colliseum + * 1 = Dojo + * 2 = Carnival 1 + * 3 = Carnival 2 + * 4 = Ghost Ship PQ? + * 5 = Pyramid PQ + * 6 = Kerning Subway + */ + public void sendDimensionalMirror(String text) { + getClient().announce(MaplePacketCreator.getDimensionalMirror(text)); + } + + public void setGetText(String text) { + this.getText = text; + } + + public String getText() { + return this.getText; + } + + public int getJobId() { + return getPlayer().getJob().getId(); + } + + public MapleJob getJob() { + return getPlayer().getJob(); + } + + public void startQuest(short id) { + try { + MapleQuest.getInstance(id).forceStart(getPlayer(), npc); + } catch (NullPointerException ex) { + ex.printStackTrace(); } - - public void resetItemScript() { - this.itemScript = false; + } + + public void completeQuest(short id) { + try { + MapleQuest.getInstance(id).forceComplete(getPlayer(), npc); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public boolean forceStartQuest(int id) { + return MapleQuest.getInstance(id).forceStart(getPlayer(), npc); + } + + public boolean forceCompleteQuest(int id) { + return MapleQuest.getInstance(id).forceComplete(getPlayer(), npc); + } + + public void startQuest(int id) { + try { + MapleQuest.getInstance(id).forceStart(getPlayer(), npc); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public void completeQuest(int id) { + try { + MapleQuest.getInstance(id).forceComplete(getPlayer(), npc); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public void startQuest(short id, int npcId) { + try { + MapleQuest.getInstance(id).forceStart(getPlayer(), npcId); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public void startQuest(int id, int npcId) { + try { + MapleQuest.getInstance(id).forceStart(getPlayer(), npcId); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public void completeQuest(short id, int npcId) { + try { + MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public void completeQuest(int id, int npcId) { + try { + MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId); + } catch (NullPointerException ex) { + ex.printStackTrace(); + } + } + + public int getMeso() { + return getPlayer().getMeso(); + } + + public void gainMeso(int gain) { + getPlayer().gainMeso(gain); + } + + public void gainExp(int gain) { + getPlayer().gainExp(gain, true, true); + } + + public int getLevel() { + return getPlayer().getLevel(); + } + + @Override + public void showEffect(String effect) { + getPlayer().getMap().broadcastMessage(MaplePacketCreator.environmentChange(effect, 3)); + } + + public void setHair(int hair) { + getPlayer().setHair(hair); + getPlayer().updateSingleStat(MapleStat.HAIR, hair); + getPlayer().equipChanged(); + } + + public void setFace(int face) { + getPlayer().setFace(face); + getPlayer().updateSingleStat(MapleStat.FACE, face); + getPlayer().equipChanged(); + } + + public void setSkin(int color) { + getPlayer().setSkinColor(MapleSkinColor.getById(color)); + getPlayer().updateSingleStat(MapleStat.SKIN, color); + getPlayer().equipChanged(); + } + + public int itemQuantity(int itemid) { + return getPlayer().getInventory(ItemConstants.getInventoryType(itemid)).countById(itemid); + } + + public void displayGuildRanks() { + MapleGuild.displayGuildRanks(getClient(), npc); + } + + public boolean canSpawnPlayerNpc(int mapid) { + MapleCharacter chr = getPlayer(); + return !ServerConstants.PLAYERNPC_AUTODEPLOY && chr.getLevel() >= chr.getMaxClassLevel() && !chr.isGM() && MaplePlayerNPC.canSpawnPlayerNpc(chr.getName(), mapid); + } + + public MaplePlayerNPC getPlayerNPCByScriptid(int scriptId) { + for (MapleMapObject pnpcObj : getPlayer().getMap().getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER_NPC))) { + MaplePlayerNPC pn = (MaplePlayerNPC) pnpcObj; + + if (pn.getScriptId() == scriptId) { + return pn; + } } - public void dispose() { - NPCScriptManager.getInstance().dispose(this); - getClient().announce(MaplePacketCreator.enableActions()); - } + return null; + } - public void sendNext(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 01", (byte) 0)); - } + @Override + public MapleParty getParty() { + return getPlayer().getParty(); + } - public void sendPrev(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 00", (byte) 0)); - } + @Override + public void resetMap(int mapid) { + getClient().getChannelServer().getMapFactory().getMap(mapid).resetReactors(); + } - public void sendNextPrev(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 01", (byte) 0)); - } + public void gainCloseness(int closeness) { + for (MaplePet pet : getPlayer().getPets()) { + if (pet != null) { + pet.gainClosenessFullness(getPlayer(), closeness, 0, 0); + } + } + } - public void sendOk(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 00", (byte) 0)); - } + public String getName() { + return getPlayer().getName(); + } - public void sendYesNo(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 1, text, "", (byte) 0)); - } + public int getGender() { + return getPlayer().getGender(); + } - public void sendAcceptDecline(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0x0C, text, "", (byte) 0)); - } + public void changeJobById(int a) { + getPlayer().changeJob(MapleJob.getById(a)); + } - public void sendSimple(String text) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 4, text, "", (byte) 0)); - } + public void changeJob(MapleJob job) { + getPlayer().changeJob(job); + } - public void sendNext(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 01", speaker)); - } + public MapleJob getJobName(int id) { + return MapleJob.getById(id); + } - public void sendPrev(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 00", speaker)); - } + public MapleStatEffect getItemEffect(int itemId) { + return MapleItemInformationProvider.getInstance().getItemEffect(itemId); + } - public void sendNextPrev(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "01 01", speaker)); - } + public void resetStats() { + getPlayer().resetStats(); + } - public void sendOk(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 00", speaker)); - } + public void openShopNPC(int id) { + MapleShopFactory.getInstance().getShop(id).sendShop(c); + } - public void sendYesNo(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 1, text, "", speaker)); - } + public void maxMastery() { + for (MapleData skill_ : MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/" + "String.wz")).getData("Skill.img").getChildren()) { + try { + Skill skill = SkillFactory.getSkill(Integer.parseInt(skill_.getName())); + getPlayer().changeSkillLevel(skill, (byte) 0, skill.getMaxLevel(), -1); + } catch (NumberFormatException nfe) { + nfe.printStackTrace(); + break; + } catch (NullPointerException npe) { + npe.printStackTrace(); + continue; + } + } + } - public void sendAcceptDecline(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0x0C, text, "", speaker)); - } + public void doGachapon() { + int[] maps = {100000000, 101000000, 102000000, 103000000, 105040300, 800000000, 809000101, 809000201, 600000000, 120000000}; - public void sendSimple(String text, byte speaker) { - getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 4, text, "", speaker)); - } + MapleGachaponItem item = MapleGachapon.getInstance().process(npc); - public void sendStyle(String text, int styles[]) { - getClient().announce(MaplePacketCreator.getNPCTalkStyle(npc, text, styles)); - } + Item itemGained = gainItem(item.getId(), (short) (item.getId() / 10000 == 200 ? 100 : 1), true, true); // For normal potions, make it give 100. - public void sendGetNumber(String text, int def, int min, int max) { - getClient().announce(MaplePacketCreator.getNPCTalkNum(npc, text, def, min, max)); - } + sendNext("You have obtained a #b#t" + item.getId() + "##k."); - public void sendGetText(String text) { - getClient().announce(MaplePacketCreator.getNPCTalkText(npc, text, "")); - } + String map = c.getChannelServer().getMapFactory().getMap(maps[(getNpc() != 9100117 && getNpc() != 9100109) ? (getNpc() - 9100100) : getNpc() == 9100109 ? 8 : 9]).getMapName(); - /* - * 0 = ariant colliseum - * 1 = Dojo - * 2 = Carnival 1 - * 3 = Carnival 2 - * 4 = Ghost Ship PQ? - * 5 = Pyramid PQ - * 6 = Kerning Subway - */ - public void sendDimensionalMirror(String text) { - getClient().announce(MaplePacketCreator.getDimensionalMirror(text)); - } + LogHelper.logGacha(getPlayer(), item.getId(), map); - public void setGetText(String text) { - this.getText = text; - } + if (item.getTier() > 0) { //Uncommon and Rare + Server.getInstance().broadcastMessage(c.getWorld(), MaplePacketCreator.gachaponMessage(itemGained, map, getPlayer())); + } + } - public String getText() { - return this.getText; - } + public void upgradeAlliance() { + MapleAlliance alliance = Server.getInstance().getAlliance(c.getPlayer().getGuild().getAllianceId()); + alliance.increaseCapacity(1); - public int getJobId() { - return getPlayer().getJob().getId(); - } + Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, c.getWorld()), -1, -1); + Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1); + } - public MapleJob getJob(){ - return getPlayer().getJob(); - } + public void disbandAlliance(MapleClient c, int allianceId) { + MapleAlliance.disbandAlliance(allianceId); + } - public void startQuest(short id) { - try { - MapleQuest.getInstance(id).forceStart(getPlayer(), npc); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } + public boolean canBeUsedAllianceName(String name) { + return MapleAlliance.canBeUsedAllianceName(name); + } - public void completeQuest(short id) { - try { - MapleQuest.getInstance(id).forceComplete(getPlayer(), npc); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } + public MapleAlliance createAlliance(String name) { + return MapleAlliance.createAlliance(getParty(), name); + } - public boolean forceStartQuest(int id) { - return MapleQuest.getInstance(id).forceStart(getPlayer(), npc); + public int getAllianceCapacity() { + return Server.getInstance().getAlliance(getPlayer().getGuild().getAllianceId()).getCapacity(); + } + + public boolean hasMerchant() { + return getPlayer().hasMerchant(); + } + + public boolean hasMerchantItems() { + try { + if (!ItemFactory.MERCHANT.loadItems(getPlayer().getId(), false).isEmpty()) { + return true; + } + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + if (getPlayer().getMerchantMeso() == 0) { + return false; + } else { + return true; + } + } + + public void showFredrick() { + c.announce(MaplePacketCreator.getFredrick(getPlayer())); + } + + public int partyMembersInMap() { + int inMap = 0; + for (MapleCharacter char2 : getPlayer().getMap().getCharacters()) { + if (char2.getParty() == getPlayer().getParty()) { + inMap++; + } + } + return inMap; + } + + public MapleEvent getEvent() { + return c.getChannelServer().getEvent(); + } + + public void divideTeams() { + if (getEvent() != null) { + getPlayer().setTeam(getEvent().getLimit() % 2); //muhaha :D + } + } + + public MapleCharacter getMapleCharacter(String player) { + MapleCharacter target = Server.getInstance().getWorld(c.getWorld()).getChannel(c.getChannel()).getPlayerStorage().getCharacterByName(player); + return target; + } + + public void logLeaf(String prize) { + LogHelper.logLeaf(getPlayer(), true, prize); + } + + public boolean createPyramid(String mode, boolean party) {//lol + PyramidMode mod = PyramidMode.valueOf(mode); + + MapleParty partyz = getPlayer().getParty(); + MapleMapFactory mf = c.getChannelServer().getMapFactory(); + + MapleMap map = null; + int mapid = 926010100; + if (party) { + mapid += 10000; + } + mapid += (mod.getMode() * 1000); + + for (byte b = 0; b < 5; b++) {//They cannot warp to the next map before the timer ends (: + map = mf.getMap(mapid + b); + if (map.getCharacters().size() > 0) { + continue; + } else { + break; + } } - public boolean forceCompleteQuest(int id) { - return MapleQuest.getInstance(id).forceComplete(getPlayer(), npc); - } - - public void startQuest(int id) { - try { - MapleQuest.getInstance(id).forceStart(getPlayer(), npc); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - - public void completeQuest(int id) { - try { - MapleQuest.getInstance(id).forceComplete(getPlayer(), npc); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - - public void startQuest(short id, int npcId) { - try { - MapleQuest.getInstance(id).forceStart(getPlayer(), npcId); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - - public void startQuest(int id, int npcId) { - try { - MapleQuest.getInstance(id).forceStart(getPlayer(), npcId); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - - public void completeQuest(short id, int npcId) { - try { - MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - - public void completeQuest(int id, int npcId) { - try { - MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId); - } catch (NullPointerException ex) { - ex.printStackTrace(); - } - } - - public int getMeso() { - return getPlayer().getMeso(); - } - - public void gainMeso(int gain) { - getPlayer().gainMeso(gain); - } - - public void gainExp(int gain) { - getPlayer().gainExp(gain, true, true); - } - - public int getLevel() { - return getPlayer().getLevel(); - } - - @Override - public void showEffect(String effect) { - getPlayer().getMap().broadcastMessage(MaplePacketCreator.environmentChange(effect, 3)); - } - - public void setHair(int hair) { - getPlayer().setHair(hair); - getPlayer().updateSingleStat(MapleStat.HAIR, hair); - getPlayer().equipChanged(); - } - - public void setFace(int face) { - getPlayer().setFace(face); - getPlayer().updateSingleStat(MapleStat.FACE, face); - getPlayer().equipChanged(); - } - - public void setSkin(int color) { - getPlayer().setSkinColor(MapleSkinColor.getById(color)); - getPlayer().updateSingleStat(MapleStat.SKIN, color); - getPlayer().equipChanged(); - } - - public int itemQuantity(int itemid) { - return getPlayer().getInventory(ItemConstants.getInventoryType(itemid)).countById(itemid); - } - - public void displayGuildRanks() { - MapleGuild.displayGuildRanks(getClient(), npc); - } - - public boolean canSpawnPlayerNpc(int mapid) { - MapleCharacter chr = getPlayer(); - return !ServerConstants.PLAYERNPC_AUTODEPLOY && chr.getLevel() >= chr.getMaxClassLevel() && !chr.isGM() && MaplePlayerNPC.canSpawnPlayerNpc(chr.getName(), mapid); - } - - public MaplePlayerNPC getPlayerNPCByScriptid(int scriptId) { - for(MapleMapObject pnpcObj : getPlayer().getMap().getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER_NPC))) { - MaplePlayerNPC pn = (MaplePlayerNPC) pnpcObj; - - if(pn.getScriptId() == scriptId) { - return pn; - } - } - - return null; + if (map == null) { + return false; } - @Override - public MapleParty getParty() { - return getPlayer().getParty(); - } + if (!party) { + partyz = new MapleParty(-1, new MaplePartyCharacter(getPlayer())); + } + Pyramid py = new Pyramid(partyz, mod, map.getId()); + getPlayer().setPartyQuest(py); + py.warp(mapid); + dispose(); + return true; + } - @Override - public void resetMap(int mapid) { - getClient().getChannelServer().getMapFactory().getMap(mapid).resetReactors(); - } + public boolean itemExists(int itemid) { + return MapleItemInformationProvider.getInstance().getName(itemid) != null; + } - public void gainCloseness(int closeness) { - for (MaplePet pet : getPlayer().getPets()) { - if(pet != null) { - pet.gainClosenessFullness(getPlayer(), closeness, 0, 0); - } - } - } - - public String getName() { - return getPlayer().getName(); - } - - public int getGender() { - return getPlayer().getGender(); - } - - public void changeJobById(int a) { - getPlayer().changeJob(MapleJob.getById(a)); - } - - public void changeJob(MapleJob job) { - getPlayer().changeJob(job); - } - - public MapleJob getJobName(int id) { - return MapleJob.getById(id); - } - - public MapleStatEffect getItemEffect(int itemId) { - return MapleItemInformationProvider.getInstance().getItemEffect(itemId); - } - - public void resetStats() { - getPlayer().resetStats(); - } - - public void openShopNPC(int id) { - MapleShopFactory.getInstance().getShop(id).sendShop(c); + public int getCosmeticItem(int itemid) { + if (itemExists(itemid)) { + return itemid; } - public void maxMastery() { - for (MapleData skill_ : MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/" + "String.wz")).getData("Skill.img").getChildren()) { - try { - Skill skill = SkillFactory.getSkill(Integer.parseInt(skill_.getName())); - getPlayer().changeSkillLevel(skill, (byte) 0, skill.getMaxLevel(), -1); - } catch (NumberFormatException nfe) { - nfe.printStackTrace(); - break; - } catch (NullPointerException npe) { - npe.printStackTrace(); - continue; - } - } - } - - public void doGachapon() { - int[] maps = {100000000, 101000000, 102000000, 103000000, 105040300, 800000000, 809000101, 809000201, 600000000, 120000000}; - - MapleGachaponItem item = MapleGachapon.getInstance().process(npc); - - Item itemGained = gainItem(item.getId(), (short) (item.getId() / 10000 == 200 ? 100 : 1), true, true); // For normal potions, make it give 100. - - sendNext("You have obtained a #b#t" + item.getId() + "##k."); - - String map = c.getChannelServer().getMapFactory().getMap(maps[(getNpc() != 9100117 && getNpc() != 9100109) ? (getNpc() - 9100100) : getNpc() == 9100109 ? 8 : 9]).getMapName(); - - LogHelper.logGacha(getPlayer(), item.getId(), map); - - if (item.getTier() > 0){ //Uncommon and Rare - Server.getInstance().broadcastMessage(c.getWorld(), MaplePacketCreator.gachaponMessage(itemGained, map, getPlayer())); - } - } - - public void upgradeAlliance() { - MapleAlliance alliance = Server.getInstance().getAlliance(c.getPlayer().getGuild().getAllianceId()); - alliance.increaseCapacity(1); - - Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, c.getWorld()), -1, -1); - Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1); + int baseid; + if (itemid < 30000) { + baseid = (itemid / 1000) * 1000 + (itemid % 100); + } else { + baseid = (itemid / 10) * 10; } - public void disbandAlliance(MapleClient c, int allianceId) { - MapleAlliance.disbandAlliance(allianceId); - } + return itemid != baseid && itemExists(baseid) ? baseid : -1; + } - public boolean canBeUsedAllianceName(String name) { - return MapleAlliance.canBeUsedAllianceName(name); - } - - public MapleAlliance createAlliance(String name) { - return MapleAlliance.createAlliance(getParty(), name); + private int getEquippedItemid(int itemid) { + if (itemid < 30000) { + return getPlayer().getFace(); + } else { + return getPlayer().getHair(); } - - public int getAllianceCapacity() { - return Server.getInstance().getAlliance(getPlayer().getGuild().getAllianceId()).getCapacity(); + } + + public boolean isCosmeticEquipped(int itemid) { + return getEquippedItemid(itemid) == itemid; + } + + public boolean isUsingOldPqNpcStyle() { + return ServerConstants.USE_OLD_GMS_STYLED_PQ_NPCS && this.getPlayer().getParty() != null; + } + + public Object[] getAvailableMasteryBooks() { + return MapleItemInformationProvider.getInstance().usableMasteryBooks(this.getPlayer()).toArray(); + } + + public Object[] getAvailableSkillBooks() { + return MapleItemInformationProvider.getInstance().usableSkillBooks(this.getPlayer()).toArray(); + } + + public Object[] getNamesWhoDropsItem(Integer itemId) { + return MapleItemInformationProvider.getInstance().getWhoDrops(itemId).toArray(); + } + + public String getSkillBookInfo(int itemid) { + SkillBookEntry sbe = MapleSkillbookInformationProvider.getInstance().getSkillbookAvailability(itemid); + return sbe != SkillBookEntry.UNAVAILABLE ? " Obtainable through #rquestline#k." : ""; + } + + + // By Drago/Dragohe4rt CPQ + WED + + public int calcAvgLvl(int map) { + int num = 0; + int avg = 0; + for (MapleMapObject mmo + : c.getChannelServer().getMapFactory().getMap(map).getAllPlayer()) { + avg += ((MapleCharacter) mmo).getLevel(); + num++; } + avg /= num; + return avg; + } - public boolean hasMerchant() { - return getPlayer().hasMerchant(); - } - - public boolean hasMerchantItems() { - try { - if (!ItemFactory.MERCHANT.loadItems(getPlayer().getId(), false).isEmpty()) { - return true; - } - } catch (SQLException e) { - e.printStackTrace(); - return false; - } - if (getPlayer().getMerchantMeso() == 0) { - return false; - } else { - return true; - } - } - - public void showFredrick() { - c.announce(MaplePacketCreator.getFredrick(getPlayer())); - } - - public int partyMembersInMap() { - int inMap = 0; - for (MapleCharacter char2 : getPlayer().getMap().getCharacters()) { - if (char2.getParty() == getPlayer().getParty()) { - inMap++; - } - } - return inMap; - } - - public MapleEvent getEvent() { - return c.getChannelServer().getEvent(); - } - - public void divideTeams() { - if (getEvent() != null) { - getPlayer().setTeam(getEvent().getLimit() % 2); //muhaha :D - } - } - - public MapleCharacter getMapleCharacter(String player) { - MapleCharacter target = Server.getInstance().getWorld(c.getWorld()).getChannel(c.getChannel()).getPlayerStorage().getCharacterByName(player); - return target; - } - - public void logLeaf(String prize) { - LogHelper.logLeaf(getPlayer(), true, prize); - } - - public boolean createPyramid(String mode, boolean party) {//lol - PyramidMode mod = PyramidMode.valueOf(mode); - - MapleParty partyz = getPlayer().getParty(); - MapleMapFactory mf = c.getChannelServer().getMapFactory(); - - MapleMap map = null; - int mapid = 926010100; - if (party) { - mapid += 10000; - } - mapid += (mod.getMode() * 1000); - - for (byte b = 0; b < 5; b++) {//They cannot warp to the next map before the timer ends (: - map = mf.getMap(mapid + b); - if (map.getCharacters().size() > 0) { - continue; - } else { - break; - } - } - - if (map == null) { - return false; - } - - if (!party) { - partyz = new MapleParty(-1, new MaplePartyCharacter(getPlayer())); - } - Pyramid py = new Pyramid(partyz, mod, map.getId()); - getPlayer().setPartyQuest(py); - py.warp(mapid); - dispose(); - return true; - } - - public boolean itemExists(int itemid) { - return MapleItemInformationProvider.getInstance().getName(itemid) != null; - } - - public int getCosmeticItem(int itemid) { - if (itemExists(itemid)) return itemid; - - int baseid; - if (itemid < 30000) { - baseid = (itemid / 1000) * 1000 + (itemid % 100); + public void sendCPQMapLists() { + String msg = LinguaConstants.Linguas(getPlayer()).CPQInicioEscolha; + for (int i = 0; i < 6; i++) { + if (fieldTaken(i)) { + if (fieldLobbied(i)) { + msg += "#b#L" + i + "#Map " + (i + 1) + " (nível: " + + calcAvgLvl(980000100 + i * 100) + " / " + + getPlayerCount(980000100 + i * 100) + "x" + + getPlayerCount(980000100 + i * 100) + ") #l\\r\\n"; } else { - baseid = (itemid / 10) * 10; + continue; } - - return itemid != baseid && itemExists(baseid) ? baseid : -1; - } - - private int getEquippedItemid(int itemid) { - if (itemid < 30000) { - return getPlayer().getFace(); + } else { + if (i == 0 || i == 1 || i == 2 || i == 3) { + msg += "#b#L" + i + "#Map " + (i + 1) + " (2x2) #l\\r\\n"; } else { - return getPlayer().getHair(); + msg += "#b#L" + i + "#Map " + (i + 1) + " (3x3) #l\\r\\n"; } + } } - - public boolean isCosmeticEquipped(int itemid) { - return getEquippedItemid(itemid) == itemid; + sendSimple(msg); + } + + public boolean fieldTaken(int field) { + if (!c.getChannelServer().getMapFactory().getMap(980000100 + field * 100).getAllPlayer().isEmpty()) { + return true; } - - public boolean isUsingOldPqNpcStyle() { - return ServerConstants.USE_OLD_GMS_STYLED_PQ_NPCS && this.getPlayer().getParty() != null; + if (!c.getChannelServer().getMapFactory().getMap(980000101 + field * 100).getAllPlayer().isEmpty()) { + return true; } - - public Object[] getAvailableMasteryBooks() { - return MapleItemInformationProvider.getInstance().usableMasteryBooks(this.getPlayer()).toArray(); + if (!c.getChannelServer().getMapFactory().getMap(980000102 + field * 100).getAllPlayer().isEmpty()) { + return true; } - - public Object[] getAvailableSkillBooks() { - return MapleItemInformationProvider.getInstance().usableSkillBooks(this.getPlayer()).toArray(); + return false; + } + + public boolean fieldLobbied(int field) { + if (!c.getChannelServer().getMapFactory().getMap(980000100 + field * 100).getAllPlayer().isEmpty()) { + return true; } - - public Object[] getNamesWhoDropsItem(Integer itemId) { - return MapleItemInformationProvider.getInstance().getWhoDrops(itemId).toArray(); + return false; + } + + public void cpqLobby(int field) { + try { + final MapleMap map, mapsaida; + Channel cs = c.getChannelServer(); + map = cs.getMapFactory().getMap(980000100 + 100 * field); + mapsaida = cs.getMapFactory().getMap(980000000); + for (MaplePartyCharacter mpc : c.getPlayer().getParty().getMembers()) { + final MapleCharacter mc; + mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.changeMap(map, map.getPortal(0)); + mc.getClient().getSession().write(MaplePacketCreator.serverNotice(6, LinguaConstants.Linguas(mc).CPQEntradaLobby)); + TimerManager tMan = TimerManager.getInstance(); + tMan.schedule(new Runnable() { + @Override + public void run() { + mapClock(3 * 60); + } + }, 1500); + } + mc.timer = TimerManager.getInstance().schedule(new Runnable() { + @Override + public void run() { + mc.changeMap(mapsaida, mapsaida.getPortal(0)); + } + }, 3 * 60 * 1000); + } + } catch (Exception ex) { + ex.printStackTrace(); } - - public String getSkillBookInfo(int itemid) { - SkillBookEntry sbe = MapleSkillbookInformationProvider.getInstance().getSkillbookAvailability(itemid); - return sbe != SkillBookEntry.UNAVAILABLE ? " Obtainable through #rquestline#k." : ""; + } + + public MapleCharacter getChrById(int id) { + Channel cs = c.getChannelServer(); + return cs.getPlayerStorage().getCharacterById(id); + } + + public void cancelarSaida() { + Channel cs = c.getChannelServer(); + for (MaplePartyCharacter mpc : c.getPlayer().getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc.timer != null) { + mc.timer.cancel(true); + mc.timer = null; + } } - + } + + public void startCPQ(final MapleCharacter challenger, int field) { + try { + cancelarSaida(); + if (challenger != null) { + if (challenger.getParty() == null) { + throw new RuntimeException("Não existe oponente!"); + } + for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { + MapleCharacter mc = c.getChannelServer().getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.changeMap(getPlayer().getMap(), getPlayer().getMap().getPortal(0)); + TimerManager tMan = TimerManager.getInstance(); + tMan.schedule(new Runnable() { + @Override + public void run() { + mapClock(10); + } + }, 1500); + } + } + for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { + MapleCharacter mc = c.getChannelServer().getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + TimerManager tMan = TimerManager.getInstance(); + tMan.schedule(new Runnable() { + @Override + public void run() { + mapClock(10); + } + }, 1500); + } + } + } + final int mapid = c.getPlayer().getMapId() + 1; + TimerManager tMan = TimerManager.getInstance(); + tMan.schedule(new Runnable() { + @Override + public void run() { + Channel cs = c.getChannelServer(); + for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + mc.setMonsterCarnival(null); + } + for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + mc.setMonsterCarnival(null); + } + new MonsterCarnival(getPlayer().getParty(), challenger.getParty(), mapid, true); + } + }, 11000); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void startCPQ2(final MapleCharacter challenger, int field) { + try { + cancelarSaida(); + if (challenger != null) { + if (challenger.getParty() == null) { + throw new RuntimeException("Não existe oponente!"); + } + for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { + MapleCharacter mc = c.getChannelServer().getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.changeMap(getPlayer().getMap(), getPlayer().getMap().getPortal(0)); + mapClock(10); + } + } + } + final int mapid = c.getPlayer().getMapId() + 100; + TimerManager tMan = TimerManager.getInstance(); + tMan.schedule(new Runnable() { + @Override + public void run() { + Channel cs = c.getChannelServer(); + for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + mc.setMonsterCarnival(null); + } + for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + mc.setMonsterCarnival(null); + } + new MonsterCarnival(getPlayer().getParty(), challenger.getParty(), mapid, false); + } + }, 10000); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void sendCPQMapLists2() { + String msg = LinguaConstants.Linguas(getPlayer()).CPQInicioEscolha; + for (int i = 0; i < 3; i++) { + if (fieldTaken2(i)) { + if (fieldLobbied2(i)) { + msg += "#b#L" + i + "#Map " + (i + 1) + " (Nível: " + + calcAvgLvl(980031000 + i * 1000) + "#l\\r\\n"; + } else { + continue; + } + } else { + if (i == 0 || i == 1) { + msg += "#b#L" + i + "#Map " + (i + 1) + " (2x2) #l\\r\\n"; + } else { + msg += "#b#L" + i + "#Map " + (i + 1) + " (3x3) #l\\r\\n"; + } + } + } + sendSimple(msg); + } + + public boolean fieldTaken2(int field) { + if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { + return true; + } + if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { + return true; + } + if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { + return true; + } + return false; + } + + public boolean fieldLobbied2(int field) { + if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { + return true; + } + return false; + } + + public void cpqLobby2(int field) { + try { + final MapleMap map, mapsaida; + Channel cs = c.getChannelServer(); + mapsaida = cs.getMapFactory().getMap(980030000); + map = cs.getMapFactory().getMap(980031000 + 1000 * field); + for (MaplePartyCharacter mpc : c.getPlayer().getParty().getMembers()) { + final MapleCharacter mc; + mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.changeMap(map, map.getPortal(0)); + mc.getClient().getSession().write(MaplePacketCreator.serverNotice(6, LinguaConstants.Linguas(mc).CPQEntradaLobby)); + TimerManager tMan = TimerManager.getInstance(); + tMan.schedule(new Runnable() { + @Override + public void run() { + mapClock(3 * 60); + } + }, 1500); + } + mc.timer = TimerManager.getInstance().schedule(new Runnable() { + @Override + public void run() { + mc.changeMap(mapsaida, mapsaida.getPortal(0)); + } + }, 3 * 60 * 1000); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public void challengeParty2(int field) { + MapleCharacter leader = null; + MapleMap map = c.getChannelServer().getMapFactory().getMap(980031000 + 1000 * field); + for (MapleMapObject mmo : map.getAllPlayer()) { + MapleCharacter mc = (MapleCharacter) mmo; + if (mc.getParty() == null) { + sendOk(LinguaConstants.Linguas(mc).CPQEscolha); + return; + } + if (mc.getParty().getLeader().getId() == mc.getId()) { + leader = mc; + break; + } + } + if (leader != null) { + if (!leader.isChallenged()) { + List members = new LinkedList<>(); + for (MaplePartyCharacter fucker : c.getPlayer().getParty().getMembers()) { + members.add(fucker); + } + NPCScriptManager.getInstance().start("cpqchallenge2", leader.getClient(), npc, members); + } else { + sendOk(LinguaConstants.Linguas(leader).CPQInicioEscolhaEmEscolha); + } + } else { + sendOk(LinguaConstants.Linguas(leader).CPQLiderNaoEncontrado); + } + } + + public void mapClock(int time) { + //getPlayer().getMap().broadcastMessage(MaplePacketCreator.serverNotice(type, message)); + getPlayer().getMap().broadcastMessage(MaplePacketCreator.getClock(time)); + } + + public void challengeParty(int field) { + MapleCharacter leader = null; + MapleMap map = c.getChannelServer().getMapFactory().getMap(980000100 + 100 * field); + if (map.getAllPlayer().size() != getPlayer().getParty().getMembers().size()) { + sendOk("erro"); + return; + } + for (MapleMapObject mmo : map.getAllPlayer()) { + MapleCharacter mc = (MapleCharacter) mmo; + if (mc.getParty() == null) { + sendOk(LinguaConstants.Linguas(mc).CPQEscolha); + return; + } + if (mc.getParty().getLeader().getId() == mc.getId()) { + leader = mc; + break; + } + } + if (leader != null) { + if (!leader.isChallenged()) { + List members = new LinkedList<>(); + for (MaplePartyCharacter fucker : c.getPlayer().getParty().getMembers()) { + members.add(fucker); + } + NPCScriptManager.getInstance().start("cpqchallenge", leader.getClient(), npc, members); + } else { + sendOk(LinguaConstants.Linguas(leader).CPQInicioEscolhaEmEscolha); + } + } else { + sendOk(LinguaConstants.Linguas(leader).CPQLiderNaoEncontrado); + } + } + + public MapleCharacter getCharByName(String namee) { + try { + return getClient().getChannelServer().getPlayerStorage().getCharacterByName(namee); + } catch (Exception e) { + return null; + } + } + + public void enviarLista() { + EventInstanceManager eim = getEventInstance(); + if(eim != null) { + String name = eim.getProperty("brideId"); + MapleCharacter chr = getChrById(Integer.parseInt(name)); + //MapleCharacter chr = getChrById(3); + if (chr != null) { + if (chr.getId() == getPlayer().getId()) { + getPlayer().announce(Wedding.OnWeddingGiftResult((byte) 0xA, chr.getItens(), chr.getItem())); + } else { + getPlayer().announce(Wedding.OnWeddingGiftResult((byte) 0x09, chr.getItens(), chr.getItem())); + } + } + } + } + + public void criarLista() { + getClient().getSession().write(Wedding.sendWishList()); + } + } diff --git a/src/scripting/npc/NPCScriptManager.java b/src/scripting/npc/NPCScriptManager.java index 120ec9ec6f..ecda65e399 100644 --- a/src/scripting/npc/NPCScriptManager.java +++ b/src/scripting/npc/NPCScriptManager.java @@ -26,10 +26,12 @@ import client.MapleClient; import java.lang.reflect.UndeclaredThrowableException; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.script.Invocable; import javax.script.ScriptException; +import net.server.world.MaplePartyCharacter; import scripting.AbstractScriptManager; import server.MapleItemInformationProvider.ScriptedItem; @@ -43,43 +45,86 @@ import tools.MaplePacketCreator; public class NPCScriptManager extends AbstractScriptManager { private static NPCScriptManager instance = new NPCScriptManager(); - + public static NPCScriptManager getInstance() { return instance; } - + private Map cms = new HashMap<>(); private Map scripts = new HashMap<>(); - + public boolean isNpcScriptAvailable(MapleClient c, String fileName) { Invocable iv = null; if (fileName != null) { iv = getInvocable("npc/" + fileName + ".js", c); } - + return iv != null; } - + public boolean start(MapleClient c, int npc, MapleCharacter chr) { return start(c, npc, -1, chr); } - + public boolean start(MapleClient c, int npc, int oid, MapleCharacter chr) { return start(c, npc, oid, null, chr); } - + public boolean start(MapleClient c, int npc, String fileName, MapleCharacter chr) { return start(c, npc, -1, fileName, chr); } - + public boolean start(MapleClient c, int npc, int oid, String fileName, MapleCharacter chr) { return start(c, npc, oid, fileName, chr, false, "cm"); } - + public boolean start(MapleClient c, ScriptedItem scriptItem, MapleCharacter chr) { return start(c, scriptItem.getNpc(), -1, scriptItem.getScript(), chr, true, "im"); } + public void start(String filename, MapleClient c, int npc, List chrs) { + try { + NPCConversationManager cm = new NPCConversationManager(c, npc, chrs, true); + cm.dispose(); + if (cms.containsKey(c)) { + return; + } + cms.put(c, cm); + Invocable iv = null; + iv = getInvocable("npc/" + filename + ".js", c); + NPCScriptManager npcsm = NPCScriptManager.getInstance(); + + if (iv == null || NPCScriptManager.getInstance() == null) { + c.getPlayer().dropMessage(1, npc + ""); + cm.dispose(); + return; + } + if (iv == null || npcsm == null) { + c.getPlayer().dropMessage(1, npc + ""); + cm.dispose(); + return; + } + engine.put("cm", cm); + scripts.put(c, iv); + try { + iv.invokeFunction("start", chrs); + } catch (final NoSuchMethodException nsme) { + try { + iv.invokeFunction("start", chrs); + } catch (final NoSuchMethodException nsma) { + nsma.printStackTrace(); + } + } + + } catch (final UndeclaredThrowableException ute) { + FilePrinter.printError(FilePrinter.NPC + npc + ".txt", ute); + dispose(c); + } catch (final Exception e) { + FilePrinter.printError(FilePrinter.NPC + npc + ".txt", e); + dispose(c); + } + } + private boolean start(MapleClient c, int npc, int oid, String fileName, MapleCharacter chr, boolean itemScript, String engineName) { try { NPCConversationManager cm = new NPCConversationManager(c, npc, oid, fileName, itemScript); @@ -121,17 +166,17 @@ public class NPCScriptManager extends AbstractScriptManager { } else { c.announce(MaplePacketCreator.enableActions()); } - + return true; } catch (final UndeclaredThrowableException | ScriptException ute) { FilePrinter.printError(FilePrinter.NPC + npc + ".txt", ute); dispose(c); - + return false; } catch (final Exception e) { FilePrinter.printError(FilePrinter.NPC + npc + ".txt", e); dispose(c); - + return false; } } @@ -157,9 +202,9 @@ public class NPCScriptManager extends AbstractScriptManager { c.getPlayer().setNpcCooldown(System.currentTimeMillis()); cms.remove(c); scripts.remove(c); - + String scriptFolder = (cm.isItemScript() ? "item" : "npc"); - if(cm.getScriptName() != null) { + if (cm.getScriptName() != null) { resetContext(scriptFolder + "/" + cm.getScriptName() + ".js", c); } else { resetContext(scriptFolder + "/" + cm.getNpc() + ".js", c); diff --git a/src/scripting/reactor/ReactorActionManager.java b/src/scripting/reactor/ReactorActionManager.java index 9dcc75aa4f..267282c7d9 100644 --- a/src/scripting/reactor/ReactorActionManager.java +++ b/src/scripting/reactor/ReactorActionManager.java @@ -47,6 +47,8 @@ import server.maps.MapMonitor; import server.maps.MapleMap; import server.maps.MapleReactor; import server.maps.ReactorDropEntry; +import server.partyquest.MapleCarnivalFactory; +import server.partyquest.MapleCarnivalFactory.MCSkill; import tools.MaplePacketCreator; /** @@ -311,4 +313,20 @@ public class ReactorActionManager extends AbstractPlayerInteraction { } }, timestamp); } + + public void dispelAllMonsters(int num, int team) { //dispels all mobs, cpq + final MCSkill skil = MapleCarnivalFactory.getInstance().getGuardian(num); + if (skil != null) { + for (MapleMonster mons : getMap().getMonsters()) { + if(mons.getTeam() == team) { + mons.dispelSkill(skil.getSkill()); + } + } + } + if (team == 0) { + getPlayer().getMap().getRedTeamBuffs().remove(skil); + } else { + getPlayer().getMap().getBlueTeamBuffs().remove(skil); + } + } } \ No newline at end of file diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 9df69bcf91..be3e956bbd 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -50,7 +50,6 @@ import client.MapleCharacter; import client.MapleDisease; import client.MapleJob; import client.MapleMount; -import client.MapleStat; import client.Skill; import client.SkillFactory; import client.inventory.Item; @@ -111,6 +110,10 @@ import constants.skills.SuperGM; import constants.skills.ThunderBreaker; import constants.skills.WhiteKnight; import constants.skills.WindArcher; +import net.server.world.MapleParty; +import net.server.world.MaplePartyCharacter; +import server.partyquest.MapleCarnivalFactory; +import server.partyquest.MapleCarnivalFactory.MCSkill; /** * @author Matze @@ -129,6 +132,8 @@ public class MapleStatEffect { private boolean overTime, repeatEffect; private int sourceid; private int moveTo; + private int cp, nuffSkill; + private List cureDebuffs; private boolean skill; private List> statups; private Map monsterStatus; @@ -155,17 +160,15 @@ public class MapleStatEffect { } private static byte mapProtection(int sourceid) { - if(sourceid == 2022001 || sourceid == 2022186) { + if (sourceid == 2022001 || sourceid == 2022186) { return 1; //elnath cold - } - - else if(sourceid == 2022040) { + } else if (sourceid == 2022040) { return 2; //aqua road underwater + } else { + return 0; } - - else return 0; } - + private static MapleStatEffect loadFromData(MapleData source, int sourceid, boolean skill, boolean overTime) { MapleStatEffect ret = new MapleStatEffect(); ret.duration = MapleDataTool.getIntConvert("time", source, -1); @@ -177,6 +180,27 @@ public class MapleStatEffect { ret.hpCon = (short) MapleDataTool.getInt("hpCon", source, 0); int iprop = MapleDataTool.getInt("prop", source, 100); ret.prop = iprop / 100.0; + + ret.cp = MapleDataTool.getInt("cp", source, 0); + List cure = new ArrayList(5); + if (MapleDataTool.getInt("poison", source, 0) > 0) { + cure.add(MapleDisease.POISON); + } + if (MapleDataTool.getInt("seal", source, 0) > 0) { + cure.add(MapleDisease.SEAL); + } + if (MapleDataTool.getInt("darkness", source, 0) > 0) { + cure.add(MapleDisease.DARKNESS); + } + if (MapleDataTool.getInt("weakness", source, 0) > 0) { + cure.add(MapleDisease.WEAKEN); + } + if (MapleDataTool.getInt("curse", source, 0) > 0) { + cure.add(MapleDisease.CURSE); + } + ret.cureDebuffs = cure; + ret.nuffSkill = MapleDataTool.getInt("nuffSkill", source, 0); + ret.mobCount = MapleDataTool.getInt("mobCount", source, 1); ret.cooldown = MapleDataTool.getInt("cooltime", source, 0); ret.morphId = MapleDataTool.getInt("morph", source, 0); @@ -192,7 +216,7 @@ public class MapleStatEffect { ret.duration *= 1000; // items have their times stored in ms, of course ret.overTime = overTime; } - + ArrayList> statups = new ArrayList<>(); ret.watk = (short) MapleDataTool.getInt("pad", source, 0); ret.wdef = (short) MapleDataTool.getInt("pdd", source, 0); @@ -200,23 +224,23 @@ public class MapleStatEffect { ret.mdef = (short) MapleDataTool.getInt("mdd", source, 0); ret.acc = (short) MapleDataTool.getIntConvert("acc", source, 0); ret.avoid = (short) MapleDataTool.getInt("eva", source, 0); - + ret.speed = (short) MapleDataTool.getInt("speed", source, 0); ret.jump = (short) MapleDataTool.getInt("jump", source, 0); - + ret.mapProtection = mapProtection(sourceid); addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MAP_PROTECTION, Integer.valueOf(ret.mapProtection)); - + if (ret.overTime && ret.getSummonMovementType() == null) { - if(!skill) { - if(isPyramidBuff(sourceid)) { + if (!skill) { + if (isPyramidBuff(sourceid)) { ret.berserk = MapleDataTool.getInt("berserk", source, 0); ret.booster = MapleDataTool.getInt("booster", source, 0); - + addBuffStatPairToListIfNotZero(statups, MapleBuffStat.BERSERK, Integer.valueOf(ret.berserk)); addBuffStatPairToListIfNotZero(statups, MapleBuffStat.BOOSTER, Integer.valueOf(ret.booster)); - - } else if(isDojoBuff(sourceid) || isHpMpRecovery(sourceid)) { + + } else if (isDojoBuff(sourceid) || isHpMpRecovery(sourceid)) { ret.mhpR = (byte) MapleDataTool.getInt("mhpR", source, 0); ret.mhpRRate = (short) (MapleDataTool.getInt("mhpRRate", source, 0) * 100); ret.mmpR = (byte) MapleDataTool.getInt("mmpR", source, 0); @@ -224,9 +248,9 @@ public class MapleStatEffect { addBuffStatPairToListIfNotZero(statups, MapleBuffStat.HPREC, Integer.valueOf(ret.mhpR)); addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MPREC, Integer.valueOf(ret.mmpR)); - - } else if(isRateCoupon(sourceid)) { - switch(MapleDataTool.getInt("expR", source, 0)) { + + } else if (isRateCoupon(sourceid)) { + switch (MapleDataTool.getInt("expR", source, 0)) { case 1: addBuffStatPairToListIfNotZero(statups, MapleBuffStat.COUPON_EXP1, 1); break; @@ -244,7 +268,7 @@ public class MapleStatEffect { break; } - switch(MapleDataTool.getInt("drpR", source, 0)) { + switch (MapleDataTool.getInt("drpR", source, 0)) { case 1: addBuffStatPairToListIfNotZero(statups, MapleBuffStat.COUPON_DRP1, 1); break; @@ -257,18 +281,18 @@ public class MapleStatEffect { addBuffStatPairToListIfNotZero(statups, MapleBuffStat.COUPON_DRP3, 1); break; } - } else if(isExpIncrease(sourceid)) { + } else if (isExpIncrease(sourceid)) { addBuffStatPairToListIfNotZero(statups, MapleBuffStat.EXP_INCREASE, MapleDataTool.getInt("expinc", source, 0)); } } else { - if(isMapChair(sourceid)) { + if (isMapChair(sourceid)) { addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MAP_CHAIR, 1); - } else if((sourceid == Beginner.NIMBLE_FEET || sourceid == Noblesse.NIMBLE_FEET || sourceid == Evan.NIMBLE_FEET || sourceid == Legend.AGILE_BODY) && ServerConstants.USE_ULTRA_NIMBLE_FEET == true) { - ret.jump = (short)(ret.speed * 4); + } else if ((sourceid == Beginner.NIMBLE_FEET || sourceid == Noblesse.NIMBLE_FEET || sourceid == Evan.NIMBLE_FEET || sourceid == Legend.AGILE_BODY) && ServerConstants.USE_ULTRA_NIMBLE_FEET == true) { + ret.jump = (short) (ret.speed * 4); ret.speed *= 15; } } - + addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WATK, Integer.valueOf(ret.watk)); addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WDEF, Integer.valueOf(ret.wdef)); addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MATK, Integer.valueOf(ret.matk)); @@ -278,26 +302,26 @@ public class MapleStatEffect { addBuffStatPairToListIfNotZero(statups, MapleBuffStat.SPEED, Integer.valueOf(ret.speed)); addBuffStatPairToListIfNotZero(statups, MapleBuffStat.JUMP, Integer.valueOf(ret.jump)); } - + MapleData ltd = source.getChildByPath("lt"); if (ltd != null) { ret.lt = (Point) ltd.getData(); ret.rb = (Point) source.getChildByPath("rb").getData(); - - if(ServerConstants.USE_MAXRANGE_ECHO_OF_HERO && (sourceid == Beginner.ECHO_OF_HERO || sourceid == Noblesse.ECHO_OF_HERO || sourceid == Legend.ECHO_OF_HERO || sourceid == Evan.ECHO_OF_HERO)) { + + if (ServerConstants.USE_MAXRANGE_ECHO_OF_HERO && (sourceid == Beginner.ECHO_OF_HERO || sourceid == Noblesse.ECHO_OF_HERO || sourceid == Legend.ECHO_OF_HERO || sourceid == Evan.ECHO_OF_HERO)) { ret.lt = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); ret.rb = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); } } - + int x = MapleDataTool.getInt("x", source, 0); - - if((sourceid == Beginner.RECOVERY || sourceid == Noblesse.RECOVERY || sourceid == Evan.RECOVERY || sourceid == Legend.RECOVERY) && ServerConstants.USE_ULTRA_RECOVERY == true) { + + if ((sourceid == Beginner.RECOVERY || sourceid == Noblesse.RECOVERY || sourceid == Evan.RECOVERY || sourceid == Legend.RECOVERY) && ServerConstants.USE_ULTRA_RECOVERY == true) { x *= 10; } ret.x = x; ret.y = MapleDataTool.getInt("y", source, 0); - + ret.damage = MapleDataTool.getIntConvert("damage", source, 100); ret.fixdamage = MapleDataTool.getIntConvert("fixdamage", source, -1); ret.attackCount = MapleDataTool.getIntConvert("attackCount", source, 1); @@ -416,8 +440,8 @@ public class MapleStatEffect { break; case BlazeWizard.ELEMENTAL_RESET: case Evan.ELEMENTAL_RESET: - statups.add(new Pair<>(MapleBuffStat.ELEMENTAL_RESET, Integer.valueOf(x))); - break; + statups.add(new Pair<>(MapleBuffStat.ELEMENTAL_RESET, Integer.valueOf(x))); + break; case Evan.MAGIC_SHIELD: statups.add(new Pair<>(MapleBuffStat.MAGIC_SHIELD, Integer.valueOf(x))); break; @@ -425,7 +449,7 @@ public class MapleStatEffect { statups.add(new Pair<>(MapleBuffStat.MAGIC_RESISTANCE, Integer.valueOf(x))); break; case Evan.SLOW: - statups.add(new Pair<>(MapleBuffStat.SLOW, Integer.valueOf(x))); + statups.add(new Pair<>(MapleBuffStat.SLOW, Integer.valueOf(x))); // BOWMAN case Priest.MYSTIC_DOOR: case Hunter.SOUL_ARROW: @@ -474,7 +498,7 @@ public class MapleStatEffect { break; case ChiefBandit.PICKPOCKET: statups.add(new Pair<>(MapleBuffStat.PICKPOCKET, Integer.valueOf(x))); - break; + break; case NightLord.SHADOW_STARS: statups.add(new Pair<>(MapleBuffStat.SHADOW_CLAW, Integer.valueOf(0))); break; @@ -605,7 +629,7 @@ public class MapleStatEffect { case Buccaneer.BARRAGE: case Gunslinger.BLANK_SHOT: case DawnWarrior.COMA: - case ThunderBreaker.BARRAGE: + case ThunderBreaker.BARRAGE: case Aran.ROLLING_SPIN: case Evan.FIRE_BREATH: case Evan.BLAZE: @@ -633,7 +657,7 @@ public class MapleStatEffect { case ILWizard.SLOW: case BlazeWizard.SLOW: monsterStatus.put(MonsterStatus.SPEED, Integer.valueOf(ret.x)); - break; + break; case FPWizard.POISON_BREATH: case FPMage.ELEMENT_COMPOSITION: monsterStatus.put(MonsterStatus.POISON, Integer.valueOf(1)); @@ -655,7 +679,7 @@ public class MapleStatEffect { monsterStatus.put(MonsterStatus.FREEZE, Integer.valueOf(1)); break; case Evan.PHANTOM_IMPRINT: - monsterStatus.put(MonsterStatus.PHANTOM_IMPRINT, Integer.valueOf(x)); + monsterStatus.put(MonsterStatus.PHANTOM_IMPRINT, Integer.valueOf(x)); //ARAN case Aran.COMBO_ABILITY: statups.add(new Pair<>(MapleBuffStat.ARAN_COMBO, Integer.valueOf(100))); @@ -723,19 +747,19 @@ public class MapleStatEffect { public boolean applyEchoOfHero(MapleCharacter applyfrom) { Map mapPlayers = applyfrom.getMap().getMapPlayers(); mapPlayers.remove(applyfrom.getId()); - + boolean hwResult = applyTo(applyfrom); for (MapleCharacter chr : mapPlayers.values()) { // Echo of Hero not buffing players in the map detected thanks to Masterrulax applyTo(applyfrom, chr, false, null, false, 1); } - + return hwResult; } - + public boolean applyTo(MapleCharacter chr) { return applyTo(chr, chr, true, null, false, 1); } - + public boolean applyTo(MapleCharacter chr, boolean useMaxRange) { return applyTo(chr, chr, true, null, useMaxRange, 1); } @@ -750,16 +774,16 @@ public class MapleStatEffect { applyto.toggleHide(false); return true; } - + if (primary && isHeal()) { affectedPlayers = applyBuff(applyfrom, useMaxRange); } - + int hpchange = calcHPChange(applyfrom, primary, affectedPlayers); int mpchange = calcMPChange(applyfrom, primary); if (primary) { if (itemConNo != 0) { - if(!applyto.getClient().getAbstractPlayerInteraction().hasItem(itemCon, itemConNo)) { + if (!applyto.getClient().getAbstractPlayerInteraction().hasItem(itemCon, itemConNo)) { applyto.announce(MaplePacketCreator.enableActions()); return false; } @@ -771,7 +795,7 @@ public class MapleStatEffect { applyto.broadcastStance(applyto.isFacingLeft() ? 5 : 4); } } - + if (isDispel() && makeChanceResult()) { applyto.dispelDebuffs(); } else if (isCureAllAbnormalStatus()) { @@ -784,24 +808,26 @@ public class MapleStatEffect { /*if (applyfrom.getMp() < getMpCon()) { AutobanFactory.MPCON.addPoint(applyfrom.getAutobanManager(), "mpCon hack for skill:" + sourceid + "; Player MP: " + applyto.getMp() + " MP Needed: " + getMpCon()); } */ - + if (!applyto.applyHpMpChange(hpCon, hpchange, mpchange)) { applyto.announce(MaplePacketCreator.enableActions()); return false; } - + if (moveTo != -1) { if (moveTo != applyto.getMapId()) { MapleMap target; MaplePortal pt; - + if (moveTo == 999999999) { - if(sourceid != 2030100) { + if (sourceid != 2030100) { target = applyto.getMap().getReturnMap(); pt = target.getRandomPlayerSpawnpoint(); } else { - if(!applyto.canRecoverLastBanish()) return false; - + if (!applyto.canRecoverLastBanish()) { + return false; + } + Pair lastBanishInfo = applyto.getLastBanishData(); target = applyto.getWarpMap(lastBanishInfo.getLeft()); pt = target.getPortal(lastBanishInfo.getRight()); @@ -810,12 +836,12 @@ public class MapleStatEffect { target = applyto.getClient().getWorldServer().getChannel(applyto.getClient().getChannel()).getMapFactory().getMap(moveTo); int targetid = target.getId() / 10000000; if (targetid != 60 && applyto.getMapId() / 10000000 != 61 && targetid != applyto.getMapId() / 10000000 && targetid != 21 && targetid != 20 && targetid != 12 && (applyto.getMapId() / 10000000 != 10 && applyto.getMapId() / 10000000 != 12)) { - return false; + return false; } - + pt = target.getRandomPlayerSpawnpoint(); } - + applyto.changeMap(target, pt); } else { return false; @@ -842,15 +868,15 @@ public class MapleStatEffect { SummonMovementType summonMovementType = getSummonMovementType(); if (overTime || isCygnusFA() || summonMovementType != null) { if (summonMovementType != null && pos != null) { - if(summonMovementType.getValue() == summonMovementType.STATIONARY.getValue()) { + if (summonMovementType.getValue() == summonMovementType.STATIONARY.getValue()) { applyto.cancelBuffStats(MapleBuffStat.PUPPET); } else { applyto.cancelBuffStats(MapleBuffStat.SUMMON); } - + applyto.announce(MaplePacketCreator.enableActions()); } - + applyBuffEffect(applyfrom, applyto, primary); } @@ -863,7 +889,7 @@ public class MapleStatEffect { applyMonsterBuff(applyfrom); } } - + if (this.getFatigue() != 0) { applyto.getMount().setTiredness(applyto.getMount().getTiredness() + this.getFatigue()); } @@ -880,25 +906,29 @@ public class MapleStatEffect { if (isMagicDoor() && !FieldLimit.DOOR.check(applyto.getMap().getFieldLimit())) { // Magic Door int y = applyto.getFh(); if (y == 0) { - y = applyto.getPosition().y; + y = applyto.getPosition().y; } Point doorPosition = new Point(applyto.getPosition().x, y); MapleDoor door = new MapleDoor(applyto, doorPosition); - - if(door.getOwnerId() >= 0) { + + if (door.getOwnerId() >= 0) { applyto.applyPartyDoor(door, false); door.getTarget().spawnDoor(door.getAreaDoor()); door.getTown().spawnDoor(door.getTownDoor()); - + applyto.disableDoorSpawn(); } else { MapleInventoryManipulator.addFromDrop(applyto.getClient(), new Item(4006000, (short) 0, (short) 1), false); - - if(door.getOwnerId() == -3) applyto.dropMessage(5, "Mystic Door cannot be cast far from a spawn point. Nearest one is at " + door.getDoorStatus().getRight() + "pts " + door.getDoorStatus().getLeft()); - else if(door.getOwnerId() == -2) applyto.dropMessage(5, "Mystic Door cannot be cast on a slope, try elsewhere."); - else applyto.dropMessage(5, "There are no door portals available for the town at this moment. Try again later."); - + + if (door.getOwnerId() == -3) { + applyto.dropMessage(5, "Mystic Door cannot be cast far from a spawn point. Nearest one is at " + door.getDoorStatus().getRight() + "pts " + door.getDoorStatus().getLeft()); + } else if (door.getOwnerId() == -2) { + applyto.dropMessage(5, "Mystic Door cannot be cast on a slope, try elsewhere."); + } else { + applyto.dropMessage(5, "There are no door portals available for the town at this moment. Try again later."); + } + applyto.cancelBuffStats(MapleBuffStat.SOULARROW); // cancel door buff } } else if (isMist()) { @@ -907,14 +937,51 @@ public class MapleStatEffect { applyfrom.getMap().spawnMist(mist, getDuration(), mist.isPoisonMist(), false, mist.isRecoveryMist()); } else if (isTimeLeap()) { applyto.removeAllCooldownsExcept(Buccaneer.TIME_LEAP, true); + } else if (cp != 0 && applyto.getMonsterCarnival() != null) { + applyto.gainCP(cp); + } else if (nuffSkill != 0 && applyto.getParty() != null && applyto.getMap().isCPQMap()) { + final MCSkill skil = MapleCarnivalFactory.getInstance().getSkill(nuffSkill); + if (skil != null) { + final MapleDisease dis = skil.getDisease(); + MapleParty inimigos = applyfrom.getParty().getEnemy(); + if (nuffSkill == 8) { + int amount = inimigos.getMembers().size() - 1; + int randd = (int) Math.floor(Math.random() * amount); + MapleCharacter chrApp = applyfrom.getClient().getChannelServer().getPlayerStorage().getCharacterById(inimigos.getMemberByPos(randd).getId()); + if (chrApp != null && chrApp.getMap().isCPQMap()) { + chrApp.dispel(); + } + } else { + for (MaplePartyCharacter chrsInimigos : inimigos.getPartyMembers()) { + MapleCharacter chrApp = chrsInimigos.getPlayer(); + if (chrApp != null && chrApp.getMap().isCPQMap()) { + if (dis == null) { + chrApp.dispel(); + } else if (skil.getSkill() != null) { + chrApp.giveDebuff(dis, skil.getSkill()); + } + } + } + } + } + } else if (cureDebuffs.size() > 0) { + for (final MapleDisease debuff : cureDebuffs) { + if (applyfrom.getParty() != null) { + for (MaplePartyCharacter chrs : applyfrom.getParty().getPartyMembers()) { + chrs.getPlayer().dispelDebuff(debuff); + } + } else { + applyfrom.dispelDebuff(debuff); + } + } } - + return true; } private int applyBuff(MapleCharacter applyfrom, boolean useMaxRange) { int affectedc = 1; - + if (isPartyBuff() && (applyfrom.getParty() != null || isGmBuff())) { Rectangle bounds = (!useMaxRange) ? calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft()) : new Rectangle(Integer.MIN_VALUE / 2, Integer.MIN_VALUE / 2, Integer.MAX_VALUE, Integer.MAX_VALUE); List affecteds = applyfrom.getMap().getMapObjectsInRect(bounds, Arrays.asList(MapleMapObjectType.PLAYER)); @@ -933,7 +1000,7 @@ public class MapleStatEffect { } } } - + affectedc += affectedp.size(); // used for heal for (MapleCharacter affected : affectedp) { applyTo(applyfrom, affected, false, null, useMaxRange, affectedc); @@ -941,7 +1008,7 @@ public class MapleStatEffect { affected.getMap().broadcastMessage(affected, MaplePacketCreator.showBuffeffect(affected.getId(), sourceid, 2), false); } } - + return affectedc; } @@ -952,15 +1019,15 @@ public class MapleStatEffect { int i = 0; for (MapleMapObject mo : affected) { MapleMonster monster = (MapleMonster) mo; - if (isDispel()) { - monster.debuffMob(skill_.getId()); + if (isDispel()) { + monster.debuffMob(skill_.getId()); } else { - if (makeChanceResult()) { - monster.applyStatus(applyfrom, new MonsterStatusEffect(getMonsterStati(), skill_, null, false), isPoison(), getDuration()); - if (isCrash()) { - monster.debuffMob(skill_.getId()); - } + if (makeChanceResult()) { + monster.applyStatus(applyfrom, new MonsterStatusEffect(getMonsterStati(), skill_, null, false), isPoison(), getDuration()); + if (isCrash()) { + monster.debuffMob(skill_.getId()); } + } } i++; if (i >= mobCount) { @@ -982,17 +1049,17 @@ public class MapleStatEffect { Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y); return bounds; } - + public int getBuffLocalDuration() { return !ServerConstants.USE_BUFF_EVERLASTING ? duration : Integer.MAX_VALUE; } - + public void silentApplyBuff(MapleCharacter chr, long localStartTime) { int localDuration = getBuffLocalDuration(); localDuration = alchemistModifyVal(chr, localDuration, false); //CancelEffectAction cancelAction = new CancelEffectAction(chr, this, starttime); //ScheduledFuture schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - Server.getInstance().getCurrentTime())); - + chr.registerEffect(this, localStartTime, localStartTime + localDuration, true); SummonMovementType summonMovementType = getSummonMovementType(); if (summonMovementType != null) { @@ -1016,7 +1083,7 @@ public class MapleStatEffect { // final ScheduledFuture schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + 99999) - Server.getInstance().getCurrentTime())); applyto.registerEffect(this, starttime, Long.MAX_VALUE, false); } - + public final void applyBeaconBuff(final MapleCharacter applyto, int objectid) { // thanks Thora & Hyun for reporting an issue with homing beacon autoflagging mobs when changing maps final List> stat = Collections.singletonList(new Pair<>(MapleBuffStat.HOMING_BEACON, objectid)); applyto.announce(MaplePacketCreator.giveBuff(1, sourceid, stat)); @@ -1024,14 +1091,14 @@ public class MapleStatEffect { final long starttime = Server.getInstance().getCurrentTime(); applyto.registerEffect(this, starttime, Long.MAX_VALUE, false); } - + public void updateBuffEffect(MapleCharacter target, List> activeStats, long starttime) { int localDuration = getBuffLocalDuration(); localDuration = alchemistModifyVal(target, localDuration, false); - + long leftDuration = (starttime + localDuration) - Server.getInstance().getCurrentTime(); - if(leftDuration > 0) { - target.announce(MaplePacketCreator.giveBuff((skill ? sourceid : -sourceid), (int)leftDuration, activeStats)); + if (leftDuration > 0) { + target.announce(MaplePacketCreator.giveBuff((skill ? sourceid : -sourceid), (int) leftDuration, activeStats)); } } @@ -1067,7 +1134,7 @@ public class MapleStatEffect { if (applyto.getMount() == null) { applyto.mount(ridingMountId, sourceid); } - + applyto.getClient().getWorldServer().registerMountHunger(applyto); } if (sourceid == Corsair.BATTLE_SHIP) { @@ -1089,8 +1156,8 @@ public class MapleStatEffect { localsourceid = ridingMountId; localstatups = Collections.singletonList(new Pair<>(MapleBuffStat.MONSTER_RIDING, 0)); } else if (isSkillMorph()) { - for(int i = 0; i < localstatups.size(); i++) { - if(localstatups.get(i).getLeft().equals(MapleBuffStat.MORPH)) { + for (int i = 0; i < localstatups.size(); i++) { + if (localstatups.get(i).getLeft().equals(MapleBuffStat.MORPH)) { localstatups.set(i, new Pair<>(MapleBuffStat.MORPH, getMorph(applyto))); break; } @@ -1110,7 +1177,7 @@ public class MapleStatEffect { buff = MaplePacketCreator.givePirateBuff(statups, sourceid, seconds); mbuff = MaplePacketCreator.giveForeignPirateBuff(applyto.getId(), sourceid, seconds, localstatups); } else if (isInfusion()) { - buff = MaplePacketCreator.givePirateBuff(localstatups, sourceid, seconds); + buff = MaplePacketCreator.givePirateBuff(localstatups, sourceid, seconds); mbuff = MaplePacketCreator.giveForeignPirateBuff(applyto.getId(), sourceid, seconds, localstatups); } else if (isDs()) { List> dsstat = Collections.singletonList(new Pair<>(MapleBuffStat.DARKSIGHT, 0)); @@ -1125,10 +1192,10 @@ public class MapleStatEffect { if (applyto.getBattleshipHp() <= 0) { applyto.resetBattleshipHp(); } - + localstatups = statups; } - + buff = MaplePacketCreator.giveBuff(localsourceid, localDuration, localstatups); mbuff = MaplePacketCreator.showMonsterRiding(applyto.getId(), givemount); localDuration = duration; @@ -1144,15 +1211,15 @@ public class MapleStatEffect { List> stat = Collections.singletonList(new Pair<>(MapleBuffStat.MORPH, Integer.valueOf(getMorph(applyto)))); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), stat); } - + if (buff != null) { - if (!hasNoIcon()) { //Thanks flav for such a simple release! :) + if (!hasNoIcon()) { //Thanks flav for such a simple release! :) applyto.announce(buff); - } else { + } else { System.out.println(" NO buff icon for id " + sourceid); } } - + long starttime = Server.getInstance().getCurrentTime(); //CancelEffectAction cancelAction = new CancelEffectAction(applyto, this, starttime); //ScheduledFuture schedule = TimerManager.getInstance().schedule(cancelAction, localDuration); @@ -1273,7 +1340,7 @@ public class MapleStatEffect { case Beginner.ECHO_OF_HERO: case Noblesse.ECHO_OF_HERO: case Legend.ECHO_OF_HERO: - case Evan.ECHO_OF_HERO: + case Evan.ECHO_OF_HERO: case SuperGM.HEAL_PLUS_DISPEL: case SuperGM.HASTE: case SuperGM.HOLY_SYMBOL: @@ -1346,45 +1413,44 @@ public class MapleStatEffect { public boolean isRecovery() { return sourceid == Beginner.RECOVERY || sourceid == Noblesse.RECOVERY || sourceid == Legend.RECOVERY || sourceid == Evan.RECOVERY; } - + public boolean isMapChair() { return sourceid == Beginner.MAP_CHAIR || sourceid == Noblesse.MAP_CHAIR || sourceid == Legend.MAP_CHAIR; } - + public static boolean isMapChair(int sourceid) { return sourceid == Beginner.MAP_CHAIR || sourceid == Noblesse.MAP_CHAIR || sourceid == Legend.MAP_CHAIR; } - - + public boolean isDojoBuff() { return sourceid >= 2022359 && sourceid <= 2022421; } - + public static boolean isDojoBuff(int sourceid) { return sourceid >= 2022359 && sourceid <= 2022421; } - + public static boolean isHpMpRecovery(int sourceid) { return sourceid == 2022198 || sourceid == 2022337; } - + public static boolean isPyramidBuff(int sourceid) { return sourceid >= 2022585 && sourceid <= 2022617; } - + public static boolean isRateCoupon(int sourceid) { int itemType = sourceid / 1000; return itemType == 5211 || itemType == 5360; } - + public static boolean isExpIncrease(int sourceid) { return sourceid >= 2022450 && sourceid <= 2022452; } - + private boolean isDs() { return skill && (sourceid == Rogue.DARK_SIGHT || sourceid == NightWalker.DARK_SIGHT); } - + private boolean isWw() { return skill && (sourceid == WindArcher.WIND_WALK); } @@ -1412,11 +1478,11 @@ public class MapleStatEffect { private boolean isCouponBuff() { return isRateCoupon(sourceid); } - + private boolean isMysticDoor() { return skill && sourceid == Priest.MYSTIC_DOOR; } - + public boolean isMonsterRiding() { return skill && (sourceid % 10000000 == 1004 || sourceid == Corsair.BATTLE_SHIP || sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP || sourceid == Beginner.YETI_MOUNT1 || sourceid == Beginner.YETI_MOUNT2 || sourceid == Beginner.WITCH_BROOMSTICK || sourceid == Beginner.BALROG_MOUNT @@ -1431,11 +1497,11 @@ public class MapleStatEffect { public boolean isPoison() { return skill && (sourceid == FPMage.POISON_MIST || sourceid == FPWizard.POISON_BREATH || sourceid == FPMage.ELEMENT_COMPOSITION || sourceid == NightWalker.POISON_BOMB || sourceid == BlazeWizard.FLAME_GEAR); } - + public boolean isMorph() { return morphId > 0; } - + public boolean isMorphWithoutAttack() { return morphId > 0 && morphId < 100; // Every morph item I have found has been under 100, pirate skill transforms start at 1000. } @@ -1453,9 +1519,9 @@ public class MapleStatEffect { } private boolean isCrash() { - return skill && (sourceid == DragonKnight.POWER_CRASH || sourceid == Crusader.ARMOR_CRASH || sourceid == WhiteKnight.MAGIC_CRASH); + return skill && (sourceid == DragonKnight.POWER_CRASH || sourceid == Crusader.ARMOR_CRASH || sourceid == WhiteKnight.MAGIC_CRASH); } - + private boolean isDispel() { return skill && (sourceid == Priest.DISPEL || sourceid == SuperGM.HEAL_PLUS_DISPEL); } @@ -1463,13 +1529,15 @@ public class MapleStatEffect { private boolean isCureAllAbnormalStatus() { if (skill) { return isHerosWill(sourceid); - } else if (sourceid == 2022544) return true; - + } else if (sourceid == 2022544) { + return true; + } + return false; } - + public static boolean isHerosWill(int skillid) { - switch(skillid) { + switch (skillid) { case Hero.HEROS_WILL: case Paladin.HEROS_WILL: case DarkKnight.HEROS_WILL: @@ -1504,7 +1572,7 @@ public class MapleStatEffect { private boolean isCygnusFA() { return skill && (sourceid == DawnWarrior.FINAL_ATTACK || sourceid == WindArcher.FINAL_ATTACK); } - + private boolean isHyperBody() { return skill && (sourceid == Spearman.HYPER_BODY || sourceid == GM.HYPER_BODY || sourceid == SuperGM.HYPER_BODY); } @@ -1561,17 +1629,16 @@ public class MapleStatEffect { return null; } - public boolean hasNoIcon() { return (sourceid == 3111002 || sourceid == 3211002 || + // puppet, puppet - sourceid == 3211005 || + // golden eagle + sourceid == 3211005 || + // golden eagle sourceid == 2121005 || sourceid == 2221005 || + // elquines, ifrit sourceid == 2321003 || sourceid == 3121006 || + // bahamut, phoenix sourceid == 3221005 || sourceid == 3111005 || + // frostprey, silver hawk sourceid == 2311006 || sourceid == 5220002 || + // summon dragon, wrath of the octopi sourceid == 5211001 || sourceid == 5211002); // octopus, gaviota } - + public boolean isSkill() { return skill; } @@ -1579,7 +1646,7 @@ public class MapleStatEffect { public int getSourceId() { return sourceid; } - + public int getBuffSourceId() { return skill ? sourceid : -sourceid; } @@ -1589,28 +1656,27 @@ public class MapleStatEffect { } /* - private static class CancelEffectAction implements Runnable { + private static class CancelEffectAction implements Runnable { - private MapleStatEffect effect; - private WeakReference target; - private long startTime; + private MapleStatEffect effect; + private WeakReference target; + private long startTime; - public CancelEffectAction(MapleCharacter target, MapleStatEffect effect, long startTime) { - this.effect = effect; - this.target = new WeakReference<>(target); - this.startTime = startTime; - } - - @Override - public void run() { - MapleCharacter realTarget = target.get(); - if (realTarget != null) { - realTarget.cancelEffect(effect, false, startTime); - } - } - } - */ + public CancelEffectAction(MapleCharacter target, MapleStatEffect effect, long startTime) { + this.effect = effect; + this.target = new WeakReference<>(target); + this.startTime = startTime; + } + @Override + public void run() { + MapleCharacter realTarget = target.get(); + if (realTarget != null) { + realTarget.cancelEffect(effect, false, startTime); + } + } + } + */ public short getHp() { return hp; } @@ -1618,7 +1684,7 @@ public class MapleStatEffect { public short getMp() { return mp; } - + public double getHpRate() { return hpR; } @@ -1626,7 +1692,7 @@ public class MapleStatEffect { public double getMpRate() { return mpR; } - + public byte getHpR() { return mhpR; } @@ -1634,7 +1700,7 @@ public class MapleStatEffect { public byte getMpR() { return mmpR; } - + public short getHpRRate() { return mhpRRate; } @@ -1654,7 +1720,7 @@ public class MapleStatEffect { public short getMatk() { return matk; } - + public short getWatk() { return watk; } @@ -1714,4 +1780,4 @@ public class MapleStatEffect { public Map getMonsterStati() { return monsterStatus; } -} \ No newline at end of file +} diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java index 6ea511e450..00286db8df 100644 --- a/src/server/life/MapleMonster.java +++ b/src/server/life/MapleMonster.java @@ -75,6 +75,7 @@ import server.MapleStatEffect; import server.maps.MapleSummon; public class MapleMonster extends AbstractLoadedMapleLife { + private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats. private MapleMonsterStats stats; private AtomicInteger hp = new AtomicInteger(1); @@ -117,11 +118,11 @@ public class MapleMonster extends AbstractLoadedMapleLife { super(monster); initWithStats(monster.stats); } - + public void lockMonster() { externalLock.lock(); } - + public void unlockMonster() { externalLock.unlock(); } @@ -131,7 +132,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { this.stats = stats; hp.set(stats.getHp()); mp = stats.getMp(); - + maxHpPlusHeal.set(hp.get()); } @@ -142,7 +143,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { public void enableDrops() { this.dropsDisabled = false; } - + public boolean dropsDisabled() { return dropsDisabled; } @@ -150,7 +151,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { public void setMap(MapleMap map) { this.map = map; } - + public int getParentMobOid() { return parentMobOid; } @@ -158,68 +159,70 @@ public class MapleMonster extends AbstractLoadedMapleLife { public void setParentMobOid(int parentMobId) { this.parentMobOid = parentMobId; } - + public int countAvailableMobSummons(int limit, int skillLimit) { // limit prop for summons has another conotation, found thanks to MedicOP Set calledOids = this.calledMobOids; - if(calledOids != null) { + if (calledOids != null) { limit -= calledOids.size(); } - + return Math.min(limit, skillLimit - this.calledMobCount); } - + public void addSummonedMob(MapleMonster mob) { Set calledOids = this.calledMobOids; if (calledOids == null) { calledOids = Collections.synchronizedSet(new HashSet()); this.calledMobOids = calledOids; } - + calledOids.add(mob.getObjectId()); mob.setSummonerMob(this); this.calledMobCount += 1; } - + private void removeSummonedMob(int mobOid) { Set calledOids = this.calledMobOids; if (calledOids != null) { calledOids.remove(mobOid); } } - + private void setSummonerMob(MapleMonster mob) { this.callerMob = new WeakReference<>(mob); } - + private void dispatchClearSummons() { MapleMonster caller = this.callerMob.get(); if (caller != null) { caller.removeSummonedMob(this.getObjectId()); } - + this.calledMobOids = null; } - + public void pushRemoveAfterAction(Runnable run) { this.removeAfterAction = run; } - + public Runnable popRemoveAfterAction() { Runnable r = this.removeAfterAction; this.removeAfterAction = null; - + return r; } - + public int getHp() { return hp.get(); } - + public synchronized void addHp(int hp) { - if(this.hp.get() <= 0) return; + if (this.hp.get() <= 0) { + return; + } this.hp.addAndGet(hp); } - + public void setStartingHp(int hp) { this.hp.set(hp); } @@ -298,20 +301,22 @@ public class MapleMonster extends AbstractLoadedMapleLife { public void setHpZero() { // force HP = 0 applyAndGetHpDamage(Integer.MAX_VALUE, false); } - + private boolean applyAnimationIfRoaming(int attackPos, MobSkill skill) { // roam: not casting attack or skill animations - if(!animationLock.tryLock()) return false; - + if (!animationLock.tryLock()) { + return false; + } + try { long animationTime; - - if(skill == null) { + + if (skill == null) { animationTime = MapleMonsterInformationProvider.getInstance().getMobAttackAnimationTime(this.getId(), attackPos); } else { animationTime = MapleMonsterInformationProvider.getInstance().getMobSkillAnimationTime(skill); } - if(animationTime > 0) { + if (animationTime > 0) { return map.getChannelServer().registerMobOnAnimationEffect(map.getId(), this.hashCode(), animationTime); } else { return true; @@ -320,37 +325,39 @@ public class MapleMonster extends AbstractLoadedMapleLife { animationLock.unlock(); } } - + public synchronized Integer applyAndGetHpDamage(int delta, boolean stayAlive) { int curHp = hp.get(); if (curHp <= 0) { // this monster is already dead return null; } - - if(delta >= 0) { - if(stayAlive) curHp--; + + if (delta >= 0) { + if (stayAlive) { + curHp--; + } int trueDamage = Math.min(curHp, delta); - + hp.addAndGet(-trueDamage); return trueDamage; } else { int trueHeal = -delta; int hp2Heal = curHp + trueHeal; int maxHp = getMaxHp(); - + if (hp2Heal > maxHp) { trueHeal -= (hp2Heal - maxHp); } - + hp.addAndGet(trueHeal); return trueHeal; } } - + public synchronized void disposeMapObject() { // mob is no longer associated with the map it was in hp.set(-1); } - + public void broadcastMobHpBar(MapleCharacter from) { if (hasBossHPBar()) { from.setPlayerAggro(this.hashCode()); @@ -370,10 +377,10 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } } - + public boolean damage(MapleCharacter attacker, int damage, boolean stayAlive) { boolean lastHit = false; - + this.lockMonster(); try { if (!this.isAlive()) { @@ -381,28 +388,27 @@ public class MapleMonster extends AbstractLoadedMapleLife { } /* pyramid not implemented - Pair cool = this.getStats().getCool(); - if (cool != null) { - Pyramid pq = (Pyramid) chr.getPartyQuest(); - if (pq != null) { - if (damage > 0) { - if (damage >= cool.getLeft()) { - if ((Math.random() * 100) < cool.getRight()) { - pq.cool(); - } else { - pq.kill(); - } - } else { - pq.kill(); - } - } else { - pq.miss(); - } - killed = true; - } - } - */ - + Pair cool = this.getStats().getCool(); + if (cool != null) { + Pyramid pq = (Pyramid) chr.getPartyQuest(); + if (pq != null) { + if (damage > 0) { + if (damage >= cool.getLeft()) { + if ((Math.random() * 100) < cool.getRight()) { + pq.cool(); + } else { + pq.kill(); + } + } else { + pq.kill(); + } + } else { + pq.miss(); + } + killed = true; + } + } + */ if (damage > 0) { this.applyDamage(attacker, damage, stayAlive); if (!this.isAlive()) { // monster just died @@ -412,10 +418,10 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { this.unlockMonster(); } - + return lastHit; } - + /** * * @param from the player that dealt the damage @@ -427,8 +433,10 @@ public class MapleMonster extends AbstractLoadedMapleLife { if (trueDamage == null) { return; } - - if(ServerConstants.USE_DEBUG) from.dropMessage(5, "Hitted MOB " + this.getId() + ", OID " + this.getObjectId()); + + if (ServerConstants.USE_DEBUG) { + from.dropMessage(5, "Hitted MOB " + this.getId() + ", OID " + this.getObjectId()); + } dispatchMonsterDamaged(from, trueDamage); if (!takenDamage.containsKey(from.getId())) { @@ -439,20 +447,24 @@ public class MapleMonster extends AbstractLoadedMapleLife { broadcastMobHpBar(from); } - + public void heal(int hp, int mp) { Integer hpHealed = applyAndGetHpDamage(-hp, false); - if(hpHealed == null) return; - + if (hpHealed == null) { + return; + } + int mp2Heal = getMp() + mp; int maxMp = getMaxMp(); if (mp2Heal >= maxMp) { mp2Heal = maxMp; } setMp(mp2Heal); - - if(hp > 0) getMap().broadcastMessage(MaplePacketCreator.healMonster(getObjectId(), hp, getHp(), getMaxHp())); - + + if (hp > 0) { + getMap().broadcastMessage(MaplePacketCreator.healMonster(getObjectId(), hp, getHp(), getMaxHp())); + } + maxHpPlusHeal.addAndGet(hpHealed); dispatchMonsterHealed(hpHealed); } @@ -464,24 +476,26 @@ public class MapleMonster extends AbstractLoadedMapleLife { private void distributeExperienceToParty(int pid, float exp, int killer, int killerLevel, Set underleveled, int minThresholdLevel) { List members = new LinkedList<>(); MapleCharacter pchar = getMap().getAnyCharacterFromParty(pid); - if(pchar != null) { - for(MapleCharacter chr : pchar.getPartyMembersOnSameMap()) { + if (pchar != null) { + for (MapleCharacter chr : pchar.getPartyMembersOnSameMap()) { members.add(chr); } } else { MapleCharacter chr = getMap().getCharacterById(killer); - if(chr == null) return; - + if (chr == null) { + return; + } + members.add(chr); } - + List expSharers = new LinkedList<>(); int expSharersLevel = 0; for (MapleCharacter mc : members) { if (mc.getLevel() >= minThresholdLevel) { //NO EXP WILL BE GIVEN for those who are underleveled! if (Math.abs(killerLevel - mc.getLevel()) < ServerConstants.MIN_RANGELEVEL_TO_EXP_LEECH) { // thanks Thora for pointing out leech level limitation - + expSharersLevel += mc.getLevel(); expSharers.add(mc); } @@ -505,38 +519,38 @@ public class MapleMonster extends AbstractLoadedMapleLife { } private int calcThresholdLevel(boolean isPqMob) { - if(!ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE) { + if (!ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE) { return 0; } else if (isPqMob) { double thresholdLevel = getLevel(); thresholdLevel /= 32.55916838; thresholdLevel = Math.log(thresholdLevel) / 0.02058204546; - + return (int) Math.ceil(thresholdLevel); } else { return getLevel() - (!isBoss() ? ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN : 2 * ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN); } } - + private void distributeExperience(int killerId) { if (isAlive()) { return; } - + EventInstanceManager eim = getMap().getEventInstance(); int minThresholdLevel = calcThresholdLevel(eim != null), killerLevel = Integer.MAX_VALUE; int exp = getExp(); long totalHealth = maxHpPlusHeal.get(); Map expDist = new HashMap<>(); Map partyExp = new HashMap<>(); - + float exp8perHp = (0.8f * exp) / totalHealth; // 80% of pool is split amongst all the damagers float exp2 = (0.2f * exp); // 20% of pool goes to the killer or his/her party - + for (Entry damage : takenDamage.entrySet()) { expDist.put(damage.getKey(), exp8perHp * damage.getValue().get()); } - + Set underleveled = new HashSet<>(); Collection mapChrs = map.getCharacters(); for (MapleCharacter mc : mapChrs) { @@ -548,18 +562,18 @@ public class MapleMonster extends AbstractLoadedMapleLife { if (eim != null) { eim.monsterKilled(mc, this); } - + killerLevel = mc.getLevel(); xp += exp2; } - + MapleParty p = mc.getParty(); if (p != null) { int pID = p.getId(); float pXP = xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0); partyExp.put(pID, pXP); } else { - if(mc.getLevel() >= minThresholdLevel) { + if (mc.getLevel() >= minThresholdLevel) { //NO EXP WILL BE GIVEN for those who are underleveled! giveExpToCharacter(mc, xp, isKiller, 1); } else { @@ -568,10 +582,10 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } } - - if(!expDist.isEmpty()) { // locate on world server the partyid of the missing characters + + if (!expDist.isEmpty()) { // locate on world server the partyid of the missing characters World wserv = map.getWorldServer(); - + for (Entry ed : expDist.entrySet()) { boolean isKiller = (ed.getKey() == killerId); float xp = ed.getValue(); @@ -586,12 +600,12 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } } - + for (Entry party : partyExp.entrySet()) { distributeExperienceToParty(party.getKey(), party.getValue(), killerId, killerLevel, underleveled, minThresholdLevel); } - - for(MapleCharacter mc : underleveled) { + + for (MapleCharacter mc : underleveled) { mc.showUnderleveledInfo(this); } } @@ -599,16 +613,16 @@ public class MapleMonster extends AbstractLoadedMapleLife { private void giveExpToCharacter(MapleCharacter attacker, float exp, boolean isKiller, int numExpSharers) { //PARTY BONUS: 2p -> +2% , 3p -> +4% , 4p -> +6% , 5p -> +8% , 6p -> +10% final float partyModifier = numExpSharers <= 1 ? 0.0f : 0.02f * (numExpSharers - 1); - + int partyExp = 0; if (attacker.getHp() > 0) { exp *= attacker.getExpRate(); - + Integer expBonus = attacker.getBuffedValue(MapleBuffStat.EXP_INCREASE); if (expBonus != null) { // exp increase buff found thanks to HighKey21 exp += expBonus; } - + int personalExp = (int) exp; if (exp <= Integer.MAX_VALUE) { // assuming no negative xp here if (partyModifier > 0.0f) { @@ -630,7 +644,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } else { personalExp = Integer.MAX_VALUE; } - + attacker.gainExp(personalExp, partyExp, true, false, isKiller); attacker.increaseEquipExp(personalExp); attacker.updateQuestMobCount(getId()); @@ -639,7 +653,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { public MapleCharacter killBy(final MapleCharacter killer) { distributeExperience(killer != null ? killer.getId() : 0); - + final Pair lastController = aggroRemoveController(); final List toSpawn = this.getRevives(); if (toSpawn != null) { @@ -669,22 +683,22 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } } - - if(toSpawn.size() > 0) { + + if (toSpawn.size() > 0) { final EventInstanceManager eim = this.getMap().getEventInstance(); - + TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { MapleCharacter controller = lastController.getLeft(); boolean aggro = lastController.getRight(); - + for (Integer mid : toSpawn) { final MapleMonster mob = MapleLifeFactory.getMonster(mid); mob.setPosition(getPosition()); mob.setFh(getFh()); mob.setParentMobOid(getObjectId()); - + if (dropsDisabled()) { mob.disableDrops(); } @@ -693,8 +707,8 @@ public class MapleMonster extends AbstractLoadedMapleLife { if (mob.getId() >= 8810010 && mob.getId() <= 8810017 && reviveMap.isHorntailDefeated()) { boolean htKilled = false; MapleMonster ht = reviveMap.getMonsterById(8810018); - - if(ht != null) { + + if (ht != null) { ht.lockMonster(); try { htKilled = ht.isAlive(); @@ -702,21 +716,21 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { ht.unlockMonster(); } - - if(htKilled) { + + if (htKilled) { reviveMap.killMonster(ht, killer, true); ht.broadcastMobHpBar(killer); } } - - for(int i = 8810017; i >= 8810010; i--) { + + for (int i = 8810017; i >= 8810010; i--) { reviveMap.killMonster(reviveMap.getMonsterById(i), killer, true); } } else if (controller != null) { mob.aggroSwitchController(controller, aggro); } - - if(eim != null) { + + if (eim != null) { eim.reviveMonster(mob); } } @@ -726,32 +740,32 @@ public class MapleMonster extends AbstractLoadedMapleLife { } else { // is this even necessary? System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName()); } - + MapleCharacter looter = map.getCharacterById(getHighestDamagerId()); return looter != null ? looter : killer; } - + private void dispatchUpdateQuestMobCount() { Set attackerChrids = takenDamage.keySet(); - if(!attackerChrids.isEmpty()) { + if (!attackerChrids.isEmpty()) { Map mapChars = map.getMapPlayers(); - if(!mapChars.isEmpty()) { + if (!mapChars.isEmpty()) { int mobid = getId(); - + for (Integer chrid : attackerChrids) { MapleCharacter chr = mapChars.get(chrid); - if(chr != null && chr.isLoggedinWorld()) { + if (chr != null && chr.isLoggedinWorld()) { chr.updateQuestMobCount(mobid); } } } } } - + public void dispatchMonsterKilled(boolean hasKiller) { processMonsterKilled(hasKiller); - + EventInstanceManager eim = getMap().getEventInstance(); if (eim != null) { if (!this.getStats().isFriendly()) { @@ -761,15 +775,15 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } } - + private synchronized void processMonsterKilled(boolean hasKiller) { - if(!hasKiller) { // players won't gain EXP from a mob that has no killer, but a quest count they should + if (!hasKiller) { // players won't gain EXP from a mob that has no killer, but a quest count they should dispatchUpdateQuestMobCount(); } - + this.aggroClearDamages(); this.dispatchClearSummons(); - + MonsterListener[] listenersList; statiLock.lock(); try { @@ -777,11 +791,11 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + for (MonsterListener listener : listenersList) { listener.monsterKilled(getAnimationTime("die1")); } - + statiLock.lock(); try { stati.clear(); @@ -791,7 +805,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { statiLock.unlock(); } } - + private void dispatchMonsterDamaged(MapleCharacter from, int trueDmg) { MonsterListener[] listenersList; statiLock.lock(); @@ -800,12 +814,12 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + for (MonsterListener listener : listenersList) { listener.monsterDamaged(from, trueDmg); } } - + private void dispatchMonsterHealed(int trueHeal) { MonsterListener[] listenersList; statiLock.lock(); @@ -814,7 +828,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + for (MonsterListener listener : listenersList) { listener.monsterHealed(trueHeal); } @@ -835,7 +849,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { public boolean isAlive() { return this.hp.get() > 0; } - + public void addListener(MonsterListener listener) { statiLock.lock(); try { @@ -852,13 +866,15 @@ public class MapleMonster extends AbstractLoadedMapleLife { private void setController(MapleCharacter controller) { this.controller = new WeakReference<>(controller); } - + public boolean isControllerHasAggro() { return fake ? false : controllerHasAggro; } private void setControllerHasAggro(boolean controllerHasAggro) { - if (!fake) this.controllerHasAggro = controllerHasAggro; + if (!fake) { + this.controllerHasAggro = controllerHasAggro; + } } public boolean isControllerKnowsAboutAggro() { @@ -866,9 +882,11 @@ public class MapleMonster extends AbstractLoadedMapleLife { } private void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) { - if (!fake) this.controllerKnowsAboutAggro = controllerKnowsAboutAggro; + if (!fake) { + this.controllerKnowsAboutAggro = controllerKnowsAboutAggro; + } } - + private void setControllerHasPuppet(boolean controllerHasPuppet) { this.controllerHasPuppet = controllerHasPuppet; } @@ -880,7 +898,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { public boolean hasBossHPBar() { return isBoss() && getTagColor() > 0; } - + @Override public void sendSpawnData(MapleClient client) { if (hp.get() <= 0) { // mustn't monsterLock this function @@ -891,7 +909,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } else { client.announce(MaplePacketCreator.spawnMonster(this, false)); } - + statiLock.lock(); try { if (stati.size() > 0) { @@ -902,7 +920,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + if (hasBossHPBar()) { client.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket()); } @@ -931,10 +949,10 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + return getMonsterEffectiveness(e); } - + private ElementalEffectiveness getMonsterEffectiveness(Element e) { monsterLock.lock(); try { @@ -946,31 +964,31 @@ public class MapleMonster extends AbstractLoadedMapleLife { private MapleCharacter getActiveController() { MapleCharacter chr = getController(); - + if (chr != null && chr.isLoggedinWorld() && chr.getMap() == this.getMap()) { return chr; } else { return null; } } - + private void broadcastMonsterStatusMessage(byte[] packet) { map.broadcastMessage(packet, getPosition()); - + MapleCharacter chrController = getActiveController(); if (chrController != null && !chrController.isMapObjectVisible(MapleMonster.this)) { chrController.announce(packet); } } - + private int broadcastStatusEffect(final MonsterStatusEffect status) { int animationTime = status.getSkill().getAnimationTime(); byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), status, null); broadcastMonsterStatusMessage(packet); - + return animationTime; } - + public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration) { return applyStatus(from, status, poison, duration, false); } @@ -1020,7 +1038,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { final Channel ch = map.getChannelServer(); final int mapid = map.getId(); - if(statis.size() > 0) { + if (statis.size() > 0) { statiLock.lock(); try { for (MonsterStatus stat : statis.keySet()) { @@ -1036,7 +1054,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { statiLock.unlock(); } } - + final Runnable cancelTask = new Runnable() { @Override @@ -1045,7 +1063,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), status.getStati()); broadcastMonsterStatusMessage(packet); } - + statiLock.lock(); try { for (MonsterStatus stat : status.getStati().keySet()) { @@ -1054,21 +1072,21 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + setVenomMulti(0); } }; - + Runnable overtimeAction = null; int overtimeDelay = -1; - + int animationTime; if (poison) { int poisonLevel = from.getSkillLevel(status.getSkill()); int poisonDamage = Math.min(Short.MAX_VALUE, (int) (getMaxHp() / (70.0 - poisonLevel) + 0.999)); status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage)); animationTime = broadcastStatusEffect(status); - + overtimeAction = new DamageTask(poisonDamage, from, status, 0); overtimeDelay = 1000; } else if (venom) { @@ -1095,35 +1113,35 @@ public class MapleMonster extends AbstractLoadedMapleLife { status.setValue(MonsterStatus.VENOMOUS_WEAPON, Integer.valueOf(poisonDamage)); status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage)); animationTime = broadcastStatusEffect(status); - + overtimeAction = new DamageTask(poisonDamage, from, status, 0); overtimeDelay = 1000; } else { return false; } /* - } else if (status.getSkill().getId() == Hermit.SHADOW_WEB || status.getSkill().getId() == NightWalker.SHADOW_WEB) { //Shadow Web - int webDamage = (int) (getMaxHp() / 50.0 + 0.999); - status.setValue(MonsterStatus.SHADOW_WEB, Integer.valueOf(webDamage)); - animationTime = broadcastStatusEffect(status); + } else if (status.getSkill().getId() == Hermit.SHADOW_WEB || status.getSkill().getId() == NightWalker.SHADOW_WEB) { //Shadow Web + int webDamage = (int) (getMaxHp() / 50.0 + 0.999); + status.setValue(MonsterStatus.SHADOW_WEB, Integer.valueOf(webDamage)); + animationTime = broadcastStatusEffect(status); - overtimeAction = new DamageTask(webDamage, from, status, 1); - overtimeDelay = 3500; - */ + overtimeAction = new DamageTask(webDamage, from, status, 1); + overtimeDelay = 3500; + */ } else if (status.getSkill().getId() == 4121004 || status.getSkill().getId() == 4221004) { // Ninja Ambush final Skill skill = SkillFactory.getSkill(status.getSkill().getId()); final byte level = from.getSkillLevel(skill); final int damage = (int) ((from.getStr() + from.getLuk()) * ((3.7 * skill.getEffect(level).getDamage()) / 100)); - + status.setValue(MonsterStatus.NINJA_AMBUSH, Integer.valueOf(damage)); animationTime = broadcastStatusEffect(status); - + overtimeAction = new DamageTask(damage, from, status, 2); overtimeDelay = 1000; } else { animationTime = broadcastStatusEffect(status); } - + statiLock.lock(); try { for (MonsterStatus stat : status.getStati().keySet()) { @@ -1133,10 +1151,23 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + ch.registerMobStatus(mapid, status, cancelTask, duration + animationTime - 100, overtimeAction, overtimeDelay); return true; } + + public final void dispelSkill(final MobSkill skillId) { + List toCancel = new ArrayList(); + for (Entry effects : stati.entrySet()) { + MonsterStatusEffect mse = effects.getValue(); + if (mse.getMobSkill() != null && mse.getMobSkill().getSkillId() == skillId.getSkillId()) { //not checking for level. + toCancel.add(effects.getKey()); + } + } + for (MonsterStatus stat : toCancel) { + debuffMobStat(stat); + } + } public void applyMonsterBuff(final Map stats, final int x, int skillId, long duration, MobSkill skill, final List reflection) { final Runnable cancelTask = new Runnable() { @@ -1146,7 +1177,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { if (isAlive()) { byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), stats); broadcastMonsterStatusMessage(packet); - + statiLock.lock(); try { for (final MonsterStatus stat : stats.keySet()) { @@ -1161,7 +1192,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { final MonsterStatusEffect effect = new MonsterStatusEffect(stats, null, skill, true); byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), effect, reflection); broadcastMonsterStatusMessage(packet); - + statiLock.lock(); try { for (MonsterStatus stat : stats.keySet()) { @@ -1171,21 +1202,21 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + map.getChannelServer().registerMobStatus(map.getId(), effect, cancelTask, duration); } - + public void refreshMobPosition() { resetMobPosition(getPosition()); } - + public void resetMobPosition(Point newPoint) { aggroRemoveController(); - + setPosition(newPoint); map.broadcastMessage(MaplePacketCreator.moveMonster(this.getObjectId(), false, -1, 0, 0, 0, this.getPosition(), this.getIdleMovement())); map.moveMonster(this, this.getPosition()); - + aggroUpdateController(); } @@ -1197,36 +1228,44 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { statiLock.unlock(); } - + if (oldEffect != null) { byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), oldEffect.getStati()); broadcastMonsterStatusMessage(packet); } } - + public void debuffMob(int skillid) { MonsterStatus[] statups = {MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.MAGIC_ATTACK_UP, MonsterStatus.MAGIC_DEFENSE_UP}; statiLock.lock(); try { - if(skillid == Hermit.SHADOW_MESO) { + if (skillid == Hermit.SHADOW_MESO) { debuffMobStat(statups[1]); debuffMobStat(statups[3]); - } else if(skillid == Priest.DISPEL) { - for(MonsterStatus ms : statups) { + } else if (skillid == Priest.DISPEL) { + for (MonsterStatus ms : statups) { debuffMobStat(ms); } } else { // is a crash skill int i = (skillid == Crusader.ARMOR_CRASH ? 1 : (skillid == WhiteKnight.MAGIC_CRASH ? 2 : 0)); debuffMobStat(statups[i]); - if(ServerConstants.USE_ANTI_IMMUNITY_CRASH) { + if (ServerConstants.USE_ANTI_IMMUNITY_CRASH) { if (skillid == Crusader.ARMOR_CRASH) { - if(!isBuffed(MonsterStatus.WEAPON_REFLECT)) debuffMobStat(MonsterStatus.WEAPON_IMMUNITY); - if(!isBuffed(MonsterStatus.MAGIC_REFLECT)) debuffMobStat(MonsterStatus.MAGIC_IMMUNITY); + if (!isBuffed(MonsterStatus.WEAPON_REFLECT)) { + debuffMobStat(MonsterStatus.WEAPON_IMMUNITY); + } + if (!isBuffed(MonsterStatus.MAGIC_REFLECT)) { + debuffMobStat(MonsterStatus.MAGIC_IMMUNITY); + } } else if (skillid == WhiteKnight.MAGIC_CRASH) { - if(!isBuffed(MonsterStatus.MAGIC_REFLECT)) debuffMobStat(MonsterStatus.MAGIC_IMMUNITY); + if (!isBuffed(MonsterStatus.MAGIC_REFLECT)) { + debuffMobStat(MonsterStatus.MAGIC_IMMUNITY); + } } else { - if(!isBuffed(MonsterStatus.WEAPON_REFLECT)) debuffMobStat(MonsterStatus.WEAPON_IMMUNITY); + if (!isBuffed(MonsterStatus.WEAPON_REFLECT)) { + debuffMobStat(MonsterStatus.WEAPON_IMMUNITY); + } } } } @@ -1265,11 +1304,11 @@ public class MapleMonster extends AbstractLoadedMapleLife { public MapleMap getMap() { return map; } - + public MapleMonsterAggroCoordinator getMapAggroCoordinator() { return map.getAggroCoordinator(); } - + public List> getSkills() { return stats.getSkills(); } @@ -1277,72 +1316,71 @@ public class MapleMonster extends AbstractLoadedMapleLife { public boolean hasSkill(int skillId, int level) { return stats.hasSkill(skillId, level); } - + public int getSkillPos(int skillId, int level) { int pos = 0; for (Pair ms : this.getSkills()) { if (ms.getLeft() == skillId && ms.getRight() == level) { return pos; } - + pos++; } - + return -1; } - + public boolean canUseSkill(MobSkill toUse) { if (toUse == null) { return false; } - + int useSkillid = toUse.getSkillId(); if (useSkillid >= 143 && useSkillid <= 145) { if (this.isBuffed(MonsterStatus.WEAPON_REFLECT) || this.isBuffed(MonsterStatus.MAGIC_REFLECT)) { return false; } } - + monsterLock.lock(); try { /* - for (Pair skill : usedSkills) { - if (skill.getLeft() == useSkillid && skill.getRight() == toUse.getSkillLevel()) { - return false; - } - } - */ - + for (Pair skill : usedSkills) { + if (skill.getLeft() == useSkillid && skill.getRight() == toUse.getSkillLevel()) { + return false; + } + } + */ + int mpCon = toUse.getMpCon(); if (mp < mpCon) { return false; } - + /* - if (!this.applyAnimationIfRoaming(-1, toUse)) { - return false; - } - */ - + if (!this.applyAnimationIfRoaming(-1, toUse)) { + return false; + } + */ this.usedSkill(toUse); } finally { monsterLock.unlock(); } - + return true; } private void usedSkill(MobSkill skill) { final int skillId = skill.getSkillId(), level = skill.getSkillLevel(); long cooltime = skill.getCoolTime(); - + monsterLock.lock(); try { mp -= skill.getMpCon(); - + Pair skillKey = new Pair<>(skillId, level); this.usedSkills.add(skillKey); - + Integer useCount = this.skillsUsed.remove(skillKey); if (useCount != null) { this.skillsUsed.put(skillKey, useCount + 1); @@ -1352,7 +1390,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { monsterLock.unlock(); } - + final MapleMonster mons = this; MapleMap mmap = mons.getMap(); Runnable r = new Runnable() { @@ -1361,7 +1399,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { mons.clearSkill(skillId, level); } }; - + mmap.getChannelServer().registerMobClearSkillAction(mmap.getId(), r, cooltime); } @@ -1382,39 +1420,38 @@ public class MapleMonster extends AbstractLoadedMapleLife { monsterLock.unlock(); } } - + public int canUseAttack(int attackPos, boolean isSkill) { monsterLock.lock(); try { /* - if (usedAttacks.contains(attackPos)) { - return -1; - } - */ - + if (usedAttacks.contains(attackPos)) { + return -1; + } + */ + Pair attackInfo = MapleMonsterInformationProvider.getInstance().getMobAttackInfo(this.getId(), attackPos); if (attackInfo == null) { return -1; } - + int mpCon = attackInfo.getLeft(); if (mp < mpCon) { return -1; } - + /* - if (!this.applyAnimationIfRoaming(attackPos, null)) { - return -1; - } - */ - + if (!this.applyAnimationIfRoaming(attackPos, null)) { + return -1; + } + */ usedAttack(attackPos, mpCon, attackInfo.getRight()); return 1; } finally { monsterLock.unlock(); } } - + private void usedAttack(final int attackPos, int mpCon, int cooltime) { monsterLock.lock(); try { @@ -1435,7 +1472,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { monsterLock.unlock(); } } - + private void clearAttack(int attackPos) { monsterLock.lock(); try { @@ -1444,7 +1481,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { monsterLock.unlock(); } } - + public int getNoSkills() { return this.stats.getNoSkills(); } @@ -1476,11 +1513,11 @@ public class MapleMonster extends AbstractLoadedMapleLife { @Override public void run() { int curHp = hp.get(); - if(curHp <= 1) { + if (curHp <= 1) { map.getChannelServer().interruptMobStatus(map.getId(), status); return; } - + int damage = dealDamage; if (damage >= curHp) { damage = curHp - 1; @@ -1495,11 +1532,11 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { unlockMonster(); } - + if (type == 1) { map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition()); } else if (type == 2) { - if(damage < dealDamage) { // ninja ambush (type 2) is already displaying DOT to the caster + if (damage < dealDamage) { // ninja ambush (type 2) is already displaying DOT to the caster map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition()); } } @@ -1526,7 +1563,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { final ElementalEffectiveness fEE = stats.getEffectiveness(e); if (!fEE.equals(ElementalEffectiveness.WEAK)) { stats.setEffectiveness(e, ee); - + MapleMap mmap = this.getMap(); Runnable r = new Runnable() { @Override @@ -1540,7 +1577,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } }; - + mmap.getChannelServer().registerMobClearSkillAction(mmap.getId(), r, milli); } } finally { @@ -1581,7 +1618,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { statiLock.unlock(); } } - + public MonsterStatusEffect getStati(MonsterStatus ms) { statiLock.lock(); try { @@ -1590,11 +1627,10 @@ public class MapleMonster extends AbstractLoadedMapleLife { statiLock.unlock(); } } - + // ---- one can always have fun trying these pieces of codes below in-game rofl ---- - public final ChangeableStats getChangedStats() { - return ostats; + return ostats; } public final int getMobMaxHp() { @@ -1603,13 +1639,13 @@ public class MapleMonster extends AbstractLoadedMapleLife { } return stats.getHp(); } - + public final void setOverrideStats(final OverrideMonsterStats ostats) { this.ostats = new ChangeableStats(stats, ostats); this.hp.set(ostats.getHp()); this.mp = ostats.getMp(); } - + public final void changeLevel(final int newLevel) { changeLevel(newLevel, true); } @@ -1622,31 +1658,36 @@ public class MapleMonster extends AbstractLoadedMapleLife { this.hp.set(ostats.getHp()); this.mp = ostats.getMp(); } - + private float getDifficultyRate(final int difficulty) { - switch(difficulty) { - case 6: return(7.7f); - case 5: return(5.6f); - case 4: return(3.2f); - case 3: return(2.1f); - case 2: return(1.4f); + switch (difficulty) { + case 6: + return (7.7f); + case 5: + return (5.6f); + case 4: + return (3.2f); + case 3: + return (2.1f); + case 2: + return (1.4f); } - - return(1.0f); + + return (1.0f); } - + private void changeLevelByDifficulty(final int difficulty, boolean pqMob) { - changeLevel((int)(this.getLevel() * getDifficultyRate(difficulty)), pqMob); + changeLevel((int) (this.getLevel() * getDifficultyRate(difficulty)), pqMob); } - + public final void changeDifficulty(final int difficulty, boolean pqMob) { changeLevelByDifficulty(difficulty, pqMob); } - + private boolean isPuppetInVicinity(MapleSummon summon) { return summon.getPosition().distanceSq(this.getPosition()) < 177777; } - + public boolean isCharacterPuppetInVicinity(MapleCharacter chr) { MapleStatEffect mse = chr.getBuffEffect(MapleBuffStat.PUPPET); if (mse != null) { @@ -1661,31 +1702,31 @@ public class MapleMonster extends AbstractLoadedMapleLife { map.getAggroCoordinator().removePuppetAggro(chr.getId()); } } - + return false; } - + public boolean isLeadingPuppetInVicinity() { MapleCharacter chrController = this.getActiveController(); - + if (chrController != null) { if (this.isCharacterPuppetInVicinity(chrController)) { return true; } } - + return false; } - + private MapleCharacter getNextControllerCandidate() { int mincontrolled = Integer.MAX_VALUE; MapleCharacter newController = null; - + int mincontrolleddead = Integer.MAX_VALUE; MapleCharacter newControllerDead = null; - + MapleCharacter newControllerWithPuppet = null; - + for (MapleCharacter chr : getMap().getAllPlayers()) { if (!chr.isHidden()) { int ctrlMonsSize = chr.getNumControlledMonsters(); @@ -1706,7 +1747,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } } - + if (newControllerWithPuppet != null) { return newControllerWithPuppet; } else if (newController != null) { @@ -1715,39 +1756,39 @@ public class MapleMonster extends AbstractLoadedMapleLife { return newControllerDead; } } - + /** * Removes controllability status from the current controller of this mob. - * + * */ private Pair aggroRemoveController() { MapleCharacter chrController; boolean hadAggro; - + aggroUpdateLock.lock(); try { chrController = getActiveController(); hadAggro = isControllerHasAggro(); - + this.setController(null); this.setControllerHasAggro(false); this.setControllerKnowsAboutAggro(false); } finally { aggroUpdateLock.unlock(); } - + if (chrController != null) { // this can/should only happen when a hidden gm attacks the monster chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId())); chrController.stopControllingMonster(this); } - + return new Pair<>(chrController, hadAggro); } - + /** * Pass over the mob controllability and updates aggro status on the new * player controller. - * + * */ public void aggroSwitchController(MapleCharacter newController, boolean immediateAggro) { if (aggroUpdateLock.tryLock()) { @@ -1756,12 +1797,12 @@ public class MapleMonster extends AbstractLoadedMapleLife { if (prevController == newController) { return; } - + aggroRemoveController(); if (!(newController != null && newController.isLoggedinWorld() && newController.getMap() == this.getMap())) { return; } - + this.setController(newController); this.setControllerHasAggro(immediateAggro); this.setControllerKnowsAboutAggro(false); @@ -1769,63 +1810,63 @@ public class MapleMonster extends AbstractLoadedMapleLife { } finally { aggroUpdateLock.unlock(); } - + this.aggroUpdatePuppetVisibility(); newController.announce(MaplePacketCreator.controlMonster(this, false, immediateAggro)); newController.controlMonster(this); } } - + public void aggroAddPuppet(MapleCharacter player) { MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator(); mmac.addPuppetAggro(player); - + aggroUpdatePuppetController(player); - + if (this.isControllerHasAggro()) { this.aggroUpdatePuppetVisibility(); } } - + public void aggroRemovePuppet(MapleCharacter player) { MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator(); mmac.removePuppetAggro(player.getId()); - + aggroUpdatePuppetController(null); - + if (this.isControllerHasAggro()) { this.aggroUpdatePuppetVisibility(); } } - + /** * Automagically finds a new controller for the given monster from the chars * on the map it is from... - * + * */ public void aggroUpdateController() { MapleCharacter chrController = this.getActiveController(); if (chrController != null && chrController.isAlive()) { return; } - + MapleCharacter newController = getNextControllerCandidate(); if (newController == null) { // was a new controller found? (if not no one is on the map) return; } - + this.aggroSwitchController(newController, false); } - + /** - * Finds a new controller for the given monster from the chars with deployed puppet - * nearby on the map it is from... - * + * Finds a new controller for the given monster from the chars with deployed + * puppet nearby on the map it is from... + * */ private void aggroUpdatePuppetController(MapleCharacter newController) { MapleCharacter chrController = this.getActiveController(); boolean updateController = false; - + if (chrController != null && chrController.isAlive()) { if (isCharacterPuppetInVicinity(chrController)) { return; @@ -1833,13 +1874,13 @@ public class MapleMonster extends AbstractLoadedMapleLife { } else { updateController = true; } - + if (newController == null || !isCharacterPuppetInVicinity(newController)) { MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator(); - + List puppetOwners = mmac.getPuppetAggroList(); List toRemovePuppets = new LinkedList<>(); - + for (Integer cid : puppetOwners) { MapleCharacter chr = map.getCharacterById(cid); @@ -1856,35 +1897,35 @@ public class MapleMonster extends AbstractLoadedMapleLife { for (Integer cid : toRemovePuppets) { mmac.removePuppetAggro(cid); } - + if (newController == null) { // was a new controller found? (if not there's no puppet nearby) if (updateController) { aggroUpdateController(); } - + return; } } else if (chrController == newController) { this.aggroUpdatePuppetVisibility(); } - + this.aggroSwitchController(newController, this.isControllerHasAggro()); } - + /** * Ensures controllability removal of the current player controller, and * fetches for any player on the map to start controlling in place. - * + * */ public void aggroRedirectController() { this.aggroRemoveController(); // don't care if new controller not found, at least remove current controller this.aggroUpdateController(); } - + /** * Returns the current aggro status on the specified player, or null if the * specified player is currently not this mob's controller. - * + * */ public Boolean aggroMoveLifeUpdate(MapleCharacter player) { MapleCharacter chrController = getController(); @@ -1893,37 +1934,37 @@ public class MapleMonster extends AbstractLoadedMapleLife { if (aggro) { this.setControllerKnowsAboutAggro(true); } - + return aggro; } else { return null; } } - + /** * Refreshes auto aggro for the player passed as parameter, does nothing if * there is already an active controller for this mob. - * + * */ public void aggroAutoAggroUpdate(MapleCharacter player) { MapleCharacter chrController = this.getActiveController(); - + if (chrController == null) { this.aggroSwitchController(player, true); } else if (chrController.getId() == player.getId()) { this.setControllerHasAggro(true); } } - + /** - * Applied damage input for this mob, enough damage taken implies - * an aggro target update for the attacker shortly. - * + * Applied damage input for this mob, enough damage taken implies an aggro + * target update for the attacker shortly. + * */ public void aggroMonsterDamage(MapleCharacter attacker, int damage) { MapleMonsterAggroCoordinator mmac = this.getMapAggroCoordinator(); mmac.addAggroDamage(this, attacker.getId(), damage); - + MapleCharacter chrController = this.getController(); // aggro based on DPS rather than first-come-first-served, now live after suggestions thanks to MedicOP, Thora, Vcoc if (chrController != attacker) { if (this.getMapAggroCoordinator().isLeadingCharacterAggro(this, attacker)) { @@ -1932,53 +1973,57 @@ public class MapleMonster extends AbstractLoadedMapleLife { this.setControllerHasAggro(true); this.aggroUpdatePuppetVisibility(); } - + /* - For some reason, some mobs loses aggro on controllers if other players also attacks them. - Maybe it was intended by Nexon to interchange controllers at every attack... + For some reason, some mobs loses aggro on controllers if other players also attacks them. + Maybe it was intended by Nexon to interchange controllers at every attack... - else if (chrController != null) { - chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId())); - chrController.announce(MaplePacketCreator.controlMonster(this, false, true)); - } - */ + else if (chrController != null) { + chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId())); + chrController.announce(MaplePacketCreator.controlMonster(this, false, true)); + } + */ } else { this.setControllerHasAggro(true); this.aggroUpdatePuppetVisibility(); } } - + private void aggroRefreshPuppetVisibility(MapleCharacter chrController, MapleSummon puppet) { // lame patch for client to redirect all aggro to the puppet - + List puppetControlled = new LinkedList<>(); for (MapleMonster mob : chrController.getControlledMonsters()) { if (mob.isPuppetInVicinity(puppet)) { puppetControlled.add(mob); } } - + for (MapleMonster mob : puppetControlled) { chrController.announce(MaplePacketCreator.stopControllingMonster(mob.getObjectId())); } chrController.announce(MaplePacketCreator.removeSummon(puppet, false)); - + for (MapleMonster mob : puppetControlled) { chrController.announce(MaplePacketCreator.controlMonster(mob, false, mob.isControllerHasAggro())); } chrController.announce(MaplePacketCreator.spawnSummon(puppet, false)); } - + public void aggroUpdatePuppetVisibility() { - if (!availablePuppetUpdate) return; - + if (!availablePuppetUpdate) { + return; + } + availablePuppetUpdate = false; Runnable r = new Runnable() { @Override public void run() { try { MapleCharacter chrController = MapleMonster.this.getActiveController(); - if (chrController == null) return; + if (chrController == null) { + return; + } MapleStatEffect puppetEffect = chrController.getBuffEffect(MapleBuffStat.PUPPET); if (puppetEffect != null) { @@ -2002,14 +2047,15 @@ public class MapleMonster extends AbstractLoadedMapleLife { } } }; - + // had to schedule this since mob wouldn't stick to puppet aggro who knows why this.getMap().getChannelServer().registerOverallAction(this.getMap().getId(), r, ServerConstants.UPDATE_INTERVAL); } - + /** - * Clears all applied damage input for this mob, doesn't refresh target aggro. - * + * Clears all applied damage input for this mob, doesn't refresh target + * aggro. + * */ public void aggroClearDamages() { this.getMapAggroCoordinator().removeAggroEntries(this); @@ -2017,7 +2063,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { /** * Clears this mob aggro on the current controller. - * + * */ public void aggroResetAggro() { aggroUpdateLock.lock(); @@ -2028,12 +2074,12 @@ public class MapleMonster extends AbstractLoadedMapleLife { aggroUpdateLock.unlock(); } } - + public void dispose() { this.getMap().dismissRemoveAfter(this); disposeLocks(); } - + private void disposeLocks() { LockCollector.getInstance().registerDisposeAction(new Runnable() { @Override @@ -2042,11 +2088,15 @@ public class MapleMonster extends AbstractLoadedMapleLife { } }); } - + private void emptyLocks() { externalLock = externalLock.dispose(); monsterLock = monsterLock.dispose(); statiLock = statiLock.dispose(); animationLock = animationLock.dispose(); } + + public final int getRemoveAfter() { + return stats.removeAfter(); + } } diff --git a/src/server/life/MapleMonsterInformationProvider.java b/src/server/life/MapleMonsterInformationProvider.java index 901526b33e..4854d125be 100644 --- a/src/server/life/MapleMonsterInformationProvider.java +++ b/src/server/life/MapleMonsterInformationProvider.java @@ -44,306 +44,308 @@ import tools.Pair; import tools.Randomizer; public class MapleMonsterInformationProvider { - // Author : LightPepsi + // Author : LightPepsi - private static final MapleMonsterInformationProvider instance = new MapleMonsterInformationProvider(); - - public static MapleMonsterInformationProvider getInstance() { - return instance; - } - - private final Map> drops = new HashMap<>(); - private final List globaldrops = new ArrayList<>(); - private final Map> continentdrops = new HashMap<>(); - - private final Map> dropsChancePool = new HashMap<>(); // thanks to ronan - private final Set hasNoMultiEquipDrops = new HashSet<>(); - private final Map> extraMultiEquipDrops = new HashMap<>(); - - private final Map, Integer> mobAttackAnimationTime = new HashMap<>(); - private final Map mobSkillAnimationTime = new HashMap<>(); - - private final Map> mobAttackInfo = new HashMap<>(); - - private final Map mobBossCache = new HashMap<>(); - private final Map mobNameCache = new HashMap<>(); + private static final MapleMonsterInformationProvider instance = new MapleMonsterInformationProvider(); - protected MapleMonsterInformationProvider() { - retrieveGlobal(); - } - - public final List getRelevantGlobalDrops(int mapid) { - int continentid = mapid / 100000000; - - List contiItems = continentdrops.get(continentid); - if (contiItems == null) { // continent separated global drops found thanks to marcuswoon - contiItems = new ArrayList<>(); - - for (MonsterGlobalDropEntry e : globaldrops) { - if (e.continentid < 0 || e.continentid == continentid) { - contiItems.add(e); - } + public static MapleMonsterInformationProvider getInstance() { + return instance; + } + + private final Map> drops = new HashMap<>(); + private final List globaldrops = new ArrayList<>(); + private final Map> continentdrops = new HashMap<>(); + + private final Map> dropsChancePool = new HashMap<>(); // thanks to ronan + private final Set hasNoMultiEquipDrops = new HashSet<>(); + private final Map> extraMultiEquipDrops = new HashMap<>(); + + private final Map, Integer> mobAttackAnimationTime = new HashMap<>(); + private final Map mobSkillAnimationTime = new HashMap<>(); + + private final Map> mobAttackInfo = new HashMap<>(); + + private final Map mobBossCache = new HashMap<>(); + private final Map mobNameCache = new HashMap<>(); + + protected MapleMonsterInformationProvider() { + retrieveGlobal(); + } + + public final List getRelevantGlobalDrops(int mapid) { + int continentid = mapid / 100000000; + + List contiItems = continentdrops.get(continentid); + if (contiItems == null) { // continent separated global drops found thanks to marcuswoon + contiItems = new ArrayList<>(); + + for (MonsterGlobalDropEntry e : globaldrops) { + if (e.continentid < 0 || e.continentid == continentid) { + contiItems.add(e); + } + } + + continentdrops.put(continentid, contiItems); + } + + return contiItems; + } + + private void retrieveGlobal() { + PreparedStatement ps = null; + ResultSet rs = null; + Connection con = null; + + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT * FROM drop_data_global WHERE chance > 0"); + rs = ps.executeQuery(); + + while (rs.next()) { + globaldrops.add( + new MonsterGlobalDropEntry( + rs.getInt("itemid"), + rs.getInt("chance"), + rs.getByte("continent"), + rs.getInt("minimum_quantity"), + rs.getInt("maximum_quantity"), + rs.getShort("questid"))); + } + + rs.close(); + ps.close(); + con.close(); + } catch (SQLException e) { + System.err.println("Error retrieving drop" + e); + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); + } + if (rs != null && !rs.isClosed()) { + rs.close(); + } + if (con != null && !con.isClosed()) { + con.close(); + } + } catch (SQLException ignore) { + ignore.printStackTrace(); + } + } + } + + public List retrieveEffectiveDrop(final int monsterId) { + // this reads the drop entries searching for multi-equip, properly processing them + + List list = retrieveDrop(monsterId); + if (hasNoMultiEquipDrops.contains(monsterId) || !ServerConstants.USE_MULTIPLE_SAME_EQUIP_DROP) { + return list; + } + + List multiDrops = extraMultiEquipDrops.get(monsterId), extra = new LinkedList<>(); + if (multiDrops == null) { + multiDrops = new LinkedList<>(); + + for (MonsterDropEntry mde : list) { + if (ItemConstants.isEquipment(mde.itemId) && mde.Maximum > 1) { + multiDrops.add(mde); + + int rnd = Randomizer.rand(mde.Minimum, mde.Maximum); + for (int i = 0; i < rnd - 1; i++) { + extra.add(mde); // this passes copies of the equips' MDE with min/max quantity > 1, but idc it'll be unused anyways } - - continentdrops.put(continentid, contiItems); } - - return contiItems; - } + } - private void retrieveGlobal() { - PreparedStatement ps = null; - ResultSet rs = null; - Connection con = null; - - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT * FROM drop_data_global WHERE chance > 0"); - rs = ps.executeQuery(); - - while (rs.next()) { - globaldrops.add( - new MonsterGlobalDropEntry( - rs.getInt("itemid"), - rs.getInt("chance"), - rs.getByte("continent"), - rs.getInt("minimum_quantity"), - rs.getInt("maximum_quantity"), - rs.getShort("questid"))); - } - - rs.close(); - ps.close(); - con.close(); - } catch (SQLException e) { - System.err.println("Error retrieving drop" + e); - } finally { - try { - if (ps != null && !ps.isClosed()) { - ps.close(); - } - if (rs != null && !rs.isClosed()) { - rs.close(); - } - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException ignore) { - ignore.printStackTrace(); - } - } - } - - public List retrieveEffectiveDrop(final int monsterId) { - // this reads the drop entries searching for multi-equip, properly processing them - - List list = retrieveDrop(monsterId); - if (hasNoMultiEquipDrops.contains(monsterId) || !ServerConstants.USE_MULTIPLE_SAME_EQUIP_DROP) { - return list; - } - - List multiDrops = extraMultiEquipDrops.get(monsterId), extra = new LinkedList<>(); - if(multiDrops == null) { - multiDrops = new LinkedList<>(); - - for(MonsterDropEntry mde : list) { - if(ItemConstants.isEquipment(mde.itemId) && mde.Maximum > 1) { - multiDrops.add(mde); - - int rnd = Randomizer.rand(mde.Minimum, mde.Maximum); - for(int i = 0; i < rnd - 1; i++) { - extra.add(mde); // this passes copies of the equips' MDE with min/max quantity > 1, but idc it'll be unused anyways - } - } - } - - if(!multiDrops.isEmpty()) extraMultiEquipDrops.put(monsterId, multiDrops); - else hasNoMultiEquipDrops.add(monsterId); - } else { - for(MonsterDropEntry mde : multiDrops) { - int rnd = Randomizer.rand(mde.Minimum, mde.Maximum); - for(int i = 0; i < rnd - 1; i++) { - extra.add(mde); - } - } + if (!multiDrops.isEmpty()) { + extraMultiEquipDrops.put(monsterId, multiDrops); + } else { + hasNoMultiEquipDrops.add(monsterId); + } + } else { + for (MonsterDropEntry mde : multiDrops) { + int rnd = Randomizer.rand(mde.Minimum, mde.Maximum); + for (int i = 0; i < rnd - 1; i++) { + extra.add(mde); } - - List ret = new LinkedList<>(list); - ret.addAll(extra); - + } + } + + List ret = new LinkedList<>(list); + ret.addAll(extra); + + return ret; + } + + public final List retrieveDrop(final int monsterId) { + if (drops.containsKey(monsterId)) { + return drops.get(monsterId); + } + final List ret = new LinkedList<>(); + + if (monsterId >= 9300127 && monsterId <= 9300136 || monsterId >= 9300315 && monsterId <= 9300324) { + int dropArray[] = {2022157, 2022158, 2022159, 2022160, 2022161, 2022162, 2022163, 2022164, 2022165, 2022166, 2022167, 2022168, 2022169, 2022170, 2022171, 2022172, 2022173, 2022174, 2022175, 2022176, 2022177, 2022178, 4001129}; //These are the drops, -1 means meso :D + for (int id : dropArray) { + ret.add(new MonsterDropEntry(id, 2000, 1, 1, (short) 0)); + } + } else { + PreparedStatement ps = null; + ResultSet rs = null; + Connection con = null; + try { + con = DatabaseConnection.getConnection(); + ps = con.prepareStatement("SELECT itemid, chance, minimum_quantity, maximum_quantity, questid FROM drop_data WHERE dropperid = ?"); + ps.setInt(1, monsterId); + rs = ps.executeQuery(); + + while (rs.next()) { + ret.add(new MonsterDropEntry(rs.getInt("itemid"), rs.getInt("chance"), rs.getInt("minimum_quantity"), rs.getInt("maximum_quantity"), rs.getShort("questid"))); + } + + con.close(); + } catch (SQLException e) { + e.printStackTrace(); return ret; - } - - public final List retrieveDrop(final int monsterId) { - if (drops.containsKey(monsterId)) { - return drops.get(monsterId); - } - final List ret = new LinkedList<>(); - - PreparedStatement ps = null; - ResultSet rs = null; - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT itemid, chance, minimum_quantity, maximum_quantity, questid FROM drop_data WHERE dropperid = ?"); - ps.setInt(1, monsterId); - rs = ps.executeQuery(); - - while (rs.next()) { - ret.add( - new MonsterDropEntry( - rs.getInt("itemid"), - rs.getInt("chance"), - rs.getInt("minimum_quantity"), - rs.getInt("maximum_quantity"), - rs.getShort("questid"))); - } - + } finally { + try { + if (ps != null && !ps.isClosed()) { + ps.close(); + } + if (rs != null && !rs.isClosed()) { + rs.close(); + } + if (con != null && !con.isClosed()) { con.close(); - } catch (SQLException e) { - e.printStackTrace(); - return ret; - } finally { - try { - if (ps != null && !ps.isClosed()) { - ps.close(); - } - if (rs != null && !rs.isClosed()) { - rs.close(); - } - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException ignore) { - ignore.printStackTrace(); - return ret; - } - } - drops.put(monsterId, ret); - return ret; - } - - public final List retrieveDropPool(final int monsterId) { // ignores Quest and Party Quest items - if (dropsChancePool.containsKey(monsterId)) { - return dropsChancePool.get(monsterId); - } - - MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - - List dropList = retrieveDrop(monsterId); - List ret = new ArrayList<>(); - - int accProp = 0; - for(MonsterDropEntry mde : dropList) { - if(!ii.isQuestItem(mde.itemId) && !ii.isPartyQuestItem(mde.itemId)) { - accProp += mde.chance; - } - - ret.add(accProp); + } + } catch (SQLException ignore) { + ignore.printStackTrace(); + return ret; } - - if(accProp == 0) ret.clear(); // don't accept mobs dropping no relevant items - - dropsChancePool.put(monsterId, ret); - return ret; - } - - public final void setMobAttackAnimationTime(int monsterId, int attackPos, int animationTime) { - mobAttackAnimationTime.put(new Pair<>(monsterId, attackPos), animationTime); + } } - - public final Integer getMobAttackAnimationTime(int monsterId, int attackPos) { - Integer time = mobAttackAnimationTime.get(new Pair<>(monsterId, attackPos)); - return time == null ? 0 : time; - } - - public final void setMobSkillAnimationTime(MobSkill skill, int animationTime) { - mobSkillAnimationTime.put(skill, animationTime); - } - - public final Integer getMobSkillAnimationTime(MobSkill skill) { - Integer time = mobSkillAnimationTime.get(skill); - return time == null ? 0 : time; - } - - public final void setMobAttackInfo(int monsterId, int attackPos, int mpCon, int coolTime) { - mobAttackInfo.put((monsterId << 3) + attackPos, new Pair<>(mpCon, coolTime)); - } - - public final Pair getMobAttackInfo(int monsterId, int attackPos) { - if (attackPos < 0 || attackPos > 7) return null; - return mobAttackInfo.get((monsterId << 3) + attackPos); + drops.put(monsterId, ret); + return ret; + } + + public final List retrieveDropPool(final int monsterId) { // ignores Quest and Party Quest items + if (dropsChancePool.containsKey(monsterId)) { + return dropsChancePool.get(monsterId); } - public static ArrayList> getMobsIDsFromName(String search) { - MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz")); - ArrayList> retMobs = new ArrayList>(); - MapleData data = dataProvider.getData("Mob.img"); - List> mobPairList = new LinkedList>(); - for (MapleData mobIdData : data.getChildren()) { - int mobIdFromData = Integer.parseInt(mobIdData.getName()); - String mobNameFromData = MapleDataTool.getString(mobIdData.getChildByPath("name"), "NO-NAME"); - mobPairList.add(new Pair(mobIdFromData, mobNameFromData)); - } - for (Pair mobPair : mobPairList) { - if (mobPair.getRight().toLowerCase().contains(search.toLowerCase())) { - retMobs.add(mobPair); - } - } - return retMobs; - } + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - public boolean isBoss(int id) { - Boolean boss = mobBossCache.get(id); - if (boss == null) { - try { - boss = MapleLifeFactory.getMonster(id).isBoss(); - } catch (NullPointerException npe) { - boss = false; - } catch (Exception e) { //nonexistant mob - boss = false; - - e.printStackTrace(); - System.err.println("Nonexistant mob id " + id); - } - - mobBossCache.put(id, boss); - } - - return boss; - } - - public String getMobNameFromId(int id) { - String mobName = mobNameCache.get(id); - if (mobName == null) { - try - { - mobName = MapleLifeFactory.getMonster(id).getName(); - } - catch (NullPointerException npe) - { - mobName = ""; //nonexistant mob - } - catch (Exception e) - { - e.printStackTrace(); - System.err.println("Nonexistant mob id " + id); - mobName = ""; //nonexistant mob - } - - mobNameCache.put(id, mobName); - } - - return mobName; - } + List dropList = retrieveDrop(monsterId); + List ret = new ArrayList<>(); - public final void clearDrops() { - drops.clear(); - hasNoMultiEquipDrops.clear(); - extraMultiEquipDrops.clear(); - dropsChancePool.clear(); - globaldrops.clear(); - continentdrops.clear(); - retrieveGlobal(); - } -} \ No newline at end of file + int accProp = 0; + for (MonsterDropEntry mde : dropList) { + if (!ii.isQuestItem(mde.itemId) && !ii.isPartyQuestItem(mde.itemId)) { + accProp += mde.chance; + } + + ret.add(accProp); + } + + if (accProp == 0) { + ret.clear(); // don't accept mobs dropping no relevant items + } + dropsChancePool.put(monsterId, ret); + return ret; + } + + public final void setMobAttackAnimationTime(int monsterId, int attackPos, int animationTime) { + mobAttackAnimationTime.put(new Pair<>(monsterId, attackPos), animationTime); + } + + public final Integer getMobAttackAnimationTime(int monsterId, int attackPos) { + Integer time = mobAttackAnimationTime.get(new Pair<>(monsterId, attackPos)); + return time == null ? 0 : time; + } + + public final void setMobSkillAnimationTime(MobSkill skill, int animationTime) { + mobSkillAnimationTime.put(skill, animationTime); + } + + public final Integer getMobSkillAnimationTime(MobSkill skill) { + Integer time = mobSkillAnimationTime.get(skill); + return time == null ? 0 : time; + } + + public final void setMobAttackInfo(int monsterId, int attackPos, int mpCon, int coolTime) { + mobAttackInfo.put((monsterId << 3) + attackPos, new Pair<>(mpCon, coolTime)); + } + + public final Pair getMobAttackInfo(int monsterId, int attackPos) { + if (attackPos < 0 || attackPos > 7) { + return null; + } + return mobAttackInfo.get((monsterId << 3) + attackPos); + } + + public static ArrayList> getMobsIDsFromName(String search) { + MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz")); + ArrayList> retMobs = new ArrayList>(); + MapleData data = dataProvider.getData("Mob.img"); + List> mobPairList = new LinkedList>(); + for (MapleData mobIdData : data.getChildren()) { + int mobIdFromData = Integer.parseInt(mobIdData.getName()); + String mobNameFromData = MapleDataTool.getString(mobIdData.getChildByPath("name"), "NO-NAME"); + mobPairList.add(new Pair(mobIdFromData, mobNameFromData)); + } + for (Pair mobPair : mobPairList) { + if (mobPair.getRight().toLowerCase().contains(search.toLowerCase())) { + retMobs.add(mobPair); + } + } + return retMobs; + } + + public boolean isBoss(int id) { + Boolean boss = mobBossCache.get(id); + if (boss == null) { + try { + boss = MapleLifeFactory.getMonster(id).isBoss(); + } catch (NullPointerException npe) { + boss = false; + } catch (Exception e) { //nonexistant mob + boss = false; + + e.printStackTrace(); + System.err.println("Nonexistant mob id " + id); + } + + mobBossCache.put(id, boss); + } + + return boss; + } + + public String getMobNameFromId(int id) { + String mobName = mobNameCache.get(id); + if (mobName == null) { + try { + mobName = MapleLifeFactory.getMonster(id).getName(); + } catch (NullPointerException npe) { + mobName = ""; //nonexistant mob + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Nonexistant mob id " + id); + mobName = ""; //nonexistant mob + } + + mobNameCache.put(id, mobName); + } + + return mobName; + } + + public final void clearDrops() { + drops.clear(); + hasNoMultiEquipDrops.clear(); + extraMultiEquipDrops.clear(); + dropsChancePool.clear(); + globaldrops.clear(); + continentdrops.clear(); + retrieveGlobal(); + } +} diff --git a/src/server/life/MobSkill.java b/src/server/life/MobSkill.java index c58775a0db..03606d2e5e 100644 --- a/src/server/life/MobSkill.java +++ b/src/server/life/MobSkill.java @@ -1,24 +1,24 @@ /* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + 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 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. + 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 . -*/ + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ package server.life; import java.awt.Point; @@ -44,6 +44,7 @@ import tools.ArrayMap; * @author Danny (Leifde) */ public class MobSkill { + private int skillId, skillLevel, mpCon; private List toSummon = new ArrayList(); private int spawnEffect, hp, x, y; @@ -106,17 +107,17 @@ public class MobSkill { public void applyDelayedEffect(final MapleCharacter player, final MapleMonster monster, final boolean skill, int animationTime) { Runnable toRun = new Runnable() { - @Override - public void run() { - if(monster.isAlive()) { - applyEffect(player, monster, skill, null); - } - } - }; - + @Override + public void run() { + if (monster.isAlive()) { + applyEffect(player, monster, skill, null); + } + } + }; + monster.getMap().getChannelServer().registerOverallAction(monster.getMap().getId(), toRun, animationTime); } - + public void applyEffect(MapleCharacter player, MapleMonster monster, boolean skill, List banishPlayers) { MapleDisease disease = null; Map stats = new ArrayMap(); @@ -142,50 +143,50 @@ public class MobSkill { case 153: stats.put(MonsterStatus.MAGIC_DEFENSE_UP, Integer.valueOf(x)); break; - case 114: - if (lt != null && rb != null && skill) { - List objects = getObjectsInRange(monster, MapleMapObjectType.MONSTER); - final int hps = (getX() / 1000) * (int) (950 + 1050 * Math.random()); - for (MapleMapObject mons : objects) { - ((MapleMonster) mons).heal(hps, getY()); - } - } else { - monster.heal(getX(), getY()); - } - break; - case 120: + case 114: + if (lt != null && rb != null && skill) { + List objects = getObjectsInRange(monster, MapleMapObjectType.MONSTER); + final int hps = (getX() / 1000) * (int) (950 + 1050 * Math.random()); + for (MapleMapObject mons : objects) { + ((MapleMonster) mons).heal(hps, getY()); + } + } else { + monster.heal(getX(), getY()); + } + break; + case 120: disease = MapleDisease.SEAL; - break; - case 121: - disease = MapleDisease.DARKNESS; - break; - case 122: - disease = MapleDisease.WEAKEN; - break; - case 123: - disease = MapleDisease.STUN; - break; - case 124: - disease = MapleDisease.CURSE; - break; - case 125: - disease = MapleDisease.POISON; - break; - case 126: // Slow - disease = MapleDisease.SLOW; - break; - case 127: - if (lt != null && rb != null && skill) { - for (MapleCharacter character : getPlayersInRange(monster, player)) { - character.dispel(); - } - } else { - player.dispel(); - } - break; - case 128: // Seduce - disease = MapleDisease.SEDUCE; - break; + break; + case 121: + disease = MapleDisease.DARKNESS; + break; + case 122: + disease = MapleDisease.WEAKEN; + break; + case 123: + disease = MapleDisease.STUN; + break; + case 124: + disease = MapleDisease.CURSE; + break; + case 125: + disease = MapleDisease.POISON; + break; + case 126: // Slow + disease = MapleDisease.SLOW; + break; + case 127: + if (lt != null && rb != null && skill) { + for (MapleCharacter character : getPlayersInRange(monster, player)) { + character.dispel(); + } + } else { + player.dispel(); + } + break; + case 128: // Seduce + disease = MapleDisease.SEDUCE; + break; case 129: // Banish if (lt != null && rb != null && skill) { for (MapleCharacter chr : getPlayersInRange(monster, player)) { @@ -214,35 +215,40 @@ public class MobSkill { stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(x)); } break; - case 143: // Weapon Reflect - stats.put(MonsterStatus.WEAPON_REFLECT, 10); - stats.put(MonsterStatus.WEAPON_IMMUNITY, 10); - reflection.add(x); - break; - case 144: // Magic Reflect - stats.put(MonsterStatus.MAGIC_REFLECT, 10); - stats.put(MonsterStatus.MAGIC_IMMUNITY, 10); - reflection.add(x); - break; - case 145: // Weapon / Magic reflect - stats.put(MonsterStatus.WEAPON_REFLECT, 10); - stats.put(MonsterStatus.WEAPON_IMMUNITY, 10); - stats.put(MonsterStatus.MAGIC_REFLECT, 10); - stats.put(MonsterStatus.MAGIC_IMMUNITY, 10); - reflection.add(x); + case 143: // Weapon Reflect + stats.put(MonsterStatus.WEAPON_REFLECT, 10); + stats.put(MonsterStatus.WEAPON_IMMUNITY, 10); + reflection.add(x); break; - case 154: // accuracy up - case 155: // avoid up - case 156: // speed up + case 144: // Magic Reflect + stats.put(MonsterStatus.MAGIC_REFLECT, 10); + stats.put(MonsterStatus.MAGIC_IMMUNITY, 10); + reflection.add(x); + break; + case 145: // Weapon / Magic reflect + stats.put(MonsterStatus.WEAPON_REFLECT, 10); + stats.put(MonsterStatus.WEAPON_IMMUNITY, 10); + stats.put(MonsterStatus.MAGIC_REFLECT, 10); + stats.put(MonsterStatus.MAGIC_IMMUNITY, 10); + reflection.add(x); + break; + case 154: + stats.put(MonsterStatus.ACC, Integer.valueOf(x)); + break; + case 155: + stats.put(MonsterStatus.AVOID, Integer.valueOf(x)); + break; + case 156: + stats.put(MonsterStatus.SPEED, Integer.valueOf(x)); break; case 200: // summon int skillLimit = this.getLimit(); MapleMap map = monster.getMap(); - + if (map.isDojoMap()) { // spawns in dojo should be unlimited skillLimit = Integer.MAX_VALUE; } - + if (map.getSpawnedMonstersOnMap() < 80) { List summons = getSummons(); int summonLimit = monster.countAvailableMobSummons(summons.size(), skillLimit); @@ -252,9 +258,10 @@ public class MobSkill { for (Integer mobId : summons.subList(0, summonLimit)) { MapleMonster toSpawn = MapleLifeFactory.getMonster(mobId); - if(toSpawn != null) { - if(bossRushMap) toSpawn.disableDrops(); // no littering on BRPQ pls - + if (toSpawn != null) { + if (bossRushMap) { + toSpawn.disableDrops(); // no littering on BRPQ pls + } toSpawn.setPosition(monster.getPosition()); int ypos, xpos; xpos = (int) monster.getPosition().getX(); @@ -277,7 +284,7 @@ public class MobSkill { } else { xpos = (int) (monster.getPosition().getX() + Randomizer.nextInt(1000) - 500); } - break; + break; } switch (map.getId()) { case 220080001: //Pap map @@ -297,9 +304,9 @@ public class MobSkill { } toSpawn.setPosition(new Point(xpos, ypos)); if (toSpawn.getId() == 8500004) { - map.spawnFakeMonster(toSpawn); + map.spawnFakeMonster(toSpawn); } else { - map.spawnMonsterWithEffect(toSpawn, getSpawnEffect(), toSpawn.getPosition()); + map.spawnMonsterWithEffect(toSpawn, getSpawnEffect(), toSpawn.getPosition()); } monster.addSummonedMob(toSpawn); } diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java index c0e6908dea..c6a926fde4 100644 --- a/src/server/maps/MapleMap.java +++ b/src/server/maps/MapleMap.java @@ -83,21 +83,24 @@ import server.life.MapleNPC; import server.life.MonsterDropEntry; import server.life.MonsterGlobalDropEntry; import server.life.SpawnPoint; -import server.partyquest.MonsterCarnival; -import server.partyquest.MonsterCarnivalParty; -//import server.partyquest.Pyramid; import scripting.event.EventInstanceManager; import server.life.MaplePlayerNPC; +import server.life.MobSkill; +import server.life.MobSkillFactory; import server.life.MonsterListener; +import server.partyquest.GuardianSpawnPoint; +import server.partyquest.MapleCarnivalFactory; +import server.partyquest.MapleCarnivalFactory.MCSkill; import tools.FilePrinter; import tools.MaplePacketCreator; import tools.Pair; import tools.Randomizer; public class MapleMap { + private static final List rangedMapobjectTypes = Arrays.asList(MapleMapObjectType.SHOP, MapleMapObjectType.ITEM, MapleMapObjectType.NPC, MapleMapObjectType.MONSTER, MapleMapObjectType.DOOR, MapleMapObjectType.SUMMON, MapleMapObjectType.REACTOR); private static final Map> dropBoundsCache = new HashMap<>(100); - + private Map mapobjects = new LinkedHashMap<>(); private Collection monsterSpawn = Collections.synchronizedList(new LinkedList()); private Collection allMonsterSpawn = Collections.synchronizedList(new LinkedList()); @@ -150,7 +153,7 @@ public class MapleMap { private Pair timeMob = null; private short mobInterval = 5000; private boolean allowSummons = true; // All maps should have this true at the beginning - + // HPQ private int riceCakes = 0; private int bunnyDamage = 0; @@ -159,7 +162,7 @@ public class MapleMap { private MapleSnowball snowball0 = null; private MapleSnowball snowball1 = null; private MapleCoconut coconut; - + //locks private ReadLock chrRLock; private WriteLock chrWLock; @@ -167,10 +170,10 @@ public class MapleMap { private WriteLock objectWLock; private Lock lootLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_LOOT, true); - + // due to the nature of loadMapFromWz (synchronized), sole function that calls 'generateMapDropRangeCache', this lock remains optional. private static final Lock bndLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_BOUNDS, true); - + public MapleMap(int mapid, int world, int channel, int returnMapId, float monsterRate) { this.mapid = mapid; this.channel = channel; @@ -187,26 +190,26 @@ public class MapleMap { final ReentrantReadWriteLock objectLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_OBJS, true); objectRLock = objectLock.readLock(); objectWLock = objectLock.writeLock(); - + aggroMonitor = new MapleMonsterAggroCoordinator(); } - + public void setEventInstance(EventInstanceManager eim) { event = eim; } - + public EventInstanceManager getEventInstance() { return event; } - + public Rectangle getMapArea() { return mapArea; } - + public int getWorld() { return world; } - + public void broadcastMessage(MapleCharacter source, final byte[] packet) { chrRLock.lock(); try { @@ -236,10 +239,9 @@ public class MapleMap { public void toggleDrops() { this.dropsOn = !dropsOn; } - - + private static double getRangedDistance() { - return(ServerConstants.USE_MAXRANGE ? Double.POSITIVE_INFINITY : 722500); + return (ServerConstants.USE_MAXRANGE ? Double.POSITIVE_INFINITY : 722500); } public List getMapObjectsInRect(Rectangle box, List types) { @@ -262,28 +264,30 @@ public class MapleMap { public int getId() { return mapid; } - + public Channel getChannelServer() { return Server.getInstance().getWorld(world).getChannel(channel); } - + public World getWorldServer() { return Server.getInstance().getWorld(world); } public MapleMap getReturnMap() { - if(returnMapId == 999999999) return this; + if (returnMapId == 999999999) { + return this; + } return getChannelServer().getMapFactory().getMap(returnMapId); } public int getReturnMapId() { return returnMapId; } - + public MapleMap getForcedReturnMap() { return getChannelServer().getMapFactory().getMap(forcedReturnMap); } - + public int getForcedReturnId() { return forcedReturnMap; } @@ -303,7 +307,7 @@ public class MapleMap { public int getTimeLeft() { return (int) ((timeLimit - System.currentTimeMillis()) / 1000); } - + public void setReactorState() { for (MapleMapObject o : getMapObjects()) { if (o.getType() == MapleMapObjectType.REACTOR) { @@ -320,11 +324,11 @@ public class MapleMap { } } } - + public final void limitReactor(final int rid, final int num) { List toDestroy = new ArrayList<>(); Map contained = new LinkedHashMap<>(); - + for (MapleMapObject obj : getReactors()) { MapleReactor mr = (MapleReactor) obj; if (contained.containsKey(mr.getId())) { @@ -337,7 +341,7 @@ public class MapleMap { contained.put(mr.getId(), 1); } } - + for (MapleReactor mr : toDestroy) { destroyReactor(mr.getObjectId()); } @@ -346,14 +350,14 @@ public class MapleMap { public boolean isAllReactorState(final int reactorId, final int state) { for (MapleMapObject mo : getReactors()) { MapleReactor r = (MapleReactor) mo; - + if (r.getId() == reactorId && r.getState() != state) { return false; } } return true; } - + public int getCurrentPartyId() { for (MapleCharacter chr : this.getCharacters()) { if (chr.getPartyId() != -1) { @@ -371,7 +375,7 @@ public class MapleMap { objectWLock.unlock(); } } - + public void addMapObject(MapleMapObject mapobject) { objectWLock.lock(); try { @@ -382,14 +386,14 @@ public class MapleMap { objectWLock.unlock(); } } - + private void spawnAndAddRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery) { spawnAndAddRangedMapObject(mapobject, packetbakery, null); } private void spawnAndAddRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery, SpawnCondition condition) { List inRangeCharacters = new LinkedList<>(); - + chrRLock.lock(); objectWLock.lock(); try { @@ -408,15 +412,15 @@ public class MapleMap { objectWLock.unlock(); chrRLock.unlock(); } - + for (MapleCharacter chr : inRangeCharacters) { packetbakery.sendPackets(chr.getClient()); } } - + private void spawnRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery, SpawnCondition condition) { List inRangeCharacters = new LinkedList<>(); - + chrRLock.lock(); try { int curOID = getUsableOID(); @@ -432,7 +436,7 @@ public class MapleMap { } finally { chrRLock.unlock(); } - + for (MapleCharacter chr : inRangeCharacters) { packetbakery.sendPackets(chr.getClient()); } @@ -442,14 +446,14 @@ public class MapleMap { objectRLock.lock(); try { Integer curOid; - + // clashes with playernpc on curOid >= 2147000000, developernpc uses >= 2147483000 do { if ((curOid = runningOid.incrementAndGet()) >= 2147000000) { runningOid.set(curOid = 1000000001); } } while (mapobjects.containsKey(curOid)); - + return curOid; } finally { objectRLock.unlock(); @@ -492,8 +496,8 @@ public class MapleMap { bndLock.lock(); try { Pair bounds = dropBoundsCache.get(mapid); - - if(bounds != null) { + + if (bounds != null) { xLimits = bounds; } else { // assuming MINIMAP always have an equal-greater picture representation of the map area (players won't walk beyond the area known by the minimap). @@ -509,56 +513,59 @@ public class MapleMap { bndLock.unlock(); } } - + private Point bsearchDropPos(Point initial, Point fallback) { Point res, dropPos = null; - + int awayx = fallback.x; int homex = initial.x; - + int y = initial.y - 85; - + do { int distx = awayx - homex; int dx = distx / 2; - + int searchx = homex + dx; - if((res = calcPointBelow(new Point(searchx, y))) != null) { + if ((res = calcPointBelow(new Point(searchx, y))) != null) { awayx = searchx; dropPos = res; } else { homex = searchx; } - } while(Math.abs(homex - awayx) > 5); - + } while (Math.abs(homex - awayx) > 5); + return (dropPos != null) ? dropPos : fallback; } - + public Point calcDropPos(Point initial, Point fallback) { - if(initial.x < xLimits.left) initial.x = xLimits.left; - else if(initial.x > xLimits.right) initial.x = xLimits.right; - + if (initial.x < xLimits.left) { + initial.x = xLimits.left; + } else if (initial.x > xLimits.right) { + initial.x = xLimits.right; + } + Point ret = calcPointBelow(new Point(initial.x, initial.y - 85)); if (ret == null) { ret = bsearchDropPos(initial, fallback); } - - if(!mapArea.contains(ret)) { // found drop pos outside the map :O + + if (!mapArea.contains(ret)) { // found drop pos outside the map :O return fallback; } - + return ret; } - + public boolean canDeployDoor(Point pos) { Point toStep = calcPointBelow(pos); return toStep != null && toStep.distance(pos) <= 42; } - + /** - * Fetches angle relative between spawn and door points - * where 3 O'Clock is 0 and 12 O'Clock is 270 degrees - * + * Fetches angle relative between spawn and door points where 3 O'Clock is 0 + * and 12 O'Clock is 270 degrees + * * @param spawnPoint * @param doorPoint * @return angle in degress from 0-360. @@ -571,47 +578,48 @@ public class MapleMap { double inRads = Math.atan2(dy, dx); // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12 O'clock - if (inRads < 0) + if (inRads < 0) { inRads = Math.abs(inRads); - else + } else { inRads = 2 * Math.PI - inRads; + } return Math.toDegrees(inRads); } - + /** * Converts angle in degrees to rounded cardinal coordinate. - * + * * @param angle * @return correspondent coordinate. */ public static String getRoundedCoordinate(double angle) { String directions[] = {"E", "SE", "S", "SW", "W", "NW", "N", "NE", "E"}; - return directions[ (int)Math.round(( ((double)angle % 360) / 45)) ]; + return directions[(int) Math.round((((double) angle % 360) / 45))]; } - + public Pair getDoorPositionStatus(Point pos) { MaplePortal portal = findClosestPlayerSpawnpoint(pos); - + double angle = getAngle(portal.getPosition(), pos); double distn = pos.distanceSq(portal.getPosition()); - - if(distn <= 777777.7) { + + if (distn <= 777777.7) { return null; } - + distn = Math.sqrt(distn); - return new Pair<>(getRoundedCoordinate(angle), Integer.valueOf((int)distn)); + return new Pair<>(getRoundedCoordinate(angle), Integer.valueOf((int) distn)); } private static void sortDropEntries(List from, List item, List visibleQuest, List otherQuest, MapleCharacter chr) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - - for(MonsterDropEntry mde : from) { - if(!ii.isQuestItem(mde.itemId)) { + + for (MonsterDropEntry mde : from) { + if (!ii.isQuestItem(mde.itemId)) { item.add(mde); } else { - if(chr.needQuestItem(mde.questid, mde.itemId)) { + if (chr.needQuestItem(mde.questid, mde.itemId)) { visibleQuest.add(mde); } else { otherQuest.add(mde); @@ -619,20 +627,20 @@ public class MapleMap { } } } - + private byte dropItemsFromMonsterOnMap(List dropEntry, Point pos, byte d, int chRate, byte droptype, int mobpos, MapleCharacter chr, MapleMonster mob) { - if(dropEntry.isEmpty()) { + if (dropEntry.isEmpty()) { return d; } - + Collections.shuffle(dropEntry); - + Item idrop; MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - + for (final MonsterDropEntry de : dropEntry) { int dropChance = (int) Math.min((float) de.chance * chRate, Integer.MAX_VALUE); - + if (Randomizer.nextInt(999999) < dropChance) { if (droptype == 3) { pos.x = (int) (mobpos + ((d % 2 == 0) ? (40 * ((d + 1) / 2)) : -(40 * (d / 2)))); @@ -647,8 +655,10 @@ public class MapleMap { mesos = (int) (mesos * chr.getBuffedValue(MapleBuffStat.MESOUP).doubleValue() / 100.0); } mesos = mesos * chr.getMesoRate(); - if(mesos <= 0) mesos = Integer.MAX_VALUE; - + if (mesos <= 0) { + mesos = Integer.MAX_VALUE; + } + spawnMesoDrop(mesos, calcDropPos(pos, mob.getPosition()), mob, chr, false, droptype); } } else { @@ -662,16 +672,16 @@ public class MapleMap { d++; } } - + return d; } - + private byte dropGlobalItemsFromMonsterOnMap(List globalEntry, Point pos, byte d, byte droptype, int mobpos, MapleCharacter chr, MapleMonster mob) { Collections.shuffle(globalEntry); - + Item idrop; MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - + for (final MonsterGlobalDropEntry de : globalEntry) { if (Randomizer.nextInt(999999) < de.chance) { if (droptype == 3) { @@ -690,15 +700,15 @@ public class MapleMap { } } } - + return d; } - + private void dropFromMonster(final MapleCharacter chr, final MapleMonster mob, final boolean useBaseRate) { if (mob.dropsDisabled() || !dropsOn) { return; } - + final byte droptype = (byte) (mob.getStats().isExplosiveReward() ? 3 : mob.getStats().isFfaLoot() ? 2 : chr.getParty() != null ? 1 : 0); final int mobpos = mob.getPosition().x; int chRate = !mob.isBoss() ? chr.getDropRate() : chr.getBossDropRate(); @@ -709,40 +719,42 @@ public class MapleMap { if (stati != null) { chRate *= (stati.getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0); } - - if(useBaseRate) chRate = 1; + + if (useBaseRate) { + chRate = 1; + } final MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance(); final List globalEntry = mi.getRelevantGlobalDrops(this.getId()); - - final List dropEntry = new ArrayList<>(); + + final List dropEntry = new ArrayList<>(); final List visibleQuestEntry = new ArrayList<>(); final List otherQuestEntry = new ArrayList<>(); sortDropEntries(ServerConstants.USE_SPAWN_RELEVANT_LOOT ? chr.retrieveRelevantDrops(mob.getId()) : mi.retrieveEffectiveDrop(mob.getId()), dropEntry, visibleQuestEntry, otherQuestEntry, chr); - + registerMobItemDrops(droptype, mobpos, chRate, pos, dropEntry, visibleQuestEntry, otherQuestEntry, globalEntry, chr, mob); } - + public void dropItemsFromMonster(List list, final MapleCharacter chr, final MapleMonster mob) { if (mob.dropsDisabled() || !dropsOn) { return; } - + final byte droptype = (byte) (chr.getParty() != null ? 1 : 0); final int mobpos = mob.getPosition().x; int chRate = 1000000; // guaranteed item drop byte d = 1; Point pos = new Point(0, mob.getPosition().y); - + dropItemsFromMonsterOnMap(list, pos, d, chRate, droptype, mobpos, chr, mob); } - + public void dropFromFriendlyMonster(final MapleCharacter chr, final MapleMonster mob) { dropFromMonster(chr, mob, true); } - + public void dropFromReactor(final MapleCharacter chr, final MapleReactor reactor, Item drop, Point dropPos, short questid) { - spawnDrop(drop, this.calcDropPos(dropPos, reactor.getPosition()), reactor, chr, (byte)(chr.getParty() != null ? 1 : 0), questid); + spawnDrop(drop, this.calcDropPos(dropPos, reactor.getPosition()), reactor, chr, (byte) (chr.getParty() != null ? 1 : 0), questid); } private void stopItemMonitor() { @@ -752,12 +764,12 @@ public class MapleMap { expireItemsTask.cancel(false); expireItemsTask = null; - if(ServerConstants.USE_SPAWN_LOOT_ON_ANIMATION) { + if (ServerConstants.USE_SPAWN_LOOT_ON_ANIMATION) { mobSpawnLootTask.cancel(false); mobSpawnLootTask = null; } } - + private void cleanItemMonitor() { objectWLock.lock(); try { @@ -766,24 +778,26 @@ public class MapleMap { objectWLock.unlock(); } } - + private void startItemMonitor() { chrWLock.lock(); try { - if(itemMonitor != null) return; - + if (itemMonitor != null) { + return; + } + itemMonitor = TimerManager.getInstance().register(new Runnable() { @Override public void run() { chrWLock.lock(); try { if (characters.isEmpty()) { - if(itemMonitorTimeout == 0) { - if(itemMonitor != null) { + if (itemMonitorTimeout == 0) { + if (itemMonitor != null) { stopItemMonitor(); aggroMonitor.stopAggroCoordinator(); } - + return; } else { itemMonitorTimeout--; @@ -794,7 +808,7 @@ public class MapleMap { } finally { chrWLock.unlock(); } - + boolean tryClean; objectRLock.lock(); try { @@ -802,19 +816,21 @@ public class MapleMap { } finally { objectRLock.unlock(); } - - if(tryClean) cleanItemMonitor(); + + if (tryClean) { + cleanItemMonitor(); + } } }, ServerConstants.ITEM_MONITOR_TIME, ServerConstants.ITEM_MONITOR_TIME); - + expireItemsTask = TimerManager.getInstance().register(new Runnable() { @Override public void run() { makeDisappearExpiredItemDrops(); } }, ServerConstants.ITEM_EXPIRE_CHECK, ServerConstants.ITEM_EXPIRE_CHECK); - - if(ServerConstants.USE_SPAWN_LOOT_ON_ANIMATION) { + + if (ServerConstants.USE_SPAWN_LOOT_ON_ANIMATION) { lootLock.lock(); try { mobLootEntries.clear(); @@ -829,13 +845,13 @@ public class MapleMap { } }, 200, 200); } - + itemMonitorTimeout = 1; } finally { chrWLock.unlock(); } } - + private boolean hasItemMonitor() { chrRLock.lock(); try { @@ -844,21 +860,23 @@ public class MapleMap { chrRLock.unlock(); } } - + public int getDroppedItemCount() { return droppedItemCount.get(); } - + private synchronized void instantiateItemDrop(MapleMapItem mdrop) { - if(droppedItemCount.get() >= ServerConstants.ITEM_LIMIT_ON_MAP) { + if (droppedItemCount.get() >= ServerConstants.ITEM_LIMIT_ON_MAP) { MapleMapObject mapobj; - + do { objectWLock.lock(); try { mapobj = registeredDrops.remove(0).get(); - while(mapobj == null) { - if(registeredDrops.isEmpty()) break; + while (mapobj == null) { + if (registeredDrops.isEmpty()) { + break; + } mapobj = registeredDrops.remove(0).get(); } } finally { @@ -866,7 +884,7 @@ public class MapleMap { } } while (!makeDisappearItemFromMap(mapobj)); } - + objectWLock.lock(); try { registerItemDrop(mdrop); @@ -874,14 +892,14 @@ public class MapleMap { } finally { objectWLock.unlock(); } - + droppedItemCount.incrementAndGet(); } - + private void registerItemDrop(MapleMapItem mdrop) { droppedItems.put(mdrop, !everlast ? Server.getInstance().getCurrentTime() + ServerConstants.ITEM_EXPIRE_TIME : Long.MAX_VALUE); } - + private void unregisterItemDrop(MapleMapItem mdrop) { objectWLock.lock(); try { @@ -890,47 +908,47 @@ public class MapleMap { objectWLock.unlock(); } } - + private void makeDisappearExpiredItemDrops() { List toDisappear = new LinkedList<>(); - + objectRLock.lock(); try { long timeNow = Server.getInstance().getCurrentTime(); - - for(Entry it : droppedItems.entrySet()) { - if(it.getValue() < timeNow) { + + for (Entry it : droppedItems.entrySet()) { + if (it.getValue() < timeNow) { toDisappear.add(it.getKey()); } } } finally { objectRLock.unlock(); } - - for(MapleMapItem mmi : toDisappear) { + + for (MapleMapItem mmi : toDisappear) { makeDisappearItemFromMap(mmi); } - + objectWLock.lock(); try { - for(MapleMapItem mmi : toDisappear) { + for (MapleMapItem mmi : toDisappear) { droppedItems.remove(mmi); } } finally { objectWLock.unlock(); } } - + private void registerMobItemDrops(byte droptype, int mobpos, int chRate, Point pos, List dropEntry, List visibleQuestEntry, List otherQuestEntry, List globalEntry, MapleCharacter chr, MapleMonster mob) { MobLootEntry mle = new MobLootEntry(droptype, mobpos, chRate, pos, dropEntry, visibleQuestEntry, otherQuestEntry, globalEntry, chr, mob); - - if(ServerConstants.USE_SPAWN_LOOT_ON_ANIMATION) { + + if (ServerConstants.USE_SPAWN_LOOT_ON_ANIMATION) { int animationTime = mob.getAnimationTime("die1"); lootLock.lock(); try { long timeNow = Server.getInstance().getCurrentTime(); - mobLootEntries.put(mle, timeNow + ((long)(0.42 * animationTime))); + mobLootEntries.put(mle, timeNow + ((long) (0.42 * animationTime))); } finally { lootLock.unlock(); } @@ -938,46 +956,46 @@ public class MapleMap { mle.run(); } } - + private void spawnMobItemDrops() { Set> mleList; - + lootLock.lock(); try { mleList = new HashSet<>(mobLootEntries.entrySet()); } finally { lootLock.unlock(); } - + long timeNow = Server.getInstance().getCurrentTime(); List toRemove = new LinkedList<>(); - for(Entry mlee : mleList) { - if(mlee.getValue() < timeNow) { + for (Entry mlee : mleList) { + if (mlee.getValue() < timeNow) { toRemove.add(mlee.getKey()); } } - - if(!toRemove.isEmpty()) { + + if (!toRemove.isEmpty()) { List toSpawnLoot = new LinkedList<>(); - + lootLock.lock(); try { - for(MobLootEntry mle : toRemove) { + for (MobLootEntry mle : toRemove) { Long mler = mobLootEntries.remove(mle); - if(mler != null) { + if (mler != null) { toSpawnLoot.add(mle); } } } finally { lootLock.unlock(); } - - for(MobLootEntry mle : toSpawnLoot) { + + for (MobLootEntry mle : toSpawnLoot) { mle.run(); } } } - + private List getDroppedItems() { objectRLock.lock(); try { @@ -986,43 +1004,45 @@ public class MapleMap { objectRLock.unlock(); } } - + public void pickItemDrop(byte[] pickupPacket, MapleMapItem mdrop) { // mdrop must be already locked and not-pickedup checked by now broadcastMessage(pickupPacket, mdrop.getPosition()); - + droppedItemCount.decrementAndGet(); this.removeMapObject(mdrop); mdrop.setPickedUp(true); unregisterItemDrop(mdrop); } - + public void updatePlayerItemDrops(int partyid, int charid, List partyMembers, MapleCharacter partyLeaver) { - for(MapleMapItem mdrop : getDroppedItems()) { - if(mdrop.getOwnerId() == charid) { + for (MapleMapItem mdrop : getDroppedItems()) { + if (mdrop.getOwnerId() == charid) { mdrop.lockItem(); try { - if(mdrop.isPickedUp()) return; - + if (mdrop.isPickedUp()) { + return; + } + mdrop.setPartyOwnerId(partyid); - + byte[] removePacket = MaplePacketCreator.silentRemoveItemFromMap(mdrop.getObjectId()); byte[] updatePacket = MaplePacketCreator.updateMapItemObject(mdrop, partyLeaver == null); - - for(MapleCharacter mc : partyMembers) { - if(this.equals(mc.getMap())) { + + for (MapleCharacter mc : partyMembers) { + if (this.equals(mc.getMap())) { mc.announce(removePacket); - - if(mc.needQuestItem(mdrop.getQuest(), mdrop.getItemId())) { + + if (mc.needQuestItem(mdrop.getQuest(), mdrop.getItemId())) { mc.announce(updatePacket); } } } - - if(partyLeaver != null) { - if(this.equals(partyLeaver.getMap())) { + + if (partyLeaver != null) { + if (this.equals(partyLeaver.getMap())) { partyLeaver.announce(removePacket); - - if(partyLeaver.needQuestItem(mdrop.getQuest(), mdrop.getItemId())) { + + if (partyLeaver.needQuestItem(mdrop.getQuest(), mdrop.getItemId())) { partyLeaver.announce(MaplePacketCreator.updateMapItemObject(mdrop, true)); } } @@ -1033,7 +1053,7 @@ public class MapleMap { } } } - + private void spawnDrop(final Item idrop, final Point dropPos, final MapleMapObject dropper, final MapleCharacter chr, final byte droptype, final short questid) { final MapleMapItem mdrop = new MapleMapItem(idrop, dropPos, dropper, chr, chr.getClient(), droptype, false, questid); mdrop.setDropTime(Server.getInstance().getCurrentTime()); @@ -1041,7 +1061,7 @@ public class MapleMap { @Override public void sendPackets(MapleClient c) { MapleCharacter chr = c.getPlayer(); - + if (chr.needQuestItem(questid, idrop.getItemId())) { mdrop.lockItem(); try { @@ -1080,7 +1100,7 @@ public class MapleMap { public final void disappearingItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, final Point pos) { final Point droppos = calcDropPos(pos, pos); final MapleMapItem mdrop = new MapleMapItem(item, droppos, dropper, owner, owner.getClient(), (byte) 1, false); - + mdrop.lockItem(); try { broadcastItemDropMessage(mdrop, dropper.getPosition(), droppos, (byte) 3, mdrop.getPosition()); @@ -1108,7 +1128,7 @@ public class MapleMap { public int countMonster(int id) { return countMonster(id, id); } - + public int countMonster(int minid, int maxid) { int count = 0; for (MapleMapObject m : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) { @@ -1119,23 +1139,23 @@ public class MapleMap { } return count; } - + public int countMonsters() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER)).size(); } - + public int countReactors() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.REACTOR)).size(); } - + public final List getReactors() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.REACTOR)); } - + public int countItems() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.ITEM)).size(); } - + public final List getItems() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.ITEM)); } @@ -1143,11 +1163,11 @@ public class MapleMap { public int countPlayers() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER)).size(); } - + public List getPlayers() { return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER)); } - + public List getAllPlayers() { List character; chrRLock.lock(); @@ -1156,10 +1176,10 @@ public class MapleMap { } finally { chrRLock.unlock(); } - + return character; } - + public List getPlayersInRange(Rectangle box, List targets) { List character = new LinkedList<>(); chrRLock.lock(); @@ -1174,20 +1194,22 @@ public class MapleMap { } finally { chrRLock.unlock(); } - + return character; } - + public int countAlivePlayers() { int count = 0; - - for(MapleCharacter mc: getAllPlayers()) { - if(mc.isAlive()) count++; + + for (MapleCharacter mc : getAllPlayers()) { + if (mc.isAlive()) { + count++; + } } - + return count; } - + public boolean damageMonster(final MapleCharacter chr, final MapleMonster monster, final int damage) { if (monster.getId() == 8800000) { for (MapleMapObject object : chr.getMap().getMapObjects()) { @@ -1218,58 +1240,62 @@ public class MapleMap { public List getMonsters() { List mobs = new ArrayList<>(); for (MapleMapObject object : this.getMapObjects()) { - if(object instanceof MapleMonster) mobs.add((MapleMonster)object); + if (object instanceof MapleMonster) { + mobs.add((MapleMonster) object); + } } return mobs; } - + public void broadcastBalrogVictory(String leaderName) { getWorldServer().dropMessage(6, "[VICTORY] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive."); } - + public void broadcastHorntailVictory() { getWorldServer().dropMessage(6, "[VICTORY] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!"); } - + public void broadcastZakumVictory() { getWorldServer().dropMessage(6, "[VICTORY] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!"); } - + public void broadcastPinkBeanVictory(int channel) { getWorldServer().dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!"); } - + private boolean removeKilledMonsterObject(MapleMonster monster) { monster.lockMonster(); try { - if(monster.getHp() < 0) { + if (monster.getHp() < 0) { return false; } - + spawnedMonstersOnMap.decrementAndGet(); removeMapObject(monster); monster.disposeMapObject(); - + return true; } finally { monster.unlockMonster(); } } - + public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops) { killMonster(monster, chr, withDrops, 1); } public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops, int animation) { - if(monster == null) return; - + if (monster == null) { + return; + } + if (chr == null) { - if(removeKilledMonsterObject(monster)) { + if (removeKilledMonsterObject(monster)) { monster.dispatchMonsterKilled(false); broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition()); } } else { - if(removeKilledMonsterObject(monster)) { + if (removeKilledMonsterObject(monster)) { if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) { AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher."); } @@ -1279,6 +1305,10 @@ public class MapleMap { } else if (monster.getStats().getLevel() >= chr.getLevel()) { } }*/ + + if (monster.getCP() > 0 && chr.getMap().isCPQMap()) { + chr.gainCP(monster.getCP()); + } int buff = monster.getBuffToGive(); if (buff > -1) { MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance(); @@ -1292,13 +1322,6 @@ public class MapleMap { } } } - - if (monster.getCP() > 0 && chr.getCarnival() != null) { - chr.getCarnivalParty().addCP(chr, monster.getCP()); - chr.announce(MaplePacketCreator.updateCP(chr.getCP(), chr.getObtainedCP())); - broadcastMessage(MaplePacketCreator.updatePartyCP(chr.getCarnivalParty())); - //they drop items too ): - } if (monster.getId() >= 8800003 && monster.getId() <= 8800010) { boolean makeZakReal = true; Collection objects = getMapObjects(); @@ -1336,8 +1359,8 @@ public class MapleMap { } if (monster.hasBossHPBar()) { - for(MapleCharacter mc : this.getAllPlayers()) { - if(mc.getTargetHpBarHash() == monster.hashCode()) { + for (MapleCharacter mc : this.getAllPlayers()) { + if (mc.getTargetHpBarHash() == monster.hashCode()) { mc.resetPlayerAggro(); } } @@ -1356,42 +1379,44 @@ public class MapleMap { public void killMonster(int mobId) { MapleCharacter chr = (MapleCharacter) getPlayers().get(0); List mobList = getMonsters(); - - for (MapleMonster mob : mobList) { + + for (MapleMonster mob : mobList) { if (mob.getId() == mobId) { this.killMonster(mob, chr, false); } } } - + public void killMonsterWithDrops(int mobId) { Map mapChars = this.getMapPlayers(); - - if(!mapChars.isEmpty()) { + + if (!mapChars.isEmpty()) { MapleCharacter defaultChr = mapChars.entrySet().iterator().next().getValue(); List mobList = getMonsters(); - + for (MapleMonster mob : mobList) { if (mob.getId() == mobId) { MapleCharacter chr = mapChars.get(mob.getHighestDamagerId()); - if(chr == null) chr = defaultChr; - + if (chr == null) { + chr = defaultChr; + } + this.killMonster(mob, chr, true); } } } } - + public void softKillAllMonsters() { closeMapSpawnPoints(); - + for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) { MapleMonster monster = (MapleMonster) monstermo; if (monster.getStats().isFriendly()) { continue; } - - if(removeKilledMonsterObject(monster)) { + + if (removeKilledMonsterObject(monster)) { monster.dispatchMonsterKilled(false); } } @@ -1399,38 +1424,38 @@ public class MapleMap { public void killAllMonstersNotFriendly() { closeMapSpawnPoints(); - + for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) { MapleMonster monster = (MapleMonster) monstermo; if (monster.getStats().isFriendly()) { continue; } - + killMonster(monster, null, false, 1); } } public void killAllMonsters() { closeMapSpawnPoints(); - + for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) { MapleMonster monster = (MapleMonster) monstermo; - + killMonster(monster, null, false, 1); } } - + public final void destroyReactors(final int first, final int last) { List toDestroy = new ArrayList<>(); List reactors = getReactors(); - + for (MapleMapObject obj : reactors) { MapleReactor mr = (MapleReactor) obj; if (mr.getId() >= first && mr.getId() <= last) { toDestroy.add(mr); } } - + for (MapleReactor mr : toDestroy) { destroyReactor(mr.getObjectId()); } @@ -1442,7 +1467,7 @@ public class MapleMap { reactor.cancelReactorTimeout(); reactor.setAlive(false); removeMapObject(reactor); - + if (reactor.getDelay() > 0) { registerMapSchedule(new Runnable() { @Override @@ -1455,7 +1480,7 @@ public class MapleMap { public void resetReactors() { List list = new ArrayList<>(); - + objectRLock.lock(); try { for (MapleMapObject o : mapobjects.values()) { @@ -1467,10 +1492,10 @@ public class MapleMap { } finally { objectRLock.unlock(); } - + resetReactors(list); } - + public final void resetReactors(List list) { for (MapleReactor r : list) { r.lockReactor(); @@ -1502,12 +1527,12 @@ public class MapleMap { objectRLock.unlock(); } } - + public final void shuffleReactors(int first, int last) { List points = new ArrayList<>(); List reactors = getReactors(); List targets = new LinkedList<>(); - + for (MapleMapObject obj : reactors) { MapleReactor mr = (MapleReactor) obj; if (mr.getId() >= first && mr.getId() <= last) { @@ -1521,19 +1546,19 @@ public class MapleMap { mr.setPosition(points.remove(points.size() - 1)); } } - + public final void shuffleReactors(List list) { List points = new ArrayList<>(); List listObjects = new ArrayList<>(); List targets = new LinkedList<>(); - + objectRLock.lock(); try { for (Object ob : list) { - if(ob instanceof MapleMapObject) { + if (ob instanceof MapleMapObject) { MapleMapObject mmo = (MapleMapObject) ob; - - if(mapobjects.containsValue(mmo) && mmo.getType() == MapleMapObjectType.REACTOR) { + + if (mapobjects.containsValue(mmo) && mmo.getType() == MapleMapObjectType.REACTOR) { listObjects.add(mmo); } } @@ -1541,10 +1566,10 @@ public class MapleMap { } finally { objectRLock.unlock(); } - + for (MapleMapObject obj : listObjects) { MapleReactor mr = (MapleReactor) obj; - + points.add(mr.getPosition()); targets.add(obj); } @@ -1554,7 +1579,7 @@ public class MapleMap { mr.setPosition(points.remove(points.size() - 1)); } } - + private Map getCopyMapObjects() { objectRLock.lock(); try { @@ -1563,7 +1588,7 @@ public class MapleMap { objectRLock.unlock(); } } - + public List getMapObjects() { objectRLock.lock(); try { @@ -1582,10 +1607,10 @@ public class MapleMap { } } } - + return null; } - + public boolean containsNPC(int npcid) { objectRLock.lock(); try { @@ -1601,7 +1626,7 @@ public class MapleMap { } return false; } - + public void destroyNPC(int npcid) { // assumption: there's at most one of the same NPC in a map. List npcs = getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.NPC)); @@ -1612,7 +1637,7 @@ public class MapleMap { if (((MapleNPC) obj).getId() == npcid) { broadcastMessage(MaplePacketCreator.removeNPCController(obj.getObjectId())); broadcastMessage(MaplePacketCreator.removeNPC(obj.getObjectId())); - + this.mapobjects.remove(Integer.valueOf(obj.getObjectId())); } } @@ -1647,7 +1672,7 @@ public class MapleMap { MapleMapObject mmo = getMapObject(oid); return (mmo != null && mmo.getType() == MapleMapObjectType.REACTOR) ? (MapleReactor) mmo : null; } - + public MapleReactor getReactorById(int Id) { objectRLock.lock(); try { @@ -1663,22 +1688,22 @@ public class MapleMap { objectRLock.unlock(); } } - + public List getReactorsByIdRange(final int first, final int last) { List list = new LinkedList<>(); - + objectRLock.lock(); try { for (MapleMapObject obj : mapobjects.values()) { if (obj.getType() == MapleMapObjectType.REACTOR) { MapleReactor mr = (MapleReactor) obj; - + if (mr.getId() >= first && mr.getId() <= last) { list.add(mr); } } } - + return list; } finally { objectRLock.unlock(); @@ -1736,15 +1761,15 @@ public class MapleMap { @Override public void run() { List chrList = MapleMap.this.getPlayers(); - + if (m.isAlive() && !chrList.isEmpty()) { MapleCharacter chr = (MapleCharacter) chrList.get(0); - + if (m.getId() == 9300061) { MapleMap.this.riceCakes++; MapleMap.this.broadcastMessage(MaplePacketCreator.serverNotice(6, "The Moon Bunny made rice cake number " + (MapleMap.this.riceCakes) + ".")); } - + dropFromFriendlyMonster(chr, m); } } @@ -1766,14 +1791,16 @@ public class MapleMap { spos.y--;//shouldn't be null! return spos; } - + public Point getPointBelow(Point pos) { return calcPointBelow(pos); } public void spawnRevives(final MapleMonster monster) { monster.setMap(this); - if(getEventInstance() != null) getEventInstance().registerMonster(monster); + if (getEventInstance() != null) { + getEventInstance().registerMonster(monster); + } spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override @@ -1782,22 +1809,22 @@ public class MapleMap { c.announce(MaplePacketCreator.spawnMonster(monster, false)); } }); - + monster.aggroUpdateController(); - + if (monster.hasBossHPBar()) { broadcastBossHpMessage(monster, monster.hashCode(), monster.makeBossHPBarPacket(), monster.getPosition()); } - + spawnedMonstersOnMap.incrementAndGet(); applyRemoveAfter(monster); } - + private void applyRemoveAfter(final MapleMonster monster) { final selfDestruction selfDestruction = monster.getStats().selfDestruction(); if (monster.getStats().removeAfter() > 0 || selfDestruction != null && selfDestruction.getHp() < 0) { Runnable removeAfterAction; - + if (selfDestruction == null) { removeAfterAction = new Runnable() { @Override @@ -1805,7 +1832,7 @@ public class MapleMap { killMonster(monster, null, false); } }; - + registerMapSchedule(removeAfterAction, monster.getStats().removeAfter() * 1000); } else { removeAfterAction = new Runnable() { @@ -1814,78 +1841,95 @@ public class MapleMap { killMonster(monster, null, false, selfDestruction.getAction()); } }; - + registerMapSchedule(removeAfterAction, selfDestruction.removeAfter() * 1000); } - + monster.pushRemoveAfterAction(removeAfterAction); } } - + public void dismissRemoveAfter(final MapleMonster monster) { Runnable removeAfterAction = monster.popRemoveAfterAction(); if (removeAfterAction != null) { this.getChannelServer().forceRunOverallAction(mapid, removeAfterAction); } } - + private List getMonsterSpawn() { synchronized (monsterSpawn) { return new ArrayList<>(monsterSpawn); } } - + private List getAllMonsterSpawn() { synchronized (allMonsterSpawn) { return new ArrayList<>(allMonsterSpawn); } } - + public void spawnAllMonsterIdFromMapSpawnList(int id) { spawnAllMonsterIdFromMapSpawnList(id, 1, false); } - + public void spawnAllMonsterIdFromMapSpawnList(int id, int difficulty, boolean isPq) { - for(SpawnPoint sp: getAllMonsterSpawn()) { - if(sp.getMonsterId() == id) { + for (SpawnPoint sp : getAllMonsterSpawn()) { + if (sp.getMonsterId() == id) { spawnMonster(sp.getMonster(), difficulty, isPq); } } } - + public void spawnAllMonstersFromMapSpawnList() { spawnAllMonstersFromMapSpawnList(1, false); } - + public void spawnAllMonstersFromMapSpawnList(int difficulty, boolean isPq) { - for(SpawnPoint sp: getAllMonsterSpawn()) { + for (SpawnPoint sp : getAllMonsterSpawn()) { spawnMonster(sp.getMonster(), difficulty, isPq); } } - + public void spawnMonster(final MapleMonster monster) { spawnMonster(monster, 1, false); } - + public void spawnMonster(final MapleMonster monster, int difficulty, boolean isPq) { if (mobCapacity != -1 && mobCapacity == spawnedMonstersOnMap.get()) { return;//PyPQ } - - monster.changeDifficulty(difficulty, isPq); - - monster.setMap(this); - if(getEventInstance() != null) getEventInstance().registerMonster(monster); + monster.changeDifficulty(difficulty, isPq); + + monster.setMap(this); + if (getEventInstance() != null) { + getEventInstance().registerMonster(monster); + } spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { c.announce(MaplePacketCreator.spawnMonster(monster, true)); } }, null); - + monster.aggroUpdateController(); - + + if ((monster.getTeam() == 1 || monster.getTeam() == 0) && (isCPQMap() || isCPQMap2())) { + List teamS = null; + if (monster.getTeam() == 0) { + teamS = redTeamBuffs; + } else if (monster.getTeam() == 1) { + teamS = blueTeamBuffs; + } + if (teamS != null) { + for (MCSkill skil : teamS) { + if (skil != null) { + skil.getSkill().applyEffect(null, monster, false, null); + } + } + } + } + if (monster.hasBossHPBar()) { broadcastBossHpMessage(monster, monster.hashCode(), monster.makeBossHPBarPacket(), monster.getPosition()); } @@ -1903,7 +1947,7 @@ public class MapleMap { FilePrinter.printError(FilePrinter.UNHANDLED_EVENT, "UNCODED TIMED MOB DETECTED: " + monster.getId()); } } - + spawnedMonstersOnMap.incrementAndGet(); applyRemoveAfter(monster); // thanks LightRyuzaki for pointing issues with spawned CWKPQ mobs not applying this } @@ -1917,10 +1961,14 @@ public class MapleMap { monster.setMap(this); Point spos = new Point(pos.x, pos.y - 1); spos = calcPointBelow(spos); - if(spos == null) return; - - if(getEventInstance() != null) getEventInstance().registerMonster(monster); - + if (spos == null) { + return; + } + + if (getEventInstance() != null) { + getEventInstance().registerMonster(monster); + } + spos.y--; monster.setPosition(spos); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @@ -1929,9 +1977,9 @@ public class MapleMap { c.announce(MaplePacketCreator.spawnMonster(monster, true, effect)); } }); - + monster.aggroUpdateController(); - + if (monster.hasBossHPBar()) { broadcastBossHpMessage(monster, monster.hashCode(), monster.makeBossHPBarPacket(), monster.getPosition()); } @@ -1956,7 +2004,7 @@ public class MapleMap { public void makeMonsterReal(final MapleMonster monster) { monster.setFake(false); broadcastMessage(MaplePacketCreator.makeMonsterReal(monster)); - + monster.aggroUpdateController(); } @@ -1979,7 +2027,7 @@ public class MapleMap { } finally { reactor.unlockReactor(); } - + spawnReactor(reactor); } @@ -1991,9 +2039,11 @@ public class MapleMap { if (c.getPlayer().getParty() != null && (door.getOwnerId() == c.getPlayer().getId() || c.getPlayer().getParty().getMemberById(door.getOwnerId()) != null)) { c.announce(MaplePacketCreator.partyPortal(door.getFrom().getId(), door.getTo().getId(), door.toPosition())); } - + c.announce(MaplePacketCreator.spawnPortal(door.getFrom().getId(), door.getTo().getId(), door.toPosition())); - if(!door.inTown()) c.announce(MaplePacketCreator.spawnDoor(door.getOwnerId(), door.getPosition(), false)); + if (!door.inTown()) { + c.announce(MaplePacketCreator.spawnDoor(door.getOwnerId(), door.getPosition(), false)); + } } c.announce(MaplePacketCreator.enableActions()); @@ -2005,17 +2055,17 @@ public class MapleMap { } }); } - + public MaplePortal getDoorPortal(int doorid) { MaplePortal doorPortal = portals.get(0x80 + doorid); - if(doorPortal == null) { + if (doorPortal == null) { FilePrinter.printError(FilePrinter.EXCEPTION, "[DOOR] " + mapName + "(" + mapid + ") does not contain door portalid " + doorid); return portals.get(0x80); } - + return doorPortal; } - + public void spawnSummon(final MapleSummon summon) { spawnAndAddRangedMapObject(summon, new DelayedPacketCreation() { @Override @@ -2054,7 +2104,7 @@ public class MapleMap { for (MapleMapObject mo : players) { if (mist.makeChanceResult()) { MapleCharacter chr = (MapleCharacter) mo; - if (mist.getOwner().getId() == chr.getId() || mist.getOwner().getParty() != null && mist.getOwner().getParty().containsMembers(chr.getMPC())) { + if (mist.getOwner().getId() == chr.getId() || mist.getOwner().getParty() != null && mist.getOwner().getParty().containsMembers(chr.getMPC())) { chr.addMP((int) mist.getSourceSkill().getEffect(chr.getSkillLevel(mist.getSourceSkill().getId())).getX() * chr.getMp() / 100); } } @@ -2065,7 +2115,7 @@ public class MapleMap { } else { poisonSchedule = null; } - + Runnable mistSchedule = new Runnable() { @Override public void run() { @@ -2076,14 +2126,14 @@ public class MapleMap { broadcastMessage(mist.makeDestroyData()); } }; - + this.getChannelServer().registerMobMistCancelAction(mapid, mistSchedule, duration); } - + public void spawnKite(final MapleKite kite) { addMapObject(kite); broadcastMessage(kite.makeSpawnData()); - + Runnable expireKite = new Runnable() { @Override public void run() { @@ -2091,12 +2141,12 @@ public class MapleMap { broadcastMessage(kite.makeDestroyData()); } }; - + getWorldServer().registerTimedMapObject(expireKite, ServerConstants.KITE_EXPIRE_TIME); } - + public final void spawnItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, Point pos, final boolean ffaDrop, final boolean playerDrop) { - spawnItemDrop(dropper, owner, item, pos, (byte)(ffaDrop ? 2 : 0), playerDrop); + spawnItemDrop(dropper, owner, item, pos, (byte) (ffaDrop ? 2 : 0), playerDrop); } public final void spawnItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, Point pos, final byte dropType, final boolean playerDrop) { @@ -2115,44 +2165,45 @@ public class MapleMap { } } }, null); - + mdrop.lockItem(); try { broadcastItemDropMessage(mdrop, dropper.getPosition(), droppos, (byte) 0); } finally { mdrop.unlockItem(); } - + instantiateItemDrop(mdrop); activateItemReactors(mdrop, owner.getClient()); } - + public final void spawnItemDropList(List list, final MapleMapObject dropper, final MapleCharacter owner, Point pos) { spawnItemDropList(list, 1, 1, dropper, owner, pos, true, false); } - + public final void spawnItemDropList(List list, int minCopies, int maxCopies, final MapleMapObject dropper, final MapleCharacter owner, Point pos) { spawnItemDropList(list, minCopies, maxCopies, dropper, owner, pos, true, false); } - + // spawns item instances of all defined item ids on a list public final void spawnItemDropList(List list, int minCopies, int maxCopies, final MapleMapObject dropper, final MapleCharacter owner, Point pos, final boolean ffaDrop, final boolean playerDrop) { int copies = (maxCopies - minCopies) + 1; - if(copies < 1) return; - + if (copies < 1) { + return; + } + Collections.shuffle(list); - + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); Random rnd = new Random(); - + final Point dropPos = new Point(pos); dropPos.x -= (12 * list.size()); - - for(int i = 0; i < list.size(); i++) { - if(list.get(i) == 0) { + + for (int i = 0; i < list.size(); i++) { + if (list.get(i) == 0) { spawnMesoDrop(owner != null ? 10 * owner.getMesoRate() : 10, calcDropPos(dropPos, pos), dropper, owner, playerDrop, (byte) (ffaDrop ? 2 : 0)); - } - else { + } else { final Item drop; int randomedId = list.get(i); @@ -2164,7 +2215,7 @@ public class MapleMap { spawnItemDrop(dropper, owner, drop, calcDropPos(dropPos, pos), ffaDrop, playerDrop); } - + dropPos.x += 25; } } @@ -2172,7 +2223,7 @@ public class MapleMap { private void registerMapSchedule(Runnable r, long delay) { this.getChannelServer().registerOverallAction(mapid, r, delay); } - + private void activateItemReactors(final MapleMapItem drop, final MapleClient c) { final Item item = drop.getItem(); @@ -2190,13 +2241,13 @@ public class MapleMap { } } } - + public void searchItemReactors(final MapleReactor react) { if (react.getReactorType() == 100) { Pair reactProp = react.getReactItem(react.getEventState()); int reactItem = reactProp.getLeft(), reactQty = reactProp.getRight(); Rectangle reactArea = react.getArea(); - + List list; objectRLock.lock(); try { @@ -2204,17 +2255,17 @@ public class MapleMap { } finally { objectRLock.unlock(); } - - for(final MapleMapItem drop : list) { + + for (final MapleMapItem drop : list) { drop.lockItem(); try { - if(!drop.isPickedUp()) { + if (!drop.isPickedUp()) { final Item item = drop.getItem(); - + if (item != null && reactItem == item.getItemId() && reactQty == item.getQuantity()) { if (reactArea.contains(drop.getPosition())) { MapleClient owner = drop.getOwnerClient(); - if(owner != null) { + if (owner != null) { registerMapSchedule(new ActivateItemReactor(drop, react, owner), 5000); } } @@ -2226,7 +2277,7 @@ public class MapleMap { } } } - + public void changeEnvironment(String mapObj, int newState) { broadcastMessage(MaplePacketCreator.environmentChange(mapObj, newState)); } @@ -2234,14 +2285,14 @@ public class MapleMap { public void startMapEffect(String msg, int itemId) { startMapEffect(msg, itemId, 30000); } - + public void startMapEffect(String msg, int itemId, long time) { if (mapEffect != null) { return; } mapEffect = new MapleMapEffect(msg, itemId); broadcastMessage(mapEffect.makeStartData()); - + Runnable r = new Runnable() { @Override public void run() { @@ -2249,56 +2300,65 @@ public class MapleMap { mapEffect = null; } }; - + registerMapSchedule(r, time); } - + public MapleCharacter getAnyCharacterFromParty(int partyid) { chrRLock.lock(); try { Set list = mapParty.get(partyid); - if(list == null) return null; - - for(Integer cid : list) { + if (list == null) { + return null; + } + + for (Integer cid : list) { for (MapleCharacter c : this.characters) { if (c.getId() == cid) { return c; } } } - + return null; } finally { chrRLock.unlock(); } } - + private void addPartyMemberInternal(MapleCharacter chr) { int partyid = chr.getPartyId(); - if(partyid == -1) return; - + if (partyid == -1) { + return; + } + Set partyEntry = mapParty.get(partyid); - if(partyEntry == null) { + if (partyEntry == null) { partyEntry = new LinkedHashSet<>(); partyEntry.add(chr.getId()); - + mapParty.put(partyid, partyEntry); } else { partyEntry.add(chr.getId()); } } - + private void removePartyMemberInternal(MapleCharacter chr) { int partyid = chr.getPartyId(); - if(partyid == -1) return; - + if (partyid == -1) { + return; + } + Set partyEntry = mapParty.get(partyid); - if(partyEntry != null) { - if(partyEntry.size() > 1) partyEntry.remove(chr.getId()); - else mapParty.remove(partyid); + if (partyEntry != null) { + if (partyEntry.size() > 1) { + partyEntry.remove(chr.getId()); + } else { + mapParty.remove(partyid); + } } } - + public void addPartyMember(MapleCharacter chr) { chrWLock.lock(); try { @@ -2307,7 +2367,7 @@ public class MapleMap { chrWLock.unlock(); } } - + public void removePartyMember(MapleCharacter chr) { chrWLock.lock(); try { @@ -2316,7 +2376,7 @@ public class MapleMap { chrWLock.unlock(); } } - + public void removeParty(int partyid) { chrWLock.lock(); try { @@ -2325,27 +2385,27 @@ public class MapleMap { chrWLock.unlock(); } } - + public void addPlayer(final MapleCharacter chr) { int chrSize; chrWLock.lock(); try { characters.add(chr); chrSize = characters.size(); - + addPartyMemberInternal(chr); itemMonitorTimeout = 1; } finally { chrWLock.unlock(); } chr.setMapId(mapid); - + if (chrSize == 1) { - if(!hasItemMonitor()) { + if (!hasItemMonitor()) { startItemMonitor(); aggroMonitor.startAggroCoordinator(); } - + if (onFirstUserEnter.length() != 0 && !chr.hasEntered(onFirstUserEnter, mapid) && MapScriptManager.getInstance().scriptExists(onFirstUserEnter, true)) { chr.enteredScript(onFirstUserEnter, mapid); MapScriptManager.getInstance().runMapScript(chr.getClient(), onFirstUserEnter, true); @@ -2361,7 +2421,7 @@ public class MapleMap { chr.cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING); chr.cancelBuffStats(MapleBuffStat.MONSTER_RIDING); } - + if (mapid == 200090060) { // To Rien int travelTime = getWorldServer().getTransportationTime(1 * 60 * 1000); chr.announce(MaplePacketCreator.getClock(travelTime / 1000)); @@ -2436,9 +2496,11 @@ public class MapleMap { }, travelTime); } else if (MapleMiniDungeonInfo.isDungeonMap(mapid)) { MapleMiniDungeon mmd = chr.getClient().getChannelServer().getMiniDungeon(mapid); - if(mmd != null) mmd.registerPlayer(chr); + if (mmd != null) { + mmd.registerPlayer(chr); + } } - + MaplePet[] pets = chr.getPets(); for (int i = 0; i < pets.length; i++) { if (pets[i] != null) { @@ -2448,9 +2510,24 @@ public class MapleMap { break; } } - + if (chr.getMonsterCarnival() != null) { + chr.getClient().announce(MaplePacketCreator.getClock(chr.getMonsterCarnival().getTimeLeftSeconds())); + if (isCPQMap()) { + int team = -1; + int oposition = -1; + if (chr.getTeam() == 0) { + team = 0; + oposition = 1; + } + if (chr.getTeam() == 1) { + team = 1; + oposition = 0; + } + chr.getClient().announce(MaplePacketCreator.startMonsterCarnival(chr, team, oposition)); + } + } chr.removeSandboxItems(); - + if (chr.isHidden()) { broadcastGMSpawnPlayerMapObjectMessage(chr, chr, true); chr.announce(MaplePacketCreator.getGMEffect(0x10, (byte) 1)); @@ -2462,7 +2539,7 @@ public class MapleMap { } sendObjectPlacement(chr.getClient()); - + if (isStartingEventMap() && !eventStarted()) { chr.getMap().getPortal("join00").setPortalStatus(false); } @@ -2522,26 +2599,22 @@ public class MapleMap { if (mapid == 109060000) { chr.announce(MaplePacketCreator.rollSnowBall(true, 0, null, null)); } - - MonsterCarnival carnival = chr.getCarnival(); - MonsterCarnivalParty cparty = chr.getCarnivalParty(); - if (carnival != null && cparty != null && (mapid == 980000101 || mapid == 980000201 || mapid == 980000301 || mapid == 980000401 || mapid == 980000501 || mapid == 980000601)) { - chr.getClient().announce(MaplePacketCreator.getClock((int) (carnival.getTimeLeft() / 1000))); - chr.getClient().announce(MaplePacketCreator.startCPQ(chr, carnival.oppositeTeam(cparty))); - } if (hasClock()) { Calendar cal = Calendar.getInstance(); chr.getClient().announce((MaplePacketCreator.getClockTime(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND)))); } if (hasBoat() > 0) { - if(hasBoat() == 1) chr.getClient().announce((MaplePacketCreator.boatPacket(true))); - else chr.getClient().announce(MaplePacketCreator.boatPacket(false)); + if (hasBoat() == 1) { + chr.getClient().announce((MaplePacketCreator.boatPacket(true))); + } else { + chr.getClient().announce(MaplePacketCreator.boatPacket(false)); + } } - + chr.receivePartyMemberHP(); announcePlayerDiseases(chr.getClient()); } - + private static void announcePlayerDiseases(final MapleClient c) { Server.getInstance().registerAnnouncePlayerDiseases(c); } @@ -2556,7 +2629,7 @@ public class MapleMap { MaplePortal portal = spawnPoints.get(new Random().nextInt(spawnPoints.size())); return portal != null ? portal : getPortal(0); } - + public MaplePortal findClosestPlayerSpawnpoint(Point from) { MaplePortal closest = null; double shortestDistance = Double.POSITIVE_INFINITY; @@ -2569,7 +2642,7 @@ public class MapleMap { } return closest; } - + public MaplePortal findClosestPortal(Point from) { MaplePortal closest = null; double shortestDistance = Double.POSITIVE_INFINITY; @@ -2582,11 +2655,11 @@ public class MapleMap { } return closest; } - + public MaplePortal findMarketPortal() { for (MaplePortal portal : portals.values()) { String ptScript = portal.getScriptName(); - if(ptScript != null && ptScript.contains("market")) { + if (ptScript != null && ptScript.contains("market")) { return portal; } } @@ -2594,17 +2667,16 @@ public class MapleMap { } /* - public Collection getPortals() { - return Collections.unmodifiableCollection(portals.values()); - } - */ - + public Collection getPortals() { + return Collections.unmodifiableCollection(portals.values()); + } + */ public void addPlayerPuppet(MapleCharacter player) { for (MapleMonster mm : this.getMonsters()) { mm.aggroAddPuppet(player); } } - + public void removePlayerPuppet(MapleCharacter player) { for (MapleMonster mm : this.getMonsters()) { mm.aggroRemovePuppet(player); @@ -2613,10 +2685,10 @@ public class MapleMap { public void removePlayer(MapleCharacter chr) { Channel cserv = chr.getClient().getChannelServer(); - + cserv.unregisterFaceExpression(mapid, chr); chr.unregisterChairBuff(); - + chrWLock.lock(); try { removePartyMemberInternal(chr); @@ -2624,16 +2696,16 @@ public class MapleMap { } finally { chrWLock.unlock(); } - + if (MapleMiniDungeonInfo.isDungeonMap(mapid)) { MapleMiniDungeon mmd = cserv.getMiniDungeon(mapid); - if(mmd != null) { - if(!mmd.unregisterPlayer(chr)) { + if (mmd != null) { + if (!mmd.unregisterPlayer(chr)) { cserv.removeMiniDungeon(mapid); } } } - + removeMapObject(chr.getObjectId()); if (!chr.isHidden()) { broadcastMessage(MaplePacketCreator.removePlayerFromMap(chr.getId())); @@ -2642,7 +2714,7 @@ public class MapleMap { } chr.leaveMap(); - + for (MapleSummon summon : new ArrayList<>(chr.getSummonsValues())) { if (summon.isStationary()) { chr.cancelEffectFromBuffStat(MapleBuffStat.PUPPET); @@ -2660,11 +2732,11 @@ public class MapleMap { } } } - + public void broadcastMessage(final byte[] packet) { broadcastMessage(null, packet, Double.POSITIVE_INFINITY, null); } - + public void broadcastGMMessage(final byte[] packet) { broadcastGMMessage(null, packet, Double.POSITIVE_INFINITY, null); } @@ -2701,7 +2773,7 @@ public class MapleMap { public void broadcastMessage(final byte[] packet, Point rangedFrom) { broadcastMessage(null, packet, getRangedDistance(), rangedFrom); } - + /** * Always ranged from point. Does not repeat to source. * @@ -2731,15 +2803,15 @@ public class MapleMap { chrRLock.unlock(); } } - + public void broadcastBossHpMessage(MapleMonster mm, int bossHash, final byte[] packet) { broadcastBossHpMessage(mm, bossHash, null, packet, Double.POSITIVE_INFINITY, null); } - + public void broadcastBossHpMessage(MapleMonster mm, int bossHash, final byte[] packet, Point rangedFrom) { broadcastBossHpMessage(mm, bossHash, null, packet, getRangedDistance(), rangedFrom); } - + private void broadcastBossHpMessage(MapleMonster mm, int bossHash, MapleCharacter source, final byte[] packet, double rangeSq, Point rangedFrom) { chrRLock.lock(); try { @@ -2762,17 +2834,17 @@ public class MapleMap { private void broadcastItemDropMessage(MapleMapItem mdrop, Point dropperPos, Point dropPos, byte mod, Point rangedFrom) { broadcastItemDropMessage(mdrop, dropperPos, dropPos, mod, getRangedDistance(), rangedFrom); } - + private void broadcastItemDropMessage(MapleMapItem mdrop, Point dropperPos, Point dropPos, byte mod) { broadcastItemDropMessage(mdrop, dropperPos, dropPos, mod, Double.POSITIVE_INFINITY, null); } - + private void broadcastItemDropMessage(MapleMapItem mdrop, Point dropperPos, Point dropPos, byte mod, double rangeSq, Point rangedFrom) { chrRLock.lock(); try { for (MapleCharacter chr : characters) { final byte[] packet = MaplePacketCreator.dropItemFromMapObject(chr.getParty() != null, mdrop, dropperPos, dropPos, mod); - + if (rangeSq < Double.POSITIVE_INFINITY) { if (rangedFrom.distanceSq(chr.getPosition()) <= rangeSq) { chr.announce(packet); @@ -2785,15 +2857,15 @@ public class MapleMap { chrRLock.unlock(); } } - + public void broadcastSpawnPlayerMapObjectMessage(MapleCharacter source, MapleCharacter player, boolean enteringField) { broadcastSpawnPlayerMapObjectMessage(source, player, enteringField, false); } - + public void broadcastGMSpawnPlayerMapObjectMessage(MapleCharacter source, MapleCharacter player, boolean enteringField) { broadcastSpawnPlayerMapObjectMessage(source, player, enteringField, true); } - + private void broadcastSpawnPlayerMapObjectMessage(MapleCharacter source, MapleCharacter player, boolean enteringField, boolean gmBroadcast) { chrRLock.lock(); try { @@ -2816,7 +2888,7 @@ public class MapleMap { chrRLock.unlock(); } } - + public void broadcastUpdateCharLookMessage(MapleCharacter source, MapleCharacter player) { chrRLock.lock(); try { @@ -2829,15 +2901,15 @@ public class MapleMap { chrRLock.unlock(); } } - + public void dropMessage(int type, String message) { broadcastStringMessage(type, message); } - + public void broadcastStringMessage(int type, String message) { broadcastMessage(MaplePacketCreator.serverNotice(type, message)); } - + private static boolean isNonRangedType(MapleMapObjectType type) { switch (type) { case NPC: @@ -2856,14 +2928,14 @@ public class MapleMap { private void sendObjectPlacement(MapleClient mapleClient) { MapleCharacter chr = mapleClient.getPlayer(); Collection objects; - + objectRLock.lock(); try { objects = new ArrayList<>(mapobjects.values()); } finally { objectRLock.unlock(); } - + for (MapleMapObject o : objects) { if (isNonRangedType(o.getType())) { o.sendSpawnData(mapleClient); @@ -2879,13 +2951,13 @@ public class MapleMap { } finally { objectWLock.unlock(); } - + //continue; } } } } - + if (chr != null) { for (MapleMapObject o : getMapObjectsInRange(chr.getPosition(), getRangedDistance(), rangedMapobjectTypes)) { if (o.getType() == MapleMapObjectType.REACTOR) { @@ -2951,7 +3023,7 @@ public class MapleMap { public MaplePortal getPortal(int portalid) { return portals.get(portalid); } - + public void addMapleArea(Rectangle rec) { areas.add(rec); } @@ -2971,19 +3043,19 @@ public class MapleMap { public MapleFootholdTree getFootholds() { return footholds; } - + public void setMapPointBoundings(int px, int py, int h, int w) { mapArea.setBounds(px, py, w, h); } - + public void setMapLineBoundings(int vrTop, int vrBottom, int vrLeft, int vrRight) { mapArea.setBounds(vrLeft, vrTop, vrRight - vrLeft, vrBottom - vrTop); } - + public MapleMonsterAggroCoordinator getAggroCoordinator() { return aggroMonitor; } - + /** * it's threadsafe, gtfo :D * @@ -2999,28 +3071,28 @@ public class MapleMap { spawnMonster(sp.getMonster()); } } - + public void addAllMonsterSpawn(MapleMonster monster, int mobTime, int team) { Point newpos = calcPointBelow(monster.getPosition()); newpos.y -= 1; SpawnPoint sp = new SpawnPoint(monster, newpos, !monster.isMobile(), mobTime, mobInterval, team); allMonsterSpawn.add(sp); } - + public void removeMonsterSpawn(int mobId, int x, int y) { // assumption: spawn points are identified by tuple (lifeid, x, y) - + Point checkpos = calcPointBelow(new Point(x, y)); checkpos.y -= 1; - + List toRemove = new LinkedList<>(); - for(SpawnPoint sp: getMonsterSpawn()) { + for (SpawnPoint sp : getMonsterSpawn()) { Point pos = sp.getPosition(); if (sp.getMonsterId() == mobId && checkpos.equals(pos)) { toRemove.add(sp); } } - + if (!toRemove.isEmpty()) { synchronized (monsterSpawn) { for (SpawnPoint sp : toRemove) { @@ -3029,21 +3101,21 @@ public class MapleMap { } } } - + public void removeAllMonsterSpawn(int mobId, int x, int y) { // assumption: spawn points are identified by tuple (lifeid, x, y) - + Point checkpos = calcPointBelow(new Point(x, y)); checkpos.y -= 1; - + List toRemove = new LinkedList<>(); - for(SpawnPoint sp: getAllMonsterSpawn()) { + for (SpawnPoint sp : getAllMonsterSpawn()) { Point pos = sp.getPosition(); if (sp.getMonsterId() == mobId && checkpos.equals(pos)) { toRemove.add(sp); } } - + if (!toRemove.isEmpty()) { synchronized (allMonsterSpawn) { for (SpawnPoint sp : toRemove) { @@ -3052,10 +3124,10 @@ public class MapleMap { } } } - + public void reportMonsterSpawnPoints(MapleCharacter chr) { chr.dropMessage(6, "Mob spawnpoints on map " + getId() + ", with available Mob SPs " + monsterSpawn.size() + ", used " + spawnedMonstersOnMap.get() + ":"); - for(SpawnPoint sp: getAllMonsterSpawn()) { + for (SpawnPoint sp : getAllMonsterSpawn()) { chr.dropMessage(6, " id: " + sp.getMonsterId() + " canSpawn: " + !sp.getDenySpawn() + " numSpawned: " + sp.getSpawned() + " x: " + sp.getPosition().getX() + " y: " + sp.getPosition().getY() + " time: " + sp.getMobTime() + " team: " + sp.getTeam()); } } @@ -3064,17 +3136,17 @@ public class MapleMap { chrRLock.lock(); try { Map mapChars = new HashMap<>(characters.size()); - - for(MapleCharacter chr : characters) { + + for (MapleCharacter chr : characters) { mapChars.put(chr.getId(), chr); } - + return mapChars; } finally { chrRLock.unlock(); } } - + public Collection getCharacters() { chrRLock.lock(); try { @@ -3119,7 +3191,7 @@ public class MapleMap { public void movePlayer(MapleCharacter player, Point newPosition) { player.setPosition(newPosition); - + try { Collection visibleObjects = player.getVisibleMapObjects(); MapleMapObject[] visibleObjectsNow = visibleObjects.toArray(new MapleMapObject[visibleObjects.size()]); @@ -3137,7 +3209,7 @@ public class MapleMap { } catch (Exception e) { e.printStackTrace(); } - + for (MapleMapObject mo : getMapObjectsInRange(player.getPosition(), getRangedDistance(), rangedMapobjectTypes)) { if (!player.isMapObjectVisible(mo)) { mo.sendSpawnData(player.getClient()); @@ -3145,10 +3217,10 @@ public class MapleMap { } } } - + public final void toggleEnvironment(final String ms) { Map env = getEnvironment(); - + if (env.containsKey(ms)) { moveEnvironment(ms, env.get(ms) == 1 ? 2 : 1); } else { @@ -3158,7 +3230,7 @@ public class MapleMap { public final void moveEnvironment(final String ms, final int type) { broadcastMessage(MaplePacketCreator.environmentMove(ms, type)); - + objectWLock.lock(); try { environment.put(ms, type); @@ -3196,6 +3268,10 @@ public class MapleMap { return clock; } + public void addClock(int seconds) { + broadcastMessage(MaplePacketCreator.getClock(seconds)); + } + public void setTown(boolean isTown) { this.town = isTown; } @@ -3235,7 +3311,7 @@ public class MapleMap { public void setBackgroundTypes(HashMap backTypes) { backgroundTypes.putAll(backTypes); } - + // not really costly to keep generating imo public void sendNightEffect(MapleCharacter mc) { for (Entry types : backgroundTypes.entrySet()) { @@ -3244,7 +3320,7 @@ public class MapleMap { } } } - + public void broadcastNightEffect() { chrRLock.lock(); try { @@ -3269,15 +3345,15 @@ public class MapleMap { } return null; } - + public boolean makeDisappearItemFromMap(MapleMapObject mapobj) { - if(mapobj instanceof MapleMapItem) { + if (mapobj instanceof MapleMapItem) { return makeDisappearItemFromMap((MapleMapItem) mapobj); } else { return mapobj == null; // no drop to make disappear... } } - + public boolean makeDisappearItemFromMap(MapleMapItem mapitem) { if (mapitem != null && mapitem == getMapObject(mapitem.getObjectId())) { mapitem.lockItem(); @@ -3285,18 +3361,19 @@ public class MapleMap { if (mapitem.isPickedUp()) { return true; } - + MapleMap.this.pickItemDrop(MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 0, 0), mapitem); return true; } finally { mapitem.unlockItem(); } } - + return false; } private class MobLootEntry implements Runnable { + private byte droptype; private int mobpos; private int chRate; @@ -3324,7 +3401,7 @@ public class MapleMap { @Override public void run() { byte d = 1; - + // Normal Drops d = dropItemsFromMonsterOnMap(dropEntry, pos, d, chRate, droptype, mobpos, chr, mob); @@ -3336,7 +3413,7 @@ public class MapleMap { dropItemsFromMonsterOnMap(otherQuestEntry, pos, d, chRate, droptype, mobpos, chr, mob); } } - + private class ActivateItemReactor implements Runnable { private MapleMapItem mapitem; @@ -3353,7 +3430,7 @@ public class MapleMap { public void run() { reactor.lockReactor(); try { - if(reactor.getReactorType() == 100) { + if (reactor.getReactorType() == 100) { if (reactor.getShouldCollect() == true && mapitem != null && mapitem == getMapObject(mapitem.getObjectId())) { mapitem.lockItem(); try { @@ -3365,15 +3442,15 @@ public class MapleMap { reactor.setShouldCollect(false); MapleMap.this.broadcastMessage(MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 0, 0), mapitem.getPosition()); - + droppedItemCount.decrementAndGet(); MapleMap.this.removeMapObject(mapitem); - + reactor.hitReactor(c); if (reactor.getDelay() > 0) { MapleMap reactorMap = reactor.getMap(); - + reactorMap.getChannelServer().registerOverallAction(reactorMap.getId(), new Runnable() { @Override public void run() { @@ -3397,25 +3474,27 @@ public class MapleMap { } } } - + public void instanceMapFirstSpawn(int difficulty, boolean isPq) { - for(SpawnPoint spawnPoint: getAllMonsterSpawn()) { - if(spawnPoint.getMobTime() == -1) { //just those allowed to be spawned only once + for (SpawnPoint spawnPoint : getAllMonsterSpawn()) { + if (spawnPoint.getMobTime() == -1) { //just those allowed to be spawned only once spawnMonster(spawnPoint.getMonster()); } } } public void instanceMapRespawn() { - if(!allowSummons) return; - + if (!allowSummons) { + return; + } + final int numShouldSpawn = (short) ((monsterSpawn.size() - spawnedMonstersOnMap.get()));//Fking lol'd if (numShouldSpawn > 0) { List randomSpawn = getMonsterSpawn(); Collections.shuffle(randomSpawn); int spawned = 0; for (SpawnPoint spawnPoint : randomSpawn) { - if(spawnPoint.shouldSpawn()) { + if (spawnPoint.shouldSpawn()) { spawnMonster(spawnPoint.getMonster()); spawned++; if (spawned >= numShouldSpawn) { @@ -3425,17 +3504,19 @@ public class MapleMap { } } } - + public void instanceMapForceRespawn() { - if(!allowSummons) return; - + if (!allowSummons) { + return; + } + final int numShouldSpawn = (short) ((monsterSpawn.size() - spawnedMonstersOnMap.get()));//Fking lol'd if (numShouldSpawn > 0) { List randomSpawn = getMonsterSpawn(); Collections.shuffle(randomSpawn); int spawned = 0; for (SpawnPoint spawnPoint : randomSpawn) { - if(spawnPoint.shouldForceSpawn()) { + if (spawnPoint.shouldForceSpawn()) { spawnMonster(spawnPoint.getMonster()); spawned++; if (spawned >= numShouldSpawn) { @@ -3445,35 +3526,35 @@ public class MapleMap { } } } - + public void closeMapSpawnPoints() { for (SpawnPoint spawnPoint : getMonsterSpawn()) { spawnPoint.setDenySpawn(true); } } - + public void restoreMapSpawnPoints() { for (SpawnPoint spawnPoint : getMonsterSpawn()) { spawnPoint.setDenySpawn(false); } } - + public void setAllowSpawnPointInBox(boolean allow, Rectangle box) { - for(SpawnPoint sp: getMonsterSpawn()) { - if(box.contains(sp.getPosition())) { + for (SpawnPoint sp : getMonsterSpawn()) { + if (box.contains(sp.getPosition())) { sp.setDenySpawn(!allow); } } } - + public void setAllowSpawnPointInRange(boolean allow, Point from, double rangeSq) { - for(SpawnPoint sp: getMonsterSpawn()) { - if(from.distanceSq(sp.getPosition()) <= rangeSq) { + for (SpawnPoint sp : getMonsterSpawn()) { + if (from.distanceSq(sp.getPosition()) <= rangeSq) { sp.setDenySpawn(!allow); } } } - + public SpawnPoint findClosestSpawnpoint(Point from) { SpawnPoint closest = null; double shortestDistance = Double.POSITIVE_INFINITY; @@ -3490,58 +3571,59 @@ public class MapleMap { private static double getCurrentSpawnRate(int numPlayers) { return 0.550 + (0.075 * Math.min(6, numPlayers)); } - + private int getNumShouldSpawn(int numPlayers) { /* - System.out.println("----------------------------------"); - for (SpawnPoint spawnPoint : getMonsterSpawn()) { - System.out.println("sp " + spawnPoint.getPosition().getX() + ", " + spawnPoint.getPosition().getY() + ": " + spawnPoint.getDenySpawn()); - } - System.out.println("try " + monsterSpawn.size() + " - " + spawnedMonstersOnMap.get()); - System.out.println("----------------------------------"); - */ - - if(ServerConstants.USE_ENABLE_FULL_RESPAWN) { + System.out.println("----------------------------------"); + for (SpawnPoint spawnPoint : getMonsterSpawn()) { + System.out.println("sp " + spawnPoint.getPosition().getX() + ", " + spawnPoint.getPosition().getY() + ": " + spawnPoint.getDenySpawn()); + } + System.out.println("try " + monsterSpawn.size() + " - " + spawnedMonstersOnMap.get()); + System.out.println("----------------------------------"); + */ + + if (ServerConstants.USE_ENABLE_FULL_RESPAWN) { return (monsterSpawn.size() - spawnedMonstersOnMap.get()); } - + int maxNumShouldSpawn = (int) Math.ceil(getCurrentSpawnRate(numPlayers) * monsterSpawn.size()); return maxNumShouldSpawn - spawnedMonstersOnMap.get(); } - + public void respawn() { - if(!allowSummons) return; - + if (!allowSummons) { + return; + } + int numPlayers; chrRLock.lock(); try { numPlayers = characters.size(); - - if(numPlayers == 0) { + + if (numPlayers == 0) { return; } } finally { chrRLock.unlock(); } - + int numShouldSpawn = getNumShouldSpawn(numPlayers); - if(numShouldSpawn > 0) { + if (numShouldSpawn > 0) { List randomSpawn = new ArrayList<>(getMonsterSpawn()); Collections.shuffle(randomSpawn); short spawned = 0; - for(SpawnPoint spawnPoint : randomSpawn) { - if(spawnPoint.shouldSpawn()) { + for (SpawnPoint spawnPoint : randomSpawn) { + if (spawnPoint.shouldSpawn()) { spawnMonster(spawnPoint.getMonster()); spawned++; - - if(spawned >= numShouldSpawn) { + if (spawned >= numShouldSpawn) { break; } } } } } - + public final int getNumPlayersInArea(final int index) { return getNumPlayersInRect(getArea(index)); } @@ -3611,7 +3693,7 @@ public class MapleMap { public void setDocked(boolean isDocked) { this.docked = isDocked; } - + public boolean getDocked() { return this.docked; } @@ -3717,7 +3799,7 @@ public class MapleMap { if (timeLimit != 0 && timeLimit < System.currentTimeMillis()) { warpEveryone(getForcedReturnId()); } - + if (getCharacters().isEmpty()) { resetReactors(); killAllMonsters(); @@ -3726,7 +3808,7 @@ public class MapleMap { if (mapid >= 922240100 && mapid <= 922240119) { toggleHiddenNPC(9001108); } - + if (mapMonitor != null) { mapMonitor.cancel(true); mapMonitor = null; @@ -3758,15 +3840,15 @@ public class MapleMap { public void warpEveryone(int to) { List players = new ArrayList<>(getCharacters()); - + for (MapleCharacter chr : players) { chr.changeMap(to); } } - + public void warpEveryone(int to, int pto) { List players = new ArrayList<>(getCharacters()); - + for (MapleCharacter chr : players) { chr.changeMap(to, pto); } @@ -3800,7 +3882,7 @@ public class MapleMap { private boolean specialEquip() {//Maybe I shouldn't use fieldType :\ return fieldType == 4 || fieldType == 19; } - + public void setCoconut(MapleCoconut nut) { this.coconut = nut; } @@ -3911,7 +3993,7 @@ public class MapleMap { chrRLock.unlock(); } } - + public void setMobInterval(short interval) { this.mobInterval = interval; } @@ -3919,71 +4001,74 @@ public class MapleMap { public short getMobInterval() { return mobInterval; } - + public void clearMapObjects() { clearDrops(); killAllMonsters(); resetReactors(); } - + public final void resetFully() { resetMapObjects(); } - + public void resetMapObjects() { resetMapObjects(1, false); } - + public void resetPQ() { resetPQ(1); } - + public void resetPQ(int difficulty) { resetMapObjects(difficulty, true); } - + public void resetMapObjects(int difficulty, boolean isPq) { clearMapObjects(); - + restoreMapSpawnPoints(); instanceMapFirstSpawn(difficulty, isPq); } - + public void broadcastShip(final boolean state) { broadcastMessage(MaplePacketCreator.boatPacket(state)); this.setDocked(state); } - + public void broadcastEnemyShip(final boolean state) { broadcastMessage(MaplePacketCreator.crogBoatPacket(state)); this.setDocked(state); } - + public boolean isDojoMap() { return mapid >= 925020000 && mapid < 925040000; } - + public boolean isDojoFightMap() { return isDojoMap() && (((mapid / 100) % 100) % 6) > 0; } - + public boolean isHorntailDefeated() { // all parts of dead horntail can be found here? - for(int i = 8810010; i <= 8810017; i++) { - if(getMonsterById(i) == null) return false; + for (int i = 8810010; i <= 8810017; i++) { + if (getMonsterById(i) == null) { + return false; + } } - + return true; } - + public void spawnHorntailOnGroundBelow(final Point targetPoint) { // ayy lmao MapleMonster htIntro = MapleLifeFactory.getMonster(8810026); spawnMonsterOnGroundBelow(htIntro, targetPoint); // htintro spawn animation converting into horntail detected thanks to Arnah - + final MapleMonster ht = MapleLifeFactory.getMonster(8810018); ht.setParentMobOid(htIntro.getObjectId()); ht.addListener(new MonsterListener() { @Override - public void monsterKilled(int aniTime) {} + public void monsterKilled(int aniTime) { + } @Override public void monsterDamaged(MapleCharacter from, int trueDmg) { @@ -4003,7 +4088,8 @@ public class MapleMap { m.addListener(new MonsterListener() { @Override - public void monsterKilled(int aniTime) {} + public void monsterKilled(int aniTime) { + } @Override public void monsterDamaged(MapleCharacter from, int trueDmg) { @@ -4020,40 +4106,40 @@ public class MapleMap { spawnMonsterOnGroundBelow(m, targetPoint); } } - + public void dispose() { - for(MapleMonster mm : this.getMonsters()) { + for (MapleMonster mm : this.getMonsters()) { mm.dispose(); } - + clearMapObjects(); - + event = null; footholds = null; portals.clear(); mapEffect = null; - - if(mapMonitor != null) { + + if (mapMonitor != null) { mapMonitor.cancel(false); mapMonitor = null; } - + chrWLock.lock(); try { aggroMonitor.dispose(); aggroMonitor = null; - - if(itemMonitor != null) { + + if (itemMonitor != null) { itemMonitor.cancel(false); itemMonitor = null; } - if(expireItemsTask != null) { + if (expireItemsTask != null) { expireItemsTask.cancel(false); expireItemsTask = null; } - - if(mobSpawnLootTask != null) { + + if (mobSpawnLootTask != null) { mobSpawnLootTask.cancel(false); mobSpawnLootTask = null; } @@ -4061,4 +4147,239 @@ public class MapleMap { chrWLock.unlock(); } } + + private final List takenSpawns = new LinkedList<>(); + private final List guardianSpawns = new LinkedList<>(); + private final List blueTeamBuffs = new ArrayList(); + private final List redTeamBuffs = new ArrayList(); + private List skillIds = new ArrayList(); + private List> mobsToSpawn = new ArrayList(); + + public List getBlueTeamBuffs() { + return blueTeamBuffs; + } + + public List getRedTeamBuffs() { + return redTeamBuffs; + } + + public void clearBuffList() { + redTeamBuffs.clear(); + blueTeamBuffs.clear(); + } + + public List getAllPlayer() { + return getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.PLAYER)); + } + + public boolean isCPQMap() { + switch (this.getId()) { + case 980000101: + case 980000201: + case 980000301: + case 980000401: + case 980000501: + case 980000601: + case 980031100: + case 980032100: + case 980033100: + return true; + } + return false; + } + + public boolean isCPQMap2() { + switch (this.getId()) { + case 980031100: + case 980032100: + case 980033100: + return true; + } + return false; + } + + public boolean isCPQLobby() { + switch (this.getId()) { + case 980000100: + case 980000200: + case 980000300: + case 980000400: + case 980000500: + case 980000600: + return true; + } + return false; + } + + public boolean isBlueCPQMap() { + switch (this.getId()) { + case 980000501: + case 980000601: + case 980031200: + case 980032200: + case 980033200: + return true; + } + return false; + } + + public boolean isPurpleCPQMap() { + switch (this.getId()) { + case 980000301: + case 980000401: + case 980031200: + case 980032200: + case 980033200: + return true; + } + return false; + } + + public Point getRandomSP(int team) { + if (takenSpawns.size() > 0) { + for (SpawnPoint sp : monsterSpawn) { + for (Point pt : takenSpawns) { + if ((sp.getPosition().x == pt.x && sp.getPosition().y == pt.y) || (sp.getTeam() != team && !this.isBlueCPQMap())) { + continue; + } else { + takenSpawns.add(pt); + return sp.getPosition(); + } + } + } + } else { + for (SpawnPoint sp : monsterSpawn) { + if (sp.getTeam() == team || this.isBlueCPQMap()) { + takenSpawns.add(sp.getPosition()); + return sp.getPosition(); + } + } + } + return null; + } + + public GuardianSpawnPoint getRandomGuardianSpawn(int team) { + boolean alltaken = false; + for (GuardianSpawnPoint a : this.guardianSpawns) { + if (!a.isTaken()) { + alltaken = false; + break; + } + } + if (alltaken) { + return null; + } + if (this.guardianSpawns.size() > 0) { + while (true) { + for (GuardianSpawnPoint gsp : this.guardianSpawns) { + if (!gsp.isTaken() && Math.random() < 0.3 && (gsp.getTeam() == -1 || gsp.getTeam() == team)) { + return gsp; + } + } + } + } + return null; + } + + public void addGuardianSpawnPoint(GuardianSpawnPoint a) { + this.guardianSpawns.add(a); + } + + public int spawnGuardian(int team, int num) { + try { + if (team == 0 && redTeamBuffs.size() >= 4 || team == 1 && blueTeamBuffs.size() >= 4) { + return 2; + } + final MCSkill skil = MapleCarnivalFactory.getInstance().getGuardian(num); + if (team == 0 && redTeamBuffs.contains(skil)) { + return 0; + } else if (team == 1 && blueTeamBuffs.contains(skil)) { + return 0; + } + GuardianSpawnPoint pt = this.getRandomGuardianSpawn(team); + if (pt == null) { + return -1; + } + int reactorID = 9980000 + team; + MapleReactor reactor = new MapleReactor(MapleReactorFactory.getReactorS(reactorID), reactorID); + pt.setTaken(true); + reactor.setPosition(pt.getPosition()); + reactor.setName(team + "" + num); //lol + reactor.resetReactorActions(0); + this.spawnReactor(reactor); + reactor.setGuardian(pt); + this.buffMonsters(team, skil); + getReactorByOid(reactor.getObjectId()).hitReactor(((MapleCharacter) this.getAllPlayer().get(0)).getClient()); + } catch (Exception e) { + e.printStackTrace(); + } + return 1; + } + + public void buffMonsters(int team, MCSkill skil) { + if (team == 0) { + redTeamBuffs.add(skil); + } else if (team == 1) { + blueTeamBuffs.add(skil); + } + for (MapleMapObject mmo : this.mapobjects.values()) { + if (mmo.getType() == MapleMapObjectType.MONSTER) { + MapleMonster mob = (MapleMonster) mmo; + if (mob.getTeam() == team) { + if (skil != null) { + skil.getSkill().applyEffect(null, mob, false, null); + } + } + + } + } + } + + public final List getSkillIds() { + return skillIds; + } + + public final void addSkillId(int z) { + this.skillIds.add(z); + } + + public final void addMobSpawn(int mobId, int spendCP) { + this.mobsToSpawn.add(new Pair(mobId, spendCP)); + } + + public final List> getMobsToSpawn() { + return mobsToSpawn; + } + + public boolean isCPQWinnerMap() { + switch (this.getId()) { + case 980000103: + case 980000203: + case 980000303: + case 980000403: + case 980000503: + case 980000603: + case 980031300: + case 980032300: + case 980033300: + return true; + } + return false; + } + + public boolean isCPQLoserMap() { + switch (this.getId()) { + case 980000104: + case 980000204: + case 980000304: + case 980000404: + case 980000504: + case 980000604: + case 980031400: + case 980032400: + case 980033400: + return true; + } + return false; + } } diff --git a/src/server/maps/MapleMapFactory.java b/src/server/maps/MapleMapFactory.java index 9b2c0d3f98..05a41ef13c 100644 --- a/src/server/maps/MapleMapFactory.java +++ b/src/server/maps/MapleMapFactory.java @@ -48,12 +48,14 @@ import server.life.MapleMonster; import server.life.MaplePlayerNPC; import server.life.MaplePlayerNPCFactory; import scripting.event.EventInstanceManager; +import server.partyquest.GuardianSpawnPoint; import tools.DatabaseConnection; import tools.StringUtil; public class MapleMapFactory { + private static Map mapRecoveryRate = new HashMap<>(); - + private MapleDataProvider source; private MapleData nameData; private EventInstanceManager event; @@ -68,12 +70,12 @@ public class MapleMapFactory { this.world = world; this.channel = channel; this.event = eim; - + ReentrantReadWriteLock rrwl = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_FACTORY); this.mapsRLock = rrwl.readLock(); this.mapsWLock = rrwl.writeLock(); } - + public MapleMap resetMap(int mapid) { mapsWLock.lock(); try { @@ -81,14 +83,23 @@ public class MapleMapFactory { } finally { mapsWLock.unlock(); } - + return getMap(mapid); } - + private void loadLifeFromWz(MapleMap map, MapleData mapData) { for (MapleData life : mapData.getChildByPath("life")) { + life.getName(); String id = MapleDataTool.getString(life.getChildByPath("id")); String type = MapleDataTool.getString(life.getChildByPath("type")); + int team = MapleDataTool.getInt("team", life, -1); + if (map.isCPQMap2() && type.equals("m")) { + if((Integer.parseInt(life.getName()) % 2) == 0) { + team = 0; + } else { + team = 1; + } + } int cy = MapleDataTool.getInt(life.getChildByPath("cy")); MapleData dF = life.getChildByPath("f"); int f = (dF != null) ? MapleDataTool.getInt(dF) : 0; @@ -99,12 +110,11 @@ public class MapleMapFactory { int y = MapleDataTool.getInt(life.getChildByPath("y")); int hide = MapleDataTool.getInt("hide", life, 0); int mobTime = MapleDataTool.getInt("mobTime", life, 0); - int team = MapleDataTool.getInt("team", life, -1); loadLifeRaw(map, Integer.parseInt(id), type, cy, f, fh, rx0, rx1, x, y, hide, mobTime, team); } } - + private void loadLifeFromDb(MapleMap map) { try { Connection con = DatabaseConnection.getConnection(); @@ -113,7 +123,7 @@ public class MapleMapFactory { ps.setInt(2, map.getWorld()); ResultSet rs = ps.executeQuery(); - while(rs.next()) { + while (rs.next()) { int id = rs.getInt("life"); String type = rs.getString("type"); int cy = rs.getInt("cy"); @@ -137,12 +147,12 @@ public class MapleMapFactory { sqle.printStackTrace(); } } - + private void loadLifeRaw(MapleMap map, int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide, int mobTime, int team) { AbstractLoadedMapleLife myLife = loadLife(id, type, cy, f, fh, rx0, rx1, x, y, hide); if (myLife instanceof MapleMonster) { MapleMonster monster = (MapleMonster) myLife; - + if (mobTime == -1) { //does not respawn, force spawn once map.spawnMonster(monster); } else { @@ -155,10 +165,10 @@ public class MapleMapFactory { map.addMapObject(myLife); } } - + private synchronized MapleMap loadMapFromWz(int mapid, Integer omapid) { MapleMap map; - + mapsRLock.lock(); try { map = maps.get(omapid); @@ -169,7 +179,7 @@ public class MapleMapFactory { if (map != null) { return map; } - + String mapName = getMapName(mapid); MapleData mapData = source.getData(mapName); // source.getData issue with giving nulls in rare ocasions found thanks to MedicOP MapleData infoData = mapData.getChildByPath("info"); @@ -209,9 +219,9 @@ public class MapleMapFactory { bounds[0] = MapleDataTool.getInt(infoData.getChildByPath("VRTop")); bounds[1] = MapleDataTool.getInt(infoData.getChildByPath("VRBottom")); - if(bounds[0] == bounds[1]) { // old-style baked map + if (bounds[0] == bounds[1]) { // old-style baked map MapleData minimapData = mapData.getChildByPath("miniMap"); - if(minimapData != null) { + if (minimapData != null) { bounds[0] = MapleDataTool.getInt(minimapData.getChildByPath("centerX")) * -1; bounds[1] = MapleDataTool.getInt(minimapData.getChildByPath("centerY")) * -1; bounds[2] = MapleDataTool.getInt(minimapData.getChildByPath("height")); @@ -272,7 +282,7 @@ public class MapleMapFactory { map.addMapleArea(new Rectangle(x1, y1, (x2 - x1), (y2 - y1))); } } - if(event == null) { + if (event == null) { try { Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("SELECT * FROM playernpcs WHERE map = ? AND world = ?")) { @@ -288,23 +298,47 @@ public class MapleMapFactory { } catch (SQLException e) { e.printStackTrace(); } - + List dnpcs = MaplePlayerNPCFactory.getDeveloperNpcsFromMapid(mapid); - if(dnpcs != null) { - for(MaplePlayerNPC dnpc : dnpcs) { + if (dnpcs != null) { + for (MaplePlayerNPC dnpc : dnpcs) { map.addPlayerNPCMapObject(dnpc); } } } - + loadLifeFromWz(map, mapData); loadLifeFromDb(map); - + + if (map.isCPQMap()) { + MapleData mcData = mapData.getChildByPath("monsterCarnival"); + if (mcData != null) { + MapleData guardianGenData = mcData.getChildByPath("guardianGenPos"); + for (MapleData node : guardianGenData.getChildren()) { + GuardianSpawnPoint pt = new GuardianSpawnPoint(new Point(MapleDataTool.getIntConvert("x", node), MapleDataTool.getIntConvert("y", node))); + pt.setTeam(MapleDataTool.getIntConvert("team", node, -1)); + pt.setTaken(false); + map.addGuardianSpawnPoint(pt); + } + } + if (mcData.getChildByPath("skill") != null) { + for (MapleData area : mcData.getChildByPath("skill")) { + map.addSkillId(MapleDataTool.getInt(area)); + } + } + + if (mcData.getChildByPath("mob") != null) { + for (MapleData area : mcData.getChildByPath("mob")) { + map.addMobSpawn(MapleDataTool.getInt(area.getChildByPath("id")), MapleDataTool.getInt(area.getChildByPath("spendCP"))); + } + } + } + if (mapData.getChildByPath("reactor") != null) { for (MapleData reactor : mapData.getChildByPath("reactor")) { String id = MapleDataTool.getString(reactor.getChildByPath("id")); if (id != null) { - MapleReactor newReactor = loadReactor(reactor, id); + MapleReactor newReactor = loadReactor(reactor, id, (byte) MapleDataTool.getInt(reactor.getChildByPath("f"), 0)); map.spawnReactor(newReactor); } } @@ -313,7 +347,7 @@ public class MapleMapFactory { map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(omapid)), "")); map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(omapid)), "")); } catch (Exception e) { - if(omapid / 1000 != 1020) { // explorer job introducion scenes + if (omapid / 1000 != 1020) { // explorer job introducion scenes e.printStackTrace(); System.err.println("Not found mapid " + omapid); } @@ -332,13 +366,13 @@ public class MapleMapFactory { map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", infoData, -1)); map.setFieldType(MapleDataTool.getIntConvert("fieldType", infoData, 0)); map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", infoData, 500));//Is there a map that contains more than 500 mobs? - + MapleData recData = infoData.getChildByPath("recovery"); - if(recData != null) { + if (recData != null) { float recoveryRate = MapleDataTool.getFloat(recData); mapRecoveryRate.put(mapid, recoveryRate); } - + HashMap backTypes = new HashMap<>(); try { for (MapleData layer : mapData.getChildByPath("back")) { // yolo @@ -351,7 +385,7 @@ public class MapleMapFactory { e.printStackTrace(); // swallow cause I'm cool } - + map.setBackgroundTypes(backTypes); map.generateMapDropRangeCache(); @@ -361,21 +395,21 @@ public class MapleMapFactory { } finally { mapsWLock.unlock(); } - + return map; } - + public MapleMap getMap(int mapid) { Integer omapid = Integer.valueOf(mapid); MapleMap map; - + mapsRLock.lock(); try { map = maps.get(omapid); } finally { mapsRLock.unlock(); } - + return (map != null) ? map : loadMapFromWz(mapid, omapid); } @@ -387,7 +421,7 @@ public class MapleMapFactory { mapsRLock.unlock(); } } - + private AbstractLoadedMapleLife loadLife(int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide) { AbstractLoadedMapleLife myLife = MapleLifeFactory.getLife(id, type); myLife.setCy(cy); @@ -402,10 +436,11 @@ public class MapleMapFactory { return myLife; } - private MapleReactor loadReactor(MapleData reactor, String id) { + private MapleReactor loadReactor(MapleData reactor, String id, final byte FacingDirection) { MapleReactor myReactor = new MapleReactor(MapleReactorFactory.getReactor(Integer.parseInt(id)), Integer.parseInt(id)); int x = MapleDataTool.getInt(reactor.getChildByPath("x")); int y = MapleDataTool.getInt(reactor.getChildByPath("y")); + myReactor.setFacingDirection(FacingDirection); myReactor.setPosition(new Point(x, y)); myReactor.setDelay(MapleDataTool.getInt(reactor.getChildByPath("reactorTime")) * 1000); myReactor.setName(MapleDataTool.getString(reactor.getChildByPath("name"), "")); @@ -442,7 +477,7 @@ public class MapleMapFactory { } else if (mapid >= 677000000 && mapid < 677100000) { builder.append("Episode1GL"); } else if (mapid >= 670000000 && mapid < 682000000) { - if((mapid >= 674030000 && mapid < 674040000) || (mapid >= 680100000 && mapid < 680200000)) { + if ((mapid >= 674030000 && mapid < 674040000) || (mapid >= 680100000 && mapid < 680200000)) { builder.append("etc"); } else { builder.append("weddingGL"); @@ -452,7 +487,7 @@ public class MapleMapFactory { } else if (mapid >= 683000000 && mapid < 684000000) { builder.append("event"); } else if (mapid >= 800000000 && mapid < 900000000) { - if((mapid >= 889100000 && mapid < 889200000)) { + if ((mapid >= 889100000 && mapid < 889200000)) { builder.append("etc"); } else { builder.append("jp"); @@ -480,17 +515,17 @@ public class MapleMapFactory { mapsRLock.unlock(); } } - + public void dispose() { Collection mapValues = getMaps().values(); - - for(MapleMap map: mapValues) { + + for (MapleMap map : mapValues) { map.dispose(); } - + this.event = null; } - + public static float getMapRecoveryRate(int mapid) { Float recRate = mapRecoveryRate.get(mapid); return recRate != null ? recRate : 1.0f; diff --git a/src/server/maps/MapleReactor.java b/src/server/maps/MapleReactor.java index 72df5fcfbc..42179421d5 100644 --- a/src/server/maps/MapleReactor.java +++ b/src/server/maps/MapleReactor.java @@ -1,27 +1,28 @@ /* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + 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 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. + 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 . -*/ + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ package server.maps; import client.MapleClient; +import client.status.MonsterStatus; import constants.ServerConstants; import java.awt.Rectangle; @@ -36,6 +37,7 @@ import server.TimerManager; import tools.MaplePacketCreator; import tools.Pair; import net.server.audit.locks.MonitoredLockType; +import server.partyquest.GuardianSpawnPoint; /** * @@ -43,6 +45,7 @@ import net.server.audit.locks.MonitoredLockType; * @author Ronan */ public class MapleReactor extends AbstractMapleMapObject { + private int rid; private MapleReactorStats stats; private byte state; @@ -54,28 +57,30 @@ public class MapleReactor extends AbstractMapleMapObject { private boolean shouldCollect; private boolean attackHit; private ScheduledFuture timeoutTask = null; + private GuardianSpawnPoint guardian = null; + private byte facingDirection = 0; private Lock reactorLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.REACTOR, true); private Lock hitLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.REACTOR_HIT, true); public MapleReactor(MapleReactorStats stats, int rid) { - this.evstate = (byte)0; + this.evstate = (byte) 0; this.stats = stats; this.rid = rid; this.alive = true; } - + public void setShouldCollect(boolean collect) { this.shouldCollect = collect; } - + public boolean getShouldCollect() { return shouldCollect; } - + public void lockReactor() { reactorLock.lock(); } - + public void unlockReactor() { reactorLock.unlock(); } @@ -83,19 +88,19 @@ public class MapleReactor extends AbstractMapleMapObject { public void setState(byte state) { this.state = state; } - + public byte getState() { return state; } - + public void setEventState(byte substate) { this.evstate = substate; } - + public byte getEventState() { return evstate; } - + public MapleReactorStats getStats() { return stats; } @@ -120,7 +125,7 @@ public class MapleReactor extends AbstractMapleMapObject { public int getReactorType() { return stats.getType(state); } - + public boolean isRecentHitFromAttack() { return attackHit; } @@ -140,7 +145,7 @@ public class MapleReactor extends AbstractMapleMapObject { public boolean isAlive() { return alive; } - + public boolean isActive() { return alive && stats.getType(state) != -1; } @@ -172,10 +177,12 @@ public class MapleReactor extends AbstractMapleMapObject { cancelReactorTimeout(); setShouldCollect(true); refreshReactorTimeout(); - - if(map != null) map.searchItemReactors(this); + + if (map != null) { + map.searchItemReactors(this); + } } - + public void forceHitReactor(final byte newState) { this.lockReactor(); try { @@ -185,10 +192,12 @@ public class MapleReactor extends AbstractMapleMapObject { this.unlockReactor(); } } - + private void tryForceHitReactor(final byte newState) { // weak hit state signal, if already changed reactor state before timeout then drop this - if(!this.reactorLock.tryLock()) return; - + if (!this.reactorLock.tryLock()) { + return; + } + try { this.resetReactorActions(newState); map.broadcastMessage(MaplePacketCreator.triggerReactor(this, (short) 0)); @@ -196,19 +205,19 @@ public class MapleReactor extends AbstractMapleMapObject { this.reactorLock.unlock(); } } - + public void cancelReactorTimeout() { if (timeoutTask != null) { timeoutTask.cancel(false); timeoutTask = null; } } - + private void refreshReactorTimeout() { int timeOut = stats.getTimeout(state); - if(timeOut > -1) { + if (timeOut > -1) { final byte nextState = stats.getTimeoutState(state); - + timeoutTask = TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { @@ -218,7 +227,7 @@ public class MapleReactor extends AbstractMapleMapObject { }, timeOut); } } - + public void delayedHitReactor(final MapleClient c, long delay) { TimerManager.getInstance().schedule(new Runnable() { @Override @@ -231,20 +240,22 @@ public class MapleReactor extends AbstractMapleMapObject { public void hitReactor(MapleClient c) { hitReactor(false, 0, (short) 0, 0, c); } - + public void hitReactor(boolean wHit, int charPos, short stance, int skillid, MapleClient c) { try { - if(!this.isActive()) { + if (!this.isActive()) { return; } - - if(hitLock.tryLock()) { + + if (hitLock.tryLock()) { this.lockReactor(); try { cancelReactorTimeout(); attackHit = wHit; - if(ServerConstants.USE_DEBUG == true) c.getPlayer().dropMessage(5, "Hitted REACTOR " + this.getId() + " with POS " + charPos + " , STANCE " + stance + " , SkillID " + skillid + " , STATE " + stats.getType(state) + " STATESIZE " + stats.getStateSize(state)); + if (ServerConstants.USE_DEBUG == true) { + c.getPlayer().dropMessage(5, "Hitted REACTOR " + this.getId() + " with POS " + charPos + " , STANCE " + stance + " , SkillID " + skillid + " , STATE " + stats.getType(state) + " STATESIZE " + stats.getStateSize(state)); + } ReactorScriptManager.getInstance().onHit(c, this); int reactorType = stats.getType(state); @@ -253,7 +264,9 @@ public class MapleReactor extends AbstractMapleMapObject { for (byte b = 0; b < stats.getStateSize(state); b++) {//YAY? List activeSkills = stats.getActiveSkills(state, b); if (activeSkills != null) { - if (!activeSkills.contains(skillid)) continue; + if (!activeSkills.contains(skillid)) { + continue; + } } state = stats.getNextState(state, b); if (stats.getNextState(state, b) == -1) {//end of reactor @@ -276,7 +289,7 @@ public class MapleReactor extends AbstractMapleMapObject { setShouldCollect(true); // refresh collectability on item drop-based reactors refreshReactorTimeout(); - if(stats.getType(state) == 100) { + if (stats.getType(state) == 100) { map.searchItemReactors(this); } } @@ -286,21 +299,23 @@ public class MapleReactor extends AbstractMapleMapObject { } else { state++; map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance)); - ReactorScriptManager.getInstance().act(c, this); + if (this.getId() != 9980000 && this.getId() != 9980001) { + ReactorScriptManager.getInstance().act(c, this); + } setShouldCollect(true); refreshReactorTimeout(); - if(stats.getType(state) == 100) { + if (stats.getType(state) == 100) { map.searchItemReactors(this); } } } finally { this.unlockReactor(); } - + hitLock.unlock(); } - } catch(Exception e) { + } catch (Exception e) { e.printStackTrace(); } } @@ -316,4 +331,20 @@ public class MapleReactor extends AbstractMapleMapObject { public void setName(String name) { this.name = name; } + + public GuardianSpawnPoint getGuardian() { + return guardian; + } + + public void setGuardian(GuardianSpawnPoint guardian) { + this.guardian = guardian; + } + + public final void setFacingDirection(final byte facingDirection) { + this.facingDirection = facingDirection; + } + + public final byte getFacingDirection() { + return facingDirection; + } } diff --git a/src/server/maps/MapleReactorFactory.java b/src/server/maps/MapleReactorFactory.java index 55e72fd305..f5a68fe7e9 100644 --- a/src/server/maps/MapleReactorFactory.java +++ b/src/server/maps/MapleReactorFactory.java @@ -38,6 +38,61 @@ public class MapleReactorFactory { private static MapleDataProvider data = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Reactor.wz")); private static Map reactorStats = new HashMap(); + + public static final MapleReactorStats getReactorS(int rid) { + MapleReactorStats stats = reactorStats.get(Integer.valueOf(rid)); + if (stats == null) { + int infoId = rid; + MapleData reactorData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(infoId) + ".img", '0', 11)); + MapleData link = reactorData.getChildByPath("info/link"); + if (link != null) { + infoId = MapleDataTool.getIntConvert("info/link", reactorData); + stats = reactorStats.get(Integer.valueOf(infoId)); + } + if (stats == null) { + stats = new MapleReactorStats(); + reactorData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(infoId) + ".img", '0', 11)); + if (reactorData == null) { + return stats; + } + boolean canTouch = MapleDataTool.getInt("info/activateByTouch", reactorData, 0) > 0; + boolean areaSet = false; + boolean foundState = false; + for (byte i = 0; true; i++) { + MapleData reactorD = reactorData.getChildByPath(String.valueOf(i)); + if (reactorD == null) { + break; + } + MapleData reactorInfoData_ = reactorD.getChildByPath("event"); + if (reactorInfoData_ != null && reactorInfoData_.getChildByPath("0") != null) { + MapleData reactorInfoData = reactorInfoData_.getChildByPath("0"); + Pair reactItem = null; + int type = MapleDataTool.getIntConvert("type", reactorInfoData); + if (type == 100) { //reactor waits for item + reactItem = new Pair(MapleDataTool.getIntConvert("0", reactorInfoData), MapleDataTool.getIntConvert("1", reactorInfoData, 1)); + if (!areaSet) { //only set area of effect for item-triggered reactors once + stats.setTL(MapleDataTool.getPoint("lt", reactorInfoData)); + stats.setBR(MapleDataTool.getPoint("rb", reactorInfoData)); + areaSet = true; + } + } + foundState = true; + stats.addState(i, type, reactItem, (byte) MapleDataTool.getIntConvert("state", reactorInfoData), MapleDataTool.getIntConvert("timeOut", reactorInfoData_, -1), (byte) (canTouch ? 2 : (MapleDataTool.getIntConvert("2", reactorInfoData, 0) > 0 || reactorInfoData.getChildByPath("clickArea") != null || type == 9 ? 1 : 0))); + } else { + stats.addState(i, 999, null, (byte) (foundState ? -1 : (i + 1)), 0, (byte) 0); + } + } + reactorStats.put(Integer.valueOf(infoId), stats); + if (rid != infoId) { + reactorStats.put(Integer.valueOf(rid), stats); + } + } else { // stats exist at infoId but not rid; add to map + reactorStats.put(Integer.valueOf(rid), stats); + } + } + return stats; + } + public static MapleReactorStats getReactor(int rid) { MapleReactorStats stats = reactorStats.get(Integer.valueOf(rid)); if (stats == null) { diff --git a/src/server/maps/MapleReactorStats.java b/src/server/maps/MapleReactorStats.java index 88507a4277..21f9d5f4c2 100644 --- a/src/server/maps/MapleReactorStats.java +++ b/src/server/maps/MapleReactorStats.java @@ -22,6 +22,7 @@ package server.maps; import java.awt.Point; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,6 +59,12 @@ public class MapleReactorStats { if(timeOut > -1) timeoutInfo.put(state, timeOut); } + public void addState(byte state, int type, Pair reactItem, byte nextState, int timeOut, byte canTouch) { + List data = new ArrayList<>(); + data.add(new StateData(type, reactItem, null, nextState)); + stateInfo.put(state, data); + } + public int getTimeout(byte state) { Integer i = timeoutInfo.get(state); return (i == null) ? -1 : i; diff --git a/src/server/maps/SavedLocationType.java b/src/server/maps/SavedLocationType.java index 238e135873..b0e8cd8893 100644 --- a/src/server/maps/SavedLocationType.java +++ b/src/server/maps/SavedLocationType.java @@ -31,6 +31,7 @@ public enum SavedLocationType { EVENT, BOSSPQ, HAPPYVILLE, + MONSTER_CARNIVAL, DEVELOPER; public static SavedLocationType fromString(String Str) { diff --git a/src/server/partyquest/GuardianSpawnPoint.java b/src/server/partyquest/GuardianSpawnPoint.java new file mode 100644 index 0000000000..9f918f22d4 --- /dev/null +++ b/src/server/partyquest/GuardianSpawnPoint.java @@ -0,0 +1,43 @@ +package server.partyquest; + +import java.awt.Point; + +/** + * + * @author David + */ +public class GuardianSpawnPoint { + + private Point position; + private boolean taken; + private int team = -1; + + public GuardianSpawnPoint(Point a) { + this.position = a; + this.taken = true; + } + + public Point getPosition() { + return position; + } + + public void setPosition(Point position) { + this.position = position; + } + + public boolean isTaken() { + return taken; + } + + public void setTaken(boolean taken) { + this.taken = taken; + } + + public int getTeam() { + return team; + } + + public void setTeam(int team) { + this.team = team; + } +} diff --git a/src/server/partyquest/MapleCarnivalFactory.java b/src/server/partyquest/MapleCarnivalFactory.java new file mode 100644 index 0000000000..a38d2e6680 --- /dev/null +++ b/src/server/partyquest/MapleCarnivalFactory.java @@ -0,0 +1,76 @@ +package server.partyquest; + +import client.MapleDisease; +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import server.life.MobSkillFactory; +import provider.MapleDataProvider; +import provider.MapleDataProviderFactory; +import provider.MapleData; +import provider.MapleDataTool; +import server.life.MobSkill; + +/** + *@author Drago/Dragohe4rt +*/ +public class MapleCarnivalFactory { + + private final static MapleCarnivalFactory instance = new MapleCarnivalFactory(); + private final Map skills = new HashMap(); + private final Map guardians = new HashMap(); + private final MapleDataProvider dataRoot = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz")); + + public MapleCarnivalFactory() { + //whoosh + initialize(); + } + + public static final MapleCarnivalFactory getInstance() { + return instance; + } + + private void initialize() { + if (skills.size() != 0) { + return; + } + for (MapleData z : dataRoot.getData("MCSkill.img")) { + skills.put(Integer.parseInt(z.getName()), new MCSkill(MapleDataTool.getInt("spendCP", z, 0), MapleDataTool.getInt("mobSkillID", z, 0), MapleDataTool.getInt("level", z, 0), MapleDataTool.getInt("target", z, 1) > 1)); + } + for (MapleData z : dataRoot.getData("MCGuardian.img")) { + guardians.put(Integer.parseInt(z.getName()), new MCSkill(MapleDataTool.getInt("spendCP", z, 0), MapleDataTool.getInt("mobSkillID", z, 0), MapleDataTool.getInt("level", z, 0), true)); + } + } + + public MCSkill getSkill(final int id) { + return skills.get(id); + } + + public MCSkill getGuardian(final int id) { + return guardians.get(id); + } + + public static class MCSkill { + + public int cpLoss, skillid, level; + public boolean targetsAll; + + public MCSkill(int _cpLoss, int _skillid, int _level, boolean _targetsAll) { + cpLoss = _cpLoss; + skillid = _skillid; + level = _level; + targetsAll = _targetsAll; + } + + public MobSkill getSkill() { + return MobSkillFactory.getMobSkill(skillid, 1); //level? + } + + public MapleDisease getDisease() { + if (skillid <= 0) { + return MapleDisease.getRandom(); + } + return MapleDisease.getBySkill(skillid); + } + } +} diff --git a/src/server/partyquest/MonsterCarnival.java b/src/server/partyquest/MonsterCarnival.java index 89945d7e82..490322a237 100644 --- a/src/server/partyquest/MonsterCarnival.java +++ b/src/server/partyquest/MonsterCarnival.java @@ -1,174 +1,489 @@ -/* - 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 server.partyquest; -import client.MapleCharacter; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; import java.util.concurrent.ScheduledFuture; +import client.MapleCharacter; +import constants.LinguaConstants; +import net.server.Server; +import net.server.channel.Channel; +import net.server.world.MapleParty; +import net.server.world.MaplePartyCharacter; import server.TimerManager; import server.maps.MapleMap; -import tools.DatabaseConnection; import tools.MaplePacketCreator; /** - * - * @author kevintjuh93 - LOST MOTIVATION >=( + * @author Drago/Dragohe4rt */ + public class MonsterCarnival { - private MonsterCarnivalParty red, blue; + + public static int D = 3; + public static int C = 2; + public static int B = 1; + public static int A = 0; + + private MapleParty p1, p2; private MapleMap map; - private int room; - private long time = 0; - private long timeStarted = 0; - private ScheduledFuture schedule = null; + private ScheduledFuture timer, effectTimer; + private long startTime = 0; + private int summons = 8, summonss = 8; + private MapleCharacter leader1, leader2, Grupo1, Grupo2; + private int redCP, blueCP, redTotalCP, blueTotalCP; + private boolean cpq1; - public MonsterCarnival(int room, byte channel, MonsterCarnivalParty red1, MonsterCarnivalParty blue1) { - //this.map = Channel.getInstance(channel).getMapFactory().getMap(980000001 + (room * 100)); - this.room = room; - this.red = red1; - this.blue = blue1; - this.timeStarted = System.currentTimeMillis(); - this.time = 600000; - map.broadcastMessage(MaplePacketCreator.getClock((int) (time / 1000))); - - for (MapleCharacter chr : red.getMembers()) - chr.setCarnival(this); - for (MapleCharacter chr : blue.getMembers()) - chr.setCarnival(this); - - this.schedule = TimerManager.getInstance().schedule(new Runnable() { + public MonsterCarnival(MapleParty p1, MapleParty p2, int mapid, boolean cpq1) { + try { + this.cpq1 = cpq1; + this.p1 = p1; + this.p2 = p2; + Channel cs = Server.getInstance().getWorld(p2.getLeader().getWorld()).getChannel(p2.getLeader().getChannel()); + p1.setEnemy(p2); + p2.setEnemy(p1); + map = cs.getMapFactory().resetMap(mapid); + int redPortal = 0; + int bluePortal = 0; + if (map.isPurpleCPQMap()) { + redPortal = 2; + bluePortal = 1; + } + for (MaplePartyCharacter mpc : p1.getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.setMonsterCarnival(this); + mc.setTeam(0); + mc.setFestivalPoints(0); + mc.changeMap(map, map.getPortal(redPortal)); + mc.dropMessage(6, LinguaConstants.Linguas(mc).CPQEntrada); + if (p1.getLeader().getId() == mc.getId()) { + leader1 = mc; + } + Grupo1 = mc; + } + } + for (MaplePartyCharacter mpc : p2.getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.setMonsterCarnival(this); + mc.setTeam(1); + mc.setFestivalPoints(0); + mc.changeMap(map, map.getPortal(bluePortal)); + mc.dropMessage(6, LinguaConstants.Linguas(mc).CPQEntrada); + if (p2.getLeader().getId() == mc.getId()) { + leader2 = mc; + } + Grupo2 = mc; + } + } + if (Grupo1 == null || Grupo2 == null) { + for (MaplePartyCharacter mpc : p2.getMembers()) { + mpc.getPlayer().dropMessage(5, LinguaConstants.Linguas(mpc.getPlayer()).CPQErro); + } + for (MaplePartyCharacter mpc : p2.getMembers()) { + mpc.getPlayer().dropMessage(5, LinguaConstants.Linguas(mpc.getPlayer()).CPQErro); + } + return; + } + Grupo1.getClient().announce(MaplePacketCreator.startMonsterCarnival(Grupo1, 0, 1)); + Grupo2.getClient().announce(MaplePacketCreator.startMonsterCarnival(Grupo2, 1, 0)); + startTime = System.currentTimeMillis() + 60 * 10000; + timer = TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { - if (red.getTotalCP() > blue.getTotalCP()) { - red.setWinner(true); - blue.setWinner(false); - red.displayMatchResult(); - blue.displayMatchResult(); - } else if (blue.getTotalCP() > red.getTotalCP()) { - red.setWinner(false); - blue.setWinner(true); - red.displayMatchResult(); - blue.displayMatchResult(); - } else { - red.setWinner(false); - blue.setWinner(false); - red.displayMatchResult(); - blue.displayMatchResult(); - } - saveResults(); - warpOut(); + timeUp(); } - - }, time); - /* if (room == 0) { - MapleData data = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz")).getData("Map/Map9" + (980000001 + (room * 100)) + ".img").getChildByPath("monsterCarnival"); - if (data != null) { - for (MapleData p : data.getChildByPath("mobGenPos").getChildren()) { - MapleData team = p.getChildByPath("team"); - if (team != null) { - if (team.getData().equals(0)) - redmonsterpoints.add(new Point(MapleDataTool.getInt(p.getChildByPath("x")), MapleDataTool.getInt(p.getChildByPath("y")))); - else - bluemonsterpoints.add(new Point(MapleDataTool.getInt(p.getChildByPath("x")), MapleDataTool.getInt(p.getChildByPath("y")))); - } else - monsterpoints.add(new Point(MapleDataTool.getInt(p.getChildByPath("x")), MapleDataTool.getInt(p.getChildByPath("y")))); - } - for (MapleData p : data.getChildByPath("guardianGenPos").getChildren()) { - MapleData team = p.getChildByPath("team"); - if (team != null) { - if (team.getData().equals(0)) - redreactorpoints.add(new Point(MapleDataTool.getInt(p.getChildByPath("x")), MapleDataTool.getInt(p.getChildByPath("y")))); - else - bluereactorpoints.add(new Point(MapleDataTool.getInt(p.getChildByPath("x")), MapleDataTool.getInt(p.getChildByPath("y")))); - } else - reactorpoints.add(new Point(MapleDataTool.getInt(p.getChildByPath("x")), MapleDataTool.getInt(p.getChildByPath("y")))); - } - } - } */ - } - - public long getTimeLeft() { - return time - (System.currentTimeMillis() - timeStarted); - } - - public MonsterCarnivalParty getPartyRed() { - return red; - } - - public MonsterCarnivalParty getPartyBlue() { - return blue; - } - - public MonsterCarnivalParty oppositeTeam(MonsterCarnivalParty team) { - if (team == red) - return blue; - else - return red; - } - - public void playerLeft(MapleCharacter chr) { - map.broadcastMessage(chr, MaplePacketCreator.leaveCPQ(chr)); - } - - private void warpOut() { - this.schedule = TimerManager.getInstance().schedule(new Runnable() { + }, 10 * 60 * 1000); + effectTimer = TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { - red.warpOut(); - blue.warpOut(); + complete(); } - }, 12000); + }, 10 * 60 * 1000 - 10 * 1000); + TimerManager.getInstance().schedule(new Runnable() { + @Override + public void run() { + map.addClock(60 * 10); + } + }, 2000); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void playerDisconnected(int charid) { + int team = -1; + for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { + if (mpc.getId() == charid) { + team = 0; + } + } + for (MaplePartyCharacter mpc : leader2.getParty().getMembers()) { + if (mpc.getId() == charid) { + team = 1; + } + } + for (MapleCharacter chrMap : map.getAllPlayers()) { + if (team == -1) { + team = 1; + } + String teamS = ""; + switch (team) { + case 0: + teamS = LinguaConstants.Linguas(chrMap).CPQVermelho; + break; + case 1: + teamS = LinguaConstants.Linguas(chrMap).CPQAzul; + break; + } + chrMap.dropMessage(5, teamS + LinguaConstants.Linguas(chrMap).CPQPlayerExit); + } + earlyFinish(); + } + + public void earlyFinish() { + dispose(true); + } + + public void leftParty(int charid) { + playerDisconnected(charid); + } + + protected void dispose() { + dispose(false); + } + + public void summon() { + this.summons--; + } + + public boolean canSummon() { + return this.summons > 0; + } + + public void summons() { + this.summonss--; + } + + public boolean canSummons() { + return this.summonss > 0; + } + + protected void dispose(boolean warpout) { + Channel cs = Server.getInstance().getWorld(p1.getLeader().getWorld()).getChannel(p1.getLeader().getChannel()); + MapleMap out; + if (!cpq1) { // cpq2 + out = cs.getMapFactory().getMap(980030000); + } else { + out = cs.getMapFactory().getMap(980000000); + } + for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.resetCP(); + mc.setTeam(-1); + mc.setMonsterCarnival(null); + if (warpout) { + mc.changeMap(out, out.getPortal(0)); + } + } + } + for (MaplePartyCharacter mpc : leader2.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.resetCP(); + mc.setTeam(-1); + mc.setMonsterCarnival(null); + if (warpout) { + mc.changeMap(out, out.getPortal(0)); + } + } + } + if (this.timer != null) { + this.timer.cancel(true); + this.timer = null; + } + if (this.effectTimer != null) { + this.effectTimer.cancel(true); + this.effectTimer = null; + } + redTotalCP = 0; + blueTotalCP = 0; + leader1.getParty().setEnemy(null); + leader2.getParty().setEnemy(null); + + } + + public void exit() { + dispose(); + } + + public ScheduledFuture getTimer() { + return this.timer; + } + + public void finish(int winningTeam) { + try { + Channel cs = Server.getInstance().getWorld(p1.getLeader().getWorld()).getChannel(p1.getLeader().getChannel()); + if (winningTeam == 0) { + for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.gainFestivalPoints(this.redTotalCP); + mc.setMonsterCarnival(null); + if (cpq1) { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 2), cs.getMapFactory().getMap(map.getId() + 2).getPortal(0)); + } else { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 200), cs.getMapFactory().getMap(map.getId() + 200).getPortal(0)); + } + mc.setTeam(-1); + mc.dispelDebuffs(); + } + } + for (MaplePartyCharacter mpc : leader2.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.gainFestivalPoints(this.blueTotalCP); + mc.setMonsterCarnival(null); + if (cpq1) { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 3), cs.getMapFactory().getMap(map.getId() + 3).getPortal(0)); + } else { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 300), cs.getMapFactory().getMap(map.getId() + 300).getPortal(0)); + } + mc.setTeam(-1); + mc.dispelDebuffs(); + } + } + } else if (winningTeam == 1) { + for (MaplePartyCharacter mpc : leader2.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.gainFestivalPoints(this.blueTotalCP); + mc.setMonsterCarnival(null); + if (cpq1) { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 2), cs.getMapFactory().getMap(map.getId() + 2).getPortal(0)); + } else { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 200), cs.getMapFactory().getMap(map.getId() + 200).getPortal(0)); + } + mc.setTeam(-1); + mc.dispelDebuffs(); + } + } + for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { + MapleCharacter mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + mc.gainFestivalPoints(this.redTotalCP); + mc.setMonsterCarnival(null); + if (cpq1) { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 3), cs.getMapFactory().getMap(map.getId() + 3).getPortal(0)); + } else { + mc.changeMap(cs.getMapFactory().getMap(map.getId() + 300), cs.getMapFactory().getMap(map.getId() + 300).getPortal(0)); + } + mc.setTeam(-1); + mc.dispelDebuffs(); + } + } + } + dispose(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void timeUp() { + int cp1 = this.redTotalCP; + int cp2 = this.blueTotalCP; + if (cp1 == cp2) { + extendTime(); + return; + } + if (cp1 > cp2) { + finish(0); + } else { + finish(1); + } + } + + public long getTimeLeft() { + return (startTime - System.currentTimeMillis()); + } + + public int getTimeLeftSeconds() { + return (int) (getTimeLeft() / 1000); + } + + public void extendTime() { + for (MapleCharacter chrMap : map.getAllPlayers()) { + chrMap.dropMessage(5, LinguaConstants.Linguas(chrMap).CPQTempoExtendido); + } + startTime = System.currentTimeMillis() + 3 * 1000; + map.addClock(3 * 60); + timer = TimerManager.getInstance().schedule(new Runnable() { + @Override + public void run() { + timeUp(); + } + }, 3 * 60 * 1000); + effectTimer = TimerManager.getInstance().schedule(new Runnable() { + @Override + public void run() { + complete(); + } + }, 3 * 60 * 1000 - 10); + } + + public void complete() { + int cp1 = this.redTotalCP; + int cp2 = this.blueTotalCP; + if (cp1 == cp2) { + return; + } + boolean redWin = cp1 > cp2; + int chnl = leader1.getClient().getChannel(); + int chnl1 = leader2.getClient().getChannel(); + if (chnl != chnl1) { + throw new RuntimeException("Os líderes estão em canais diferentes."); } - public int getRoom() { - return room; - } - - public void saveResults() { - Connection con = null; - try { - con = DatabaseConnection.getConnection(); - PreparedStatement ps = con.prepareStatement("INSERT INTO carnivalresults VALUES (?,?,?,?)"); - for (MapleCharacter chr : red.getMembers()) { - ps.setInt(1, chr.getId()); - ps.setInt(2, chr.getCP()); - ps.setInt(3, red.getTotalCP()); - ps.setInt(4, red.isWinner() ? 1 : 0); - ps.execute(); - } - for (MapleCharacter chr : blue.getMembers()) { - ps.setInt(1, chr.getId()); - ps.setInt(2, chr.getCP()); - ps.setInt(3, blue.getTotalCP()); - ps.setInt(4, blue.isWinner() ? 1 : 0); - ps.execute(); - } - ps.close(); - con.close(); - } catch (SQLException ex) { - ex.printStackTrace(); + Channel cs = Server.getInstance().getWorld(p1.getLeader().getWorld()).getChannel(p1.getLeader().getChannel()); + map.killAllMonsters(); + for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { + MapleCharacter mc; + mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + if (redWin) { + mc.getClient().announce(MaplePacketCreator.showEffect("quest/carnival/win")); + mc.getClient().announce(MaplePacketCreator.playSound("MobCarnival/Win")); + mc.dispelDebuffs(); + } else { + mc.getClient().announce(MaplePacketCreator.showEffect("quest/carnival/lose")); + mc.getClient().announce(MaplePacketCreator.playSound("MobCarnival/Lose")); + mc.dispelDebuffs(); } + } } + for (MaplePartyCharacter mpc : leader2.getParty().getMembers()) { + MapleCharacter mc; + mc = cs.getPlayerStorage().getCharacterByName(mpc.getName()); + if (mc != null) { + if (!redWin) { + mc.getClient().announce(MaplePacketCreator.showEffect("quest/carnival/win")); + mc.getClient().announce(MaplePacketCreator.playSound("MobCarnival/Win")); + mc.dispelDebuffs(); + } else { + mc.getClient().announce(MaplePacketCreator.showEffect("quest/carnival/lose")); + mc.getClient().announce(MaplePacketCreator.playSound("MobCarnival/Lose")); + mc.dispelDebuffs(); + } + } + } + } + + public MapleParty getRed() { + return p1; + } + + public void setRed(MapleParty p1) { + this.p1 = p1; + } + + public MapleParty getBlue() { + return p2; + } + + public void setBlue(MapleParty p2) { + this.p2 = p2; + } + + public MapleCharacter getLeader1() { + return leader1; + } + + public void setLeader1(MapleCharacter leader1) { + this.leader1 = leader1; + } + + public MapleCharacter getLeader2() { + return leader2; + } + + public void setLeader2(MapleCharacter leader2) { + this.leader2 = leader2; + } + + public MapleCharacter getEnemyLeader(int team) { + switch (team) { + case 0: + return leader2; + case 1: + return leader1; + } + return null; + } + + public int getBlueCP() { + return blueCP; + } + + public void setBlueCP(int blueCP) { + this.blueCP = blueCP; + } + + public int getBlueTotalCP() { + return blueTotalCP; + } + + public void setBlueTotalCP(int blueTotalCP) { + this.blueTotalCP = blueTotalCP; + } + + public int getRedCP() { + return redCP; + } + + public void setRedCP(int redCP) { + this.redCP = redCP; + } + + public int getRedTotalCP() { + return redTotalCP; + } + + public void setRedTotalCP(int redTotalCP) { + this.redTotalCP = redTotalCP; + } + + public int getTotalCP(int team) { + if (team == 0) { + return redTotalCP; + } else if (team == 1) { + return blueTotalCP; + } else { + throw new RuntimeException("Equipe desconhecida"); + } + } + + public void setTotalCP(int totalCP, int team) { + if (team == 0) { + this.redTotalCP = totalCP; + } else if (team == 1) { + this.blueTotalCP = totalCP; + } + } + + public int getCP(int team) { + if (team == 0) { + return redCP; + } else if (team == 1) { + return blueCP; + } else { + throw new RuntimeException("Equipe desconhecida" + team); + } + } + + public void setCP(int CP, int team) { + if (team == 0) { + this.redCP = CP; + } else if (team == 1) { + this.blueCP = CP; + } + } } diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index e26d6370d6..171ce14f88 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -75,7 +75,6 @@ import server.maps.MapleReactor; import server.maps.MapleSummon; import server.life.MaplePlayerNPC; import server.movement.LifeMovementFragment; -import server.partyquest.MonsterCarnivalParty; import tools.data.output.LittleEndianWriter; import tools.data.output.MaplePacketLittleEndianWriter; import client.BuddylistEntry; @@ -119,7723 +118,7740 @@ import server.maps.AbstractMapleMapObject; */ public class MaplePacketCreator { - public static final List> EMPTY_STATUPDATE = Collections.emptyList(); - private final static long FT_UT_OFFSET = 116444628000000000L; - private final static long DEFAULT_TIME = 150842304000000000L;//00 80 05 BB 46 E6 17 02 - public final static long ZERO_TIME = 94354848000000000L;//00 40 E0 FD 3B 37 4F 01 - private final static long PERMANENT = 150841440000000000L; // 00 C0 9B 90 7D E5 17 02 + public static final List> EMPTY_STATUPDATE = Collections.emptyList(); + private final static long FT_UT_OFFSET = 116444628000000000L; + private final static long DEFAULT_TIME = 150842304000000000L;//00 80 05 BB 46 E6 17 02 + public final static long ZERO_TIME = 94354848000000000L;//00 40 E0 FD 3B 37 4F 01 + private final static long PERMANENT = 150841440000000000L; // 00 C0 9B 90 7D E5 17 02 - private static long getTime(long realTimestamp) { - if (realTimestamp == -1) { - return DEFAULT_TIME;//high number ll - } else if (realTimestamp == -2) { - return ZERO_TIME; - } else if (realTimestamp == -3) { - return PERMANENT; - } - return realTimestamp * 10000 + FT_UT_OFFSET; + private static long getTime(long realTimestamp) { + if (realTimestamp == -1) { + return DEFAULT_TIME;//high number ll + } else if (realTimestamp == -2) { + return ZERO_TIME; + } else if (realTimestamp == -3) { + return PERMANENT; + } + return realTimestamp * 10000 + FT_UT_OFFSET; + } + + public static byte[] showHpHealed(int cid, int amount) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(0x0A); //Type + mplew.write(amount); + return mplew.getPacket(); + } + + private static void addRemainingSkillInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + int remainingSp[] = chr.getRemainingSps(); + int effectiveLength = 0; + for (int i = 0; i < remainingSp.length; i++) { + if (remainingSp[i] > 0) { + effectiveLength++; + } } - public static byte[] showHpHealed(int cid, int amount) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(0x0A); //Type - mplew.write(amount); - return mplew.getPacket(); - } - - private static void addRemainingSkillInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - int remainingSp[] = chr.getRemainingSps(); - int effectiveLength = 0; - for (int i = 0; i < remainingSp.length; i++) { - if (remainingSp[i] > 0) { - effectiveLength++; - } - } - - mplew.write(effectiveLength); - for (int i = 0; i < remainingSp.length; i++) { - if (remainingSp[i] > 0) { - mplew.write(i + 1); - mplew.write(remainingSp[i]); - } - } + mplew.write(effectiveLength); + for (int i = 0; i < remainingSp.length; i++) { + if (remainingSp[i] > 0) { + mplew.write(i + 1); + mplew.write(remainingSp[i]); + } } - - private static void addCharStats(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.writeInt(chr.getId()); // character id - mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getName(), '\0', 13)); - mplew.write(chr.getGender()); // gender (0 = male, 1 = female) - mplew.write(chr.getSkinColor().getId()); // skin color - mplew.writeInt(chr.getFace()); // face - mplew.writeInt(chr.getHair()); // hair + } - for (int i = 0; i < 3; i++) { - MaplePet pet = chr.getPet(i); - if (pet != null) //Checked GMS.. and your pets stay when going into the cash shop. - { - mplew.writeLong(pet.getUniqueId()); - } else { - mplew.writeLong(0); - } - } + private static void addCharStats(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.writeInt(chr.getId()); // character id + mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getName(), '\0', 13)); + mplew.write(chr.getGender()); // gender (0 = male, 1 = female) + mplew.write(chr.getSkinColor().getId()); // skin color + mplew.writeInt(chr.getFace()); // face + mplew.writeInt(chr.getHair()); // hair - mplew.write(chr.getLevel()); // level - mplew.writeShort(chr.getJob().getId()); // job - mplew.writeShort(chr.getStr()); // str - mplew.writeShort(chr.getDex()); // dex - mplew.writeShort(chr.getInt()); // int - mplew.writeShort(chr.getLuk()); // luk - mplew.writeShort(chr.getHp()); // hp (?) - mplew.writeShort(chr.getClientMaxHp()); // maxhp - mplew.writeShort(chr.getMp()); // mp (?) - mplew.writeShort(chr.getClientMaxMp()); // maxmp - mplew.writeShort(chr.getRemainingAp()); // remaining ap - if (GameConstants.hasSPTable(chr.getJob())) { - addRemainingSkillInfo(mplew, chr); - } else { - mplew.writeShort(chr.getRemainingSp()); // remaining sp - } - mplew.writeInt(chr.getExp()); // current exp - mplew.writeShort(chr.getFame()); // fame - mplew.writeInt(chr.getGachaExp()); //Gacha Exp - mplew.writeInt(chr.getMapId()); // current map id - mplew.write(chr.getInitialSpawnpoint()); // spawnpoint - mplew.writeInt(0); - } - - protected static void addCharLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean mega) { - mplew.write(chr.getGender()); - mplew.write(chr.getSkinColor().getId()); // skin color - mplew.writeInt(chr.getFace()); // face - mplew.write(mega ? 0 : 1); - mplew.writeInt(chr.getHair()); // hair - addCharEquips(mplew, chr); - } - - private static void addCharacterInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.writeLong(-1); - mplew.write(0); - addCharStats(mplew, chr); - mplew.write(chr.getBuddylist().getCapacity()); - - if (chr.getLinkedName() == null) { - mplew.write(0); - } else { - mplew.write(1); - mplew.writeMapleAsciiString(chr.getLinkedName()); - } - - mplew.writeInt(chr.getMeso()); - addInventoryInfo(mplew, chr); - addSkillInfo(mplew, chr); - addQuestInfo(mplew, chr); - addMiniGameInfo(mplew, chr); - addRingInfo(mplew, chr); - addTeleportInfo(mplew, chr); - addMonsterBookInfo(mplew, chr); - addNewYearInfo(mplew, chr); - addAreaInfo(mplew, chr);//assuming it stayed here xd - mplew.writeShort(0); - } - - private static void addNewYearInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - Set received = chr.getReceivedNewYearRecords(); - - mplew.writeShort(received.size()); - for(NewYearCardRecord nyc : received) { - encodeNewYearCard(nyc, mplew); - } - } - - private static void addTeleportInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - final List tele = chr.getTrockMaps(); - final List viptele = chr.getVipTrockMaps(); - for (int i = 0; i < 5; i++) { - mplew.writeInt(tele.get(i)); - } - for (int i = 0; i < 10; i++) { - mplew.writeInt(viptele.get(i)); - } - } - - private static void addMiniGameInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.writeShort(0); - /*for (int m = size; m > 0; m--) {//nexon does this :P - mplew.writeInt(0); - mplew.writeInt(0); - mplew.writeInt(0); - mplew.writeInt(0); - mplew.writeInt(0); - }*/ - } - - private static void addAreaInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - Map areaInfos = chr.getAreaInfos(); - mplew.writeShort(areaInfos.size()); - for (Short area : areaInfos.keySet()) { - mplew.writeShort(area); - mplew.writeMapleAsciiString(areaInfos.get(area)); - } - } - - private static void addCharEquips(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - MapleInventory equip = chr.getInventory(MapleInventoryType.EQUIPPED); - Collection ii = MapleItemInformationProvider.getInstance().canWearEquipment(chr, equip.list()); - Map myEquip = new LinkedHashMap<>(); - Map maskedEquip = new LinkedHashMap<>(); - for (Item item : ii) { - short pos = (byte) (item.getPosition() * -1); - if (pos < 100 && myEquip.get(pos) == null) { - myEquip.put(pos, item.getItemId()); - } else if (pos > 100 && pos != 111) { // don't ask. o.o - pos -= 100; - if (myEquip.get(pos) != null) { - maskedEquip.put(pos, myEquip.get(pos)); - } - myEquip.put(pos, item.getItemId()); - } else if (myEquip.get(pos) != null) { - maskedEquip.put(pos, item.getItemId()); - } - } - for (Entry entry : myEquip.entrySet()) { - mplew.write(entry.getKey()); - mplew.writeInt(entry.getValue()); - } - mplew.write(0xFF); - for (Entry entry : maskedEquip.entrySet()) { - mplew.write(entry.getKey()); - mplew.writeInt(entry.getValue()); - } - mplew.write(0xFF); - Item cWeapon = equip.getItem((short) -111); - mplew.writeInt(cWeapon != null ? cWeapon.getItemId() : 0); - for (int i = 0; i < 3; i++) { - if (chr.getPet(i) != null) { - mplew.writeInt(chr.getPet(i).getItemId()); - } else { - mplew.writeInt(0); - } - } - } - - public static byte[] setExtraPendantSlot(boolean toggleExtraSlot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_EXTRA_PENDANT_SLOT.getValue()); - mplew.writeBool(toggleExtraSlot); - return mplew.getPacket(); - } - - private static void addCharEntry(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean viewall) { - addCharStats(mplew, chr); - addCharLook(mplew, chr, false); - if (!viewall) { - mplew.write(0); - } - if (chr.isGM()) { - mplew.write(0); - return; - } - mplew.write(1); // world rank enabled (next 4 ints are not sent if disabled) Short?? - mplew.writeInt(chr.getRank()); // world rank - mplew.writeInt(chr.getRankMove()); // move (negative is downwards) - mplew.writeInt(chr.getJobRank()); // job rank - mplew.writeInt(chr.getJobRankMove()); // move (negative is downwards) - } - - private static void addQuestInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.writeShort(chr.getStartedQuestsSize()); - for (MapleQuestStatus q : chr.getStartedQuests()) { - mplew.writeShort(q.getQuest().getId()); - mplew.writeMapleAsciiString(q.getQuestData()); - if (q.getQuest().getInfoNumber() > 0) { - mplew.writeShort(q.getQuest().getInfoNumber()); - mplew.writeMapleAsciiString(q.getQuestData()); - } - } - List completed = chr.getCompletedQuests(); - mplew.writeShort(completed.size()); - for (MapleQuestStatus q : completed) { - mplew.writeShort(q.getQuest().getId()); - mplew.writeLong(getTime(q.getCompletionTime())); - } - } - - private static void addExpirationTime(final MaplePacketLittleEndianWriter mplew, long time) { - mplew.writeLong(getTime(time)); // offset expiration time issue found thanks to Thora - } - - private static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item) { - addItemInfo(mplew, item, false); - } - - protected static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item, boolean zeroPosition) { - MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - boolean isCash = ii.isCash(item.getItemId()); - boolean isPet = item.getPetId() > -1; - boolean isRing = false; - Equip equip = null; - short pos = item.getPosition(); - byte itemType = item.getItemType(); - if (itemType == 1) { - equip = (Equip) item; - isRing = equip.getRingId() > -1; - } - if (!zeroPosition) { - if (equip != null) { - if (pos < 0) { - pos *= -1; - } - mplew.writeShort(pos > 100 ? pos - 100 : pos); - } else { - mplew.write(pos); - } - } - mplew.write(itemType); - mplew.writeInt(item.getItemId()); - mplew.writeBool(isCash); - if (isCash) { - mplew.writeLong(isPet ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId()); - } - addExpirationTime(mplew, item.getExpiration()); - if (isPet) { - MaplePet pet = item.getPet(); - mplew.writeAsciiString(StringUtil.getRightPaddedStr(pet.getName(), '\0', 13)); - mplew.write(pet.getLevel()); - mplew.writeShort(pet.getCloseness()); - mplew.write(pet.getFullness()); - addExpirationTime(mplew, item.getExpiration()); - mplew.writeInt(pet.getPetFlag()); /* pet flags found by -- Irenex & Spoon */ - mplew.write(new byte[]{(byte) 0x50, (byte) 0x46}); //wonder what this is - mplew.writeInt(0); - return; - } - if (equip == null) { - mplew.writeShort(item.getQuantity()); - mplew.writeMapleAsciiString(item.getOwner()); - mplew.writeShort(item.getFlag()); // flag - - if (ItemConstants.isRechargeable(item.getItemId())) { - mplew.writeInt(2); - mplew.write(new byte[]{(byte) 0x54, 0, 0, (byte) 0x34}); - } - return; - } - mplew.write(equip.getUpgradeSlots()); // upgrade slots - mplew.write(equip.getLevel()); // level - mplew.writeShort(equip.getStr()); // str - mplew.writeShort(equip.getDex()); // dex - mplew.writeShort(equip.getInt()); // int - mplew.writeShort(equip.getLuk()); // luk - mplew.writeShort(equip.getHp()); // hp - mplew.writeShort(equip.getMp()); // mp - mplew.writeShort(equip.getWatk()); // watk - mplew.writeShort(equip.getMatk()); // matk - mplew.writeShort(equip.getWdef()); // wdef - mplew.writeShort(equip.getMdef()); // mdef - mplew.writeShort(equip.getAcc()); // accuracy - mplew.writeShort(equip.getAvoid()); // avoid - mplew.writeShort(equip.getHands()); // hands - mplew.writeShort(equip.getSpeed()); // speed - mplew.writeShort(equip.getJump()); // jump - mplew.writeMapleAsciiString(equip.getOwner()); // owner name - mplew.writeShort(equip.getFlag()); //Item Flags - - if (isCash) { - for (int i = 0; i < 10; i++) { - mplew.write(0x40); - } - } else { - int itemLevel = equip.getItemLevel(); - - long expNibble = (ExpTable.getExpNeededForLevel(ii.getEquipLevelReq(item.getItemId())) * equip.getItemExp()); - expNibble /= ExpTable.getEquipExpNeededForLevel(itemLevel); - - mplew.write(0); - mplew.write(itemLevel); //Item Level - mplew.writeInt((int) expNibble); - mplew.writeInt(equip.getVicious()); //WTF NEXON ARE YOU SERIOUS? - mplew.writeLong(0); - } - mplew.writeLong(getTime(-2)); - mplew.writeInt(-1); - - } - - private static void addInventoryInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - for (byte i = 1; i <= 5; i++) { - mplew.write(chr.getInventory(MapleInventoryType.getByType(i)).getSlotLimit()); - } - mplew.writeLong(getTime(-2)); - MapleInventory iv = chr.getInventory(MapleInventoryType.EQUIPPED); - Collection equippedC = iv.list(); - List equipped = new ArrayList<>(equippedC.size()); - List equippedCash = new ArrayList<>(equippedC.size()); - for (Item item : equippedC) { - if (item.getPosition() <= -100) { - equippedCash.add((Item) item); - } else { - equipped.add((Item) item); - } - } - Collections.sort(equipped); - for (Item item : equipped) { - addItemInfo(mplew, item); - } - mplew.writeShort(0); // start of equip cash - for (Item item : equippedCash) { - addItemInfo(mplew, item); - } - mplew.writeShort(0); // start of equip inventory - for (Item item : chr.getInventory(MapleInventoryType.EQUIP).list()) { - addItemInfo(mplew, item); - } - mplew.writeInt(0); - for (Item item : chr.getInventory(MapleInventoryType.USE).list()) { - addItemInfo(mplew, item); - } - mplew.write(0); - for (Item item : chr.getInventory(MapleInventoryType.SETUP).list()) { - addItemInfo(mplew, item); - } - mplew.write(0); - for (Item item : chr.getInventory(MapleInventoryType.ETC).list()) { - addItemInfo(mplew, item); - } - mplew.write(0); - for (Item item : chr.getInventory(MapleInventoryType.CASH).list()) { - addItemInfo(mplew, item); - } - } - - private static void addSkillInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.write(0); // start of skills - Map skills = chr.getSkills(); - int skillsSize = skills.size(); - // We don't want to include any hidden skill in this, so subtract them from the size list and ignore them. - for (Iterator> it = skills.entrySet().iterator(); it.hasNext();) { - Entry skill = it.next(); - if (GameConstants.isHiddenSkills(skill.getKey().getId())) { - skillsSize--; - } - } - mplew.writeShort(skillsSize); - for (Iterator> it = skills.entrySet().iterator(); it.hasNext();) { - Entry skill = it.next(); - if (GameConstants.isHiddenSkills(skill.getKey().getId())) { - continue; - } - mplew.writeInt(skill.getKey().getId()); - mplew.writeInt(skill.getValue().skillevel); - addExpirationTime(mplew, skill.getValue().expiration); - if (skill.getKey().isFourthJob()) { - mplew.writeInt(skill.getValue().masterlevel); - } - } - mplew.writeShort(chr.getAllCooldowns().size()); - for (PlayerCoolDownValueHolder cooling : chr.getAllCooldowns()) { - mplew.writeInt(cooling.skillId); - int timeLeft = (int) (cooling.length + cooling.startTime - System.currentTimeMillis()); - mplew.writeShort(timeLeft / 1000); - } - } - - private static void addMonsterBookInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.writeInt(chr.getMonsterBookCover()); // cover - mplew.write(0); - Map cards = chr.getMonsterBook().getCards(); - mplew.writeShort(cards.size()); - for (Entry all : cards.entrySet()) { - mplew.writeShort(all.getKey() % 10000); // Id - mplew.write(all.getValue()); // Level - } - } - - public static byte[] sendGuestTOS() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUEST_ID_LOGIN.getValue()); - mplew.writeShort(0x100); - mplew.writeInt(Randomizer.nextInt(999999)); + for (int i = 0; i < 3; i++) { + MaplePet pet = chr.getPet(i); + if (pet != null) //Checked GMS.. and your pets stay when going into the cash shop. + { + mplew.writeLong(pet.getUniqueId()); + } else { mplew.writeLong(0); - mplew.writeLong(getTime(-2)); - mplew.writeLong(getTime(System.currentTimeMillis())); + } + } + + mplew.write(chr.getLevel()); // level + mplew.writeShort(chr.getJob().getId()); // job + mplew.writeShort(chr.getStr()); // str + mplew.writeShort(chr.getDex()); // dex + mplew.writeShort(chr.getInt()); // int + mplew.writeShort(chr.getLuk()); // luk + mplew.writeShort(chr.getHp()); // hp (?) + mplew.writeShort(chr.getClientMaxHp()); // maxhp + mplew.writeShort(chr.getMp()); // mp (?) + mplew.writeShort(chr.getClientMaxMp()); // maxmp + mplew.writeShort(chr.getRemainingAp()); // remaining ap + if (GameConstants.hasSPTable(chr.getJob())) { + addRemainingSkillInfo(mplew, chr); + } else { + mplew.writeShort(chr.getRemainingSp()); // remaining sp + } + mplew.writeInt(chr.getExp()); // current exp + mplew.writeShort(chr.getFame()); // fame + mplew.writeInt(chr.getGachaExp()); //Gacha Exp + mplew.writeInt(chr.getMapId()); // current map id + mplew.write(chr.getInitialSpawnpoint()); // spawnpoint + mplew.writeInt(0); + } + + protected static void addCharLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean mega) { + mplew.write(chr.getGender()); + mplew.write(chr.getSkinColor().getId()); // skin color + mplew.writeInt(chr.getFace()); // face + mplew.write(mega ? 0 : 1); + mplew.writeInt(chr.getHair()); // hair + addCharEquips(mplew, chr); + } + + private static void addCharacterInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.writeLong(-1); + mplew.write(0); + addCharStats(mplew, chr); + mplew.write(chr.getBuddylist().getCapacity()); + + if (chr.getLinkedName() == null) { + mplew.write(0); + } else { + mplew.write(1); + mplew.writeMapleAsciiString(chr.getLinkedName()); + } + + mplew.writeInt(chr.getMeso()); + addInventoryInfo(mplew, chr); + addSkillInfo(mplew, chr); + addQuestInfo(mplew, chr); + addMiniGameInfo(mplew, chr); + addRingInfo(mplew, chr); + addTeleportInfo(mplew, chr); + addMonsterBookInfo(mplew, chr); + addNewYearInfo(mplew, chr); + addAreaInfo(mplew, chr);//assuming it stayed here xd + mplew.writeShort(0); + } + + private static void addNewYearInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + Set received = chr.getReceivedNewYearRecords(); + + mplew.writeShort(received.size()); + for (NewYearCardRecord nyc : received) { + encodeNewYearCard(nyc, mplew); + } + } + + private static void addTeleportInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + final List tele = chr.getTrockMaps(); + final List viptele = chr.getVipTrockMaps(); + for (int i = 0; i < 5; i++) { + mplew.writeInt(tele.get(i)); + } + for (int i = 0; i < 10; i++) { + mplew.writeInt(viptele.get(i)); + } + } + + private static void addMiniGameInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.writeShort(0); + /*for (int m = size; m > 0; m--) {//nexon does this :P + mplew.writeInt(0); + mplew.writeInt(0); + mplew.writeInt(0); + mplew.writeInt(0); + mplew.writeInt(0); + }*/ + } + + private static void addAreaInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + Map areaInfos = chr.getAreaInfos(); + mplew.writeShort(areaInfos.size()); + for (Short area : areaInfos.keySet()) { + mplew.writeShort(area); + mplew.writeMapleAsciiString(areaInfos.get(area)); + } + } + + private static void addCharEquips(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + MapleInventory equip = chr.getInventory(MapleInventoryType.EQUIPPED); + Collection ii = MapleItemInformationProvider.getInstance().canWearEquipment(chr, equip.list()); + Map myEquip = new LinkedHashMap<>(); + Map maskedEquip = new LinkedHashMap<>(); + for (Item item : ii) { + short pos = (byte) (item.getPosition() * -1); + if (pos < 100 && myEquip.get(pos) == null) { + myEquip.put(pos, item.getItemId()); + } else if (pos > 100 && pos != 111) { // don't ask. o.o + pos -= 100; + if (myEquip.get(pos) != null) { + maskedEquip.put(pos, myEquip.get(pos)); + } + myEquip.put(pos, item.getItemId()); + } else if (myEquip.get(pos) != null) { + maskedEquip.put(pos, item.getItemId()); + } + } + for (Entry entry : myEquip.entrySet()) { + mplew.write(entry.getKey()); + mplew.writeInt(entry.getValue()); + } + mplew.write(0xFF); + for (Entry entry : maskedEquip.entrySet()) { + mplew.write(entry.getKey()); + mplew.writeInt(entry.getValue()); + } + mplew.write(0xFF); + Item cWeapon = equip.getItem((short) -111); + mplew.writeInt(cWeapon != null ? cWeapon.getItemId() : 0); + for (int i = 0; i < 3; i++) { + if (chr.getPet(i) != null) { + mplew.writeInt(chr.getPet(i).getItemId()); + } else { mplew.writeInt(0); - mplew.writeMapleAsciiString("http://maplesolaxia.com"); - return mplew.getPacket(); - } - - /** - * Sends a hello packet. - * - * @param mapleVersion The maple client version. - * @param sendIv the IV used by the server for sending - * @param recvIv the IV used by the server for receiving - * @return - */ - public static byte[] getHello(short mapleVersion, byte[] sendIv, byte[] recvIv) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); - mplew.writeShort(0x0E); - mplew.writeShort(mapleVersion); - mplew.writeShort(1); - mplew.write(49); - mplew.write(recvIv); - mplew.write(sendIv); - mplew.write(8); - return mplew.getPacket(); - } - - /** - * Sends a ping packet. - * - * @return The packet. - */ - public static byte[] getPing() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); - mplew.writeShort(SendOpcode.PING.getValue()); - return mplew.getPacket(); - } - - /** - * Gets a login failed packet. - * - * Possible values for reason:
3: ID deleted or blocked
- * 4: Incorrect password
5: Not a registered id
6: System error
- * 7: Already logged in
8: System error
9: System error
10: - * Cannot process so many connections
11: Only users older than 20 can - * use this channel
13: Unable to log on as master at this ip
14: - * Wrong gateway or personal info and weird korean button
15: Processing - * request with that korean button!
16: Please verify your account - * through email...
17: Wrong gateway or personal info
21: Please - * verify your account through email...
23: License agreement
25: - * Maple Europe notice =[ FUCK YOU NEXON
27: Some weird full client - * notice, probably for trial versions
- * - * @param reason The reason logging in failed. - * @return The login failed packet. - */ - public static byte[] getLoginFailed(int reason) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); - mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); - mplew.write(reason); - mplew.write(0); - mplew.writeInt(0); - return mplew.getPacket(); - } - - /** - * Gets a login failed packet. - * - * Possible values for reason:
2: ID deleted or blocked
- * 3: ID deleted or blocked
4: Incorrect password
5: Not a - * registered id
6: Trouble logging into the game?
7: Already logged - * in
8: Trouble logging into the game?
9: Trouble logging into the - * game?
10: Cannot process so many connections
11: Only users older - * than 20 can use this channel
12: Trouble logging into the game?
- * 13: Unable to log on as master at this ip
14: Wrong gateway or - * personal info and weird korean button
15: Processing request with - * that korean button!
16: Please verify your account through - * email...
17: Wrong gateway or personal info
21: Please verify - * your account through email...
23: Crashes
25: Maple Europe notice - * =[ FUCK YOU NEXON
27: Some weird full client notice, probably for - * trial versions
- * - * @param reason The reason logging in failed. - * @return The login failed packet. - */ - public static byte[] getAfterLoginError(int reason) {//same as above o.o - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); - mplew.writeShort(SendOpcode.SELECT_CHARACTER_BY_VAC.getValue()); - mplew.writeShort(reason);//using other types than stated above = CRASH - return mplew.getPacket(); - } - - public static byte[] sendPolice() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAKE_GM_NOTICE.getValue()); - mplew.write(0);//doesn't even matter what value - return mplew.getPacket(); - } - - public static byte[] sendPolice(String text) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DATA_CRC_CHECK_FAILED.getValue()); - mplew.writeMapleAsciiString(text); - return mplew.getPacket(); - } - - public static byte[] getPermBan(byte reason) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); - mplew.write(2); // Account is banned - mplew.write(0); - mplew.writeInt(0); - mplew.write(0); - mplew.writeLong(getTime(-1)); - - return mplew.getPacket(); - } - - public static byte[] getTempBan(long timestampTill, byte reason) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(17); - mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); - mplew.write(2); - mplew.write(0); - mplew.writeInt(0); - mplew.write(reason); - mplew.writeLong(getTime(timestampTill)); // Tempban date is handled as a 64-bit long, number of 100NS intervals since 1/1/1601. Lulz. - - return mplew.getPacket(); - } - - /** - * Gets a successful authentication packet. - * - * @param c - * @return the successful authentication packet - */ - public static byte[] getAuthSuccess(MapleClient c) { - Server.getInstance().loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB. - - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); - mplew.writeInt(0); - mplew.writeShort(0); - mplew.writeInt(c.getAccID()); - mplew.write(c.getGender()); - - boolean canFly = Server.getInstance().canFly(c.getAccID()); - mplew.writeBool((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) ? c.getGMLevel() > 1 : false); // thanks Steve(kaito1410) for pointing the GM account boolean here - mplew.write(((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) && c.getGMLevel() > 1) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish. - mplew.write(0); // Country Code. - - mplew.writeMapleAsciiString(c.getAccountName()); - mplew.write(0); - - mplew.write(0); // IsQuietBan - mplew.writeLong(0);//IsQuietBanTimeStamp - mplew.writeLong(0); //CreationTimeStamp - - mplew.writeInt(1); // 1: Remove the "Select the world you want to play in" - - mplew.write(ServerConstants.ENABLE_PIN && !c.canBypassPin() ? 0 : 1); // 0 = Pin-System Enabled, 1 = Disabled - mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null ? 0 : 1) : 2); // 0 = Register PIC, 1 = Ask for PIC, 2 = Disabled - - return mplew.getPacket(); - } - - /** - * Gets a packet detailing a PIN operation. - * - * Possible values for mode:
0 - PIN was accepted
1 - - * Register a new PIN
2 - Invalid pin / Reenter
3 - Connection - * failed due to system error
4 - Enter the pin - * - * @param mode The mode. - * @return - */ - private static byte[] pinOperation(byte mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.CHECK_PINCODE.getValue()); - mplew.write(mode); - return mplew.getPacket(); - } - - public static byte[] pinRegistered() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.UPDATE_PINCODE.getValue()); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] requestPin() { - return pinOperation((byte) 4); - } - - public static byte[] requestPinAfterFailure() { - return pinOperation((byte) 2); - } - - public static byte[] registerPin() { - return pinOperation((byte) 1); - } - - public static byte[] pinAccepted() { - return pinOperation((byte) 0); - } - - public static byte[] wrongPic() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.CHECK_SPW_RESULT.getValue()); - mplew.write(0); - return mplew.getPacket(); - } - - /** - * Gets a packet detailing a server and its channels. - * - * @param serverId - * @param serverName The name of the server. - * @param flag - * @param eventmsg - * @param channelLoad Load of the channel - 1200 seems to be max. - * @return The server info packet. - */ - public static byte[] getServerList(int serverId, String serverName, int flag, String eventmsg, List channelLoad) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SERVERLIST.getValue()); - mplew.write(serverId); - mplew.writeMapleAsciiString(serverName); - mplew.write(flag); - mplew.writeMapleAsciiString(eventmsg); - mplew.write(100); // rate modifier, don't ask O.O! - mplew.write(0); // event xp * 2.6 O.O! - mplew.write(100); // rate modifier, don't ask O.O! - mplew.write(0); // drop rate * 2.6 - mplew.write(0); - mplew.write(channelLoad.size()); - for (Channel ch : channelLoad) { - mplew.writeMapleAsciiString(serverName + "-" + ch.getId()); - mplew.writeInt(ch.getChannelCapacity()); - - // thanks GabrielSin for this channel packet structure part - mplew.write(1);// nWorldID - mplew.write(ch.getId() - 1);// nChannelID - mplew.writeBool(false);// bAdultChannel - } - mplew.writeShort(0); - return mplew.getPacket(); - } - - /** - * Gets a packet saying that the server list is over. - * - * @return The end of server list packet. - */ - public static byte[] getEndOfServerList() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.SERVERLIST.getValue()); - mplew.write(0xFF); - return mplew.getPacket(); - } - - /** - * Gets a packet detailing a server status message. - * - * Possible values for status:
0 - Normal
1 - Highly - * populated
2 - Full - * - * @param status The server status. - * @return The server status packet. - */ - public static byte[] getServerStatus(int status) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.SERVERSTATUS.getValue()); - mplew.writeShort(status); - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client the IP of the channel server. - * - * @param inetAddr The InetAddress of the requested channel server. - * @param port The port the channel is on. - * @param clientId The ID of the client. - * @return The server IP packet. - */ - public static byte[] getServerIP(InetAddress inetAddr, int port, int clientId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SERVER_IP.getValue()); - mplew.writeShort(0); - byte[] addr = inetAddr.getAddress(); - mplew.write(addr); - mplew.writeShort(port); - mplew.writeInt(clientId); - mplew.write(new byte[]{0, 0, 0, 0, 0}); - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client the IP of the new channel. - * - * @param inetAddr The InetAddress of the requested channel server. - * @param port The port the channel is on. - * @return The server IP packet. - */ - public static byte[] getChannelChange(InetAddress inetAddr, int port) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CHANGE_CHANNEL.getValue()); - mplew.write(1); - byte[] addr = inetAddr.getAddress(); - mplew.write(addr); - mplew.writeShort(port); - return mplew.getPacket(); - } - - /** - * Gets a packet with a list of characters. - * - * @param c The MapleClient to load characters of. - * @param serverId The ID of the server requested. - * @param status The charlist request result. - * @return The character list packet. - * - * Possible values for status: - *
2: ID deleted or blocked
- *
3: ID deleted or blocked
- *
4: Incorrect password
- *
5: Not an registered ID
- *
6: Trouble logging in?
- *
10: Server handling too many connections
- *
11: Only 20 years or older
- *
13: Unable to log as master at IP
- *
14: Wrong gateway or personal info
- *
15: Still processing request
- *
16: Verify account via email
- *
17: Wrong gateway or personal info
- *
21: Verify account via email
- */ - public static byte[] getCharList(MapleClient c, int serverId, int status) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CHARLIST.getValue()); - mplew.write(status); - List chars = c.loadCharacters(serverId); - mplew.write((byte) chars.size()); - for (MapleCharacter chr : chars) { - addCharEntry(mplew, chr, false); - } - - mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null ? 0 : 1) : 2); - mplew.writeInt(ServerConstants.COLLECTIVE_CHARSLOT ? chars.size() + c.getAvailableCharacterSlots() : c.getCharacterSlots()); - return mplew.getPacket(); - } - - public static byte[] enableTV() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.ENABLE_TV.getValue()); - mplew.writeInt(0); - mplew.write(0); - return mplew.getPacket(); - } - - /** - * Removes TV - * - * @return The Remove TV Packet - */ - public static byte[] removeTV() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); - mplew.writeShort(SendOpcode.REMOVE_TV.getValue()); - return mplew.getPacket(); - } - - /** - * Sends MapleTV - * - * @param chr The character shown in TV - * @param messages The message sent with the TV - * @param type The type of TV - * @param partner The partner shown with chr - * @return the SEND_TV packet - */ - public static byte[] sendTV(MapleCharacter chr, List messages, int type, MapleCharacter partner) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SEND_TV.getValue()); - mplew.write(partner != null ? 3 : 1); - mplew.write(type); //Heart = 2 Star = 1 Normal = 0 - addCharLook(mplew, chr, false); - mplew.writeMapleAsciiString(chr.getName()); - if (partner != null) { - mplew.writeMapleAsciiString(partner.getName()); - } else { - mplew.writeShort(0); - } - for (int i = 0; i < messages.size(); i++) { - if (i == 4 && messages.get(4).length() > 15) { - mplew.writeMapleAsciiString(messages.get(4).substring(0, 15)); - } else { - mplew.writeMapleAsciiString(messages.get(i)); - } - } - mplew.writeInt(1337); // time limit shit lol 'Your thing still start in blah blah seconds' - if (partner != null) { - addCharLook(mplew, partner, false); - } - return mplew.getPacket(); - } - - /** - * Gets character info for a character. - * - * @param chr The character to get info about. - * @return The character info packet. - */ - public static byte[] getCharInfo(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_FIELD.getValue()); - mplew.writeInt(chr.getClient().getChannel() - 1); - mplew.write(1); - mplew.write(1); - mplew.writeShort(0); - for (int i = 0; i < 3; i++) { - mplew.writeInt(Randomizer.nextInt()); - } - addCharacterInfo(mplew, chr); - mplew.writeLong(getTime(System.currentTimeMillis())); - return mplew.getPacket(); - } - - /** - * Gets an empty stat update. - * - * @return The empty stat update packet. - */ - public static byte[] enableActions() { - return updatePlayerStats(EMPTY_STATUPDATE, true, null); - } - - /** - * Gets an update for specified stats. - * - * @param stats The list of stats to update. - * @param enableActions Allows actions after the update. - * @param chr The update target. - * @return The stat update packet. - */ - public static byte[] updatePlayerStats(List> stats, boolean enableActions, MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STAT_CHANGED.getValue()); - mplew.write(enableActions ? 1 : 0); - int updateMask = 0; - for (Pair statupdate : stats) { - updateMask |= statupdate.getLeft().getValue(); - } - List> mystats = stats; - if (mystats.size() > 1) { - Collections.sort(mystats, new Comparator>() { - @Override - public int compare(Pair o1, Pair o2) { - int val1 = o1.getLeft().getValue(); - int val2 = o2.getLeft().getValue(); - return (val1 < val2 ? -1 : (val1 == val2 ? 0 : 1)); - } - }); - } - mplew.writeInt(updateMask); - for (Pair statupdate : mystats) { - if (statupdate.getLeft().getValue() >= 1) { - if (statupdate.getLeft().getValue() == 0x1) { - mplew.writeShort(statupdate.getRight().shortValue()); - } else if (statupdate.getLeft().getValue() <= 0x4) { - mplew.writeInt(statupdate.getRight()); - } else if (statupdate.getLeft().getValue() < 0x20) { - mplew.write(statupdate.getRight().shortValue()); - } else if (statupdate.getLeft().getValue() == 0x8000) { - if (GameConstants.hasSPTable(chr.getJob())) { - addRemainingSkillInfo(mplew, chr); - } else { - mplew.writeShort(statupdate.getRight().shortValue()); - } - } else if (statupdate.getLeft().getValue() < 0xFFFF) { - mplew.writeShort(statupdate.getRight().shortValue()); - } else { - mplew.writeInt(statupdate.getRight().intValue()); - } - } - } - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client to change maps. - * - * @param to The MapleMap to warp to. - * @param spawnPoint The spawn portal number to spawn at. - * @param chr The character warping to to - * @return The map change packet. - */ - public static byte[] getWarpToMap(MapleMap to, int spawnPoint, MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_FIELD.getValue()); - mplew.writeInt(chr.getClient().getChannel() - 1); - mplew.writeInt(0);//updated - mplew.write(0);//updated - mplew.writeInt(to.getId()); - mplew.write(spawnPoint); - mplew.writeShort(chr.getHp()); - mplew.writeBool(false); - mplew.writeLong(getTime(Server.getInstance().getCurrentTime())); - mplew.skip(14); - return mplew.getPacket(); - } - - public static byte[] getWarpToMap(MapleMap to, int spawnPoint, Point spawnPosition, MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_FIELD.getValue()); - mplew.writeInt(chr.getClient().getChannel() - 1); - mplew.writeInt(0);//updated - mplew.write(0);//updated - mplew.writeInt(to.getId()); - mplew.write(spawnPoint); - mplew.writeShort(chr.getHp()); - mplew.writeBool(true); - mplew.writeInt(spawnPosition.x); // spawn position placement thanks to Arnah (Vertisy) - mplew.writeInt(spawnPosition.y); - mplew.writeLong(getTime(Server.getInstance().getCurrentTime())); - mplew.skip(14); - return mplew.getPacket(); - } - - /** - * Gets a packet to spawn a portal. - * - * @param townId The ID of the town the portal goes to. - * @param targetId The ID of the target. - * @param pos Where to put the portal. - * @return The portal spawn packet. - */ - public static byte[] spawnPortal(int townId, int targetId, Point pos) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(14); - mplew.writeShort(SendOpcode.SPAWN_PORTAL.getValue()); - mplew.writeInt(townId); - mplew.writeInt(targetId); - mplew.writePos(pos); - return mplew.getPacket(); - } - - /** - * Gets a packet to spawn a door. - * - * @param ownerid The door's owner ID. - * @param pos The position of the door. - * @param launched Already deployed the door. - * @return The remove door packet. - */ - public static byte[] spawnDoor(int ownerid, Point pos, boolean launched) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); - mplew.writeShort(SendOpcode.SPAWN_DOOR.getValue()); - mplew.writeBool(launched); - mplew.writeInt(ownerid); - mplew.writePos(pos); - return mplew.getPacket(); - } - - /** - * Gets a packet to remove a door. - * - * @param ownerid The door's owner ID. - * @param town - * @return The remove door packet. - */ - public static byte[] removeDoor(int ownerid, boolean town) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(10); - if (town) { - mplew.writeShort(SendOpcode.SPAWN_PORTAL.getValue()); - mplew.writeInt(999999999); - mplew.writeInt(999999999); - } else { - mplew.writeShort(SendOpcode.REMOVE_DOOR.getValue()); - mplew.write(0); - mplew.writeInt(ownerid); - } - return mplew.getPacket(); - } - - /** - * Gets a packet to spawn a special map object. - * - * @param summon - * @param skillLevel The level of the skill used. - * @param animated Animated spawn? - * @return The spawn packet for the map object. - */ - public static byte[] spawnSummon(MapleSummon summon, boolean animated) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(25); - mplew.writeShort(SendOpcode.SPAWN_SPECIAL_MAPOBJECT.getValue()); - mplew.writeInt(summon.getOwner().getId()); - mplew.writeInt(summon.getObjectId()); - mplew.writeInt(summon.getSkill()); - mplew.write(0x0A); //v83 - mplew.write(summon.getSkillLevel()); - mplew.writePos(summon.getPosition()); - mplew.write(summon.getStance()); //bMoveAction & foothold, found thanks to Rien dev team - mplew.writeShort(0); - mplew.write(summon.getMovementType().getValue()); // 0 = don't move, 1 = follow (4th mage summons?), 2/4 = only tele follow, 3 = bird follow - mplew.write(summon.isPuppet() ? 0 : 1); // 0 and the summon can't attack - but puppets don't attack with 1 either ^.- - mplew.write(animated ? 0 : 1); - return mplew.getPacket(); - } - - /** - * Gets a packet to remove a special map object. - * - * @param summon - * @param animated Animated removal? - * @return The packet removing the object. - */ - public static byte[] removeSummon(MapleSummon summon, boolean animated) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); - mplew.writeShort(SendOpcode.REMOVE_SPECIAL_MAPOBJECT.getValue()); - mplew.writeInt(summon.getOwner().getId()); - mplew.writeInt(summon.getObjectId()); - mplew.write(animated ? 4 : 1); // ? - return mplew.getPacket(); - } - - public static byte[] spawnKite(int oid, int itemid, String name, String msg, Point pos, int ft) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_KITE.getValue()); - mplew.writeInt(oid); - mplew.writeInt(itemid); - mplew.writeMapleAsciiString(msg); - mplew.writeMapleAsciiString(name); - mplew.writeShort(pos.x); - mplew.writeShort(ft); - return mplew.getPacket(); - } - - public static byte[] removeKite(int objectid, int animationType) { // thanks to Arnah - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.REMOVE_KITE.getValue()); - mplew.write(animationType); // 0 is 10/10, 1 just vanishes - mplew.writeInt(objectid); - return mplew.getPacket(); - } - - public static byte[] sendCannotSpawnKite() { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANNOT_SPAWN_KITE.getValue()); - return mplew.getPacket(); - } - - /** - * Gets the response to a relog request. - * - * @return The relog response packet. - */ - public static byte[] getRelogResponse() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.RELOG_RESPONSE.getValue()); - mplew.write(1);//1 O.O Must be more types ): - return mplew.getPacket(); - } - - /** - * Gets a server message packet. - * - * @param message The message to convey. - * @return The server message packet. - */ - public static byte[] serverMessage(String message) { - return serverMessage(4, (byte) 0, message, true, false, 0); - } - - /** - * Gets a server notice packet. - * - * Possible values for type:
0: [Notice]
1: Popup
- * 2: Megaphone
3: Super Megaphone
4: Scrolling message at top
- * 5: Pink Text
6: Lightblue Text - * - * @param type The type of the notice. - * @param message The message to convey. - * @return The server notice packet. - */ - public static byte[] serverNotice(int type, String message) { - return serverMessage(type, (byte) 0, message, false, false, 0); - } - - /** - * Gets a server notice packet. - * - * Possible values for type:
0: [Notice]
1: Popup
- * 2: Megaphone
3: Super Megaphone
4: Scrolling message at top
- * 5: Pink Text
6: Lightblue Text - * - * @param type The type of the notice. - * @param channel The channel this notice was sent on. - * @param message The message to convey. - * @return The server notice packet. - */ - public static byte[] serverNotice(int type, String message, int npc) { - return serverMessage(type, 0, message, false, false, npc); - } - - public static byte[] serverNotice(int type, int channel, String message) { - return serverMessage(type, channel, message, false, false, 0); - } - - public static byte[] serverNotice(int type, int channel, String message, boolean smegaEar) { - return serverMessage(type, channel, message, false, smegaEar, 0); - } - - /** - * Gets a server message packet. - * - * Possible values for type:
0: [Notice]
1: Popup
- * 2: Megaphone
3: Super Megaphone
4: Scrolling message at top
- * 5: Pink Text
6: Lightblue Text
7: BroadCasting NPC - * - * @param type The type of the notice. - * @param channel The channel this notice was sent on. - * @param message The message to convey. - * @param servermessage Is this a scrolling ticker? - * @return The server notice packet. - */ - private static byte[] serverMessage(int type, int channel, String message, boolean servermessage, boolean megaEar, int npc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); - mplew.write(type); - if (servermessage) { - mplew.write(1); - } - mplew.writeMapleAsciiString(message); - if (type == 3) { - mplew.write(channel - 1); // channel - mplew.writeBool(megaEar); - } else if (type == 6) { - mplew.writeInt(0); - } else if (type == 7) { // npc - mplew.writeInt(npc); - } - return mplew.getPacket(); - } - - /** - * Sends a Avatar Super Megaphone packet. - * - * @param chr The character name. - * @param medal The medal text. - * @param channel Which channel. - * @param itemId Which item used. - * @param message The message sent. - * @param ear Whether or not the ear is shown for whisper. - * @return - */ - public static byte[] getAvatarMega(MapleCharacter chr, String medal, int channel, int itemId, List message, boolean ear) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_AVATAR_MEGAPHONE.getValue()); - mplew.writeInt(itemId); - mplew.writeMapleAsciiString(medal + chr.getName()); - for (String s : message) { - mplew.writeMapleAsciiString(s); - } - mplew.writeInt(channel - 1); // channel - mplew.writeBool(ear); - addCharLook(mplew, chr, true); - return mplew.getPacket(); - } - - /* - * Sends a packet to remove the tiger megaphone - * @return - */ - public static byte[] byeAvatarMega() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CLEAR_AVATAR_MEGAPHONE.getValue()); - mplew.write(1); - return mplew.getPacket(); - } - - /** - * Sends the Gachapon green message when a user uses a gachapon ticket. - * - * @param item - * @param town - * @param player - * @return - */ - public static byte[] gachaponMessage(Item item, String town, MapleCharacter player) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); - mplew.write(0x0B); - mplew.writeMapleAsciiString(player.getName() + " : got a(n)"); - mplew.writeInt(0); //random? - mplew.writeMapleAsciiString(town); - addItemInfo(mplew, item, true); - return mplew.getPacket(); - } - - public static byte[] spawnNPC(MapleNPC life) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(24); - mplew.writeShort(SendOpcode.SPAWN_NPC.getValue()); - mplew.writeInt(life.getObjectId()); - mplew.writeInt(life.getId()); - mplew.writeShort(life.getPosition().x); - mplew.writeShort(life.getCy()); - if (life.getF() == 1) { - mplew.write(0); - } else { - mplew.write(1); - } - mplew.writeShort(life.getFh()); - mplew.writeShort(life.getRx0()); - mplew.writeShort(life.getRx1()); - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] spawnNPCRequestController(MapleNPC life, boolean MiniMap) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(23); - mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue()); - mplew.write(1); - mplew.writeInt(life.getObjectId()); - mplew.writeInt(life.getId()); - mplew.writeShort(life.getPosition().x); - mplew.writeShort(life.getCy()); - if (life.getF() == 1) { - mplew.write(0); - } else { - mplew.write(1); - } - mplew.writeShort(life.getFh()); - mplew.writeShort(life.getRx0()); - mplew.writeShort(life.getRx1()); - mplew.writeBool(MiniMap); - return mplew.getPacket(); - } - - /** - * Gets a spawn monster packet. - * - * @param life The monster to spawn. - * @param newSpawn Is it a new spawn? - * @return The spawn monster packet. - */ - public static byte[] spawnMonster(MapleMonster life, boolean newSpawn) { - return spawnMonsterInternal(life, false, newSpawn, false, 0, false); - } - - /** - * Gets a spawn monster packet. - * - * @param life The monster to spawn. - * @param newSpawn Is it a new spawn? - * @param effect The spawn effect. - * @return The spawn monster packet. - */ - public static byte[] spawnMonster(MapleMonster life, boolean newSpawn, int effect) { - return spawnMonsterInternal(life, false, newSpawn, false, effect, false); - } - - /** - * Gets a control monster packet. - * - * @param life The monster to give control to. - * @param newSpawn Is it a new spawn? - * @param aggro Aggressive monster? - * @return The monster control packet. - */ - public static byte[] controlMonster(MapleMonster life, boolean newSpawn, boolean aggro) { - return spawnMonsterInternal(life, true, newSpawn, aggro, 0, false); - } - - /** - * Removes a monster invisibility. - * - * @param life - * @return - */ - public static byte[] removeMonsterInvisibility(MapleMonster life) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); - mplew.write(1); - mplew.writeInt(life.getObjectId()); - return mplew.getPacket(); - } - - /** - * Makes a monster invisible for Ariant PQ. - * - * @param life - * @return - */ - public static byte[] makeMonsterInvisible(MapleMonster life) { - return spawnMonsterInternal(life, true, false, false, 0, true); - } - - private static void encodeParentlessMobSpawnEffect(MaplePacketLittleEndianWriter mplew, boolean newSpawn, int effect) { - if (effect > 0) { - mplew.write(effect); - mplew.write(0); - mplew.writeShort(0); - if (effect == 15) { - mplew.write(0); - } - } - mplew.write(newSpawn ? -2 : -1); - } - - /** - * Internal function to handler monster spawning and controlling. - * - * @param life The mob to perform operations with. - * @param requestController Requesting control of mob? - * @param newSpawn New spawn (fade in?) - * @param aggro Aggressive mob? - * @param effect The spawn effect to use. - * @return The spawn/control packet. - */ - private static byte[] spawnMonsterInternal(MapleMonster life, boolean requestController, boolean newSpawn, boolean aggro, int effect, boolean makeInvis) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - if (makeInvis) { - mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); - mplew.write(0); - mplew.writeInt(life.getObjectId()); - return mplew.getPacket(); - } - if (requestController) { - mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); - mplew.write(aggro ? 2 : 1); - } else { - mplew.writeShort(SendOpcode.SPAWN_MONSTER.getValue()); - } - mplew.writeInt(life.getObjectId()); - mplew.write(life.getController() == null ? 5 : 1); - mplew.writeInt(life.getId()); - mplew.skip(15); - mplew.write(0x88); - mplew.skip(6); - mplew.writePos(life.getPosition()); - mplew.write(life.getStance()); - mplew.writeShort(0); //Origin FH //life.getStartFh() - mplew.writeShort(life.getFh()); - - - /** - * -4: Fake - * -3: Appear after linked mob is dead - * -2: Fade in - * 1: Smoke - * 3: King Slime spawn - * 4: Summoning rock thing, used for 3rd job? - * 6: Magical shit - * 7: Smoke shit - * 8: 'The Boss' - * 9/10: Grim phantom shit? - * 11/12: Nothing? - * 13: Frankenstein - * 14: Angry ^ - * 15: Orb animation thing, ?? - * 16: ?? - * 19: Mushroom castle boss thing - */ - - if (life.getParentMobOid() != 0) { - MapleMonster parentMob = life.getMap().getMonsterByOid(life.getParentMobOid()); - if(parentMob != null && parentMob.isAlive()) { - mplew.write(effect != 0 ? effect : -3); - mplew.writeInt(life.getParentMobOid()); - } else { - encodeParentlessMobSpawnEffect(mplew, newSpawn, effect); - } - } else { - encodeParentlessMobSpawnEffect(mplew, newSpawn, effect); - } - - mplew.write(life.getTeam()); - mplew.writeInt(0); // getItemEffect - return mplew.getPacket(); - } - - /** - * Handles monsters not being targettable, such as Zakum's first body. - * - * @param life The mob to spawn as non-targettable. - * @param effect The effect to show when spawning. - * @return The packet to spawn the mob as non-targettable. - */ - public static byte[] spawnFakeMonster(MapleMonster life, int effect) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); - mplew.write(1); - mplew.writeInt(life.getObjectId()); - mplew.write(5); - mplew.writeInt(life.getId()); - mplew.skip(15); - mplew.write(0x88); - mplew.skip(6); - mplew.writePos(life.getPosition()); - mplew.write(life.getStance()); - mplew.writeShort(0);//life.getStartFh() - mplew.writeShort(life.getFh()); - if (effect > 0) { - mplew.write(effect); - mplew.write(0); - mplew.writeShort(0); - } - mplew.writeShort(-2); - mplew.write(life.getTeam()); - mplew.writeInt(0); - return mplew.getPacket(); - } - - /** - * Makes a monster previously spawned as non-targettable, targettable. - * - * @param life The mob to make targettable. - * @return The packet to make the mob targettable. - */ - public static byte[] makeMonsterReal(MapleMonster life) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_MONSTER.getValue()); - mplew.writeInt(life.getObjectId()); - mplew.write(5); - mplew.writeInt(life.getId()); - mplew.skip(15); - mplew.write(0x88); - mplew.skip(6); - mplew.writePos(life.getPosition()); - mplew.write(life.getStance()); - mplew.writeShort(0);//life.getStartFh() - mplew.writeShort(life.getFh()); - mplew.writeShort(-1); - mplew.writeInt(0); - return mplew.getPacket(); - } - - /** - * Gets a stop control monster packet. - * - * @param oid The ObjectID of the monster to stop controlling. - * @return The stop control monster packet. - */ - public static byte[] stopControllingMonster(int oid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); - mplew.write(0); - mplew.writeInt(oid); - return mplew.getPacket(); - } - - /** - * Gets a response to a move monster packet. - * - * @param objectid The ObjectID of the monster being moved. - * @param moveid The movement ID. - * @param currentMp The current MP of the monster. - * @param useSkills Can the monster use skills? - * @return The move response packet. - */ - public static byte[] moveMonsterResponse(int objectid, short moveid, int currentMp, boolean useSkills) { - return moveMonsterResponse(objectid, moveid, currentMp, useSkills, 0, 0); - } - - /** - * Gets a response to a move monster packet. - * - * @param objectid The ObjectID of the monster being moved. - * @param moveid The movement ID. - * @param currentMp The current MP of the monster. - * @param useSkills Can the monster use skills? - * @param skillId The skill ID for the monster to use. - * @param skillLevel The level of the skill to use. - * @return The move response packet. - */ - - public static byte[] moveMonsterResponse(int objectid, short moveid, int currentMp, boolean useSkills, int skillId, int skillLevel) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(13); - mplew.writeShort(SendOpcode.MOVE_MONSTER_RESPONSE.getValue()); - mplew.writeInt(objectid); - mplew.writeShort(moveid); - mplew.writeBool(useSkills); - mplew.writeShort(currentMp); - mplew.write(skillId); - mplew.write(skillLevel); - return mplew.getPacket(); - } - - /** - * Gets a general chat packet. - * - * @param cidfrom The character ID who sent the chat. - * @param text The text of the chat. - * @param whiteBG - * @param show - * @return The general chat packet. - */ - public static byte[] getChatText(int cidfrom, String text, boolean gm, int show) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CHATTEXT.getValue()); - mplew.writeInt(cidfrom); - mplew.writeBool(gm); - mplew.writeMapleAsciiString(text); - mplew.write(show); - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client to show an EXP increase. - * - * @param gain The amount of EXP gained. - * @param inChat In the chat box? - * @param white White text or yellow? - * @return The exp gained packet. - */ - public static byte[] getShowExpGain(int gain, int equip, int party, boolean inChat, boolean white) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(3); // 3 = exp, 4 = fame, 5 = mesos, 6 = guildpoints - mplew.writeBool(white); - mplew.writeInt(gain); - mplew.writeBool(inChat); - mplew.writeInt(0); // monster book bonus (Bonus Event Exp) - mplew.write(0); // third monster kill event - mplew.write(0); // RIP byte, this is always a 0 - mplew.writeInt(0); //wedding bonus - if (inChat) { // quest bonus rate stuff - mplew.write(0); - } - - int mod = ServerConstants.PARTY_EXPERIENCE_MOD != 1 ? ServerConstants.PARTY_EXPERIENCE_MOD * 100 : 0; - - mplew.write(mod); //0 = party bonus, 100 = 1x Bonus EXP, 200 = 2x Bonus EXP - mplew.writeInt(party); // party bonus - mplew.writeInt(equip); //equip bonus - mplew.writeInt(0); //Internet Cafe Bonus - mplew.writeInt(0); //Rainbow Week Bonus - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client to show a fame gain. - * - * @param gain How many fame gained. - * @return The meso gain packet. - */ - public static byte[] getShowFameGain(int gain) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(4); - mplew.writeInt(gain); - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client to show a meso gain. - * - * @param gain How many mesos gained. - * @return The meso gain packet. - */ - public static byte[] getShowMesoGain(int gain) { - return getShowMesoGain(gain, false); - } - - /** - * Gets a packet telling the client to show a meso gain. - * - * @param gain How many mesos gained. - * @param inChat Show in the chat window? - * @return The meso gain packet. - */ - public static byte[] getShowMesoGain(int gain, boolean inChat) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - if (!inChat) { - mplew.write(0); - mplew.writeShort(1); //v83 - } else { - mplew.write(5); - } - mplew.writeInt(gain); - mplew.writeShort(0); - return mplew.getPacket(); - } - - /** - * Gets a packet telling the client to show a item gain. - * - * @param itemId The ID of the item gained. - * @param quantity How many items gained. - * @return The item gain packet. - */ - public static byte[] getShowItemGain(int itemId, short quantity) { - return getShowItemGain(itemId, quantity, false); - } - - /** - * Gets a packet telling the client to show an item gain. - * - * @param itemId The ID of the item gained. - * @param quantity The number of items gained. - * @param inChat Show in the chat window? - * @return The item gain packet. - */ - public static byte[] getShowItemGain(int itemId, short quantity, boolean inChat) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - if (inChat) { - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(3); - mplew.write(1); - mplew.writeInt(itemId); - mplew.writeInt(quantity); - } else { - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.writeShort(0); - mplew.writeInt(itemId); - mplew.writeInt(quantity); - mplew.writeInt(0); - mplew.writeInt(0); - } - return mplew.getPacket(); - } - - public static byte[] killMonster(int oid, boolean animation) { - return killMonster(oid, animation ? 1 : 0); - } - - /** - * Gets a packet telling the client that a monster was killed. - * - * @param oid The objectID of the killed monster. - * @param animation 0 = dissapear, 1 = fade out, 2+ = special - * @return The kill monster packet. - */ - public static byte[] killMonster(int oid, int animation) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.KILL_MONSTER.getValue()); - mplew.writeInt(oid); - mplew.write(animation); - mplew.write(animation); - return mplew.getPacket(); - } - - public static byte[] updateMapItemObject(MapleMapItem drop, boolean giveOwnership) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DROP_ITEM_FROM_MAPOBJECT.getValue()); - mplew.write(2); - mplew.writeInt(drop.getObjectId()); - mplew.writeBool(drop.getMeso() > 0); - mplew.writeInt(drop.getItemId()); - mplew.writeInt(giveOwnership ? 0 : -1); - mplew.write(drop.getDropType()); - mplew.writePos(drop.getPosition()); - mplew.writeInt(giveOwnership ? 0 : -1); - - if (drop.getMeso() == 0) { - addExpirationTime(mplew, drop.getItem().getExpiration()); - } - mplew.write(drop.isPlayerDrop() ? 0 : 1); - return mplew.getPacket(); - } - - public static byte[] dropItemFromMapObject(boolean recvrInParty, MapleMapItem drop, Point dropfrom, Point dropto, byte mod) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DROP_ITEM_FROM_MAPOBJECT.getValue()); - mplew.write(mod); - mplew.writeInt(drop.getObjectId()); - mplew.writeBool(drop.getMeso() > 0); // 1 mesos, 0 item, 2 and above all item meso bag, - mplew.writeInt(drop.getItemId()); // drop object ID - mplew.writeInt(!drop.isFFADrop() ? (recvrInParty ? drop.getPartyOwnerId() : drop.getOwnerId()) : 0); // owner charid/partyid :) - mplew.write(drop.getDropType()); // 0 = timeout for non-owner, 1 = timeout for non-owner's party, 2 = FFA, 3 = explosive/FFA - mplew.writePos(dropto); - mplew.writeInt(drop.getDropper().getObjectId()); // dropper oid, found thanks to Li Jixue - - if (mod != 2) { - mplew.writePos(dropfrom); - mplew.writeShort(0);//Fh? - } - if (drop.getMeso() == 0) { - addExpirationTime(mplew, drop.getItem().getExpiration()); - } - mplew.write(drop.isPlayerDrop() ? 0 : 1); //pet EQP pickup - return mplew.getPacket(); - } - - /** - * Guild Name & Mark update packet, thanks to Arnah (Vertisy) - * - * @param guildName The Guild name, blank for nothing. - */ - public static byte[] guildNameChanged(int chrid, String guildName){ - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_NAME_CHANGED.getValue()); - mplew.writeInt(chrid); - mplew.writeMapleAsciiString(guildName); - return mplew.getPacket(); - } - - public static byte[] guildMarkChanged(int chrid, MapleGuild guild){ - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_MARK_CHANGED.getValue()); - mplew.writeInt(chrid); - mplew.writeShort(guild.getLogoBG()); - mplew.write(guild.getLogoBGColor()); - mplew.writeShort(guild.getLogo()); - mplew.write(guild.getLogoColor()); - return mplew.getPacket(); - } - - /** - * Gets a packet spawning a player as a mapobject to other clients. - * - * @param target The client receiving this packet. - * @param chr The character to spawn to other clients. - * @param enteringField Whether the character to spawn is not yet present in the map or already is. - * @return The spawn player packet. - */ - public static byte[] spawnPlayerMapObject(MapleClient target, MapleCharacter chr, boolean enteringField) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_PLAYER.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(chr.getLevel()); //v83 - mplew.writeMapleAsciiString(chr.getName()); - if (chr.getGuildId() < 1) { - mplew.writeMapleAsciiString(""); - mplew.write(new byte[6]); - } else { - MapleGuildSummary gs = chr.getClient().getWorldServer().getGuildSummary(chr.getGuildId(), chr.getWorld()); - if (gs != null) { - mplew.writeMapleAsciiString(gs.getName()); - mplew.writeShort(gs.getLogoBG()); - mplew.write(gs.getLogoBGColor()); - mplew.writeShort(gs.getLogo()); - mplew.write(gs.getLogoColor()); - } else { - mplew.writeMapleAsciiString(""); - mplew.write(new byte[6]); - } - } - mplew.writeInt(0); - mplew.writeShort(0); //v83 - mplew.write(0xFC); - mplew.write(1); - if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { - mplew.writeInt(2); - } else { - mplew.writeInt(0); - } - long buffmask = 0; - Integer buffvalue = null; - if (chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && !chr.isHidden()) { - buffmask |= MapleBuffStat.DARKSIGHT.getValue(); - } - if (chr.getBuffedValue(MapleBuffStat.COMBO) != null) { - buffmask |= MapleBuffStat.COMBO.getValue(); - buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.COMBO).intValue()); - } - if (chr.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) { - buffmask |= MapleBuffStat.SHADOWPARTNER.getValue(); - } - if (chr.getBuffedValue(MapleBuffStat.SOULARROW) != null) { - buffmask |= MapleBuffStat.SOULARROW.getValue(); - } - if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { - buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.MORPH).intValue()); - } - if (chr.getBuffedValue(MapleBuffStat.ENERGY_CHARGE) != null) { - buffmask |= MapleBuffStat.ENERGY_CHARGE.getValue(); - buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.ENERGY_CHARGE).intValue()); - }//AREN'T THESE - mplew.writeInt((int) ((buffmask >> 32) & 0xffffffffL)); - if (buffvalue != null) { - if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { //TEST - mplew.writeShort(buffvalue); - } else { - mplew.write(buffvalue.byteValue()); - } - } - mplew.writeInt((int) (buffmask & 0xffffffffL)); - int CHAR_MAGIC_SPAWN = Randomizer.nextInt(); - mplew.skip(6); - mplew.writeInt(CHAR_MAGIC_SPAWN); - mplew.skip(11); - mplew.writeInt(CHAR_MAGIC_SPAWN);//v74 - mplew.skip(11); - mplew.writeInt(CHAR_MAGIC_SPAWN); - mplew.writeShort(0); - mplew.write(0); - - Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING); - if (bv != null) { - if(bv.equals(Corsair.BATTLE_SHIP)) { - mplew.writeInt(1932000); - mplew.writeInt(Corsair.BATTLE_SHIP); - } else { - final Item mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18); - if(mount != null) { - mplew.writeInt(mount.getItemId()); - mplew.writeInt(1004); - } else { - mplew.writeLong(0); - } - } - } else { - mplew.writeLong(0); - } - - mplew.writeInt(CHAR_MAGIC_SPAWN); - mplew.skip(9); - mplew.writeInt(CHAR_MAGIC_SPAWN); - mplew.writeShort(0); - mplew.writeInt(0); // actually not 0, why is it 0 then? - mplew.skip(10); - mplew.writeInt(CHAR_MAGIC_SPAWN); - mplew.skip(13); - mplew.writeInt(CHAR_MAGIC_SPAWN); - mplew.writeShort(0); - mplew.write(0); - - mplew.writeShort(chr.getJob().getId()); - - /* replace "mplew.writeShort(chr.getJob().getId())" with this snippet for 3rd person FJ animation on all classes - if (chr.getJob().isA(MapleJob.HERMIT) || chr.getJob().isA(MapleJob.DAWNWARRIOR2) || chr.getJob().isA(MapleJob.NIGHTWALKER2)) { - mplew.writeShort(chr.getJob().getId()); - } else { - mplew.writeShort(412); - }*/ - - addCharLook(mplew, chr, false); - mplew.writeInt(chr.getInventory(MapleInventoryType.CASH).countById(5110000)); - mplew.writeInt(chr.getItemEffect()); - mplew.writeInt(ItemConstants.getInventoryType(chr.getChair()) == MapleInventoryType.SETUP ? chr.getChair() : 0); - - if(enteringField) { - Point spawnPos = new Point(chr.getPosition()); - spawnPos.y -= 42; - mplew.writePos(spawnPos); - mplew.write(6); - } else { - mplew.writePos(chr.getPosition()); - mplew.write(chr.getStance()); - } - - mplew.writeShort(0);//chr.getFh() - mplew.write(0); - MaplePet[] pet = chr.getPets(); - for (int i = 0; i < 3; i++) { - if (pet[i] != null) { - addPetInfo(mplew, pet[i], false); - } - } - mplew.write(0); //end of pets - if (chr.getMount() == null) { - mplew.writeInt(1); // mob level - mplew.writeLong(0); // mob exp + tiredness - } else { - mplew.writeInt(chr.getMount().getLevel()); - mplew.writeInt(chr.getMount().getExp()); - mplew.writeInt(chr.getMount().getTiredness()); - } - - MaplePlayerShop mps = chr.getPlayerShop(); - if (mps != null && mps.isOwner(chr)) { - if (mps.hasFreeSlot()) { - addAnnounceBox(mplew, mps, mps.getVisitors().length); - } else { - addAnnounceBox(mplew, mps, 1); - } - } else { - MapleMiniGame miniGame = chr.getMiniGame(); - if (miniGame != null && miniGame.isOwner(chr)) { - if (miniGame.hasFreeSlot()) { - addAnnounceBox(mplew, miniGame, 1, 0); - } else { - addAnnounceBox(mplew, miniGame, 2, miniGame.isMatchInProgress() ? 1 : 0); - } - } else { - mplew.write(0); - } - } - - if (chr.getChalkboard() != null) { - mplew.write(1); - mplew.writeMapleAsciiString(chr.getChalkboard()); - } else { - mplew.write(0); - } - addRingLook(mplew, chr, true); // crush - addRingLook(mplew, chr, false); // friendship - addMarriageRingLook(target, mplew, chr); - encodeNewYearCardInfo(mplew, chr); // new year seems to crash sometimes... - mplew.skip(2); - mplew.write(chr.getTeam());//only needed in specific fields - return mplew.getPacket(); - } - - private static void encodeNewYearCardInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - Set newyears = chr.getReceivedNewYearRecords(); - if(!newyears.isEmpty()) { - mplew.write(1); - - mplew.writeInt(newyears.size()); - for(NewYearCardRecord nyc : newyears) { - mplew.writeInt(nyc.getId()); - } - } else { - mplew.write(0); - } - } - - public static byte[] onNewYearCardRes(MapleCharacter user, int cardId, int mode, int msg) { - NewYearCardRecord newyear = user.getNewYearRecord(cardId); - return onNewYearCardRes(user, newyear, mode, msg); - } - - public static byte[] onNewYearCardRes(MapleCharacter user, NewYearCardRecord newyear, int mode, int msg) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NEW_YEAR_CARD_RES.getValue()); - mplew.write(mode); - switch (mode) { - case 4: // Successfully sent a New Year Card\r\n to %s. - case 6: // Successfully received a New Year Card. - encodeNewYearCard(newyear, mplew); - break; - - case 8: // Successfully deleted a New Year Card. - mplew.writeInt(newyear.getId()); - break; - - case 5: // Nexon's stupid and makes 4 modes do the same operation.. - case 7: - case 9: - case 0xB: - // 0x10: You have no free slot to store card.\r\ntry later on please. - // 0x11: You have no card to send. - // 0x12: Wrong inventory information ! - // 0x13: Cannot find such character ! - // 0x14: Incoherent Data ! - // 0x15: An error occured during DB operation. - // 0x16: An unknown error occured ! - // 0xF: You cannot send a card to yourself ! - mplew.write(msg); - break; - - case 0xA: // GetUnreceivedList_Done - int nSN = 1; - mplew.writeInt(nSN); - if ((nSN - 1) <= 98 && nSN > 0) {//lol nexon are you kidding - for (int i = 0; i < nSN; i++) { - mplew.writeInt(newyear.getId()); - mplew.writeInt(newyear.getSenderId()); - mplew.writeMapleAsciiString(newyear.getSenderName()); - } - } - break; - - case 0xC: // NotiArrived - mplew.writeInt(newyear.getId()); - mplew.writeMapleAsciiString(newyear.getSenderName()); - break; - - case 0xD: // BroadCast_AddCardInfo - mplew.writeInt(newyear.getId()); - mplew.writeInt(user.getId()); - break; - - case 0xE: // BroadCast_RemoveCardInfo - mplew.writeInt(newyear.getId()); - break; - } - return mplew.getPacket(); - } - - private static void encodeNewYearCard(NewYearCardRecord newyear, MaplePacketLittleEndianWriter mplew) { - mplew.writeInt(newyear.getId()); - mplew.writeInt(newyear.getSenderId()); - mplew.writeMapleAsciiString(newyear.getSenderName()); - mplew.writeBool(newyear.isSenderCardDiscarded()); - mplew.writeLong(newyear.getDateSent()); - mplew.writeInt(newyear.getReceiverId()); - mplew.writeMapleAsciiString(newyear.getReceiverName()); - mplew.writeBool(newyear.isReceiverCardDiscarded()); - mplew.writeBool(newyear.isReceiverCardReceived()); - mplew.writeLong(newyear.getDateReceived()); - mplew.writeMapleAsciiString(newyear.getMessage()); - } - - private static void addRingLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean crush) { - List rings; - if (crush) { - rings = chr.getCrushRings(); - } else { - rings = chr.getFriendshipRings(); - } - boolean yes = false; - for (MapleRing ring : rings) { - if (ring.equipped()) { - if (yes == false) { - yes = true; - mplew.write(1); - } - mplew.writeInt(ring.getRingId()); - mplew.writeInt(0); - mplew.writeInt(ring.getPartnerRingId()); - mplew.writeInt(0); - mplew.writeInt(ring.getItemId()); - } - } - if (yes == false) { - mplew.write(0); - } - } - - private static void addMarriageRingLook(MapleClient target, final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - MapleRing ring = chr.getMarriageRing(); - - if (ring == null || !ring.equipped()) { - mplew.write(0); - } else { - mplew.write(1); - - MapleCharacter targetChr = target.getPlayer(); - if (targetChr != null && targetChr.getPartnerId() == chr.getId()) { - mplew.writeInt(0); - mplew.writeInt(0); - } else { - mplew.writeInt(chr.getId()); - mplew.writeInt(ring.getPartnerChrId()); - } - - mplew.writeInt(ring.getItemId()); - } - } - - /** - * Adds a announcement box to an existing MaplePacketLittleEndianWriter. - * - * @param mplew The MaplePacketLittleEndianWriter to add an announcement box - * to. - * @param shop The shop to announce. - */ - private static void addAnnounceBox(final MaplePacketLittleEndianWriter mplew, MaplePlayerShop shop, int availability) { - mplew.write(4); - mplew.writeInt(shop.getObjectId()); - mplew.writeMapleAsciiString(shop.getDescription()); - mplew.write(0); - mplew.write(0); - mplew.write(1); - mplew.write(availability); - mplew.write(0); - } - - private static void addAnnounceBox(final MaplePacketLittleEndianWriter mplew, MapleMiniGame game, int ammount, int joinable) { - mplew.write(game.getGameType().getValue()); - mplew.writeInt(game.getObjectId()); // gameid/shopid - mplew.writeMapleAsciiString(game.getDescription()); // desc - mplew.writeBool(!game.getPassword().isEmpty()); // password here, thanks GabrielSin! - mplew.write(game.getPieceType()); - mplew.write(ammount); - mplew.write(2); //player capacity - mplew.write(joinable); - } - - private static void updateHiredMerchantBoxInfo(MaplePacketLittleEndianWriter mplew, MapleHiredMerchant hm) { - byte[] roomInfo = hm.getShopRoomInfo(); - - mplew.write(5); - mplew.writeInt(hm.getObjectId()); - mplew.writeMapleAsciiString(hm.getDescription()); - mplew.write(hm.getItemId() % 100); - mplew.write(roomInfo); // visitor capacity here, thanks GabrielSin! - } - - public static byte[] updateHiredMerchantBox(MapleHiredMerchant hm) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_HIRED_MERCHANT.getValue()); - mplew.writeInt(hm.getOwnerId()); - - updateHiredMerchantBoxInfo(mplew, hm); - return mplew.getPacket(); - } - - private static void updatePlayerShopBoxInfo(final MaplePacketLittleEndianWriter mplew, MaplePlayerShop shop) { - byte[] roomInfo = shop.getShopRoomInfo(); - - mplew.write(4); - mplew.writeInt(shop.getObjectId()); - mplew.writeMapleAsciiString(shop.getDescription()); - mplew.write(0); // pw - mplew.write(shop.getItemId() % 100); - mplew.write(roomInfo[0]); // curPlayers - mplew.write(roomInfo[1]); // maxPlayers - mplew.write(0); - } - - public static byte[] updatePlayerShopBox(MaplePlayerShop shop) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); - mplew.writeInt(shop.getOwner().getId()); - - updatePlayerShopBoxInfo(mplew, shop); - return mplew.getPacket(); - } - - public static byte[] removePlayerShopBox(MaplePlayerShop shop) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); - mplew.writeInt(shop.getOwner().getId()); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] facialExpression(MapleCharacter from, int expression) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(10); - mplew.writeShort(SendOpcode.FACIAL_EXPRESSION.getValue()); - mplew.writeInt(from.getId()); - mplew.writeInt(expression); - return mplew.getPacket(); - } - - private static void serializeMovementList(LittleEndianWriter lew, List moves) { - lew.write(moves.size()); - for (LifeMovementFragment move : moves) { - move.serialize(lew); - } - } - - public static byte[] movePlayer(int cid, List moves) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MOVE_PLAYER.getValue()); - mplew.writeInt(cid); - mplew.writeInt(0); - serializeMovementList(mplew, moves); - return mplew.getPacket(); - } - - public static byte[] moveSummon(int cid, int oid, Point startPos, List moves) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MOVE_SUMMON.getValue()); - mplew.writeInt(cid); - mplew.writeInt(oid); - mplew.writePos(startPos); - serializeMovementList(mplew, moves); - return mplew.getPacket(); - } - - public static byte[] moveMonster(int oid, boolean skillPossible, int skill, int skillId, int skillLevel, int pOption, Point startPos, List moves) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MOVE_MONSTER.getValue()); - mplew.writeInt(oid); - mplew.write(0); - mplew.writeBool(skillPossible); - mplew.write(skill); - mplew.write(skillId); - mplew.write(skillLevel); - mplew.writeShort(pOption); - mplew.writePos(startPos); - serializeMovementList(mplew, moves); - return mplew.getPacket(); - } - - public static byte[] summonAttack(int cid, int summonOid, byte direction, List allDamage) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - //b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00 - mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue()); - mplew.writeInt(cid); - mplew.writeInt(summonOid); - mplew.write(0); // char level - mplew.write(direction); - mplew.write(allDamage.size()); - for (SummonAttackEntry attackEntry : allDamage) { - mplew.writeInt(attackEntry.getMonsterOid()); // oid - mplew.write(6); // who knows - mplew.writeInt(attackEntry.getDamage()); // damage - } - - return mplew.getPacket(); - } - - /* - public static byte[] summonAttack(int cid, int summonSkillId, byte direction, List allDamage) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - //b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00 - mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue()); - mplew.writeInt(cid); - mplew.writeInt(summonSkillId); - mplew.write(direction); - mplew.write(4); - mplew.write(allDamage.size()); - for (SummonAttackEntry attackEntry : allDamage) { - mplew.writeInt(attackEntry.getMonsterOid()); // oid - mplew.write(6); // who knows - mplew.writeInt(attackEntry.getDamage()); // damage - } - return mplew.getPacket(); - } - */ - - public static byte[] closeRangeAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map> damage, int speed, int direction, int display) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CLOSE_RANGE_ATTACK.getValue()); - addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display); - return mplew.getPacket(); - } - - public static byte[] rangedAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map> damage, int speed, int direction, int display) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.RANGED_ATTACK.getValue()); - addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, projectile, damage, speed, direction, display); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] magicAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map> damage, int charge, int speed, int direction, int display) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MAGIC_ATTACK.getValue()); - addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display); - if (charge != -1) { - mplew.writeInt(charge); - } - return mplew.getPacket(); - } - - private static void addAttackBody(LittleEndianWriter lew, MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map> damage, int speed, int direction, int display) { - lew.writeInt(chr.getId()); - lew.write(numAttackedAndDamage); - lew.write(0x5B);//? - lew.write(skilllevel); - if (skilllevel > 0) { - lew.writeInt(skill); - } - lew.write(display); - lew.write(direction); - lew.write(stance); - lew.write(speed); - lew.write(0x0A); - lew.writeInt(projectile); - for (Integer oned : damage.keySet()) { - List onedList = damage.get(oned); - if (onedList != null) { - lew.writeInt(oned.intValue()); - lew.write(0x0); - if (skill == 4211006) { - lew.write(onedList.size()); - } - for (Integer eachd : onedList) { - lew.writeInt(eachd.intValue()); - } - } - } - } - - public static byte[] throwGrenade(int cid, Point p, int keyDown, int skillId, int skillLevel) { // packets found thanks to GabrielSin - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.THROW_GRENADE.getValue()); - mplew.writeInt(cid); - mplew.writeInt(p.x); - mplew.writeInt(p.y); - mplew.writeInt(keyDown); - mplew.writeInt(skillId); - mplew.writeInt(skillLevel); - return mplew.getPacket(); - } - - // someone thought it was a good idea to handle floating point representation through packets ROFL - private static int doubleToShortBits(double d) { - return (int) (Double.doubleToLongBits(d) >> 48); - } - - public static byte[] getNPCShop(MapleClient c, int sid, List items) { - MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.OPEN_NPC_SHOP.getValue()); - mplew.writeInt(sid); - mplew.writeShort(items.size()); // item count - for (MapleShopItem item : items) { - mplew.writeInt(item.getItemId()); - mplew.writeInt(item.getPrice()); - mplew.writeInt(item.getPrice() == 0 ? item.getPitch() : 0); //Perfect Pitch - mplew.writeInt(0); //Can be used x minutes after purchase - mplew.writeInt(0); //Hmm - if (!ItemConstants.isRechargeable(item.getItemId())) { - mplew.writeShort(1); // stacksize o.o - mplew.writeShort(item.getBuyable()); - } else { - mplew.writeShort(0); - mplew.writeInt(0); - mplew.writeShort(doubleToShortBits(ii.getUnitPrice(item.getItemId()))); - mplew.writeShort(ii.getSlotMax(c, item.getItemId())); - } - } - return mplew.getPacket(); - } - - /* 00 = / - * 01 = You don't have enough in stock - * 02 = You do not have enough mesos - * 03 = Please check if your inventory is full or not - * 05 = You don't have enough in stock - * 06 = Due to an error, the trade did not happen - * 07 = Due to an error, the trade did not happen - * 08 = / - * 0D = You need more items - * 0E = CRASH; LENGTH NEEDS TO BE LONGER :O - */ - public static byte[] shopTransaction(byte code) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.CONFIRM_SHOP_TRANSACTION.getValue()); - mplew.write(code); - return mplew.getPacket(); - } - - public static byte[] updateInventorySlotLimit(int type, int newLimit) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.INVENTORY_GROW.getValue()); - mplew.write(type); - mplew.write(newLimit); - return mplew.getPacket(); - } - - public static byte[] modifyInventory(boolean updateTick, final List mods) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.INVENTORY_OPERATION.getValue()); - mplew.writeBool(updateTick); - mplew.write(mods.size()); - //mplew.write(0); v104 :) - int addMovement = -1; - for (ModifyInventory mod : mods) { - mplew.write(mod.getMode()); - mplew.write(mod.getInventoryType()); - mplew.writeShort(mod.getMode() == 2 ? mod.getOldPosition() : mod.getPosition()); - switch (mod.getMode()) { - case 0: {//add item - addItemInfo(mplew, mod.getItem(), true); - break; - } - case 1: {//update quantity - mplew.writeShort(mod.getQuantity()); - break; - } - case 2: {//move - mplew.writeShort(mod.getPosition()); - if (mod.getPosition() < 0 || mod.getOldPosition() < 0) { - addMovement = mod.getOldPosition() < 0 ? 1 : 2; - } - break; - } - case 3: {//remove - if (mod.getPosition() < 0) { - addMovement = 2; - } - break; - } - } - mod.clear(); - } - if (addMovement > -1) { - mplew.write(addMovement); - } - return mplew.getPacket(); - } - - public static byte[] getScrollEffect(int chr, ScrollResult scrollSuccess, boolean legendarySpirit) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_SCROLL_EFFECT.getValue()); - mplew.writeInt(chr); - switch (scrollSuccess) { - case SUCCESS: - mplew.writeShort(1); - mplew.writeShort(legendarySpirit ? 1 : 0); - break; - case FAIL: - mplew.writeShort(0); - mplew.writeShort(legendarySpirit ? 1 : 0); - break; - case CURSE: - mplew.write(0); - mplew.write(1); - mplew.writeShort(legendarySpirit ? 1 : 0); - break; - } - return mplew.getPacket(); - } - - public static byte[] removePlayerFromMap(int cid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.REMOVE_PLAYER_FROM_MAP.getValue()); - mplew.writeInt(cid); - return mplew.getPacket(); - } - - public static byte[] silentRemoveItemFromMap(int oid) { - return removeItemFromMap(oid, 1, 0); - } - - /** - * animation: 0 - expire
1 - without animation
2 - pickup
4 - - * explode
cid is ignored for 0 and 1 - * - * @param oid - * @param animation - * @param cid - * @return - */ - public static byte[] removeItemFromMap(int oid, int animation, int cid) { - return removeItemFromMap(oid, animation, cid, false, 0); - } - - /** - * animation: 0 - expire
1 - without animation
2 - pickup
4 - - * explode
cid is ignored for 0 and 1.

Flagging pet as true - * will make a pet pick up the item. - * - * @param oid - * @param animation - * @param cid - * @param pet - * @param slot - * @return - */ - public static byte[] removeItemFromMap(int oid, int animation, int cid, boolean pet, int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.REMOVE_ITEM_FROM_MAP.getValue()); - mplew.write(animation); // expire - mplew.writeInt(oid); - if (animation >= 2) { - mplew.writeInt(cid); - if (pet) { - mplew.write(slot); - } - } - return mplew.getPacket(); - } - - public static byte[] updateCharLook(MapleClient target, MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_CHAR_LOOK.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(1); - addCharLook(mplew, chr, false); - addRingLook(mplew, chr, true); - addRingLook(mplew, chr, false); - addMarriageRingLook(target, mplew, chr); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] damagePlayer(int skill, int monsteridfrom, int cid, int damage, int fake, int direction, boolean pgmr, int pgmr_1, boolean is_pg, int oid, int pos_x, int pos_y) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DAMAGE_PLAYER.getValue()); - mplew.writeInt(cid); - mplew.write(skill); - mplew.writeInt(damage); - if(skill != -4) { - mplew.writeInt(monsteridfrom); - mplew.write(direction); - if (pgmr) { - mplew.write(pgmr_1); - mplew.write(is_pg ? 1 : 0); - mplew.writeInt(oid); - mplew.write(6); - mplew.writeShort(pos_x); - mplew.writeShort(pos_y); - mplew.write(0); - } else { - mplew.writeShort(0); - } - mplew.writeInt(damage); - if (fake > 0) { - mplew.writeInt(fake); - } - } else { - mplew.writeInt(damage); - } - - return mplew.getPacket(); - } - - public static byte[] sendMapleLifeCharacterInfo() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MAPLELIFE_RESULT.getValue()); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] sendMapleLifeNameError() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MAPLELIFE_RESULT.getValue()); - mplew.writeInt(2); - mplew.writeInt(3); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] sendMapleLifeError(int code) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MAPLELIFE_ERROR.getValue()); - mplew.write(0); - mplew.writeInt(code); - return mplew.getPacket(); - } - - public static byte[] charNameResponse(String charname, boolean nameUsed) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CHAR_NAME_RESPONSE.getValue()); - mplew.writeMapleAsciiString(charname); - mplew.write(nameUsed ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] addNewCharEntry(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ADD_NEW_CHAR_ENTRY.getValue()); - mplew.write(0); - addCharEntry(mplew, chr, false); - return mplew.getPacket(); - } - - /** - * state 0 = del ok state 12 = invalid bday state 14 = incorrect pic - * - * @param cid - * @param state - * @return - */ - public static byte[] deleteCharResponse(int cid, int state) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DELETE_CHAR_RESPONSE.getValue()); - mplew.writeInt(cid); - mplew.write(state); - return mplew.getPacket(); - } - - public static byte[] selectWorld(int world) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.LAST_CONNECTED_WORLD.getValue()); - mplew.writeInt(world);//According to GMS, it should be the world that contains the most characters (most active) - return mplew.getPacket(); - } - - public static byte[] sendRecommended(List> worlds) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.RECOMMENDED_WORLD_MESSAGE.getValue()); - mplew.write(worlds.size());//size - for (Iterator> it = worlds.iterator(); it.hasNext();) { - Pair world = it.next(); - mplew.writeInt(world.getLeft()); - mplew.writeMapleAsciiString(world.getRight()); - } - return mplew.getPacket(); - } - - /** - * - * @param chr - * @param isSelf - * @return - */ - public static byte[] charInfo(MapleCharacter chr) { - //3D 00 0A 43 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CHAR_INFO.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(chr.getLevel()); - mplew.writeShort(chr.getJob().getId()); - mplew.writeShort(chr.getFame()); - mplew.write(chr.getMarriageRing() != null ? 1 : 0); - String guildName = ""; - String allianceName = ""; - if (chr.getGuildId() > 0) { - MapleGuild mg = Server.getInstance().getGuild(chr.getGuildId()); - guildName = mg.getName(); - - MapleAlliance alliance = Server.getInstance().getAlliance(chr.getGuild().getAllianceId()); - if (alliance != null) { - allianceName = alliance.getName(); - } - } - mplew.writeMapleAsciiString(guildName); - mplew.writeMapleAsciiString(allianceName); // does not seem to work - mplew.write(0); // pMedalInfo, thanks to Arnah (Vertisy) - - MaplePet[] pets = chr.getPets(); - Item inv = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -114); - for (int i = 0; i < 3; i++) { - if (pets[i] != null) { - mplew.write(pets[i].getUniqueId()); - mplew.writeInt(pets[i].getItemId()); // petid - mplew.writeMapleAsciiString(pets[i].getName()); - mplew.write(pets[i].getLevel()); // pet level - mplew.writeShort(pets[i].getCloseness()); // pet closeness - mplew.write(pets[i].getFullness()); // pet fullness - mplew.writeShort(0); - mplew.writeInt(inv != null ? inv.getItemId() : 0); - } - } - mplew.write(0); //end of pets - - Item mount; //mounts can potentially crash the client if the player's level is not properly checked - if (chr.getMount() != null && (mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18)) != null && MapleItemInformationProvider.getInstance().getEquipLevelReq(mount.getItemId()) <= chr.getLevel()) { - MapleMount mmount = chr.getMount(); - mplew.write(mmount.getId()); //mount - mplew.writeInt(mmount.getLevel()); //level - mplew.writeInt(mmount.getExp()); //exp - mplew.writeInt(mmount.getTiredness()); //tiredness - } else { - mplew.write(0); - } - mplew.write(chr.getCashShop().getWishList().size()); - for (int sn : chr.getCashShop().getWishList()) { - mplew.writeInt(sn); - } - - MonsterBook book = chr.getMonsterBook(); - mplew.writeInt(book.getBookLevel()); - mplew.writeInt(book.getNormalCard()); - mplew.writeInt(book.getSpecialCard()); - mplew.writeInt(book.getTotalCards()); - mplew.writeInt(chr.getMonsterBookCover() > 0 ? MapleItemInformationProvider.getInstance().getCardMobId(chr.getMonsterBookCover()) : 0); - Item medal = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -49); - if (medal != null) { - mplew.writeInt(medal.getItemId()); - } else { - mplew.writeInt(0); - } - ArrayList medalQuests = new ArrayList<>(); - List completed = chr.getCompletedQuests(); - for (MapleQuestStatus q : completed) { - if (q.getQuest().getId() >= 29000) { // && q.getQuest().getId() <= 29923 - medalQuests.add(q.getQuest().getId()); - } - } - - Collections.sort(medalQuests); - mplew.writeShort(medalQuests.size()); - for (Short s : medalQuests) { - mplew.writeShort(s); - } - return mplew.getPacket(); - } - - /** - * It is important that statups is in the correct order (see declaration - * order in MapleBuffStat) since this method doesn't do automagical - * reordering. - * - * @param buffid - * @param bufflength - * @param statups - * @return - */ - //1F 00 00 00 00 00 03 00 00 40 00 00 00 E0 00 00 00 00 00 00 00 00 E0 01 8E AA 4F 00 00 C2 EB 0B E0 01 8E AA 4F 00 00 C2 EB 0B 0C 00 8E AA 4F 00 00 C2 EB 0B 44 02 8E AA 4F 00 00 C2 EB 0B 44 02 8E AA 4F 00 00 C2 EB 0B 00 00 E0 7A 1D 00 8E AA 4F 00 00 00 00 00 00 00 00 03 - public static byte[] giveBuff(int buffid, int bufflength, List> statups) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); - boolean special = false; - writeLongMask(mplew, statups); - for (Pair statup : statups) { - if (statup.getLeft().equals(MapleBuffStat.MONSTER_RIDING) || statup.getLeft().equals(MapleBuffStat.HOMING_BEACON)) { - special = true; - } - mplew.writeShort(statup.getRight().shortValue()); - mplew.writeInt(buffid); - mplew.writeInt(bufflength); - } - mplew.writeInt(0); - mplew.write(0); - mplew.writeInt(statups.get(0).getRight()); //Homing beacon ... - - if (special) { - mplew.skip(3); - } - return mplew.getPacket(); - } - - /** - * - * @param cid - * @param statups - * @param mount - * @return - */ - public static byte[] showMonsterRiding(int cid, MapleMount mount) { //Gtfo with this, this is just giveForeignBuff - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - mplew.writeLong(MapleBuffStat.MONSTER_RIDING.getValue()); - mplew.writeLong(0); - mplew.writeShort(0); - mplew.writeInt(mount.getItemId()); - mplew.writeInt(mount.getSkillId()); - mplew.writeInt(0); //Server Tick value. - mplew.writeShort(0); - mplew.write(0); //Times you have been buffed - return mplew.getPacket(); - } - /* mplew.writeInt(cid); - writeLongMask(mplew, statups); - for (Pair statup : statups) { - if (morph) { - mplew.writeInt(statup.getRight().intValue()); - } else { - mplew.writeShort(statup.getRight().shortValue()); - } - } - mplew.writeShort(0); - mplew.write(0);*/ - - /** - * - * @param c - * @param quest - * @return - */ - public static byte[] forfeitQuest(short quest) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(1); - mplew.writeShort(quest); - mplew.write(0); - return mplew.getPacket(); - } - - /** - * - * @param c - * @param quest - * @return - */ - public static byte[] completeQuest(short quest, long time) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(1); - mplew.writeShort(quest); - mplew.write(2); - mplew.writeLong(getTime(time)); - return mplew.getPacket(); - } - - /** - * - * @param c - * @param quest - * @param npc - * @param progress - * @return - */ - - public static byte[] updateQuestInfo(short quest, int npc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); - mplew.write(8); //0x0A in v95 - mplew.writeShort(quest); - mplew.writeInt(npc); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] addQuestTimeLimit(final short quest, final int time) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); - mplew.write(6); - mplew.writeShort(1);//Size but meh, when will there be 2 at the same time? And it won't even replace the old one :) - mplew.writeShort(quest); - mplew.writeInt(time); - return mplew.getPacket(); - } - - public static byte[] removeQuestTimeLimit(final short quest) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); - mplew.write(7); - mplew.writeShort(1);//Position - mplew.writeShort(quest); - return mplew.getPacket(); - } - - public static byte[] updateQuest(MapleQuestStatus q, boolean infoUpdate) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(1); - mplew.writeShort(infoUpdate ? q.getQuest().getInfoNumber() : q.getQuest().getId()); - if (infoUpdate) { - mplew.write(1); - } else { - mplew.write(q.getStatus().getId()); - } - + } + } + } + + public static byte[] setExtraPendantSlot(boolean toggleExtraSlot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_EXTRA_PENDANT_SLOT.getValue()); + mplew.writeBool(toggleExtraSlot); + return mplew.getPacket(); + } + + private static void addCharEntry(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean viewall) { + addCharStats(mplew, chr); + addCharLook(mplew, chr, false); + if (!viewall) { + mplew.write(0); + } + if (chr.isGM()) { + mplew.write(0); + return; + } + mplew.write(1); // world rank enabled (next 4 ints are not sent if disabled) Short?? + mplew.writeInt(chr.getRank()); // world rank + mplew.writeInt(chr.getRankMove()); // move (negative is downwards) + mplew.writeInt(chr.getJobRank()); // job rank + mplew.writeInt(chr.getJobRankMove()); // move (negative is downwards) + } + + private static void addQuestInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.writeShort(chr.getStartedQuestsSize()); + for (MapleQuestStatus q : chr.getStartedQuests()) { + mplew.writeShort(q.getQuest().getId()); + mplew.writeMapleAsciiString(q.getQuestData()); + if (q.getQuest().getInfoNumber() > 0) { + mplew.writeShort(q.getQuest().getInfoNumber()); mplew.writeMapleAsciiString(q.getQuestData()); - mplew.skip(5); - return mplew.getPacket(); + } } + List completed = chr.getCompletedQuests(); + mplew.writeShort(completed.size()); + for (MapleQuestStatus q : completed) { + mplew.writeShort(q.getQuest().getId()); + mplew.writeLong(getTime(q.getCompletionTime())); + } + } - private static void writeLongMaskD(final MaplePacketLittleEndianWriter mplew, List> statups) { - long firstmask = 0; - long secondmask = 0; - for (Pair statup : statups) { - if (statup.getLeft().isFirst()) { - firstmask |= statup.getLeft().getValue(); - } else { - secondmask |= statup.getLeft().getValue(); - } + private static void addExpirationTime(final MaplePacketLittleEndianWriter mplew, long time) { + mplew.writeLong(getTime(time)); // offset expiration time issue found thanks to Thora + } + + private static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item) { + addItemInfo(mplew, item, false); + } + + protected static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item, boolean zeroPosition) { + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + boolean isCash = ii.isCash(item.getItemId()); + boolean isPet = item.getPetId() > -1; + boolean isRing = false; + Equip equip = null; + short pos = item.getPosition(); + byte itemType = item.getItemType(); + if (itemType == 1) { + equip = (Equip) item; + isRing = equip.getRingId() > -1; + } + if (!zeroPosition) { + if (equip != null) { + if (pos < 0) { + pos *= -1; } - mplew.writeLong(firstmask); - mplew.writeLong(secondmask); + mplew.writeShort(pos > 100 ? pos - 100 : pos); + } else { + mplew.write(pos); + } } - - public static byte[] giveDebuff(List> statups, MobSkill skill) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); - writeLongMaskD(mplew, statups); - for (Pair statup : statups) { - mplew.writeShort(statup.getRight().shortValue()); - mplew.writeShort(skill.getSkillId()); - mplew.writeShort(skill.getSkillLevel()); - mplew.writeInt((int) skill.getDuration()); + mplew.write(itemType); + mplew.writeInt(item.getItemId()); + mplew.writeBool(isCash); + if (isCash) { + mplew.writeLong(isPet ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId()); + } + addExpirationTime(mplew, item.getExpiration()); + if (isPet) { + MaplePet pet = item.getPet(); + mplew.writeAsciiString(StringUtil.getRightPaddedStr(pet.getName(), '\0', 13)); + mplew.write(pet.getLevel()); + mplew.writeShort(pet.getCloseness()); + mplew.write(pet.getFullness()); + addExpirationTime(mplew, item.getExpiration()); + mplew.writeInt(pet.getPetFlag()); /* pet flags found by -- Irenex & Spoon */ + + mplew.write(new byte[]{(byte) 0x50, (byte) 0x46}); //wonder what this is + mplew.writeInt(0); + return; + } + if (equip == null) { + mplew.writeShort(item.getQuantity()); + mplew.writeMapleAsciiString(item.getOwner()); + mplew.writeShort(item.getFlag()); // flag + + if (ItemConstants.isRechargeable(item.getItemId())) { + mplew.writeInt(2); + mplew.write(new byte[]{(byte) 0x54, 0, 0, (byte) 0x34}); + } + return; + } + mplew.write(equip.getUpgradeSlots()); // upgrade slots + mplew.write(equip.getLevel()); // level + mplew.writeShort(equip.getStr()); // str + mplew.writeShort(equip.getDex()); // dex + mplew.writeShort(equip.getInt()); // int + mplew.writeShort(equip.getLuk()); // luk + mplew.writeShort(equip.getHp()); // hp + mplew.writeShort(equip.getMp()); // mp + mplew.writeShort(equip.getWatk()); // watk + mplew.writeShort(equip.getMatk()); // matk + mplew.writeShort(equip.getWdef()); // wdef + mplew.writeShort(equip.getMdef()); // mdef + mplew.writeShort(equip.getAcc()); // accuracy + mplew.writeShort(equip.getAvoid()); // avoid + mplew.writeShort(equip.getHands()); // hands + mplew.writeShort(equip.getSpeed()); // speed + mplew.writeShort(equip.getJump()); // jump + mplew.writeMapleAsciiString(equip.getOwner()); // owner name + mplew.writeShort(equip.getFlag()); //Item Flags + + if (isCash) { + for (int i = 0; i < 10; i++) { + mplew.write(0x40); + } + } else { + int itemLevel = equip.getItemLevel(); + + long expNibble = (ExpTable.getExpNeededForLevel(ii.getEquipLevelReq(item.getItemId())) * equip.getItemExp()); + expNibble /= ExpTable.getEquipExpNeededForLevel(itemLevel); + + mplew.write(0); + mplew.write(itemLevel); //Item Level + mplew.writeInt((int) expNibble); + mplew.writeInt(equip.getVicious()); //WTF NEXON ARE YOU SERIOUS? + mplew.writeLong(0); + } + mplew.writeLong(getTime(-2)); + mplew.writeInt(-1); + + } + + private static void addInventoryInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + for (byte i = 1; i <= 5; i++) { + mplew.write(chr.getInventory(MapleInventoryType.getByType(i)).getSlotLimit()); + } + mplew.writeLong(getTime(-2)); + MapleInventory iv = chr.getInventory(MapleInventoryType.EQUIPPED); + Collection equippedC = iv.list(); + List equipped = new ArrayList<>(equippedC.size()); + List equippedCash = new ArrayList<>(equippedC.size()); + for (Item item : equippedC) { + if (item.getPosition() <= -100) { + equippedCash.add((Item) item); + } else { + equipped.add((Item) item); + } + } + Collections.sort(equipped); + for (Item item : equipped) { + addItemInfo(mplew, item); + } + mplew.writeShort(0); // start of equip cash + for (Item item : equippedCash) { + addItemInfo(mplew, item); + } + mplew.writeShort(0); // start of equip inventory + for (Item item : chr.getInventory(MapleInventoryType.EQUIP).list()) { + addItemInfo(mplew, item); + } + mplew.writeInt(0); + for (Item item : chr.getInventory(MapleInventoryType.USE).list()) { + addItemInfo(mplew, item); + } + mplew.write(0); + for (Item item : chr.getInventory(MapleInventoryType.SETUP).list()) { + addItemInfo(mplew, item); + } + mplew.write(0); + for (Item item : chr.getInventory(MapleInventoryType.ETC).list()) { + addItemInfo(mplew, item); + } + mplew.write(0); + for (Item item : chr.getInventory(MapleInventoryType.CASH).list()) { + addItemInfo(mplew, item); + } + } + + private static void addSkillInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.write(0); // start of skills + Map skills = chr.getSkills(); + int skillsSize = skills.size(); + // We don't want to include any hidden skill in this, so subtract them from the size list and ignore them. + for (Iterator> it = skills.entrySet().iterator(); it.hasNext();) { + Entry skill = it.next(); + if (GameConstants.isHiddenSkills(skill.getKey().getId())) { + skillsSize--; + } + } + mplew.writeShort(skillsSize); + for (Iterator> it = skills.entrySet().iterator(); it.hasNext();) { + Entry skill = it.next(); + if (GameConstants.isHiddenSkills(skill.getKey().getId())) { + continue; + } + mplew.writeInt(skill.getKey().getId()); + mplew.writeInt(skill.getValue().skillevel); + addExpirationTime(mplew, skill.getValue().expiration); + if (skill.getKey().isFourthJob()) { + mplew.writeInt(skill.getValue().masterlevel); + } + } + mplew.writeShort(chr.getAllCooldowns().size()); + for (PlayerCoolDownValueHolder cooling : chr.getAllCooldowns()) { + mplew.writeInt(cooling.skillId); + int timeLeft = (int) (cooling.length + cooling.startTime - System.currentTimeMillis()); + mplew.writeShort(timeLeft / 1000); + } + } + + private static void addMonsterBookInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.writeInt(chr.getMonsterBookCover()); // cover + mplew.write(0); + Map cards = chr.getMonsterBook().getCards(); + mplew.writeShort(cards.size()); + for (Entry all : cards.entrySet()) { + mplew.writeShort(all.getKey() % 10000); // Id + mplew.write(all.getValue()); // Level + } + } + + public static byte[] sendGuestTOS() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUEST_ID_LOGIN.getValue()); + mplew.writeShort(0x100); + mplew.writeInt(Randomizer.nextInt(999999)); + mplew.writeLong(0); + mplew.writeLong(getTime(-2)); + mplew.writeLong(getTime(System.currentTimeMillis())); + mplew.writeInt(0); + mplew.writeMapleAsciiString("http://maplesolaxia.com"); + return mplew.getPacket(); + } + + /** + * Sends a hello packet. + * + * @param mapleVersion The maple client version. + * @param sendIv the IV used by the server for sending + * @param recvIv the IV used by the server for receiving + * @return + */ + public static byte[] getHello(short mapleVersion, byte[] sendIv, byte[] recvIv) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); + mplew.writeShort(0x0E); + mplew.writeShort(mapleVersion); + mplew.writeShort(1); + mplew.write(49); + mplew.write(recvIv); + mplew.write(sendIv); + mplew.write(8); + return mplew.getPacket(); + } + + /** + * Sends a ping packet. + * + * @return The packet. + */ + public static byte[] getPing() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); + mplew.writeShort(SendOpcode.PING.getValue()); + return mplew.getPacket(); + } + + /** + * Gets a login failed packet. + * + * Possible values for reason:
3: ID deleted or blocked
+ * 4: Incorrect password
5: Not a registered id
6: System error
+ * 7: Already logged in
8: System error
9: System error
10: + * Cannot process so many connections
11: Only users older than 20 can + * use this channel
13: Unable to log on as master at this ip
14: + * Wrong gateway or personal info and weird korean button
15: Processing + * request with that korean button!
16: Please verify your account + * through email...
17: Wrong gateway or personal info
21: Please + * verify your account through email...
23: License agreement
25: + * Maple Europe notice =[ FUCK YOU NEXON
27: Some weird full client + * notice, probably for trial versions
+ * + * @param reason The reason logging in failed. + * @return The login failed packet. + */ + public static byte[] getLoginFailed(int reason) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); + mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); + mplew.write(reason); + mplew.write(0); + mplew.writeInt(0); + return mplew.getPacket(); + } + + /** + * Gets a login failed packet. + * + * Possible values for reason:
2: ID deleted or blocked
+ * 3: ID deleted or blocked
4: Incorrect password
5: Not a + * registered id
6: Trouble logging into the game?
7: Already logged + * in
8: Trouble logging into the game?
9: Trouble logging into the + * game?
10: Cannot process so many connections
11: Only users older + * than 20 can use this channel
12: Trouble logging into the game?
+ * 13: Unable to log on as master at this ip
14: Wrong gateway or + * personal info and weird korean button
15: Processing request with + * that korean button!
16: Please verify your account through + * email...
17: Wrong gateway or personal info
21: Please verify + * your account through email...
23: Crashes
25: Maple Europe notice + * =[ FUCK YOU NEXON
27: Some weird full client notice, probably for + * trial versions
+ * + * @param reason The reason logging in failed. + * @return The login failed packet. + */ + public static byte[] getAfterLoginError(int reason) {//same as above o.o + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); + mplew.writeShort(SendOpcode.SELECT_CHARACTER_BY_VAC.getValue()); + mplew.writeShort(reason);//using other types than stated above = CRASH + return mplew.getPacket(); + } + + public static byte[] sendPolice() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAKE_GM_NOTICE.getValue()); + mplew.write(0);//doesn't even matter what value + return mplew.getPacket(); + } + + public static byte[] sendPolice(String text) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DATA_CRC_CHECK_FAILED.getValue()); + mplew.writeMapleAsciiString(text); + return mplew.getPacket(); + } + + public static byte[] getPermBan(byte reason) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); + mplew.write(2); // Account is banned + mplew.write(0); + mplew.writeInt(0); + mplew.write(0); + mplew.writeLong(getTime(-1)); + + return mplew.getPacket(); + } + + public static byte[] getTempBan(long timestampTill, byte reason) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(17); + mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); + mplew.write(2); + mplew.write(0); + mplew.writeInt(0); + mplew.write(reason); + mplew.writeLong(getTime(timestampTill)); // Tempban date is handled as a 64-bit long, number of 100NS intervals since 1/1/1601. Lulz. + + return mplew.getPacket(); + } + + /** + * Gets a successful authentication packet. + * + * @param c + * @return the successful authentication packet + */ + public static byte[] getAuthSuccess(MapleClient c) { + Server.getInstance().loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB. + + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); + mplew.writeInt(0); + mplew.writeShort(0); + mplew.writeInt(c.getAccID()); + mplew.write(c.getGender()); + + boolean canFly = Server.getInstance().canFly(c.getAccID()); + mplew.writeBool((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) ? c.getGMLevel() > 1 : false); // thanks Steve(kaito1410) for pointing the GM account boolean here + mplew.write(((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) && c.getGMLevel() > 1) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish. + mplew.write(0); // Country Code. + + mplew.writeMapleAsciiString(c.getAccountName()); + mplew.write(0); + + mplew.write(0); // IsQuietBan + mplew.writeLong(0);//IsQuietBanTimeStamp + mplew.writeLong(0); //CreationTimeStamp + + mplew.writeInt(1); // 1: Remove the "Select the world you want to play in" + + mplew.write(ServerConstants.ENABLE_PIN && !c.canBypassPin() ? 0 : 1); // 0 = Pin-System Enabled, 1 = Disabled + mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null ? 0 : 1) : 2); // 0 = Register PIC, 1 = Ask for PIC, 2 = Disabled + + return mplew.getPacket(); + } + + /** + * Gets a packet detailing a PIN operation. + * + * Possible values for mode:
0 - PIN was accepted
1 - + * Register a new PIN
2 - Invalid pin / Reenter
3 - Connection + * failed due to system error
4 - Enter the pin + * + * @param mode The mode. + * @return + */ + private static byte[] pinOperation(byte mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.CHECK_PINCODE.getValue()); + mplew.write(mode); + return mplew.getPacket(); + } + + public static byte[] pinRegistered() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.UPDATE_PINCODE.getValue()); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] requestPin() { + return pinOperation((byte) 4); + } + + public static byte[] requestPinAfterFailure() { + return pinOperation((byte) 2); + } + + public static byte[] registerPin() { + return pinOperation((byte) 1); + } + + public static byte[] pinAccepted() { + return pinOperation((byte) 0); + } + + public static byte[] wrongPic() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.CHECK_SPW_RESULT.getValue()); + mplew.write(0); + return mplew.getPacket(); + } + + /** + * Gets a packet detailing a server and its channels. + * + * @param serverId + * @param serverName The name of the server. + * @param flag + * @param eventmsg + * @param channelLoad Load of the channel - 1200 seems to be max. + * @return The server info packet. + */ + public static byte[] getServerList(int serverId, String serverName, int flag, String eventmsg, List channelLoad) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SERVERLIST.getValue()); + mplew.write(serverId); + mplew.writeMapleAsciiString(serverName); + mplew.write(flag); + mplew.writeMapleAsciiString(eventmsg); + mplew.write(100); // rate modifier, don't ask O.O! + mplew.write(0); // event xp * 2.6 O.O! + mplew.write(100); // rate modifier, don't ask O.O! + mplew.write(0); // drop rate * 2.6 + mplew.write(0); + mplew.write(channelLoad.size()); + for (Channel ch : channelLoad) { + mplew.writeMapleAsciiString(serverName + "-" + ch.getId()); + mplew.writeInt(ch.getChannelCapacity()); + + // thanks GabrielSin for this channel packet structure part + mplew.write(1);// nWorldID + mplew.write(ch.getId() - 1);// nChannelID + mplew.writeBool(false);// bAdultChannel + } + mplew.writeShort(0); + return mplew.getPacket(); + } + + /** + * Gets a packet saying that the server list is over. + * + * @return The end of server list packet. + */ + public static byte[] getEndOfServerList() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.SERVERLIST.getValue()); + mplew.write(0xFF); + return mplew.getPacket(); + } + + /** + * Gets a packet detailing a server status message. + * + * Possible values for status:
0 - Normal
1 - Highly + * populated
2 - Full + * + * @param status The server status. + * @return The server status packet. + */ + public static byte[] getServerStatus(int status) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.SERVERSTATUS.getValue()); + mplew.writeShort(status); + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client the IP of the channel server. + * + * @param inetAddr The InetAddress of the requested channel server. + * @param port The port the channel is on. + * @param clientId The ID of the client. + * @return The server IP packet. + */ + public static byte[] getServerIP(InetAddress inetAddr, int port, int clientId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SERVER_IP.getValue()); + mplew.writeShort(0); + byte[] addr = inetAddr.getAddress(); + mplew.write(addr); + mplew.writeShort(port); + mplew.writeInt(clientId); + mplew.write(new byte[]{0, 0, 0, 0, 0}); + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client the IP of the new channel. + * + * @param inetAddr The InetAddress of the requested channel server. + * @param port The port the channel is on. + * @return The server IP packet. + */ + public static byte[] getChannelChange(InetAddress inetAddr, int port) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CHANGE_CHANNEL.getValue()); + mplew.write(1); + byte[] addr = inetAddr.getAddress(); + mplew.write(addr); + mplew.writeShort(port); + return mplew.getPacket(); + } + + /** + * Gets a packet with a list of characters. + * + * @param c The MapleClient to load characters of. + * @param serverId The ID of the server requested. + * @param status The charlist request result. + * @return The character list packet. + * + * Possible values for status: + *
2: ID deleted or blocked
+ *
3: ID deleted or blocked
+ *
4: Incorrect password
+ *
5: Not an registered ID
+ *
6: Trouble logging in?
+ *
10: Server handling too many connections
+ *
11: Only 20 years or older
+ *
13: Unable to log as master at IP
+ *
14: Wrong gateway or personal info
+ *
15: Still processing request
+ *
16: Verify account via email
+ *
17: Wrong gateway or personal info
+ *
21: Verify account via email
+ */ + public static byte[] getCharList(MapleClient c, int serverId, int status) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CHARLIST.getValue()); + mplew.write(status); + List chars = c.loadCharacters(serverId); + mplew.write((byte) chars.size()); + for (MapleCharacter chr : chars) { + addCharEntry(mplew, chr, false); + } + + mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null ? 0 : 1) : 2); + mplew.writeInt(ServerConstants.COLLECTIVE_CHARSLOT ? chars.size() + c.getAvailableCharacterSlots() : c.getCharacterSlots()); + return mplew.getPacket(); + } + + public static byte[] enableTV() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.ENABLE_TV.getValue()); + mplew.writeInt(0); + mplew.write(0); + return mplew.getPacket(); + } + + /** + * Removes TV + * + * @return The Remove TV Packet + */ + public static byte[] removeTV() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); + mplew.writeShort(SendOpcode.REMOVE_TV.getValue()); + return mplew.getPacket(); + } + + /** + * Sends MapleTV + * + * @param chr The character shown in TV + * @param messages The message sent with the TV + * @param type The type of TV + * @param partner The partner shown with chr + * @return the SEND_TV packet + */ + public static byte[] sendTV(MapleCharacter chr, List messages, int type, MapleCharacter partner) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SEND_TV.getValue()); + mplew.write(partner != null ? 3 : 1); + mplew.write(type); //Heart = 2 Star = 1 Normal = 0 + addCharLook(mplew, chr, false); + mplew.writeMapleAsciiString(chr.getName()); + if (partner != null) { + mplew.writeMapleAsciiString(partner.getName()); + } else { + mplew.writeShort(0); + } + for (int i = 0; i < messages.size(); i++) { + if (i == 4 && messages.get(4).length() > 15) { + mplew.writeMapleAsciiString(messages.get(4).substring(0, 15)); + } else { + mplew.writeMapleAsciiString(messages.get(i)); + } + } + mplew.writeInt(1337); // time limit shit lol 'Your thing still start in blah blah seconds' + if (partner != null) { + addCharLook(mplew, partner, false); + } + return mplew.getPacket(); + } + + /** + * Gets character info for a character. + * + * @param chr The character to get info about. + * @return The character info packet. + */ + public static byte[] getCharInfo(MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_FIELD.getValue()); + mplew.writeInt(chr.getClient().getChannel() - 1); + mplew.write(1); + mplew.write(1); + mplew.writeShort(0); + for (int i = 0; i < 3; i++) { + mplew.writeInt(Randomizer.nextInt()); + } + addCharacterInfo(mplew, chr); + mplew.writeLong(getTime(System.currentTimeMillis())); + return mplew.getPacket(); + } + + /** + * Gets an empty stat update. + * + * @return The empty stat update packet. + */ + public static byte[] enableActions() { + return updatePlayerStats(EMPTY_STATUPDATE, true, null); + } + + /** + * Gets an update for specified stats. + * + * @param stats The list of stats to update. + * @param enableActions Allows actions after the update. + * @param chr The update target. + * @return The stat update packet. + */ + public static byte[] updatePlayerStats(List> stats, boolean enableActions, MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STAT_CHANGED.getValue()); + mplew.write(enableActions ? 1 : 0); + int updateMask = 0; + for (Pair statupdate : stats) { + updateMask |= statupdate.getLeft().getValue(); + } + List> mystats = stats; + if (mystats.size() > 1) { + Collections.sort(mystats, new Comparator>() { + @Override + public int compare(Pair o1, Pair o2) { + int val1 = o1.getLeft().getValue(); + int val2 = o2.getLeft().getValue(); + return (val1 < val2 ? -1 : (val1 == val2 ? 0 : 1)); } - mplew.writeShort(0); // ??? wk charges have 600 here o.o - mplew.writeShort(900);//Delay - mplew.write(1); - return mplew.getPacket(); + }); } - - public static byte[] giveForeignDebuff(int cid, List> statups, MobSkill skill) { - // Poison damage visibility and missing diseases status visibility, extended through map transitions thanks to Ronan - - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMaskD(mplew, statups); - for (Pair statup : statups) { - if(statup.getLeft() == MapleDisease.POISON) mplew.writeShort(statup.getRight().shortValue()); - mplew.writeShort(skill.getSkillId()); - mplew.writeShort(skill.getSkillLevel()); - } - mplew.writeShort(0); // same as give_buff - mplew.writeShort(900);//Delay - return mplew.getPacket(); - } - - public static byte[] cancelForeignDebuff(int cid, long mask) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - mplew.writeLong(0); - mplew.writeLong(mask); - return mplew.getPacket(); - } - - public static byte[] giveForeignBuff(int cid, List> statups) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMask(mplew, statups); - for (Pair statup : statups) { - mplew.writeShort(statup.getRight().shortValue()); - } - mplew.writeInt(0); - mplew.writeShort(0); - return mplew.getPacket(); - } - - public static byte[] cancelForeignBuff(int cid, List statups) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMaskFromList(mplew, statups); - return mplew.getPacket(); - } - - public static byte[] cancelBuff(List statups) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_BUFF.getValue()); - writeLongMaskFromList(mplew, statups); - mplew.write(1);//? - return mplew.getPacket(); - } - - private static void writeLongMask(final MaplePacketLittleEndianWriter mplew, List> statups) { - long firstmask = 0; - long secondmask = 0; - for (Pair statup : statups) { - if (statup.getLeft().isFirst()) { - firstmask |= statup.getLeft().getValue(); - } else { - secondmask |= statup.getLeft().getValue(); - } - } - mplew.writeLong(firstmask); - mplew.writeLong(secondmask); - } - - private static void writeLongMaskFromList(final MaplePacketLittleEndianWriter mplew, List statups) { - long firstmask = 0; - long secondmask = 0; - for (MapleBuffStat statup : statups) { - if (statup.isFirst()) { - firstmask |= statup.getValue(); - } else { - secondmask |= statup.getValue(); - } - } - mplew.writeLong(firstmask); - mplew.writeLong(secondmask); - } - - public static byte[] cancelDebuff(long mask) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); - mplew.writeShort(SendOpcode.CANCEL_BUFF.getValue()); - mplew.writeLong(0); - mplew.writeLong(mask); - mplew.write(0); - return mplew.getPacket(); - } - - private static void writeLongMaskSlowD(final MaplePacketLittleEndianWriter mplew) { - mplew.writeInt(0); - mplew.writeInt(2048); - mplew.writeLong(0); - } - - public static byte[] giveForeignSlowDebuff(int cid, List> statups, MobSkill skill) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMaskSlowD(mplew); - for (Pair statup : statups) { - if(statup.getLeft() == MapleDisease.POISON) mplew.writeShort(statup.getRight().shortValue()); - mplew.writeShort(skill.getSkillId()); - mplew.writeShort(skill.getSkillLevel()); - } - mplew.writeShort(0); // same as give_buff - mplew.writeShort(900);//Delay - return mplew.getPacket(); - } - - public static byte[] cancelForeignSlowDebuff(int cid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMaskSlowD(mplew); - return mplew.getPacket(); - } - - private static void writeLongMaskChair(final MaplePacketLittleEndianWriter mplew) { - mplew.writeInt(0); - mplew.writeInt(262144); - mplew.writeLong(0); - } - - public static byte[] giveForeignChairSkillEffect(int cid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMaskChair(mplew); - - mplew.writeShort(0); - mplew.writeShort(0); - mplew.writeShort(100); - mplew.writeShort(1); - - mplew.writeShort(0); - mplew.writeShort(900); - - for(int i = 0; i < 7; i++) mplew.write(0); - - return mplew.getPacket(); - } - - public static byte[] cancelForeignChairSkillEffect(int cid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); - mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMaskChair(mplew); - - return mplew.getPacket(); - } - - public static byte[] getPlayerShopChat(MapleCharacter c, String chat, boolean owner) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); - mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); - mplew.write(owner ? 0 : 1); - mplew.writeMapleAsciiString(c.getName() + " : " + chat); - return mplew.getPacket(); - } - - public static byte[] getPlayerShopNewVisitor(MapleCharacter c, int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); - mplew.write(slot); - addCharLook(mplew, c, false); - mplew.writeMapleAsciiString(c.getName()); - return mplew.getPacket(); - } - - public static byte[] getPlayerShopRemoveVisitor(int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - if (slot != 0) { - mplew.writeShort(slot); - } - return mplew.getPacket(); - } - - public static byte[] getTradePartnerAdd(MapleCharacter c) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); - mplew.write(1); - addCharLook(mplew, c, false); - mplew.writeMapleAsciiString(c.getName()); - return mplew.getPacket(); - } - - public static byte[] getTradeInvite(MapleCharacter c) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.INVITE.getCode()); - mplew.write(3); - mplew.writeMapleAsciiString(c.getName()); - mplew.write(new byte[]{(byte) 0xB7, (byte) 0x50, 0, 0}); - return mplew.getPacket(); - } - - public static byte[] getTradeMesoSet(byte number, int meso) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.SET_MESO.getCode()); - mplew.write(number); - mplew.writeInt(meso); - return mplew.getPacket(); - } - - public static byte[] getTradeItemAdd(byte number, Item item) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.SET_ITEMS.getCode()); - mplew.write(number); - mplew.write(item.getPosition()); - addItemInfo(mplew, item, true); - return mplew.getPacket(); - } - - public static byte[] getPlayerShopItemUpdate(MaplePlayerShop shop) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.UPDATE_MERCHANT.getCode()); - mplew.write(shop.getItems().size()); - for (MaplePlayerShopItem item : shop.getItems()) { - mplew.writeShort(item.getBundles()); - mplew.writeShort(item.getItem().getQuantity()); - mplew.writeInt(item.getPrice()); - addItemInfo(mplew, item.getItem(), true); - } - return mplew.getPacket(); - } - - public static byte[] getPlayerShopOwnerUpdate(MaplePlayerShop.SoldItem item, int position) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.UPDATE_PLAYERSHOP.getCode()); - mplew.write(position); - mplew.writeShort(item.getQuantity()); - mplew.writeMapleAsciiString(item.getBuyer()); - - return mplew.getPacket(); - } - - /** - * - * @param c - * @param shop - * @param owner - * @return - */ - public static byte[] getPlayerShop(MaplePlayerShop shop, boolean owner) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(4); - mplew.write(4); - mplew.write(owner ? 0 : 1); - - if (owner) { - List sold = shop.getSold(); - mplew.write(sold.size()); - for (MaplePlayerShop.SoldItem s : sold) { - mplew.writeInt(s.getItemId()); - mplew.writeShort(s.getQuantity()); - mplew.writeInt(s.getMesos()); - mplew.writeMapleAsciiString(s.getBuyer()); - } + mplew.writeInt(updateMask); + for (Pair statupdate : mystats) { + if (statupdate.getLeft().getValue() >= 1) { + if (statupdate.getLeft().getValue() == 0x1) { + mplew.writeShort(statupdate.getRight().shortValue()); + } else if (statupdate.getLeft().getValue() <= 0x4) { + mplew.writeInt(statupdate.getRight()); + } else if (statupdate.getLeft().getValue() < 0x20) { + mplew.write(statupdate.getRight().shortValue()); + } else if (statupdate.getLeft().getValue() == 0x8000) { + if (GameConstants.hasSPTable(chr.getJob())) { + addRemainingSkillInfo(mplew, chr); + } else { + mplew.writeShort(statupdate.getRight().shortValue()); + } + } else if (statupdate.getLeft().getValue() < 0xFFFF) { + mplew.writeShort(statupdate.getRight().shortValue()); } else { - mplew.write(0); + mplew.writeInt(statupdate.getRight().intValue()); } - - addCharLook(mplew, shop.getOwner(), false); - mplew.writeMapleAsciiString(shop.getOwner().getName()); - - MapleCharacter visitors[] = shop.getVisitors(); - for(int i = 0; i < 3; i++) { - if(visitors[i] != null) { - mplew.write(i + 1); - addCharLook(mplew, visitors[i], false); - mplew.writeMapleAsciiString(visitors[i].getName()); + } + } + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client to change maps. + * + * @param to The MapleMap to warp to. + * @param spawnPoint The spawn portal number to spawn at. + * @param chr The character warping to to + * @return The map change packet. + */ + public static byte[] getWarpToMap(MapleMap to, int spawnPoint, MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_FIELD.getValue()); + mplew.writeInt(chr.getClient().getChannel() - 1); + mplew.writeInt(0);//updated + mplew.write(0);//updated + mplew.writeInt(to.getId()); + mplew.write(spawnPoint); + mplew.writeShort(chr.getHp()); + mplew.writeBool(false); + mplew.writeLong(getTime(Server.getInstance().getCurrentTime())); + mplew.skip(14); + return mplew.getPacket(); + } + + public static byte[] getWarpToMap(MapleMap to, int spawnPoint, Point spawnPosition, MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_FIELD.getValue()); + mplew.writeInt(chr.getClient().getChannel() - 1); + mplew.writeInt(0);//updated + mplew.write(0);//updated + mplew.writeInt(to.getId()); + mplew.write(spawnPoint); + mplew.writeShort(chr.getHp()); + mplew.writeBool(true); + mplew.writeInt(spawnPosition.x); // spawn position placement thanks to Arnah (Vertisy) + mplew.writeInt(spawnPosition.y); + mplew.writeLong(getTime(Server.getInstance().getCurrentTime())); + mplew.skip(14); + return mplew.getPacket(); + } + + /** + * Gets a packet to spawn a portal. + * + * @param townId The ID of the town the portal goes to. + * @param targetId The ID of the target. + * @param pos Where to put the portal. + * @return The portal spawn packet. + */ + public static byte[] spawnPortal(int townId, int targetId, Point pos) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(14); + mplew.writeShort(SendOpcode.SPAWN_PORTAL.getValue()); + mplew.writeInt(townId); + mplew.writeInt(targetId); + mplew.writePos(pos); + return mplew.getPacket(); + } + + /** + * Gets a packet to spawn a door. + * + * @param ownerid The door's owner ID. + * @param pos The position of the door. + * @param launched Already deployed the door. + * @return The remove door packet. + */ + public static byte[] spawnDoor(int ownerid, Point pos, boolean launched) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); + mplew.writeShort(SendOpcode.SPAWN_DOOR.getValue()); + mplew.writeBool(launched); + mplew.writeInt(ownerid); + mplew.writePos(pos); + return mplew.getPacket(); + } + + /** + * Gets a packet to remove a door. + * + * @param ownerid The door's owner ID. + * @param town + * @return The remove door packet. + */ + public static byte[] removeDoor(int ownerid, boolean town) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(10); + if (town) { + mplew.writeShort(SendOpcode.SPAWN_PORTAL.getValue()); + mplew.writeInt(999999999); + mplew.writeInt(999999999); + } else { + mplew.writeShort(SendOpcode.REMOVE_DOOR.getValue()); + mplew.write(0); + mplew.writeInt(ownerid); + } + return mplew.getPacket(); + } + + /** + * Gets a packet to spawn a special map object. + * + * @param summon + * @param skillLevel The level of the skill used. + * @param animated Animated spawn? + * @return The spawn packet for the map object. + */ + public static byte[] spawnSummon(MapleSummon summon, boolean animated) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(25); + mplew.writeShort(SendOpcode.SPAWN_SPECIAL_MAPOBJECT.getValue()); + mplew.writeInt(summon.getOwner().getId()); + mplew.writeInt(summon.getObjectId()); + mplew.writeInt(summon.getSkill()); + mplew.write(0x0A); //v83 + mplew.write(summon.getSkillLevel()); + mplew.writePos(summon.getPosition()); + mplew.write(summon.getStance()); //bMoveAction & foothold, found thanks to Rien dev team + mplew.writeShort(0); + mplew.write(summon.getMovementType().getValue()); // 0 = don't move, 1 = follow (4th mage summons?), 2/4 = only tele follow, 3 = bird follow + mplew.write(summon.isPuppet() ? 0 : 1); // 0 and the summon can't attack - but puppets don't attack with 1 either ^.- + mplew.write(animated ? 0 : 1); + return mplew.getPacket(); + } + + /** + * Gets a packet to remove a special map object. + * + * @param summon + * @param animated Animated removal? + * @return The packet removing the object. + */ + public static byte[] removeSummon(MapleSummon summon, boolean animated) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); + mplew.writeShort(SendOpcode.REMOVE_SPECIAL_MAPOBJECT.getValue()); + mplew.writeInt(summon.getOwner().getId()); + mplew.writeInt(summon.getObjectId()); + mplew.write(animated ? 4 : 1); // ? + return mplew.getPacket(); + } + + public static byte[] spawnKite(int oid, int itemid, String name, String msg, Point pos, int ft) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_KITE.getValue()); + mplew.writeInt(oid); + mplew.writeInt(itemid); + mplew.writeMapleAsciiString(msg); + mplew.writeMapleAsciiString(name); + mplew.writeShort(pos.x); + mplew.writeShort(ft); + return mplew.getPacket(); + } + + public static byte[] removeKite(int objectid, int animationType) { // thanks to Arnah + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.REMOVE_KITE.getValue()); + mplew.write(animationType); // 0 is 10/10, 1 just vanishes + mplew.writeInt(objectid); + return mplew.getPacket(); + } + + public static byte[] sendCannotSpawnKite() { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANNOT_SPAWN_KITE.getValue()); + return mplew.getPacket(); + } + + /** + * Gets the response to a relog request. + * + * @return The relog response packet. + */ + public static byte[] getRelogResponse() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.RELOG_RESPONSE.getValue()); + mplew.write(1);//1 O.O Must be more types ): + return mplew.getPacket(); + } + + /** + * Gets a server message packet. + * + * @param message The message to convey. + * @return The server message packet. + */ + public static byte[] serverMessage(String message) { + return serverMessage(4, (byte) 0, message, true, false, 0); + } + + /** + * Gets a server notice packet. + * + * Possible values for type:
0: [Notice]
1: Popup
+ * 2: Megaphone
3: Super Megaphone
4: Scrolling message at top
+ * 5: Pink Text
6: Lightblue Text + * + * @param type The type of the notice. + * @param message The message to convey. + * @return The server notice packet. + */ + public static byte[] serverNotice(int type, String message) { + return serverMessage(type, (byte) 0, message, false, false, 0); + } + + /** + * Gets a server notice packet. + * + * Possible values for type:
0: [Notice]
1: Popup
+ * 2: Megaphone
3: Super Megaphone
4: Scrolling message at top
+ * 5: Pink Text
6: Lightblue Text + * + * @param type The type of the notice. + * @param channel The channel this notice was sent on. + * @param message The message to convey. + * @return The server notice packet. + */ + public static byte[] serverNotice(int type, String message, int npc) { + return serverMessage(type, 0, message, false, false, npc); + } + + public static byte[] serverNotice(int type, int channel, String message) { + return serverMessage(type, channel, message, false, false, 0); + } + + public static byte[] serverNotice(int type, int channel, String message, boolean smegaEar) { + return serverMessage(type, channel, message, false, smegaEar, 0); + } + + /** + * Gets a server message packet. + * + * Possible values for type:
0: [Notice]
1: Popup
+ * 2: Megaphone
3: Super Megaphone
4: Scrolling message at top
+ * 5: Pink Text
6: Lightblue Text
7: BroadCasting NPC + * + * @param type The type of the notice. + * @param channel The channel this notice was sent on. + * @param message The message to convey. + * @param servermessage Is this a scrolling ticker? + * @return The server notice packet. + */ + private static byte[] serverMessage(int type, int channel, String message, boolean servermessage, boolean megaEar, int npc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); + mplew.write(type); + if (servermessage) { + mplew.write(1); + } + mplew.writeMapleAsciiString(message); + if (type == 3) { + mplew.write(channel - 1); // channel + mplew.writeBool(megaEar); + } else if (type == 6) { + mplew.writeInt(0); + } else if (type == 7) { // npc + mplew.writeInt(npc); + } + return mplew.getPacket(); + } + + /** + * Sends a Avatar Super Megaphone packet. + * + * @param chr The character name. + * @param medal The medal text. + * @param channel Which channel. + * @param itemId Which item used. + * @param message The message sent. + * @param ear Whether or not the ear is shown for whisper. + * @return + */ + public static byte[] getAvatarMega(MapleCharacter chr, String medal, int channel, int itemId, List message, boolean ear) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_AVATAR_MEGAPHONE.getValue()); + mplew.writeInt(itemId); + mplew.writeMapleAsciiString(medal + chr.getName()); + for (String s : message) { + mplew.writeMapleAsciiString(s); + } + mplew.writeInt(channel - 1); // channel + mplew.writeBool(ear); + addCharLook(mplew, chr, true); + return mplew.getPacket(); + } + + /* + * Sends a packet to remove the tiger megaphone + * @return + */ + public static byte[] byeAvatarMega() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CLEAR_AVATAR_MEGAPHONE.getValue()); + mplew.write(1); + return mplew.getPacket(); + } + + /** + * Sends the Gachapon green message when a user uses a gachapon ticket. + * + * @param item + * @param town + * @param player + * @return + */ + public static byte[] gachaponMessage(Item item, String town, MapleCharacter player) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); + mplew.write(0x0B); + mplew.writeMapleAsciiString(player.getName() + " : got a(n)"); + mplew.writeInt(0); //random? + mplew.writeMapleAsciiString(town); + addItemInfo(mplew, item, true); + return mplew.getPacket(); + } + + public static byte[] spawnNPC(MapleNPC life) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(24); + mplew.writeShort(SendOpcode.SPAWN_NPC.getValue()); + mplew.writeInt(life.getObjectId()); + mplew.writeInt(life.getId()); + mplew.writeShort(life.getPosition().x); + mplew.writeShort(life.getCy()); + if (life.getF() == 1) { + mplew.write(0); + } else { + mplew.write(1); + } + mplew.writeShort(life.getFh()); + mplew.writeShort(life.getRx0()); + mplew.writeShort(life.getRx1()); + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] spawnNPCRequestController(MapleNPC life, boolean MiniMap) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(23); + mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue()); + mplew.write(1); + mplew.writeInt(life.getObjectId()); + mplew.writeInt(life.getId()); + mplew.writeShort(life.getPosition().x); + mplew.writeShort(life.getCy()); + if (life.getF() == 1) { + mplew.write(0); + } else { + mplew.write(1); + } + mplew.writeShort(life.getFh()); + mplew.writeShort(life.getRx0()); + mplew.writeShort(life.getRx1()); + mplew.writeBool(MiniMap); + return mplew.getPacket(); + } + + /** + * Gets a spawn monster packet. + * + * @param life The monster to spawn. + * @param newSpawn Is it a new spawn? + * @return The spawn monster packet. + */ + public static byte[] spawnMonster(MapleMonster life, boolean newSpawn) { + return spawnMonsterInternal(life, false, newSpawn, false, 0, false); + } + + /** + * Gets a spawn monster packet. + * + * @param life The monster to spawn. + * @param newSpawn Is it a new spawn? + * @param effect The spawn effect. + * @return The spawn monster packet. + */ + public static byte[] spawnMonster(MapleMonster life, boolean newSpawn, int effect) { + return spawnMonsterInternal(life, false, newSpawn, false, effect, false); + } + + /** + * Gets a control monster packet. + * + * @param life The monster to give control to. + * @param newSpawn Is it a new spawn? + * @param aggro Aggressive monster? + * @return The monster control packet. + */ + public static byte[] controlMonster(MapleMonster life, boolean newSpawn, boolean aggro) { + return spawnMonsterInternal(life, true, newSpawn, aggro, 0, false); + } + + /** + * Removes a monster invisibility. + * + * @param life + * @return + */ + public static byte[] removeMonsterInvisibility(MapleMonster life) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); + mplew.write(1); + mplew.writeInt(life.getObjectId()); + return mplew.getPacket(); + } + + /** + * Makes a monster invisible for Ariant PQ. + * + * @param life + * @return + */ + public static byte[] makeMonsterInvisible(MapleMonster life) { + return spawnMonsterInternal(life, true, false, false, 0, true); + } + + private static void encodeParentlessMobSpawnEffect(MaplePacketLittleEndianWriter mplew, boolean newSpawn, int effect) { + if (effect > 0) { + mplew.write(effect); + mplew.write(0); + mplew.writeShort(0); + if (effect == 15) { + mplew.write(0); + } + } + mplew.write(newSpawn ? -2 : -1); + } + + /** + * Internal function to handler monster spawning and controlling. + * + * @param life The mob to perform operations with. + * @param requestController Requesting control of mob? + * @param newSpawn New spawn (fade in?) + * @param aggro Aggressive mob? + * @param effect The spawn effect to use. + * @return The spawn/control packet. + */ + private static byte[] spawnMonsterInternal(MapleMonster life, boolean requestController, boolean newSpawn, boolean aggro, int effect, boolean makeInvis) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + if (makeInvis) { + mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); + mplew.write(0); + mplew.writeInt(life.getObjectId()); + return mplew.getPacket(); + } + if (requestController) { + mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); + mplew.write(aggro ? 2 : 1); + } else { + mplew.writeShort(SendOpcode.SPAWN_MONSTER.getValue()); + } + mplew.writeInt(life.getObjectId()); + mplew.write(life.getController() == null ? 5 : 1); + mplew.writeInt(life.getId()); + mplew.skip(15); + mplew.write(0x88); + mplew.skip(6); + mplew.writePos(life.getPosition()); + mplew.write(life.getStance()); + mplew.writeShort(0); //Origin FH //life.getStartFh() + mplew.writeShort(life.getFh()); + + /** + * -4: Fake -3: Appear after linked mob is dead -2: Fade in 1: Smoke 3: + * King Slime spawn 4: Summoning rock thing, used for 3rd job? 6: + * Magical shit 7: Smoke shit 8: 'The Boss' 9/10: Grim phantom shit? + * 11/12: Nothing? 13: Frankenstein 14: Angry ^ 15: Orb animation thing, + * ?? 16: ?? 19: Mushroom castle boss thing + */ + if (life.getParentMobOid() != 0) { + MapleMonster parentMob = life.getMap().getMonsterByOid(life.getParentMobOid()); + if (parentMob != null && parentMob.isAlive()) { + mplew.write(effect != 0 ? effect : -3); + mplew.writeInt(life.getParentMobOid()); + } else { + encodeParentlessMobSpawnEffect(mplew, newSpawn, effect); + } + } else { + encodeParentlessMobSpawnEffect(mplew, newSpawn, effect); + } + + mplew.write(life.getTeam()); + mplew.writeInt(0); // getItemEffect + return mplew.getPacket(); + } + + /** + * Handles monsters not being targettable, such as Zakum's first body. + * + * @param life The mob to spawn as non-targettable. + * @param effect The effect to show when spawning. + * @return The packet to spawn the mob as non-targettable. + */ + public static byte[] spawnFakeMonster(MapleMonster life, int effect) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); + mplew.write(1); + mplew.writeInt(life.getObjectId()); + mplew.write(5); + mplew.writeInt(life.getId()); + mplew.skip(15); + mplew.write(0x88); + mplew.skip(6); + mplew.writePos(life.getPosition()); + mplew.write(life.getStance()); + mplew.writeShort(0);//life.getStartFh() + mplew.writeShort(life.getFh()); + if (effect > 0) { + mplew.write(effect); + mplew.write(0); + mplew.writeShort(0); + } + mplew.writeShort(-2); + mplew.write(life.getTeam()); + mplew.writeInt(0); + return mplew.getPacket(); + } + + /** + * Makes a monster previously spawned as non-targettable, targettable. + * + * @param life The mob to make targettable. + * @return The packet to make the mob targettable. + */ + public static byte[] makeMonsterReal(MapleMonster life) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_MONSTER.getValue()); + mplew.writeInt(life.getObjectId()); + mplew.write(5); + mplew.writeInt(life.getId()); + mplew.skip(15); + mplew.write(0x88); + mplew.skip(6); + mplew.writePos(life.getPosition()); + mplew.write(life.getStance()); + mplew.writeShort(0);//life.getStartFh() + mplew.writeShort(life.getFh()); + mplew.writeShort(-1); + mplew.writeInt(0); + return mplew.getPacket(); + } + + /** + * Gets a stop control monster packet. + * + * @param oid The ObjectID of the monster to stop controlling. + * @return The stop control monster packet. + */ + public static byte[] stopControllingMonster(int oid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue()); + mplew.write(0); + mplew.writeInt(oid); + return mplew.getPacket(); + } + + /** + * Gets a response to a move monster packet. + * + * @param objectid The ObjectID of the monster being moved. + * @param moveid The movement ID. + * @param currentMp The current MP of the monster. + * @param useSkills Can the monster use skills? + * @return The move response packet. + */ + public static byte[] moveMonsterResponse(int objectid, short moveid, int currentMp, boolean useSkills) { + return moveMonsterResponse(objectid, moveid, currentMp, useSkills, 0, 0); + } + + /** + * Gets a response to a move monster packet. + * + * @param objectid The ObjectID of the monster being moved. + * @param moveid The movement ID. + * @param currentMp The current MP of the monster. + * @param useSkills Can the monster use skills? + * @param skillId The skill ID for the monster to use. + * @param skillLevel The level of the skill to use. + * @return The move response packet. + */ + public static byte[] moveMonsterResponse(int objectid, short moveid, int currentMp, boolean useSkills, int skillId, int skillLevel) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(13); + mplew.writeShort(SendOpcode.MOVE_MONSTER_RESPONSE.getValue()); + mplew.writeInt(objectid); + mplew.writeShort(moveid); + mplew.writeBool(useSkills); + mplew.writeShort(currentMp); + mplew.write(skillId); + mplew.write(skillLevel); + return mplew.getPacket(); + } + + /** + * Gets a general chat packet. + * + * @param cidfrom The character ID who sent the chat. + * @param text The text of the chat. + * @param whiteBG + * @param show + * @return The general chat packet. + */ + public static byte[] getChatText(int cidfrom, String text, boolean gm, int show) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CHATTEXT.getValue()); + mplew.writeInt(cidfrom); + mplew.writeBool(gm); + mplew.writeMapleAsciiString(text); + mplew.write(show); + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client to show an EXP increase. + * + * @param gain The amount of EXP gained. + * @param inChat In the chat box? + * @param white White text or yellow? + * @return The exp gained packet. + */ + public static byte[] getShowExpGain(int gain, int equip, int party, boolean inChat, boolean white) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(3); // 3 = exp, 4 = fame, 5 = mesos, 6 = guildpoints + mplew.writeBool(white); + mplew.writeInt(gain); + mplew.writeBool(inChat); + mplew.writeInt(0); // monster book bonus (Bonus Event Exp) + mplew.write(0); // third monster kill event + mplew.write(0); // RIP byte, this is always a 0 + mplew.writeInt(0); //wedding bonus + if (inChat) { // quest bonus rate stuff + mplew.write(0); + } + + int mod = ServerConstants.PARTY_EXPERIENCE_MOD != 1 ? ServerConstants.PARTY_EXPERIENCE_MOD * 100 : 0; + + mplew.write(mod); //0 = party bonus, 100 = 1x Bonus EXP, 200 = 2x Bonus EXP + mplew.writeInt(party); // party bonus + mplew.writeInt(equip); //equip bonus + mplew.writeInt(0); //Internet Cafe Bonus + mplew.writeInt(0); //Rainbow Week Bonus + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client to show a fame gain. + * + * @param gain How many fame gained. + * @return The meso gain packet. + */ + public static byte[] getShowFameGain(int gain) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(4); + mplew.writeInt(gain); + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client to show a meso gain. + * + * @param gain How many mesos gained. + * @return The meso gain packet. + */ + public static byte[] getShowMesoGain(int gain) { + return getShowMesoGain(gain, false); + } + + /** + * Gets a packet telling the client to show a meso gain. + * + * @param gain How many mesos gained. + * @param inChat Show in the chat window? + * @return The meso gain packet. + */ + public static byte[] getShowMesoGain(int gain, boolean inChat) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + if (!inChat) { + mplew.write(0); + mplew.writeShort(1); //v83 + } else { + mplew.write(5); + } + mplew.writeInt(gain); + mplew.writeShort(0); + return mplew.getPacket(); + } + + /** + * Gets a packet telling the client to show a item gain. + * + * @param itemId The ID of the item gained. + * @param quantity How many items gained. + * @return The item gain packet. + */ + public static byte[] getShowItemGain(int itemId, short quantity) { + return getShowItemGain(itemId, quantity, false); + } + + /** + * Gets a packet telling the client to show an item gain. + * + * @param itemId The ID of the item gained. + * @param quantity The number of items gained. + * @param inChat Show in the chat window? + * @return The item gain packet. + */ + public static byte[] getShowItemGain(int itemId, short quantity, boolean inChat) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + if (inChat) { + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(3); + mplew.write(1); + mplew.writeInt(itemId); + mplew.writeInt(quantity); + } else { + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.writeShort(0); + mplew.writeInt(itemId); + mplew.writeInt(quantity); + mplew.writeInt(0); + mplew.writeInt(0); + } + return mplew.getPacket(); + } + + public static byte[] killMonster(int oid, boolean animation) { + return killMonster(oid, animation ? 1 : 0); + } + + /** + * Gets a packet telling the client that a monster was killed. + * + * @param oid The objectID of the killed monster. + * @param animation 0 = dissapear, 1 = fade out, 2+ = special + * @return The kill monster packet. + */ + public static byte[] killMonster(int oid, int animation) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.KILL_MONSTER.getValue()); + mplew.writeInt(oid); + mplew.write(animation); + mplew.write(animation); + return mplew.getPacket(); + } + + public static byte[] updateMapItemObject(MapleMapItem drop, boolean giveOwnership) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DROP_ITEM_FROM_MAPOBJECT.getValue()); + mplew.write(2); + mplew.writeInt(drop.getObjectId()); + mplew.writeBool(drop.getMeso() > 0); + mplew.writeInt(drop.getItemId()); + mplew.writeInt(giveOwnership ? 0 : -1); + mplew.write(drop.getDropType()); + mplew.writePos(drop.getPosition()); + mplew.writeInt(giveOwnership ? 0 : -1); + + if (drop.getMeso() == 0) { + addExpirationTime(mplew, drop.getItem().getExpiration()); + } + mplew.write(drop.isPlayerDrop() ? 0 : 1); + return mplew.getPacket(); + } + + public static byte[] dropItemFromMapObject(boolean recvrInParty, MapleMapItem drop, Point dropfrom, Point dropto, byte mod) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DROP_ITEM_FROM_MAPOBJECT.getValue()); + mplew.write(mod); + mplew.writeInt(drop.getObjectId()); + mplew.writeBool(drop.getMeso() > 0); // 1 mesos, 0 item, 2 and above all item meso bag, + mplew.writeInt(drop.getItemId()); // drop object ID + mplew.writeInt(!drop.isFFADrop() ? (recvrInParty ? drop.getPartyOwnerId() : drop.getOwnerId()) : 0); // owner charid/partyid :) + mplew.write(drop.getDropType()); // 0 = timeout for non-owner, 1 = timeout for non-owner's party, 2 = FFA, 3 = explosive/FFA + mplew.writePos(dropto); + mplew.writeInt(drop.getDropper().getObjectId()); // dropper oid, found thanks to Li Jixue + + if (mod != 2) { + mplew.writePos(dropfrom); + mplew.writeShort(0);//Fh? + } + if (drop.getMeso() == 0) { + addExpirationTime(mplew, drop.getItem().getExpiration()); + } + mplew.write(drop.isPlayerDrop() ? 0 : 1); //pet EQP pickup + return mplew.getPacket(); + } + + /** + * Guild Name & Mark update packet, thanks to Arnah (Vertisy) + * + * @param guildName The Guild name, blank for nothing. + */ + public static byte[] guildNameChanged(int chrid, String guildName) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_NAME_CHANGED.getValue()); + mplew.writeInt(chrid); + mplew.writeMapleAsciiString(guildName); + return mplew.getPacket(); + } + + public static byte[] guildMarkChanged(int chrid, MapleGuild guild) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_MARK_CHANGED.getValue()); + mplew.writeInt(chrid); + mplew.writeShort(guild.getLogoBG()); + mplew.write(guild.getLogoBGColor()); + mplew.writeShort(guild.getLogo()); + mplew.write(guild.getLogoColor()); + return mplew.getPacket(); + } + + /** + * Gets a packet spawning a player as a mapobject to other clients. + * + * @param target The client receiving this packet. + * @param chr The character to spawn to other clients. + * @param enteringField Whether the character to spawn is not yet present in + * the map or already is. + * @return The spawn player packet. + */ + public static byte[] spawnPlayerMapObject(MapleClient target, MapleCharacter chr, boolean enteringField) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_PLAYER.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(chr.getLevel()); //v83 + mplew.writeMapleAsciiString(chr.getName()); + if (chr.getGuildId() < 1) { + mplew.writeMapleAsciiString(""); + mplew.write(new byte[6]); + } else { + MapleGuildSummary gs = chr.getClient().getWorldServer().getGuildSummary(chr.getGuildId(), chr.getWorld()); + if (gs != null) { + mplew.writeMapleAsciiString(gs.getName()); + mplew.writeShort(gs.getLogoBG()); + mplew.write(gs.getLogoBGColor()); + mplew.writeShort(gs.getLogo()); + mplew.write(gs.getLogoColor()); + } else { + mplew.writeMapleAsciiString(""); + mplew.write(new byte[6]); + } + } + mplew.writeInt(0); + mplew.writeShort(0); //v83 + mplew.write(0xFC); + mplew.write(1); + if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { + mplew.writeInt(2); + } else { + mplew.writeInt(0); + } + long buffmask = 0; + Integer buffvalue = null; + if (chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && !chr.isHidden()) { + buffmask |= MapleBuffStat.DARKSIGHT.getValue(); + } + if (chr.getBuffedValue(MapleBuffStat.COMBO) != null) { + buffmask |= MapleBuffStat.COMBO.getValue(); + buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.COMBO).intValue()); + } + if (chr.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) { + buffmask |= MapleBuffStat.SHADOWPARTNER.getValue(); + } + if (chr.getBuffedValue(MapleBuffStat.SOULARROW) != null) { + buffmask |= MapleBuffStat.SOULARROW.getValue(); + } + if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { + buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.MORPH).intValue()); + } + if (chr.getBuffedValue(MapleBuffStat.ENERGY_CHARGE) != null) { + buffmask |= MapleBuffStat.ENERGY_CHARGE.getValue(); + buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.ENERGY_CHARGE).intValue()); + }//AREN'T THESE + mplew.writeInt((int) ((buffmask >> 32) & 0xffffffffL)); + if (buffvalue != null) { + if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { //TEST + mplew.writeShort(buffvalue); + } else { + mplew.write(buffvalue.byteValue()); + } + } + mplew.writeInt((int) (buffmask & 0xffffffffL)); + int CHAR_MAGIC_SPAWN = Randomizer.nextInt(); + mplew.skip(6); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.skip(11); + mplew.writeInt(CHAR_MAGIC_SPAWN);//v74 + mplew.skip(11); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.writeShort(0); + mplew.write(0); + + Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING); + if (bv != null) { + if (bv.equals(Corsair.BATTLE_SHIP)) { + mplew.writeInt(1932000); + mplew.writeInt(Corsair.BATTLE_SHIP); + } else { + final Item mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18); + if (mount != null) { + mplew.writeInt(mount.getItemId()); + mplew.writeInt(1004); + } else { + mplew.writeLong(0); + } + } + } else { + mplew.writeLong(0); + } + + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.skip(9); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.writeShort(0); + mplew.writeInt(0); // actually not 0, why is it 0 then? + mplew.skip(10); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.skip(13); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.writeShort(0); + mplew.write(0); + + mplew.writeShort(chr.getJob().getId()); + + /* replace "mplew.writeShort(chr.getJob().getId())" with this snippet for 3rd person FJ animation on all classes + if (chr.getJob().isA(MapleJob.HERMIT) || chr.getJob().isA(MapleJob.DAWNWARRIOR2) || chr.getJob().isA(MapleJob.NIGHTWALKER2)) { + mplew.writeShort(chr.getJob().getId()); + } else { + mplew.writeShort(412); + }*/ + addCharLook(mplew, chr, false); + mplew.writeInt(chr.getInventory(MapleInventoryType.CASH).countById(5110000)); + mplew.writeInt(chr.getItemEffect()); + mplew.writeInt(ItemConstants.getInventoryType(chr.getChair()) == MapleInventoryType.SETUP ? chr.getChair() : 0); + + if (enteringField) { + Point spawnPos = new Point(chr.getPosition()); + spawnPos.y -= 42; + mplew.writePos(spawnPos); + mplew.write(6); + } else { + mplew.writePos(chr.getPosition()); + mplew.write(chr.getStance()); + } + + mplew.writeShort(0);//chr.getFh() + mplew.write(0); + MaplePet[] pet = chr.getPets(); + for (int i = 0; i < 3; i++) { + if (pet[i] != null) { + addPetInfo(mplew, pet[i], false); + } + } + mplew.write(0); //end of pets + if (chr.getMount() == null) { + mplew.writeInt(1); // mob level + mplew.writeLong(0); // mob exp + tiredness + } else { + mplew.writeInt(chr.getMount().getLevel()); + mplew.writeInt(chr.getMount().getExp()); + mplew.writeInt(chr.getMount().getTiredness()); + } + + MaplePlayerShop mps = chr.getPlayerShop(); + if (mps != null && mps.isOwner(chr)) { + if (mps.hasFreeSlot()) { + addAnnounceBox(mplew, mps, mps.getVisitors().length); + } else { + addAnnounceBox(mplew, mps, 1); + } + } else { + MapleMiniGame miniGame = chr.getMiniGame(); + if (miniGame != null && miniGame.isOwner(chr)) { + if (miniGame.hasFreeSlot()) { + addAnnounceBox(mplew, miniGame, 1, 0); + } else { + addAnnounceBox(mplew, miniGame, 2, miniGame.isMatchInProgress() ? 1 : 0); + } + } else { + mplew.write(0); + } + } + + if (chr.getChalkboard() != null) { + mplew.write(1); + mplew.writeMapleAsciiString(chr.getChalkboard()); + } else { + mplew.write(0); + } + addRingLook(mplew, chr, true); // crush + addRingLook(mplew, chr, false); // friendship + addMarriageRingLook(target, mplew, chr); + encodeNewYearCardInfo(mplew, chr); // new year seems to crash sometimes... + mplew.skip(2); + mplew.write(chr.getTeam());//only needed in specific fields + return mplew.getPacket(); + } + + private static void encodeNewYearCardInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + Set newyears = chr.getReceivedNewYearRecords(); + if (!newyears.isEmpty()) { + mplew.write(1); + + mplew.writeInt(newyears.size()); + for (NewYearCardRecord nyc : newyears) { + mplew.writeInt(nyc.getId()); + } + } else { + mplew.write(0); + } + } + + public static byte[] onNewYearCardRes(MapleCharacter user, int cardId, int mode, int msg) { + NewYearCardRecord newyear = user.getNewYearRecord(cardId); + return onNewYearCardRes(user, newyear, mode, msg); + } + + public static byte[] onNewYearCardRes(MapleCharacter user, NewYearCardRecord newyear, int mode, int msg) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NEW_YEAR_CARD_RES.getValue()); + mplew.write(mode); + switch (mode) { + case 4: // Successfully sent a New Year Card\r\n to %s. + case 6: // Successfully received a New Year Card. + encodeNewYearCard(newyear, mplew); + break; + + case 8: // Successfully deleted a New Year Card. + mplew.writeInt(newyear.getId()); + break; + + case 5: // Nexon's stupid and makes 4 modes do the same operation.. + case 7: + case 9: + case 0xB: + // 0x10: You have no free slot to store card.\r\ntry later on please. + // 0x11: You have no card to send. + // 0x12: Wrong inventory information ! + // 0x13: Cannot find such character ! + // 0x14: Incoherent Data ! + // 0x15: An error occured during DB operation. + // 0x16: An unknown error occured ! + // 0xF: You cannot send a card to yourself ! + mplew.write(msg); + break; + + case 0xA: // GetUnreceivedList_Done + int nSN = 1; + mplew.writeInt(nSN); + if ((nSN - 1) <= 98 && nSN > 0) {//lol nexon are you kidding + for (int i = 0; i < nSN; i++) { + mplew.writeInt(newyear.getId()); + mplew.writeInt(newyear.getSenderId()); + mplew.writeMapleAsciiString(newyear.getSenderName()); } } - - mplew.write(0xFF); - mplew.writeMapleAsciiString(shop.getDescription()); - List items = shop.getItems(); - mplew.write(0x10); //TODO SLOTS, which is 16 for most stores...slotMax - mplew.write(items.size()); - for (MaplePlayerShopItem item : items) { - mplew.writeShort(item.getBundles()); - mplew.writeShort(item.getItem().getQuantity()); - mplew.writeInt(item.getPrice()); - addItemInfo(mplew, item.getItem(), true); + break; + + case 0xC: // NotiArrived + mplew.writeInt(newyear.getId()); + mplew.writeMapleAsciiString(newyear.getSenderName()); + break; + + case 0xD: // BroadCast_AddCardInfo + mplew.writeInt(newyear.getId()); + mplew.writeInt(user.getId()); + break; + + case 0xE: // BroadCast_RemoveCardInfo + mplew.writeInt(newyear.getId()); + break; + } + return mplew.getPacket(); + } + + private static void encodeNewYearCard(NewYearCardRecord newyear, MaplePacketLittleEndianWriter mplew) { + mplew.writeInt(newyear.getId()); + mplew.writeInt(newyear.getSenderId()); + mplew.writeMapleAsciiString(newyear.getSenderName()); + mplew.writeBool(newyear.isSenderCardDiscarded()); + mplew.writeLong(newyear.getDateSent()); + mplew.writeInt(newyear.getReceiverId()); + mplew.writeMapleAsciiString(newyear.getReceiverName()); + mplew.writeBool(newyear.isReceiverCardDiscarded()); + mplew.writeBool(newyear.isReceiverCardReceived()); + mplew.writeLong(newyear.getDateReceived()); + mplew.writeMapleAsciiString(newyear.getMessage()); + } + + private static void addRingLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean crush) { + List rings; + if (crush) { + rings = chr.getCrushRings(); + } else { + rings = chr.getFriendshipRings(); + } + boolean yes = false; + for (MapleRing ring : rings) { + if (ring.equipped()) { + if (yes == false) { + yes = true; + mplew.write(1); } - return mplew.getPacket(); - } - - public static byte[] getTradeStart(MapleClient c, MapleTrade trade, byte number) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(3); - mplew.write(2); - mplew.write(number); - if (number == 1) { - mplew.write(0); - addCharLook(mplew, trade.getPartner().getChr(), false); - mplew.writeMapleAsciiString(trade.getPartner().getChr().getName()); - } - mplew.write(number); - addCharLook(mplew, c.getPlayer(), false); - mplew.writeMapleAsciiString(c.getPlayer().getName()); - mplew.write(0xFF); - return mplew.getPacket(); - } - - public static byte[] getTradeConfirmation() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.CONFIRM.getCode()); - return mplew.getPacket(); - } - - public static byte[] getTradeCompletion(byte number) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - mplew.write(number); - mplew.write(6); - return mplew.getPacket(); - } - - public static byte[] getTradeCancel(byte number) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - mplew.write(number); - mplew.write(2); - return mplew.getPacket(); - } - - /** - * Possible values for speaker:
0: Npc talking (left)
- * 1: Npc talking (right)
2: Player talking (left)
3: Player talking - * (left)
- * - * @param npc Npcid - * @param msgType - * @param talk - * @param endBytes - * @param speaker - * @return - */ - public static byte[] getNPCTalk(int npc, byte msgType, String talk, String endBytes, byte speaker) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NPC_TALK.getValue()); - mplew.write(4); // ? - mplew.writeInt(npc); - mplew.write(msgType); - mplew.write(speaker); - mplew.writeMapleAsciiString(talk); - mplew.write(HexTool.getByteArrayFromHexString(endBytes)); - return mplew.getPacket(); - } - - public static byte[] getDimensionalMirror(String talk) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NPC_TALK.getValue()); - mplew.write(4); // ? - mplew.writeInt(9010022); - mplew.write(0x0E); - mplew.write(0); + mplew.writeInt(ring.getRingId()); mplew.writeInt(0); - mplew.writeMapleAsciiString(talk); - return mplew.getPacket(); - } - - public static byte[] getNPCTalkStyle(int npc, String talk, int styles[]) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NPC_TALK.getValue()); - mplew.write(4); // ? - mplew.writeInt(npc); - mplew.write(7); - mplew.write(0); //speaker - mplew.writeMapleAsciiString(talk); - mplew.write(styles.length); - for (int i = 0; i < styles.length; i++) { - mplew.writeInt(styles[i]); - } - return mplew.getPacket(); - } - - public static byte[] getNPCTalkNum(int npc, String talk, int def, int min, int max) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NPC_TALK.getValue()); - mplew.write(4); // ? - mplew.writeInt(npc); - mplew.write(3); - mplew.write(0); //speaker - mplew.writeMapleAsciiString(talk); - mplew.writeInt(def); - mplew.writeInt(min); - mplew.writeInt(max); + mplew.writeInt(ring.getPartnerRingId()); mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] getNPCTalkText(int npc, String talk, String def) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NPC_TALK.getValue()); - mplew.write(4); // Doesn't matter - mplew.writeInt(npc); - mplew.write(2); - mplew.write(0); //speaker - mplew.writeMapleAsciiString(talk); - mplew.writeMapleAsciiString(def);//:D - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] showBuffeffect(int cid, int skillid, int effectid) { - return showBuffeffect(cid, skillid, effectid, (byte) 3); - } - - public static byte[] showBuffeffect(int cid, int skillid, int effectid, byte direction) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(effectid); //buff level - mplew.writeInt(skillid); - mplew.write(direction); - mplew.write(1); - mplew.writeLong(0); - return mplew.getPacket(); - } - - public static byte[] showBuffeffect(int cid, int skillid, int skilllv, int effectid, byte direction) { // updated packet structure found thanks to Rien dev team - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(effectid); - mplew.writeInt(skillid); - mplew.write(0); - mplew.write(skilllv); - mplew.write(direction); - - return mplew.getPacket(); - } - - public static byte[] showOwnBuffEffect(int skillid, int effectid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(effectid); - mplew.writeInt(skillid); - mplew.write(0xA9); - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] showOwnBerserk(int skilllevel, boolean Berserk) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(1); - mplew.writeInt(1320006); - mplew.write(0xA9); - mplew.write(skilllevel); - mplew.write(Berserk ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] showBerserk(int cid, int skilllevel, boolean Berserk) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(1); - mplew.writeInt(1320006); - mplew.write(0xA9); - mplew.write(skilllevel); - mplew.write(Berserk ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] updateSkill(int skillid, int level, int masterlevel, long expiration) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_SKILLS.getValue()); - mplew.write(1); - mplew.writeShort(1); - mplew.writeInt(skillid); - mplew.writeInt(level); - mplew.writeInt(masterlevel); - addExpirationTime(mplew, expiration); - mplew.write(4); - return mplew.getPacket(); - } - - public static byte[] getShowQuestCompletion(int id) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.QUEST_CLEAR.getValue()); - mplew.writeShort(id); - return mplew.getPacket(); - } - - public static byte[] getKeymap(Map keybindings) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.KEYMAP.getValue()); - mplew.write(0); - for (int x = 0; x < 90; x++) { - MapleKeyBinding binding = keybindings.get(Integer.valueOf(x)); - if (binding != null) { - mplew.write(binding.getType()); - mplew.writeInt(binding.getAction()); - } else { - mplew.write(0); - mplew.writeInt(0); - } - } - return mplew.getPacket(); - } - - public static byte[] getWhisper(String sender, int channel, String text) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.WHISPER.getValue()); - mplew.write(0x12); - mplew.writeMapleAsciiString(sender); - mplew.writeShort(channel - 1); // I guess this is the channel - mplew.writeMapleAsciiString(text); - return mplew.getPacket(); - } - - /** - * - * @param target name of the target character - * @param reply error code: 0x0 = cannot find char, 0x1 = success - * @return the MaplePacket - */ - public static byte[] getWhisperReply(String target, byte reply) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.WHISPER.getValue()); - mplew.write(0x0A); // whisper? - mplew.writeMapleAsciiString(target); - mplew.write(reply); - return mplew.getPacket(); - } - - public static byte[] getInventoryFull() { - return modifyInventory(true, Collections.emptyList()); - } - - public static byte[] getShowInventoryFull() { - return getShowInventoryStatus(0xff); - } - - public static byte[] showItemUnavailable() { - return getShowInventoryStatus(0xfe); - } - - public static byte[] getShowInventoryStatus(int mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(0); - mplew.write(mode); - mplew.writeInt(0); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] getStorage(int npcId, byte slots, Collection items, int meso) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STORAGE.getValue()); - mplew.write(0x16); - mplew.writeInt(npcId); - mplew.write(slots); - mplew.writeShort(0x7E); - mplew.writeShort(0); - mplew.writeInt(0); - mplew.writeInt(meso); - mplew.writeShort(0); - mplew.write((byte) items.size()); - for (Item item : items) { - addItemInfo(mplew, item, true); - } - mplew.writeShort(0); - mplew.write(0); - return mplew.getPacket(); - } - - /* - * 0x0A = Inv full - * 0x0B = You do not have enough mesos - * 0x0C = One-Of-A-Kind error - */ - public static byte[] getStorageError(byte i) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STORAGE.getValue()); - mplew.write(i); - return mplew.getPacket(); - } - - public static byte[] mesoStorage(byte slots, int meso) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STORAGE.getValue()); - mplew.write(0x13); - mplew.write(slots); - mplew.writeShort(2); - mplew.writeShort(0); - mplew.writeInt(0); - mplew.writeInt(meso); - return mplew.getPacket(); - } - - public static byte[] storeStorage(byte slots, MapleInventoryType type, Collection items) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STORAGE.getValue()); - mplew.write(0xD); - mplew.write(slots); - mplew.writeShort(type.getBitfieldEncoding()); - mplew.writeShort(0); - mplew.writeInt(0); - mplew.write(items.size()); - for (Item item : items) { - addItemInfo(mplew, item, true); - } - return mplew.getPacket(); - } - - public static byte[] takeOutStorage(byte slots, MapleInventoryType type, Collection items) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STORAGE.getValue()); - mplew.write(0x9); - mplew.write(slots); - mplew.writeShort(type.getBitfieldEncoding()); - mplew.writeShort(0); - mplew.writeInt(0); - mplew.write(items.size()); - for (Item item : items) { - addItemInfo(mplew, item, true); - } - return mplew.getPacket(); - } - - public static byte[] arrangeStorage(byte slots, Collection items) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - - mplew.writeShort(SendOpcode.STORAGE.getValue()); - mplew.write(0xF); - mplew.write(slots); - mplew.write(124); - for(byte i = 0; i < 10; i++) mplew.write(0); - mplew.write(items.size()); - for (Item item : items) { - addItemInfo(mplew, item, true); - } - mplew.write(0); - return mplew.getPacket(); - } - - /** - * - * @param oid - * @param remhppercentage - * @return - */ - public static byte[] showMonsterHP(int oid, int remhppercentage) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_MONSTER_HP.getValue()); - mplew.writeInt(oid); - mplew.write(remhppercentage); - return mplew.getPacket(); - } - - public static byte[] showBossHP(int oid, int currHP, int maxHP, byte tagColor, byte tagBgColor) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(5); - mplew.writeInt(oid); - mplew.writeInt(currHP); - mplew.writeInt(maxHP); - mplew.write(tagColor); - mplew.write(tagBgColor); - return mplew.getPacket(); - } - - private static Pair normalizedCustomMaxHP(long currHP, long maxHP) { - int sendHP, sendMaxHP; - - if(maxHP <= Integer.MAX_VALUE) { - sendHP = (int) currHP; - sendMaxHP = (int) maxHP; - } else { - float f = ((float) currHP) / maxHP; - - sendHP = (int) (Integer.MAX_VALUE * f); - sendMaxHP = Integer.MAX_VALUE; - } - - return new Pair<>(sendHP, sendMaxHP); - } - - public static byte[] customShowBossHP(byte call, int oid, long currHP, long maxHP, byte tagColor, byte tagBgColor) { - Pair customHP = normalizedCustomMaxHP(currHP, maxHP); - - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(call); - mplew.writeInt(oid); - mplew.writeInt(customHP.left); - mplew.writeInt(customHP.right); - mplew.write(tagColor); - mplew.write(tagBgColor); - return mplew.getPacket(); - } - - public static byte[] giveFameResponse(int mode, String charname, int newfame) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue()); - mplew.write(0); - mplew.writeMapleAsciiString(charname); - mplew.write(mode); - mplew.writeShort(newfame); - mplew.writeShort(0); - return mplew.getPacket(); - } - - /** - * status can be:
0: ok, use giveFameResponse
1: the username is - * incorrectly entered
2: users under level 15 are unable to toggle with - * fame.
3: can't raise or drop fame anymore today.
4: can't raise - * or drop fame for this character for this month anymore.
5: received - * fame, use receiveFame()
6: level of fame neither has been raised nor - * dropped due to an unexpected error - * - * @param status - * @return - */ - public static byte[] giveFameErrorResponse(int status) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue()); - mplew.write(status); - return mplew.getPacket(); - } - - public static byte[] receiveFame(int mode, String charnameFrom) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue()); - mplew.write(5); - mplew.writeMapleAsciiString(charnameFrom); - mplew.write(mode); - return mplew.getPacket(); - } - - public static byte[] partyCreated(MapleParty party, int partycharid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); - mplew.write(8); - mplew.writeInt(party.getId()); - - Map partyDoors = party.getDoors(); - if (partyDoors.size() > 0) { - MapleDoor door = partyDoors.get(partycharid); - - if(door != null) { - MapleDoorObject mdo = door.getAreaDoor(); - mplew.writeInt(mdo.getTo().getId()); - mplew.writeInt(mdo.getFrom().getId()); - mplew.writeInt(mdo.getPosition().x); - mplew.writeInt(mdo.getPosition().y); - } else { - mplew.writeInt(999999999); - mplew.writeInt(999999999); - mplew.writeInt(0); - mplew.writeInt(0); - } - } else { - mplew.writeInt(999999999); - mplew.writeInt(999999999); - mplew.writeInt(0); - mplew.writeInt(0); - } - return mplew.getPacket(); - } - - public static byte[] partyInvite(MapleCharacter from) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); - mplew.write(4); - mplew.writeInt(from.getParty().getId()); - mplew.writeMapleAsciiString(from.getName()); - mplew.write(0); - return mplew.getPacket(); - } - - /** - * 10: A beginner can't create a party. 1/5/6/11/14/19: Your request for a - * party didn't work due to an unexpected error. 12: Quit as leader of the - * party. 13: You have yet to join a party. - * 16: Already have joined a party. 17: The party you're trying to join is - * already in full capacity. 19: Unable to find the requested character in - * this channel. 21: Player is blocking any party invitations. 22: Player - * is taking care of another invitation. 23: Player denied request. - * 25: Cannot kick another user in this map. 28/29: Leadership can only be - * given to a party member in the vicinity. 30: Change leadership only on - * same channel. - * - * @param message - * @return - */ - public static byte[] partyStatusMessage(int message) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); - mplew.write(message); - return mplew.getPacket(); - } - - /** - * 23: 'Char' have denied request to the party. - * - * @param message - * @param charname - * @return - */ - public static byte[] partyStatusMessage(int message, String charname) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); - mplew.write(message); - mplew.writeMapleAsciiString(charname); - return mplew.getPacket(); - } - - private static void addPartyStatus(int forchannel, MapleParty party, LittleEndianWriter lew, boolean leaving) { - List partymembers = new ArrayList<>(party.getMembers()); - while (partymembers.size() < 6) { - partymembers.add(new MaplePartyCharacter()); - } - for (MaplePartyCharacter partychar : partymembers) { - lew.writeInt(partychar.getId()); - } - for (MaplePartyCharacter partychar : partymembers) { - lew.writeAsciiString(getRightPaddedStr(partychar.getName(), '\0', 13)); - } - for (MaplePartyCharacter partychar : partymembers) { - lew.writeInt(partychar.getJobId()); - } - for (MaplePartyCharacter partychar : partymembers) { - lew.writeInt(partychar.getLevel()); - } - for (MaplePartyCharacter partychar : partymembers) { - if (partychar.isOnline()) { - lew.writeInt(partychar.getChannel() - 1); - } else { - lew.writeInt(-2); - } - } - lew.writeInt(party.getLeader().getId()); - for (MaplePartyCharacter partychar : partymembers) { - if (partychar.getChannel() == forchannel) { - lew.writeInt(partychar.getMapId()); - } else { - lew.writeInt(0); - } - } - - Map partyDoors = party.getDoors(); - for (MaplePartyCharacter partychar : partymembers) { - if (partychar.getChannel() == forchannel && !leaving) { - if (partyDoors.size() > 0) { - MapleDoor door = partyDoors.get(partychar.getId()); - if(door != null) { - MapleDoorObject mdo = door.getTownDoor(); - lew.writeInt(mdo.getTown().getId()); - lew.writeInt(mdo.getArea().getId()); - lew.writeInt(mdo.getPosition().x); - lew.writeInt(mdo.getPosition().y); - } else { - lew.writeInt(999999999); - lew.writeInt(999999999); - lew.writeInt(0); - lew.writeInt(0); - } - } else { - lew.writeInt(999999999); - lew.writeInt(999999999); - lew.writeInt(0); - lew.writeInt(0); - } - } else { - lew.writeInt(999999999); - lew.writeInt(999999999); - lew.writeInt(0); - lew.writeInt(0); - } - } - } - - public static byte[] updateParty(int forChannel, MapleParty party, PartyOperation op, MaplePartyCharacter target) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); - switch (op) { - case DISBAND: - case EXPEL: - case LEAVE: - mplew.write(0x0C); - mplew.writeInt(party.getId()); - mplew.writeInt(target.getId()); - if (op == PartyOperation.DISBAND) { - mplew.write(0); - mplew.writeInt(party.getId()); - } else { - mplew.write(1); - if (op == PartyOperation.EXPEL) { - mplew.write(1); - } else { - mplew.write(0); - } - mplew.writeMapleAsciiString(target.getName()); - addPartyStatus(forChannel, party, mplew, false); - } - break; - case JOIN: - mplew.write(0xF); - mplew.writeInt(party.getId()); - mplew.writeMapleAsciiString(target.getName()); - addPartyStatus(forChannel, party, mplew, false); - break; - case SILENT_UPDATE: - case LOG_ONOFF: - mplew.write(0x7); - mplew.writeInt(party.getId()); - addPartyStatus(forChannel, party, mplew, false); - break; - case CHANGE_LEADER: - mplew.write(0x1B); - mplew.writeInt(target.getId()); - mplew.write(0); - break; - } - return mplew.getPacket(); - } - - public static byte[] partyPortal(int townId, int targetId, Point position) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); - mplew.writeShort(0x23); - mplew.writeInt(townId); - mplew.writeInt(targetId); - mplew.writePos(position); - return mplew.getPacket(); - } - - public static byte[] updatePartyMemberHP(int cid, int curhp, int maxhp) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_PARTYMEMBER_HP.getValue()); - mplew.writeInt(cid); - mplew.writeInt(curhp); - mplew.writeInt(maxhp); - return mplew.getPacket(); - } - - /** - * mode: 0 buddychat; 1 partychat; 2 guildchat - * - * @param name - * @param chattext - * @param mode - * @return - */ - public static byte[] multiChat(String name, String chattext, int mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MULTICHAT.getValue()); - mplew.write(mode); - mplew.writeMapleAsciiString(name); - mplew.writeMapleAsciiString(chattext); - return mplew.getPacket(); - } - - private static void writeIntMask(final MaplePacketLittleEndianWriter mplew, Map stats) { - int firstmask = 0; - int secondmask = 0; - for (MonsterStatus stat : stats.keySet()) { - if (stat.isFirst()) { - firstmask |= stat.getValue(); - } else { - secondmask |= stat.getValue(); - } - } - mplew.writeInt(firstmask); - mplew.writeInt(secondmask); - } - - public static byte[] applyMonsterStatus(final int oid, final MonsterStatusEffect mse, final List reflection) { - Map stati = mse.getStati(); - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.APPLY_MONSTER_STATUS.getValue()); - mplew.writeInt(oid); - mplew.writeLong(0); - writeIntMask(mplew, stati); - for (Map.Entry stat : stati.entrySet()) { - mplew.writeShort(stat.getValue()); - if (mse.isMonsterSkill()) { - mplew.writeShort(mse.getMobSkill().getSkillId()); - mplew.writeShort(mse.getMobSkill().getSkillLevel()); - } else { - mplew.writeInt(mse.getSkill().getId()); - } - mplew.writeShort(-1); // might actually be the buffTime but it's not displayed anywhere - } - int size = stati.size(); // size - if (reflection != null) { - for (Integer ref : reflection) { - mplew.writeInt(ref); - } - if (reflection.size() > 0) { - size /= 2; // This gives 2 buffs per reflection but it's really one buff - } - } - mplew.write(size); // size - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] cancelMonsterStatus(int oid, Map stats) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_MONSTER_STATUS.getValue()); - mplew.writeInt(oid); - mplew.writeLong(0); - writeIntMask(mplew, stats); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] getClock(int time) { // time in seconds - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CLOCK.getValue()); - mplew.write(2); // clock type. if you send 3 here you have to send another byte (which does not matter at all) before the timestamp - mplew.writeInt(time); - return mplew.getPacket(); - } - - public static byte[] getClockTime(int hour, int min, int sec) { // Current Time - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CLOCK.getValue()); - mplew.write(1); //Clock-Type - mplew.write(hour); - mplew.write(min); - mplew.write(sec); - return mplew.getPacket(); - } - - public static byte[] removeClock() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STOP_CLOCK.getValue()); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] spawnMist(int oid, int ownerCid, int skill, int level, MapleMist mist) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_MIST.getValue()); - mplew.writeInt(oid); - mplew.writeInt(mist.isMobMist() ? 0 : mist.isPoisonMist() ? 1 : mist.isRecoveryMist() ? 4 : 2); // mob mist = 0, player poison = 1, smokescreen = 2, unknown = 3, recovery = 4 - mplew.writeInt(ownerCid); - mplew.writeInt(skill); - mplew.write(level); - mplew.writeShort(mist.getSkillDelay()); // Skill delay - mplew.writeInt(mist.getBox().x); - mplew.writeInt(mist.getBox().y); - mplew.writeInt(mist.getBox().x + mist.getBox().width); - mplew.writeInt(mist.getBox().y + mist.getBox().height); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] removeMist(int oid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.REMOVE_MIST.getValue()); - mplew.writeInt(oid); - return mplew.getPacket(); - } - - public static byte[] damageSummon(int cid, int oid, int damage, int monsterIdFrom) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DAMAGE_SUMMON.getValue()); - mplew.writeInt(cid); - mplew.writeInt(oid); - mplew.write(12); - mplew.writeInt(damage); // damage display doesn't seem to work... - mplew.writeInt(monsterIdFrom); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] damageMonster(int oid, int damage) { - return damageMonster(oid, damage, 0, 0); - } - - public static byte[] healMonster(int oid, int heal, int curhp, int maxhp) { - return damageMonster(oid, -heal, curhp, maxhp); - } - - private static byte[] damageMonster(int oid, int damage, int curhp, int maxhp) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DAMAGE_MONSTER.getValue()); - mplew.writeInt(oid); - mplew.write(0); - mplew.writeInt(damage); - mplew.writeInt(curhp); - mplew.writeInt(maxhp); - return mplew.getPacket(); - } - - public static byte[] updateBuddylist(Collection buddylist) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); - mplew.write(7); - mplew.write(buddylist.size()); - for (BuddylistEntry buddy : buddylist) { - if (buddy.isVisible()) { - mplew.writeInt(buddy.getCharacterId()); // cid - mplew.writeAsciiString(getRightPaddedStr(buddy.getName(), '\0', 13)); - mplew.write(0); // opposite status - mplew.writeInt(buddy.getChannel() - 1); - mplew.writeAsciiString(getRightPaddedStr(buddy.getGroup(), '\0', 13)); - mplew.writeInt(0);//mapid? - } - } - for (int x = 0; x < buddylist.size(); x++) { - mplew.writeInt(0);//mapid? - } - return mplew.getPacket(); - } - - public static byte[] buddylistMessage(byte message) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); - mplew.write(message); - return mplew.getPacket(); - } - - public static byte[] requestBuddylistAdd(int cidFrom, int cid, String nameFrom) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); - mplew.write(9); - mplew.writeInt(cidFrom); - mplew.writeMapleAsciiString(nameFrom); - mplew.writeInt(cidFrom); - mplew.writeAsciiString(getRightPaddedStr(nameFrom, '\0', 11)); - mplew.write(0x09); - mplew.write(0xf0); - mplew.write(0x01); - mplew.writeInt(0x0f); - mplew.writeNullTerminatedAsciiString("Default Group"); - mplew.writeInt(cid); - return mplew.getPacket(); - } - - public static byte[] updateBuddyChannel(int characterid, int channel) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); - mplew.write(0x14); - mplew.writeInt(characterid); - mplew.write(0); - mplew.writeInt(channel); - return mplew.getPacket(); - } - - public static byte[] itemEffect(int characterid, int itemid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_EFFECT.getValue()); - mplew.writeInt(characterid); - mplew.writeInt(itemid); - return mplew.getPacket(); - } - - public static byte[] updateBuddyCapacity(int capacity) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); - mplew.write(0x15); - mplew.write(capacity); - return mplew.getPacket(); - } - - public static byte[] showChair(int characterid, int itemid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_CHAIR.getValue()); - mplew.writeInt(characterid); - mplew.writeInt(itemid); - return mplew.getPacket(); - } - - public static byte[] cancelChair(int id) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_CHAIR.getValue()); - if (id == -1) { - mplew.write(0); - } else { - mplew.write(1); - mplew.writeShort(id); - } - return mplew.getPacket(); - } - - // is there a way to spawn reactors non-animated? - public static byte[] spawnReactor(MapleReactor reactor) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - Point pos = reactor.getPosition(); - mplew.writeShort(SendOpcode.REACTOR_SPAWN.getValue()); - mplew.writeInt(reactor.getObjectId()); - mplew.writeInt(reactor.getId()); - mplew.write(reactor.getState()); - mplew.writePos(pos); - mplew.writeShort(0); - mplew.write(0); - return mplew.getPacket(); - } - - // is there a way to trigger reactors without performing the hit animation? - public static byte[] triggerReactor(MapleReactor reactor, int stance) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - Point pos = reactor.getPosition(); - mplew.writeShort(SendOpcode.REACTOR_HIT.getValue()); - mplew.writeInt(reactor.getObjectId()); - mplew.write(reactor.getState()); - mplew.writePos(pos); - mplew.writeShort(stance); - mplew.write(0); - mplew.write(5); // frame delay, set to 5 since there doesn't appear to be a fixed formula for it - return mplew.getPacket(); - } - - public static byte[] destroyReactor(MapleReactor reactor) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - Point pos = reactor.getPosition(); - mplew.writeShort(SendOpcode.REACTOR_DESTROY.getValue()); - mplew.writeInt(reactor.getObjectId()); - mplew.write(reactor.getState()); - mplew.writePos(pos); - return mplew.getPacket(); - } - - public static byte[] musicChange(String song) { - return environmentChange(song, 6); - } - - public static byte[] showEffect(String effect) { - return environmentChange(effect, 3); - } - - public static byte[] playSound(String sound) { - return environmentChange(sound, 4); - } - - public static byte[] environmentChange(String env, int mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(mode); - mplew.writeMapleAsciiString(env); - return mplew.getPacket(); - } - - public static byte[] environmentMove(String env, int mode) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - - mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ONOFF.getValue()); - mplew.writeMapleAsciiString(env); - mplew.writeInt(mode); // 0: stop and back to start, 1: move - - return mplew.getPacket(); - } - - public static byte[] environmentMoveList(Set> envList) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ONOFF_LIST.getValue()); - mplew.writeInt(envList.size()); - - for(Entry envMove : envList) { - mplew.writeMapleAsciiString(envMove.getKey()); - mplew.writeInt(envMove.getValue()); - } - - return mplew.getPacket(); - } - - public static byte[] environmentMoveReset() { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ALL_RESET.getValue()); - return mplew.getPacket(); - } - - public static byte[] startMapEffect(String msg, int itemid, boolean active) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); - mplew.write(active ? 0 : 1); - mplew.writeInt(itemid); - if (active) { - mplew.writeMapleAsciiString(msg); - } - return mplew.getPacket(); - } - - public static byte[] removeMapEffect() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); - mplew.write(0); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] mapEffect(String path) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(3); - mplew.writeMapleAsciiString(path); - return mplew.getPacket(); - } - - public static byte[] mapSound(String path) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(4); - mplew.writeMapleAsciiString(path); - return mplew.getPacket(); - } - - public static byte[] showGuildInfo(MapleCharacter c) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x1A); //signature for showing guild info - if (c == null) { //show empty guild (used for leaving, expelled) - mplew.write(0); - return mplew.getPacket(); - } - MapleGuild g = c.getClient().getWorldServer().getGuild(c.getMGC()); - if (g == null) { //failed to read from DB - don't show a guild - mplew.write(0); - return mplew.getPacket(); - } - mplew.write(1); //bInGuild - mplew.writeInt(g.getId()); - mplew.writeMapleAsciiString(g.getName()); - for (int i = 1; i <= 5; i++) { - mplew.writeMapleAsciiString(g.getRankTitle(i)); - } - Collection members = g.getMembers(); - mplew.write(members.size()); //then it is the size of all the members - for (MapleGuildCharacter mgc : members) {//and each of their character ids o_O - mplew.writeInt(mgc.getId()); - } - for (MapleGuildCharacter mgc : members) { - mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13)); - mplew.writeInt(mgc.getJobId()); - mplew.writeInt(mgc.getLevel()); - mplew.writeInt(mgc.getGuildRank()); - mplew.writeInt(mgc.isOnline() ? 1 : 0); - mplew.writeInt(g.getSignature()); - mplew.writeInt(mgc.getAllianceRank()); - } - mplew.writeInt(g.getCapacity()); - mplew.writeShort(g.getLogoBG()); - mplew.write(g.getLogoBGColor()); - mplew.writeShort(g.getLogo()); - mplew.write(g.getLogoColor()); - mplew.writeMapleAsciiString(g.getNotice()); - mplew.writeInt(g.getGP()); - mplew.writeInt(g.getAllianceId()); - return mplew.getPacket(); - } - - public static byte[] guildMemberOnline(int gid, int cid, boolean bOnline) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x3d); - mplew.writeInt(gid); - mplew.writeInt(cid); - mplew.write(bOnline ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] guildInvite(int gid, String charName) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x05); - mplew.writeInt(gid); - mplew.writeMapleAsciiString(charName); - return mplew.getPacket(); - } - - /** - * 'Char' has denied your guild invitation. - * - * @param charname - * @return - */ - public static byte[] denyGuildInvitation(String charname) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x37); - mplew.writeMapleAsciiString(charname); - return mplew.getPacket(); - } - - public static byte[] genericGuildMessage(byte code) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(code); - return mplew.getPacket(); - } - - public static byte[] newGuildMember(MapleGuildCharacter mgc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x27); - mplew.writeInt(mgc.getGuildId()); - mplew.writeInt(mgc.getId()); - mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13)); - mplew.writeInt(mgc.getJobId()); - mplew.writeInt(mgc.getLevel()); - mplew.writeInt(mgc.getGuildRank()); //should be always 5 but whatevs - mplew.writeInt(mgc.isOnline() ? 1 : 0); //should always be 1 too - mplew.writeInt(1); //? could be guild signature, but doesn't seem to matter - mplew.writeInt(3); - return mplew.getPacket(); - } - - //someone leaving, mode == 0x2c for leaving, 0x2f for expelled - public static byte[] memberLeft(MapleGuildCharacter mgc, boolean bExpelled) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(bExpelled ? 0x2f : 0x2c); - mplew.writeInt(mgc.getGuildId()); - mplew.writeInt(mgc.getId()); - mplew.writeMapleAsciiString(mgc.getName()); - return mplew.getPacket(); - } - - //rank change - public static byte[] changeRank(MapleGuildCharacter mgc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x40); - mplew.writeInt(mgc.getGuildId()); - mplew.writeInt(mgc.getId()); - mplew.write(mgc.getGuildRank()); - return mplew.getPacket(); - } - - public static byte[] guildNotice(int gid, String notice) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x44); - mplew.writeInt(gid); - mplew.writeMapleAsciiString(notice); - return mplew.getPacket(); - } - - public static byte[] guildMemberLevelJobUpdate(MapleGuildCharacter mgc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x3C); - mplew.writeInt(mgc.getGuildId()); - mplew.writeInt(mgc.getId()); - mplew.writeInt(mgc.getLevel()); - mplew.writeInt(mgc.getJobId()); - return mplew.getPacket(); - } - - public static byte[] rankTitleChange(int gid, String[] ranks) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x3E); - mplew.writeInt(gid); - for (int i = 0; i < 5; i++) { - mplew.writeMapleAsciiString(ranks[i]); - } - return mplew.getPacket(); - } - - public static byte[] guildDisband(int gid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x32); - mplew.writeInt(gid); - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] guildQuestWaitingNotice(byte channel, int waitingPos) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x4C); - mplew.write(channel - 1); - mplew.write(waitingPos); - return mplew.getPacket(); - } - - public static byte[] guildEmblemChange(int gid, short bg, byte bgcolor, short logo, byte logocolor) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x42); - mplew.writeInt(gid); - mplew.writeShort(bg); - mplew.write(bgcolor); - mplew.writeShort(logo); - mplew.write(logocolor); - return mplew.getPacket(); - } - - public static byte[] guildCapacityChange(int gid, int capacity) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x3A); - mplew.writeInt(gid); - mplew.write(capacity); - return mplew.getPacket(); - } - - public static void addThread(final MaplePacketLittleEndianWriter mplew, ResultSet rs) throws SQLException { - mplew.writeInt(rs.getInt("localthreadid")); - mplew.writeInt(rs.getInt("postercid")); - mplew.writeMapleAsciiString(rs.getString("name")); - mplew.writeLong(getTime(rs.getLong("timestamp"))); - mplew.writeInt(rs.getInt("icon")); - mplew.writeInt(rs.getInt("replycount")); - } - - public static byte[] BBSThreadList(ResultSet rs, int start) throws SQLException { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_BBS_PACKET.getValue()); - mplew.write(0x06); - if (!rs.last()) { - mplew.write(0); - mplew.writeInt(0); - mplew.writeInt(0); - return mplew.getPacket(); - } - int threadCount = rs.getRow(); - if (rs.getInt("localthreadid") == 0) { //has a notice - mplew.write(1); - addThread(mplew, rs); - threadCount--; //one thread didn't count (because it's a notice) - } else { - mplew.write(0); - } - if (!rs.absolute(start + 1)) { //seek to the thread before where we start - rs.first(); //uh, we're trying to start at a place past possible - start = 0; - } - mplew.writeInt(threadCount); - mplew.writeInt(Math.min(10, threadCount - start)); - for (int i = 0; i < Math.min(10, threadCount - start); i++) { - addThread(mplew, rs); - rs.next(); - } - return mplew.getPacket(); - } - - public static byte[] showThread(int localthreadid, ResultSet threadRS, ResultSet repliesRS) throws SQLException, RuntimeException { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_BBS_PACKET.getValue()); - mplew.write(0x07); - mplew.writeInt(localthreadid); - mplew.writeInt(threadRS.getInt("postercid")); - mplew.writeLong(getTime(threadRS.getLong("timestamp"))); - mplew.writeMapleAsciiString(threadRS.getString("name")); - mplew.writeMapleAsciiString(threadRS.getString("startpost")); - mplew.writeInt(threadRS.getInt("icon")); - if (repliesRS != null) { - int replyCount = threadRS.getInt("replycount"); - mplew.writeInt(replyCount); - int i; - for (i = 0; i < replyCount && repliesRS.next(); i++) { - mplew.writeInt(repliesRS.getInt("replyid")); - mplew.writeInt(repliesRS.getInt("postercid")); - mplew.writeLong(getTime(repliesRS.getLong("timestamp"))); - mplew.writeMapleAsciiString(repliesRS.getString("content")); - } - if (i != replyCount || repliesRS.next()) { - throw new RuntimeException(String.valueOf(threadRS.getInt("threadid"))); - } - } else { - mplew.writeInt(0); - } - return mplew.getPacket(); - } - - public static byte[] showGuildRanks(int npcid, ResultSet rs) throws SQLException { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x49); - mplew.writeInt(npcid); - if (!rs.last()) { //no guilds o.o - mplew.writeInt(0); - return mplew.getPacket(); - } - mplew.writeInt(rs.getRow()); //number of entries - rs.beforeFirst(); - while (rs.next()) { - mplew.writeMapleAsciiString(rs.getString("name")); - mplew.writeInt(rs.getInt("GP")); - mplew.writeInt(rs.getInt("logo")); - mplew.writeInt(rs.getInt("logoColor")); - mplew.writeInt(rs.getInt("logoBG")); - mplew.writeInt(rs.getInt("logoBGColor")); - } - return mplew.getPacket(); - } - - public static byte[] showPlayerRanks(int npcid, List> worldRanking) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x49); - mplew.writeInt(npcid); - if (worldRanking.isEmpty()) { - mplew.writeInt(0); - return mplew.getPacket(); - } - mplew.writeInt(worldRanking.size()); - for (Pair wr : worldRanking) { - mplew.writeMapleAsciiString(wr.getLeft()); - mplew.writeInt(wr.getRight()); - mplew.writeInt(0); - mplew.writeInt(0); - mplew.writeInt(0); - mplew.writeInt(0); - } - return mplew.getPacket(); - } - - public static byte[] updateGP(int gid, int GP) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); - mplew.write(0x48); - mplew.writeInt(gid); - mplew.writeInt(GP); - return mplew.getPacket(); - } - - public static byte[] skillEffect(MapleCharacter from, int skillId, int level, byte flags, int speed, byte direction) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SKILL_EFFECT.getValue()); - mplew.writeInt(from.getId()); - mplew.writeInt(skillId); - mplew.write(level); - mplew.write(flags); - mplew.write(speed); - mplew.write(direction); //Mmmk - return mplew.getPacket(); - } - - public static byte[] skillCancel(MapleCharacter from, int skillId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CANCEL_SKILL_EFFECT.getValue()); - mplew.writeInt(from.getId()); - mplew.writeInt(skillId); - return mplew.getPacket(); - } - - public static byte[] catchMonster(int mobOid, byte success) { // updated packet structure found thanks to Rien dev team - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CATCH_MONSTER.getValue()); - mplew.writeInt(mobOid); - mplew.write(success); - return mplew.getPacket(); - } - - public static byte[] catchMonster(int mobOid, int itemid, byte success) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CATCH_MONSTER_WITH_ITEM.getValue()); - mplew.writeInt(mobOid); - mplew.writeInt(itemid); - mplew.write(success); - return mplew.getPacket(); - } - - /** - * Sends a player hint. - * - * @param hint The hint it's going to send. - * @param width How tall the box is going to be. - * @param height How long the box is going to be. - * @return The player hint packet. - */ - public static byte[] sendHint(String hint, int width, int height) { - if (width < 1) { - width = hint.length() * 10; - if (width < 40) { - width = 40; - } - } - if (height < 5) { - height = 5; - } - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_HINT.getValue()); - mplew.writeMapleAsciiString(hint); - mplew.writeShort(width); - mplew.writeShort(height); - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] messengerInvite(String from, int messengerid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(0x03); - mplew.writeMapleAsciiString(from); - mplew.write(0); - mplew.writeInt(messengerid); - mplew.write(0); - return mplew.getPacket(); - } - - /* - public static byte[] sendSpouseChat(MapleCharacter partner, String msg) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue()); - mplew.writeMapleAsciiString(partner.getName()); - mplew.writeMapleAsciiString(msg); - return mplew.getPacket(); - } - */ - - public static byte[] OnCoupleMessage(String fiance, String text, boolean spouse) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue()); - mplew.write(spouse ? 5 : 4); // v2 = CInPacket::Decode1(a1) - 4; - if (spouse) { // if ( v2 ) { - mplew.writeMapleAsciiString(fiance); + mplew.writeInt(ring.getItemId()); } - mplew.write(spouse ? 5 : 1); - mplew.writeMapleAsciiString(text); - return mplew.getPacket(); - } - - public static byte[] addMessengerPlayer(String from, MapleCharacter chr, int position, int channel) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(0x00); - mplew.write(position); - addCharLook(mplew, chr, true); - mplew.writeMapleAsciiString(from); - mplew.write(channel); - mplew.write(0x00); - return mplew.getPacket(); } - - public static byte[] removeMessengerPlayer(int position) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(0x02); - mplew.write(position); - return mplew.getPacket(); + if (yes == false) { + mplew.write(0); } + } - public static byte[] updateMessengerPlayer(String from, MapleCharacter chr, int position, int channel) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(0x07); - mplew.write(position); - addCharLook(mplew, chr, true); - mplew.writeMapleAsciiString(from); - mplew.write(channel); - mplew.write(0x00); - return mplew.getPacket(); - } + private static void addMarriageRingLook(MapleClient target, final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + MapleRing ring = chr.getMarriageRing(); - public static byte[] joinMessenger(int position) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(0x01); - mplew.write(position); - return mplew.getPacket(); - } + if (ring == null || !ring.equipped()) { + mplew.write(0); + } else { + mplew.write(1); - public static byte[] messengerChat(String text) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(0x06); - mplew.writeMapleAsciiString(text); - return mplew.getPacket(); - } - - public static byte[] messengerNote(String text, int mode, int mode2) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MESSENGER.getValue()); - mplew.write(mode); - mplew.writeMapleAsciiString(text); - mplew.write(mode2); - return mplew.getPacket(); - } - - private static void addPetInfo(final MaplePacketLittleEndianWriter mplew, MaplePet pet, boolean showpet) { - mplew.write(1); - if (showpet) { - mplew.write(0); - } - - mplew.writeInt(pet.getItemId()); - mplew.writeMapleAsciiString(pet.getName()); - mplew.writeLong(pet.getUniqueId()); - mplew.writePos(pet.getPos()); - mplew.write(pet.getStance()); - mplew.writeInt(pet.getFh()); - } - - public static byte[] showPet(MapleCharacter chr, MaplePet pet, boolean remove, boolean hunger) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_PET.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(chr.getPetIndex(pet)); - if (remove) { - mplew.write(0); - mplew.write(hunger ? 1 : 0); - } else { - addPetInfo(mplew, pet, true); - } - return mplew.getPacket(); - } - - public static byte[] movePet(int cid, int pid, byte slot, List moves) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MOVE_PET.getValue()); - mplew.writeInt(cid); - mplew.write(slot); - mplew.writeInt(pid); - serializeMovementList(mplew, moves); - return mplew.getPacket(); - } - - public static byte[] petChat(int cid, byte index, int act, String text) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PET_CHAT.getValue()); - mplew.writeInt(cid); - mplew.write(index); - mplew.write(0); - mplew.write(act); - mplew.writeMapleAsciiString(text); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] petFoodResponse(int cid, byte index, boolean success, boolean balloonType) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PET_COMMAND.getValue()); - mplew.writeInt(cid); - mplew.write(index); - mplew.write(1); - mplew.writeBool(success); - mplew.writeBool(balloonType); - return mplew.getPacket(); - } - - public static byte[] commandResponse(int cid, byte index, boolean talk, int animation, boolean balloonType) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PET_COMMAND.getValue()); - mplew.writeInt(cid); - mplew.write(index); - mplew.write(0); - mplew.write(animation); - mplew.writeBool(!talk); - mplew.writeBool(balloonType); - return mplew.getPacket(); - } - - public static byte[] showOwnPetLevelUp(byte index) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(4); - mplew.write(0); - mplew.write(index); // Pet Index - return mplew.getPacket(); - } - - public static byte[] showPetLevelUp(MapleCharacter chr, byte index) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(4); - mplew.write(0); - mplew.write(index); - return mplew.getPacket(); - } - - public static byte[] changePetName(MapleCharacter chr, String newname, int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PET_NAMECHANGE.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(0); - mplew.writeMapleAsciiString(newname); - mplew.write(0); - return mplew.getPacket(); - } - - public static final byte[] loadExceptionList(final int cid, final int petId, final byte petIdx, final List data) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PET_EXCEPTION_LIST.getValue()); - mplew.writeInt(cid); - mplew.write(petIdx); - mplew.writeLong(petId); - mplew.write(data.size()); - for (final Integer ids : data) { - mplew.writeInt(ids); - } - return mplew.getPacket(); - } - - public static byte[] petStatUpdate(MapleCharacter chr) { - // this actually does nothing... packet structure and stats needs to be uncovered - - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.STAT_CHANGED.getValue()); - int mask = 0; - mask |= MapleStat.PET.getValue(); - mplew.write(0); - mplew.writeInt(mask); - MaplePet[] pets = chr.getPets(); - for (int i = 0; i < 3; i++) { - if (pets[i] != null) { - mplew.writeLong(pets[i].getUniqueId()); - } else { - mplew.writeLong(0); - } - } - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] showForcedEquip(int team) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FORCED_MAP_EQUIP.getValue()); - if (team > -1) { - mplew.write(team); // 00 = red, 01 = blue - } - return mplew.getPacket(); - } - - public static byte[] summonSkill(int cid, int summonSkillId, int newStance) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SUMMON_SKILL.getValue()); - mplew.writeInt(cid); - mplew.writeInt(summonSkillId); - mplew.write(newStance); - return mplew.getPacket(); - } - - public static byte[] skillCooldown(int sid, int time) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.COOLDOWN.getValue()); - mplew.writeInt(sid); - mplew.writeShort(time);//Int in v97 - return mplew.getPacket(); - } - - public static byte[] skillBookSuccess(MapleCharacter chr, int skillid, int maxlevel, boolean canuse, boolean success) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SKILL_LEARN_ITEM_RESULT.getValue()); - mplew.writeInt(chr.getId()); - mplew.write(1); - mplew.writeInt(skillid); - mplew.writeInt(maxlevel); - mplew.write(canuse ? 1 : 0); - mplew.write(success ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] getMacros(SkillMacro[] macros) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MACRO_SYS_DATA_INIT.getValue()); - int count = 0; - for (int i = 0; i < 5; i++) { - if (macros[i] != null) { - count++; - } - } - mplew.write(count); - for (int i = 0; i < 5; i++) { - SkillMacro macro = macros[i]; - if (macro != null) { - mplew.writeMapleAsciiString(macro.getName()); - mplew.write(macro.getShout()); - mplew.writeInt(macro.getSkill1()); - mplew.writeInt(macro.getSkill2()); - mplew.writeInt(macro.getSkill3()); - } - } - return mplew.getPacket(); - } - - public static byte[] updateAriantPQRanking(String name, int score, boolean empty) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ARIANT_SCORE.getValue()); - mplew.write(empty ? 0 : 1); - if (!empty) { - mplew.writeMapleAsciiString(name); - mplew.writeInt(score); - } - return mplew.getPacket(); - } - - public static byte[] catchMessage(int message) { // not done, I guess - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BRIDLE_MOB_CATCH_FAIL.getValue()); - mplew.write(message); // 1 = too strong, 2 = Elemental Rock - mplew.writeInt(0);//Maybe itemid? + MapleCharacter targetChr = target.getPlayer(); + if (targetChr != null && targetChr.getPartnerId() == chr.getId()) { mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] showAllCharacter(int chars, int unk) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); - mplew.writeShort(SendOpcode.VIEW_ALL_CHAR.getValue()); - mplew.write(chars > 0 ? 1 : 5); // 2: already connected to server, 3 : unk error (view-all-characters), 5 : cannot find any - mplew.writeInt(chars); - mplew.writeInt(unk); - return mplew.getPacket(); - } - - public static byte[] showAllCharacterInfo(int worldid, List chars, boolean usePic) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.VIEW_ALL_CHAR.getValue()); - mplew.write(0); - mplew.write(worldid); - mplew.write(chars.size()); - for (MapleCharacter chr : chars) { - addCharEntry(mplew, chr, true); - } - mplew.write(usePic ? 1 : 2); - return mplew.getPacket(); - } - - public static byte[] updateMount(int charid, MapleMount mount, boolean levelup) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_TAMING_MOB_INFO.getValue()); - mplew.writeInt(charid); - mplew.writeInt(mount.getLevel()); - mplew.writeInt(mount.getExp()); - mplew.writeInt(mount.getTiredness()); - mplew.write(levelup ? (byte) 1 : (byte) 0); - return mplew.getPacket(); - } - - public static byte[] crogBoatPacket(boolean type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CONTI_MOVE.getValue()); - mplew.write(10); - mplew.write(type ? 4 : 5); - return mplew.getPacket(); - } - - public static byte[] boatPacket(boolean type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CONTI_STATE.getValue()); - mplew.write(type ? 1 : 2); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] getMiniGame(MapleClient c, MapleMiniGame minigame, boolean owner, int piece) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(1); - mplew.write(0); - mplew.write(owner ? 0 : 1); - mplew.write(0); - addCharLook(mplew, minigame.getOwner(), false); - mplew.writeMapleAsciiString(minigame.getOwner().getName()); - if (minigame.getVisitor() != null) { - MapleCharacter visitor = minigame.getVisitor(); - mplew.write(1); - addCharLook(mplew, visitor, false); - mplew.writeMapleAsciiString(visitor.getName()); - } - mplew.write(0xFF); - mplew.write(0); - mplew.writeInt(1); - mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.WIN, true)); - mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.TIE, true)); - mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.LOSS, true)); - mplew.writeInt(minigame.getOwnerScore()); - if (minigame.getVisitor() != null) { - MapleCharacter visitor = minigame.getVisitor(); - mplew.write(1); - mplew.writeInt(1); - mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.WIN, true)); - mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.TIE, true)); - mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.LOSS, true)); - mplew.writeInt(minigame.getVisitorScore()); - } - mplew.write(0xFF); - mplew.writeMapleAsciiString(minigame.getDescription()); - mplew.write(piece); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] getMiniGameReady(MapleMiniGame game) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.READY.getCode()); - return mplew.getPacket(); - } - - public static byte[] getMiniGameUnReady(MapleMiniGame game) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.UN_READY.getCode()); - return mplew.getPacket(); - } - - public static byte[] getMiniGameStart(MapleMiniGame game, int loser) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.START.getCode()); - mplew.write(loser); - return mplew.getPacket(); - } - - public static byte[] getMiniGameSkipOwner(MapleMiniGame game) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.SKIP.getCode()); - mplew.write(0x01); - return mplew.getPacket(); - } - - public static byte[] getMiniGameRequestTie(MapleMiniGame game) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.REQUEST_TIE.getCode()); - return mplew.getPacket(); - } - - public static byte[] getMiniGameDenyTie(MapleMiniGame game) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ANSWER_TIE.getCode()); - return mplew.getPacket(); - } - - /** - * 1 = Room already closed 2 = Can't enter due full cappacity 3 = Other requests at this minute - * 4 = Can't do while dead 5 = Can't do while middle event 6 = This character unable to do it - * 7, 20 = Not allowed to trade anymore 9 = Can only trade on same map 10 = May not open store near portal - * 11, 14 = Can't start game here 12 = Can't open store at this channel 13 = Can't estabilish miniroom - * 15 = Stores only an the free market 16 = Lists the rooms at FM (?) 17 = You may not enter this store - * 18 = Owner undergoing store maintenance 19 = Unable to enter tournament room 21 = Not enough mesos to enter - * 22 = Incorrect password - * - * @param status - * @return - */ - public static byte[] getMiniRoomError(int status) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(0); - mplew.write(status); - return mplew.getPacket(); - } - - public static byte[] getMiniGameSkipVisitor(MapleMiniGame game) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.writeShort(PlayerInteractionHandler.Action.SKIP.getCode()); - return mplew.getPacket(); - } - - public static byte[] getMiniGameMoveOmok(MapleMiniGame game, int move1, int move2, int move3) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(12); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.MOVE_OMOK.getCode()); - mplew.writeInt(move1); - mplew.writeInt(move2); - mplew.write(move3); - return mplew.getPacket(); - } - - public static byte[] getMiniGameNewVisitor(MapleMiniGame minigame, MapleCharacter c, int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); - mplew.write(slot); - addCharLook(mplew, c, false); - mplew.writeMapleAsciiString(c.getName()); - mplew.writeInt(1); - mplew.writeInt(c.getMiniGamePoints(MiniGameResult.WIN, true)); - mplew.writeInt(c.getMiniGamePoints(MiniGameResult.TIE, true)); - mplew.writeInt(c.getMiniGamePoints(MiniGameResult.LOSS, true)); - mplew.writeInt(minigame.getVisitorScore()); - return mplew.getPacket(); - } - - public static byte[] getMiniGameRemoveVisitor() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - mplew.write(1); - return mplew.getPacket(); - } - - private static byte[] getMiniGameResult(MapleMiniGame game, int tie, int result, int forfeit) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.GET_RESULT.getCode()); - - int matchResultType; - if (tie == 0 && forfeit != 1) { - matchResultType = 0; - } else if (tie != 0) { - matchResultType = 1; - } else { - matchResultType = 2; - } - - mplew.write(matchResultType); - mplew.writeBool(result == 2); // host/visitor wins - - boolean omok = game.isOmok(); - if (matchResultType == 1) { - mplew.write(0); - mplew.writeShort(0); - mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins - mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties - mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses - mplew.writeInt(game.getOwnerScore()); // points - - mplew.writeInt(0); // unknown - mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins - mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties - mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses - mplew.writeInt(game.getVisitorScore()); // points - mplew.write(0); - } else { - mplew.writeInt(0); - mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins - mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties - mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses - mplew.writeInt(game.getOwnerScore()); // points - mplew.writeInt(0); - mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins - mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties - mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses - mplew.writeInt(game.getVisitorScore()); // points - } - - return mplew.getPacket(); - } - - public static byte[] getMiniGameOwnerWin(MapleMiniGame game, boolean forfeit) { - return getMiniGameResult(game, 0, 1, forfeit ? 1 : 0); - } - - public static byte[] getMiniGameVisitorWin(MapleMiniGame game, boolean forfeit) { - return getMiniGameResult(game, 0, 2, forfeit ? 1 : 0); - } - - public static byte[] getMiniGameTie(MapleMiniGame game) { - return getMiniGameResult(game, 1, 3, 0); - } - - public static byte[] getMiniGameClose(int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - mplew.write(1); - mplew.write(type); /* 2 : CRASH 3 : The room has been closed 4 : You have left the room 5 : You have been expelled */ - return mplew.getPacket(); - } - - public static byte[] getMatchCard(MapleClient c, MapleMiniGame minigame, boolean owner, int piece) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(2); - mplew.write(2); - mplew.write(owner ? 0 : 1); - mplew.write(0); - addCharLook(mplew, minigame.getOwner(), false); - mplew.writeMapleAsciiString(minigame.getOwner().getName()); - if (minigame.getVisitor() != null) { - MapleCharacter visitor = minigame.getVisitor(); - mplew.write(1); - addCharLook(mplew, visitor, false); - mplew.writeMapleAsciiString(visitor.getName()); - } - mplew.write(0xFF); - mplew.write(0); - mplew.writeInt(2); - mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.WIN, false)); - mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.TIE, false)); - mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.LOSS, false)); - - //set vs - mplew.writeInt(minigame.getOwnerScore()); - if (minigame.getVisitor() != null) { - MapleCharacter visitor = minigame.getVisitor(); - mplew.write(1); - mplew.writeInt(2); - mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.WIN, false)); - mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.TIE, false)); - mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.LOSS, false)); - mplew.writeInt(minigame.getVisitorScore()); - } - mplew.write(0xFF); - mplew.writeMapleAsciiString(minigame.getDescription()); - mplew.write(piece); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] getMatchCardStart(MapleMiniGame game, int loser) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.START.getCode()); - mplew.write(loser); - - int last; - if (game.getMatchesToWin() > 10) { - last = 30; - } else if (game.getMatchesToWin() > 6) { - last = 20; - } else { - last = 12; - } - - mplew.write(last); - for (int i = 0; i < last; i++) { - mplew.writeInt(game.getCardId(i)); - } - return mplew.getPacket(); - } - - public static byte[] getMatchCardNewVisitor(MapleMiniGame minigame, MapleCharacter c, int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); - mplew.write(slot); - addCharLook(mplew, c, false); - mplew.writeMapleAsciiString(c.getName()); - mplew.writeInt(1); - mplew.writeInt(c.getMiniGamePoints(MiniGameResult.WIN, false)); - mplew.writeInt(c.getMiniGamePoints(MiniGameResult.TIE, false)); - mplew.writeInt(c.getMiniGamePoints(MiniGameResult.LOSS, false)); - mplew.writeInt(minigame.getVisitorScore()); - return mplew.getPacket(); - } - - public static byte[] getMatchCardSelect(MapleMiniGame game, int turn, int slot, int firstslot, int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.SELECT_CARD.getCode()); - mplew.write(turn); - if (turn == 1) { - mplew.write(slot); - } else if (turn == 0) { - mplew.write(slot); - mplew.write(firstslot); - mplew.write(type); - } - return mplew.getPacket(); - } - - public static byte[] fredrickMessage(byte operation) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FREDRICK_MESSAGE.getValue()); - mplew.write(operation); - return mplew.getPacket(); - } - - public static byte[] getFredrick(byte op) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FREDRICK.getValue()); - mplew.write(op); - - switch (op) { - case 0x24: - mplew.skip(8); - break; - default: - mplew.write(0); - break; - } - - return mplew.getPacket(); - } - - public static byte[] getFredrick(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FREDRICK.getValue()); - mplew.write(0x23); - mplew.writeInt(9030000); // Fredrick - mplew.writeInt(32272); //id - mplew.skip(5); - mplew.writeInt(chr.getMerchantMeso()); - mplew.write(0); - try { - List> items = ItemFactory.MERCHANT.loadItems(chr.getId(), false); - mplew.write(items.size()); - - for (int i = 0; i < items.size(); i++) { - addItemInfo(mplew, items.get(i).getLeft(), true); - } - } catch (SQLException e) { - e.printStackTrace(); - } - mplew.skip(3); - return mplew.getPacket(); - } - - public static byte[] addOmokBox(MapleCharacter c, int ammount, int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); - mplew.writeInt(c.getId()); - addAnnounceBox(mplew, c.getMiniGame(), ammount, type); - return mplew.getPacket(); - } - - public static byte[] addMatchCardBox(MapleCharacter c, int ammount, int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); - mplew.writeInt(c.getId()); - addAnnounceBox(mplew, c.getMiniGame(), ammount, type); - return mplew.getPacket(); - } - - public static byte[] removeMinigameBox(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); + mplew.writeInt(0); + } else { mplew.writeInt(chr.getId()); + mplew.writeInt(ring.getPartnerChrId()); + } + + mplew.writeInt(ring.getItemId()); + } + } + + /** + * Adds a announcement box to an existing MaplePacketLittleEndianWriter. + * + * @param mplew The MaplePacketLittleEndianWriter to add an announcement box + * to. + * @param shop The shop to announce. + */ + private static void addAnnounceBox(final MaplePacketLittleEndianWriter mplew, MaplePlayerShop shop, int availability) { + mplew.write(4); + mplew.writeInt(shop.getObjectId()); + mplew.writeMapleAsciiString(shop.getDescription()); + mplew.write(0); + mplew.write(0); + mplew.write(1); + mplew.write(availability); + mplew.write(0); + } + + private static void addAnnounceBox(final MaplePacketLittleEndianWriter mplew, MapleMiniGame game, int ammount, int joinable) { + mplew.write(game.getGameType().getValue()); + mplew.writeInt(game.getObjectId()); // gameid/shopid + mplew.writeMapleAsciiString(game.getDescription()); // desc + mplew.writeBool(!game.getPassword().isEmpty()); // password here, thanks GabrielSin! + mplew.write(game.getPieceType()); + mplew.write(ammount); + mplew.write(2); //player capacity + mplew.write(joinable); + } + + private static void updateHiredMerchantBoxInfo(MaplePacketLittleEndianWriter mplew, MapleHiredMerchant hm) { + byte[] roomInfo = hm.getShopRoomInfo(); + + mplew.write(5); + mplew.writeInt(hm.getObjectId()); + mplew.writeMapleAsciiString(hm.getDescription()); + mplew.write(hm.getItemId() % 100); + mplew.write(roomInfo); // visitor capacity here, thanks GabrielSin! + } + + public static byte[] updateHiredMerchantBox(MapleHiredMerchant hm) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_HIRED_MERCHANT.getValue()); + mplew.writeInt(hm.getOwnerId()); + + updateHiredMerchantBoxInfo(mplew, hm); + return mplew.getPacket(); + } + + private static void updatePlayerShopBoxInfo(final MaplePacketLittleEndianWriter mplew, MaplePlayerShop shop) { + byte[] roomInfo = shop.getShopRoomInfo(); + + mplew.write(4); + mplew.writeInt(shop.getObjectId()); + mplew.writeMapleAsciiString(shop.getDescription()); + mplew.write(0); // pw + mplew.write(shop.getItemId() % 100); + mplew.write(roomInfo[0]); // curPlayers + mplew.write(roomInfo[1]); // maxPlayers + mplew.write(0); + } + + public static byte[] updatePlayerShopBox(MaplePlayerShop shop) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); + mplew.writeInt(shop.getOwner().getId()); + + updatePlayerShopBoxInfo(mplew, shop); + return mplew.getPacket(); + } + + public static byte[] removePlayerShopBox(MaplePlayerShop shop) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); + mplew.writeInt(shop.getOwner().getId()); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] facialExpression(MapleCharacter from, int expression) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(10); + mplew.writeShort(SendOpcode.FACIAL_EXPRESSION.getValue()); + mplew.writeInt(from.getId()); + mplew.writeInt(expression); + return mplew.getPacket(); + } + + private static void serializeMovementList(LittleEndianWriter lew, List moves) { + lew.write(moves.size()); + for (LifeMovementFragment move : moves) { + move.serialize(lew); + } + } + + public static byte[] movePlayer(int cid, List moves) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MOVE_PLAYER.getValue()); + mplew.writeInt(cid); + mplew.writeInt(0); + serializeMovementList(mplew, moves); + return mplew.getPacket(); + } + + public static byte[] moveSummon(int cid, int oid, Point startPos, List moves) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MOVE_SUMMON.getValue()); + mplew.writeInt(cid); + mplew.writeInt(oid); + mplew.writePos(startPos); + serializeMovementList(mplew, moves); + return mplew.getPacket(); + } + + public static byte[] moveMonster(int oid, boolean skillPossible, int skill, int skillId, int skillLevel, int pOption, Point startPos, List moves) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MOVE_MONSTER.getValue()); + mplew.writeInt(oid); + mplew.write(0); + mplew.writeBool(skillPossible); + mplew.write(skill); + mplew.write(skillId); + mplew.write(skillLevel); + mplew.writeShort(pOption); + mplew.writePos(startPos); + serializeMovementList(mplew, moves); + return mplew.getPacket(); + } + + public static byte[] summonAttack(int cid, int summonOid, byte direction, List allDamage) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + //b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00 + mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue()); + mplew.writeInt(cid); + mplew.writeInt(summonOid); + mplew.write(0); // char level + mplew.write(direction); + mplew.write(allDamage.size()); + for (SummonAttackEntry attackEntry : allDamage) { + mplew.writeInt(attackEntry.getMonsterOid()); // oid + mplew.write(6); // who knows + mplew.writeInt(attackEntry.getDamage()); // damage + } + + return mplew.getPacket(); + } + + /* + public static byte[] summonAttack(int cid, int summonSkillId, byte direction, List allDamage) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + //b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00 + mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue()); + mplew.writeInt(cid); + mplew.writeInt(summonSkillId); + mplew.write(direction); + mplew.write(4); + mplew.write(allDamage.size()); + for (SummonAttackEntry attackEntry : allDamage) { + mplew.writeInt(attackEntry.getMonsterOid()); // oid + mplew.write(6); // who knows + mplew.writeInt(attackEntry.getDamage()); // damage + } + return mplew.getPacket(); + } + */ + public static byte[] closeRangeAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map> damage, int speed, int direction, int display) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CLOSE_RANGE_ATTACK.getValue()); + addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display); + return mplew.getPacket(); + } + + public static byte[] rangedAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map> damage, int speed, int direction, int display) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.RANGED_ATTACK.getValue()); + addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, projectile, damage, speed, direction, display); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] magicAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map> damage, int charge, int speed, int direction, int display) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MAGIC_ATTACK.getValue()); + addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display); + if (charge != -1) { + mplew.writeInt(charge); + } + return mplew.getPacket(); + } + + private static void addAttackBody(LittleEndianWriter lew, MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map> damage, int speed, int direction, int display) { + lew.writeInt(chr.getId()); + lew.write(numAttackedAndDamage); + lew.write(0x5B);//? + lew.write(skilllevel); + if (skilllevel > 0) { + lew.writeInt(skill); + } + lew.write(display); + lew.write(direction); + lew.write(stance); + lew.write(speed); + lew.write(0x0A); + lew.writeInt(projectile); + for (Integer oned : damage.keySet()) { + List onedList = damage.get(oned); + if (onedList != null) { + lew.writeInt(oned.intValue()); + lew.write(0x0); + if (skill == 4211006) { + lew.write(onedList.size()); + } + for (Integer eachd : onedList) { + lew.writeInt(eachd.intValue()); + } + } + } + } + + public static byte[] throwGrenade(int cid, Point p, int keyDown, int skillId, int skillLevel) { // packets found thanks to GabrielSin + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.THROW_GRENADE.getValue()); + mplew.writeInt(cid); + mplew.writeInt(p.x); + mplew.writeInt(p.y); + mplew.writeInt(keyDown); + mplew.writeInt(skillId); + mplew.writeInt(skillLevel); + return mplew.getPacket(); + } + + // someone thought it was a good idea to handle floating point representation through packets ROFL + private static int doubleToShortBits(double d) { + return (int) (Double.doubleToLongBits(d) >> 48); + } + + public static byte[] getNPCShop(MapleClient c, int sid, List items) { + MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.OPEN_NPC_SHOP.getValue()); + mplew.writeInt(sid); + mplew.writeShort(items.size()); // item count + for (MapleShopItem item : items) { + mplew.writeInt(item.getItemId()); + mplew.writeInt(item.getPrice()); + mplew.writeInt(item.getPrice() == 0 ? item.getPitch() : 0); //Perfect Pitch + mplew.writeInt(0); //Can be used x minutes after purchase + mplew.writeInt(0); //Hmm + if (!ItemConstants.isRechargeable(item.getItemId())) { + mplew.writeShort(1); // stacksize o.o + mplew.writeShort(item.getBuyable()); + } else { + mplew.writeShort(0); + mplew.writeInt(0); + mplew.writeShort(doubleToShortBits(ii.getUnitPrice(item.getItemId()))); + mplew.writeShort(ii.getSlotMax(c, item.getItemId())); + } + } + return mplew.getPacket(); + } + + /* 00 = / + * 01 = You don't have enough in stock + * 02 = You do not have enough mesos + * 03 = Please check if your inventory is full or not + * 05 = You don't have enough in stock + * 06 = Due to an error, the trade did not happen + * 07 = Due to an error, the trade did not happen + * 08 = / + * 0D = You need more items + * 0E = CRASH; LENGTH NEEDS TO BE LONGER :O + */ + public static byte[] shopTransaction(byte code) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.CONFIRM_SHOP_TRANSACTION.getValue()); + mplew.write(code); + return mplew.getPacket(); + } + + public static byte[] updateInventorySlotLimit(int type, int newLimit) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.INVENTORY_GROW.getValue()); + mplew.write(type); + mplew.write(newLimit); + return mplew.getPacket(); + } + + public static byte[] modifyInventory(boolean updateTick, final List mods) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.INVENTORY_OPERATION.getValue()); + mplew.writeBool(updateTick); + mplew.write(mods.size()); + //mplew.write(0); v104 :) + int addMovement = -1; + for (ModifyInventory mod : mods) { + mplew.write(mod.getMode()); + mplew.write(mod.getInventoryType()); + mplew.writeShort(mod.getMode() == 2 ? mod.getOldPosition() : mod.getPosition()); + switch (mod.getMode()) { + case 0: {//add item + addItemInfo(mplew, mod.getItem(), true); + break; + } + case 1: {//update quantity + mplew.writeShort(mod.getQuantity()); + break; + } + case 2: {//move + mplew.writeShort(mod.getPosition()); + if (mod.getPosition() < 0 || mod.getOldPosition() < 0) { + addMovement = mod.getOldPosition() < 0 ? 1 : 2; + } + break; + } + case 3: {//remove + if (mod.getPosition() < 0) { + addMovement = 2; + } + break; + } + } + mod.clear(); + } + if (addMovement > -1) { + mplew.write(addMovement); + } + return mplew.getPacket(); + } + + public static byte[] getScrollEffect(int chr, ScrollResult scrollSuccess, boolean legendarySpirit) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_SCROLL_EFFECT.getValue()); + mplew.writeInt(chr); + switch (scrollSuccess) { + case SUCCESS: + mplew.writeShort(1); + mplew.writeShort(legendarySpirit ? 1 : 0); + break; + case FAIL: + mplew.writeShort(0); + mplew.writeShort(legendarySpirit ? 1 : 0); + break; + case CURSE: mplew.write(0); - return mplew.getPacket(); + mplew.write(1); + mplew.writeShort(legendarySpirit ? 1 : 0); + break; } + return mplew.getPacket(); + } - public static byte[] getPlayerShopChat(MapleCharacter c, String chat, byte slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); - mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); + public static byte[] removePlayerFromMap(int cid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.REMOVE_PLAYER_FROM_MAP.getValue()); + mplew.writeInt(cid); + return mplew.getPacket(); + } + + public static byte[] silentRemoveItemFromMap(int oid) { + return removeItemFromMap(oid, 1, 0); + } + + /** + * animation: 0 - expire
1 - without animation
2 - pickup
4 - + * explode
cid is ignored for 0 and 1 + * + * @param oid + * @param animation + * @param cid + * @return + */ + public static byte[] removeItemFromMap(int oid, int animation, int cid) { + return removeItemFromMap(oid, animation, cid, false, 0); + } + + /** + * animation: 0 - expire
1 - without animation
2 - pickup
4 - + * explode
cid is ignored for 0 and 1.

Flagging pet as true + * will make a pet pick up the item. + * + * @param oid + * @param animation + * @param cid + * @param pet + * @param slot + * @return + */ + public static byte[] removeItemFromMap(int oid, int animation, int cid, boolean pet, int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.REMOVE_ITEM_FROM_MAP.getValue()); + mplew.write(animation); // expire + mplew.writeInt(oid); + if (animation >= 2) { + mplew.writeInt(cid); + if (pet) { mplew.write(slot); - mplew.writeMapleAsciiString(c.getName() + " : " + chat); - return mplew.getPacket(); + } + } + return mplew.getPacket(); + } + + public static byte[] updateCharLook(MapleClient target, MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_CHAR_LOOK.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(1); + addCharLook(mplew, chr, false); + addRingLook(mplew, chr, true); + addRingLook(mplew, chr, false); + addMarriageRingLook(target, mplew, chr); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] damagePlayer(int skill, int monsteridfrom, int cid, int damage, int fake, int direction, boolean pgmr, int pgmr_1, boolean is_pg, int oid, int pos_x, int pos_y) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DAMAGE_PLAYER.getValue()); + mplew.writeInt(cid); + mplew.write(skill); + mplew.writeInt(damage); + if (skill != -4) { + mplew.writeInt(monsteridfrom); + mplew.write(direction); + if (pgmr) { + mplew.write(pgmr_1); + mplew.write(is_pg ? 1 : 0); + mplew.writeInt(oid); + mplew.write(6); + mplew.writeShort(pos_x); + mplew.writeShort(pos_y); + mplew.write(0); + } else { + mplew.writeShort(0); + } + mplew.writeInt(damage); + if (fake > 0) { + mplew.writeInt(fake); + } + } else { + mplew.writeInt(damage); } - public static byte[] getTradeChat(MapleCharacter c, String chat, boolean owner) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); - mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); - mplew.write(owner ? 0 : 1); - mplew.writeMapleAsciiString(c.getName() + " : " + chat); - return mplew.getPacket(); + return mplew.getPacket(); + } + + public static byte[] sendMapleLifeCharacterInfo() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MAPLELIFE_RESULT.getValue()); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] sendMapleLifeNameError() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MAPLELIFE_RESULT.getValue()); + mplew.writeInt(2); + mplew.writeInt(3); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] sendMapleLifeError(int code) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MAPLELIFE_ERROR.getValue()); + mplew.write(0); + mplew.writeInt(code); + return mplew.getPacket(); + } + + public static byte[] charNameResponse(String charname, boolean nameUsed) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CHAR_NAME_RESPONSE.getValue()); + mplew.writeMapleAsciiString(charname); + mplew.write(nameUsed ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] addNewCharEntry(MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ADD_NEW_CHAR_ENTRY.getValue()); + mplew.write(0); + addCharEntry(mplew, chr, false); + return mplew.getPacket(); + } + + /** + * state 0 = del ok state 12 = invalid bday state 14 = incorrect pic + * + * @param cid + * @param state + * @return + */ + public static byte[] deleteCharResponse(int cid, int state) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DELETE_CHAR_RESPONSE.getValue()); + mplew.writeInt(cid); + mplew.write(state); + return mplew.getPacket(); + } + + public static byte[] selectWorld(int world) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.LAST_CONNECTED_WORLD.getValue()); + mplew.writeInt(world);//According to GMS, it should be the world that contains the most characters (most active) + return mplew.getPacket(); + } + + public static byte[] sendRecommended(List> worlds) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.RECOMMENDED_WORLD_MESSAGE.getValue()); + mplew.write(worlds.size());//size + for (Iterator> it = worlds.iterator(); it.hasNext();) { + Pair world = it.next(); + mplew.writeInt(world.getLeft()); + mplew.writeMapleAsciiString(world.getRight()); + } + return mplew.getPacket(); + } + + /** + * + * @param chr + * @param isSelf + * @return + */ + public static byte[] charInfo(MapleCharacter chr) { + //3D 00 0A 43 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CHAR_INFO.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(chr.getLevel()); + mplew.writeShort(chr.getJob().getId()); + mplew.writeShort(chr.getFame()); + mplew.write(chr.getMarriageRing() != null ? 1 : 0); + String guildName = ""; + String allianceName = ""; + if (chr.getGuildId() > 0) { + MapleGuild mg = Server.getInstance().getGuild(chr.getGuildId()); + guildName = mg.getName(); + + MapleAlliance alliance = Server.getInstance().getAlliance(chr.getGuild().getAllianceId()); + if (alliance != null) { + allianceName = alliance.getName(); + } + } + mplew.writeMapleAsciiString(guildName); + mplew.writeMapleAsciiString(allianceName); // does not seem to work + mplew.write(0); // pMedalInfo, thanks to Arnah (Vertisy) + + MaplePet[] pets = chr.getPets(); + Item inv = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -114); + for (int i = 0; i < 3; i++) { + if (pets[i] != null) { + mplew.write(pets[i].getUniqueId()); + mplew.writeInt(pets[i].getItemId()); // petid + mplew.writeMapleAsciiString(pets[i].getName()); + mplew.write(pets[i].getLevel()); // pet level + mplew.writeShort(pets[i].getCloseness()); // pet closeness + mplew.write(pets[i].getFullness()); // pet fullness + mplew.writeShort(0); + mplew.writeInt(inv != null ? inv.getItemId() : 0); + } + } + mplew.write(0); //end of pets + + Item mount; //mounts can potentially crash the client if the player's level is not properly checked + if (chr.getMount() != null && (mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18)) != null && MapleItemInformationProvider.getInstance().getEquipLevelReq(mount.getItemId()) <= chr.getLevel()) { + MapleMount mmount = chr.getMount(); + mplew.write(mmount.getId()); //mount + mplew.writeInt(mmount.getLevel()); //level + mplew.writeInt(mmount.getExp()); //exp + mplew.writeInt(mmount.getTiredness()); //tiredness + } else { + mplew.write(0); + } + mplew.write(chr.getCashShop().getWishList().size()); + for (int sn : chr.getCashShop().getWishList()) { + mplew.writeInt(sn); } - public static byte[] hiredMerchantBox() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header. - mplew.write(0x07); - return mplew.getPacket(); + MonsterBook book = chr.getMonsterBook(); + mplew.writeInt(book.getBookLevel()); + mplew.writeInt(book.getNormalCard()); + mplew.writeInt(book.getSpecialCard()); + mplew.writeInt(book.getTotalCards()); + mplew.writeInt(chr.getMonsterBookCover() > 0 ? MapleItemInformationProvider.getInstance().getCardMobId(chr.getMonsterBookCover()) : 0); + Item medal = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -49); + if (medal != null) { + mplew.writeInt(medal.getItemId()); + } else { + mplew.writeInt(0); } + ArrayList medalQuests = new ArrayList<>(); + List completed = chr.getCompletedQuests(); + for (MapleQuestStatus q : completed) { + if (q.getQuest().getId() >= 29000) { // && q.getQuest().getId() <= 29923 + medalQuests.add(q.getQuest().getId()); + } + } + + Collections.sort(medalQuests); + mplew.writeShort(medalQuests.size()); + for (Short s : medalQuests) { + mplew.writeShort(s); + } + return mplew.getPacket(); + } + + /** + * It is important that statups is in the correct order (see declaration + * order in MapleBuffStat) since this method doesn't do automagical + * reordering. + * + * @param buffid + * @param bufflength + * @param statups + * @return + */ + //1F 00 00 00 00 00 03 00 00 40 00 00 00 E0 00 00 00 00 00 00 00 00 E0 01 8E AA 4F 00 00 C2 EB 0B E0 01 8E AA 4F 00 00 C2 EB 0B 0C 00 8E AA 4F 00 00 C2 EB 0B 44 02 8E AA 4F 00 00 C2 EB 0B 44 02 8E AA 4F 00 00 C2 EB 0B 00 00 E0 7A 1D 00 8E AA 4F 00 00 00 00 00 00 00 00 03 + public static byte[] giveBuff(int buffid, int bufflength, List> statups) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); + boolean special = false; + writeLongMask(mplew, statups); + for (Pair statup : statups) { + if (statup.getLeft().equals(MapleBuffStat.MONSTER_RIDING) || statup.getLeft().equals(MapleBuffStat.HOMING_BEACON)) { + special = true; + } + mplew.writeShort(statup.getRight().shortValue()); + mplew.writeInt(buffid); + mplew.writeInt(bufflength); + } + mplew.writeInt(0); + mplew.write(0); + mplew.writeInt(statups.get(0).getRight()); //Homing beacon ... + + if (special) { + mplew.skip(3); + } + return mplew.getPacket(); + } + + /** + * + * @param cid + * @param statups + * @param mount + * @return + */ + public static byte[] showMonsterRiding(int cid, MapleMount mount) { //Gtfo with this, this is just giveForeignBuff + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + mplew.writeLong(MapleBuffStat.MONSTER_RIDING.getValue()); + mplew.writeLong(0); + mplew.writeShort(0); + mplew.writeInt(mount.getItemId()); + mplew.writeInt(mount.getSkillId()); + mplew.writeInt(0); //Server Tick value. + mplew.writeShort(0); + mplew.write(0); //Times you have been buffed + return mplew.getPacket(); + } + /* mplew.writeInt(cid); + writeLongMask(mplew, statups); + for (Pair statup : statups) { + if (morph) { + mplew.writeInt(statup.getRight().intValue()); + } else { + mplew.writeShort(statup.getRight().shortValue()); + } + } + mplew.writeShort(0); + mplew.write(0);*/ + + /** + * + * @param c + * @param quest + * @return + */ + public static byte[] forfeitQuest(short quest) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(1); + mplew.writeShort(quest); + mplew.write(0); + return mplew.getPacket(); + } + + /** + * + * @param c + * @param quest + * @return + */ + public static byte[] completeQuest(short quest, long time) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(1); + mplew.writeShort(quest); + mplew.write(2); + mplew.writeLong(getTime(time)); + return mplew.getPacket(); + } + + /** + * + * @param c + * @param quest + * @param npc + * @param progress + * @return + */ + public static byte[] updateQuestInfo(short quest, int npc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); + mplew.write(8); //0x0A in v95 + mplew.writeShort(quest); + mplew.writeInt(npc); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] addQuestTimeLimit(final short quest, final int time) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); + mplew.write(6); + mplew.writeShort(1);//Size but meh, when will there be 2 at the same time? And it won't even replace the old one :) + mplew.writeShort(quest); + mplew.writeInt(time); + return mplew.getPacket(); + } + + public static byte[] removeQuestTimeLimit(final short quest) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); + mplew.write(7); + mplew.writeShort(1);//Position + mplew.writeShort(quest); + return mplew.getPacket(); + } + + public static byte[] updateQuest(MapleQuestStatus q, boolean infoUpdate) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(1); + mplew.writeShort(infoUpdate ? q.getQuest().getInfoNumber() : q.getQuest().getId()); + if (infoUpdate) { + mplew.write(1); + } else { + mplew.write(q.getStatus().getId()); + } + + mplew.writeMapleAsciiString(q.getQuestData()); + mplew.skip(5); + return mplew.getPacket(); + } + + private static void writeLongMaskD(final MaplePacketLittleEndianWriter mplew, List> statups) { + long firstmask = 0; + long secondmask = 0; + for (Pair statup : statups) { + if (statup.getLeft().isFirst()) { + firstmask |= statup.getLeft().getValue(); + } else { + secondmask |= statup.getLeft().getValue(); + } + } + mplew.writeLong(firstmask); + mplew.writeLong(secondmask); + } + + public static byte[] giveDebuff(List> statups, MobSkill skill) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); + writeLongMaskD(mplew, statups); + for (Pair statup : statups) { + mplew.writeShort(statup.getRight().shortValue()); + mplew.writeShort(skill.getSkillId()); + mplew.writeShort(skill.getSkillLevel()); + mplew.writeInt((int) skill.getDuration()); + } + mplew.writeShort(0); // ??? wk charges have 600 here o.o + mplew.writeShort(900);//Delay + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] giveForeignDebuff(int cid, List> statups, MobSkill skill) { + // Poison damage visibility and missing diseases status visibility, extended through map transitions thanks to Ronan + + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMaskD(mplew, statups); + for (Pair statup : statups) { + if (statup.getLeft() == MapleDisease.POISON) { + mplew.writeShort(statup.getRight().shortValue()); + } + mplew.writeShort(skill.getSkillId()); + mplew.writeShort(skill.getSkillLevel()); + } + mplew.writeShort(0); // same as give_buff + mplew.writeShort(900);//Delay + return mplew.getPacket(); + } + + public static byte[] cancelForeignDebuff(int cid, long mask) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + mplew.writeLong(0); + mplew.writeLong(mask); + return mplew.getPacket(); + } + + public static byte[] giveForeignBuff(int cid, List> statups) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMask(mplew, statups); + for (Pair statup : statups) { + mplew.writeShort(statup.getRight().shortValue()); + } + mplew.writeInt(0); + mplew.writeShort(0); + return mplew.getPacket(); + } + + public static byte[] cancelForeignBuff(int cid, List statups) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMaskFromList(mplew, statups); + return mplew.getPacket(); + } + + public static byte[] cancelBuff(List statups) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_BUFF.getValue()); + writeLongMaskFromList(mplew, statups); + mplew.write(1);//? + return mplew.getPacket(); + } + + private static void writeLongMask(final MaplePacketLittleEndianWriter mplew, List> statups) { + long firstmask = 0; + long secondmask = 0; + for (Pair statup : statups) { + if (statup.getLeft().isFirst()) { + firstmask |= statup.getLeft().getValue(); + } else { + secondmask |= statup.getLeft().getValue(); + } + } + mplew.writeLong(firstmask); + mplew.writeLong(secondmask); + } + + private static void writeLongMaskFromList(final MaplePacketLittleEndianWriter mplew, List statups) { + long firstmask = 0; + long secondmask = 0; + for (MapleBuffStat statup : statups) { + if (statup.isFirst()) { + firstmask |= statup.getValue(); + } else { + secondmask |= statup.getValue(); + } + } + mplew.writeLong(firstmask); + mplew.writeLong(secondmask); + } + + public static byte[] cancelDebuff(long mask) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); + mplew.writeShort(SendOpcode.CANCEL_BUFF.getValue()); + mplew.writeLong(0); + mplew.writeLong(mask); + mplew.write(0); + return mplew.getPacket(); + } + + private static void writeLongMaskSlowD(final MaplePacketLittleEndianWriter mplew) { + mplew.writeInt(0); + mplew.writeInt(2048); + mplew.writeLong(0); + } + + public static byte[] giveForeignSlowDebuff(int cid, List> statups, MobSkill skill) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMaskSlowD(mplew); + for (Pair statup : statups) { + if (statup.getLeft() == MapleDisease.POISON) { + mplew.writeShort(statup.getRight().shortValue()); + } + mplew.writeShort(skill.getSkillId()); + mplew.writeShort(skill.getSkillLevel()); + } + mplew.writeShort(0); // same as give_buff + mplew.writeShort(900);//Delay + return mplew.getPacket(); + } + + public static byte[] cancelForeignSlowDebuff(int cid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMaskSlowD(mplew); + return mplew.getPacket(); + } + + private static void writeLongMaskChair(final MaplePacketLittleEndianWriter mplew) { + mplew.writeInt(0); + mplew.writeInt(262144); + mplew.writeLong(0); + } + + public static byte[] giveForeignChairSkillEffect(int cid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMaskChair(mplew); + + mplew.writeShort(0); + mplew.writeShort(0); + mplew.writeShort(100); + mplew.writeShort(1); + + mplew.writeShort(0); + mplew.writeShort(900); + + for (int i = 0; i < 7; i++) { + mplew.write(0); + } + + return mplew.getPacket(); + } + + public static byte[] cancelForeignChairSkillEffect(int cid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); + mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMaskChair(mplew); + + return mplew.getPacket(); + } + + public static byte[] getPlayerShopChat(MapleCharacter c, String chat, boolean owner) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); + mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); + mplew.write(owner ? 0 : 1); + mplew.writeMapleAsciiString(c.getName() + " : " + chat); + return mplew.getPacket(); + } + + public static byte[] getPlayerShopNewVisitor(MapleCharacter c, int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); + mplew.write(slot); + addCharLook(mplew, c, false); + mplew.writeMapleAsciiString(c.getName()); + return mplew.getPacket(); + } + + public static byte[] getPlayerShopRemoveVisitor(int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + if (slot != 0) { + mplew.writeShort(slot); + } + return mplew.getPacket(); + } + + public static byte[] getTradePartnerAdd(MapleCharacter c) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); + mplew.write(1); + addCharLook(mplew, c, false); + mplew.writeMapleAsciiString(c.getName()); + return mplew.getPacket(); + } + + public static byte[] getTradeInvite(MapleCharacter c) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.INVITE.getCode()); + mplew.write(3); + mplew.writeMapleAsciiString(c.getName()); + mplew.write(new byte[]{(byte) 0xB7, (byte) 0x50, 0, 0}); + return mplew.getPacket(); + } + + public static byte[] getTradeMesoSet(byte number, int meso) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.SET_MESO.getCode()); + mplew.write(number); + mplew.writeInt(meso); + return mplew.getPacket(); + } + + public static byte[] getTradeItemAdd(byte number, Item item) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.SET_ITEMS.getCode()); + mplew.write(number); + mplew.write(item.getPosition()); + addItemInfo(mplew, item, true); + return mplew.getPacket(); + } + + public static byte[] getPlayerShopItemUpdate(MaplePlayerShop shop) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.UPDATE_MERCHANT.getCode()); + mplew.write(shop.getItems().size()); + for (MaplePlayerShopItem item : shop.getItems()) { + mplew.writeShort(item.getBundles()); + mplew.writeShort(item.getItem().getQuantity()); + mplew.writeInt(item.getPrice()); + addItemInfo(mplew, item.getItem(), true); + } + return mplew.getPacket(); + } + + public static byte[] getPlayerShopOwnerUpdate(MaplePlayerShop.SoldItem item, int position) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.UPDATE_PLAYERSHOP.getCode()); + mplew.write(position); + mplew.writeShort(item.getQuantity()); + mplew.writeMapleAsciiString(item.getBuyer()); + + return mplew.getPacket(); + } + + /** + * + * @param c + * @param shop + * @param owner + * @return + */ + public static byte[] getPlayerShop(MaplePlayerShop shop, boolean owner) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(4); + mplew.write(4); + mplew.write(owner ? 0 : 1); + + if (owner) { + List sold = shop.getSold(); + mplew.write(sold.size()); + for (MaplePlayerShop.SoldItem s : sold) { + mplew.writeInt(s.getItemId()); + mplew.writeShort(s.getQuantity()); + mplew.writeInt(s.getMesos()); + mplew.writeMapleAsciiString(s.getBuyer()); + } + } else { + mplew.write(0); + } + + addCharLook(mplew, shop.getOwner(), false); + mplew.writeMapleAsciiString(shop.getOwner().getName()); + + MapleCharacter visitors[] = shop.getVisitors(); + for (int i = 0; i < 3; i++) { + if (visitors[i] != null) { + mplew.write(i + 1); + addCharLook(mplew, visitors[i], false); + mplew.writeMapleAsciiString(visitors[i].getName()); + } + } + + mplew.write(0xFF); + mplew.writeMapleAsciiString(shop.getDescription()); + List items = shop.getItems(); + mplew.write(0x10); //TODO SLOTS, which is 16 for most stores...slotMax + mplew.write(items.size()); + for (MaplePlayerShopItem item : items) { + mplew.writeShort(item.getBundles()); + mplew.writeShort(item.getItem().getQuantity()); + mplew.writeInt(item.getPrice()); + addItemInfo(mplew, item.getItem(), true); + } + return mplew.getPacket(); + } + + public static byte[] getTradeStart(MapleClient c, MapleTrade trade, byte number) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(3); + mplew.write(2); + mplew.write(number); + if (number == 1) { + mplew.write(0); + addCharLook(mplew, trade.getPartner().getChr(), false); + mplew.writeMapleAsciiString(trade.getPartner().getChr().getName()); + } + mplew.write(number); + addCharLook(mplew, c.getPlayer(), false); + mplew.writeMapleAsciiString(c.getPlayer().getName()); + mplew.write(0xFF); + return mplew.getPacket(); + } + + public static byte[] getTradeConfirmation() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.CONFIRM.getCode()); + return mplew.getPacket(); + } + + public static byte[] getTradeCompletion(byte number) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + mplew.write(number); + mplew.write(6); + return mplew.getPacket(); + } + + public static byte[] getTradeCancel(byte number) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + mplew.write(number); + mplew.write(2); + return mplew.getPacket(); + } + + /** + * Possible values for speaker:
0: Npc talking (left)
+ * 1: Npc talking (right)
2: Player talking (left)
3: Player talking + * (left)
+ * + * @param npc Npcid + * @param msgType + * @param talk + * @param endBytes + * @param speaker + * @return + */ + public static byte[] getNPCTalk(int npc, byte msgType, String talk, String endBytes, byte speaker) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NPC_TALK.getValue()); + mplew.write(4); // ? + mplew.writeInt(npc); + mplew.write(msgType); + mplew.write(speaker); + mplew.writeMapleAsciiString(talk); + mplew.write(HexTool.getByteArrayFromHexString(endBytes)); + return mplew.getPacket(); + } + + public static byte[] getDimensionalMirror(String talk) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NPC_TALK.getValue()); + mplew.write(4); // ? + mplew.writeInt(9010022); + mplew.write(0x0E); + mplew.write(0); + mplew.writeInt(0); + mplew.writeMapleAsciiString(talk); + return mplew.getPacket(); + } + + public static byte[] getNPCTalkStyle(int npc, String talk, int styles[]) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NPC_TALK.getValue()); + mplew.write(4); // ? + mplew.writeInt(npc); + mplew.write(7); + mplew.write(0); //speaker + mplew.writeMapleAsciiString(talk); + mplew.write(styles.length); + for (int i = 0; i < styles.length; i++) { + mplew.writeInt(styles[i]); + } + return mplew.getPacket(); + } + + public static byte[] getNPCTalkNum(int npc, String talk, int def, int min, int max) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NPC_TALK.getValue()); + mplew.write(4); // ? + mplew.writeInt(npc); + mplew.write(3); + mplew.write(0); //speaker + mplew.writeMapleAsciiString(talk); + mplew.writeInt(def); + mplew.writeInt(min); + mplew.writeInt(max); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] getNPCTalkText(int npc, String talk, String def) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NPC_TALK.getValue()); + mplew.write(4); // Doesn't matter + mplew.writeInt(npc); + mplew.write(2); + mplew.write(0); //speaker + mplew.writeMapleAsciiString(talk); + mplew.writeMapleAsciiString(def);//:D + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] showBuffeffect(int cid, int skillid, int effectid) { + return showBuffeffect(cid, skillid, effectid, (byte) 3); + } + + public static byte[] showBuffeffect(int cid, int skillid, int effectid, byte direction) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(effectid); //buff level + mplew.writeInt(skillid); + mplew.write(direction); + mplew.write(1); + mplew.writeLong(0); + return mplew.getPacket(); + } + + public static byte[] showBuffeffect(int cid, int skillid, int skilllv, int effectid, byte direction) { // updated packet structure found thanks to Rien dev team + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(effectid); + mplew.writeInt(skillid); + mplew.write(0); + mplew.write(skilllv); + mplew.write(direction); + + return mplew.getPacket(); + } + + public static byte[] showOwnBuffEffect(int skillid, int effectid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(effectid); + mplew.writeInt(skillid); + mplew.write(0xA9); + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] showOwnBerserk(int skilllevel, boolean Berserk) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(1); + mplew.writeInt(1320006); + mplew.write(0xA9); + mplew.write(skilllevel); + mplew.write(Berserk ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] showBerserk(int cid, int skilllevel, boolean Berserk) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(1); + mplew.writeInt(1320006); + mplew.write(0xA9); + mplew.write(skilllevel); + mplew.write(Berserk ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] updateSkill(int skillid, int level, int masterlevel, long expiration) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_SKILLS.getValue()); + mplew.write(1); + mplew.writeShort(1); + mplew.writeInt(skillid); + mplew.writeInt(level); + mplew.writeInt(masterlevel); + addExpirationTime(mplew, expiration); + mplew.write(4); + return mplew.getPacket(); + } + + public static byte[] getShowQuestCompletion(int id) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.QUEST_CLEAR.getValue()); + mplew.writeShort(id); + return mplew.getPacket(); + } + + public static byte[] getKeymap(Map keybindings) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.KEYMAP.getValue()); + mplew.write(0); + for (int x = 0; x < 90; x++) { + MapleKeyBinding binding = keybindings.get(Integer.valueOf(x)); + if (binding != null) { + mplew.write(binding.getType()); + mplew.writeInt(binding.getAction()); + } else { + mplew.write(0); + mplew.writeInt(0); + } + } + return mplew.getPacket(); + } + + public static byte[] getWhisper(String sender, int channel, String text) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.WHISPER.getValue()); + mplew.write(0x12); + mplew.writeMapleAsciiString(sender); + mplew.writeShort(channel - 1); // I guess this is the channel + mplew.writeMapleAsciiString(text); + return mplew.getPacket(); + } + + /** + * + * @param target name of the target character + * @param reply error code: 0x0 = cannot find char, 0x1 = success + * @return the MaplePacket + */ + public static byte[] getWhisperReply(String target, byte reply) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.WHISPER.getValue()); + mplew.write(0x0A); // whisper? + mplew.writeMapleAsciiString(target); + mplew.write(reply); + return mplew.getPacket(); + } + + public static byte[] getInventoryFull() { + return modifyInventory(true, Collections.emptyList()); + } + + public static byte[] getShowInventoryFull() { + return getShowInventoryStatus(0xff); + } + + public static byte[] showItemUnavailable() { + return getShowInventoryStatus(0xfe); + } + + public static byte[] getShowInventoryStatus(int mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(0); + mplew.write(mode); + mplew.writeInt(0); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] getStorage(int npcId, byte slots, Collection items, int meso) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STORAGE.getValue()); + mplew.write(0x16); + mplew.writeInt(npcId); + mplew.write(slots); + mplew.writeShort(0x7E); + mplew.writeShort(0); + mplew.writeInt(0); + mplew.writeInt(meso); + mplew.writeShort(0); + mplew.write((byte) items.size()); + for (Item item : items) { + addItemInfo(mplew, item, true); + } + mplew.writeShort(0); + mplew.write(0); + return mplew.getPacket(); + } + + /* + * 0x0A = Inv full + * 0x0B = You do not have enough mesos + * 0x0C = One-Of-A-Kind error + */ + public static byte[] getStorageError(byte i) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STORAGE.getValue()); + mplew.write(i); + return mplew.getPacket(); + } + + public static byte[] mesoStorage(byte slots, int meso) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STORAGE.getValue()); + mplew.write(0x13); + mplew.write(slots); + mplew.writeShort(2); + mplew.writeShort(0); + mplew.writeInt(0); + mplew.writeInt(meso); + return mplew.getPacket(); + } + + public static byte[] storeStorage(byte slots, MapleInventoryType type, Collection items) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STORAGE.getValue()); + mplew.write(0xD); + mplew.write(slots); + mplew.writeShort(type.getBitfieldEncoding()); + mplew.writeShort(0); + mplew.writeInt(0); + mplew.write(items.size()); + for (Item item : items) { + addItemInfo(mplew, item, true); + } + return mplew.getPacket(); + } + + public static byte[] takeOutStorage(byte slots, MapleInventoryType type, Collection items) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STORAGE.getValue()); + mplew.write(0x9); + mplew.write(slots); + mplew.writeShort(type.getBitfieldEncoding()); + mplew.writeShort(0); + mplew.writeInt(0); + mplew.write(items.size()); + for (Item item : items) { + addItemInfo(mplew, item, true); + } + return mplew.getPacket(); + } + + public static byte[] arrangeStorage(byte slots, Collection items) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + + mplew.writeShort(SendOpcode.STORAGE.getValue()); + mplew.write(0xF); + mplew.write(slots); + mplew.write(124); + for (byte i = 0; i < 10; i++) { + mplew.write(0); + } + mplew.write(items.size()); + for (Item item : items) { + addItemInfo(mplew, item, true); + } + mplew.write(0); + return mplew.getPacket(); + } + + /** + * + * @param oid + * @param remhppercentage + * @return + */ + public static byte[] showMonsterHP(int oid, int remhppercentage) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_MONSTER_HP.getValue()); + mplew.writeInt(oid); + mplew.write(remhppercentage); + return mplew.getPacket(); + } + + public static byte[] showBossHP(int oid, int currHP, int maxHP, byte tagColor, byte tagBgColor) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(5); + mplew.writeInt(oid); + mplew.writeInt(currHP); + mplew.writeInt(maxHP); + mplew.write(tagColor); + mplew.write(tagBgColor); + return mplew.getPacket(); + } + + private static Pair normalizedCustomMaxHP(long currHP, long maxHP) { + int sendHP, sendMaxHP; + + if (maxHP <= Integer.MAX_VALUE) { + sendHP = (int) currHP; + sendMaxHP = (int) maxHP; + } else { + float f = ((float) currHP) / maxHP; + + sendHP = (int) (Integer.MAX_VALUE * f); + sendMaxHP = Integer.MAX_VALUE; + } + + return new Pair<>(sendHP, sendMaxHP); + } + + public static byte[] customShowBossHP(byte call, int oid, long currHP, long maxHP, byte tagColor, byte tagBgColor) { + Pair customHP = normalizedCustomMaxHP(currHP, maxHP); + + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(call); + mplew.writeInt(oid); + mplew.writeInt(customHP.left); + mplew.writeInt(customHP.right); + mplew.write(tagColor); + mplew.write(tagBgColor); + return mplew.getPacket(); + } + + public static byte[] giveFameResponse(int mode, String charname, int newfame) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue()); + mplew.write(0); + mplew.writeMapleAsciiString(charname); + mplew.write(mode); + mplew.writeShort(newfame); + mplew.writeShort(0); + return mplew.getPacket(); + } + + /** + * status can be:
0: ok, use giveFameResponse
1: the username is + * incorrectly entered
2: users under level 15 are unable to toggle with + * fame.
3: can't raise or drop fame anymore today.
4: can't raise + * or drop fame for this character for this month anymore.
5: received + * fame, use receiveFame()
6: level of fame neither has been raised nor + * dropped due to an unexpected error + * + * @param status + * @return + */ + public static byte[] giveFameErrorResponse(int status) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue()); + mplew.write(status); + return mplew.getPacket(); + } + + public static byte[] receiveFame(int mode, String charnameFrom) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue()); + mplew.write(5); + mplew.writeMapleAsciiString(charnameFrom); + mplew.write(mode); + return mplew.getPacket(); + } + + public static byte[] partyCreated(MapleParty party, int partycharid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); + mplew.write(8); + mplew.writeInt(party.getId()); + + Map partyDoors = party.getDoors(); + if (partyDoors.size() > 0) { + MapleDoor door = partyDoors.get(partycharid); + + if (door != null) { + MapleDoorObject mdo = door.getAreaDoor(); + mplew.writeInt(mdo.getTo().getId()); + mplew.writeInt(mdo.getFrom().getId()); + mplew.writeInt(mdo.getPosition().x); + mplew.writeInt(mdo.getPosition().y); + } else { + mplew.writeInt(999999999); + mplew.writeInt(999999999); + mplew.writeInt(0); + mplew.writeInt(0); + } + } else { + mplew.writeInt(999999999); + mplew.writeInt(999999999); + mplew.writeInt(0); + mplew.writeInt(0); + } + return mplew.getPacket(); + } + + public static byte[] partyInvite(MapleCharacter from) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); + mplew.write(4); + mplew.writeInt(from.getParty().getId()); + mplew.writeMapleAsciiString(from.getName()); + mplew.write(0); + return mplew.getPacket(); + } + + /** + * 10: A beginner can't create a party. 1/5/6/11/14/19: Your request for a + * party didn't work due to an unexpected error. 12: Quit as leader of the + * party. 13: You have yet to join a party. 16: Already have joined a party. + * 17: The party you're trying to join is already in full capacity. 19: + * Unable to find the requested character in this channel. 21: Player is + * blocking any party invitations. 22: Player is taking care of another + * invitation. 23: Player denied request. 25: Cannot kick another user in + * this map. 28/29: Leadership can only be given to a party member in the + * vicinity. 30: Change leadership only on same channel. + * + * @param message + * @return + */ + public static byte[] partyStatusMessage(int message) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); + mplew.write(message); + return mplew.getPacket(); + } + + /** + * 23: 'Char' have denied request to the party. + * + * @param message + * @param charname + * @return + */ + public static byte[] partyStatusMessage(int message, String charname) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); + mplew.write(message); + mplew.writeMapleAsciiString(charname); + return mplew.getPacket(); + } + + private static void addPartyStatus(int forchannel, MapleParty party, LittleEndianWriter lew, boolean leaving) { + List partymembers = new ArrayList<>(party.getMembers()); + while (partymembers.size() < 6) { + partymembers.add(new MaplePartyCharacter()); + } + for (MaplePartyCharacter partychar : partymembers) { + lew.writeInt(partychar.getId()); + } + for (MaplePartyCharacter partychar : partymembers) { + lew.writeAsciiString(getRightPaddedStr(partychar.getName(), '\0', 13)); + } + for (MaplePartyCharacter partychar : partymembers) { + lew.writeInt(partychar.getJobId()); + } + for (MaplePartyCharacter partychar : partymembers) { + lew.writeInt(partychar.getLevel()); + } + for (MaplePartyCharacter partychar : partymembers) { + if (partychar.isOnline()) { + lew.writeInt(partychar.getChannel() - 1); + } else { + lew.writeInt(-2); + } + } + lew.writeInt(party.getLeader().getId()); + for (MaplePartyCharacter partychar : partymembers) { + if (partychar.getChannel() == forchannel) { + lew.writeInt(partychar.getMapId()); + } else { + lew.writeInt(0); + } + } + + Map partyDoors = party.getDoors(); + for (MaplePartyCharacter partychar : partymembers) { + if (partychar.getChannel() == forchannel && !leaving) { + if (partyDoors.size() > 0) { + MapleDoor door = partyDoors.get(partychar.getId()); + if (door != null) { + MapleDoorObject mdo = door.getTownDoor(); + lew.writeInt(mdo.getTown().getId()); + lew.writeInt(mdo.getArea().getId()); + lew.writeInt(mdo.getPosition().x); + lew.writeInt(mdo.getPosition().y); + } else { + lew.writeInt(999999999); + lew.writeInt(999999999); + lew.writeInt(0); + lew.writeInt(0); + } + } else { + lew.writeInt(999999999); + lew.writeInt(999999999); + lew.writeInt(0); + lew.writeInt(0); + } + } else { + lew.writeInt(999999999); + lew.writeInt(999999999); + lew.writeInt(0); + lew.writeInt(0); + } + } + } + + public static byte[] updateParty(int forChannel, MapleParty party, PartyOperation op, MaplePartyCharacter target) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); + switch (op) { + case DISBAND: + case EXPEL: + case LEAVE: + mplew.write(0x0C); + mplew.writeInt(party.getId()); + mplew.writeInt(target.getId()); + if (op == PartyOperation.DISBAND) { + mplew.write(0); + mplew.writeInt(party.getId()); + } else { + mplew.write(1); + if (op == PartyOperation.EXPEL) { + mplew.write(1); + } else { + mplew.write(0); + } + mplew.writeMapleAsciiString(target.getName()); + addPartyStatus(forChannel, party, mplew, false); + } + break; + case JOIN: + mplew.write(0xF); + mplew.writeInt(party.getId()); + mplew.writeMapleAsciiString(target.getName()); + addPartyStatus(forChannel, party, mplew, false); + break; + case SILENT_UPDATE: + case LOG_ONOFF: + mplew.write(0x7); + mplew.writeInt(party.getId()); + addPartyStatus(forChannel, party, mplew, false); + break; + case CHANGE_LEADER: + mplew.write(0x1B); + mplew.writeInt(target.getId()); + mplew.write(0); + break; + } + return mplew.getPacket(); + } + + public static byte[] partyPortal(int townId, int targetId, Point position) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); + mplew.writeShort(0x23); + mplew.writeInt(townId); + mplew.writeInt(targetId); + mplew.writePos(position); + return mplew.getPacket(); + } + + public static byte[] updatePartyMemberHP(int cid, int curhp, int maxhp) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_PARTYMEMBER_HP.getValue()); + mplew.writeInt(cid); + mplew.writeInt(curhp); + mplew.writeInt(maxhp); + return mplew.getPacket(); + } + + /** + * mode: 0 buddychat; 1 partychat; 2 guildchat + * + * @param name + * @param chattext + * @param mode + * @return + */ + public static byte[] multiChat(String name, String chattext, int mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MULTICHAT.getValue()); + mplew.write(mode); + mplew.writeMapleAsciiString(name); + mplew.writeMapleAsciiString(chattext); + return mplew.getPacket(); + } + + private static void writeIntMask(final MaplePacketLittleEndianWriter mplew, Map stats) { + int firstmask = 0; + int secondmask = 0; + for (MonsterStatus stat : stats.keySet()) { + if (stat.isFirst()) { + firstmask |= stat.getValue(); + } else { + secondmask |= stat.getValue(); + } + } + mplew.writeInt(firstmask); + mplew.writeInt(secondmask); + } + + public static byte[] applyMonsterStatus(int oid, Map stats, int skill, boolean monsterSkill, int delay, MobSkill mobskill) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.APPLY_MONSTER_STATUS.getValue()); + mplew.writeInt(oid); + int mask = 0; + for (MonsterStatus stat : stats.keySet()) { + mask |= stat.getValue(); + } + mplew.writeInt(mask); + for (Integer val : stats.values()) { + mplew.writeShort(val); + if (monsterSkill) { + mplew.writeShort(mobskill.getSkillId()); + mplew.writeShort(mobskill.getSkillLevel()); + } else { + mplew.writeInt(skill); + } + mplew.writeShort(0); // as this looks similar to giveBuff this + } + mplew.writeShort(delay); // delay in ms + mplew.write(1); // ? + return mplew.getPacket(); + } + + public static byte[] applyMonsterStatus(final int oid, final MonsterStatusEffect mse, final List reflection) { + Map stati = mse.getStati(); + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.APPLY_MONSTER_STATUS.getValue()); + mplew.writeInt(oid); + mplew.writeLong(0); + writeIntMask(mplew, stati); + for (Map.Entry stat : stati.entrySet()) { + mplew.writeShort(stat.getValue()); + if (mse.isMonsterSkill()) { + mplew.writeShort(mse.getMobSkill().getSkillId()); + mplew.writeShort(mse.getMobSkill().getSkillLevel()); + } else { + mplew.writeInt(mse.getSkill().getId()); + } + mplew.writeShort(-1); // might actually be the buffTime but it's not displayed anywhere + } + int size = stati.size(); // size + if (reflection != null) { + for (Integer ref : reflection) { + mplew.writeInt(ref); + } + if (reflection.size() > 0) { + size /= 2; // This gives 2 buffs per reflection but it's really one buff + } + } + mplew.write(size); // size + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] cancelMonsterStatus(int oid, Map stats) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_MONSTER_STATUS.getValue()); + mplew.writeInt(oid); + mplew.writeLong(0); + writeIntMask(mplew, stats); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] getClock(int time) { // time in seconds + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CLOCK.getValue()); + mplew.write(2); // clock type. if you send 3 here you have to send another byte (which does not matter at all) before the timestamp + mplew.writeInt(time); + return mplew.getPacket(); + } + + public static byte[] getClockTime(int hour, int min, int sec) { // Current Time + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CLOCK.getValue()); + mplew.write(1); //Clock-Type + mplew.write(hour); + mplew.write(min); + mplew.write(sec); + return mplew.getPacket(); + } + + public static byte[] removeClock() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STOP_CLOCK.getValue()); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] spawnMist(int oid, int ownerCid, int skill, int level, MapleMist mist) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_MIST.getValue()); + mplew.writeInt(oid); + mplew.writeInt(mist.isMobMist() ? 0 : mist.isPoisonMist() ? 1 : mist.isRecoveryMist() ? 4 : 2); // mob mist = 0, player poison = 1, smokescreen = 2, unknown = 3, recovery = 4 + mplew.writeInt(ownerCid); + mplew.writeInt(skill); + mplew.write(level); + mplew.writeShort(mist.getSkillDelay()); // Skill delay + mplew.writeInt(mist.getBox().x); + mplew.writeInt(mist.getBox().y); + mplew.writeInt(mist.getBox().x + mist.getBox().width); + mplew.writeInt(mist.getBox().y + mist.getBox().height); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] removeMist(int oid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.REMOVE_MIST.getValue()); + mplew.writeInt(oid); + return mplew.getPacket(); + } + + public static byte[] damageSummon(int cid, int oid, int damage, int monsterIdFrom) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DAMAGE_SUMMON.getValue()); + mplew.writeInt(cid); + mplew.writeInt(oid); + mplew.write(12); + mplew.writeInt(damage); // damage display doesn't seem to work... + mplew.writeInt(monsterIdFrom); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] damageMonster(int oid, int damage) { + return damageMonster(oid, damage, 0, 0); + } + + public static byte[] healMonster(int oid, int heal, int curhp, int maxhp) { + return damageMonster(oid, -heal, curhp, maxhp); + } + + private static byte[] damageMonster(int oid, int damage, int curhp, int maxhp) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DAMAGE_MONSTER.getValue()); + mplew.writeInt(oid); + mplew.write(0); + mplew.writeInt(damage); + mplew.writeInt(curhp); + mplew.writeInt(maxhp); + return mplew.getPacket(); + } + + public static byte[] updateBuddylist(Collection buddylist) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); + mplew.write(7); + mplew.write(buddylist.size()); + for (BuddylistEntry buddy : buddylist) { + if (buddy.isVisible()) { + mplew.writeInt(buddy.getCharacterId()); // cid + mplew.writeAsciiString(getRightPaddedStr(buddy.getName(), '\0', 13)); + mplew.write(0); // opposite status + mplew.writeInt(buddy.getChannel() - 1); + mplew.writeAsciiString(getRightPaddedStr(buddy.getGroup(), '\0', 13)); + mplew.writeInt(0);//mapid? + } + } + for (int x = 0; x < buddylist.size(); x++) { + mplew.writeInt(0);//mapid? + } + return mplew.getPacket(); + } + + public static byte[] buddylistMessage(byte message) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); + mplew.write(message); + return mplew.getPacket(); + } + + public static byte[] requestBuddylistAdd(int cidFrom, int cid, String nameFrom) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); + mplew.write(9); + mplew.writeInt(cidFrom); + mplew.writeMapleAsciiString(nameFrom); + mplew.writeInt(cidFrom); + mplew.writeAsciiString(getRightPaddedStr(nameFrom, '\0', 11)); + mplew.write(0x09); + mplew.write(0xf0); + mplew.write(0x01); + mplew.writeInt(0x0f); + mplew.writeNullTerminatedAsciiString("Default Group"); + mplew.writeInt(cid); + return mplew.getPacket(); + } + + public static byte[] updateBuddyChannel(int characterid, int channel) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); + mplew.write(0x14); + mplew.writeInt(characterid); + mplew.write(0); + mplew.writeInt(channel); + return mplew.getPacket(); + } + + public static byte[] itemEffect(int characterid, int itemid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_EFFECT.getValue()); + mplew.writeInt(characterid); + mplew.writeInt(itemid); + return mplew.getPacket(); + } + + public static byte[] updateBuddyCapacity(int capacity) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BUDDYLIST.getValue()); + mplew.write(0x15); + mplew.write(capacity); + return mplew.getPacket(); + } + + public static byte[] showChair(int characterid, int itemid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_CHAIR.getValue()); + mplew.writeInt(characterid); + mplew.writeInt(itemid); + return mplew.getPacket(); + } + + public static byte[] cancelChair(int id) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_CHAIR.getValue()); + if (id == -1) { + mplew.write(0); + } else { + mplew.write(1); + mplew.writeShort(id); + } + return mplew.getPacket(); + } + + // is there a way to spawn reactors non-animated? + public static byte[] spawnReactor(MapleReactor reactor) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + Point pos = reactor.getPosition(); + mplew.writeShort(SendOpcode.REACTOR_SPAWN.getValue()); + mplew.writeInt(reactor.getObjectId()); + mplew.writeInt(reactor.getId()); + mplew.write(reactor.getState()); + mplew.writePos(pos); + mplew.writeShort(0); + mplew.write(reactor.getFacingDirection()); // stance + return mplew.getPacket(); + } + + // is there a way to trigger reactors without performing the hit animation? + public static byte[] triggerReactor(MapleReactor reactor, int stance) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + Point pos = reactor.getPosition(); + mplew.writeShort(SendOpcode.REACTOR_HIT.getValue()); + mplew.writeInt(reactor.getObjectId()); + mplew.write(reactor.getState()); + mplew.writePos(pos); + mplew.writeShort(stance); + mplew.write(0); + mplew.write(5); // frame delay, set to 5 since there doesn't appear to be a fixed formula for it + return mplew.getPacket(); + } + + public static byte[] destroyReactor(MapleReactor reactor) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + Point pos = reactor.getPosition(); + mplew.writeShort(SendOpcode.REACTOR_DESTROY.getValue()); + mplew.writeInt(reactor.getObjectId()); + mplew.write(reactor.getState()); + mplew.writePos(pos); + return mplew.getPacket(); + } + + public static byte[] musicChange(String song) { + return environmentChange(song, 6); + } + + public static byte[] showEffect(String effect) { + return environmentChange(effect, 3); + } + + public static byte[] playSound(String sound) { + return environmentChange(sound, 4); + } + + public static byte[] environmentChange(String env, int mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(mode); + mplew.writeMapleAsciiString(env); + return mplew.getPacket(); + } + + public static byte[] environmentMove(String env, int mode) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + + mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ONOFF.getValue()); + mplew.writeMapleAsciiString(env); + mplew.writeInt(mode); // 0: stop and back to start, 1: move + + return mplew.getPacket(); + } + + public static byte[] environmentMoveList(Set> envList) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ONOFF_LIST.getValue()); + mplew.writeInt(envList.size()); + + for (Entry envMove : envList) { + mplew.writeMapleAsciiString(envMove.getKey()); + mplew.writeInt(envMove.getValue()); + } + + return mplew.getPacket(); + } + + public static byte[] environmentMoveReset() { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ALL_RESET.getValue()); + return mplew.getPacket(); + } + + public static byte[] startMapEffect(String msg, int itemid, boolean active) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); + mplew.write(active ? 0 : 1); + mplew.writeInt(itemid); + if (active) { + mplew.writeMapleAsciiString(msg); + } + return mplew.getPacket(); + } + + public static byte[] removeMapEffect() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); + mplew.write(0); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] mapEffect(String path) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(3); + mplew.writeMapleAsciiString(path); + return mplew.getPacket(); + } + + public static byte[] mapSound(String path) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(4); + mplew.writeMapleAsciiString(path); + return mplew.getPacket(); + } + + public static byte[] showGuildInfo(MapleCharacter c) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x1A); //signature for showing guild info + if (c == null) { //show empty guild (used for leaving, expelled) + mplew.write(0); + return mplew.getPacket(); + } + MapleGuild g = c.getClient().getWorldServer().getGuild(c.getMGC()); + if (g == null) { //failed to read from DB - don't show a guild + mplew.write(0); + return mplew.getPacket(); + } + mplew.write(1); //bInGuild + mplew.writeInt(g.getId()); + mplew.writeMapleAsciiString(g.getName()); + for (int i = 1; i <= 5; i++) { + mplew.writeMapleAsciiString(g.getRankTitle(i)); + } + Collection members = g.getMembers(); + mplew.write(members.size()); //then it is the size of all the members + for (MapleGuildCharacter mgc : members) {//and each of their character ids o_O + mplew.writeInt(mgc.getId()); + } + for (MapleGuildCharacter mgc : members) { + mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13)); + mplew.writeInt(mgc.getJobId()); + mplew.writeInt(mgc.getLevel()); + mplew.writeInt(mgc.getGuildRank()); + mplew.writeInt(mgc.isOnline() ? 1 : 0); + mplew.writeInt(g.getSignature()); + mplew.writeInt(mgc.getAllianceRank()); + } + mplew.writeInt(g.getCapacity()); + mplew.writeShort(g.getLogoBG()); + mplew.write(g.getLogoBGColor()); + mplew.writeShort(g.getLogo()); + mplew.write(g.getLogoColor()); + mplew.writeMapleAsciiString(g.getNotice()); + mplew.writeInt(g.getGP()); + mplew.writeInt(g.getAllianceId()); + return mplew.getPacket(); + } + + public static byte[] guildMemberOnline(int gid, int cid, boolean bOnline) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x3d); + mplew.writeInt(gid); + mplew.writeInt(cid); + mplew.write(bOnline ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] guildInvite(int gid, String charName) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x05); + mplew.writeInt(gid); + mplew.writeMapleAsciiString(charName); + return mplew.getPacket(); + } + + /** + * 'Char' has denied your guild invitation. + * + * @param charname + * @return + */ + public static byte[] denyGuildInvitation(String charname) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x37); + mplew.writeMapleAsciiString(charname); + return mplew.getPacket(); + } + + public static byte[] genericGuildMessage(byte code) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(code); + return mplew.getPacket(); + } + + public static byte[] newGuildMember(MapleGuildCharacter mgc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x27); + mplew.writeInt(mgc.getGuildId()); + mplew.writeInt(mgc.getId()); + mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13)); + mplew.writeInt(mgc.getJobId()); + mplew.writeInt(mgc.getLevel()); + mplew.writeInt(mgc.getGuildRank()); //should be always 5 but whatevs + mplew.writeInt(mgc.isOnline() ? 1 : 0); //should always be 1 too + mplew.writeInt(1); //? could be guild signature, but doesn't seem to matter + mplew.writeInt(3); + return mplew.getPacket(); + } + + //someone leaving, mode == 0x2c for leaving, 0x2f for expelled + public static byte[] memberLeft(MapleGuildCharacter mgc, boolean bExpelled) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(bExpelled ? 0x2f : 0x2c); + mplew.writeInt(mgc.getGuildId()); + mplew.writeInt(mgc.getId()); + mplew.writeMapleAsciiString(mgc.getName()); + return mplew.getPacket(); + } + + //rank change + public static byte[] changeRank(MapleGuildCharacter mgc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x40); + mplew.writeInt(mgc.getGuildId()); + mplew.writeInt(mgc.getId()); + mplew.write(mgc.getGuildRank()); + return mplew.getPacket(); + } + + public static byte[] guildNotice(int gid, String notice) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x44); + mplew.writeInt(gid); + mplew.writeMapleAsciiString(notice); + return mplew.getPacket(); + } + + public static byte[] guildMemberLevelJobUpdate(MapleGuildCharacter mgc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x3C); + mplew.writeInt(mgc.getGuildId()); + mplew.writeInt(mgc.getId()); + mplew.writeInt(mgc.getLevel()); + mplew.writeInt(mgc.getJobId()); + return mplew.getPacket(); + } + + public static byte[] rankTitleChange(int gid, String[] ranks) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x3E); + mplew.writeInt(gid); + for (int i = 0; i < 5; i++) { + mplew.writeMapleAsciiString(ranks[i]); + } + return mplew.getPacket(); + } + + public static byte[] guildDisband(int gid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x32); + mplew.writeInt(gid); + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] guildQuestWaitingNotice(byte channel, int waitingPos) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x4C); + mplew.write(channel - 1); + mplew.write(waitingPos); + return mplew.getPacket(); + } + + public static byte[] guildEmblemChange(int gid, short bg, byte bgcolor, short logo, byte logocolor) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x42); + mplew.writeInt(gid); + mplew.writeShort(bg); + mplew.write(bgcolor); + mplew.writeShort(logo); + mplew.write(logocolor); + return mplew.getPacket(); + } + + public static byte[] guildCapacityChange(int gid, int capacity) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x3A); + mplew.writeInt(gid); + mplew.write(capacity); + return mplew.getPacket(); + } + + public static void addThread(final MaplePacketLittleEndianWriter mplew, ResultSet rs) throws SQLException { + mplew.writeInt(rs.getInt("localthreadid")); + mplew.writeInt(rs.getInt("postercid")); + mplew.writeMapleAsciiString(rs.getString("name")); + mplew.writeLong(getTime(rs.getLong("timestamp"))); + mplew.writeInt(rs.getInt("icon")); + mplew.writeInt(rs.getInt("replycount")); + } + + public static byte[] BBSThreadList(ResultSet rs, int start) throws SQLException { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_BBS_PACKET.getValue()); + mplew.write(0x06); + if (!rs.last()) { + mplew.write(0); + mplew.writeInt(0); + mplew.writeInt(0); + return mplew.getPacket(); + } + int threadCount = rs.getRow(); + if (rs.getInt("localthreadid") == 0) { //has a notice + mplew.write(1); + addThread(mplew, rs); + threadCount--; //one thread didn't count (because it's a notice) + } else { + mplew.write(0); + } + if (!rs.absolute(start + 1)) { //seek to the thread before where we start + rs.first(); //uh, we're trying to start at a place past possible + start = 0; + } + mplew.writeInt(threadCount); + mplew.writeInt(Math.min(10, threadCount - start)); + for (int i = 0; i < Math.min(10, threadCount - start); i++) { + addThread(mplew, rs); + rs.next(); + } + return mplew.getPacket(); + } + + public static byte[] showThread(int localthreadid, ResultSet threadRS, ResultSet repliesRS) throws SQLException, RuntimeException { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_BBS_PACKET.getValue()); + mplew.write(0x07); + mplew.writeInt(localthreadid); + mplew.writeInt(threadRS.getInt("postercid")); + mplew.writeLong(getTime(threadRS.getLong("timestamp"))); + mplew.writeMapleAsciiString(threadRS.getString("name")); + mplew.writeMapleAsciiString(threadRS.getString("startpost")); + mplew.writeInt(threadRS.getInt("icon")); + if (repliesRS != null) { + int replyCount = threadRS.getInt("replycount"); + mplew.writeInt(replyCount); + int i; + for (i = 0; i < replyCount && repliesRS.next(); i++) { + mplew.writeInt(repliesRS.getInt("replyid")); + mplew.writeInt(repliesRS.getInt("postercid")); + mplew.writeLong(getTime(repliesRS.getLong("timestamp"))); + mplew.writeMapleAsciiString(repliesRS.getString("content")); + } + if (i != replyCount || repliesRS.next()) { + throw new RuntimeException(String.valueOf(threadRS.getInt("threadid"))); + } + } else { + mplew.writeInt(0); + } + return mplew.getPacket(); + } + + public static byte[] showGuildRanks(int npcid, ResultSet rs) throws SQLException { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x49); + mplew.writeInt(npcid); + if (!rs.last()) { //no guilds o.o + mplew.writeInt(0); + return mplew.getPacket(); + } + mplew.writeInt(rs.getRow()); //number of entries + rs.beforeFirst(); + while (rs.next()) { + mplew.writeMapleAsciiString(rs.getString("name")); + mplew.writeInt(rs.getInt("GP")); + mplew.writeInt(rs.getInt("logo")); + mplew.writeInt(rs.getInt("logoColor")); + mplew.writeInt(rs.getInt("logoBG")); + mplew.writeInt(rs.getInt("logoBGColor")); + } + return mplew.getPacket(); + } + + public static byte[] showPlayerRanks(int npcid, List> worldRanking) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x49); + mplew.writeInt(npcid); + if (worldRanking.isEmpty()) { + mplew.writeInt(0); + return mplew.getPacket(); + } + mplew.writeInt(worldRanking.size()); + for (Pair wr : worldRanking) { + mplew.writeMapleAsciiString(wr.getLeft()); + mplew.writeInt(wr.getRight()); + mplew.writeInt(0); + mplew.writeInt(0); + mplew.writeInt(0); + mplew.writeInt(0); + } + return mplew.getPacket(); + } + + public static byte[] updateGP(int gid, int GP) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x48); + mplew.writeInt(gid); + mplew.writeInt(GP); + return mplew.getPacket(); + } + + public static byte[] skillEffect(MapleCharacter from, int skillId, int level, byte flags, int speed, byte direction) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SKILL_EFFECT.getValue()); + mplew.writeInt(from.getId()); + mplew.writeInt(skillId); + mplew.write(level); + mplew.write(flags); + mplew.write(speed); + mplew.write(direction); //Mmmk + return mplew.getPacket(); + } + + public static byte[] skillCancel(MapleCharacter from, int skillId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_SKILL_EFFECT.getValue()); + mplew.writeInt(from.getId()); + mplew.writeInt(skillId); + return mplew.getPacket(); + } + + public static byte[] catchMonster(int mobOid, byte success) { // updated packet structure found thanks to Rien dev team + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CATCH_MONSTER.getValue()); + mplew.writeInt(mobOid); + mplew.write(success); + return mplew.getPacket(); + } + + public static byte[] catchMonster(int mobOid, int itemid, byte success) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CATCH_MONSTER_WITH_ITEM.getValue()); + mplew.writeInt(mobOid); + mplew.writeInt(itemid); + mplew.write(success); + return mplew.getPacket(); + } + + /** + * Sends a player hint. + * + * @param hint The hint it's going to send. + * @param width How tall the box is going to be. + * @param height How long the box is going to be. + * @return The player hint packet. + */ + public static byte[] sendHint(String hint, int width, int height) { + if (width < 1) { + width = hint.length() * 10; + if (width < 40) { + width = 40; + } + } + if (height < 5) { + height = 5; + } + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_HINT.getValue()); + mplew.writeMapleAsciiString(hint); + mplew.writeShort(width); + mplew.writeShort(height); + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] messengerInvite(String from, int messengerid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(0x03); + mplew.writeMapleAsciiString(from); + mplew.write(0); + mplew.writeInt(messengerid); + mplew.write(0); + return mplew.getPacket(); + } + + /* + public static byte[] sendSpouseChat(MapleCharacter partner, String msg) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue()); + mplew.writeMapleAsciiString(partner.getName()); + mplew.writeMapleAsciiString(msg); + return mplew.getPacket(); + } + */ + public static byte[] OnCoupleMessage(String fiance, String text, boolean spouse) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue()); + mplew.write(spouse ? 5 : 4); // v2 = CInPacket::Decode1(a1) - 4; + if (spouse) { // if ( v2 ) { + mplew.writeMapleAsciiString(fiance); + } + mplew.write(spouse ? 5 : 1); + mplew.writeMapleAsciiString(text); + return mplew.getPacket(); + } + + public static byte[] addMessengerPlayer(String from, MapleCharacter chr, int position, int channel) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(0x00); + mplew.write(position); + addCharLook(mplew, chr, true); + mplew.writeMapleAsciiString(from); + mplew.write(channel); + mplew.write(0x00); + return mplew.getPacket(); + } + + public static byte[] removeMessengerPlayer(int position) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(0x02); + mplew.write(position); + return mplew.getPacket(); + } + + public static byte[] updateMessengerPlayer(String from, MapleCharacter chr, int position, int channel) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(0x07); + mplew.write(position); + addCharLook(mplew, chr, true); + mplew.writeMapleAsciiString(from); + mplew.write(channel); + mplew.write(0x00); + return mplew.getPacket(); + } + + public static byte[] joinMessenger(int position) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(0x01); + mplew.write(position); + return mplew.getPacket(); + } + + public static byte[] messengerChat(String text) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(0x06); + mplew.writeMapleAsciiString(text); + return mplew.getPacket(); + } + + public static byte[] messengerNote(String text, int mode, int mode2) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MESSENGER.getValue()); + mplew.write(mode); + mplew.writeMapleAsciiString(text); + mplew.write(mode2); + return mplew.getPacket(); + } + + private static void addPetInfo(final MaplePacketLittleEndianWriter mplew, MaplePet pet, boolean showpet) { + mplew.write(1); + if (showpet) { + mplew.write(0); + } + + mplew.writeInt(pet.getItemId()); + mplew.writeMapleAsciiString(pet.getName()); + mplew.writeLong(pet.getUniqueId()); + mplew.writePos(pet.getPos()); + mplew.write(pet.getStance()); + mplew.writeInt(pet.getFh()); + } + + public static byte[] showPet(MapleCharacter chr, MaplePet pet, boolean remove, boolean hunger) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_PET.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(chr.getPetIndex(pet)); + if (remove) { + mplew.write(0); + mplew.write(hunger ? 1 : 0); + } else { + addPetInfo(mplew, pet, true); + } + return mplew.getPacket(); + } + + public static byte[] movePet(int cid, int pid, byte slot, List moves) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MOVE_PET.getValue()); + mplew.writeInt(cid); + mplew.write(slot); + mplew.writeInt(pid); + serializeMovementList(mplew, moves); + return mplew.getPacket(); + } + + public static byte[] petChat(int cid, byte index, int act, String text) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PET_CHAT.getValue()); + mplew.writeInt(cid); + mplew.write(index); + mplew.write(0); + mplew.write(act); + mplew.writeMapleAsciiString(text); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] petFoodResponse(int cid, byte index, boolean success, boolean balloonType) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PET_COMMAND.getValue()); + mplew.writeInt(cid); + mplew.write(index); + mplew.write(1); + mplew.writeBool(success); + mplew.writeBool(balloonType); + return mplew.getPacket(); + } + + public static byte[] commandResponse(int cid, byte index, boolean talk, int animation, boolean balloonType) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PET_COMMAND.getValue()); + mplew.writeInt(cid); + mplew.write(index); + mplew.write(0); + mplew.write(animation); + mplew.writeBool(!talk); + mplew.writeBool(balloonType); + return mplew.getPacket(); + } + + public static byte[] showOwnPetLevelUp(byte index) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(4); + mplew.write(0); + mplew.write(index); // Pet Index + return mplew.getPacket(); + } + + public static byte[] showPetLevelUp(MapleCharacter chr, byte index) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(4); + mplew.write(0); + mplew.write(index); + return mplew.getPacket(); + } + + public static byte[] changePetName(MapleCharacter chr, String newname, int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PET_NAMECHANGE.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(0); + mplew.writeMapleAsciiString(newname); + mplew.write(0); + return mplew.getPacket(); + } + + public static final byte[] loadExceptionList(final int cid, final int petId, final byte petIdx, final List data) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PET_EXCEPTION_LIST.getValue()); + mplew.writeInt(cid); + mplew.write(petIdx); + mplew.writeLong(petId); + mplew.write(data.size()); + for (final Integer ids : data) { + mplew.writeInt(ids); + } + return mplew.getPacket(); + } + + public static byte[] petStatUpdate(MapleCharacter chr) { + // this actually does nothing... packet structure and stats needs to be uncovered + + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.STAT_CHANGED.getValue()); + int mask = 0; + mask |= MapleStat.PET.getValue(); + mplew.write(0); + mplew.writeInt(mask); + MaplePet[] pets = chr.getPets(); + for (int i = 0; i < 3; i++) { + if (pets[i] != null) { + mplew.writeLong(pets[i].getUniqueId()); + } else { + mplew.writeLong(0); + } + } + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] showForcedEquip(int team) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FORCED_MAP_EQUIP.getValue()); + if (team > -1) { + mplew.write(team); // 00 = red, 01 = blue + } + return mplew.getPacket(); + } + + public static byte[] summonSkill(int cid, int summonSkillId, int newStance) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SUMMON_SKILL.getValue()); + mplew.writeInt(cid); + mplew.writeInt(summonSkillId); + mplew.write(newStance); + return mplew.getPacket(); + } + + public static byte[] skillCooldown(int sid, int time) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.COOLDOWN.getValue()); + mplew.writeInt(sid); + mplew.writeShort(time);//Int in v97 + return mplew.getPacket(); + } + + public static byte[] skillBookSuccess(MapleCharacter chr, int skillid, int maxlevel, boolean canuse, boolean success) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SKILL_LEARN_ITEM_RESULT.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(1); + mplew.writeInt(skillid); + mplew.writeInt(maxlevel); + mplew.write(canuse ? 1 : 0); + mplew.write(success ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] getMacros(SkillMacro[] macros) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MACRO_SYS_DATA_INIT.getValue()); + int count = 0; + for (int i = 0; i < 5; i++) { + if (macros[i] != null) { + count++; + } + } + mplew.write(count); + for (int i = 0; i < 5; i++) { + SkillMacro macro = macros[i]; + if (macro != null) { + mplew.writeMapleAsciiString(macro.getName()); + mplew.write(macro.getShout()); + mplew.writeInt(macro.getSkill1()); + mplew.writeInt(macro.getSkill2()); + mplew.writeInt(macro.getSkill3()); + } + } + return mplew.getPacket(); + } + + public static byte[] updateAriantPQRanking(String name, int score, boolean empty) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ARIANT_SCORE.getValue()); + mplew.write(empty ? 0 : 1); + if (!empty) { + mplew.writeMapleAsciiString(name); + mplew.writeInt(score); + } + return mplew.getPacket(); + } + + public static byte[] catchMessage(int message) { // not done, I guess + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BRIDLE_MOB_CATCH_FAIL.getValue()); + mplew.write(message); // 1 = too strong, 2 = Elemental Rock + mplew.writeInt(0);//Maybe itemid? + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] showAllCharacter(int chars, int unk) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); + mplew.writeShort(SendOpcode.VIEW_ALL_CHAR.getValue()); + mplew.write(chars > 0 ? 1 : 5); // 2: already connected to server, 3 : unk error (view-all-characters), 5 : cannot find any + mplew.writeInt(chars); + mplew.writeInt(unk); + return mplew.getPacket(); + } + + public static byte[] showAllCharacterInfo(int worldid, List chars, boolean usePic) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.VIEW_ALL_CHAR.getValue()); + mplew.write(0); + mplew.write(worldid); + mplew.write(chars.size()); + for (MapleCharacter chr : chars) { + addCharEntry(mplew, chr, true); + } + mplew.write(usePic ? 1 : 2); + return mplew.getPacket(); + } + + public static byte[] updateMount(int charid, MapleMount mount, boolean levelup) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_TAMING_MOB_INFO.getValue()); + mplew.writeInt(charid); + mplew.writeInt(mount.getLevel()); + mplew.writeInt(mount.getExp()); + mplew.writeInt(mount.getTiredness()); + mplew.write(levelup ? (byte) 1 : (byte) 0); + return mplew.getPacket(); + } + + public static byte[] crogBoatPacket(boolean type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CONTI_MOVE.getValue()); + mplew.write(10); + mplew.write(type ? 4 : 5); + return mplew.getPacket(); + } + + public static byte[] boatPacket(boolean type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CONTI_STATE.getValue()); + mplew.write(type ? 1 : 2); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] getMiniGame(MapleClient c, MapleMiniGame minigame, boolean owner, int piece) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(1); + mplew.write(0); + mplew.write(owner ? 0 : 1); + mplew.write(0); + addCharLook(mplew, minigame.getOwner(), false); + mplew.writeMapleAsciiString(minigame.getOwner().getName()); + if (minigame.getVisitor() != null) { + MapleCharacter visitor = minigame.getVisitor(); + mplew.write(1); + addCharLook(mplew, visitor, false); + mplew.writeMapleAsciiString(visitor.getName()); + } + mplew.write(0xFF); + mplew.write(0); + mplew.writeInt(1); + mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.WIN, true)); + mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.TIE, true)); + mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.LOSS, true)); + mplew.writeInt(minigame.getOwnerScore()); + if (minigame.getVisitor() != null) { + MapleCharacter visitor = minigame.getVisitor(); + mplew.write(1); + mplew.writeInt(1); + mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.WIN, true)); + mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.TIE, true)); + mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.LOSS, true)); + mplew.writeInt(minigame.getVisitorScore()); + } + mplew.write(0xFF); + mplew.writeMapleAsciiString(minigame.getDescription()); + mplew.write(piece); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] getMiniGameReady(MapleMiniGame game) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.READY.getCode()); + return mplew.getPacket(); + } + + public static byte[] getMiniGameUnReady(MapleMiniGame game) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.UN_READY.getCode()); + return mplew.getPacket(); + } + + public static byte[] getMiniGameStart(MapleMiniGame game, int loser) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.START.getCode()); + mplew.write(loser); + return mplew.getPacket(); + } + + public static byte[] getMiniGameSkipOwner(MapleMiniGame game) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.SKIP.getCode()); + mplew.write(0x01); + return mplew.getPacket(); + } + + public static byte[] getMiniGameRequestTie(MapleMiniGame game) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.REQUEST_TIE.getCode()); + return mplew.getPacket(); + } + + public static byte[] getMiniGameDenyTie(MapleMiniGame game) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ANSWER_TIE.getCode()); + return mplew.getPacket(); + } + + /** + * 1 = Room already closed 2 = Can't enter due full cappacity 3 = Other + * requests at this minute 4 = Can't do while dead 5 = Can't do while middle + * event 6 = This character unable to do it 7, 20 = Not allowed to trade + * anymore 9 = Can only trade on same map 10 = May not open store near + * portal 11, 14 = Can't start game here 12 = Can't open store at this + * channel 13 = Can't estabilish miniroom 15 = Stores only an the free + * market 16 = Lists the rooms at FM (?) 17 = You may not enter this store + * 18 = Owner undergoing store maintenance 19 = Unable to enter tournament + * room 21 = Not enough mesos to enter 22 = Incorrect password + * + * @param status + * @return + */ + public static byte[] getMiniRoomError(int status) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(0); + mplew.write(status); + return mplew.getPacket(); + } + + public static byte[] getMiniGameSkipVisitor(MapleMiniGame game) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.writeShort(PlayerInteractionHandler.Action.SKIP.getCode()); + return mplew.getPacket(); + } + + public static byte[] getMiniGameMoveOmok(MapleMiniGame game, int move1, int move2, int move3) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(12); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.MOVE_OMOK.getCode()); + mplew.writeInt(move1); + mplew.writeInt(move2); + mplew.write(move3); + return mplew.getPacket(); + } + + public static byte[] getMiniGameNewVisitor(MapleMiniGame minigame, MapleCharacter c, int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); + mplew.write(slot); + addCharLook(mplew, c, false); + mplew.writeMapleAsciiString(c.getName()); + mplew.writeInt(1); + mplew.writeInt(c.getMiniGamePoints(MiniGameResult.WIN, true)); + mplew.writeInt(c.getMiniGamePoints(MiniGameResult.TIE, true)); + mplew.writeInt(c.getMiniGamePoints(MiniGameResult.LOSS, true)); + mplew.writeInt(minigame.getVisitorScore()); + return mplew.getPacket(); + } + + public static byte[] getMiniGameRemoveVisitor() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + mplew.write(1); + return mplew.getPacket(); + } + + private static byte[] getMiniGameResult(MapleMiniGame game, int tie, int result, int forfeit) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.GET_RESULT.getCode()); + + int matchResultType; + if (tie == 0 && forfeit != 1) { + matchResultType = 0; + } else if (tie != 0) { + matchResultType = 1; + } else { + matchResultType = 2; + } + + mplew.write(matchResultType); + mplew.writeBool(result == 2); // host/visitor wins + + boolean omok = game.isOmok(); + if (matchResultType == 1) { + mplew.write(0); + mplew.writeShort(0); + mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins + mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties + mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses + mplew.writeInt(game.getOwnerScore()); // points + + mplew.writeInt(0); // unknown + mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins + mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties + mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses + mplew.writeInt(game.getVisitorScore()); // points + mplew.write(0); + } else { + mplew.writeInt(0); + mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins + mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties + mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses + mplew.writeInt(game.getOwnerScore()); // points + mplew.writeInt(0); + mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins + mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties + mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses + mplew.writeInt(game.getVisitorScore()); // points + } + + return mplew.getPacket(); + } + + public static byte[] getMiniGameOwnerWin(MapleMiniGame game, boolean forfeit) { + return getMiniGameResult(game, 0, 1, forfeit ? 1 : 0); + } + + public static byte[] getMiniGameVisitorWin(MapleMiniGame game, boolean forfeit) { + return getMiniGameResult(game, 0, 2, forfeit ? 1 : 0); + } + + public static byte[] getMiniGameTie(MapleMiniGame game) { + return getMiniGameResult(game, 1, 3, 0); + } + + public static byte[] getMiniGameClose(int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + mplew.write(1); + mplew.write(type); /* 2 : CRASH 3 : The room has been closed 4 : You have left the room 5 : You have been expelled */ + + return mplew.getPacket(); + } + + public static byte[] getMatchCard(MapleClient c, MapleMiniGame minigame, boolean owner, int piece) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(2); + mplew.write(2); + mplew.write(owner ? 0 : 1); + mplew.write(0); + addCharLook(mplew, minigame.getOwner(), false); + mplew.writeMapleAsciiString(minigame.getOwner().getName()); + if (minigame.getVisitor() != null) { + MapleCharacter visitor = minigame.getVisitor(); + mplew.write(1); + addCharLook(mplew, visitor, false); + mplew.writeMapleAsciiString(visitor.getName()); + } + mplew.write(0xFF); + mplew.write(0); + mplew.writeInt(2); + mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.WIN, false)); + mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.TIE, false)); + mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.LOSS, false)); + + //set vs + mplew.writeInt(minigame.getOwnerScore()); + if (minigame.getVisitor() != null) { + MapleCharacter visitor = minigame.getVisitor(); + mplew.write(1); + mplew.writeInt(2); + mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.WIN, false)); + mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.TIE, false)); + mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.LOSS, false)); + mplew.writeInt(minigame.getVisitorScore()); + } + mplew.write(0xFF); + mplew.writeMapleAsciiString(minigame.getDescription()); + mplew.write(piece); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] getMatchCardStart(MapleMiniGame game, int loser) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.START.getCode()); + mplew.write(loser); + + int last; + if (game.getMatchesToWin() > 10) { + last = 30; + } else if (game.getMatchesToWin() > 6) { + last = 20; + } else { + last = 12; + } + + mplew.write(last); + for (int i = 0; i < last; i++) { + mplew.writeInt(game.getCardId(i)); + } + return mplew.getPacket(); + } + + public static byte[] getMatchCardNewVisitor(MapleMiniGame minigame, MapleCharacter c, int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); + mplew.write(slot); + addCharLook(mplew, c, false); + mplew.writeMapleAsciiString(c.getName()); + mplew.writeInt(1); + mplew.writeInt(c.getMiniGamePoints(MiniGameResult.WIN, false)); + mplew.writeInt(c.getMiniGamePoints(MiniGameResult.TIE, false)); + mplew.writeInt(c.getMiniGamePoints(MiniGameResult.LOSS, false)); + mplew.writeInt(minigame.getVisitorScore()); + return mplew.getPacket(); + } + + public static byte[] getMatchCardSelect(MapleMiniGame game, int turn, int slot, int firstslot, int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.SELECT_CARD.getCode()); + mplew.write(turn); + if (turn == 1) { + mplew.write(slot); + } else if (turn == 0) { + mplew.write(slot); + mplew.write(firstslot); + mplew.write(type); + } + return mplew.getPacket(); + } + + public static byte[] fredrickMessage(byte operation) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FREDRICK_MESSAGE.getValue()); + mplew.write(operation); + return mplew.getPacket(); + } + + public static byte[] getFredrick(byte op) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FREDRICK.getValue()); + mplew.write(op); + + switch (op) { + case 0x24: + mplew.skip(8); + break; + default: + mplew.write(0); + break; + } + + return mplew.getPacket(); + } + + public static byte[] getFredrick(MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FREDRICK.getValue()); + mplew.write(0x23); + mplew.writeInt(9030000); // Fredrick + mplew.writeInt(32272); //id + mplew.skip(5); + mplew.writeInt(chr.getMerchantMeso()); + mplew.write(0); + try { + List> items = ItemFactory.MERCHANT.loadItems(chr.getId(), false); + mplew.write(items.size()); + + for (int i = 0; i < items.size(); i++) { + addItemInfo(mplew, items.get(i).getLeft(), true); + } + } catch (SQLException e) { + e.printStackTrace(); + } + mplew.skip(3); + return mplew.getPacket(); + } + + public static byte[] addOmokBox(MapleCharacter c, int ammount, int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); + mplew.writeInt(c.getId()); + addAnnounceBox(mplew, c.getMiniGame(), ammount, type); + return mplew.getPacket(); + } + + public static byte[] addMatchCardBox(MapleCharacter c, int ammount, int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); + mplew.writeInt(c.getId()); + addAnnounceBox(mplew, c.getMiniGame(), ammount, type); + return mplew.getPacket(); + } + + public static byte[] removeMinigameBox(MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue()); + mplew.writeInt(chr.getId()); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] getPlayerShopChat(MapleCharacter c, String chat, byte slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); + mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); + mplew.write(slot); + mplew.writeMapleAsciiString(c.getName() + " : " + chat); + return mplew.getPacket(); + } + + public static byte[] getTradeChat(MapleCharacter c, String chat, boolean owner) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); + mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); + mplew.write(owner ? 0 : 1); + mplew.writeMapleAsciiString(c.getName() + " : " + chat); + return mplew.getPacket(); + } + + public static byte[] hiredMerchantBox() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header. + mplew.write(0x07); + return mplew.getPacket(); + } // 0: Success - // 1: The room is already closed. - // 2: You can't enter the room due to full capacity. - // 3: Other requests are being fulfilled this minute. - // 4: You can't do it while you're dead. - // 7: You are not allowed to trade other items at this point. - // 17: You may not enter this store. - // 18: The owner of the store is currently undergoing store maintenance. Please try again in a bit. - // 23: This can only be used inside the Free Market. - // default: This character is unable to do it. - public static byte[] getOwlMessage(int msg) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - - mplew.writeShort(SendOpcode.SHOP_LINK_RESULT.getValue()); - mplew.write(msg); // depending on the byte sent, a different message is sent. - - return mplew.getPacket(); - } - - public static byte[] owlOfMinerva(MapleClient c, int itemid, List> hmsAvailable) { - byte itemType = ItemConstants.getInventoryType(itemid).getType(); - - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue()); // header. - mplew.write(6); - mplew.writeInt(0); - mplew.writeInt(itemid); - mplew.writeInt(hmsAvailable.size()); - for (Pair hme : hmsAvailable) { - MaplePlayerShopItem item = hme.getLeft(); - AbstractMapleMapObject mo = hme.getRight(); - - if(mo instanceof MaplePlayerShop) { - MaplePlayerShop ps = (MaplePlayerShop) mo; - MapleCharacter owner = ps.getOwner(); - - mplew.writeMapleAsciiString(owner.getName()); - mplew.writeInt(owner.getMapId()); - mplew.writeMapleAsciiString(ps.getDescription()); - mplew.writeInt(item.getBundles()); - mplew.writeInt(item.getItem().getQuantity()); - mplew.writeInt(item.getPrice()); - mplew.writeInt(owner.getId()); - mplew.write(owner.getClient().getChannel() - 1); - } else { - MapleHiredMerchant hm = (MapleHiredMerchant) mo; - - mplew.writeMapleAsciiString(hm.getOwner()); - mplew.writeInt(hm.getMapId()); - mplew.writeMapleAsciiString(hm.getDescription()); - mplew.writeInt(item.getBundles()); - mplew.writeInt(item.getItem().getQuantity()); - mplew.writeInt(item.getPrice()); - mplew.writeInt(hm.getOwnerId()); - mplew.write(hm.getChannel() - 1); - } - - mplew.write(itemType); - if (itemType == MapleInventoryType.EQUIP.getType()) { - addItemInfo(mplew, item.getItem(), true); - } - } - return mplew.getPacket(); - } - - public static byte[] getOwlOpen(List owlLeaderboards) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - - mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue()); - mplew.write(7); - mplew.write(owlLeaderboards.size()); - for (Integer i : owlLeaderboards) { - mplew.writeInt(i); - } - - return mplew.getPacket(); - } - - public static byte[] retrieveFirstMessage() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header. - mplew.write(0x09); - return mplew.getPacket(); - } - - public static byte[] remoteChannelChange(byte ch) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header. - mplew.write(0x10); - mplew.writeInt(0);//No idea yet - mplew.write(ch); - return mplew.getPacket(); - } - /* - * Possible things for ENTRUSTED_SHOP_CHECK_RESULT - * 0x0E = 00 = Renaming Failed - Can't find the merchant, 01 = Renaming successful - * 0x10 = Changes channel to the store (Store is open at Channel 1, do you want to change channels?) - * 0x11 = You cannot sell any items when managing.. blabla - * 0x12 = FKING POPUP LOL - */ - - public static byte[] getHiredMerchant(MapleCharacter chr, MapleHiredMerchant hm, boolean firstTime) {//Thanks Dustin - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(0x05); - mplew.write(0x04); - mplew.writeShort(hm.getVisitorSlotThreadsafe(chr) + 1); - mplew.writeInt(hm.getItemId()); - mplew.writeMapleAsciiString("Hired Merchant"); - - MapleCharacter visitors[] = hm.getVisitors(); - for (int i = 0; i < 3; i++) { - if (visitors[i] != null) { - mplew.write(i + 1); - addCharLook(mplew, visitors[i], false); - mplew.writeMapleAsciiString(visitors[i].getName()); - } - } - mplew.write(-1); - if (hm.isOwner(chr)) { - List> msgList = hm.getMessages(); - - mplew.writeShort(msgList.size()); - for (int i = 0; i < msgList.size(); i++) { - mplew.writeMapleAsciiString(msgList.get(i).getLeft()); - mplew.write(msgList.get(i).getRight()); - } - } else { - mplew.writeShort(0); - } - mplew.writeMapleAsciiString(hm.getOwner()); - if (hm.isOwner(chr)) { - mplew.writeInt(hm.getTimeLeft()); - mplew.write(firstTime ? 1 : 0); - List sold = hm.getSold(); - mplew.write(sold.size()); - for (MapleHiredMerchant.SoldItem s : sold) { - mplew.writeInt(s.getItemId()); - mplew.writeShort(s.getQuantity()); - mplew.writeInt(s.getMesos()); - mplew.writeMapleAsciiString(s.getBuyer()); - } - mplew.writeInt(chr.getMerchantMeso());//:D? - } - mplew.writeMapleAsciiString(hm.getDescription()); - mplew.write(0x10); //TODO SLOTS, which is 16 for most stores...slotMax - mplew.writeInt(hm.isOwner(chr) ? chr.getMerchantMeso() : chr.getMeso()); - mplew.write(hm.getItems().size()); - if (hm.getItems().isEmpty()) { - mplew.write(0);//Hmm?? - } else { - for (MaplePlayerShopItem item : hm.getItems()) { - mplew.writeShort(item.getBundles()); - mplew.writeShort(item.getItem().getQuantity()); - mplew.writeInt(item.getPrice()); - addItemInfo(mplew, item.getItem(), true); - } - } - return mplew.getPacket(); - } - - public static byte[] updateHiredMerchant(MapleHiredMerchant hm, MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.UPDATE_MERCHANT.getCode()); - mplew.writeInt(hm.isOwner(chr) ? chr.getMerchantMeso() : chr.getMeso()); - mplew.write(hm.getItems().size()); - for (MaplePlayerShopItem item : hm.getItems()) { - mplew.writeShort(item.getBundles()); - mplew.writeShort(item.getItem().getQuantity()); - mplew.writeInt(item.getPrice()); - addItemInfo(mplew, item.getItem(), true); - } - return mplew.getPacket(); - } - - public static byte[] hiredMerchantChat(String message, byte slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); - mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); - mplew.write(slot); - mplew.writeMapleAsciiString(message); - return mplew.getPacket(); - } - - public static byte[] hiredMerchantVisitorLeave(int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - if (slot != 0) { - mplew.write(slot); - } - return mplew.getPacket(); - } - - public static byte[] hiredMerchantOwnerLeave() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.REAL_CLOSE_MERCHANT.getCode()); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] hiredMerchantOwnerMaintenanceLeave() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.REAL_CLOSE_MERCHANT.getCode()); - mplew.write(5); - return mplew.getPacket(); - } - - public static byte[] hiredMerchantMaintenanceMessage() { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); - mplew.write(0x00); - mplew.write(0x12); - return mplew.getPacket(); - } - - public static byte[] leaveHiredMerchant(int slot, int status2) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); - mplew.write(slot); - mplew.write(status2); - return mplew.getPacket(); - } - - public static byte[] hiredMerchantVisitorAdd(MapleCharacter chr, int slot) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); - mplew.write(slot); - addCharLook(mplew, chr, false); - mplew.writeMapleAsciiString(chr.getName()); - return mplew.getPacket(); - } - - public static byte[] spawnHiredMerchantBox(MapleHiredMerchant hm) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_HIRED_MERCHANT.getValue()); - mplew.writeInt(hm.getOwnerId()); - mplew.writeInt(hm.getItemId()); - mplew.writeShort((short) hm.getPosition().getX()); - mplew.writeShort((short) hm.getPosition().getY()); - mplew.writeShort(0); - mplew.writeMapleAsciiString(hm.getOwner()); - mplew.write(0x05); - mplew.writeInt(hm.getObjectId()); - mplew.writeMapleAsciiString(hm.getDescription()); - mplew.write(hm.getItemId() % 100); - mplew.write(new byte[]{1, 4}); - return mplew.getPacket(); - } - - public static byte[] removeHiredMerchantBox(int id) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DESTROY_HIRED_MERCHANT.getValue()); - mplew.writeInt(id); - return mplew.getPacket(); - } - - public static byte[] spawnPlayerNPC(MaplePlayerNPC npc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue()); - mplew.write(1); - mplew.writeInt(npc.getObjectId()); - mplew.writeInt(npc.getScriptId()); - mplew.writeShort(npc.getPosition().x); - mplew.writeShort(npc.getCY()); - mplew.write(npc.getDirection()); - mplew.writeShort(npc.getFH()); - mplew.writeShort(npc.getRX0()); - mplew.writeShort(npc.getRX1()); - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] getPlayerNPC(MaplePlayerNPC npc) { // thanks to Arnah - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.IMITATED_NPC_DATA.getValue()); - mplew.write(0x01); - mplew.writeInt(npc.getScriptId()); - mplew.writeMapleAsciiString(npc.getName()); - mplew.write(npc.getGender()); - mplew.write(npc.getSkin()); - mplew.writeInt(npc.getFace()); - mplew.write(0); - mplew.writeInt(npc.getHair()); - Map equip = npc.getEquips(); - Map myEquip = new LinkedHashMap<>(); - Map maskedEquip = new LinkedHashMap<>(); - for(short position : equip.keySet()) { - short pos = (byte) (position * -1); - if(pos < 100 && myEquip.get(pos) == null) { - myEquip.put(pos, equip.get(position)); - } else if((pos > 100 && pos != 111) || pos == -128) { // don't ask. o.o - pos -= 100; - if(myEquip.get(pos) != null) { - maskedEquip.put(pos, myEquip.get(pos)); - } - myEquip.put(pos, equip.get(position)); - } else if(myEquip.get(pos) != null) { - maskedEquip.put(pos, equip.get(position)); - } - } - for(Entry entry : myEquip.entrySet()) { - mplew.write(entry.getKey()); - mplew.writeInt(entry.getValue()); - } - mplew.write(0xFF); - for(Entry entry : maskedEquip.entrySet()) { - mplew.write(entry.getKey()); - mplew.writeInt(entry.getValue()); - } - mplew.write(0xFF); - Integer cWeapon = equip.get((byte) -111); - if(cWeapon != null) { - mplew.writeInt(cWeapon); - } else { - mplew.writeInt(0); - } - for(int i = 0; i < 3; i++) { - mplew.writeInt(0); - } - return mplew.getPacket(); - } - - public static byte[] removePlayerNPC(int oid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.IMITATED_NPC_DATA.getValue()); - mplew.write(0x00); - mplew.writeInt(oid); - - return mplew.getPacket(); - } - - public static byte[] sendYellowTip(String tip) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_WEEK_EVENT_MESSAGE.getValue()); - mplew.write(0xFF); - mplew.writeMapleAsciiString(tip); - mplew.writeShort(0); - return mplew.getPacket(); - } - - public static byte[] givePirateBuff(List> statups, int buffid, int duration) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - boolean infusion = buffid == Buccaneer.SPEED_INFUSION || buffid == ThunderBreaker.SPEED_INFUSION || buffid == Corsair.SPEED_INFUSION; - mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); - writeLongMask(mplew, statups); - mplew.writeShort(0); - for (Pair stat : statups) { - mplew.writeInt(stat.getRight().shortValue()); - mplew.writeInt(buffid); - mplew.skip(infusion ? 10 : 5); - mplew.writeShort(duration); - } - mplew.skip(3); - return mplew.getPacket(); - } - - public static byte[] giveForeignPirateBuff(int cid, int buffid, int time, List> statups) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - boolean infusion = buffid == Buccaneer.SPEED_INFUSION || buffid == ThunderBreaker.SPEED_INFUSION || buffid == Corsair.SPEED_INFUSION; - mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); - mplew.writeInt(cid); - writeLongMask(mplew, statups); - mplew.writeShort(0); - for (Pair statup : statups) { - mplew.writeInt(statup.getRight().shortValue()); - mplew.writeInt(buffid); - mplew.skip(infusion ? 10 : 5); - mplew.writeShort(time); - } - mplew.writeShort(0); - mplew.write(2); - return mplew.getPacket(); - } - - public static byte[] sendMTS(List items, int tab, int type, int page, int pages) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x15); //operation - mplew.writeInt(pages * 16); //testing, change to 10 if fails - mplew.writeInt(items.size()); //number of items - mplew.writeInt(tab); - mplew.writeInt(type); - mplew.writeInt(page); - mplew.write(1); - mplew.write(1); - for (int i = 0; i < items.size(); i++) { - MTSItemInfo item = items.get(i); - addItemInfo(mplew, item.getItem(), true); - mplew.writeInt(item.getID()); //id - mplew.writeInt(item.getTaxes()); //this + below = price - mplew.writeInt(item.getPrice()); //price - mplew.writeInt(0); - mplew.writeLong(getTime(item.getEndingDate())); - mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?) - mplew.writeMapleAsciiString(item.getSeller()); //char name - for (int j = 0; j < 28; j++) { - mplew.write(0); - } - } - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] noteSendMsg() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.MEMO_RESULT.getValue()); - mplew.write(4); - return mplew.getPacket(); - } - - /* - * 0 = Player online, use whisper - * 1 = Check player's name - * 2 = Receiver inbox full - */ - public static byte[] noteError(byte error) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.MEMO_RESULT.getValue()); - mplew.write(5); - mplew.write(error); - return mplew.getPacket(); - } - - public static byte[] showNotes(ResultSet notes, int count) throws SQLException { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MEMO_RESULT.getValue()); - mplew.write(3); - mplew.write(count); - for (int i = 0; i < count; i++) { - mplew.writeInt(notes.getInt("id")); - mplew.writeMapleAsciiString(notes.getString("from") + " ");//Stupid nexon forgot space lol - mplew.writeMapleAsciiString(notes.getString("message")); - mplew.writeLong(getTime(notes.getLong("timestamp"))); - mplew.write(notes.getByte("fame"));//FAME :D - notes.next(); - } - return mplew.getPacket(); - } - - public static byte[] useChalkboard(MapleCharacter chr, boolean close) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CHALKBOARD.getValue()); - mplew.writeInt(chr.getId()); - if (close) { - mplew.write(0); - } else { - mplew.write(1); - mplew.writeMapleAsciiString(chr.getChalkboard()); - } - return mplew.getPacket(); - } - - public static byte[] trockRefreshMapList(MapleCharacter chr, boolean delete, boolean vip) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MAP_TRANSFER_RESULT.getValue()); - mplew.write(delete ? 2 : 3); - if (vip) { - mplew.write(1); - List map = chr.getVipTrockMaps(); - for (int i = 0; i < 10; i++) { - mplew.writeInt(map.get(i)); - } - } else { - mplew.write(0); - List map = chr.getTrockMaps(); - for (int i = 0; i < 5; i++) { - mplew.writeInt(map.get(i)); - } - } - return mplew.getPacket(); - } - - /* 1: cannot find char info, - 2: cannot transfer under 20, - 3: cannot send banned, - 4: cannot send married, - 5: cannot send guild leader, - 6: cannot send if account already requested transfer, - 7: cannot transfer within 30days, - 8: must quit family, - 9: unknown error - */ - public static byte[] sendWorldTransferRules(int error) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_CHECK_TRANSFER_WORLD_POSSIBLE_RESULT.getValue()); - mplew.writeInt(0); - mplew.write(0); - mplew.write(error); - mplew.writeInt(0); - - return mplew.getPacket(); - } - - /* 1: name change already submitted - 2: name change within a month - 3: recently banned - 4: unknown error - */ - public static byte[] sendNameTransferRules(int error) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_CHECK_NAME_CHANGE_POSSIBLE_RESULT.getValue()); - mplew.writeInt(0); - mplew.write(error); - mplew.writeInt(0); - - return mplew.getPacket(); - } - - public static byte[] sendNameTransferCheck(boolean canUseName) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_CHECK_NAME_CHANGE.getValue()); - mplew.writeShort(0); - mplew.writeBool(!canUseName); - - return mplew.getPacket(); - } - - public static byte[] showMTSCash(MapleCharacter p) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION2.getValue()); - mplew.writeInt(p.getCashShop().getCash(4)); - mplew.writeInt(p.getCashShop().getCash(2)); - return mplew.getPacket(); - } - - public static byte[] MTSWantedListingOver(int nx, int items) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x3D); - mplew.writeInt(nx); - mplew.writeInt(items); - return mplew.getPacket(); - } - - public static byte[] MTSConfirmSell() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x1D); - return mplew.getPacket(); - } - - public static byte[] MTSConfirmBuy() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x33); - return mplew.getPacket(); - } - - public static byte[] MTSFailBuy() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x34); - mplew.write(0x42); - return mplew.getPacket(); - } - - public static byte[] MTSConfirmTransfer(int quantity, int pos) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x27); - mplew.writeInt(quantity); - mplew.writeInt(pos); - return mplew.getPacket(); - } - - public static byte[] notYetSoldInv(List items) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x23); - mplew.writeInt(items.size()); - if (!items.isEmpty()) { - for (MTSItemInfo item : items) { - addItemInfo(mplew, item.getItem(), true); - mplew.writeInt(item.getID()); //id - mplew.writeInt(item.getTaxes()); //this + below = price - mplew.writeInt(item.getPrice()); //price - mplew.writeInt(0); - mplew.writeLong(getTime(item.getEndingDate())); - mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?) - mplew.writeMapleAsciiString(item.getSeller()); //char name - for (int i = 0; i < 28; i++) { - mplew.write(0); - } - } - } else { - mplew.writeInt(0); - } - return mplew.getPacket(); - } - - public static byte[] transferInventory(List items) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); - mplew.write(0x21); - mplew.writeInt(items.size()); - if (!items.isEmpty()) { - for (MTSItemInfo item : items) { - addItemInfo(mplew, item.getItem(), true); - mplew.writeInt(item.getID()); //id - mplew.writeInt(item.getTaxes()); //taxes - mplew.writeInt(item.getPrice()); //price - mplew.writeInt(0); - mplew.writeLong(getTime(item.getEndingDate())); - mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?) - mplew.writeMapleAsciiString(item.getSeller()); //char name - for (int i = 0; i < 28; i++) { - mplew.write(0); - } - } - } - mplew.write(0xD0 + items.size()); - mplew.write(new byte[]{-1, -1, -1, 0}); - return mplew.getPacket(); - } - - public static byte[] showCouponRedeemedItem(int itemid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - mplew.writeShort(0x49); //v72 - mplew.writeInt(0); - mplew.writeInt(1); - mplew.writeShort(1); - mplew.writeShort(0x1A); - mplew.writeInt(itemid); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] showCash(MapleCharacter mc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.QUERY_CASH_RESULT.getValue()); - - mplew.writeInt(mc.getCashShop().getCash(1)); - mplew.writeInt(mc.getCashShop().getCash(2)); - mplew.writeInt(mc.getCashShop().getCash(4)); - - return mplew.getPacket(); - } - - public static byte[] enableCSUse(MapleCharacter mc) { - return showCash(mc); - } - - /** - * - * @param target - * @param mapid - * @param MTSmapCSchannel 0: MTS 1: Map 2: CS 3: Different Channel - * @return - */ - public static byte[] getFindReply(String target, int mapid, int MTSmapCSchannel) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.WHISPER.getValue()); - mplew.write(9); - mplew.writeMapleAsciiString(target); - mplew.write(MTSmapCSchannel); // 0: mts 1: map 2: cs - mplew.writeInt(mapid); // -1 if mts, cs - if (MTSmapCSchannel == 1) { - mplew.write(new byte[8]); - } - return mplew.getPacket(); - } - - /** - * - * @param target - * @param mapid - * @param MTSmapCSchannel 0: MTS 1: Map 2: CS 3: Different Channel - * @return - */ - public static byte[] getBuddyFindReply(String target, int mapid, int MTSmapCSchannel) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.WHISPER.getValue()); - mplew.write(72); - mplew.writeMapleAsciiString(target); - mplew.write(MTSmapCSchannel); // 0: mts 1: map 2: cs - mplew.writeInt(mapid); // -1 if mts, cs - if (MTSmapCSchannel == 1) { - mplew.write(new byte[8]); - } - return mplew.getPacket(); - } - - public static byte[] sendAutoHpPot(int itemId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.AUTO_HP_POT.getValue()); - mplew.writeInt(itemId); - return mplew.getPacket(); - } - - public static byte[] sendAutoMpPot(int itemId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.AUTO_MP_POT.getValue()); - mplew.writeInt(itemId); - return mplew.getPacket(); - } - - public static byte[] showOXQuiz(int questionSet, int questionId, boolean askQuestion) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.OX_QUIZ.getValue()); - mplew.write(askQuestion ? 1 : 0); - mplew.write(questionSet); - mplew.writeShort(questionId); - return mplew.getPacket(); - } - - public static byte[] updateGender(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.SET_GENDER.getValue()); - mplew.write(chr.getGender()); - return mplew.getPacket(); - } - - public static byte[] enableReport() { // thanks to snow - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.CLAIM_STATUS_CHANGED.getValue()); - mplew.write(1); - return mplew.getPacket(); - } - - public static byte[] giveFinalAttack(int skillid, int time) { // packets found thanks to lailainoob - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); - mplew.writeLong(0); - mplew.writeShort(0); - mplew.write(0);//some 80 and 0 bs DIRECTION - mplew.write(0x80);//let's just do 80, then 0 - mplew.writeInt(0); - mplew.writeShort(1); - mplew.writeInt(skillid); - mplew.writeInt(time); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] loadFamily(MapleCharacter player) { - String[] title = {"Family Reunion", "Summon Family", "My Drop Rate 1.5x (15 min)", "My EXP 1.5x (15 min)", "Family Bonding (30 min)", "My Drop Rate 2x (15 min)", "My EXP 2x (15 min)", "My Drop Rate 2x (30 min)", "My EXP 2x (30 min)", "My Party Drop Rate 2x (30 min)", "My Party EXP 2x (30 min)"}; - String[] description = {"[Target] Me\n[Effect] Teleport directly to the Family member of your choice.", "[Target] 1 Family member\n[Effect] Summon a Family member of choice to the map you're in.", "[Target] Me\n[Time] 15 min.\n[Effect] Monster drop rate will be increased #c1.5x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] Me\n[Time] 15 min.\n[Effect] EXP earned from hunting will be increased #c1.5x#.\n* If the EXP event is in progress, this will be nullified.", "[Target] At least 6 Family members online that are below me in the Pedigree\n[Time] 30 min.\n[Effect] Monster drop rate and EXP earned will be increased #c2x#. \n* If the EXP event is in progress, this will be nullified.", "[Target] Me\n[Time] 15 min.\n[Effect] Monster drop rate will be increased #c2x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] Me\n[Time] 15 min.\n[Effect] EXP earned from hunting will be increased #c2x#.\n* If the EXP event is in progress, this will be nullified.", "[Target] Me\n[Time] 30 min.\n[Effect] Monster drop rate will be increased #c2x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] Me\n[Time] 30 min.\n[Effect] EXP earned from hunting will be increased #c2x#. \n* If the EXP event is in progress, this will be nullified.", "[Target] My party\n[Time] 30 min.\n[Effect] Monster drop rate will be increased #c2x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] My party\n[Time] 30 min.\n[Effect] EXP earned from hunting will be increased #c2x#.\n* If the EXP event is in progress, this will be nullified."}; - int[] repCost = {3, 5, 7, 8, 10, 12, 15, 20, 25, 40, 50}; - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_PRIVILEGE_LIST.getValue()); - mplew.writeInt(11); - for (int i = 0; i < 11; i++) { - mplew.write(i > 4 ? (i % 2) + 1 : i); - mplew.writeInt(repCost[i] * 100); - mplew.writeInt(1); - mplew.writeMapleAsciiString(title[i]); - mplew.writeMapleAsciiString(description[i]); - } - return mplew.getPacket(); - } - - /** - * Family Result Message - * - * Possible values for type:
- * 67: You do not belong to the same family.
- * 69: The character you wish to add as\r\na Junior must be in the same - * map.
- * 70: This character is already a Junior of another character.
- * 71: The Junior you wish to add\r\nmust be at a lower rank.
- * 72: The gap between you and your\r\njunior must be within 20 levels.
- * 73: Another character has requested to add this character.\r\nPlease try - * again later.
- * 74: Another character has requested a summon.\r\nPlease try again - * later.
- * 75: The summons has failed. Your current location or state does not allow - * a summons.
- * 76: The family cannot extend more than 1000 generations from above and - * below.
- * 77: The Junior you wish to add\r\nmust be over Level 10.
- * 78: You cannot add a Junior \r\nthat has requested to change worlds.
- * 79: You cannot add a Junior \r\nsince you've requested to change - * worlds.
- * 80: Separation is not possible due to insufficient Mesos.\r\nYou will - * need %d Mesos to\r\nseparate with a Senior.
- * 81: Separation is not possible due to insufficient Mesos.\r\nYou will - * need %d Mesos to\r\nseparate with a Junior.
- * 82: The Entitlement does not apply because your level does not match the - * corresponding area.
- * - * @param type The type - * @return Family Result packet - */ - public static byte[] sendFamilyMessage(int type, int mesos) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.FAMILY_RESULT.getValue()); - mplew.writeInt(type); - mplew.writeInt(mesos); - return mplew.getPacket(); - } - - public static byte[] getFamilyInfo(MapleFamilyEntry f) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_INFO_RESULT.getValue()); - mplew.writeInt(f.getReputation()); // cur rep left - mplew.writeInt(f.getTotalReputation()); // tot rep left - mplew.writeInt(f.getTodaysRep()); // todays rep - mplew.writeShort(f.getJuniors()); // juniors added - mplew.writeShort(f.getTotalJuniors()); // juniors allowed - mplew.writeShort(0); //Unknown - mplew.writeInt(f.getId()); // id? - mplew.writeMapleAsciiString(f.getFamilyName()); - mplew.writeInt(0); - mplew.writeShort(0); - return mplew.getPacket(); - } - - public static byte[] showPedigree(int chrid, Map members) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_CHART_RESULT.getValue()); - //Hmmm xD - return mplew.getPacket(); - } - - public static byte[] updateAreaInfo(int area, String info) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(0x0A); //0x0B in v95 - mplew.writeShort(area);//infoNumber - mplew.writeMapleAsciiString(info); - return mplew.getPacket(); - } - - public static byte[] getGPMessage(int gpChange) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(6); - mplew.writeInt(gpChange); - return mplew.getPacket(); - } - - public static byte[] getItemMessage(int itemid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(7); - mplew.writeInt(itemid); - return mplew.getPacket(); - } - - public static byte[] addCard(boolean full, int cardid, int level) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); - mplew.writeShort(SendOpcode.MONSTER_BOOK_SET_CARD.getValue()); - mplew.write(full ? 0 : 1); - mplew.writeInt(cardid); - mplew.writeInt(level); - return mplew.getPacket(); - } - - public static byte[] showGainCard() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(0x0D); - return mplew.getPacket(); - } - - public static byte[] showForeignCardEffect(int id) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(id); - mplew.write(0x0D); - return mplew.getPacket(); - } - - public static byte[] changeCover(int cardid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.MONSTER_BOOK_SET_COVER.getValue()); - mplew.writeInt(cardid); - return mplew.getPacket(); - } - - public static byte[] aranGodlyStats() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FORCED_STAT_SET.getValue()); - mplew.write(new byte[]{(byte) 0x1F, (byte) 0x0F, 0, 0, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xFF, 0, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0x78, (byte) 0x8C}); - return mplew.getPacket(); - } - - public static byte[] showIntro(String path) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(0x12); - mplew.writeMapleAsciiString(path); - return mplew.getPacket(); - } - - public static byte[] showInfo(String path) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(0x17); - mplew.writeMapleAsciiString(path); - mplew.writeInt(1); - return mplew.getPacket(); - } - - /** - * Sends a UI utility. 0x01 - Equipment Inventory. 0x02 - Stat Window. 0x03 - * - Skill Window. 0x05 - Keyboard Settings. 0x06 - Quest window. 0x09 - - * Monsterbook Window. 0x0A - Char Info 0x0B - Guild BBS 0x12 - Monster - * Carnival Window 0x16 - Party Search. 0x17 - Item Creation Window. 0x1A - - * My Ranking O.O 0x1B - Family Window 0x1C - Family Pedigree 0x1D - GM - * Story Board /funny shet 0x1E - Envelop saying you got mail from an admin. - * lmfao 0x1F - Medal Window 0x20 - Maple Event (???) 0x21 - Invalid Pointer - * Crash - * - * @param ui - * @return - */ - public static byte[] openUI(byte ui) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.OPEN_UI.getValue()); - mplew.write(ui); - return mplew.getPacket(); - } - - public static byte[] lockUI(boolean enable) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.LOCK_UI.getValue()); - mplew.write(enable ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] disableUI(boolean enable) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DISABLE_UI.getValue()); - mplew.write(enable ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] itemMegaphone(String msg, boolean whisper, int channel, Item item) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); - mplew.write(8); - mplew.writeMapleAsciiString(msg); - mplew.write(channel - 1); - mplew.write(whisper ? 1 : 0); - if (item == null) { - mplew.write(0); - } else { - mplew.write(item.getPosition()); - addItemInfo(mplew, item, true); - } - return mplew.getPacket(); - } - - public static byte[] removeNPC(int oid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.REMOVE_NPC.getValue()); - mplew.writeInt(oid); - - return mplew.getPacket(); - } - - public static byte[] removeNPCController(int objectid) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - - mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue()); - mplew.write(0); - mplew.writeInt(objectid); - - return mplew.getPacket(); - } - - /** - * Sends a report response - * - * Possible values for mode:
0: You have succesfully - * reported the user.
1: Unable to locate the user.
2: You may only - * report users 10 times a day.
3: You have been reported to the GM's by - * a user.
4: Your request did not go through for unknown reasons. - * Please try again later.
- * - * @param mode The mode - * @return Report Reponse packet - */ - public static byte[] reportResponse(byte mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SUE_CHARACTER_RESULT.getValue()); - mplew.write(mode); - return mplew.getPacket(); - } - - public static byte[] sendHammerData(int hammerUsed) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.VICIOUS_HAMMER.getValue()); - mplew.write(0x39); - mplew.writeInt(0); - mplew.writeInt(hammerUsed); - return mplew.getPacket(); - } - - public static byte[] sendHammerMessage() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.VICIOUS_HAMMER.getValue()); - mplew.write(0x3D); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] playPortalSound() { - return showSpecialEffect(7); - } - - public static byte[] showMonsterBookPickup() { - return showSpecialEffect(14); - } - - public static byte[] showEquipmentLevelUp() { - return showSpecialEffect(15); - } - - public static byte[] showItemLevelup() { - return showSpecialEffect(15); - } - - public static byte[] showBuybackEffect() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(11); - mplew.writeInt(0); - - return mplew.getPacket(); - } - - public static byte[] showForeignBuybackEffect(int cid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(11); - mplew.writeInt(0); - - return mplew.getPacket(); - } - - /** - * 0 = Levelup 6 = Exp did not drop (Safety Charms) 7 = Enter portal sound 8 = Job - * change 9 = Quest complete 10 = Recovery 11 = Buff effect 14 = Monster book pickup 15 = - * Equipment levelup 16 = Maker Skill Success 17 = Buff effect w/ sfx 19 = Exp card [500, 200, 50] 21 = Wheel of destiny 26 = Spirit Stone - * - * @param effect - * @return - */ - public static byte[] showSpecialEffect(int effect) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(effect); - return mplew.getPacket(); - } - - public static byte[] showMakerEffect(boolean makerSucceeded) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(16); - mplew.writeInt(makerSucceeded ? 0 : 1); - return mplew.getPacket(); - } - - public static byte[] showForeignMakerEffect(int cid, boolean makerSucceeded) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(16); - mplew.writeInt(makerSucceeded ? 0 : 1); - return mplew.getPacket(); - } - - public static byte[] showForeignEffect(int effect) { - return showForeignEffect(-1, effect); - } - - public static byte[] showForeignEffect(int cid, int effect) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(effect); - return mplew.getPacket(); - } - - public static byte[] showOwnRecovery(byte heal) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(0x0A); - mplew.write(heal); - return mplew.getPacket(); - } - - public static byte[] showRecovery(int cid, byte amount) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); - mplew.writeInt(cid); - mplew.write(0x0A); - mplew.write(amount); - return mplew.getPacket(); - } - - public static byte[] showWheelsLeft(int left) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); - mplew.write(0x15); - mplew.write(left); - return mplew.getPacket(); - } - - public static byte[] updateQuestFinish(short quest, int npc, short nextquest) { //Check - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); //0xF2 in v95 - mplew.write(8);//0x0A in v95 - mplew.writeShort(quest); - mplew.writeInt(npc); - mplew.writeShort(nextquest); - return mplew.getPacket(); - } - - public static byte[] showInfoText(String text) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(9); - mplew.writeMapleAsciiString(text); - return mplew.getPacket(); - } - - public static byte[] questError(short quest) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); - mplew.write(0x0A); - mplew.writeShort(quest); - return mplew.getPacket(); - } - - public static byte[] questFailure(byte type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); - mplew.write(type);//0x0B = No meso, 0x0D = Worn by character, 0x0E = Not having the item ? - return mplew.getPacket(); - } - - public static byte[] questExpire(short quest) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); - mplew.write(0x0F); - mplew.writeShort(quest); - return mplew.getPacket(); - } - - public static byte[] getMultiMegaphone(String[] messages, int channel, boolean showEar) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); - mplew.write(0x0A); - if (messages[0] != null) { - mplew.writeMapleAsciiString(messages[0]); - } - mplew.write(messages.length); - for (int i = 1; i < messages.length; i++) { - if (messages[i] != null) { - mplew.writeMapleAsciiString(messages[i]); - } - } - for (int i = 0; i < 10; i++) { - mplew.write(channel - 1); - } - mplew.write(showEar ? 1 : 0); - mplew.write(1); - return mplew.getPacket(); - } - - /** - * Gets a gm effect packet (ie. hide, banned, etc.) - * - * Possible values for type:
0x04: You have successfully - * blocked access.
- * 0x05: The unblocking has been successful.
0x06 with Mode 0: You have - * successfully removed the name from the ranks.
0x06 with Mode 1: You - * have entered an invalid character name.
0x10: GM Hide, mode - * determines whether or not it is on.
0x1E: Mode 0: Failed to send - * warning Mode 1: Sent warning
0x13 with Mode 0: + mapid 0x13 with Mode - * 1: + ch (FF = Unable to find merchant) - * - * @param type The type - * @param mode The mode - * @return The gm effect packet - */ - public static byte[] getGMEffect(int type, byte mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue()); - mplew.write(type); - mplew.write(mode); - return mplew.getPacket(); - } - - public static byte[] findMerchantResponse(boolean map, int extra) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue()); - mplew.write(0x13); - mplew.write(map ? 0 : 1); //00 = mapid, 01 = ch - if (map) { - mplew.writeInt(extra); - } else { - mplew.write(extra); //-1 = unable to find - } - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] disableMinimap() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue()); - mplew.writeShort(0x1C); - return mplew.getPacket(); - } - - public static byte[] sendFamilyInvite(int playerId, String inviter) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST.getValue()); - mplew.writeInt(playerId); - mplew.writeMapleAsciiString(inviter); - return mplew.getPacket(); - } - - public static byte[] showBoughtCashPackage(List cashPackage, int accountId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x89); - mplew.write(cashPackage.size()); - - for (Item item : cashPackage) { - addCashItemInformation(mplew, item, accountId); - } - - mplew.writeShort(0); - - return mplew.getPacket(); - } - - public static byte[] showBoughtQuestItem(int itemId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x8D); - mplew.writeInt(1); - mplew.writeShort(1); - mplew.write(0x0B); - mplew.write(0); - mplew.writeInt(itemId); - - return mplew.getPacket(); - } - - private static void getGuildInfo(final MaplePacketLittleEndianWriter mplew, MapleGuild guild) { - mplew.writeInt(guild.getId()); - mplew.writeMapleAsciiString(guild.getName()); - for (int i = 1; i <= 5; i++) { - mplew.writeMapleAsciiString(guild.getRankTitle(i)); - } - Collection members = guild.getMembers(); - mplew.write(members.size()); - for (MapleGuildCharacter mgc : members) { - mplew.writeInt(mgc.getId()); - } - for (MapleGuildCharacter mgc : members) { - mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13)); - mplew.writeInt(mgc.getJobId()); - mplew.writeInt(mgc.getLevel()); - mplew.writeInt(mgc.getGuildRank()); - mplew.writeInt(mgc.isOnline() ? 1 : 0); - mplew.writeInt(guild.getSignature()); - mplew.writeInt(mgc.getAllianceRank()); - } - mplew.writeInt(guild.getCapacity()); - mplew.writeShort(guild.getLogoBG()); - mplew.write(guild.getLogoBGColor()); - mplew.writeShort(guild.getLogo()); - mplew.write(guild.getLogoColor()); - mplew.writeMapleAsciiString(guild.getNotice()); - mplew.writeInt(guild.getGP()); - mplew.writeInt(guild.getAllianceId()); - } - - public static byte[] getAllianceInfo(MapleAlliance alliance) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x0C); - mplew.write(1); - mplew.writeInt(alliance.getId()); - mplew.writeMapleAsciiString(alliance.getName()); - for (int i = 1; i <= 5; i++) { - mplew.writeMapleAsciiString(alliance.getRankTitle(i)); - } - mplew.write(alliance.getGuilds().size()); - mplew.writeInt(alliance.getCapacity()); // probably capacity - for (Integer guild : alliance.getGuilds()) { - mplew.writeInt(guild); - } - mplew.writeMapleAsciiString(alliance.getNotice()); - return mplew.getPacket(); - } - - public static byte[] updateAllianceInfo(MapleAlliance alliance, int world) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x0F); - mplew.writeInt(alliance.getId()); - mplew.writeMapleAsciiString(alliance.getName()); - for (int i = 1; i <= 5; i++) { - mplew.writeMapleAsciiString(alliance.getRankTitle(i)); - } - mplew.write(alliance.getGuilds().size()); - for (Integer guild : alliance.getGuilds()) { - mplew.writeInt(guild); - } - mplew.writeInt(alliance.getCapacity()); // probably capacity - mplew.writeShort(0); - for (Integer guildid : alliance.getGuilds()) { - getGuildInfo(mplew, Server.getInstance().getGuild(guildid, world)); - } - return mplew.getPacket(); - } - - public static byte[] getGuildAlliances(MapleAlliance alliance, int worldId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x0D); - mplew.writeInt(alliance.getGuilds().size()); - for (Integer guild : alliance.getGuilds()) { - getGuildInfo(mplew, Server.getInstance().getGuild(guild, worldId)); - } - return mplew.getPacket(); - } - - public static byte[] addGuildToAlliance(MapleAlliance alliance, int newGuild, MapleClient c) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x12); - mplew.writeInt(alliance.getId()); - mplew.writeMapleAsciiString(alliance.getName()); - for (int i = 1; i <= 5; i++) { - mplew.writeMapleAsciiString(alliance.getRankTitle(i)); - } - mplew.write(alliance.getGuilds().size()); - for (Integer guild : alliance.getGuilds()) { - mplew.writeInt(guild); - } - mplew.writeInt(alliance.getCapacity()); - mplew.writeMapleAsciiString(alliance.getNotice()); - mplew.writeInt(newGuild); - getGuildInfo(mplew, Server.getInstance().getGuild(newGuild, c.getWorld(), null)); - return mplew.getPacket(); - } - - public static byte[] allianceMemberOnline(MapleCharacter mc, boolean online) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x0E); - mplew.writeInt(mc.getGuild().getAllianceId()); - mplew.writeInt(mc.getGuildId()); - mplew.writeInt(mc.getId()); - mplew.write(online ? 1 : 0); - return mplew.getPacket(); - } - - public static byte[] allianceNotice(int id, String notice) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x1C); - mplew.writeInt(id); - mplew.writeMapleAsciiString(notice); - return mplew.getPacket(); - } - - public static byte[] changeAllianceRankTitle(int alliance, String[] ranks) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x1A); - mplew.writeInt(alliance); - for (int i = 0; i < 5; i++) { - mplew.writeMapleAsciiString(ranks[i]); - } - return mplew.getPacket(); - } - - public static byte[] updateAllianceJobLevel(MapleCharacter mc) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x18); - mplew.writeInt(mc.getGuild().getAllianceId()); - mplew.writeInt(mc.getGuildId()); - mplew.writeInt(mc.getId()); - mplew.writeInt(mc.getLevel()); - mplew.writeInt(mc.getJob().getId()); - return mplew.getPacket(); - } - - public static byte[] removeGuildFromAlliance(MapleAlliance alliance, int expelledGuild, int worldId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x10); - mplew.writeInt(alliance.getId()); - mplew.writeMapleAsciiString(alliance.getName()); - for (int i = 1; i <= 5; i++) { - mplew.writeMapleAsciiString(alliance.getRankTitle(i)); - } - mplew.write(alliance.getGuilds().size()); - for (Integer guild : alliance.getGuilds()) { - mplew.writeInt(guild); - } - mplew.writeInt(alliance.getCapacity()); - mplew.writeMapleAsciiString(alliance.getNotice()); - mplew.writeInt(expelledGuild); - getGuildInfo(mplew, Server.getInstance().getGuild(expelledGuild, worldId, null)); - mplew.write(0x01); - return mplew.getPacket(); - } - - public static byte[] disbandAlliance(int alliance) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x1D); - mplew.writeInt(alliance); - return mplew.getPacket(); - } - - public static byte[] sendAllianceInvitation(int allianceid, MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); - mplew.write(0x03); - mplew.writeInt(allianceid); - mplew.writeMapleAsciiString(chr.getName()); - mplew.writeShort(0); - return mplew.getPacket(); - } - - public static byte[] sendMesoLimit() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.TRADE_MONEY_LIMIT.getValue()); //Players under level 15 can only trade 1m per day - return mplew.getPacket(); - } - - public static byte[] sendFamilyJoinResponse(boolean accepted, String added) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST_RESULT.getValue()); - mplew.write(accepted ? 1 : 0); - mplew.writeMapleAsciiString(added); - return mplew.getPacket(); - } - - public static byte[] getSeniorMessage(String name) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_JOIN_ACCEPTED.getValue()); - mplew.writeMapleAsciiString(name); - mplew.writeInt(0); - return mplew.getPacket(); - } - - public static byte[] sendGainRep(int gain, int mode) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FAMILY_FAMOUS_POINT_INC_RESULT.getValue()); - mplew.writeInt(gain); - mplew.writeShort(0); - return mplew.getPacket(); - } - - public static byte[] removeItemFromDuey(boolean remove, int Package) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARCEL.getValue()); - mplew.write(0x17); - mplew.writeInt(Package); - mplew.write(remove ? 3 : 4); - return mplew.getPacket(); - } - - public static byte[] sendDueyNotification(boolean quickDelivery) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARCEL.getValue()); - mplew.write(0x1B); - mplew.writeBool(quickDelivery); // 0 : package received, 1 : quick delivery package - - return mplew.getPacket(); - } - - public static byte[] sendDueyMSG(byte operation) { - return sendDuey(operation, null); - } - - public static byte[] sendDuey(byte operation, List packages) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PARCEL.getValue()); - mplew.write(operation); - if (operation == 8) { - mplew.write(0); - mplew.write(packages.size()); - for (DueyPackages dp : packages) { - mplew.writeInt(dp.getPackageId()); - mplew.writeAsciiString(dp.getSender()); - for (int i = dp.getSender().length(); i < 13; i++) { - mplew.write(0); - } - mplew.writeInt(dp.getMesos()); - mplew.writeLong(getTime(dp.sentTimeInMilliseconds())); - mplew.writeLong(0); // Contains message o____o. - for (int i = 0; i < 48; i++) { - mplew.writeInt(Randomizer.nextInt(Integer.MAX_VALUE)); - } - mplew.writeInt(0); - mplew.write(0); - if (dp.getItem() != null) { - mplew.write(1); - addItemInfo(mplew, dp.getItem(), true); - } else { - mplew.write(0); - } - } - mplew.write(0); - } - - return mplew.getPacket(); - } - - public static byte[] sendDojoAnimation(byte firstByte, String animation) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(firstByte); - mplew.writeMapleAsciiString(animation); - return mplew.getPacket(); - } - - public static byte[] getDojoInfo(String info) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(10); - mplew.write(new byte[]{(byte) 0xB7, 4});//QUEST ID f5 - mplew.writeMapleAsciiString(info); - return mplew.getPacket(); - } - - public static byte[] getDojoInfoMessage(String message) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(9); - mplew.writeMapleAsciiString(message); - return mplew.getPacket(); - } - - /** - * Gets a "block" packet (ie. the cash shop is unavailable, etc) - * - * Possible values for type:
1: The portal is closed for - * now.
2: You cannot go to that place.
3: Unable to approach due to - * the force of the ground.
4: You cannot teleport to or on this - * map.
5: Unable to approach due to the force of the ground.
6: - * This map can only be entered by party members.
7: The Cash Shop is - * currently not available. Stay tuned...
- * - * @param type The type - * @return The "block" packet. - */ - public static byte[] blockedMessage(int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BLOCKED_MAP.getValue()); - mplew.write(type); - return mplew.getPacket(); - } - - /** - * Gets a "block" packet (ie. the cash shop is unavailable, etc) - * - * Possible values for type:
1: You cannot move that - * channel. Please try again later.
2: You cannot go into the cash shop. - * Please try again later.
3: The Item-Trading Shop is currently - * unavailable. Please try again later.
4: You cannot go into the trade - * shop, due to limitation of user count.
5: You do not meet the minimum - * level requirement to access the Trade Shop.
- * - * @param type The type - * @return The "block" packet. - */ - public static byte[] blockedMessage2(int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BLOCKED_SERVER.getValue()); - mplew.write(type); - return mplew.getPacket(); - } - - public static byte[] updateDojoStats(MapleCharacter chr, int belt) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(10); - mplew.write(new byte[]{(byte) 0xB7, 4}); //? - mplew.writeMapleAsciiString("pt=" + chr.getDojoPoints() + ";belt=" + belt + ";tuto=" + (chr.getFinishedDojoTutorial() ? "1" : "0")); - return mplew.getPacket(); - } - - /** - * Sends a "levelup" packet to the guild or family. - * - * Possible values for type:
0: ? has reached Lv. - * ?.
- The Reps you have received from ? will be reduced in half. 1: - * ? has reached Lv. ?.
2: ? has reached Lv. ?.
- * - * @param type The type - * @return The "levelup" packet. - */ - public static byte[] levelUpMessage(int type, int level, String charname) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NOTIFY_LEVELUP.getValue()); - mplew.write(type); - mplew.writeInt(level); - mplew.writeMapleAsciiString(charname); - - return mplew.getPacket(); - } - - /** - * Sends a "married" packet to the guild or family. - * - * Possible values for type:
0: 1: - * - * @param type The type - * @return The "married" packet. - */ - public static byte[] marriageMessage(int type, String charname) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NOTIFY_MARRIAGE.getValue()); - mplew.write(type); // 0: guild, 1: family - mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol - - return mplew.getPacket(); - } - - /** - * Sends a "job advance" packet to the guild or family. - * - * Possible values for type:
0: 1: - * - * @param type The type - * @return The "job advance" packet. - */ - public static byte[] jobMessage(int type, int job, String charname) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.NOTIFY_JOB_CHANGE.getValue()); - mplew.write(type); - mplew.writeInt(job); //Why fking int? - mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol - - return mplew.getPacket(); - } - - /** - * - * @param type - (0:Light&Long 1:Heavy&Short) - * @param delay - seconds - * @return - */ - public static byte[] trembleEffect(int type, int delay) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); - mplew.write(1); - mplew.write(type); - mplew.writeInt(delay); - return mplew.getPacket(); - } - - public static byte[] getEnergy(String info, int amount) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SESSION_VALUE.getValue()); - mplew.writeMapleAsciiString(info); - mplew.writeMapleAsciiString(Integer.toString(amount)); - return mplew.getPacket(); - } - - public static byte[] dojoWarpUp() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DOJO_WARP_UP.getValue()); - mplew.write(0); - mplew.write(6); - return mplew.getPacket(); - } - - public static byte[] itemExpired(int itemid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(2); - mplew.writeInt(itemid); - return mplew.getPacket(); - } - - private static String getRightPaddedStr(String in, char padchar, int length) { - StringBuilder builder = new StringBuilder(in); - for (int x = in.length(); x < length; x++) { - builder.append(padchar); - } - return builder.toString(); - } - - public static byte[] MobDamageMobFriendly(MapleMonster mob, int damage) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.DAMAGE_MONSTER.getValue()); - mplew.writeInt(mob.getObjectId()); - mplew.write(1); // direction ? - mplew.writeInt(damage); - - mob.applyAndGetHpDamage(damage, false); - int remainingHp = mob.getHp(); - if(remainingHp <= 0) { - remainingHp = 0; - mob.getMap().removeMapObject(mob); - } - - mplew.writeInt(remainingHp); - mplew.writeInt(mob.getMaxHp()); - return mplew.getPacket(); - } - - public static byte[] shopErrorMessage(int error, int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); - mplew.write(0x0A); - mplew.write(type); - mplew.write(error); - return mplew.getPacket(); - } - - private static void addRingInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { - mplew.writeShort(chr.getCrushRings().size()); - for (MapleRing ring : chr.getCrushRings()) { - mplew.writeInt(ring.getPartnerChrId()); - mplew.writeAsciiString(getRightPaddedStr(ring.getPartnerName(), '\0', 13)); - mplew.writeInt(ring.getRingId()); - mplew.writeInt(0); - mplew.writeInt(ring.getPartnerRingId()); - mplew.writeInt(0); - } - mplew.writeShort(chr.getFriendshipRings().size()); - for (MapleRing ring : chr.getFriendshipRings()) { - mplew.writeInt(ring.getPartnerChrId()); - mplew.writeAsciiString(getRightPaddedStr(ring.getPartnerName(), '\0', 13)); - mplew.writeInt(ring.getRingId()); - mplew.writeInt(0); - mplew.writeInt(ring.getPartnerRingId()); - mplew.writeInt(0); - mplew.writeInt(ring.getItemId()); - } - - if(chr.getPartnerId() > 0) { - MapleRing marriageRing = chr.getMarriageRing(); - - mplew.writeShort(1); - mplew.writeInt(chr.getRelationshipId()); - mplew.writeInt(chr.getGender() == 0 ? chr.getId() : chr.getPartnerId()); - mplew.writeInt(chr.getGender() == 0 ? chr.getPartnerId() : chr.getId()); - mplew.writeShort((marriageRing != null) ? 3 : 1); - if (marriageRing != null) { - mplew.writeInt(marriageRing.getItemId()); - mplew.writeInt(marriageRing.getItemId()); - } else { - mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement) - mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement) - } - mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getName() : MapleCharacter.getNameById(chr.getPartnerId()), '\0', 13)); - mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? MapleCharacter.getNameById(chr.getPartnerId()) : chr.getName(), '\0', 13)); - } else { - mplew.writeShort(0); - } - } - - public static byte[] finishedSort(int inv) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.GATHER_ITEM_RESULT.getValue()); - mplew.write(0); - mplew.write(inv); - return mplew.getPacket(); - } - - public static byte[] finishedSort2(int inv) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.SORT_ITEM_RESULT.getValue()); - mplew.write(0); - mplew.write(inv); - return mplew.getPacket(); - } - - public static byte[] bunnyPacket() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); - mplew.write(9); - mplew.writeAsciiString("Protect the Moon Bunny!!!"); - return mplew.getPacket(); - } - - public static byte[] hpqMessage(String text) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); // not 100% sure - mplew.write(0); - mplew.writeInt(5120016); - mplew.writeAsciiString(text); - return mplew.getPacket(); - } - - public static byte[] showEventInstructions() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.GMEVENT_INSTRUCTIONS.getValue()); - mplew.write(0); - return mplew.getPacket(); - } - - public static byte[] leftKnockBack() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); - mplew.writeShort(SendOpcode.LEFT_KNOCK_BACK.getValue()); - return mplew.getPacket(); - } - - public static byte[] rollSnowBall(boolean entermap, int state, MapleSnowball ball0, MapleSnowball ball1) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SNOWBALL_STATE.getValue()); - if (entermap) { - mplew.skip(21); - } else { - mplew.write(state);// 0 = move, 1 = roll, 2 is down disappear, 3 is up disappear - mplew.writeInt(ball0.getSnowmanHP() / 75); - mplew.writeInt(ball1.getSnowmanHP() / 75); - mplew.writeShort(ball0.getPosition());//distance snowball down, 84 03 = max - mplew.write(-1); - mplew.writeShort(ball1.getPosition());//distance snowball up, 84 03 = max - mplew.write(-1); - } - return mplew.getPacket(); - } - - public static byte[] hitSnowBall(int what, int damage) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.HIT_SNOWBALL.getValue()); - mplew.write(what); - mplew.writeInt(damage); - return mplew.getPacket(); - } - - /** - * Sends a Snowball Message
- * - * Possible values for message:
1: ... Team's snowball has - * passed the stage 1.
2: ... Team's snowball has passed the stage - * 2.
3: ... Team's snowball has passed the stage 3.
4: ... Team is - * attacking the snowman, stopping the progress
5: ... Team is moving - * again
- * - * @param message - * - */ - public static byte[] snowballMessage(int team, int message) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.SNOWBALL_MESSAGE.getValue()); - mplew.write(team);// 0 is down, 1 is up - mplew.writeInt(message); - return mplew.getPacket(); - } - - public static byte[] coconutScore(int team1, int team2) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.COCONUT_SCORE.getValue()); - mplew.writeShort(team1); - mplew.writeShort(team2); - return mplew.getPacket(); - } - - public static byte[] hitCoconut(boolean spawn, int id, int type) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.COCONUT_HIT.getValue()); - if (spawn) { - mplew.writeShort(-1); - mplew.writeShort(5000); - mplew.write(0); - } else { - mplew.writeShort(id); - mplew.writeShort(1000);//delay till you can attack again! - mplew.write(type); // What action to do for the coconut. - } - return mplew.getPacket(); - } - - public static byte[] customPacket(String packet) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.write(HexTool.getByteArrayFromHexString(packet)); - return mplew.getPacket(); - } - - public static byte[] customPacket(byte[] packet) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(packet.length); - mplew.write(packet); - return mplew.getPacket(); - } - - public static byte[] spawnGuide(boolean spawn) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.SPAWN_GUIDE.getValue()); - if (spawn) { - mplew.write(1); - } else { - mplew.write(0); - } - return mplew.getPacket(); - } - - public static byte[] talkGuide(String talk) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.TALK_GUIDE.getValue()); - mplew.write(0); - mplew.writeMapleAsciiString(talk); - mplew.write(new byte[]{(byte) 0xC8, 0, 0, 0, (byte) 0xA0, (byte) 0x0F, 0, 0}); - return mplew.getPacket(); - } - - public static byte[] guideHint(int hint) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); - mplew.writeShort(SendOpcode.TALK_GUIDE.getValue()); - mplew.write(1); - mplew.writeInt(hint); - mplew.writeInt(7000); - return mplew.getPacket(); - } - - public static void addCashItemInformation(final MaplePacketLittleEndianWriter mplew, Item item, int accountId) { - addCashItemInformation(mplew, item, accountId, null); - } - - public static void addCashItemInformation(final MaplePacketLittleEndianWriter mplew, Item item, int accountId, String giftMessage) { - boolean isGift = giftMessage != null; - boolean isRing = false; - Equip equip = null; - if (item.getInventoryType().equals(MapleInventoryType.EQUIP)) { - equip = (Equip) item; - isRing = equip.getRingId() > -1; - } - mplew.writeLong(item.getPetId() > -1 ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId()); - if (!isGift) { - mplew.writeInt(accountId); - mplew.writeInt(0); - } - mplew.writeInt(item.getItemId()); - if (!isGift) { - mplew.writeInt(item.getSN()); - mplew.writeShort(item.getQuantity()); - } - mplew.writeAsciiString(StringUtil.getRightPaddedStr(item.getGiftFrom(), '\0', 13)); - if (isGift) { - mplew.writeAsciiString(StringUtil.getRightPaddedStr(giftMessage, '\0', 73)); - return; - } - addExpirationTime(mplew, item.getExpiration()); - mplew.writeLong(0); - } - - public static byte[] showWishList(MapleCharacter mc, boolean update) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - if (update) { - mplew.write(0x55); - } else { - mplew.write(0x4F); - } - - for (int sn : mc.getCashShop().getWishList()) { - mplew.writeInt(sn); - } - - for (int i = mc.getCashShop().getWishList().size(); i < 10; i++) { - mplew.writeInt(0); - } - - return mplew.getPacket(); - } - - public static byte[] showBoughtCashItem(Item item, int accountId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x57); - addCashItemInformation(mplew, item, accountId); - - return mplew.getPacket(); - } - - /* - * 00 = Due to an unknown error, failed - * A4 = Due to an unknown error, failed + warpout - * A5 = You don't have enough cash. - * A6 = long as shet msg - * A7 = You have exceeded the allotted limit of price for gifts. - * A8 = You cannot send a gift to your own account. Log in on the char and purchase - * A9 = Please confirm whether the character's name is correct. - * AA = Gender restriction! - * AB = gift cannot be sent because recipient inv is full - * AC = exceeded the number of cash items you can have - * AD = check and see if the character name is wrong or there is gender restrictions - * //Skipped a few - * B0 = Wrong Coupon Code - * B1 = Disconnect from CS because of 3 wrong coupon codes < lol - * B2 = Expired Coupon - * B3 = Coupon has been used already - * B4 = Nexon internet cafes? lolfk - * BB = inv full - * BC = long as shet "(not?) available to purchase by a use at the premium" msg - * BD = invalid gift recipient - * BE = invalid receiver name - * BF = item unavailable to purchase at this hour - * C0 = not enough items in stock, therefore not available - * C1 = you have exceeded spending limit of NX - * C2 = not enough mesos? Lol not even 1 mesos xD - * C3 = cash shop unavailable during beta phase - * C4 = check birthday code - * C7 = only available to users buying cash item, whatever msg too long - * C8 = already applied for this - * D2 = coupon system currently unavailable - * D3 = item can only be used 15 days after registration - * D4 = not enough gift tokens - * D6 = fresh people cannot gift items lul - * D7 = bad people cannot gift items >:( - * D8 = cannot gift due to limitations - * D9 = cannot gift due to amount of gifted times - * DA = cannot be gifted due to technical difficulties - * DB = cannot transfer to char below level 20 - * DC = cannot transfer char to same world - * DD = cannot transfer char to new server world - * DE = cannot transfer char out of this world - * DF = cannot transfer char due to no empty char slots - * E0 = event or free test time ended - * E6 = item cannot be purchased with MaplePoints - * E7 = lol sorry for the inconvenience, eh? - * E8 = cannot be purchased by anyone under 7 - */ - public static byte[] showCashShopMessage(byte message) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x5C); - mplew.write(message); - - return mplew.getPacket(); - } - - public static byte[] showCashInventory(MapleClient c) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x4B); - mplew.writeShort(c.getPlayer().getCashShop().getInventory().size()); - - for (Item item : c.getPlayer().getCashShop().getInventory()) { - addCashItemInformation(mplew, item, c.getAccID()); - } - - mplew.writeShort(c.getPlayer().getStorage().getSlots()); - mplew.writeShort(c.getCharacterSlots()); - - return mplew.getPacket(); - } - - public static byte[] showGifts(List> gifts) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x4D); - mplew.writeShort(gifts.size()); - - for (Pair gift : gifts) { - addCashItemInformation(mplew, gift.getLeft(), 0, gift.getRight()); - } - - return mplew.getPacket(); - } - - public static byte[] showGiftSucceed(String to, CashItem item) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x5E); //0x5D, Couldn't be sent - mplew.writeMapleAsciiString(to); - mplew.writeInt(item.getItemId()); - mplew.writeShort(item.getCount()); + // 1: The room is already closed. + // 2: You can't enter the room due to full capacity. + // 3: Other requests are being fulfilled this minute. + // 4: You can't do it while you're dead. + // 7: You are not allowed to trade other items at this point. + // 17: You may not enter this store. + // 18: The owner of the store is currently undergoing store maintenance. Please try again in a bit. + // 23: This can only be used inside the Free Market. + // default: This character is unable to do it. + public static byte[] getOwlMessage(int msg) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + + mplew.writeShort(SendOpcode.SHOP_LINK_RESULT.getValue()); + mplew.write(msg); // depending on the byte sent, a different message is sent. + + return mplew.getPacket(); + } + + public static byte[] owlOfMinerva(MapleClient c, int itemid, List> hmsAvailable) { + byte itemType = ItemConstants.getInventoryType(itemid).getType(); + + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue()); // header. + mplew.write(6); + mplew.writeInt(0); + mplew.writeInt(itemid); + mplew.writeInt(hmsAvailable.size()); + for (Pair hme : hmsAvailable) { + MaplePlayerShopItem item = hme.getLeft(); + AbstractMapleMapObject mo = hme.getRight(); + + if (mo instanceof MaplePlayerShop) { + MaplePlayerShop ps = (MaplePlayerShop) mo; + MapleCharacter owner = ps.getOwner(); + + mplew.writeMapleAsciiString(owner.getName()); + mplew.writeInt(owner.getMapId()); + mplew.writeMapleAsciiString(ps.getDescription()); + mplew.writeInt(item.getBundles()); + mplew.writeInt(item.getItem().getQuantity()); mplew.writeInt(item.getPrice()); + mplew.writeInt(owner.getId()); + mplew.write(owner.getClient().getChannel() - 1); + } else { + MapleHiredMerchant hm = (MapleHiredMerchant) mo; - return mplew.getPacket(); + mplew.writeMapleAsciiString(hm.getOwner()); + mplew.writeInt(hm.getMapId()); + mplew.writeMapleAsciiString(hm.getDescription()); + mplew.writeInt(item.getBundles()); + mplew.writeInt(item.getItem().getQuantity()); + mplew.writeInt(item.getPrice()); + mplew.writeInt(hm.getOwnerId()); + mplew.write(hm.getChannel() - 1); + } + + mplew.write(itemType); + if (itemType == MapleInventoryType.EQUIP.getType()) { + addItemInfo(mplew, item.getItem(), true); + } + } + return mplew.getPacket(); + } + + public static byte[] getOwlOpen(List owlLeaderboards) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + + mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue()); + mplew.write(7); + mplew.write(owlLeaderboards.size()); + for (Integer i : owlLeaderboards) { + mplew.writeInt(i); } - public static byte[] showBoughtInventorySlots(int type, short slots) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + return mplew.getPacket(); + } - mplew.write(0x60); - mplew.write(type); - mplew.writeShort(slots); + public static byte[] retrieveFirstMessage() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header. + mplew.write(0x09); + return mplew.getPacket(); + } - return mplew.getPacket(); + public static byte[] remoteChannelChange(byte ch) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header. + mplew.write(0x10); + mplew.writeInt(0);//No idea yet + mplew.write(ch); + return mplew.getPacket(); + } + /* + * Possible things for ENTRUSTED_SHOP_CHECK_RESULT + * 0x0E = 00 = Renaming Failed - Can't find the merchant, 01 = Renaming successful + * 0x10 = Changes channel to the store (Store is open at Channel 1, do you want to change channels?) + * 0x11 = You cannot sell any items when managing.. blabla + * 0x12 = FKING POPUP LOL + */ + + public static byte[] getHiredMerchant(MapleCharacter chr, MapleHiredMerchant hm, boolean firstTime) {//Thanks Dustin + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(0x05); + mplew.write(0x04); + mplew.writeShort(hm.getVisitorSlotThreadsafe(chr) + 1); + mplew.writeInt(hm.getItemId()); + mplew.writeMapleAsciiString("Hired Merchant"); + + MapleCharacter visitors[] = hm.getVisitors(); + for (int i = 0; i < 3; i++) { + if (visitors[i] != null) { + mplew.write(i + 1); + addCharLook(mplew, visitors[i], false); + mplew.writeMapleAsciiString(visitors[i].getName()); + } } + mplew.write(-1); + if (hm.isOwner(chr)) { + List> msgList = hm.getMessages(); - public static byte[] showBoughtStorageSlots(short slots) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x62); - mplew.writeShort(slots); - - return mplew.getPacket(); + mplew.writeShort(msgList.size()); + for (int i = 0; i < msgList.size(); i++) { + mplew.writeMapleAsciiString(msgList.get(i).getLeft()); + mplew.write(msgList.get(i).getRight()); + } + } else { + mplew.writeShort(0); } - - public static byte[] showBoughtCharacterSlot(short slots) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x64); - mplew.writeShort(slots); - - return mplew.getPacket(); + mplew.writeMapleAsciiString(hm.getOwner()); + if (hm.isOwner(chr)) { + mplew.writeInt(hm.getTimeLeft()); + mplew.write(firstTime ? 1 : 0); + List sold = hm.getSold(); + mplew.write(sold.size()); + for (MapleHiredMerchant.SoldItem s : sold) { + mplew.writeInt(s.getItemId()); + mplew.writeShort(s.getQuantity()); + mplew.writeInt(s.getMesos()); + mplew.writeMapleAsciiString(s.getBuyer()); + } + mplew.writeInt(chr.getMerchantMeso());//:D? } - - public static byte[] takeFromCashInventory(Item item) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x68); - mplew.writeShort(item.getPosition()); - addItemInfo(mplew, item, true); - - return mplew.getPacket(); + mplew.writeMapleAsciiString(hm.getDescription()); + mplew.write(0x10); //TODO SLOTS, which is 16 for most stores...slotMax + mplew.writeInt(hm.isOwner(chr) ? chr.getMerchantMeso() : chr.getMeso()); + mplew.write(hm.getItems().size()); + if (hm.getItems().isEmpty()) { + mplew.write(0);//Hmm?? + } else { + for (MaplePlayerShopItem item : hm.getItems()) { + mplew.writeShort(item.getBundles()); + mplew.writeShort(item.getItem().getQuantity()); + mplew.writeInt(item.getPrice()); + addItemInfo(mplew, item.getItem(), true); + } } + return mplew.getPacket(); + } - public static byte[] putIntoCashInventory(Item item, int accountId) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); - - mplew.write(0x6A); - addCashItemInformation(mplew, item, accountId); - - return mplew.getPacket(); + public static byte[] updateHiredMerchant(MapleHiredMerchant hm, MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.UPDATE_MERCHANT.getCode()); + mplew.writeInt(hm.isOwner(chr) ? chr.getMerchantMeso() : chr.getMeso()); + mplew.write(hm.getItems().size()); + for (MaplePlayerShopItem item : hm.getItems()) { + mplew.writeShort(item.getBundles()); + mplew.writeShort(item.getItem().getQuantity()); + mplew.writeInt(item.getPrice()); + addItemInfo(mplew, item.getItem(), true); } + return mplew.getPacket(); + } - public static byte[] openCashShop(MapleClient c, boolean mts) throws Exception { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(mts ? SendOpcode.SET_ITC.getValue() : SendOpcode.SET_CASH_SHOP.getValue()); + public static byte[] hiredMerchantChat(String message, byte slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.CHAT.getCode()); + mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode()); + mplew.write(slot); + mplew.writeMapleAsciiString(message); + return mplew.getPacket(); + } - addCharacterInfo(mplew, c.getPlayer()); + public static byte[] hiredMerchantVisitorLeave(int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + if (slot != 0) { + mplew.write(slot); + } + return mplew.getPacket(); + } - if (!mts) { - mplew.write(1); + public static byte[] hiredMerchantOwnerLeave() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.REAL_CLOSE_MERCHANT.getCode()); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] hiredMerchantOwnerMaintenanceLeave() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.REAL_CLOSE_MERCHANT.getCode()); + mplew.write(5); + return mplew.getPacket(); + } + + public static byte[] hiredMerchantMaintenanceMessage() { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.ROOM.getCode()); + mplew.write(0x00); + mplew.write(0x12); + return mplew.getPacket(); + } + + public static byte[] leaveHiredMerchant(int slot, int status2) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.EXIT.getCode()); + mplew.write(slot); + mplew.write(status2); + return mplew.getPacket(); + } + + public static byte[] hiredMerchantVisitorAdd(MapleCharacter chr, int slot) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(PlayerInteractionHandler.Action.VISIT.getCode()); + mplew.write(slot); + addCharLook(mplew, chr, false); + mplew.writeMapleAsciiString(chr.getName()); + return mplew.getPacket(); + } + + public static byte[] spawnHiredMerchantBox(MapleHiredMerchant hm) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_HIRED_MERCHANT.getValue()); + mplew.writeInt(hm.getOwnerId()); + mplew.writeInt(hm.getItemId()); + mplew.writeShort((short) hm.getPosition().getX()); + mplew.writeShort((short) hm.getPosition().getY()); + mplew.writeShort(0); + mplew.writeMapleAsciiString(hm.getOwner()); + mplew.write(0x05); + mplew.writeInt(hm.getObjectId()); + mplew.writeMapleAsciiString(hm.getDescription()); + mplew.write(hm.getItemId() % 100); + mplew.write(new byte[]{1, 4}); + return mplew.getPacket(); + } + + public static byte[] removeHiredMerchantBox(int id) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DESTROY_HIRED_MERCHANT.getValue()); + mplew.writeInt(id); + return mplew.getPacket(); + } + + public static byte[] spawnPlayerNPC(MaplePlayerNPC npc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue()); + mplew.write(1); + mplew.writeInt(npc.getObjectId()); + mplew.writeInt(npc.getScriptId()); + mplew.writeShort(npc.getPosition().x); + mplew.writeShort(npc.getCY()); + mplew.write(npc.getDirection()); + mplew.writeShort(npc.getFH()); + mplew.writeShort(npc.getRX0()); + mplew.writeShort(npc.getRX1()); + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] getPlayerNPC(MaplePlayerNPC npc) { // thanks to Arnah + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.IMITATED_NPC_DATA.getValue()); + mplew.write(0x01); + mplew.writeInt(npc.getScriptId()); + mplew.writeMapleAsciiString(npc.getName()); + mplew.write(npc.getGender()); + mplew.write(npc.getSkin()); + mplew.writeInt(npc.getFace()); + mplew.write(0); + mplew.writeInt(npc.getHair()); + Map equip = npc.getEquips(); + Map myEquip = new LinkedHashMap<>(); + Map maskedEquip = new LinkedHashMap<>(); + for (short position : equip.keySet()) { + short pos = (byte) (position * -1); + if (pos < 100 && myEquip.get(pos) == null) { + myEquip.put(pos, equip.get(position)); + } else if ((pos > 100 && pos != 111) || pos == -128) { // don't ask. o.o + pos -= 100; + if (myEquip.get(pos) != null) { + maskedEquip.put(pos, myEquip.get(pos)); } - - mplew.writeMapleAsciiString(c.getAccountName()); - if (mts) { - mplew.write(new byte[]{(byte) 0x88, 19, 0, 0, 7, 0, 0, 0, (byte) 0xF4, 1, 0, 0, (byte) 0x18, 0, 0, 0, (byte) 0xA8, 0, 0, 0, (byte) 0x70, (byte) 0xAA, (byte) 0xA7, (byte) 0xC5, (byte) 0x4E, (byte) 0xC1, (byte) 0xCA, 1}); - } else { - mplew.writeInt(0); - List lsci = CashItemFactory.getSpecialCashItems(); - mplew.writeShort(lsci.size());//Guess what - for (SpecialCashItem sci : lsci) { - mplew.writeInt(sci.getSN()); - mplew.writeInt(sci.getModifier()); - mplew.write(sci.getInfo()); - } - mplew.skip(121); - - List> mostSellers = c.getWorldServer().getMostSellerCashItems(); - for (int i = 1; i <= 8; i++) { - List mostSellersTab = mostSellers.get(i); - - for (int j = 0; j < 2; j++) { - for (Integer snid : mostSellersTab) { - mplew.writeInt(i); - mplew.writeInt(j); - mplew.writeInt(snid); - } - } - } - - mplew.writeInt(0); - mplew.writeShort(0); - mplew.write(0); - mplew.writeInt(75); - } - return mplew.getPacket(); + myEquip.put(pos, equip.get(position)); + } else if (myEquip.get(pos) != null) { + maskedEquip.put(pos, equip.get(position)); + } } - - public static byte[] sendVegaScroll(int op) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.VEGA_SCROLL.getValue()); - mplew.write(op); - return mplew.getPacket(); + for (Entry entry : myEquip.entrySet()) { + mplew.write(entry.getKey()); + mplew.writeInt(entry.getValue()); } - - public static byte[] resetForcedStats() { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); - mplew.writeShort(SendOpcode.FORCED_STAT_RESET.getValue()); - return mplew.getPacket(); + mplew.write(0xFF); + for (Entry entry : maskedEquip.entrySet()) { + mplew.write(entry.getKey()); + mplew.writeInt(entry.getValue()); } - - public static byte[] showCombo(int count) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.SHOW_COMBO.getValue()); - mplew.writeInt(count); - return mplew.getPacket(); + mplew.write(0xFF); + Integer cWeapon = equip.get((byte) -111); + if (cWeapon != null) { + mplew.writeInt(cWeapon); + } else { + mplew.writeInt(0); } - - public static byte[] earnTitleMessage(String msg) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SCRIPT_PROGRESS_MESSAGE.getValue()); - mplew.writeMapleAsciiString(msg); - return mplew.getPacket(); + for (int i = 0; i < 3; i++) { + mplew.writeInt(0); } + return mplew.getPacket(); + } - public static byte[] startCPQ(MapleCharacter chr, MonsterCarnivalParty enemy) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(25); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_START.getValue()); - mplew.write(chr.getTeam()); //team - mplew.writeShort(chr.getCP()); //Obtained CP - Used CP - mplew.writeShort(chr.getObtainedCP()); //Total Obtained CP - mplew.writeShort(chr.getCarnivalParty().getAvailableCP()); //Obtained CP - Used CP of the team - mplew.writeShort(chr.getCarnivalParty().getTotalCP()); //Total Obtained CP of the team - mplew.writeShort(enemy.getAvailableCP()); //Obtained CP - Used CP of the team - mplew.writeShort(enemy.getTotalCP()); //Total Obtained CP of the team - mplew.writeShort(0); //Probably useless nexon shit - mplew.writeLong(0); //Probably useless nexon shit - return mplew.getPacket(); + public static byte[] removePlayerNPC(int oid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.IMITATED_NPC_DATA.getValue()); + mplew.write(0x00); + mplew.writeInt(oid); + + return mplew.getPacket(); + } + + public static byte[] sendYellowTip(String tip) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_WEEK_EVENT_MESSAGE.getValue()); + mplew.write(0xFF); + mplew.writeMapleAsciiString(tip); + mplew.writeShort(0); + return mplew.getPacket(); + } + + public static byte[] givePirateBuff(List> statups, int buffid, int duration) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + boolean infusion = buffid == Buccaneer.SPEED_INFUSION || buffid == ThunderBreaker.SPEED_INFUSION || buffid == Corsair.SPEED_INFUSION; + mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); + writeLongMask(mplew, statups); + mplew.writeShort(0); + for (Pair stat : statups) { + mplew.writeInt(stat.getRight().shortValue()); + mplew.writeInt(buffid); + mplew.skip(infusion ? 10 : 5); + mplew.writeShort(duration); } + mplew.skip(3); + return mplew.getPacket(); + } - public static byte[] updateCP(int cp, int tcp) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_OBTAINED_CP.getValue()); - mplew.writeShort(cp); //Obtained CP - Used CP - mplew.writeShort(tcp); //Total Obtained CP - return mplew.getPacket(); + public static byte[] giveForeignPirateBuff(int cid, int buffid, int time, List> statups) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + boolean infusion = buffid == Buccaneer.SPEED_INFUSION || buffid == ThunderBreaker.SPEED_INFUSION || buffid == Corsair.SPEED_INFUSION; + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMask(mplew, statups); + mplew.writeShort(0); + for (Pair statup : statups) { + mplew.writeInt(statup.getRight().shortValue()); + mplew.writeInt(buffid); + mplew.skip(infusion ? 10 : 5); + mplew.writeShort(time); } + mplew.writeShort(0); + mplew.write(2); + return mplew.getPacket(); + } - public static byte[] updatePartyCP(MonsterCarnivalParty party) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_PARTY_CP.getValue()); - mplew.write(party.getTeam()); //Team where the points are given to. - mplew.writeShort(party.getAvailableCP()); //Obtained CP - Used CP - mplew.writeShort(party.getTotalCP()); //Total Obtained CP - return mplew.getPacket(); - } - - public static byte[] CPQSummon(int tab, int number, String name) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_SUMMON.getValue()); - mplew.write(tab); //Tab - mplew.writeShort(number); //Number of summon inside the tab - mplew.writeMapleAsciiString(name); //Name of the player that summons - return mplew.getPacket(); - } - - public static byte[] CPQDied(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_DIED.getValue()); - mplew.write(chr.getTeam()); //Team - mplew.writeMapleAsciiString(chr.getName()); //Name of the player that died - mplew.write(chr.getAndRemoveCP()); //Lost CP - return mplew.getPacket(); - } - - /** - * Sends a CPQ Message
- * - * Possible values for message:
1: You don't have enough CP - * to continue.
2: You can no longer summon the Monster.
3: You can - * no longer summon the being.
4: This being is already summoned.
5: - * This request has failed due to an unknown error.
- * - * @param message Displays a message inside Carnival PQ - * - */ - public static byte[] CPQMessage(byte message) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_MESSAGE.getValue()); - mplew.write(message); //Message - return mplew.getPacket(); - } - - public static byte[] leaveCPQ(MapleCharacter chr) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_LEAVE.getValue()); - mplew.write(0); //Something - mplew.write(chr.getTeam()); //Team - mplew.writeMapleAsciiString(chr.getName()); //Player name - return mplew.getPacket(); - } - - public static byte[] sheepRanchInfo(byte wolf, byte sheep) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHEEP_RANCH_INFO.getValue()); - mplew.write(wolf); - mplew.write(sheep); - return mplew.getPacket(); - } - //Know what this is? ?? >=) - - public static byte[] sheepRanchClothes(int id, byte clothes) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SHEEP_RANCH_CLOTHES.getValue()); - mplew.writeInt(id); //Character id - mplew.write(clothes); //0 = sheep, 1 = wolf, 2 = Spectator (wolf without wool) - return mplew.getPacket(); - } - - public static byte[] incubatorResult() {//lol - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); - mplew.writeShort(SendOpcode.INCUBATOR_RESULT.getValue()); - mplew.skip(6); - return mplew.getPacket(); - } - - public static byte[] pyramidGauge(int gauge) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); - mplew.writeShort(SendOpcode.PYRAMID_GAUGE.getValue()); - mplew.writeInt(gauge); - return mplew.getPacket(); - } - // f2 - - public static byte[] pyramidScore(byte score, int exp) {//Type cannot be higher than 4 (Rank D), otherwise you'll crash - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); - mplew.writeShort(SendOpcode.PYRAMID_SCORE.getValue()); - mplew.write(score); - mplew.writeInt(exp); - return mplew.getPacket(); - } - - public static byte[] spawnDragon(MapleDragon dragon) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SPAWN_DRAGON.getValue()); - mplew.writeInt(dragon.getOwner().getId());//objectid = owner id - mplew.writeShort(dragon.getPosition().x); - mplew.writeShort(0); - mplew.writeShort(dragon.getPosition().y); - mplew.writeShort(0); - mplew.write(dragon.getStance()); + public static byte[] sendMTS(List items, int tab, int type, int page, int pages) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x15); //operation + mplew.writeInt(pages * 16); //testing, change to 10 if fails + mplew.writeInt(items.size()); //number of items + mplew.writeInt(tab); + mplew.writeInt(type); + mplew.writeInt(page); + mplew.write(1); + mplew.write(1); + for (int i = 0; i < items.size(); i++) { + MTSItemInfo item = items.get(i); + addItemInfo(mplew, item.getItem(), true); + mplew.writeInt(item.getID()); //id + mplew.writeInt(item.getTaxes()); //this + below = price + mplew.writeInt(item.getPrice()); //price + mplew.writeInt(0); + mplew.writeLong(getTime(item.getEndingDate())); + mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?) + mplew.writeMapleAsciiString(item.getSeller()); //char name + for (int j = 0; j < 28; j++) { mplew.write(0); - mplew.writeShort(dragon.getOwner().getJob().getId()); - return mplew.getPacket(); + } + } + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] noteSendMsg() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.MEMO_RESULT.getValue()); + mplew.write(4); + return mplew.getPacket(); + } + + /* + * 0 = Player online, use whisper + * 1 = Check player's name + * 2 = Receiver inbox full + */ + public static byte[] noteError(byte error) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.MEMO_RESULT.getValue()); + mplew.write(5); + mplew.write(error); + return mplew.getPacket(); + } + + public static byte[] showNotes(ResultSet notes, int count) throws SQLException { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MEMO_RESULT.getValue()); + mplew.write(3); + mplew.write(count); + for (int i = 0; i < count; i++) { + mplew.writeInt(notes.getInt("id")); + mplew.writeMapleAsciiString(notes.getString("from") + " ");//Stupid nexon forgot space lol + mplew.writeMapleAsciiString(notes.getString("message")); + mplew.writeLong(getTime(notes.getLong("timestamp"))); + mplew.write(notes.getByte("fame"));//FAME :D + notes.next(); + } + return mplew.getPacket(); + } + + public static byte[] useChalkboard(MapleCharacter chr, boolean close) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CHALKBOARD.getValue()); + mplew.writeInt(chr.getId()); + if (close) { + mplew.write(0); + } else { + mplew.write(1); + mplew.writeMapleAsciiString(chr.getChalkboard()); + } + return mplew.getPacket(); + } + + public static byte[] trockRefreshMapList(MapleCharacter chr, boolean delete, boolean vip) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MAP_TRANSFER_RESULT.getValue()); + mplew.write(delete ? 2 : 3); + if (vip) { + mplew.write(1); + List map = chr.getVipTrockMaps(); + for (int i = 0; i < 10; i++) { + mplew.writeInt(map.get(i)); + } + } else { + mplew.write(0); + List map = chr.getTrockMaps(); + for (int i = 0; i < 5; i++) { + mplew.writeInt(map.get(i)); + } + } + return mplew.getPacket(); + } + + /* 1: cannot find char info, + 2: cannot transfer under 20, + 3: cannot send banned, + 4: cannot send married, + 5: cannot send guild leader, + 6: cannot send if account already requested transfer, + 7: cannot transfer within 30days, + 8: must quit family, + 9: unknown error + */ + public static byte[] sendWorldTransferRules(int error) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_CHECK_TRANSFER_WORLD_POSSIBLE_RESULT.getValue()); + mplew.writeInt(0); + mplew.write(0); + mplew.write(error); + mplew.writeInt(0); + + return mplew.getPacket(); + } + + /* 1: name change already submitted + 2: name change within a month + 3: recently banned + 4: unknown error + */ + public static byte[] sendNameTransferRules(int error) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_CHECK_NAME_CHANGE_POSSIBLE_RESULT.getValue()); + mplew.writeInt(0); + mplew.write(error); + mplew.writeInt(0); + + return mplew.getPacket(); + } + + public static byte[] sendNameTransferCheck(boolean canUseName) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_CHECK_NAME_CHANGE.getValue()); + mplew.writeShort(0); + mplew.writeBool(!canUseName); + + return mplew.getPacket(); + } + + public static byte[] showMTSCash(MapleCharacter p) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION2.getValue()); + mplew.writeInt(p.getCashShop().getCash(4)); + mplew.writeInt(p.getCashShop().getCash(2)); + return mplew.getPacket(); + } + + public static byte[] MTSWantedListingOver(int nx, int items) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x3D); + mplew.writeInt(nx); + mplew.writeInt(items); + return mplew.getPacket(); + } + + public static byte[] MTSConfirmSell() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x1D); + return mplew.getPacket(); + } + + public static byte[] MTSConfirmBuy() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x33); + return mplew.getPacket(); + } + + public static byte[] MTSFailBuy() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x34); + mplew.write(0x42); + return mplew.getPacket(); + } + + public static byte[] MTSConfirmTransfer(int quantity, int pos) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x27); + mplew.writeInt(quantity); + mplew.writeInt(pos); + return mplew.getPacket(); + } + + public static byte[] notYetSoldInv(List items) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x23); + mplew.writeInt(items.size()); + if (!items.isEmpty()) { + for (MTSItemInfo item : items) { + addItemInfo(mplew, item.getItem(), true); + mplew.writeInt(item.getID()); //id + mplew.writeInt(item.getTaxes()); //this + below = price + mplew.writeInt(item.getPrice()); //price + mplew.writeInt(0); + mplew.writeLong(getTime(item.getEndingDate())); + mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?) + mplew.writeMapleAsciiString(item.getSeller()); //char name + for (int i = 0; i < 28; i++) { + mplew.write(0); + } + } + } else { + mplew.writeInt(0); + } + return mplew.getPacket(); + } + + public static byte[] transferInventory(List items) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MTS_OPERATION.getValue()); + mplew.write(0x21); + mplew.writeInt(items.size()); + if (!items.isEmpty()) { + for (MTSItemInfo item : items) { + addItemInfo(mplew, item.getItem(), true); + mplew.writeInt(item.getID()); //id + mplew.writeInt(item.getTaxes()); //taxes + mplew.writeInt(item.getPrice()); //price + mplew.writeInt(0); + mplew.writeLong(getTime(item.getEndingDate())); + mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?) + mplew.writeMapleAsciiString(item.getSeller()); //char name + for (int i = 0; i < 28; i++) { + mplew.write(0); + } + } + } + mplew.write(0xD0 + items.size()); + mplew.write(new byte[]{-1, -1, -1, 0}); + return mplew.getPacket(); + } + + public static byte[] showCouponRedeemedItem(int itemid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + mplew.writeShort(0x49); //v72 + mplew.writeInt(0); + mplew.writeInt(1); + mplew.writeShort(1); + mplew.writeShort(0x1A); + mplew.writeInt(itemid); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] showCash(MapleCharacter mc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.QUERY_CASH_RESULT.getValue()); + + mplew.writeInt(mc.getCashShop().getCash(1)); + mplew.writeInt(mc.getCashShop().getCash(2)); + mplew.writeInt(mc.getCashShop().getCash(4)); + + return mplew.getPacket(); + } + + public static byte[] enableCSUse(MapleCharacter mc) { + return showCash(mc); + } + + /** + * + * @param target + * @param mapid + * @param MTSmapCSchannel 0: MTS 1: Map 2: CS 3: Different Channel + * @return + */ + public static byte[] getFindReply(String target, int mapid, int MTSmapCSchannel) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.WHISPER.getValue()); + mplew.write(9); + mplew.writeMapleAsciiString(target); + mplew.write(MTSmapCSchannel); // 0: mts 1: map 2: cs + mplew.writeInt(mapid); // -1 if mts, cs + if (MTSmapCSchannel == 1) { + mplew.write(new byte[8]); + } + return mplew.getPacket(); + } + + /** + * + * @param target + * @param mapid + * @param MTSmapCSchannel 0: MTS 1: Map 2: CS 3: Different Channel + * @return + */ + public static byte[] getBuddyFindReply(String target, int mapid, int MTSmapCSchannel) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.WHISPER.getValue()); + mplew.write(72); + mplew.writeMapleAsciiString(target); + mplew.write(MTSmapCSchannel); // 0: mts 1: map 2: cs + mplew.writeInt(mapid); // -1 if mts, cs + if (MTSmapCSchannel == 1) { + mplew.write(new byte[8]); + } + return mplew.getPacket(); + } + + public static byte[] sendAutoHpPot(int itemId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.AUTO_HP_POT.getValue()); + mplew.writeInt(itemId); + return mplew.getPacket(); + } + + public static byte[] sendAutoMpPot(int itemId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.AUTO_MP_POT.getValue()); + mplew.writeInt(itemId); + return mplew.getPacket(); + } + + public static byte[] showOXQuiz(int questionSet, int questionId, boolean askQuestion) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.OX_QUIZ.getValue()); + mplew.write(askQuestion ? 1 : 0); + mplew.write(questionSet); + mplew.writeShort(questionId); + return mplew.getPacket(); + } + + public static byte[] updateGender(MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.SET_GENDER.getValue()); + mplew.write(chr.getGender()); + return mplew.getPacket(); + } + + public static byte[] enableReport() { // thanks to snow + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.CLAIM_STATUS_CHANGED.getValue()); + mplew.write(1); + return mplew.getPacket(); + } + + public static byte[] giveFinalAttack(int skillid, int time) { // packets found thanks to lailainoob + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GIVE_BUFF.getValue()); + mplew.writeLong(0); + mplew.writeShort(0); + mplew.write(0);//some 80 and 0 bs DIRECTION + mplew.write(0x80);//let's just do 80, then 0 + mplew.writeInt(0); + mplew.writeShort(1); + mplew.writeInt(skillid); + mplew.writeInt(time); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] loadFamily(MapleCharacter player) { + String[] title = {"Family Reunion", "Summon Family", "My Drop Rate 1.5x (15 min)", "My EXP 1.5x (15 min)", "Family Bonding (30 min)", "My Drop Rate 2x (15 min)", "My EXP 2x (15 min)", "My Drop Rate 2x (30 min)", "My EXP 2x (30 min)", "My Party Drop Rate 2x (30 min)", "My Party EXP 2x (30 min)"}; + String[] description = {"[Target] Me\n[Effect] Teleport directly to the Family member of your choice.", "[Target] 1 Family member\n[Effect] Summon a Family member of choice to the map you're in.", "[Target] Me\n[Time] 15 min.\n[Effect] Monster drop rate will be increased #c1.5x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] Me\n[Time] 15 min.\n[Effect] EXP earned from hunting will be increased #c1.5x#.\n* If the EXP event is in progress, this will be nullified.", "[Target] At least 6 Family members online that are below me in the Pedigree\n[Time] 30 min.\n[Effect] Monster drop rate and EXP earned will be increased #c2x#. \n* If the EXP event is in progress, this will be nullified.", "[Target] Me\n[Time] 15 min.\n[Effect] Monster drop rate will be increased #c2x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] Me\n[Time] 15 min.\n[Effect] EXP earned from hunting will be increased #c2x#.\n* If the EXP event is in progress, this will be nullified.", "[Target] Me\n[Time] 30 min.\n[Effect] Monster drop rate will be increased #c2x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] Me\n[Time] 30 min.\n[Effect] EXP earned from hunting will be increased #c2x#. \n* If the EXP event is in progress, this will be nullified.", "[Target] My party\n[Time] 30 min.\n[Effect] Monster drop rate will be increased #c2x#.\n* If the Drop Rate event is in progress, this will be nullified.", "[Target] My party\n[Time] 30 min.\n[Effect] EXP earned from hunting will be increased #c2x#.\n* If the EXP event is in progress, this will be nullified."}; + int[] repCost = {3, 5, 7, 8, 10, 12, 15, 20, 25, 40, 50}; + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_PRIVILEGE_LIST.getValue()); + mplew.writeInt(11); + for (int i = 0; i < 11; i++) { + mplew.write(i > 4 ? (i % 2) + 1 : i); + mplew.writeInt(repCost[i] * 100); + mplew.writeInt(1); + mplew.writeMapleAsciiString(title[i]); + mplew.writeMapleAsciiString(description[i]); + } + return mplew.getPacket(); + } + + /** + * Family Result Message + * + * Possible values for type:
+ * 67: You do not belong to the same family.
+ * 69: The character you wish to add as\r\na Junior must be in the same + * map.
+ * 70: This character is already a Junior of another character.
+ * 71: The Junior you wish to add\r\nmust be at a lower rank.
+ * 72: The gap between you and your\r\njunior must be within 20 levels.
+ * 73: Another character has requested to add this character.\r\nPlease try + * again later.
+ * 74: Another character has requested a summon.\r\nPlease try again + * later.
+ * 75: The summons has failed. Your current location or state does not allow + * a summons.
+ * 76: The family cannot extend more than 1000 generations from above and + * below.
+ * 77: The Junior you wish to add\r\nmust be over Level 10.
+ * 78: You cannot add a Junior \r\nthat has requested to change worlds.
+ * 79: You cannot add a Junior \r\nsince you've requested to change + * worlds.
+ * 80: Separation is not possible due to insufficient Mesos.\r\nYou will + * need %d Mesos to\r\nseparate with a Senior.
+ * 81: Separation is not possible due to insufficient Mesos.\r\nYou will + * need %d Mesos to\r\nseparate with a Junior.
+ * 82: The Entitlement does not apply because your level does not match the + * corresponding area.
+ * + * @param type The type + * @return Family Result packet + */ + public static byte[] sendFamilyMessage(int type, int mesos) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.FAMILY_RESULT.getValue()); + mplew.writeInt(type); + mplew.writeInt(mesos); + return mplew.getPacket(); + } + + public static byte[] getFamilyInfo(MapleFamilyEntry f) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_INFO_RESULT.getValue()); + mplew.writeInt(f.getReputation()); // cur rep left + mplew.writeInt(f.getTotalReputation()); // tot rep left + mplew.writeInt(f.getTodaysRep()); // todays rep + mplew.writeShort(f.getJuniors()); // juniors added + mplew.writeShort(f.getTotalJuniors()); // juniors allowed + mplew.writeShort(0); //Unknown + mplew.writeInt(f.getId()); // id? + mplew.writeMapleAsciiString(f.getFamilyName()); + mplew.writeInt(0); + mplew.writeShort(0); + return mplew.getPacket(); + } + + public static byte[] showPedigree(int chrid, Map members) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_CHART_RESULT.getValue()); + //Hmmm xD + return mplew.getPacket(); + } + + public static byte[] updateAreaInfo(int area, String info) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(0x0A); //0x0B in v95 + mplew.writeShort(area);//infoNumber + mplew.writeMapleAsciiString(info); + return mplew.getPacket(); + } + + public static byte[] getGPMessage(int gpChange) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(6); + mplew.writeInt(gpChange); + return mplew.getPacket(); + } + + public static byte[] getItemMessage(int itemid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(7); + mplew.writeInt(itemid); + return mplew.getPacket(); + } + + public static byte[] addCard(boolean full, int cardid, int level) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); + mplew.writeShort(SendOpcode.MONSTER_BOOK_SET_CARD.getValue()); + mplew.write(full ? 0 : 1); + mplew.writeInt(cardid); + mplew.writeInt(level); + return mplew.getPacket(); + } + + public static byte[] showGainCard() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(0x0D); + return mplew.getPacket(); + } + + public static byte[] showForeignCardEffect(int id) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(id); + mplew.write(0x0D); + return mplew.getPacket(); + } + + public static byte[] changeCover(int cardid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.MONSTER_BOOK_SET_COVER.getValue()); + mplew.writeInt(cardid); + return mplew.getPacket(); + } + + public static byte[] aranGodlyStats() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FORCED_STAT_SET.getValue()); + mplew.write(new byte[]{(byte) 0x1F, (byte) 0x0F, 0, 0, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xFF, 0, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0x78, (byte) 0x8C}); + return mplew.getPacket(); + } + + public static byte[] showIntro(String path) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(0x12); + mplew.writeMapleAsciiString(path); + return mplew.getPacket(); + } + + public static byte[] showInfo(String path) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(0x17); + mplew.writeMapleAsciiString(path); + mplew.writeInt(1); + return mplew.getPacket(); + } + + /** + * Sends a UI utility. 0x01 - Equipment Inventory. 0x02 - Stat Window. 0x03 + * - Skill Window. 0x05 - Keyboard Settings. 0x06 - Quest window. 0x09 - + * Monsterbook Window. 0x0A - Char Info 0x0B - Guild BBS 0x12 - Monster + * Carnival Window 0x16 - Party Search. 0x17 - Item Creation Window. 0x1A - + * My Ranking O.O 0x1B - Family Window 0x1C - Family Pedigree 0x1D - GM + * Story Board /funny shet 0x1E - Envelop saying you got mail from an admin. + * lmfao 0x1F - Medal Window 0x20 - Maple Event (???) 0x21 - Invalid Pointer + * Crash + * + * @param ui + * @return + */ + public static byte[] openUI(byte ui) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.OPEN_UI.getValue()); + mplew.write(ui); + return mplew.getPacket(); + } + + public static byte[] lockUI(boolean enable) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.LOCK_UI.getValue()); + mplew.write(enable ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] disableUI(boolean enable) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DISABLE_UI.getValue()); + mplew.write(enable ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] itemMegaphone(String msg, boolean whisper, int channel, Item item) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); + mplew.write(8); + mplew.writeMapleAsciiString(msg); + mplew.write(channel - 1); + mplew.write(whisper ? 1 : 0); + if (item == null) { + mplew.write(0); + } else { + mplew.write(item.getPosition()); + addItemInfo(mplew, item, true); + } + return mplew.getPacket(); + } + + public static byte[] removeNPC(int oid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.REMOVE_NPC.getValue()); + mplew.writeInt(oid); + + return mplew.getPacket(); + } + + public static byte[] removeNPCController(int objectid) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + + mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue()); + mplew.write(0); + mplew.writeInt(objectid); + + return mplew.getPacket(); + } + + /** + * Sends a report response + * + * Possible values for mode:
0: You have succesfully + * reported the user.
1: Unable to locate the user.
2: You may only + * report users 10 times a day.
3: You have been reported to the GM's by + * a user.
4: Your request did not go through for unknown reasons. + * Please try again later.
+ * + * @param mode The mode + * @return Report Reponse packet + */ + public static byte[] reportResponse(byte mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SUE_CHARACTER_RESULT.getValue()); + mplew.write(mode); + return mplew.getPacket(); + } + + public static byte[] sendHammerData(int hammerUsed) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.VICIOUS_HAMMER.getValue()); + mplew.write(0x39); + mplew.writeInt(0); + mplew.writeInt(hammerUsed); + return mplew.getPacket(); + } + + public static byte[] sendHammerMessage() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.VICIOUS_HAMMER.getValue()); + mplew.write(0x3D); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] playPortalSound() { + return showSpecialEffect(7); + } + + public static byte[] showMonsterBookPickup() { + return showSpecialEffect(14); + } + + public static byte[] showEquipmentLevelUp() { + return showSpecialEffect(15); + } + + public static byte[] showItemLevelup() { + return showSpecialEffect(15); + } + + public static byte[] showBuybackEffect() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(11); + mplew.writeInt(0); + + return mplew.getPacket(); + } + + public static byte[] showForeignBuybackEffect(int cid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(11); + mplew.writeInt(0); + + return mplew.getPacket(); + } + + /** + * 0 = Levelup 6 = Exp did not drop (Safety Charms) 7 = Enter portal sound 8 + * = Job change 9 = Quest complete 10 = Recovery 11 = Buff effect 14 = + * Monster book pickup 15 = Equipment levelup 16 = Maker Skill Success 17 = + * Buff effect w/ sfx 19 = Exp card [500, 200, 50] 21 = Wheel of destiny 26 + * = Spirit Stone + * + * @param effect + * @return + */ + public static byte[] showSpecialEffect(int effect) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(effect); + return mplew.getPacket(); + } + + public static byte[] showMakerEffect(boolean makerSucceeded) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(16); + mplew.writeInt(makerSucceeded ? 0 : 1); + return mplew.getPacket(); + } + + public static byte[] showForeignMakerEffect(int cid, boolean makerSucceeded) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(16); + mplew.writeInt(makerSucceeded ? 0 : 1); + return mplew.getPacket(); + } + + public static byte[] showForeignEffect(int effect) { + return showForeignEffect(-1, effect); + } + + public static byte[] showForeignEffect(int cid, int effect) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(effect); + return mplew.getPacket(); + } + + public static byte[] showOwnRecovery(byte heal) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(0x0A); + mplew.write(heal); + return mplew.getPacket(); + } + + public static byte[] showRecovery(int cid, byte amount) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue()); + mplew.writeInt(cid); + mplew.write(0x0A); + mplew.write(amount); + return mplew.getPacket(); + } + + public static byte[] showWheelsLeft(int left) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue()); + mplew.write(0x15); + mplew.write(left); + return mplew.getPacket(); + } + + public static byte[] updateQuestFinish(short quest, int npc, short nextquest) { //Check + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); //0xF2 in v95 + mplew.write(8);//0x0A in v95 + mplew.writeShort(quest); + mplew.writeInt(npc); + mplew.writeShort(nextquest); + return mplew.getPacket(); + } + + public static byte[] showInfoText(String text) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(9); + mplew.writeMapleAsciiString(text); + return mplew.getPacket(); + } + + public static byte[] questError(short quest) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); + mplew.write(0x0A); + mplew.writeShort(quest); + return mplew.getPacket(); + } + + public static byte[] questFailure(byte type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); + mplew.write(type);//0x0B = No meso, 0x0D = Worn by character, 0x0E = Not having the item ? + return mplew.getPacket(); + } + + public static byte[] questExpire(short quest) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); + mplew.write(0x0F); + mplew.writeShort(quest); + return mplew.getPacket(); + } + + public static byte[] getMultiMegaphone(String[] messages, int channel, boolean showEar) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue()); + mplew.write(0x0A); + if (messages[0] != null) { + mplew.writeMapleAsciiString(messages[0]); + } + mplew.write(messages.length); + for (int i = 1; i < messages.length; i++) { + if (messages[i] != null) { + mplew.writeMapleAsciiString(messages[i]); + } + } + for (int i = 0; i < 10; i++) { + mplew.write(channel - 1); + } + mplew.write(showEar ? 1 : 0); + mplew.write(1); + return mplew.getPacket(); + } + + /** + * Gets a gm effect packet (ie. hide, banned, etc.) + * + * Possible values for type:
0x04: You have successfully + * blocked access.
+ * 0x05: The unblocking has been successful.
0x06 with Mode 0: You have + * successfully removed the name from the ranks.
0x06 with Mode 1: You + * have entered an invalid character name.
0x10: GM Hide, mode + * determines whether or not it is on.
0x1E: Mode 0: Failed to send + * warning Mode 1: Sent warning
0x13 with Mode 0: + mapid 0x13 with Mode + * 1: + ch (FF = Unable to find merchant) + * + * @param type The type + * @param mode The mode + * @return The gm effect packet + */ + public static byte[] getGMEffect(int type, byte mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue()); + mplew.write(type); + mplew.write(mode); + return mplew.getPacket(); + } + + public static byte[] findMerchantResponse(boolean map, int extra) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue()); + mplew.write(0x13); + mplew.write(map ? 0 : 1); //00 = mapid, 01 = ch + if (map) { + mplew.writeInt(extra); + } else { + mplew.write(extra); //-1 = unable to find + } + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] disableMinimap() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue()); + mplew.writeShort(0x1C); + return mplew.getPacket(); + } + + public static byte[] sendFamilyInvite(int playerId, String inviter) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST.getValue()); + mplew.writeInt(playerId); + mplew.writeMapleAsciiString(inviter); + return mplew.getPacket(); + } + + public static byte[] showBoughtCashPackage(List cashPackage, int accountId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x89); + mplew.write(cashPackage.size()); + + for (Item item : cashPackage) { + addCashItemInformation(mplew, item, accountId); } - public static byte[] moveDragon(MapleDragon dragon, Point startPos, List res) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.MOVE_DRAGON.getValue()); - mplew.writeInt(dragon.getOwner().getId()); - mplew.writePos(startPos); - serializeMovementList(mplew, res); - return mplew.getPacket(); + mplew.writeShort(0); + + return mplew.getPacket(); + } + + public static byte[] showBoughtQuestItem(int itemId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x8D); + mplew.writeInt(1); + mplew.writeShort(1); + mplew.write(0x0B); + mplew.write(0); + mplew.writeInt(itemId); + + return mplew.getPacket(); + } + + private static void getGuildInfo(final MaplePacketLittleEndianWriter mplew, MapleGuild guild) { + mplew.writeInt(guild.getId()); + mplew.writeMapleAsciiString(guild.getName()); + for (int i = 1; i <= 5; i++) { + mplew.writeMapleAsciiString(guild.getRankTitle(i)); + } + Collection members = guild.getMembers(); + mplew.write(members.size()); + for (MapleGuildCharacter mgc : members) { + mplew.writeInt(mgc.getId()); + } + for (MapleGuildCharacter mgc : members) { + mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13)); + mplew.writeInt(mgc.getJobId()); + mplew.writeInt(mgc.getLevel()); + mplew.writeInt(mgc.getGuildRank()); + mplew.writeInt(mgc.isOnline() ? 1 : 0); + mplew.writeInt(guild.getSignature()); + mplew.writeInt(mgc.getAllianceRank()); + } + mplew.writeInt(guild.getCapacity()); + mplew.writeShort(guild.getLogoBG()); + mplew.write(guild.getLogoBGColor()); + mplew.writeShort(guild.getLogo()); + mplew.write(guild.getLogoColor()); + mplew.writeMapleAsciiString(guild.getNotice()); + mplew.writeInt(guild.getGP()); + mplew.writeInt(guild.getAllianceId()); + } + + public static byte[] getAllianceInfo(MapleAlliance alliance) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x0C); + mplew.write(1); + mplew.writeInt(alliance.getId()); + mplew.writeMapleAsciiString(alliance.getName()); + for (int i = 1; i <= 5; i++) { + mplew.writeMapleAsciiString(alliance.getRankTitle(i)); + } + mplew.write(alliance.getGuilds().size()); + mplew.writeInt(alliance.getCapacity()); // probably capacity + for (Integer guild : alliance.getGuilds()) { + mplew.writeInt(guild); + } + mplew.writeMapleAsciiString(alliance.getNotice()); + return mplew.getPacket(); + } + + public static byte[] updateAllianceInfo(MapleAlliance alliance, int world) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x0F); + mplew.writeInt(alliance.getId()); + mplew.writeMapleAsciiString(alliance.getName()); + for (int i = 1; i <= 5; i++) { + mplew.writeMapleAsciiString(alliance.getRankTitle(i)); + } + mplew.write(alliance.getGuilds().size()); + for (Integer guild : alliance.getGuilds()) { + mplew.writeInt(guild); + } + mplew.writeInt(alliance.getCapacity()); // probably capacity + mplew.writeShort(0); + for (Integer guildid : alliance.getGuilds()) { + getGuildInfo(mplew, Server.getInstance().getGuild(guildid, world)); + } + return mplew.getPacket(); + } + + public static byte[] getGuildAlliances(MapleAlliance alliance, int worldId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x0D); + mplew.writeInt(alliance.getGuilds().size()); + for (Integer guild : alliance.getGuilds()) { + getGuildInfo(mplew, Server.getInstance().getGuild(guild, worldId)); + } + return mplew.getPacket(); + } + + public static byte[] addGuildToAlliance(MapleAlliance alliance, int newGuild, MapleClient c) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x12); + mplew.writeInt(alliance.getId()); + mplew.writeMapleAsciiString(alliance.getName()); + for (int i = 1; i <= 5; i++) { + mplew.writeMapleAsciiString(alliance.getRankTitle(i)); + } + mplew.write(alliance.getGuilds().size()); + for (Integer guild : alliance.getGuilds()) { + mplew.writeInt(guild); + } + mplew.writeInt(alliance.getCapacity()); + mplew.writeMapleAsciiString(alliance.getNotice()); + mplew.writeInt(newGuild); + getGuildInfo(mplew, Server.getInstance().getGuild(newGuild, c.getWorld(), null)); + return mplew.getPacket(); + } + + public static byte[] allianceMemberOnline(MapleCharacter mc, boolean online) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x0E); + mplew.writeInt(mc.getGuild().getAllianceId()); + mplew.writeInt(mc.getGuildId()); + mplew.writeInt(mc.getId()); + mplew.write(online ? 1 : 0); + return mplew.getPacket(); + } + + public static byte[] allianceNotice(int id, String notice) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x1C); + mplew.writeInt(id); + mplew.writeMapleAsciiString(notice); + return mplew.getPacket(); + } + + public static byte[] changeAllianceRankTitle(int alliance, String[] ranks) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x1A); + mplew.writeInt(alliance); + for (int i = 0; i < 5; i++) { + mplew.writeMapleAsciiString(ranks[i]); + } + return mplew.getPacket(); + } + + public static byte[] updateAllianceJobLevel(MapleCharacter mc) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x18); + mplew.writeInt(mc.getGuild().getAllianceId()); + mplew.writeInt(mc.getGuildId()); + mplew.writeInt(mc.getId()); + mplew.writeInt(mc.getLevel()); + mplew.writeInt(mc.getJob().getId()); + return mplew.getPacket(); + } + + public static byte[] removeGuildFromAlliance(MapleAlliance alliance, int expelledGuild, int worldId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x10); + mplew.writeInt(alliance.getId()); + mplew.writeMapleAsciiString(alliance.getName()); + for (int i = 1; i <= 5; i++) { + mplew.writeMapleAsciiString(alliance.getRankTitle(i)); + } + mplew.write(alliance.getGuilds().size()); + for (Integer guild : alliance.getGuilds()) { + mplew.writeInt(guild); + } + mplew.writeInt(alliance.getCapacity()); + mplew.writeMapleAsciiString(alliance.getNotice()); + mplew.writeInt(expelledGuild); + getGuildInfo(mplew, Server.getInstance().getGuild(expelledGuild, worldId, null)); + mplew.write(0x01); + return mplew.getPacket(); + } + + public static byte[] disbandAlliance(int alliance) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x1D); + mplew.writeInt(alliance); + return mplew.getPacket(); + } + + public static byte[] sendAllianceInvitation(int allianceid, MapleCharacter chr) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue()); + mplew.write(0x03); + mplew.writeInt(allianceid); + mplew.writeMapleAsciiString(chr.getName()); + mplew.writeShort(0); + return mplew.getPacket(); + } + + public static byte[] sendMesoLimit() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.TRADE_MONEY_LIMIT.getValue()); //Players under level 15 can only trade 1m per day + return mplew.getPacket(); + } + + public static byte[] sendFamilyJoinResponse(boolean accepted, String added) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST_RESULT.getValue()); + mplew.write(accepted ? 1 : 0); + mplew.writeMapleAsciiString(added); + return mplew.getPacket(); + } + + public static byte[] getSeniorMessage(String name) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_JOIN_ACCEPTED.getValue()); + mplew.writeMapleAsciiString(name); + mplew.writeInt(0); + return mplew.getPacket(); + } + + public static byte[] sendGainRep(int gain, int mode) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FAMILY_FAMOUS_POINT_INC_RESULT.getValue()); + mplew.writeInt(gain); + mplew.writeShort(0); + return mplew.getPacket(); + } + + public static byte[] removeItemFromDuey(boolean remove, int Package) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARCEL.getValue()); + mplew.write(0x17); + mplew.writeInt(Package); + mplew.write(remove ? 3 : 4); + return mplew.getPacket(); + } + + public static byte[] sendDueyNotification(boolean quickDelivery) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARCEL.getValue()); + mplew.write(0x1B); + mplew.writeBool(quickDelivery); // 0 : package received, 1 : quick delivery package + + return mplew.getPacket(); + } + + public static byte[] sendDueyMSG(byte operation) { + return sendDuey(operation, null); + } + + public static byte[] sendDuey(byte operation, List packages) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PARCEL.getValue()); + mplew.write(operation); + if (operation == 8) { + mplew.write(0); + mplew.write(packages.size()); + for (DueyPackages dp : packages) { + mplew.writeInt(dp.getPackageId()); + mplew.writeAsciiString(dp.getSender()); + for (int i = dp.getSender().length(); i < 13; i++) { + mplew.write(0); + } + mplew.writeInt(dp.getMesos()); + mplew.writeLong(getTime(dp.sentTimeInMilliseconds())); + mplew.writeLong(0); // Contains message o____o. + for (int i = 0; i < 48; i++) { + mplew.writeInt(Randomizer.nextInt(Integer.MAX_VALUE)); + } + mplew.writeInt(0); + mplew.write(0); + if (dp.getItem() != null) { + mplew.write(1); + addItemInfo(mplew, dp.getItem(), true); + } else { + mplew.write(0); + } + } + mplew.write(0); } - /** - * Sends a request to remove Mir
- * - * @param charid - Needs the specific Character ID - * @return The packet - * - */ - public static byte[] removeDragon(int chrid) { - final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.REMOVE_DRAGON.getValue()); - mplew.writeInt(chrid); - return mplew.getPacket(); + return mplew.getPacket(); + } + + public static byte[] sendDojoAnimation(byte firstByte, String animation) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(firstByte); + mplew.writeMapleAsciiString(animation); + return mplew.getPacket(); + } + + public static byte[] getDojoInfo(String info) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(10); + mplew.write(new byte[]{(byte) 0xB7, 4});//QUEST ID f5 + mplew.writeMapleAsciiString(info); + return mplew.getPacket(); + } + + public static byte[] getDojoInfoMessage(String message) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(9); + mplew.writeMapleAsciiString(message); + return mplew.getPacket(); + } + + /** + * Gets a "block" packet (ie. the cash shop is unavailable, etc) + * + * Possible values for type:
1: The portal is closed for + * now.
2: You cannot go to that place.
3: Unable to approach due to + * the force of the ground.
4: You cannot teleport to or on this + * map.
5: Unable to approach due to the force of the ground.
6: + * This map can only be entered by party members.
7: The Cash Shop is + * currently not available. Stay tuned...
+ * + * @param type The type + * @return The "block" packet. + */ + public static byte[] blockedMessage(int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BLOCKED_MAP.getValue()); + mplew.write(type); + return mplew.getPacket(); + } + + /** + * Gets a "block" packet (ie. the cash shop is unavailable, etc) + * + * Possible values for type:
1: You cannot move that + * channel. Please try again later.
2: You cannot go into the cash shop. + * Please try again later.
3: The Item-Trading Shop is currently + * unavailable. Please try again later.
4: You cannot go into the trade + * shop, due to limitation of user count.
5: You do not meet the minimum + * level requirement to access the Trade Shop.
+ * + * @param type The type + * @return The "block" packet. + */ + public static byte[] blockedMessage2(int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BLOCKED_SERVER.getValue()); + mplew.write(type); + return mplew.getPacket(); + } + + public static byte[] updateDojoStats(MapleCharacter chr, int belt) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(10); + mplew.write(new byte[]{(byte) 0xB7, 4}); //? + mplew.writeMapleAsciiString("pt=" + chr.getDojoPoints() + ";belt=" + belt + ";tuto=" + (chr.getFinishedDojoTutorial() ? "1" : "0")); + return mplew.getPacket(); + } + + /** + * Sends a "levelup" packet to the guild or family. + * + * Possible values for type:
0: ? has reached Lv. + * ?.
- The Reps you have received from ? will be reduced in half. 1: + * ? has reached Lv. ?.
2: ? has reached Lv. ?.
+ * + * @param type The type + * @return The "levelup" packet. + */ + public static byte[] levelUpMessage(int type, int level, String charname) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NOTIFY_LEVELUP.getValue()); + mplew.write(type); + mplew.writeInt(level); + mplew.writeMapleAsciiString(charname); + + return mplew.getPacket(); + } + + /** + * Sends a "married" packet to the guild or family. + * + * Possible values for type:
0: 1: + * + * @param type The type + * @return The "married" packet. + */ + public static byte[] marriageMessage(int type, String charname) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NOTIFY_MARRIAGE.getValue()); + mplew.write(type); // 0: guild, 1: family + mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol + + return mplew.getPacket(); + } + + /** + * Sends a "job advance" packet to the guild or family. + * + * Possible values for type:
0: 1: + * + * @param type The type + * @return The "job advance" packet. + */ + public static byte[] jobMessage(int type, int job, String charname) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.NOTIFY_JOB_CHANGE.getValue()); + mplew.write(type); + mplew.writeInt(job); //Why fking int? + mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol + + return mplew.getPacket(); + } + + /** + * + * @param type - (0:Light&Long 1:Heavy&Short) + * @param delay - seconds + * @return + */ + public static byte[] trembleEffect(int type, int delay) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue()); + mplew.write(1); + mplew.write(type); + mplew.writeInt(delay); + return mplew.getPacket(); + } + + public static byte[] getEnergy(String info, int amount) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SESSION_VALUE.getValue()); + mplew.writeMapleAsciiString(info); + mplew.writeMapleAsciiString(Integer.toString(amount)); + return mplew.getPacket(); + } + + public static byte[] dojoWarpUp() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DOJO_WARP_UP.getValue()); + mplew.write(0); + mplew.write(6); + return mplew.getPacket(); + } + + public static byte[] itemExpired(int itemid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(2); + mplew.writeInt(itemid); + return mplew.getPacket(); + } + + private static String getRightPaddedStr(String in, char padchar, int length) { + StringBuilder builder = new StringBuilder(in); + for (int x = in.length(); x < length; x++) { + builder.append(padchar); + } + return builder.toString(); + } + + public static byte[] MobDamageMobFriendly(MapleMonster mob, int damage) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.DAMAGE_MONSTER.getValue()); + mplew.writeInt(mob.getObjectId()); + mplew.write(1); // direction ? + mplew.writeInt(damage); + + mob.applyAndGetHpDamage(damage, false); + int remainingHp = mob.getHp(); + if (remainingHp <= 0) { + remainingHp = 0; + mob.getMap().removeMapObject(mob); } - /** - * Changes the current background effect to either being rendered or not. - * Data is still missing, so this is pretty binary at the moment in how it - * behaves. - * - * @param remove whether or not the remove or add the specified layer. - * @param layer the targeted layer for removal or addition. - * @param transition the time it takes to transition the effect. - * - * @return a packet to change the background effect of a specified layer. - */ - public static byte[] changeBackgroundEffect(boolean remove, int layer, int transition) { - MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); - mplew.writeShort(SendOpcode.SET_BACK_EFFECT.getValue()); - mplew.writeBool(remove); - mplew.writeInt(0); // not sure what this int32 does yet - mplew.write(layer); - mplew.writeInt(transition); - return mplew.getPacket(); + mplew.writeInt(remainingHp); + mplew.writeInt(mob.getMaxHp()); + return mplew.getPacket(); + } + + public static byte[] shopErrorMessage(int error, int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue()); + mplew.write(0x0A); + mplew.write(type); + mplew.write(error); + return mplew.getPacket(); + } + + private static void addRingInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { + mplew.writeShort(chr.getCrushRings().size()); + for (MapleRing ring : chr.getCrushRings()) { + mplew.writeInt(ring.getPartnerChrId()); + mplew.writeAsciiString(getRightPaddedStr(ring.getPartnerName(), '\0', 13)); + mplew.writeInt(ring.getRingId()); + mplew.writeInt(0); + mplew.writeInt(ring.getPartnerRingId()); + mplew.writeInt(0); } + mplew.writeShort(chr.getFriendshipRings().size()); + for (MapleRing ring : chr.getFriendshipRings()) { + mplew.writeInt(ring.getPartnerChrId()); + mplew.writeAsciiString(getRightPaddedStr(ring.getPartnerName(), '\0', 13)); + mplew.writeInt(ring.getRingId()); + mplew.writeInt(0); + mplew.writeInt(ring.getPartnerRingId()); + mplew.writeInt(0); + mplew.writeInt(ring.getItemId()); + } + + if (chr.getPartnerId() > 0) { + MapleRing marriageRing = chr.getMarriageRing(); + + mplew.writeShort(1); + mplew.writeInt(chr.getRelationshipId()); + mplew.writeInt(chr.getGender() == 0 ? chr.getId() : chr.getPartnerId()); + mplew.writeInt(chr.getGender() == 0 ? chr.getPartnerId() : chr.getId()); + mplew.writeShort((marriageRing != null) ? 3 : 1); + if (marriageRing != null) { + mplew.writeInt(marriageRing.getItemId()); + mplew.writeInt(marriageRing.getItemId()); + } else { + mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement) + mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement) + } + mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getName() : MapleCharacter.getNameById(chr.getPartnerId()), '\0', 13)); + mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? MapleCharacter.getNameById(chr.getPartnerId()) : chr.getName(), '\0', 13)); + } else { + mplew.writeShort(0); + } + } + + public static byte[] finishedSort(int inv) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.GATHER_ITEM_RESULT.getValue()); + mplew.write(0); + mplew.write(inv); + return mplew.getPacket(); + } + + public static byte[] finishedSort2(int inv) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.SORT_ITEM_RESULT.getValue()); + mplew.write(0); + mplew.write(inv); + return mplew.getPacket(); + } + + public static byte[] bunnyPacket() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue()); + mplew.write(9); + mplew.writeAsciiString("Protect the Moon Bunny!!!"); + return mplew.getPacket(); + } + + public static byte[] hpqMessage(String text) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); // not 100% sure + mplew.write(0); + mplew.writeInt(5120016); + mplew.writeAsciiString(text); + return mplew.getPacket(); + } + + public static byte[] showEventInstructions() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GMEVENT_INSTRUCTIONS.getValue()); + mplew.write(0); + return mplew.getPacket(); + } + + public static byte[] leftKnockBack() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); + mplew.writeShort(SendOpcode.LEFT_KNOCK_BACK.getValue()); + return mplew.getPacket(); + } + + public static byte[] rollSnowBall(boolean entermap, int state, MapleSnowball ball0, MapleSnowball ball1) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SNOWBALL_STATE.getValue()); + if (entermap) { + mplew.skip(21); + } else { + mplew.write(state);// 0 = move, 1 = roll, 2 is down disappear, 3 is up disappear + mplew.writeInt(ball0.getSnowmanHP() / 75); + mplew.writeInt(ball1.getSnowmanHP() / 75); + mplew.writeShort(ball0.getPosition());//distance snowball down, 84 03 = max + mplew.write(-1); + mplew.writeShort(ball1.getPosition());//distance snowball up, 84 03 = max + mplew.write(-1); + } + return mplew.getPacket(); + } + + public static byte[] hitSnowBall(int what, int damage) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.HIT_SNOWBALL.getValue()); + mplew.write(what); + mplew.writeInt(damage); + return mplew.getPacket(); + } + + /** + * Sends a Snowball Message
+ * + * Possible values for message:
1: ... Team's snowball has + * passed the stage 1.
2: ... Team's snowball has passed the stage + * 2.
3: ... Team's snowball has passed the stage 3.
4: ... Team is + * attacking the snowman, stopping the progress
5: ... Team is moving + * again
+ * + * @param message + * + */ + public static byte[] snowballMessage(int team, int message) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.SNOWBALL_MESSAGE.getValue()); + mplew.write(team);// 0 is down, 1 is up + mplew.writeInt(message); + return mplew.getPacket(); + } + + public static byte[] coconutScore(int team1, int team2) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.COCONUT_SCORE.getValue()); + mplew.writeShort(team1); + mplew.writeShort(team2); + return mplew.getPacket(); + } + + public static byte[] hitCoconut(boolean spawn, int id, int type) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.COCONUT_HIT.getValue()); + if (spawn) { + mplew.writeShort(-1); + mplew.writeShort(5000); + mplew.write(0); + } else { + mplew.writeShort(id); + mplew.writeShort(1000);//delay till you can attack again! + mplew.write(type); // What action to do for the coconut. + } + return mplew.getPacket(); + } + + public static byte[] customPacket(String packet) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.write(HexTool.getByteArrayFromHexString(packet)); + return mplew.getPacket(); + } + + public static byte[] customPacket(byte[] packet) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(packet.length); + mplew.write(packet); + return mplew.getPacket(); + } + + public static byte[] spawnGuide(boolean spawn) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.SPAWN_GUIDE.getValue()); + if (spawn) { + mplew.write(1); + } else { + mplew.write(0); + } + return mplew.getPacket(); + } + + public static byte[] talkGuide(String talk) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.TALK_GUIDE.getValue()); + mplew.write(0); + mplew.writeMapleAsciiString(talk); + mplew.write(new byte[]{(byte) 0xC8, 0, 0, 0, (byte) 0xA0, (byte) 0x0F, 0, 0}); + return mplew.getPacket(); + } + + public static byte[] guideHint(int hint) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11); + mplew.writeShort(SendOpcode.TALK_GUIDE.getValue()); + mplew.write(1); + mplew.writeInt(hint); + mplew.writeInt(7000); + return mplew.getPacket(); + } + + public static void addCashItemInformation(final MaplePacketLittleEndianWriter mplew, Item item, int accountId) { + addCashItemInformation(mplew, item, accountId, null); + } + + public static void addCashItemInformation(final MaplePacketLittleEndianWriter mplew, Item item, int accountId, String giftMessage) { + boolean isGift = giftMessage != null; + boolean isRing = false; + Equip equip = null; + if (item.getInventoryType().equals(MapleInventoryType.EQUIP)) { + equip = (Equip) item; + isRing = equip.getRingId() > -1; + } + mplew.writeLong(item.getPetId() > -1 ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId()); + if (!isGift) { + mplew.writeInt(accountId); + mplew.writeInt(0); + } + mplew.writeInt(item.getItemId()); + if (!isGift) { + mplew.writeInt(item.getSN()); + mplew.writeShort(item.getQuantity()); + } + mplew.writeAsciiString(StringUtil.getRightPaddedStr(item.getGiftFrom(), '\0', 13)); + if (isGift) { + mplew.writeAsciiString(StringUtil.getRightPaddedStr(giftMessage, '\0', 73)); + return; + } + addExpirationTime(mplew, item.getExpiration()); + mplew.writeLong(0); + } + + public static byte[] showWishList(MapleCharacter mc, boolean update) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + if (update) { + mplew.write(0x55); + } else { + mplew.write(0x4F); + } + + for (int sn : mc.getCashShop().getWishList()) { + mplew.writeInt(sn); + } + + for (int i = mc.getCashShop().getWishList().size(); i < 10; i++) { + mplew.writeInt(0); + } + + return mplew.getPacket(); + } + + public static byte[] showBoughtCashItem(Item item, int accountId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x57); + addCashItemInformation(mplew, item, accountId); + + return mplew.getPacket(); + } + + /* + * 00 = Due to an unknown error, failed + * A4 = Due to an unknown error, failed + warpout + * A5 = You don't have enough cash. + * A6 = long as shet msg + * A7 = You have exceeded the allotted limit of price for gifts. + * A8 = You cannot send a gift to your own account. Log in on the char and purchase + * A9 = Please confirm whether the character's name is correct. + * AA = Gender restriction! + * AB = gift cannot be sent because recipient inv is full + * AC = exceeded the number of cash items you can have + * AD = check and see if the character name is wrong or there is gender restrictions + * //Skipped a few + * B0 = Wrong Coupon Code + * B1 = Disconnect from CS because of 3 wrong coupon codes < lol + * B2 = Expired Coupon + * B3 = Coupon has been used already + * B4 = Nexon internet cafes? lolfk + * BB = inv full + * BC = long as shet "(not?) available to purchase by a use at the premium" msg + * BD = invalid gift recipient + * BE = invalid receiver name + * BF = item unavailable to purchase at this hour + * C0 = not enough items in stock, therefore not available + * C1 = you have exceeded spending limit of NX + * C2 = not enough mesos? Lol not even 1 mesos xD + * C3 = cash shop unavailable during beta phase + * C4 = check birthday code + * C7 = only available to users buying cash item, whatever msg too long + * C8 = already applied for this + * D2 = coupon system currently unavailable + * D3 = item can only be used 15 days after registration + * D4 = not enough gift tokens + * D6 = fresh people cannot gift items lul + * D7 = bad people cannot gift items >:( + * D8 = cannot gift due to limitations + * D9 = cannot gift due to amount of gifted times + * DA = cannot be gifted due to technical difficulties + * DB = cannot transfer to char below level 20 + * DC = cannot transfer char to same world + * DD = cannot transfer char to new server world + * DE = cannot transfer char out of this world + * DF = cannot transfer char due to no empty char slots + * E0 = event or free test time ended + * E6 = item cannot be purchased with MaplePoints + * E7 = lol sorry for the inconvenience, eh? + * E8 = cannot be purchased by anyone under 7 + */ + public static byte[] showCashShopMessage(byte message) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x5C); + mplew.write(message); + + return mplew.getPacket(); + } + + public static byte[] showCashInventory(MapleClient c) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x4B); + mplew.writeShort(c.getPlayer().getCashShop().getInventory().size()); + + for (Item item : c.getPlayer().getCashShop().getInventory()) { + addCashItemInformation(mplew, item, c.getAccID()); + } + + mplew.writeShort(c.getPlayer().getStorage().getSlots()); + mplew.writeShort(c.getCharacterSlots()); + + return mplew.getPacket(); + } + + public static byte[] showGifts(List> gifts) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x4D); + mplew.writeShort(gifts.size()); + + for (Pair gift : gifts) { + addCashItemInformation(mplew, gift.getLeft(), 0, gift.getRight()); + } + + return mplew.getPacket(); + } + + public static byte[] showGiftSucceed(String to, CashItem item) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x5E); //0x5D, Couldn't be sent + mplew.writeMapleAsciiString(to); + mplew.writeInt(item.getItemId()); + mplew.writeShort(item.getCount()); + mplew.writeInt(item.getPrice()); + + return mplew.getPacket(); + } + + public static byte[] showBoughtInventorySlots(int type, short slots) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x60); + mplew.write(type); + mplew.writeShort(slots); + + return mplew.getPacket(); + } + + public static byte[] showBoughtStorageSlots(short slots) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x62); + mplew.writeShort(slots); + + return mplew.getPacket(); + } + + public static byte[] showBoughtCharacterSlot(short slots) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x64); + mplew.writeShort(slots); + + return mplew.getPacket(); + } + + public static byte[] takeFromCashInventory(Item item) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x68); + mplew.writeShort(item.getPosition()); + addItemInfo(mplew, item, true); + + return mplew.getPacket(); + } + + public static byte[] putIntoCashInventory(Item item, int accountId) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue()); + + mplew.write(0x6A); + addCashItemInformation(mplew, item, accountId); + + return mplew.getPacket(); + } + + public static byte[] openCashShop(MapleClient c, boolean mts) throws Exception { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(mts ? SendOpcode.SET_ITC.getValue() : SendOpcode.SET_CASH_SHOP.getValue()); + + addCharacterInfo(mplew, c.getPlayer()); + + if (!mts) { + mplew.write(1); + } + + mplew.writeMapleAsciiString(c.getAccountName()); + if (mts) { + mplew.write(new byte[]{(byte) 0x88, 19, 0, 0, 7, 0, 0, 0, (byte) 0xF4, 1, 0, 0, (byte) 0x18, 0, 0, 0, (byte) 0xA8, 0, 0, 0, (byte) 0x70, (byte) 0xAA, (byte) 0xA7, (byte) 0xC5, (byte) 0x4E, (byte) 0xC1, (byte) 0xCA, 1}); + } else { + mplew.writeInt(0); + List lsci = CashItemFactory.getSpecialCashItems(); + mplew.writeShort(lsci.size());//Guess what + for (SpecialCashItem sci : lsci) { + mplew.writeInt(sci.getSN()); + mplew.writeInt(sci.getModifier()); + mplew.write(sci.getInfo()); + } + mplew.skip(121); + + List> mostSellers = c.getWorldServer().getMostSellerCashItems(); + for (int i = 1; i <= 8; i++) { + List mostSellersTab = mostSellers.get(i); + + for (int j = 0; j < 2; j++) { + for (Integer snid : mostSellersTab) { + mplew.writeInt(i); + mplew.writeInt(j); + mplew.writeInt(snid); + } + } + } + + mplew.writeInt(0); + mplew.writeShort(0); + mplew.write(0); + mplew.writeInt(75); + } + return mplew.getPacket(); + } + + public static byte[] sendVegaScroll(int op) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3); + mplew.writeShort(SendOpcode.VEGA_SCROLL.getValue()); + mplew.write(op); + return mplew.getPacket(); + } + + public static byte[] resetForcedStats() { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2); + mplew.writeShort(SendOpcode.FORCED_STAT_RESET.getValue()); + return mplew.getPacket(); + } + + public static byte[] showCombo(int count) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.SHOW_COMBO.getValue()); + mplew.writeInt(count); + return mplew.getPacket(); + } + + public static byte[] earnTitleMessage(String msg) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SCRIPT_PROGRESS_MESSAGE.getValue()); + mplew.writeMapleAsciiString(msg); + return mplew.getPacket(); + } + + public static byte[] CPUpdate(boolean party, int curCP, int totalCP, + int team) { // CPQ + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + if (!party) { + mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_OBTAINED_CP.getValue()); + } else { + mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_PARTY_CP.getValue()); + mplew.write(team); // team? + } + mplew.writeShort(curCP); + mplew.writeShort(totalCP); + return mplew.getPacket(); + } + + public static byte[] CPQMessage(byte message) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter( + 3); + mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_MESSAGE.getValue()); + mplew.write(message); // Message + return mplew.getPacket(); + } + + public static byte[] playerSummoned(String name, int tab, int number) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_SUMMON.getValue()); + mplew.write(tab); + mplew.write(number); + mplew.writeMapleAsciiString(name); + return mplew.getPacket(); + } + + public static byte[] playerDiedMessage(String name, int lostCP, int team) { // CPQ + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + + mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_DIED.getValue()); + mplew.write(team); // team + mplew.writeMapleAsciiString(name); + mplew.write(lostCP); + return mplew.getPacket(); + } + + public static byte[] startMonsterCarnival(MapleCharacter chr, int team, + int oposition) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter( + 25); + mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_START.getValue()); + mplew.write(team); // team + mplew.writeShort(chr.getCP()); // Obtained CP - Used CP + mplew.writeShort(chr.getTotalCP()); // Total Obtained CP + mplew.writeShort(chr.getMonsterCarnival().getCP(team)); // Obtained CP - + // Used CP of + // the team + mplew.writeShort(chr.getMonsterCarnival().getTotalCP(team)); // Total + // Obtained + // CP of + // the + // team + mplew.writeShort(chr.getMonsterCarnival().getCP(oposition)); // Obtained + // CP - + // Used + // CP of + // the + // team + mplew.writeShort(chr.getMonsterCarnival().getTotalCP(oposition)); // Total + // Obtained + // CP + // of + // the + // team + mplew.writeShort(0); // Probably useless nexon shit + mplew.writeLong(0); // Probably useless nexon shit + return mplew.getPacket(); + } + + public static byte[] sheepRanchInfo(byte wolf, byte sheep) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHEEP_RANCH_INFO.getValue()); + mplew.write(wolf); + mplew.write(sheep); + return mplew.getPacket(); + } + //Know what this is? ?? >=) + + public static byte[] sheepRanchClothes(int id, byte clothes) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SHEEP_RANCH_CLOTHES.getValue()); + mplew.writeInt(id); //Character id + mplew.write(clothes); //0 = sheep, 1 = wolf, 2 = Spectator (wolf without wool) + return mplew.getPacket(); + } + + public static byte[] incubatorResult() {//lol + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); + mplew.writeShort(SendOpcode.INCUBATOR_RESULT.getValue()); + mplew.skip(6); + return mplew.getPacket(); + } + + public static byte[] pyramidGauge(int gauge) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6); + mplew.writeShort(SendOpcode.PYRAMID_GAUGE.getValue()); + mplew.writeInt(gauge); + return mplew.getPacket(); + } + // f2 + + public static byte[] pyramidScore(byte score, int exp) {//Type cannot be higher than 4 (Rank D), otherwise you'll crash + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7); + mplew.writeShort(SendOpcode.PYRAMID_SCORE.getValue()); + mplew.write(score); + mplew.writeInt(exp); + return mplew.getPacket(); + } + + public static byte[] spawnDragon(MapleDragon dragon) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SPAWN_DRAGON.getValue()); + mplew.writeInt(dragon.getOwner().getId());//objectid = owner id + mplew.writeShort(dragon.getPosition().x); + mplew.writeShort(0); + mplew.writeShort(dragon.getPosition().y); + mplew.writeShort(0); + mplew.write(dragon.getStance()); + mplew.write(0); + mplew.writeShort(dragon.getOwner().getJob().getId()); + return mplew.getPacket(); + } + + public static byte[] moveDragon(MapleDragon dragon, Point startPos, List res) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.MOVE_DRAGON.getValue()); + mplew.writeInt(dragon.getOwner().getId()); + mplew.writePos(startPos); + serializeMovementList(mplew, res); + return mplew.getPacket(); + } + + /** + * Sends a request to remove Mir
+ * + * @param charid - Needs the specific Character ID + * @return The packet + * + */ + public static byte[] removeDragon(int chrid) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.REMOVE_DRAGON.getValue()); + mplew.writeInt(chrid); + return mplew.getPacket(); + } + + /** + * Changes the current background effect to either being rendered or not. + * Data is still missing, so this is pretty binary at the moment in how it + * behaves. + * + * @param remove whether or not the remove or add the specified layer. + * @param layer the targeted layer for removal or addition. + * @param transition the time it takes to transition the effect. + * + * @return a packet to change the background effect of a specified layer. + */ + public static byte[] changeBackgroundEffect(boolean remove, int layer, int transition) { + MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.SET_BACK_EFFECT.getValue()); + mplew.writeBool(remove); + mplew.writeInt(0); // not sure what this int32 does yet + mplew.write(layer); + mplew.writeInt(transition); + return mplew.getPacket(); + } } diff --git a/src/tools/data/output/GenericLittleEndianWriter.java b/src/tools/data/output/GenericLittleEndianWriter.java index 91779e4d57..bc8351be8a 100644 --- a/src/tools/data/output/GenericLittleEndianWriter.java +++ b/src/tools/data/output/GenericLittleEndianWriter.java @@ -33,7 +33,7 @@ import constants.CharsetConstants.MapleLanguageType; * @since Revision 323 */ public class GenericLittleEndianWriter implements LittleEndianWriter { - private static Charset ASCII = Charset.forName(MapleLanguageType.LANGUAGE_US.getAscii()); + private static Charset ASCII = Charset.forName(MapleLanguageType.LANGUAGE_PT_BR.getAscii()); private ByteOutputStream bos; /** diff --git a/src/tools/packets/Wedding.java b/src/tools/packets/Wedding.java index 97ef9bb347..95946051de 100644 --- a/src/tools/packets/Wedding.java +++ b/src/tools/packets/Wedding.java @@ -18,7 +18,7 @@ import tools.data.output.MaplePacketLittleEndianWriter; /** * CField_Wedding, CField_WeddingPhoto, CWeddingMan, OnMarriageResult, and all Wedding/Marriage enum/structs. * - * @author Eric + * @author Eric edited by Drago/Dragohe4rt on Wishlist */ public class Wedding extends MaplePacketCreator { private static final short MARRIAGE_REQUEST = 0x48; @@ -375,7 +375,7 @@ public class Wedding extends MaplePacketCreator { } /** - * Handles all of WeddingWishlist packets + * Handles all of WeddingWishlist packets * * @param mode * @param itemnames @@ -392,17 +392,16 @@ public class Wedding extends MaplePacketCreator { MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(WEDDING_GIFT_RESULT); mplew.write(mode); - switch(mode) { + switch (mode) { case 0x09: { // Load Wedding Registry mplew.write(itemnames.size()); for (String names : itemnames) { mplew.writeMapleAsciiString(names); } - mplew.write(itemnames.size()); - for (String names : itemnames) { - mplew.writeMapleAsciiString(names); + mplew.write(items.size()); + for (Item item : items) { + addItemInfo(mplew, item, true); } - // need to load items somehow break; } case 0xA: // Load Bride's Wishlist @@ -415,30 +414,31 @@ public class Wedding extends MaplePacketCreator { mplew.writeMapleAsciiString(names); } } - switch (items.get((items.size() - 1)).getInventoryType()) { - case EQUIP: - mplew.writeLong(4); - break; - case USE: - mplew.writeLong(8); - break; - case SETUP: - mplew.writeLong(16); - break; - case ETC: - mplew.writeLong(32); - break; - default: // impossible flag, cash item can't be sent - if (items.get((items.size() - 1)).getInventoryType() != MapleInventoryType.CASH) { - mplew.writeLong(0); - } - } - if (mode == 0xA) { // random unknown bytes involved within Bride's Wishlist - mplew.writeInt(0); + if (items.size() >= 1) { + switch (items.get((items.size() - 1)).getInventoryType()) { + case EQUIP: + mplew.writeLong(4); + break; + case USE: + mplew.writeLong(8); + break; + case SETUP: + mplew.writeLong(16); + break; + case ETC: + mplew.writeLong(32); + break; + default: // impossible flag, cash item can't be sent + if (items.get((items.size() - 1)).getInventoryType() != MapleInventoryType.CASH) { + mplew.writeLong(0); + } + } + } else { + mplew.writeLong(0); } mplew.write(items.size()); for (Item item : items) { - MaplePacketCreator.addItemInfo(mplew, item, true); + addItemInfo(mplew, item, true); } break; } From 0a8efa42384c54ca26546c881d10b7fe4b881064 Mon Sep 17 00:00:00 2001 From: Diego Armando de Freitas Matos Date: Thu, 7 Mar 2019 22:37:00 -0300 Subject: [PATCH 2/2] Cpq1 ,2 add linguas --- sql/db_database.sql | 3 +- src/client/MapleCharacter.java | 21 +++++++--- src/client/MapleClient.java | 12 +++++- src/client/command/CommandsExecutor.java | 1 + .../commands/gm0/ChangeLinguaCommand.java | 42 +++++++++++++++++++ src/constants/LinguaConstants.java | 7 +--- src/server/MapleStatEffect.java | 4 +- 7 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 src/client/command/commands/gm0/ChangeLinguaCommand.java diff --git a/sql/db_database.sql b/sql/db_database.sql index 645d8bada3..a2443057c5 100644 --- a/sql/db_database.sql +++ b/sql/db_database.sql @@ -42,6 +42,7 @@ CREATE TABLE IF NOT EXISTS `accounts` ( `rewardpoints` int(11) NOT NULL DEFAULT '0', `votepoints` int(11) NOT NULL DEFAULT '0', `hwid` varchar(12) NOT NULL DEFAULT '', + `lingua` int(1) NOT NULL DEFAULT '2', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`), KEY `ranking1` (`id`,`banned`), @@ -17443,7 +17444,7 @@ CREATE TABLE IF NOT EXISTS `rings` ( CREATE TABLE IF NOT EXISTS `savedlocations` ( `id` int(11) NOT NULL AUTO_INCREMENT, `characterid` int(11) NOT NULL, - `locationtype` enum('FREE_MARKET','WORLDTOUR','FLORINA','INTRO','SUNDAY_MARKET','MIRROR','EVENT','BOSSPQ','HAPPYVILLE','DEVELOPER') NOT NULL, + `locationtype` enum('FREE_MARKET','WORLDTOUR','FLORINA','INTRO','SUNDAY_MARKET','MIRROR','EVENT','BOSSPQ','HAPPYVILLE','DEVELOPER','MONSTER_CARNIVAL') NOT NULL, `map` int(11) NOT NULL, `portal` int(11) NOT NULL, PRIMARY KEY (`id`) diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index b36adb2f85..146f65eb1a 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -9598,7 +9598,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject { private MapleFitness fitness; private MapleOla ola; private long snowballattack; - private int lingua = 0;// 0 PTB 1 ESP 2 ENG public static final List itens = new ArrayList(); public static final List item = new ArrayList(); @@ -10174,12 +10173,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject { this.challenged = challenged; } - public void setLingua(int a) { - this.lingua = a; + public void setLingua(int num) { + getClient().setLingua(num); + try { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET lingua = ? WHERE id = ?")) { + ps.setInt(1, num); + ps.setInt(2, getClient().getAccID()); + ps.executeUpdate(); + } finally { + con.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } } - + public int getLingua() { - return lingua; + return getClient().getLingua(); } public void setItens(String item) { diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java index ec62f10fe8..2df77a0e24 100644 --- a/src/client/MapleClient.java +++ b/src/client/MapleClient.java @@ -124,6 +124,7 @@ public class MapleClient { private int visibleWorlds; private long lastNpcClick; private long sessionId; + private int lingua = 0; public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) { this.send = send; @@ -535,7 +536,7 @@ public class MapleClient { ResultSet rs = null; try { con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?"); + ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos, lingua FROM accounts WHERE name = ?"); ps.setString(1, login); rs = ps.executeQuery(); if (rs.next()) { @@ -546,6 +547,7 @@ public class MapleClient { pic = rs.getString("pic"); gender = rs.getByte("gender"); characterSlots = rs.getByte("characterslots"); + lingua = rs.getInt("lingua"); String passhash = rs.getString("password"); byte tos = rs.getByte("tos"); @@ -1528,4 +1530,12 @@ public class MapleClient { public boolean canBypassPic() { return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, true); } + + public int getLingua() { + return lingua; + } + + public void setLingua(int lingua) { + this.lingua = lingua; + } } diff --git a/src/client/command/CommandsExecutor.java b/src/client/command/CommandsExecutor.java index 012a784ef0..285b0da748 100644 --- a/src/client/command/CommandsExecutor.java +++ b/src/client/command/CommandsExecutor.java @@ -178,6 +178,7 @@ public class CommandsExecutor { addCommand("uptime", UptimeCommand.class); addCommand("gacha", GachaCommand.class); addCommand("dispose", DisposeCommand.class); + addCommand("changel", ChangeLinguaCommand.class); addCommand("equiplv", EquipLvCommand.class); addCommand("showrates", ShowRatesCommand.class); addCommand("rates", RatesCommand.class); diff --git a/src/client/command/commands/gm0/ChangeLinguaCommand.java b/src/client/command/commands/gm0/ChangeLinguaCommand.java new file mode 100644 index 0000000000..219279a99f --- /dev/null +++ b/src/client/command/commands/gm0/ChangeLinguaCommand.java @@ -0,0 +1,42 @@ +/* + This file is part of the HeavenMS MapleStory Server, commands OdinMS-based + Copyleft (L) 2016 - 2018 RonanLana + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/* + @Author: Arthur L - Refactored command content into modules +*/ +package client.command.commands.gm0; + +import client.command.Command; +import client.MapleClient; + +public class ChangeLinguaCommand extends Command { + { + setDescription(""); + } + + @Override + public void execute(MapleClient c, String[] params) { + if (params.length < 1) { + c.getPlayer().yellowMessage("Syntax: !changel <0=ptb, 1=esp, 2=eng>"); + return; + } + c.setLingua(Integer.parseInt(params[0])); + } +} diff --git a/src/constants/LinguaConstants.java b/src/constants/LinguaConstants.java index f583c24b05..af1089d60e 100644 --- a/src/constants/LinguaConstants.java +++ b/src/constants/LinguaConstants.java @@ -1,15 +1,10 @@ -/* - * 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 constants; import client.MapleCharacter; /** * - * @author Drago + * @author Drago - Dragohe4rt */ public class LinguaConstants { // Portugues diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index be3e956bbd..5c83c32285 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -939,7 +939,7 @@ public class MapleStatEffect { applyto.removeAllCooldownsExcept(Buccaneer.TIME_LEAP, true); } else if (cp != 0 && applyto.getMonsterCarnival() != null) { applyto.gainCP(cp); - } else if (nuffSkill != 0 && applyto.getParty() != null && applyto.getMap().isCPQMap()) { + } else if (nuffSkill != 0 && applyto.getParty() != null && applyto.getMap().isCPQMap()) { // by Drago-Dragohe4rt final MCSkill skil = MapleCarnivalFactory.getInstance().getSkill(nuffSkill); if (skil != null) { final MapleDisease dis = skil.getDisease(); @@ -964,7 +964,7 @@ public class MapleStatEffect { } } } - } else if (cureDebuffs.size() > 0) { + } else if (cureDebuffs.size() > 0) { // by Drago-Dragohe4rt for (final MapleDisease debuff : cureDebuffs) { if (applyfrom.getParty() != null) { for (MaplePartyCharacter chrs : applyfrom.getParty().getPartyMembers()) {