diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index a4e71c40a2..3b787ea089 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -2305,4 +2305,27 @@ Corrigido buff Final Attack de Cygnus sendo reaplicado a todo acerto de skill. 24 - 25 Novembro 2019, Corrigido caso não sendo checado devidamente com Maker. Corrigido contagem de projéteis nos stats de skill usando tipo de dados de tamanho insuficiente. -Refatorado acesso a membros relativos a Dojo em canais de forma a buscar melhorar efetividade dos ingressos e liberações de lobby. \ No newline at end of file +Refatorado acesso a membros relativos a Dojo em canais de forma a buscar melhorar efetividade dos ingressos e liberações de lobby. +Revisado exceção inutilizável na classe geradora de áreas do jogo. + +27 Novembro 2019, +Revisado carregamento de storage da DB ocorrendo a cada login realizado. +Revisado aquisição de itens no CS ocorrendo antes de utilizar os pontos disponíveis. + +28 Novembro 2019, +Revisado interação de flag de permissão de ganho de EXP em equipamentos. + +29 - 30 Novembro 2019, +Fatorado diversas habilidades (Energy Charge, Wind Walk, Dash) não transcorrendo como esperado na visão de outros jogadores ao trocar de mapas. + +02 - 03 Dezembro 2019, +Revisado uso de locks compartilhados em MapleClient. +Refatorado criação de conjunto durante checagem de slots, que seria de fato efetivo em cenários muito raros (melhor deixar inserção de itens limitados dar fail-fast nas réplicas). +Refatorado sistema de pool de stats, que estava atuando erroneamente em casos-limite. +Corrigido Item Guard inconsistentemente levando a NPE ao utilizar o mesmo. +Corrigido itens perdendo flags ao equipar aqueles tidos como "untradeable após equipar". +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). \ No newline at end of file diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js index e5d2adfb4c..fcf7833e05 100644 --- a/scripts/npc/9977777.js +++ b/scripts/npc/9977777.js @@ -1,6 +1,6 @@ /* This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2016 - 2018 RonanLana + Copyleft (L) 2016 - 2019 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 @@ -61,8 +61,9 @@ function writeFeatureTab_Skills() { addFeature("Maker skill features developed - pckts thanks Arnah."); addFeature("Chair Mastery - map chair boosts HP/MP rec."); addFeature("Mu Lung Dojo skills functional."); - addFeature("Monster Magnet skill no longer crashes players."); + addFeature("Monster Magnet skill on bosses no longer crash."); addFeature("HP/MP consumption from skills triggers pet autopot."); + addFeature("Elemental weapon imbue visibility for other players."); } function writeFeatureTab_Quests() { diff --git a/src/client/AbstractMapleCharacterObject.java b/src/client/AbstractMapleCharacterObject.java index 5b92ce2ec5..205d0535e1 100644 --- a/src/client/AbstractMapleCharacterObject.java +++ b/src/client/AbstractMapleCharacterObject.java @@ -277,17 +277,22 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple this.clientmaxmp = Math.min(30000, mp_); } - private static long calcStatPoolNode(long v, int displacement) { - if (v > Short.MAX_VALUE) { - v = Short.MAX_VALUE; - } else if (v < Short.MIN_VALUE) { - v = Short.MIN_VALUE; - } - - return ((v & 0x0FFFF) << displacement); + private static long clampStat(int v, int min, int max) { + return (v < min) ? min : ((v > max) ? max : v); } - private static long calcStatPoolLong(int v1, int v2, int v3, int v4) { + private static long calcStatPoolNode(Integer v, int displacement) { + long r; + if (v == null) { + r = -32768; + } else { + r = clampStat(v, -32767, 32767); + } + + return ((r & 0x0FFFF) << displacement); + } + + private static long calcStatPoolLong(Integer v1, Integer v2, Integer v3, Integer v4) { long ret = 0; ret |= calcStatPoolNode(v1, 48); @@ -419,40 +424,48 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple } protected void changeHpMp(int newhp, int newmp, boolean silent) { - changeHpMpPool(newhp, newmp, Short.MIN_VALUE, Short.MIN_VALUE, silent); + changeHpMpPool(newhp, newmp, null, null, silent); } - private void changeHpMpPool(int hp, int mp, int maxhp, int maxmp, boolean silent) { + private void changeHpMpPool(Integer hp, Integer mp, Integer maxhp, Integer maxmp, boolean silent) { long hpMpPool = calcStatPoolLong(hp, mp, maxhp, maxmp); changeStatPool(hpMpPool, null, null, -1, silent); } public void updateHp(int hp) { - updateHpMaxHp(hp, Short.MIN_VALUE); + updateHpMaxHp(hp, null); } public void updateMaxHp(int maxhp) { - updateHpMaxHp(Short.MIN_VALUE, maxhp); + updateHpMaxHp(null, maxhp); } public void updateHpMaxHp(int hp, int maxhp) { - changeHpMpPool(hp, Short.MIN_VALUE, maxhp, Short.MIN_VALUE, false); + updateHpMaxHp(Integer.valueOf(hp), Integer.valueOf(maxhp)); + } + + private void updateHpMaxHp(Integer hp, Integer maxhp) { + changeHpMpPool(hp, null, maxhp, null, false); } public void updateMp(int mp) { - updateMpMaxMp(mp, Short.MIN_VALUE); + updateMpMaxMp(mp, null); } public void updateMaxMp(int maxmp) { - updateMpMaxMp(Short.MIN_VALUE, maxmp); + updateMpMaxMp(null, maxmp); } public void updateMpMaxMp(int mp, int maxmp) { - changeHpMpPool(Short.MIN_VALUE, mp, Short.MIN_VALUE, maxmp, false); + updateMpMaxMp(Integer.valueOf(mp), Integer.valueOf(maxmp)); + } + + private void updateMpMaxMp(Integer mp, Integer maxmp) { + changeHpMpPool(null, mp, null, maxmp, false); } public void updateMaxHpMaxMp(int maxhp, int maxmp) { - changeHpMpPool(Short.MIN_VALUE, Short.MIN_VALUE, maxhp, maxmp, false); + changeHpMpPool(null, null, maxhp, maxmp, false); } protected void enforceMaxHpMp() { @@ -521,7 +534,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple effLock.lock(); statWlock.lock(); try { - changeHpMpPool(Short.MIN_VALUE, Short.MIN_VALUE, maxhp + hpdelta, maxmp + mpdelta, silent); + changeHpMpPool(null, null, maxhp + hpdelta, maxmp + mpdelta, silent); } finally { statWlock.unlock(); effLock.unlock(); @@ -567,19 +580,19 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple } public boolean assignStr(int x) { - return assignStrDexIntLuk(x, Short.MIN_VALUE, Short.MIN_VALUE, Short.MIN_VALUE); + return assignStrDexIntLuk(x, null, null, null); } public boolean assignDex(int x) { - return assignStrDexIntLuk(Short.MIN_VALUE, x, Short.MIN_VALUE, Short.MIN_VALUE); + return assignStrDexIntLuk(null, x, null, null); } public boolean assignInt(int x) { - return assignStrDexIntLuk(Short.MIN_VALUE, Short.MIN_VALUE, x, Short.MIN_VALUE); + return assignStrDexIntLuk(null, null, x, null); } public boolean assignLuk(int x) { - return assignStrDexIntLuk(Short.MIN_VALUE, Short.MIN_VALUE, Short.MIN_VALUE, x); + return assignStrDexIntLuk(null, null, null, x); } public boolean assignHP(int deltaHP, int deltaAp) { @@ -590,7 +603,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple return false; } - long hpMpPool = calcStatPoolLong(Short.MIN_VALUE, Short.MIN_VALUE, maxhp + deltaHP, maxmp); + long hpMpPool = calcStatPoolLong(null, null, maxhp + deltaHP, maxmp); long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk); changeStatPool(hpMpPool, strDexIntLuk, null, remainingAp - deltaAp, false); @@ -610,7 +623,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple return false; } - long hpMpPool = calcStatPoolLong(Short.MIN_VALUE, Short.MIN_VALUE, maxhp, maxmp + deltaMP); + long hpMpPool = calcStatPoolLong(null, null, maxhp, maxmp + deltaMP); long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk); changeStatPool(hpMpPool, strDexIntLuk, null, remainingAp - deltaAp, false); @@ -622,11 +635,15 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple } } - private static int apAssigned(int x) { - return x != Short.MIN_VALUE ? x : 0; + private static int apAssigned(Integer x) { + return x != null ? x : 0; } public boolean assignStrDexIntLuk(int deltaStr, int deltaDex, int deltaInt, int deltaLuk) { + return assignStrDexIntLuk(Integer.valueOf(deltaStr), Integer.valueOf(deltaDex), Integer.valueOf(deltaInt), Integer.valueOf(deltaLuk)); + } + + private boolean assignStrDexIntLuk(Integer deltaStr, Integer deltaDex, Integer deltaInt, Integer deltaLuk) { effLock.lock(); statWlock.lock(); try { @@ -636,19 +653,19 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple } int newStr = str + deltaStr, newDex = dex + deltaDex, newInt = int_ + deltaInt, newLuk = luk + deltaLuk; - if (newStr < 4 && deltaStr != Short.MIN_VALUE || newStr > YamlConfig.config.server.MAX_AP) { + if (newStr < 4 && deltaStr != null || newStr > YamlConfig.config.server.MAX_AP) { return false; } - if (newDex < 4 && deltaDex != Short.MIN_VALUE || newDex > YamlConfig.config.server.MAX_AP) { + if (newDex < 4 && deltaDex != null || newDex > YamlConfig.config.server.MAX_AP) { return false; } - if (newInt < 4 && deltaInt != Short.MIN_VALUE || newInt > YamlConfig.config.server.MAX_AP) { + if (newInt < 4 && deltaInt != null || newInt > YamlConfig.config.server.MAX_AP) { return false; } - if (newLuk < 4 && deltaLuk != Short.MIN_VALUE || newLuk > YamlConfig.config.server.MAX_AP) { + if (newLuk < 4 && deltaLuk != null || newLuk > YamlConfig.config.server.MAX_AP) { return false; } @@ -691,12 +708,12 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple changeStrDexIntLuk(str, dex, int_, luk, remainingAp, false); } - private void changeStrDexIntLuk(int str, int dex, int int_, int luk, int remainingAp, boolean silent) { + private void changeStrDexIntLuk(Integer str, Integer dex, Integer int_, Integer luk, int remainingAp, boolean silent) { long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk); changeStatPool(null, strDexIntLuk, null, remainingAp, silent); } - private void changeStrDexIntLukSp(int str, int dex, int int_, int luk, int remainingAp, int remainingSp, int skillbook, boolean silent) { + private void changeStrDexIntLukSp(Integer str, Integer dex, Integer int_, Integer luk, int remainingAp, int remainingSp, int skillbook, boolean silent) { long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk); long sp = calcStatPoolLong(0, 0, remainingSp, skillbook); changeStatPool(null, strDexIntLuk, sp, remainingAp, silent); diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index f23d08e6c0..7284964a6b 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -1472,11 +1472,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { changeMap(to, to.getPortal(portal)); } - public void changeMap(final MapleMap target, final MaplePortal pto) { + public void changeMap(final MapleMap target, MaplePortal pto) { canWarpCounter++; eventChangedMap(target.getId()); // player can be dropped from an event here, hence the new warping target. MapleMap to = getWarpMap(target.getId()); + if (pto == null) { + pto = to.getPortal(0); + } changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this)); canWarpMap = false; @@ -1504,7 +1507,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { eventAfterChangedMap(this.getMapId()); } - public void forceChangeMap(final MapleMap target, final MaplePortal pto) { + public void forceChangeMap(final MapleMap target, MaplePortal pto) { // will actually enter the map given as parameter, regardless of being an eventmap or whatnot canWarpCounter++; @@ -1525,6 +1528,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } MapleMap to = target; // warps directly to the target intead of the target's map id, this allows GMs to patrol players inside instances. + if (pto == null) { + pto = to.getPortal(0); + } changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this)); canWarpMap = false; @@ -6102,7 +6108,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { List> stat = Collections.singletonList(new Pair<>(MapleBuffStat.ENERGY_CHARGE, energybar)); setBuffedValue(MapleBuffStat.ENERGY_CHARGE, energybar); client.announce(MaplePacketCreator.giveBuff(energybar, 0, stat)); - getMap().broadcastMessage(chr, MaplePacketCreator.giveForeignBuff(energybar, stat)); + getMap().broadcastMessage(chr, MaplePacketCreator.cancelForeignFirstDebuff(id, ((long) 1) << 50)); } }, ceffect.getDuration()); } @@ -9403,25 +9409,41 @@ public class MapleCharacter extends AbstractMapleCharacterObject { public byte getSlots(int type) { return type == MapleInventoryType.CASH.getType() ? 96 : inventory[type].getSlotLimit(); } - + + public boolean canGainSlots(int type, int slots) { + slots += inventory[type].getSlotLimit(); + return slots <= 96; + } + public boolean gainSlots(int type, int slots) { return gainSlots(type, slots, true); } public boolean gainSlots(int type, int slots, boolean update) { - slots += inventory[type].getSlotLimit(); - if (slots <= 96) { - inventory[type].setSlotLimit(slots); - + boolean ret = gainSlotsInternal(type, slots, update); + if (ret) { this.saveCharToDB(); if (update) { client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots)); } - - return true; } - - return false; + + return ret; + } + + private boolean gainSlotsInternal(int type, int slots, boolean update) { + inventory[type].lockInventory(); + try { + if (canGainSlots(type, slots)) { + slots += inventory[type].getSlotLimit(); + inventory[type].setSlotLimit(slots); + return true; + } else { + return false; + } + } finally { + inventory[type].unlockInventory(); + } } public int sellAllItemsFromName(byte invTypeId, String name) { @@ -10487,18 +10509,20 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public void increaseEquipExp(int expGain) { - 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; + if (allowExpGain) { // thanks Vcoc for suggesting equip EXP gain conditionally + 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); } - - nEquip.gainItemExp(client, expGain); } } diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java index aad0849b22..bd8b34e773 100644 --- a/src/client/MapleClient.java +++ b/src/client/MapleClient.java @@ -118,8 +118,7 @@ public class MapleClient { private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true); private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true); private final Lock announcerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ANNOUNCER, true); - private static final int lockCount = 200; - private static final Lock loginLocks[] = new Lock[lockCount]; // thanks Masterrulax & try2hack for pointing out a bottleneck issue here + // thanks Masterrulax & try2hack for pointing out a bottleneck issue with shared locks, shavit for noticing an opportunity for improvement private Calendar tempBanCalendar; private int votePoints; private int voteTime = -1; @@ -129,12 +128,6 @@ public class MapleClient { private long lastPacket = System.currentTimeMillis(); private int lang = 0; - static { - for (int i = 0; i < lockCount; i++) { - loginLocks[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true); - } - } - public void updateLastPacket() { lastPacket = System.currentTimeMillis(); } @@ -453,8 +446,7 @@ public class MapleClient { } public int finishLogin() { - Lock loginLock = loginLocks[this.getAccID() % lockCount]; - loginLock.lock(); + encoderLock.lock(); try { if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN loggedIn = false; @@ -462,7 +454,7 @@ public class MapleClient { } updateLoginState(MapleClient.LOGIN_LOGGEDIN); } finally { - loginLock.unlock(); + encoderLock.unlock(); } return 0; @@ -1379,8 +1371,12 @@ public class MapleClient { characterSlots = slots; } + public boolean canGainCharacterSlot() { + return characterSlots < 15; + } + public synchronized boolean gainCharacterSlot() { - if (characterSlots < 15) { + if (canGainCharacterSlot()) { Connection con = null; try { con = DatabaseConnection.getConnection(); diff --git a/src/client/command/commands/gm0/DisposeCommand.java b/src/client/command/commands/gm0/DisposeCommand.java index eed816cde2..b37a17c8a3 100644 --- a/src/client/command/commands/gm0/DisposeCommand.java +++ b/src/client/command/commands/gm0/DisposeCommand.java @@ -41,5 +41,5 @@ public class DisposeCommand extends Command { c.announce(MaplePacketCreator.enableActions()); c.removeClickedNPC(); c.getPlayer().message("You've been disposed."); + } } -} diff --git a/src/client/inventory/MapleInventory.java b/src/client/inventory/MapleInventory.java index f910a4d903..a2ce3a7f16 100644 --- a/src/client/inventory/MapleInventory.java +++ b/src/client/inventory/MapleInventory.java @@ -453,10 +453,10 @@ public class MapleInventory implements Iterable { private static boolean checkItemRestricted(List> items) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); - Set itemids = new HashSet<>(); + // thanks Shavit for noticing set creation that would be only effective in rare situations for (Pair p : items) { int itemid = p.getLeft().getItemId(); - if (ii.isPickupRestricted(itemid) && (p.getLeft().getQuantity() > 1 || !itemids.add(itemid))) { + if (ii.isPickupRestricted(itemid) && p.getLeft().getQuantity() > 1) { return false; } } diff --git a/src/client/inventory/manipulator/MapleInventoryManipulator.java b/src/client/inventory/manipulator/MapleInventoryManipulator.java index 14428fd4b0..682affe285 100644 --- a/src/client/inventory/manipulator/MapleInventoryManipulator.java +++ b/src/client/inventory/manipulator/MapleInventoryManipulator.java @@ -523,7 +523,10 @@ public class MapleInventoryManipulator { } boolean itemChanged = false; if (ii.isUntradeableOnEquip(source.getItemId())) { - source.setFlag((byte) ItemConstants.UNTRADEABLE); + short flag = source.getFlag(); // thanks BHB for noticing flags missing after equipping these + flag |= ItemConstants.UNTRADEABLE; + source.setFlag(flag); + itemChanged = true; } if (dst == -6) { // unequip the overall diff --git a/src/constants/inventory/ItemConstants.java b/src/constants/inventory/ItemConstants.java index dae6df6b89..c7b73f781e 100644 --- a/src/constants/inventory/ItemConstants.java +++ b/src/constants/inventory/ItemConstants.java @@ -21,7 +21,6 @@ */ package constants.inventory; -import constants.net.ServerConstants; import client.inventory.MapleInventoryType; import config.YamlConfig; diff --git a/src/net/server/Server.java b/src/net/server/Server.java index 108ad0491c..00472b3262 100644 --- a/src/net/server/Server.java +++ b/src/net/server/Server.java @@ -894,33 +894,8 @@ public class Server { //MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run MapleCashidGenerator.loadExistentCashIdsFromDb(); - IoBuffer.setUseDirectBuffer(false); - IoBuffer.setAllocator(new SimpleBufferAllocator()); - acceptor = new NioSocketAcceptor(); - acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory())); - ThreadManager.getInstance().start(); - TimerManager tMan = TimerManager.getInstance(); - tMan.start(); - tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw... - disconnectIdlesOnLoginTask(); - - long timeLeft = getTimeLeftForNextHour(); - tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL); - tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000); - tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft); - tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000); - tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft); - tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft); - tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft); - tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000); - tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft); - tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000); - tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL); - - timeLeft = getTimeLeftForNextDay(); - MapleExpeditionBossLog.resetBossLogTable(); - tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft); + initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan long timeToTake = System.currentTimeMillis(); SkillFactory.loadAllSkills(); @@ -965,6 +940,10 @@ public class Server { System.out.println(); + IoBuffer.setUseDirectBuffer(false); // join IO operations performed by lxconan + IoBuffer.setAllocator(new SimpleBufferAllocator()); + acceptor = new NioSocketAcceptor(); + acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory())); acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30); acceptor.setHandler(new MapleServerHandler()); try { @@ -986,6 +965,30 @@ public class Server { ch.reloadEventScriptManager(); } } + + private void initializeTimelyTasks() { + TimerManager tMan = TimerManager.getInstance(); + tMan.start(); + tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw... + disconnectIdlesOnLoginTask(); + + long timeLeft = getTimeLeftForNextHour(); + tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL); + tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000); + tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft); + tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000); + tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft); + tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft); + tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft); + tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000); + tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft); + tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000); + tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL); + + timeLeft = getTimeLeftForNextDay(); + MapleExpeditionBossLog.resetBossLogTable(); + tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft); + } public static void main(String args[]) { System.setProperty("wzpath", "wz"); @@ -1755,7 +1758,7 @@ public class Server { for (Integer worldid : accWorlds) { if (worldid < worldList.size()) { World wserv = worldList.get(worldid); - wserv.registerAccountStorage(accountId); + wserv.loadAccountStorage(accountId); } } } diff --git a/src/net/server/audit/locks/empty/AbstractEmptyLock.java b/src/net/server/audit/locks/empty/AbstractEmptyLock.java new file mode 100644 index 0000000000..ca81b5af19 --- /dev/null +++ b/src/net/server/audit/locks/empty/AbstractEmptyLock.java @@ -0,0 +1,24 @@ +package net.server.audit.locks.empty; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public abstract class AbstractEmptyLock { + + protected static String printThreadStack(StackTraceElement[] list) { + DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); // DRY-code opportunity performed by jtumidanski + dateFormat.setTimeZone(TimeZone.getDefault()); + String df = dateFormat.format(new Date()); + + String s = "\r\n" + df + "\r\n"; + for(int i = 0; i < list.length; i++) { + s += (" " + list[i].toString() + "\r\n"); + } + s += "----------------------------\r\n\r\n"; + + return s; + } + +} diff --git a/src/net/server/audit/locks/empty/EmptyReadLock.java b/src/net/server/audit/locks/empty/EmptyReadLock.java index 18d3d66c5d..9010dc5ec8 100644 --- a/src/net/server/audit/locks/empty/EmptyReadLock.java +++ b/src/net/server/audit/locks/empty/EmptyReadLock.java @@ -19,11 +19,6 @@ */ package net.server.audit.locks.empty; -import constants.net.ServerConstants; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReadLock; import tools.FilePrinter; @@ -32,27 +27,13 @@ import tools.FilePrinter; * * @author RonanLana */ -public class EmptyReadLock implements MonitoredReadLock { +public class EmptyReadLock extends AbstractEmptyLock implements MonitoredReadLock { private final MonitoredLockType id; public EmptyReadLock(MonitoredLockType type) { this.id = type; } - private static String printThreadStack(StackTraceElement[] list) { - DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getDefault()); - String df = dateFormat.format(new Date()); - - String s = "\r\n" + df + "\r\n"; - for(int i = 0; i < list.length; i++) { - s += (" " + list[i].toString() + "\r\n"); - } - s += "----------------------------\r\n\r\n"; - - return s; - } - @Override public void lock() { FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); diff --git a/src/net/server/audit/locks/empty/EmptyReentrantLock.java b/src/net/server/audit/locks/empty/EmptyReentrantLock.java index be1889e7da..354b9528b8 100644 --- a/src/net/server/audit/locks/empty/EmptyReentrantLock.java +++ b/src/net/server/audit/locks/empty/EmptyReentrantLock.java @@ -19,11 +19,6 @@ */ package net.server.audit.locks.empty; -import constants.net.ServerConstants; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import tools.FilePrinter; @@ -32,27 +27,13 @@ import tools.FilePrinter; * * @author RonanLana */ -public class EmptyReentrantLock implements MonitoredReentrantLock { +public class EmptyReentrantLock extends AbstractEmptyLock implements MonitoredReentrantLock { private final MonitoredLockType id; public EmptyReentrantLock(MonitoredLockType type) { this.id = type; } - private static String printThreadStack(StackTraceElement[] list) { - DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getDefault()); - String df = dateFormat.format(new Date()); - - String s = "\r\n" + df + "\r\n"; - for(int i = 0; i < list.length; i++) { - s += (" " + list[i].toString() + "\r\n"); - } - s += "----------------------------\r\n\r\n"; - - return s; - } - @Override public void lock() { FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); diff --git a/src/net/server/audit/locks/empty/EmptyWriteLock.java b/src/net/server/audit/locks/empty/EmptyWriteLock.java index cbfa163f74..c900689950 100644 --- a/src/net/server/audit/locks/empty/EmptyWriteLock.java +++ b/src/net/server/audit/locks/empty/EmptyWriteLock.java @@ -19,11 +19,6 @@ */ package net.server.audit.locks.empty; -import constants.net.ServerConstants; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredWriteLock; import tools.FilePrinter; @@ -32,27 +27,13 @@ import tools.FilePrinter; * * @author RonanLana */ -public class EmptyWriteLock implements MonitoredWriteLock { +public class EmptyWriteLock extends AbstractEmptyLock implements MonitoredWriteLock { private final MonitoredLockType id; public EmptyWriteLock(MonitoredLockType type) { this.id = type; } - private static String printThreadStack(StackTraceElement[] list) { - DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - dateFormat.setTimeZone(TimeZone.getDefault()); - String df = dateFormat.format(new Date()); - - String s = "\r\n" + df + "\r\n"; - for(int i = 0; i < list.length; i++) { - s += (" " + list[i].toString() + "\r\n"); - } - s += "----------------------------\r\n\r\n"; - - return s; - } - @Override public void lock() { FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); diff --git a/src/net/server/channel/handlers/CashOperationHandler.java b/src/net/server/channel/handlers/CashOperationHandler.java index ea776e240e..39a56c61f0 100644 --- a/src/net/server/channel/handlers/CashOperationHandler.java +++ b/src/net/server/channel/handlers/CashOperationHandler.java @@ -86,16 +86,18 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { } Item item = cItem.toItem(); + cs.gainCash(useNX, cItem, chr.getWorld()); // thanks Rohenn for noticing cash operations after item acquisition cs.addToInventory(item); c.announce(MaplePacketCreator.showBoughtCashItem(item, c.getAccID())); } else { // Package + cs.gainCash(useNX, cItem, chr.getWorld()); + List cashPackage = CashItemFactory.getPackage(cItem.getItemId()); for (Item item : cashPackage) { cs.addToInventory(item); } c.announce(MaplePacketCreator.showBoughtCashPackage(cashPackage, c.getAccID())); } - cs.gainCash(useNX, cItem, chr.getWorld()); c.announce(MaplePacketCreator.showCash(chr)); } else if (action == 0x04) {//TODO check for gender int birthday = slea.readInt(); @@ -116,9 +118,9 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA8)); return; } + cs.gainCash(4, cItem, chr.getWorld()); cs.gift(Integer.parseInt(recipient.get("id")), chr.getName(), message, cItem.getSN()); c.announce(MaplePacketCreator.showGiftSucceed(recipient.get("name"), cItem)); - cs.gainCash(4, cItem, chr.getWorld()); c.announce(MaplePacketCreator.showCash(chr)); try { chr.sendNote(recipient.get("name"), chr.getName() + " has sent you a gift! Go check out the Cash Shop.", (byte) 0); //fame or not @@ -147,10 +149,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { c.enableCSActions(); return; } - if (chr.gainSlots(type, 4, false)) { + int qty = 4; + if (!chr.canGainSlots(type, qty)) { + c.enableCSActions(); + return; + } + cs.gainCash(cash, -4000); + if (chr.gainSlots(type, qty, false)) { c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type))); - cs.gainCash(cash, -4000); c.announce(MaplePacketCreator.showCash(chr)); + } else { + FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName())); } } else { CashItem cItem = CashItemFactory.getItem(slea.readInt()); @@ -159,10 +168,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { c.enableCSActions(); return; } - if (chr.gainSlots(type, 8, false)) { + int qty = 8; + if (!chr.canGainSlots(type, qty)) { + c.enableCSActions(); + return; + } + cs.gainCash(cash, cItem, chr.getWorld()); + if (chr.gainSlots(type, qty, false)) { c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type))); - cs.gainCash(cash, cItem, chr.getWorld()); c.announce(MaplePacketCreator.showCash(chr)); + } else { + FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName())); } } } else if (action == 0x07) { // Increase Storage Slots @@ -174,13 +190,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { c.enableCSActions(); return; } - if (chr.getStorage().gainSlots(4)) { - FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought 4 slots to their account storage."); + int qty = 4; + if (!chr.getStorage().canGainSlots(qty)) { + c.enableCSActions(); + return; + } + cs.gainCash(cash, -4000); + if (chr.getStorage().gainSlots(qty)) { + FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage."); chr.setUsedStorage(); c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots())); - cs.gainCash(cash, -4000); c.announce(MaplePacketCreator.showCash(chr)); + } else { + FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account."); } } else { CashItem cItem = CashItemFactory.getItem(slea.readInt()); @@ -189,13 +212,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { c.enableCSActions(); return; } - if (chr.getStorage().gainSlots(8)) { // thanks ABaldParrot & Thora for detecting storage issues here - FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought 8 slots to their account storage."); + int qty = 8; + if (!chr.getStorage().canGainSlots(qty)) { + c.enableCSActions(); + return; + } + cs.gainCash(cash, cItem, chr.getWorld()); + if (chr.getStorage().gainSlots(qty)) { // thanks ABaldParrot & Thora for detecting storage issues here + FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage."); chr.setUsedStorage(); c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots())); - cs.gainCash(cash, cItem, chr.getWorld()); c.announce(MaplePacketCreator.showCash(chr)); + } else { + FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account."); } } } else if (action == 0x08) { // Increase Character Slots @@ -207,13 +237,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { c.enableCSActions(); return; } - + if (!c.canGainCharacterSlot()) { + chr.dropMessage(1, "You have already used up all 12 extra character slots."); + c.enableCSActions(); + return; + } + cs.gainCash(cash, cItem, chr.getWorld()); if (c.gainCharacterSlot()) { c.announce(MaplePacketCreator.showBoughtCharacterSlot(c.getCharacterSlots())); - cs.gainCash(cash, cItem, chr.getWorld()); c.announce(MaplePacketCreator.showCash(chr)); } else { - chr.dropMessage(1, "You have already used up all 12 extra character slots."); + FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add a character slot to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account."); c.enableCSActions(); return; } @@ -287,8 +321,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { eqp.setRingId(rings.getLeft()); cs.addToInventory(eqp); c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID())); - cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight()); cs.gainCash(toCharge, itemRing, chr.getWorld()); + cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight()); chr.addCrushRing(MapleRing.loadFromDb(rings.getLeft())); try { chr.sendNote(partner.getName(), text, (byte) 1); @@ -353,8 +387,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { eqp.setRingId(rings.getLeft()); cs.addToInventory(eqp); c.announce(MaplePacketCreator.showBoughtCashRing(eqp, partner.getName(), c.getAccID())); - cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight()); cs.gainCash(payment, -itemRing.getPrice()); + cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight()); chr.addFriendshipRing(MapleRing.loadFromDb(rings.getLeft())); try { chr.sendNote(partner.getName(), text, (byte) 1); @@ -391,8 +425,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { if(chr.registerNameChange(newName)) { //success Item item = cItem.toItem(); c.announce(MaplePacketCreator.showNameChangeSuccess(item, c.getAccID())); - cs.addToInventory(item); cs.gainCash(4, cItem, chr.getWorld()); + cs.addToInventory(item); } else { c.announce(MaplePacketCreator.showCashShopMessage((byte)0)); } @@ -421,8 +455,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler { } else if(chr.registerWorldTransfer(newWorldSelection)) { Item item = cItem.toItem(); c.announce(MaplePacketCreator.showWorldTransferSuccess(item, c.getAccID())); - cs.addToInventory(item); cs.gainCash(4, cItem, chr.getWorld()); + cs.addToInventory(item); } else { c.announce(MaplePacketCreator.showCashShopMessage((byte)0)); } diff --git a/src/net/server/channel/handlers/InventorySortHandler.java b/src/net/server/channel/handlers/InventorySortHandler.java index d7510405f8..63b00ba038 100644 --- a/src/net/server/channel/handlers/InventorySortHandler.java +++ b/src/net/server/channel/handlers/InventorySortHandler.java @@ -35,7 +35,6 @@ import client.inventory.Equip; import client.inventory.MapleInventory; import client.inventory.MapleInventoryType; import client.inventory.ModifyInventory; -import constants.net.ServerConstants; import server.MapleItemInformationProvider; import net.server.Server; @@ -73,7 +72,11 @@ class PairedQuicksort { } while (i <= j); } - private void PartitionByItemIdReverse(int Esq, int Dir, ArrayList A) { + private int getWatkForProjectile(Item item) { + return ii.getWatkForProjectile(item.getItemId()); + } + + private void PartitionByProjectileAtk(int Esq, int Dir, ArrayList A) { Item x, w; i = Esq; @@ -81,8 +84,9 @@ class PairedQuicksort { x = A.get((i + j) / 2); do { - while (x.getItemId() < A.get(i).getItemId()) i++; - while (x.getItemId() > A.get(j).getItemId()) j--; + int watk = getWatkForProjectile(x); + while (watk < getWatkForProjectile(A.get(i))) i++; + while (watk > getWatkForProjectile(A.get(j))) j--; if (i <= j) { w = A.get(i); @@ -228,7 +232,7 @@ class PairedQuicksort { public void reverseSortSublist(ArrayList A, int[] range) { if (range != null) { - PartitionByItemIdReverse(range[0], range[1], A); + PartitionByProjectileAtk(range[0], range[1], A); } } diff --git a/src/net/server/channel/handlers/UseCashItemHandler.java b/src/net/server/channel/handlers/UseCashItemHandler.java index 7146eba05d..5c8a207a79 100644 --- a/src/net/server/channel/handlers/UseCashItemHandler.java +++ b/src/net/server/channel/handlers/UseCashItemHandler.java @@ -244,7 +244,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler { eq.setExpiration(currentServerTime() + (period * 60 * 60 * 24 * 1000)); } - remove(c, position, itemId); + // double-remove found thanks to BHB } else if (itemId == 5060002) { // Incubator byte inventory2 = (byte) slea.readInt(); short slot2 = (short) slea.readInt(); diff --git a/src/net/server/world/World.java b/src/net/server/world/World.java index 6d5181edd9..f1ebaf43d1 100644 --- a/src/net/server/world/World.java +++ b/src/net/server/world/World.java @@ -467,7 +467,13 @@ public class World { } } - public void registerAccountStorage(Integer accountId) { + public void loadAccountStorage(Integer accountId) { + if (getAccountStorage(accountId) == null) { + registerAccountStorage(accountId); + } + } + + private void registerAccountStorage(Integer accountId) { MapleStorage storage = MapleStorage.loadOrCreateFromDB(accountId, this.id); accountCharsLock.lock(); try { @@ -572,7 +578,7 @@ public class World { if(cserv != null) { if(!cserv.removePlayer(chr)) { - // oy the player is not where it should be, find this mf + // oy the player is not where they should be, find this mf for(Channel ch : getChannels()) { if(ch.removePlayer(chr)) { diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 5fa69ad6c9..08b1b02916 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.HashMap; import java.util.Map; import config.YamlConfig; @@ -640,7 +639,7 @@ public class MapleStatEffect { break; case WindArcher.WIND_WALK: statups.add(new Pair<>(MapleBuffStat.WIND_WALK, Integer.valueOf(x))); - break; + //break; thanks Vcoc for noticing WW not showing for other players when changing maps case Rogue.DARK_SIGHT: case NightWalker.DARK_SIGHT: statups.add(new Pair<>(MapleBuffStat.DARKSIGHT, Integer.valueOf(x))); @@ -1343,6 +1342,8 @@ public class MapleStatEffect { if (isDash()) { buff = MaplePacketCreator.givePirateBuff(statups, sourceid, seconds); mbuff = MaplePacketCreator.giveForeignPirateBuff(applyto.getId(), sourceid, seconds, localstatups); + } else if (isWkCharge()) { + mbuff = MaplePacketCreator.giveForeignWKChargeEffect(applyto.getId(), sourceid, localstatups); } else if (isInfusion()) { buff = MaplePacketCreator.givePirateBuff(localstatups, sourceid, seconds); mbuff = MaplePacketCreator.giveForeignPirateBuff(applyto.getId(), sourceid, seconds, localstatups); @@ -1746,6 +1747,20 @@ public class MapleStatEffect { return false; } } + + private boolean isWkCharge() { + if (!skill) { + return false; + } + + for (Pair p : statups) { + if (p.getLeft().equals(MapleBuffStat.WK_CHARGE)) { + return true; + } + } + + return false; + } private boolean isDash() { return skill && (sourceid == Pirate.DASH || sourceid == ThunderBreaker.DASH || sourceid == Beginner.SPACE_DASH || sourceid == Noblesse.SPACE_DASH); diff --git a/src/server/MapleStorage.java b/src/server/MapleStorage.java index af551e435c..f1dd374fb8 100644 --- a/src/server/MapleStorage.java +++ b/src/server/MapleStorage.java @@ -114,12 +114,16 @@ public class MapleStorage { return slots; } + public boolean canGainSlots(int slots) { + slots += this.slots; + return slots <= 48; + } + public boolean gainSlots(int slots) { lock.lock(); try { - slots += this.slots; - - if (slots <= 48) { + if (canGainSlots(slots)) { + slots += this.slots; this.slots = (byte) slots; return true; } diff --git a/src/server/maps/MapleMapFactory.java b/src/server/maps/MapleMapFactory.java index dd483131d2..3b7ab48db3 100644 --- a/src/server/maps/MapleMapFactory.java +++ b/src/server/maps/MapleMapFactory.java @@ -310,19 +310,9 @@ public class MapleMapFactory { } } - try { - map.setMapName(loadPlaceName(mapid)); - map.setStreetName(loadStreetName(mapid)); - } catch (Exception e) { - if (mapid / 1000 != 1020) { // explorer job introduction scenes - e.printStackTrace(); - System.err.println("Not found mapid " + mapid); - } - - map.setMapName(""); - map.setStreetName(""); - } - + map.setMapName(loadPlaceName(mapid)); + map.setStreetName(loadStreetName(mapid)); + map.setClock(mapData.getChildByPath("clock") != null); map.setEverlast(MapleDataTool.getIntConvert("everlast", infoData, 0) != 0); // thanks davidlafriniere for noticing value 0 accounting as true map.setTown(MapleDataTool.getIntConvert("town", infoData, 0) != 0); @@ -435,7 +425,7 @@ public class MapleMapFactory { return builder.toString(); } - public static String loadPlaceName(int mapid) throws Exception { + public static String loadPlaceName(int mapid) { try { return MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(mapid)), ""); } catch (Exception e) { @@ -443,7 +433,7 @@ public class MapleMapFactory { } } - public static String loadStreetName(int mapid) throws Exception { + public static String loadStreetName(int mapid) { try { return MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(mapid)), ""); } catch (Exception e) { diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index ee0e25d53b..0b180c19cd 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -1890,7 +1890,7 @@ public class MaplePacketCreator { } long buffmask = 0; Integer buffvalue = null; - if (chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && !chr.isHidden()) { + if ((chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null || chr.getBuffedValue(MapleBuffStat.WIND_WALK) != null) && !chr.isHidden()) { buffmask |= MapleBuffStat.DARKSIGHT.getValue(); } if (chr.getBuffedValue(MapleBuffStat.COMBO) != null) { @@ -1906,10 +1906,6 @@ public class MaplePacketCreator { 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 @@ -1919,16 +1915,24 @@ public class MaplePacketCreator { } } mplew.writeInt((int) (buffmask & 0xffffffffL)); - int CHAR_MAGIC_SPAWN = Randomizer.nextInt(); - mplew.skip(6); - mplew.writeInt(CHAR_MAGIC_SPAWN); + + // Energy Charge + mplew.writeInt(chr.getEnergyBar() == 15000 ? 1 : 0); + mplew.writeShort(0); + mplew.skip(4); + + boolean dashBuff = chr.getBuffedValue(MapleBuffStat.DASH) != null; + // Dash Speed + mplew.writeInt(dashBuff ? 1 << 24 : 0); mplew.skip(11); - mplew.writeInt(CHAR_MAGIC_SPAWN);//v74 - mplew.skip(11); - mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.writeShort(0); + // Dash Jump + mplew.skip(9); + mplew.writeInt(dashBuff ? 1 << 24 : 0); mplew.writeShort(0); mplew.write(0); + // Monster Riding Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING); if (bv != null) { MapleMount mount = chr.getMount(); @@ -1942,17 +1946,23 @@ public class MaplePacketCreator { mplew.writeLong(0); } + int CHAR_MAGIC_SPAWN = Randomizer.nextInt(); // skill references found thanks to Rien dev team mplew.writeInt(CHAR_MAGIC_SPAWN); + // Speed Infusion + mplew.skip(8); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.write(0); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.writeShort(0); + // Homing Beacon + mplew.skip(9); + mplew.writeInt(CHAR_MAGIC_SPAWN); + mplew.writeInt(0); + // Zombify 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); } /** @@ -3067,6 +3077,15 @@ public class MaplePacketCreator { return mplew.getPacket(); } + public static byte[] cancelForeignFirstDebuff(int cid, long mask) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + mplew.writeLong(mask); + mplew.writeLong(0); + return mplew.getPacket(); + } + public static byte[] cancelForeignDebuff(int cid, long mask) { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); @@ -3198,6 +3217,20 @@ public class MaplePacketCreator { return mplew.getPacket(); } + // packet found thanks to Ronan + public static byte[] giveForeignWKChargeEffect(int cid, int buffid, List> statups) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); + mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue()); + mplew.writeInt(cid); + writeLongMask(mplew, statups); + mplew.writeInt(buffid); + mplew.writeShort(600); + mplew.writeShort(1000);//Delay + mplew.write(1); + + return mplew.getPacket(); + } + public static byte[] cancelForeignChairSkillEffect(int cid) { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19); mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue()); diff --git a/wz/String.wz/Consume.img.xml b/wz/String.wz/Consume.img.xml index e98d748844..3a4a74fc31 100644 --- a/wz/String.wz/Consume.img.xml +++ b/wz/String.wz/Consume.img.xml @@ -230,7 +230,7 @@ - + @@ -1445,31 +1445,31 @@ - + - + - + - + - + - + - + @@ -3689,7 +3689,7 @@ - + @@ -8305,7 +8305,7 @@ - +