From 07fe495bfd584f524e0df7e61411cac188908bd7 Mon Sep 17 00:00:00 2001 From: ronancpl Date: Tue, 24 Dec 2019 20:11:32 -0300 Subject: [PATCH] Skillbook announcer update + Encoded temporary mob buffs + Slot gains patch Encoded temporary mob buffs on mob control request/spawn packets. Improved scroll generator NPC, now testing other bucket set possibilities. Fixed slot gain method recently updated leading to a temporary visual glitch (inventory would show as normal after relogin). Reviewed mobid check by name, no longer trying to generate a whole mob instance for info retrieval. Added debuff purge when applying a buyback. Reviewed skillbook announcer not informing properly storybooks, reactor or script loots. Fixed autoaggro not working properly as soon as a player enters the field. Fixed "fake" mobs disappearing as soon as its controller changes. --- README.md | 14 ++- config.yaml | 1 + docs/mychanges_ptbr.txt | 26 +++++ scripts/event/HorntailBattle.js | 2 +- scripts/npc/9209000.js | 2 +- scripts/npc/scroll_generator.js | 32 ++++++- src/client/MapleCharacter.java | 37 +++++--- .../command/commands/gm0/DisposeCommand.java | 4 +- .../command/commands/gm0/TimeCommand.java | 1 - .../commands/gm1/WhatDropsFromCommand.java | 1 - src/client/inventory/MapleInventory.java | 6 +- .../processor/action/BuybackProcessor.java | 1 + src/config/ServerConfig.java | 1 + src/constants/net/ServerConstants.java | 1 + .../handlers/GuildOperationHandler.java | 1 - .../handlers/PartyOperationHandler.java | 1 - .../handlers/PlayerMapTransitionHandler.java | 4 +- .../MapleMatchCheckerCoordinator.java | 2 +- .../server/task/CharacterAutosaverTask.java | 2 +- src/net/server/task/RankingLoginTask.java | 1 - src/scripting/npc/NPCConversationManager.java | 9 +- src/server/CashShop.java | 1 - src/server/MapleItemInformationProvider.java | 3 +- .../MapleSkillbookInformationProvider.java | 15 ++- src/server/MapleStatEffect.java | 5 +- src/server/MapleTrade.java | 1 - src/server/life/MapleMonster.java | 33 ++----- .../life/MapleMonsterInformationProvider.java | 14 +-- src/server/life/MaplePlayerNPC.java | 1 - src/server/life/MaplePlayerNPCFactory.java | 1 - src/server/maps/MapleHiredMerchant.java | 25 ++--- src/server/maps/MapleMap.java | 11 ++- src/tools/MaplePacketCreator.java | 94 ++++++++++++------- src/tools/packets/Fishing.java | 1 - 34 files changed, 211 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 7ba64be0d39..c82836594ba 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Besides myself for maintaining this repository, credits are to be given to Wizet Regarding distributability and usage of the code presented here: like it was before, this MapleStory server is open-source. By that, it is meant that anyone is **free to install, use, modify and redistribute the contents**, as long as there is **no kind of commercial trading involved** and the **credits to the original creators are maintained** within the codes. -This is a NetBeans 8.2 Project, that should be built and run on Java 8 in order to run properly (used to be ran in Java 7, thanks @kolakcc for the Java 8 support!). +This is a NetBeans 8.2 Project, that should be built and run on Java 8 in order to run properly. -- Used to be ran in Java 7, thanks kolakcc (Familiar) for the Java 8 support! Being a NetBeans 8.2 Project, this means that it's easier to install the project via opening the server project folder inside NetBeans' IDE. Once installed, build this project on your machine and run the server using the "launch.bat" application. @@ -33,6 +33,8 @@ Java 8 SDK & NetBeans bundle: https://www.oracle.com/technetwork/pt/java/javase/ **Change log:** + * Fixed Monster Magnet crashing the caster when trying to pull fixed mobs. https://gofile.io/?c=BW7dVM + * Cleared need for administrator privileges (OS) to play the game, credits to Ubaware. * Set a higher cap for AP assigning with AP Reset, credits to Ubaware. @@ -75,7 +77,7 @@ HeavenClient Github: https://github.com/ryantpayton/HeavenClient --- ### Development information -Status: __In development (4th round)__. +Status: __Released (4 rounds)__. #### Mission @@ -112,15 +114,11 @@ Our Discord channel is still available on: https://discord.gg/Q7wKxHX -### Donation - -If you REALLY liked what you have seen on the project, please feel free to donate a little something as a helping hand for my contributions towards Maple development. Also remember to **support Nexon**! - -Paypal: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3K8KVTWRLFBQ4 +[//]: <> (If you REALLY liked what you have seen on the project, please feel free to donate a little something as a helping hand for my contributions towards Maple development. Also remember to **support Nexon**!) ### Disclaimer -* HeavenMS development is decisively __ONLY accepting donations__ from the Paypal link aforementioned, in the __ronancpl/HeavenMS__ repository readme (no patreons or other revenue resources). +[//]: <> (* HeavenMS development is decisively __ONLY accepting donations__ from the Paypal link aforementioned, in the __ronancpl/HeavenMS__ repository readme (no patreons or other revenue resources).) * HeavenMS staff has __no current intention__ to publicly open a server with this source, if that ever comes to happen this note will be lifted. __Don't be scammed!__ diff --git a/config.yaml b/config.yaml index 182227bda5d..15ec53a7a64 100644 --- a/config.yaml +++ b/config.yaml @@ -335,6 +335,7 @@ server: MOB_STATUS_MONITOR_LIFE: 84 #Idle proc count the mob disease monitor is allowed to be there before closing it due to inactivity. MOB_STATUS_AGGRO_PERSISTENCE: 2 #Idle proc count on aggro update for a mob to keep following the current controller, given him/her is the leading damage dealer. MOB_STATUS_AGGRO_INTERVAL: 5000 #Interval in milliseconds between aggro logistics update. + USE_AUTOAGGRO_NEARBY: false #Mobs start following the player when approached. #Some Gameplay Enhancing Configurations #Scroll Configuration diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index 9a63d3ff283..7714778d3e7 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -2330,3 +2330,29 @@ Revisado Inventory Sort, agora ordenando projéteis por bônus de dano. 06 Dezembro 2019, Implementado pacote para visão de buffs de efeito imbuído em armas para outros jogadores. Corrigido casos de exceção devido a portais nulos na função que troca jogador de mapas interferindo com próximas trocas de mapa (jogador fica preso até relogar). + +07 Dezembro 2019, +Corrigido caso de exceção ao tentar atribuir pontos de stats ao jogador, que passou a ocorrer após mudança recente no sistema de stats. + +09 Dezembro 2019, +Implementado aplicação de buffs ao se realizar a chamada/requisição de controle de um mob. + +11 Dezembro 2019, +Incrementado suporte para aplicação de buffs de mobs de dano refletido, completando-se a ronda. + +14 Dezembro 2019, +Melhorado NPC de geração de scrolls, agora testando outras possibilidades caso nenhum scroll encontrado em conjunto de scrolls. +Corrigido método de ganho de slots atualizado recentemente levando a bug visual, onde somente os 4 primeiros itens do inventário estariam aparecendo na tela. +Revisado método de busca por nomes, não mais tentando gerar um objeto de mob somente para checar o nome. +Adicionado limpa de debuffs ao se utilizar buyback. +Revisado anunciador de skillbooks não informando devidamente sobre os campos de reatores e scripts. + +16 Dezembro 2019, +Revisado possível caso de dupe com itens ao fechar Hired Merchant. + +20 Dezembro 2019, +Corrigido autoaggro não atuando devidamente em mobs assim que jogador entra no mapa e adquire controladores sobre os mesmos. +Corrigido anunciador de skillbooks não reportando etc de quest para começar, quando lidando com questlines onde se obtém a skill diretamente. + +21 Dezembro 2019, +Corrigido mobs em estado "fake" desaparecendo da tela assim que muda-se o controlador do mesmo. \ No newline at end of file diff --git a/scripts/event/HorntailBattle.js b/scripts/event/HorntailBattle.js index 90c69d27eaf..a49801f5253 100644 --- a/scripts/event/HorntailBattle.js +++ b/scripts/event/HorntailBattle.js @@ -88,7 +88,7 @@ function setEventRewards(eim) { function afterSetup(eim) {} function setup(channel) { - var eim = em.newInstance("Horntail" + channel); // thanks Thora for reporting an issue with misleading event name here + var eim = em.newInstance("Horntail" + channel); // thanks Thora (Arufonsu) for reporting an issue with misleading event name here eim.setProperty("canJoin", 1); eim.setProperty("defeatedBoss", 0); eim.setProperty("defeatedHead", 0); diff --git a/scripts/npc/9209000.js b/scripts/npc/9209000.js index 3c149e6df6e..8d222a57904 100644 --- a/scripts/npc/9209000.js +++ b/scripts/npc/9209000.js @@ -125,7 +125,7 @@ function action(mode, type, selection) { sendStr += " #L" + i + "# " + mobList[i] + "#l\r\n"; } - sendStr += "\r\n"; + sendStr += "\r\n\r\n"; } } else { sendStr = "\r\n\r\n"; diff --git a/scripts/npc/scroll_generator.js b/scripts/npc/scroll_generator.js index b3b3f038c7e..1fa746d0671 100644 --- a/scripts/npc/scroll_generator.js +++ b/scripts/npc/scroll_generator.js @@ -353,7 +353,7 @@ function calculateScrollTiers() { return tiers; } -function getRandomScroll(tiers) { +function getRandomScrollFromTiers(tiers) { var typeTier = tiers[0], subtypeTier = tiers[1], successTier = tiers[2]; var scrollTypePool = getScrollTypePool(typeTier); var scrollPool = getAvailableScrollsPool(scrollTypePool, subtypeTier, successTier); @@ -365,6 +365,36 @@ function getRandomScroll(tiers) { } } +function getRandomScrollFromRightPermutations(tiers) { + for (var i = 2; i >= 0; i--) { + for (var j = i - 1; j >= 0; j--) { + if (tiers[i] >= 3) { + break; + } else if (tiers[j] > 1) { + tiers[i]++; + tiers[j]--; + + var itemid = getRandomScrollFromTiers(tiers); + if (itemid != -1) { + return itemid; + } + } + } + } + + return -1; +} + +function getRandomScroll(tiers) { + var itemid = getRandomScrollFromTiers(tiers); + if (itemid == -1) { + // worst case shift-right permutations... + itemid = getRandomScrollFromRightPermutations(tiers); + } + + return itemid; +} + function performExchange(sgItemid, sgCount) { if (cm.getMeso() < sgAppliedMeso) { return false; diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index 3ff5915271e..ccb050c21a0 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -144,7 +144,6 @@ import constants.game.ExpTable; import constants.game.GameConstants; import constants.inventory.ItemConstants; -import constants.net.ServerConstants; import constants.skills.Aran; import constants.skills.Beginner; import constants.skills.Bishop; @@ -2819,7 +2818,14 @@ public void dispelDebuffs() { dispelDebuff(MapleDisease.WEAKEN); dispelDebuff(MapleDisease.SLOW); // thanks Conrad for noticing ZOMBIFY isn't dispellable } - + + public void purgeDebuffs() { + dispelDebuff(MapleDisease.SEDUCE); + dispelDebuff(MapleDisease.ZOMBIFY); + dispelDebuff(MapleDisease.CONFUSE); + dispelDebuffs(); + } + public void cancelAllDebuffs() { chrLock.lock(); try { @@ -9420,26 +9426,27 @@ public boolean gainSlots(int type, int slots) { } public boolean gainSlots(int type, int slots, boolean update) { - boolean ret = gainSlotsInternal(type, slots, update); - if (ret) { + int newLimit = gainSlotsInternal(type, slots); + if (newLimit != -1) { this.saveCharToDB(); if (update) { - client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots)); + client.announce(MaplePacketCreator.updateInventorySlotLimit(type, newLimit)); } + return true; + } else { + return false; } - - return ret; } - private boolean gainSlotsInternal(int type, int slots, boolean update) { + private int gainSlotsInternal(int type, int slots) { inventory[type].lockInventory(); try { if (canGainSlots(type, slots)) { - slots += inventory[type].getSlotLimit(); - inventory[type].setSlotLimit(slots); - return true; + int newLimit = inventory[type].getSlotLimit() + slots; + inventory[type].setSlotLimit(newLimit); + return newLimit; } else { - return false; + return -1; } } finally { inventory[type].unlockInventory(); @@ -10652,6 +10659,12 @@ public void run() { client = null; // clients still triggers handlers a few times after disconnecting map = null; setListener(null); + + // thanks Shavit for noticing a memory leak with inventories holding owner object + for (int i = 0; i < inventory.length; i++) { + inventory[i].dispose(); + } + inventory = null; } }, 5 * 60 * 1000); } diff --git a/src/client/command/commands/gm0/DisposeCommand.java b/src/client/command/commands/gm0/DisposeCommand.java index ffb5fa44149..50fb77086dc 100644 --- a/src/client/command/commands/gm0/DisposeCommand.java +++ b/src/client/command/commands/gm0/DisposeCommand.java @@ -33,7 +33,7 @@ public class DisposeCommand extends Command { { setDescription(""); } - + @Override public void execute(MapleClient c, String[] params) { NPCScriptManager.getInstance().dispose(c); @@ -41,5 +41,5 @@ public void execute(MapleClient c, String[] params) { c.announce(MaplePacketCreator.enableActions()); c.removeClickedNPC(); c.getPlayer().message("You've been disposed."); - } } +} diff --git a/src/client/command/commands/gm0/TimeCommand.java b/src/client/command/commands/gm0/TimeCommand.java index d91a3b8a01d..975d5b57174 100644 --- a/src/client/command/commands/gm0/TimeCommand.java +++ b/src/client/command/commands/gm0/TimeCommand.java @@ -25,7 +25,6 @@ import client.MapleClient; import client.command.Command; -import constants.net.ServerConstants; import java.text.DateFormat; import java.text.SimpleDateFormat; diff --git a/src/client/command/commands/gm1/WhatDropsFromCommand.java b/src/client/command/commands/gm1/WhatDropsFromCommand.java index 14747c0679c..a35c092b2fb 100644 --- a/src/client/command/commands/gm1/WhatDropsFromCommand.java +++ b/src/client/command/commands/gm1/WhatDropsFromCommand.java @@ -29,7 +29,6 @@ import server.MapleItemInformationProvider; import server.life.MapleMonsterInformationProvider; import server.life.MonsterDropEntry; -import tools.MaplePacketCreator; import tools.Pair; import java.util.Iterator; diff --git a/src/client/inventory/MapleInventory.java b/src/client/inventory/MapleInventory.java index a2ce3a7f16f..705d2811867 100644 --- a/src/client/inventory/MapleInventory.java +++ b/src/client/inventory/MapleInventory.java @@ -25,14 +25,12 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; import java.util.Map; -import java.util.Set; import java.util.concurrent.locks.Lock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -672,4 +670,8 @@ public void lockInventory() { public void unlockInventory() { lock.unlock(); } + + public void dispose() { + owner = null; + } } \ No newline at end of file diff --git a/src/client/processor/action/BuybackProcessor.java b/src/client/processor/action/BuybackProcessor.java index cacd0067be0..4fd5a6e628e 100644 --- a/src/client/processor/action/BuybackProcessor.java +++ b/src/client/processor/action/BuybackProcessor.java @@ -70,6 +70,7 @@ public static void processBuyback(MapleClient c) { } chr.healHpMp(); + chr.purgeDebuffs(); chr.broadcastStance(chr.isFacingLeft() ? 5 : 4); MapleMap map = chr.getMap(); diff --git a/src/config/ServerConfig.java b/src/config/ServerConfig.java index ea40b0b2ad9..fbef7503674 100644 --- a/src/config/ServerConfig.java +++ b/src/config/ServerConfig.java @@ -179,6 +179,7 @@ public class ServerConfig { public int MOB_STATUS_MONITOR_LIFE; public int MOB_STATUS_AGGRO_PERSISTENCE; public int MOB_STATUS_AGGRO_INTERVAL; + public boolean USE_AUTOAGGRO_NEARBY; //Some Gameplay Enhancing Configurations //Scroll Configuration diff --git a/src/constants/net/ServerConstants.java b/src/constants/net/ServerConstants.java index 869a135f5db..f341f45c4de 100644 --- a/src/constants/net/ServerConstants.java +++ b/src/constants/net/ServerConstants.java @@ -12,6 +12,7 @@ public class ServerConstants { public static int DEBUG_VALUES[] = new int[10]; // Field designed for packet testing purposes // https://github.com/openstreetmap/josm/blob/a3a6e8a6b657cf4c5b4c64ea14d6e87be6280d65/src/org/openstreetmap/josm/tools/Utils.java#L1566-L1585 + // Added by kolakcc (Familiar) /** * Returns the Java version as an int value. * @return the Java version as an int value (8, 9, etc.) diff --git a/src/net/server/channel/handlers/GuildOperationHandler.java b/src/net/server/channel/handlers/GuildOperationHandler.java index 92991f4269c..c8c900177b8 100644 --- a/src/net/server/channel/handlers/GuildOperationHandler.java +++ b/src/net/server/channel/handlers/GuildOperationHandler.java @@ -25,7 +25,6 @@ import net.server.guild.MapleGuildResponse; import net.server.guild.MapleGuild; import constants.game.GameConstants; -import constants.net.ServerConstants; import client.MapleClient; import net.AbstractMaplePacketHandler; import tools.data.input.SeekableLittleEndianAccessor; diff --git a/src/net/server/channel/handlers/PartyOperationHandler.java b/src/net/server/channel/handlers/PartyOperationHandler.java index e73fe559665..4977ce01375 100644 --- a/src/net/server/channel/handlers/PartyOperationHandler.java +++ b/src/net/server/channel/handlers/PartyOperationHandler.java @@ -31,7 +31,6 @@ import tools.data.input.SeekableLittleEndianAccessor; import client.MapleCharacter; import client.MapleClient; -import constants.net.ServerConstants; import net.server.coordinator.world.MapleInviteCoordinator; import net.server.coordinator.world.MapleInviteCoordinator.InviteResult; import net.server.coordinator.world.MapleInviteCoordinator.InviteType; diff --git a/src/net/server/channel/handlers/PlayerMapTransitionHandler.java b/src/net/server/channel/handlers/PlayerMapTransitionHandler.java index 00b94828dce..760cd41bc94 100644 --- a/src/net/server/channel/handlers/PlayerMapTransitionHandler.java +++ b/src/net/server/channel/handlers/PlayerMapTransitionHandler.java @@ -58,13 +58,13 @@ public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) if (m.getController() == chr) { c.announce(MaplePacketCreator.stopControllingMonster(m.getObjectId())); m.sendDestroyData(c); - m.aggroRedirectController(); + m.aggroRemoveController(); } else { m.sendDestroyData(c); } - m.aggroSwitchController(chr, false); m.sendSpawnData(c); + m.aggroSwitchController(chr, false); } } } diff --git a/src/net/server/coordinator/matchchecker/MapleMatchCheckerCoordinator.java b/src/net/server/coordinator/matchchecker/MapleMatchCheckerCoordinator.java index 29ba8611e03..0c6c0251cbf 100644 --- a/src/net/server/coordinator/matchchecker/MapleMatchCheckerCoordinator.java +++ b/src/net/server/coordinator/matchchecker/MapleMatchCheckerCoordinator.java @@ -354,7 +354,7 @@ public boolean answerMatchConfirmation(int cid, boolean accept) { if (mmce != null) { synchronized (mmce) { - if (!mmce.isMatchActive()) { // thanks Alex (CanIGetaPR) for noticing that exploiters could stall on match checking + if (!mmce.isMatchActive()) { // thanks Alex (Alex-0000) for noticing that exploiters could stall on match checking matchEntries.remove(cid); mmce = null; } else { diff --git a/src/net/server/task/CharacterAutosaverTask.java b/src/net/server/task/CharacterAutosaverTask.java index 4c44ef2abb7..122f6888a2e 100644 --- a/src/net/server/task/CharacterAutosaverTask.java +++ b/src/net/server/task/CharacterAutosaverTask.java @@ -27,7 +27,7 @@ /** * @author Ronan */ -public class CharacterAutosaverTask extends BaseTask implements Runnable { // thanks Alex (Alex09) for noticing these runnable classes are tasks, "workers" runs them +public class CharacterAutosaverTask extends BaseTask implements Runnable { // thanks Alex09 (Alex-0000) for noticing these runnable classes are tasks, "workers" runs them @Override public void run() { diff --git a/src/net/server/task/RankingLoginTask.java b/src/net/server/task/RankingLoginTask.java index c56a9ea4db4..b5d0d74309f 100644 --- a/src/net/server/task/RankingLoginTask.java +++ b/src/net/server/task/RankingLoginTask.java @@ -28,7 +28,6 @@ import client.MapleJob; import config.YamlConfig; import tools.DatabaseConnection; -import constants.net.ServerConstants; import net.server.Server; /** diff --git a/src/scripting/npc/NPCConversationManager.java b/src/scripting/npc/NPCConversationManager.java index bb5f963d11d..f4b22ed08ad 100644 --- a/src/scripting/npc/NPCConversationManager.java +++ b/src/scripting/npc/NPCConversationManager.java @@ -60,7 +60,6 @@ import constants.game.GameConstants; import constants.inventory.ItemConstants; import constants.string.LanguageConstants; -import net.server.PlayerStorage; import net.server.channel.Channel; import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType; import server.MapleMarriage; @@ -603,6 +602,12 @@ public String getSkillBookInfo(int itemid) { switch (sbe) { case UNAVAILABLE: return ""; + + case REACTOR: + return " Obtainable through #rexploring#k (loot boxes)."; + + case SCRIPT: + return " Obtainable through #rexploring#k (field interaction)."; case QUEST_BOOK: return " Obtainable through #rquestline#k (collecting book)."; @@ -633,7 +638,7 @@ public boolean sendCPQMapLists() { for (int i = 0; i < 6; i++) { if (fieldTaken(i)) { if (fieldLobbied(i)) { - msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (Level: " // "Carnival field" GMS-like improvement thanks to Jayd + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (Level: " // "Carnival field" GMS-like improvement thanks to Jayd (jaydenseah) + cpqCalcAvgLvl(980000100 + i * 100) + " / " + getPlayerCount(980000100 + i * 100) + "x" + getPlayerCount(980000100 + i * 100) + ") #l\r\n"; diff --git a/src/server/CashShop.java b/src/server/CashShop.java index 19b99e9b03f..1eb541e05d2 100644 --- a/src/server/CashShop.java +++ b/src/server/CashShop.java @@ -49,7 +49,6 @@ import client.inventory.MapleInventoryType; import client.inventory.MaplePet; import constants.inventory.ItemConstants; -import constants.net.ServerConstants; import java.util.Collections; import net.server.audit.locks.MonitoredLockType; diff --git a/src/server/MapleItemInformationProvider.java b/src/server/MapleItemInformationProvider.java index a1ad6c58b29..e8b8dab9ffa 100644 --- a/src/server/MapleItemInformationProvider.java +++ b/src/server/MapleItemInformationProvider.java @@ -60,7 +60,6 @@ import client.inventory.MapleInventory; import client.inventory.MapleInventoryType; import client.inventory.MapleWeaponType; -import constants.net.ServerConstants; import constants.inventory.EquipSlot; import constants.inventory.ItemConstants; import constants.skills.Assassin; @@ -2117,7 +2116,7 @@ public Set getWhoDrops(Integer itemId) { ResultSet rs = ps.executeQuery(); while(rs.next()) { String resultName = MapleMonsterInformationProvider.getInstance().getMobNameFromId(rs.getInt("dropperid")); - if (resultName != null) { + if (!resultName.isEmpty()) { list.add(resultName); } } diff --git a/src/server/MapleSkillbookInformationProvider.java b/src/server/MapleSkillbookInformationProvider.java index 9d4c75055fd..fdc2f4ab216 100644 --- a/src/server/MapleSkillbookInformationProvider.java +++ b/src/server/MapleSkillbookInformationProvider.java @@ -65,18 +65,11 @@ public enum SkillBookEntry { SCRIPT } - private static String host = "jdbc:mysql://localhost:3306/heavenms"; - private static String driver = "com.mysql.jdbc.Driver"; - private static String username = "root"; - private static String password = ""; - private static String rootDirectory = "."; private static int skillbookMinItemid = 2280000; private static int skillbookMaxItemid = 2300000; // exclusively - private static Set questSkills = new HashSet<>(); - static { loadSkillbooks(); } @@ -156,7 +149,13 @@ private static void fetchSkillbooksFromQuests() { int skillid = MapleDataTool.getInt("id", questSkillData, 0); if (is4thJobSkill(skillid)) { // negative itemids are skill rewards - foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_REWARD); + + int questbook = fetchQuestbook(checkData, questData.getName()); + if (questbook < 0) { + foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_REWARD); + } else { + foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_BOOK); + } } } } diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 7cde000dd9a..d7821b11938 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -958,10 +958,7 @@ private boolean applyTo(MapleCharacter applyfrom, MapleCharacter applyto, boolea if (isDispel() && makeChanceResult()) { applyto.dispelDebuffs(); } else if (isCureAllAbnormalStatus()) { - applyto.dispelDebuff(MapleDisease.SEDUCE); - applyto.dispelDebuff(MapleDisease.ZOMBIFY); - applyto.dispelDebuff(MapleDisease.CONFUSE); - applyto.dispelDebuffs(); + applyto.purgeDebuffs(); } else if (isComboReset()) { applyto.setCombo((short) 0); } diff --git a/src/server/MapleTrade.java b/src/server/MapleTrade.java index 5c2c00e3b84..7ad528c3978 100644 --- a/src/server/MapleTrade.java +++ b/src/server/MapleTrade.java @@ -36,7 +36,6 @@ import client.inventory.manipulator.MapleInventoryManipulator; import client.inventory.manipulator.MapleKarmaManipulator; import constants.game.GameConstants; -import constants.net.ServerConstants; import net.server.coordinator.world.MapleInviteCoordinator; import net.server.coordinator.world.MapleInviteCoordinator.InviteResult; import net.server.coordinator.world.MapleInviteCoordinator.InviteType; diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java index bef2d83a8df..b5f3c0c9ad1 100644 --- a/src/server/life/MapleMonster.java +++ b/src/server/life/MapleMonster.java @@ -1040,23 +1040,6 @@ public boolean hasBossHPBar() { return isBoss() && getTagColor() > 0; } - public void broadcastMonsterStatus() { - Collection mseList = this.getStati().values(); - for (MapleCharacter chr : map.getAllPlayers()) { - announceMonsterStatusInternal(chr.getClient(), mseList); - } - } - - public void announceMonsterStatus(MapleClient client) { - announceMonsterStatusInternal(client, this.getStati().values()); - } - - public void announceMonsterStatusInternal(MapleClient client, Collection mseList) { - for (MonsterStatusEffect mse : mseList) { - client.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null)); - } - } - @Override public void sendSpawnData(MapleClient client) { if (hp.get() <= 0) { // mustn't monsterLock this function @@ -1068,8 +1051,6 @@ public void sendSpawnData(MapleClient client) { client.announce(MaplePacketCreator.spawnMonster(this, false)); } - announceMonsterStatus(client); - if (hasBossHPBar()) { client.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket()); } @@ -1934,7 +1915,7 @@ private MapleCharacter getNextControllerCandidate() { * Removes controllability status from the current controller of this mob. * */ - private Pair aggroRemoveController() { + public Pair aggroRemoveController() { MapleCharacter chrController; boolean hadAggro; @@ -1951,7 +1932,7 @@ private Pair aggroRemoveController() { } if (chrController != null) { // this can/should only happen when a hidden gm attacks the monster - chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId())); + if (!this.isFake()) chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId())); chrController.stopControllingMonster(this); } @@ -2123,9 +2104,12 @@ public void aggroAutoAggroUpdate(MapleCharacter player) { MapleCharacter chrController = this.getActiveController(); if (chrController == null) { - this.aggroSwitchController(player, true); + this.aggroSwitchController(player, true); } else if (chrController.getId() == player.getId()) { this.setControllerHasAggro(true); + if (!YamlConfig.config.server.USE_AUTOAGGRO_NEARBY) { // thanks Lichtmager for noticing autoaggro not updating the player properly + aggroMonsterControl(player.getClient(), this, true); + } } } @@ -2164,9 +2148,6 @@ else if (chrController != null) { private static void aggroMonsterControl(MapleClient c, MapleMonster mob, boolean immediateAggro) { c.announce(MaplePacketCreator.controlMonster(mob, false, immediateAggro)); - - // thanks BHB for noticing puppets disrupting mobstatuses for bowmans - mob.announceMonsterStatus(c); } private void aggroRefreshPuppetVisibility(MapleCharacter chrController, MapleSummon puppet) { @@ -2185,7 +2166,7 @@ private void aggroRefreshPuppetVisibility(MapleCharacter chrController, MapleSum chrController.announce(MaplePacketCreator.removeSummon(puppet, false)); MapleClient c = chrController.getClient(); - for (MapleMonster mob : puppetControlled) { + for (MapleMonster mob : puppetControlled) { // thanks BHB for noticing puppets disrupting mobstatuses for bowmans aggroMonsterControl(c, mob, mob.isControllerKnowsAboutAggro()); } chrController.announce(MaplePacketCreator.spawnSummon(puppet, false)); diff --git a/src/server/life/MapleMonsterInformationProvider.java b/src/server/life/MapleMonsterInformationProvider.java index 66e0d385b69..565dc3b3251 100644 --- a/src/server/life/MapleMonsterInformationProvider.java +++ b/src/server/life/MapleMonsterInformationProvider.java @@ -316,16 +316,10 @@ public boolean isBoss(int id) { 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 - } - + MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz")); + MapleData mobData = dataProvider.getData("Mob.img"); + + mobName = MapleDataTool.getString(mobData.getChildByPath(id + "/name"), ""); mobNameCache.put(id, mobName); } diff --git a/src/server/life/MaplePlayerNPC.java b/src/server/life/MaplePlayerNPC.java index e49da183a2a..86164d3a954 100644 --- a/src/server/life/MaplePlayerNPC.java +++ b/src/server/life/MaplePlayerNPC.java @@ -44,7 +44,6 @@ import client.inventory.Item; import client.inventory.MapleInventoryType; import constants.game.GameConstants; -import constants.net.ServerConstants; import net.server.Server; import net.server.channel.Channel; import net.server.world.World; diff --git a/src/server/life/MaplePlayerNPCFactory.java b/src/server/life/MaplePlayerNPCFactory.java index bd32f773b64..ea8da0658fe 100644 --- a/src/server/life/MaplePlayerNPCFactory.java +++ b/src/server/life/MaplePlayerNPCFactory.java @@ -19,7 +19,6 @@ */ package server.life; -import constants.net.ServerConstants; import java.io.File; import java.util.HashMap; import java.util.Map; diff --git a/src/server/maps/MapleHiredMerchant.java b/src/server/maps/MapleHiredMerchant.java index a1870dd6ae9..261238e411b 100644 --- a/src/server/maps/MapleHiredMerchant.java +++ b/src/server/maps/MapleHiredMerchant.java @@ -413,18 +413,6 @@ private void closeShop(MapleClient c, boolean timeout) { this.removeOwner(c.getPlayer()); try { - MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterById(ownerId); - if(player != null) { - player.setHasMerchant(false); - } else { - Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0 WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) { - ps.setInt(1, ownerId); - ps.executeUpdate(); - } - con.close(); - } - List copyItems = getItems(); if (check(c.getPlayer(), copyItems) && !timeout) { for (MaplePlayerShopItem mpsi : copyItems) { @@ -448,6 +436,19 @@ private void closeShop(MapleClient c, boolean timeout) { e.printStackTrace(); } + // thanks Rohenn for noticing a possible dupe scenario on closing shop + MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterById(ownerId); + if(player != null) { + player.setHasMerchant(false); + } else { + Connection con = DatabaseConnection.getConnection(); + try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0 WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) { + ps.setInt(1, ownerId); + ps.executeUpdate(); + } + con.close(); + } + if (YamlConfig.config.server.USE_ENFORCE_MERCHANT_SAVE) { c.getPlayer().saveCharToDB(false); } diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java index 2c820036c4e..514f82a272a 100644 --- a/src/server/maps/MapleMap.java +++ b/src/server/maps/MapleMap.java @@ -2017,7 +2017,7 @@ public void spawnMonster(final MapleMonster monster, int difficulty, boolean isP if (getEventInstance() != null) { getEventInstance().registerMonster(monster); } - + spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { @@ -2108,7 +2108,7 @@ public void sendPackets(MapleClient c) { c.announce(MaplePacketCreator.spawnFakeMonster(monster, 0)); } }); - + spawnedMonstersOnMap.incrementAndGet(); addSelfDestructive(monster); } @@ -2116,7 +2116,6 @@ public void sendPackets(MapleClient c) { public void makeMonsterReal(final MapleMonster monster) { monster.setFake(false); broadcastMessage(MaplePacketCreator.makeMonsterReal(monster)); - monster.broadcastMonsterStatus(); monster.aggroUpdateController(); updateBossSpawn(monster); } @@ -3081,8 +3080,6 @@ private void sendObjectPlacement(MapleClient c) { for (MapleMapObject o : objects) { if (isNonRangedType(o.getType())) { o.sendSpawnData(c); - } else if (o.getType() == MapleMapObjectType.MONSTER) { - ((MapleMonster) o).aggroUpdateController(); } else if (o.getType() == MapleMapObjectType.SUMMON) { MapleSummon summon = (MapleSummon) o; if (summon.getOwner() == chr) { @@ -3110,6 +3107,10 @@ private void sendObjectPlacement(MapleClient c) { } else { o.sendSpawnData(chr.getClient()); chr.addVisibleMapObject(o); + + if (o.getType() == MapleMapObjectType.MONSTER) { + ((MapleMonster) o).aggroUpdateController(); + } } } } diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index f26d8cdd80e..893c76d44bc 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -1486,6 +1486,43 @@ private static void encodeParentlessMobSpawnEffect(MaplePacketLittleEndianWriter mplew.write(newSpawn ? -2 : -1); } + private static void encodeTemporary(MaplePacketLittleEndianWriter mplew, Map stati) { + int pCounter = -1, mCounter = -1; + + writeLongEncodeTemporaryMask(mplew, stati.keySet()); // packet structure mapped thanks to Eric + + for (Entry s : stati.entrySet()) { + MonsterStatusEffect mse = s.getValue(); + mplew.writeShort(mse.getStati().get(s.getKey())); + + MobSkill mobSkill = mse.getMobSkill(); + if (mobSkill != null) { + mplew.writeShort(mobSkill.getSkillId()); + mplew.writeShort(mobSkill.getSkillLevel()); + + switch(s.getKey()) { + case WEAPON_REFLECT: + pCounter = mobSkill.getX(); + break; + + case MAGIC_REFLECT: + mCounter = mobSkill.getY(); + break; + } + } else { + Skill skill = mse.getSkill(); + mplew.writeInt(skill != null ? skill.getId() : 0); + } + + mplew.writeShort(-1); // duration + } + + // reflect packet structure found thanks to Arnah (Vertisy) + if(pCounter != -1) mplew.writeInt(pCounter);// wPCounter_ + if(mCounter != -1) mplew.writeInt(mCounter);// wMCounter_ + if(pCounter != -1 || mCounter != -1) mplew.writeInt(100);// nCounterProb_ + } + /** * Internal function to handler monster spawning and controlling. * @@ -1513,9 +1550,13 @@ private static byte[] spawnMonsterInternal(MapleMonster life, boolean requestCon mplew.writeInt(life.getObjectId()); mplew.write(life.getController() == null ? 5 : 1); mplew.writeInt(life.getId()); - mplew.skip(15); - mplew.write(0x88); - mplew.skip(6); + + if (requestController) { + encodeTemporary(mplew, life.getStati()); // thanks shot for noticing encode temporary buffs missing + } else { + mplew.skip(16); + } + mplew.writePos(life.getPosition()); mplew.write(life.getStance()); mplew.writeShort(0); //Origin FH //life.getStartFh() @@ -1561,9 +1602,7 @@ public static byte[] spawnFakeMonster(MapleMonster life, int effect) { mplew.writeInt(life.getObjectId()); mplew.write(5); mplew.writeInt(life.getId()); - mplew.skip(15); - mplew.write(0x88); - mplew.skip(6); + encodeTemporary(mplew, life.getStati()); mplew.writePos(life.getPosition()); mplew.write(life.getStance()); mplew.writeShort(0);//life.getStartFh() @@ -1591,9 +1630,7 @@ public static byte[] makeMonsterReal(MapleMonster life) { mplew.writeInt(life.getObjectId()); mplew.write(5); mplew.writeInt(life.getId()); - mplew.skip(15); - mplew.write(0x88); - mplew.skip(6); + encodeTemporary(mplew, life.getStati()); mplew.writePos(life.getPosition()); mplew.write(life.getStance()); mplew.writeShort(0);//life.getStartFh() @@ -3151,6 +3188,21 @@ private static void writeLongMaskFromList(final MaplePacketLittleEndianWriter mp mplew.writeLong(firstmask); mplew.writeLong(secondmask); } + + private static void writeLongEncodeTemporaryMask(final MaplePacketLittleEndianWriter mplew, Collection stati) { + int masks[] = new int[4]; + + for (MonsterStatus statup : stati) { + int pos = statup.isFirst() ? 0 : 2; + for (int i = 0; i < 2; i++) { + masks[pos + i] |= statup.getValue() >> 32 * i; + } + } + + for (int i = 0; i < masks.length; i++) { + mplew.writeInt(masks[i]); + } + } public static byte[] cancelDebuff(long mask) { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); @@ -4137,30 +4189,6 @@ private static void writeIntMask(final MaplePacketLittleEndianWriter mplew, Map< 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(); diff --git a/src/tools/packets/Fishing.java b/src/tools/packets/Fishing.java index 469e56e6c61..8ea1a0fc49d 100644 --- a/src/tools/packets/Fishing.java +++ b/src/tools/packets/Fishing.java @@ -23,7 +23,6 @@ import config.YamlConfig; import constants.game.GameConstants; import constants.inventory.ItemConstants; -import constants.net.ServerConstants; import server.MapleItemInformationProvider; import tools.MaplePacketCreator;