From 2ffca90d29f2d756d01bf8f78b89043d8c3e3aba Mon Sep 17 00:00:00 2001 From: P0nk Date: Wed, 14 Aug 2024 07:45:06 +0200 Subject: [PATCH] Add attack delay to AttackInfo Meant to be used in item drop packet for timing handled by the client rather than scheduling item drop packets on the server. --- .../handlers/AbstractDealDamageHandler.java | 38 ++-- .../handlers/CloseRangeDamageHandler.java | 8 +- .../channel/handlers/MagicDamageHandler.java | 7 +- .../channel/handlers/RangedAttackHandler.java | 20 +- src/main/java/server/maps/MapleMap.java | 174 +++++++++--------- src/main/java/tools/PacketCreator.java | 44 +++-- 6 files changed, 163 insertions(+), 128 deletions(-) diff --git a/src/main/java/net/server/channel/handlers/AbstractDealDamageHandler.java b/src/main/java/net/server/channel/handlers/AbstractDealDamageHandler.java index c661d03efc..b9b80b9b32 100644 --- a/src/main/java/net/server/channel/handlers/AbstractDealDamageHandler.java +++ b/src/main/java/net/server/channel/handlers/AbstractDealDamageHandler.java @@ -117,7 +117,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { public static class AttackInfo { public int numAttacked, numDamage, numAttackedAndDamage, skill, skilllevel, stance, direction, rangedirection, charge, display; - public Map> allDamage; + public Map targets; public boolean ranged, magic; public int speed = 4; public Point position = new Point(); @@ -146,6 +146,9 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { } } + // TODO: add position + public record AttackTarget(short delay, List damageLines) {} + protected void applyAttack(AttackInfo attack, final Character player, int attackCount) { final MapleMap map = player.getMap(); if (map.isOwnershipRestricted(player)) { @@ -216,7 +219,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { if (attack.skill == ChiefBandit.MESO_EXPLOSION) { int delay = 0; - for (Integer oned : attack.allDamage.keySet()) { + for (Integer oned : attack.targets.keySet()) { MapObject mapobject = map.getMapObject(oned); if (mapobject != null && mapobject.getType() == MapObjectType.ITEM) { final MapItem mapitem = (MapItem) mapobject; @@ -249,7 +252,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { } } } - for (Integer oned : attack.allDamage.keySet()) { + for (Integer oned : attack.targets.keySet()) { final Monster monster = map.getMonsterByOid(oned); if (monster != null) { double distance = player.getPosition().distanceSq(monster.getPosition()); @@ -285,7 +288,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { } int totDamageToOneMonster = 0; - List onedList = attack.allDamage.get(oned); + List onedList = attack.targets.get(oned).damageLines(); if (attack.magic) { // thanks BHB, Alex (CanIGetaPR) for noticing no immunity status check here if (monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) { @@ -600,7 +603,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { ret.numAttackedAndDamage = p.readByte(); ret.numAttacked = (ret.numAttackedAndDamage >>> 4) & 0xF; ret.numDamage = ret.numAttackedAndDamage & 0xF; - ret.allDamage = new HashMap<>(); + ret.targets = new HashMap<>(); ret.skill = p.readInt(); ret.ranged = ranged; ret.magic = magic; @@ -629,7 +632,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { for (int j = 0; j < bullets; j++) { int mesoid = p.readInt(); p.skip(1); - ret.allDamage.put(mesoid, null); + ret.targets.put(mesoid, null); } return ret; } else { @@ -638,6 +641,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { for (int i = 0; i < ret.numAttacked + 1; i++) { int oid = p.readInt(); if (i < ret.numAttacked) { + // TODO: read delay in from these skipped bytes p.skip(12); int bullets = p.readByte(); List allDamageNumbers = new ArrayList<>(); @@ -645,14 +649,14 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { int damage = p.readInt(); allDamageNumbers.add(damage); } - ret.allDamage.put(oid, allDamageNumbers); + ret.targets.put(oid, new AttackTarget((short) 0, allDamageNumbers)); p.skip(4); } else { int bullets = p.readByte(); for (int j = 0; j < bullets; j++) { int mesoid = p.readInt(); p.skip(1); - ret.allDamage.put(mesoid, null); + ret.targets.put(mesoid, null); } } } @@ -814,10 +818,12 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { } for (int i = 0; i < ret.numAttacked; i++) { int oid = p.readInt(); - p.skip(14); - List allDamageNumbers = new ArrayList<>(); - Monster monster = chr.getMap().getMonsterByOid(oid); - + p.skip(4); + Point curPos = p.readPos(); + Point nextPos = p.readPos(); + short delay = p.readShort(); + List damageLines = new ArrayList<>(); + final Monster monster = chr.getMap().getMonsterByOid(oid); if (chr.getBuffEffect(BuffStat.WK_CHARGE) != null) { // Charge, so now we need to check elemental effectiveness int sourceID = chr.getBuffSource(BuffStat.WK_CHARGE); @@ -941,12 +947,12 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { } } - allDamageNumbers.add(damage); + damageLines.add(damage); } if (ret.skill != Corsair.RAPID_FIRE || ret.skill != Aran.HIDDEN_FULL_DOUBLE || ret.skill != Aran.HIDDEN_FULL_TRIPLE || ret.skill != Aran.HIDDEN_OVER_DOUBLE || ret.skill != Aran.HIDDEN_OVER_TRIPLE) { p.skip(4); } - ret.allDamage.put(oid, allDamageNumbers); + ret.targets.put(oid, new AttackTarget(delay, damageLines)); } if (ret.skill == NightWalker.POISON_BOMB) { // Poison Bomb p.skip(4); @@ -954,8 +960,4 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler { } return ret; } - - private static int rand(int l, int u) { - return (int) ((Math.random() * (u - l + 1)) + l); - } } diff --git a/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java b/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java index 5a8a9bef61..b25712d912 100644 --- a/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java +++ b/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java @@ -78,7 +78,9 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler { c.sendPacket(PacketCreator.getEnergy("energy", chr.getDojoEnergy())); } - chr.getMap().broadcastMessage(chr, PacketCreator.closeRangeAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, attack.speed, attack.direction, attack.display), false, true); + chr.getMap().broadcastMessage(chr, PacketCreator.closeRangeAttack(chr, attack.skill, attack.skilllevel, + attack.stance, attack.numAttackedAndDamage, attack.targets, attack.speed, attack.direction, + attack.display), false, true); int numFinisherOrbs = 0; Integer comboBuff = chr.getBuffedValue(BuffStat.COMBO); if (GameConstants.isFinisherSkill(attack.skill)) { @@ -139,9 +141,9 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler { } if (attack.numAttacked > 0 && attack.skill == DragonKnight.SACRIFICE) { int totDamageToOneMonster = 0; // sacrifice attacks only 1 mob with 1 attack - final Iterator> dmgIt = attack.allDamage.values().iterator(); + final Iterator dmgIt = attack.targets.values().iterator(); if (dmgIt.hasNext()) { - totDamageToOneMonster = dmgIt.next().get(0); + totDamageToOneMonster = dmgIt.next().damageLines().getFirst(); } chr.safeAddHP(-1 * totDamageToOneMonster * attack.getAttackEffect(chr, null).getX() / 100); diff --git a/src/main/java/net/server/channel/handlers/MagicDamageHandler.java b/src/main/java/net/server/channel/handlers/MagicDamageHandler.java index 7350e55c55..3324ebb023 100644 --- a/src/main/java/net/server/channel/handlers/MagicDamageHandler.java +++ b/src/main/java/net/server/channel/handlers/MagicDamageHandler.java @@ -66,7 +66,8 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler { } int charge = (attack.skill == Evan.FIRE_BREATH || attack.skill == Evan.ICE_BREATH || attack.skill == FPArchMage.BIG_BANG || attack.skill == ILArchMage.BIG_BANG || attack.skill == Bishop.BIG_BANG) ? attack.charge : -1; - Packet packet = PacketCreator.magicAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, attack.allDamage, charge, attack.speed, attack.direction, attack.display); + Packet packet = PacketCreator.magicAttack(chr, attack.skill, attack.skilllevel, attack.stance, + attack.numAttackedAndDamage, attack.targets, charge, attack.speed, attack.direction, attack.display); chr.getMap().broadcastMessage(chr, packet, false, true); StatEffect effect = attack.getAttackEffect(chr, null); @@ -84,8 +85,8 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler { Skill eaterSkill = SkillFactory.getSkill((chr.getJob().getId() - (chr.getJob().getId() % 10)) * 10000);// MP Eater, works with right job int eaterLevel = chr.getSkillLevel(eaterSkill); if (eaterLevel > 0) { - for (Integer singleDamage : attack.allDamage.keySet()) { - eaterSkill.getEffect(eaterLevel).applyPassive(chr, chr.getMap().getMapObject(singleDamage), 0); + for (Integer oid : attack.targets.keySet()) { + eaterSkill.getEffect(eaterLevel).applyPassive(chr, chr.getMap().getMapObject(oid), 0); } } } diff --git a/src/main/java/net/server/channel/handlers/RangedAttackHandler.java b/src/main/java/net/server/channel/handlers/RangedAttackHandler.java index 85d599b9fc..dff4e77d7a 100644 --- a/src/main/java/net/server/channel/handlers/RangedAttackHandler.java +++ b/src/main/java/net/server/channel/handlers/RangedAttackHandler.java @@ -83,17 +83,23 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler { } if (attack.skill == Buccaneer.ENERGY_ORB || attack.skill == ThunderBreaker.SPARK || attack.skill == Shadower.TAUNT || attack.skill == NightLord.TAUNT) { - chr.getMap().broadcastMessage(chr, PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, 0, attack.allDamage, attack.speed, attack.direction, attack.display), false); + chr.getMap().broadcastMessage(chr, PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, + attack.stance, attack.numAttackedAndDamage, 0, attack.targets, attack.speed, + attack.direction, attack.display), false); applyAttack(attack, chr, 1); } else if (attack.skill == ThunderBreaker.SHARK_WAVE && chr.getSkillLevel(ThunderBreaker.SHARK_WAVE) > 0) { - chr.getMap().broadcastMessage(chr, PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, 0, attack.allDamage, attack.speed, attack.direction, attack.display), false); + chr.getMap().broadcastMessage(chr, PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, + attack.stance, attack.numAttackedAndDamage, 0, attack.targets, attack.speed, + attack.direction, attack.display), false); applyAttack(attack, chr, 1); for (int i = 0; i < attack.numAttacked; i++) { chr.handleEnergyChargeGain(); } } else if (attack.skill == Aran.COMBO_SMASH || attack.skill == Aran.COMBO_FENRIR || attack.skill == Aran.COMBO_TEMPEST) { - chr.getMap().broadcastMessage(chr, PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, 0, attack.allDamage, attack.speed, attack.direction, attack.display), false); + chr.getMap().broadcastMessage(chr, PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, + attack.stance, attack.numAttackedAndDamage, 0, attack.targets, attack.speed, + attack.direction, attack.display), false); if (attack.skill == Aran.COMBO_SMASH && chr.getCombo() >= 30) { chr.setCombo((short) 0); applyAttack(attack, chr, 1); @@ -213,10 +219,14 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler { case 3221001: // Pierce case 5221004: // Rapid Fire case 13111002: // KoC Hurricane - packet = PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.rangedirection, attack.numAttackedAndDamage, visProjectile, attack.allDamage, attack.speed, attack.direction, attack.display); + packet = PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.rangedirection, + attack.numAttackedAndDamage, visProjectile, attack.targets, attack.speed, + attack.direction, attack.display); break; default: - packet = PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.stance, attack.numAttackedAndDamage, visProjectile, attack.allDamage, attack.speed, attack.direction, attack.display); + packet = PacketCreator.rangedAttack(chr, attack.skill, attack.skilllevel, attack.stance, + attack.numAttackedAndDamage, visProjectile, attack.targets, attack.speed, + attack.direction, attack.display); break; } chr.getMap().broadcastMessage(chr, packet, false, true); diff --git a/src/main/java/server/maps/MapleMap.java b/src/main/java/server/maps/MapleMap.java index ceadc01aff..9440fc48ff 100644 --- a/src/main/java/server/maps/MapleMap.java +++ b/src/main/java/server/maps/MapleMap.java @@ -1337,22 +1337,23 @@ public class MapleMap { } } } - if (monster.isAlive()) { - boolean killed = monster.damage(chr, damage, false); - - selfDestruction selfDestr = monster.getStats().selfDestruction(); - if (selfDestr != null && selfDestr.getHp() > -1) {// should work ;p - if (monster.getHp() <= selfDestr.getHp()) { - killMonster(monster, chr, true, selfDestr.getAction()); - return true; - } - } - if (killed) { - killMonster(monster, chr, true); - } - return true; + if (!monster.isAlive()) { + return false; } - return false; + + boolean killed = monster.damage(chr, damage, false); + + selfDestruction selfDestr = monster.getStats().selfDestruction(); + if (selfDestr != null && selfDestr.getHp() > -1) {// should work ;p + if (monster.getHp() <= selfDestr.getHp()) { + killMonster(monster, chr, true, selfDestr.getAction()); + return true; + } + } + if (killed) { + killMonster(monster, chr, true); + } + return true; } public void broadcastBalrogVictory(String leaderName) { @@ -1406,12 +1407,17 @@ public class MapleMap { broadcastMessage(PacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition()); monster.aggroSwitchController(null, false); } - } else { - if (removeKilledMonsterObject(monster)) { - try { - if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) { - AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher."); - } + return; + } + + if (!removeKilledMonsterObject(monster)) { + return; + } + + try { + if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) { + AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher."); + } /*if (chr.getQuest(Quest.getInstance(29400)).getStatus().equals(QuestStatus.Status.STARTED)) { if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) { @@ -1420,74 +1426,74 @@ public class MapleMap { } }*/ - if (monster.getCP() > 0 && chr.getMap().isCPQMap()) { - chr.gainCP(monster.getCP()); - } + if (monster.getCP() > 0 && chr.getMap().isCPQMap()) { + chr.gainCP(monster.getCP()); + } - int buff = monster.getBuffToGive(); - if (buff > -1) { - ItemInformationProvider mii = ItemInformationProvider.getInstance(); - for (MapObject mmo : this.getPlayers()) { - Character character = (Character) mmo; - if (character.isAlive()) { - StatEffect statEffect = mii.getItemEffect(buff); - character.sendPacket(PacketCreator.showOwnBuffEffect(buff, 1)); - broadcastMessage(character, PacketCreator.showBuffEffect(character.getId(), buff, 1), false); - statEffect.applyTo(character); - } - } + int buff = monster.getBuffToGive(); + if (buff > -1) { + ItemInformationProvider mii = ItemInformationProvider.getInstance(); + for (MapObject mmo : this.getPlayers()) { + Character character = (Character) mmo; + if (character.isAlive()) { + StatEffect statEffect = mii.getItemEffect(buff); + character.sendPacket(PacketCreator.showOwnBuffEffect(buff, 1)); + broadcastMessage(character, PacketCreator.showBuffEffect(character.getId(), buff, 1), false); + statEffect.applyTo(character); } - - if (MobId.isZakumArm(monster.getId())) { - boolean makeZakReal = true; - Collection objects = getMapObjects(); - for (MapObject object : objects) { - Monster mons = getMonsterByOid(object.getObjectId()); - if (mons != null) { - if (MobId.isZakumArm(mons.getId())) { - makeZakReal = false; - break; - } - } - } - if (makeZakReal) { - MapleMap map = chr.getMap(); - - for (MapObject object : objects) { - Monster mons = map.getMonsterByOid(object.getObjectId()); - if (mons != null) { - if (mons.getId() == MobId.ZAKUM_1) { - makeMonsterReal(mons); - break; - } - } - } - } - } - - Character dropOwner = monster.killBy(chr); - if (withDrops && !monster.dropsDisabled()) { - if (dropOwner == null) { - dropOwner = chr; - } - dropFromMonster(dropOwner, monster, false); - } - - if (monster.hasBossHPBar()) { - for (Character mc : this.getAllPlayers()) { - if (mc.getTargetHpBarHash() == monster.hashCode()) { - mc.resetPlayerAggro(); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } finally { // thanks resinate for pointing out a memory leak possibly from an exception thrown - monster.dispatchMonsterKilled(true); - broadcastMessage(PacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition()); } } + + if (MobId.isZakumArm(monster.getId())) { + boolean makeZakReal = true; + Collection objects = getMapObjects(); + for (MapObject object : objects) { + Monster mons = getMonsterByOid(object.getObjectId()); + if (mons != null) { + if (MobId.isZakumArm(mons.getId())) { + makeZakReal = false; + break; + } + } + } + if (makeZakReal) { + MapleMap map = chr.getMap(); + + for (MapObject object : objects) { + Monster mons = map.getMonsterByOid(object.getObjectId()); + if (mons != null) { + if (mons.getId() == MobId.ZAKUM_1) { + makeMonsterReal(mons); + break; + } + } + } + } + } + + Character dropOwner = monster.killBy(chr); + if (withDrops && !monster.dropsDisabled()) { + if (dropOwner == null) { + dropOwner = chr; + } + dropFromMonster(dropOwner, monster, false); + } + + if (monster.hasBossHPBar()) { + for (Character mc : this.getAllPlayers()) { + if (mc.getTargetHpBarHash() == monster.hashCode()) { + mc.resetPlayerAggro(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { // thanks resinate for pointing out a memory leak possibly from an exception thrown + monster.dispatchMonsterKilled(true); + broadcastMessage(PacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition()); } + + } public void killFriendlies(Monster mob) { diff --git a/src/main/java/tools/PacketCreator.java b/src/main/java/tools/PacketCreator.java index a6cf3cf6eb..3ee9d8fdff 100644 --- a/src/main/java/tools/PacketCreator.java +++ b/src/main/java/tools/PacketCreator.java @@ -56,6 +56,7 @@ import constants.id.MapId; import constants.id.NpcId; import constants.inventory.ItemConstants; import constants.skills.Buccaneer; +import constants.skills.ChiefBandit; import constants.skills.Corsair; import constants.skills.ThunderBreaker; import net.encryption.InitializationVector; @@ -67,6 +68,7 @@ import net.packet.Packet; import net.server.PlayerCoolDownValueHolder; import net.server.Server; import net.server.channel.Channel; +import net.server.channel.handlers.AbstractDealDamageHandler.AttackTarget; import net.server.channel.handlers.PlayerInteractionHandler; import net.server.channel.handlers.SummonDamageHandler.SummonAttackEntry; import net.server.channel.handlers.WhisperHandler; @@ -2338,29 +2340,40 @@ public class PacketCreator { } */ - public static Packet closeRangeAttack(Character chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map> damage, int speed, int direction, int display) { + public static Packet closeRangeAttack(Character chr, int skill, int skilllevel, int stance, + int numAttackedAndDamage, Map targets, int speed, + int direction, int display) { final OutPacket p = OutPacket.create(SendOpcode.CLOSE_RANGE_ATTACK); - addAttackBody(p, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display); + addAttackBody(p, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, targets, speed, direction, + display); return p; } - public static Packet rangedAttack(Character chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map> damage, int speed, int direction, int display) { + public static Packet rangedAttack(Character chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, + int projectile, Map targets, int speed, int direction, + int display) { final OutPacket p = OutPacket.create(SendOpcode.RANGED_ATTACK); - addAttackBody(p, chr, skill, skilllevel, stance, numAttackedAndDamage, projectile, damage, speed, direction, display); + addAttackBody(p, chr, skill, skilllevel, stance, numAttackedAndDamage, projectile, targets, speed, direction, + display); p.writeInt(0); return p; } - public static Packet magicAttack(Character chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map> damage, int charge, int speed, int direction, int display) { + public static Packet magicAttack(Character chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, + Map targets, int charge, int speed, int direction, + int display) { final OutPacket p = OutPacket.create(SendOpcode.MAGIC_ATTACK); - addAttackBody(p, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display); + addAttackBody(p, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, targets, speed, direction, + display); if (charge != -1) { p.writeInt(charge); } return p; } - private static void addAttackBody(OutPacket p, Character chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map> damage, int speed, int direction, int display) { + private static void addAttackBody(OutPacket p, Character chr, int skill, int skilllevel, int stance, + int numAttackedAndDamage, int projectile, Map targets, + int speed, int direction, int display) { p.writeInt(chr.getId()); p.writeByte(numAttackedAndDamage); p.writeByte(0x5B);//? @@ -2374,16 +2387,16 @@ public class PacketCreator { p.writeByte(speed); p.writeByte(0x0A); p.writeInt(projectile); - for (Integer oned : damage.keySet()) { - List onedList = damage.get(oned); - if (onedList != null) { - p.writeInt(oned); + for (Map.Entry target : targets.entrySet()) { + AttackTarget value = target.getValue(); + if (value != null) { + p.writeInt(target.getKey()); p.writeByte(0x0); - if (skill == 4211006) { - p.writeByte(onedList.size()); + if (skill == ChiefBandit.MESO_EXPLOSION) { + p.writeByte(value.damageLines().size()); } - for (Integer eachd : onedList) { - p.writeInt(eachd); + for (Integer damageLine : value.damageLines()) { + p.writeInt(damageLine); } } } @@ -2581,6 +2594,7 @@ public class PacketCreator { * @param slot * @return */ + // TODO: look for a "delay" in case animation = 4 (explode). Doesn't make sense for it to be server-sided. public static Packet removeItemFromMap(int objId, int animation, int chrId, boolean pet, int slot) { OutPacket p = OutPacket.create(SendOpcode.REMOVE_ITEM_FROM_MAP); p.writeByte(animation); // expire