public void AttackMonster(int damage, byte speed, MapleMonster monster) { AttackInfo info = new AttackInfo(); info.Attacks = 1; info.Targets = 1; info.AttacksByte = 0x11; info.Speed = speed; AttackPair attackPair = new AttackPair(); attackPair.TargetObjectId = monster.ObjectId; attackPair.Damage = new List <int>() { damage }; info.TargetDamageList = new List <AttackPair>() { attackPair }; Owner.Map.BroadcastPacket(GetAttackPacket(info, true)); monster.Damage(Owner, damage); }
public static void HandleAttack(MapleClient c, PacketReader pr) { int objectId = pr.ReadInt(); MapleCharacter chr = c.Account.Character; MapleSummon summon = chr.Map.GetSummon(objectId); if (summon != null) { if (summon.Owner.Id != chr.Id) { return; } int tickCount = pr.ReadInt(); WzCharacterSkill skillInfo = DataBuffer.GetCharacterSkillById(summon.SourceSkillId); if (skillInfo == null || skillInfo.SummonInfo == null) { return; } WzCharacterSkill.SummonAttackInfo summonAttackInfo = skillInfo.SummonInfo; byte animation = pr.ReadByte(); byte attackByte = pr.ReadByte(); int attacks = (attackByte & 0x0F); int targets = ((attackByte >> 4) & 0x0F); if (summonAttackInfo.MobCount < targets || summonAttackInfo.AttackCount < attacks) { ServerConsole.Warning("Player " + chr.Name + "'s summon: " + summon.SourceSkillId + "has mismatching targets- or attackcount: " + attacks + "/" + summonAttackInfo.AttackCount + " attacks, " + targets + "/" + summonAttackInfo.MobCount + " mobs"); return; } pr.Skip(12); List <AttackPair> attackList = new List <AttackPair>(); for (int i = 0; i < targets; i++) { int targetObjectId = pr.ReadInt(); MapleMonster target = chr.Map.GetMob(targetObjectId); if (target == null) { ServerConsole.Debug("Error parsing summon attack, summon skillId: " + summon.SourceSkillId + " attack byte: " + attackByte); return; } AttackPair ap = new AttackPair(); ap.TargetObjectId = targetObjectId; pr.Skip(24); int damage = pr.ReadInt(); //only supports 1 damage count, not sure if there are summons with attackcount > 1 ap.Damage.Add(damage); attackList.Add(ap); pr.Skip(4); } AttackInfo attackInfo = new AttackInfo(); attackInfo.Attacks = attacks; attackInfo.AttacksByte = attackByte; attackInfo.Speed = animation; attackInfo.Targets = targets; attackInfo.TargetDamageList = attackList; foreach (AttackPair ap in attackList) { MapleMonster mob = chr.Map.GetMob(ap.TargetObjectId); if (mob != null) { long totalDamage = 0; foreach (int i in ap.Damage) { totalDamage += i; } if (totalDamage > int.MaxValue) { totalDamage = int.MaxValue; } mob.Damage(chr, (int)totalDamage); } } bool darkFlare = summon.SourceSkillId == ChiefBandit.DARK_FLARE || summon.SourceSkillId == Hermit.DARK_FLARE || summon.SourceSkillId == NightWalker3.DARK_FLARE; chr.Map.BroadcastPacket(summon.GetAttackPacket(attackInfo, darkFlare)); } }
private static void HandleAttackInfo(MapleClient c, AttackInfo attackInfo, SendHeader type, SkillEffect effect) { //Anti-cheat //c.CheatTracker.Trigger(AntiCheat.TriggerType.Attack); WzCharacterSkill wzSkill = effect != null ? effect.Parent : null; MapleCharacter chr = c.Account.Character; if (attackInfo.SkillId > 0) { if (!SkillEffect.CheckAndApplySkillEffect(c.Account.Character, attackInfo.SkillId, wzSkill, -1, attackInfo.Targets, attackInfo.Attacks)) { return; } } chr.Map.BroadcastPacket(GenerateAttackInfo(type, c.Account.Character, attackInfo), c.Account.Character, false); long totalDamage = 0; #region DoTs and Pickpocket int pickPocketProp = 0; int dotSkillId = 0; int dotChance = 0; int dotDamage = 0; int dotTimeMS = 0; int dotMaxStacks = 1; #region Thief if (chr.IsThief) { byte venomSkillLevel = 0; if (chr.IsBandit) { Buff pickPocket = chr.GetBuff(ChiefBandit.PICKPOCKET); if (pickPocket != null) { pickPocketProp = pickPocket.Effect.Info[CharacterSkillStat.prop]; } venomSkillLevel = chr.GetSkillLevel(ChiefBandit.VENOM); if (venomSkillLevel > 0) { dotSkillId = ChiefBandit.VENOM; byte toxicVenomSkillLevel = chr.GetSkillLevel(Shadower.TOXIC_VENOM); if (toxicVenomSkillLevel > 0) { venomSkillLevel = toxicVenomSkillLevel; dotSkillId = Shadower.TOXIC_VENOM; } } } else if (chr.IsAssassin) { #region Assassin venomSkillLevel = chr.GetSkillLevel(Hermit.VENOM); if (venomSkillLevel > 0) { dotSkillId = Hermit.VENOM; byte toxicVenomSkillLevel = chr.GetSkillLevel(NightLord.TOXIC_VENOM); if (toxicVenomSkillLevel > 0) { venomSkillLevel = toxicVenomSkillLevel; dotSkillId = NightLord.TOXIC_VENOM; } } #endregion } else if (chr.IsDualBlade) { #region DualBlade venomSkillLevel = chr.GetSkillLevel(DualBlade3.VENOM); if (venomSkillLevel > 0) { dotSkillId = DualBlade3.VENOM; byte toxicVenomSkillLevel = chr.GetSkillLevel(DualBlade4.TOXIC_VENOM); if (toxicVenomSkillLevel > 0) { venomSkillLevel = toxicVenomSkillLevel; dotSkillId = DualBlade4.TOXIC_VENOM; } } #endregion } if (venomSkillLevel > 0) { SkillEffect venomEffect = DataBuffer.GetCharacterSkillById(dotSkillId).GetEffect(venomSkillLevel); dotChance = venomEffect.Info[CharacterSkillStat.prop]; dotDamage = (int)(chr.Stats.GetDamage() * (venomEffect.Info[CharacterSkillStat.dot] / 100.0)); dotTimeMS = venomEffect.Info[CharacterSkillStat.dotTime] * 1000; if (!venomEffect.Info.TryGetValue(CharacterSkillStat.dotSuperpos, out dotMaxStacks)) { dotMaxStacks = 1; } } } #endregion if (attackInfo.SkillId > 0 && effect.Info.TryGetValue(CharacterSkillStat.dot, out dotDamage)) //Skill has/is dot { dotTimeMS = effect.Info[CharacterSkillStat.dotTime] * 1000; if (!effect.Info.TryGetValue(CharacterSkillStat.prop, out dotChance)) { dotChance = 100; } dotSkillId = attackInfo.SkillId; dotDamage = (int)(chr.Stats.GetDamage() * (dotDamage / 100.0)); if (!effect.Info.TryGetValue(CharacterSkillStat.dotSuperpos, out dotMaxStacks)) { dotMaxStacks = 1; } } #endregion foreach (AttackPair ap in attackInfo.TargetDamageList) { MapleMonster mob = chr.Map.GetMob(ap.TargetObjectId); if (mob != null && mob.Alive) { long totalMobDamage = 0; foreach (int damage in ap.Damage) { totalMobDamage += damage; } if (totalMobDamage > 0) { totalDamage += totalMobDamage; if (totalDamage > int.MaxValue) { totalDamage = int.MaxValue; } #region Status effects if (effect != null) { foreach (MonsterBuffApplication mba in effect.MonsterBuffs) { if (Functions.MakeChance(mba.Prop)) { foreach (var kvp in mba.Buffs) { mob.ApplyStatusEffect(attackInfo.SkillId, kvp.Key, kvp.Value, mba.Duration, chr); } } } } #endregion #region MP Eater if (chr.Stats.MpEaterProp > 0) { if (Functions.MakeChance(chr.Stats.MpEaterProp)) { int mpSteal = (int)((chr.Stats.MpEaterR / 100.0) * mob.WzInfo.MP); chr.AddMP(mpSteal); } } #endregion #region Bandit if (chr.IsBandit) { if (Functions.MakeChance(pickPocketProp)) { chr.Map.SpawnMesoMapItem(1, mob.Position, chr.Map.GetDropPositionBelow(mob.Position, mob.Position), false, MapleDropType.Player, chr); } if (attackInfo.SkillId == Bandit.STEAL) { int prop = DataBuffer.GetCharacterSkillById(Bandit.STEAL).GetEffect(chr.GetSkillLevel(Bandit.STEAL)).Info[CharacterSkillStat.prop]; if (Functions.MakeChance(prop)) { MapleItem item = mob.TryGetStealableItem(chr.Id, chr.Name); if (item != null) { chr.Map.SpawnMapItem(item, mob.Position, chr.Map.GetDropPositionBelow(chr.Position, mob.Position), false, Map.MapleDropType.Player, chr); } } } } #endregion if (Functions.MakeChance(dotChance)) { mob.ApplyPoison(dotSkillId, dotTimeMS, dotDamage, 1000, chr, dotMaxStacks); } mob.Damage(chr, (int)totalDamage); } } } #region special skill handling if (type == SendHeader.RangedAttack) { if (attackInfo.Targets > 0 && chr.IsHunter) { #region QuiverCartridge QuiverCartridgeSystem qcs = chr.Resource as QuiverCartridgeSystem; if (qcs != null && qcs.ChosenArrow > -1) { int usedArrow = qcs.HandleUse(c); switch (usedArrow) { case 0: // Blood if (Functions.MakeChance(50)) //50% chance to heal 20% of damage as hp { chr.AddHP((int)(totalDamage * 0.2)); } break; case 1: // Poison //TODO: poison, 90% damage, 8 seconds, stacks 3 times break; case 2: // Magic, don't need handling I think break; } } #endregion } } if (totalDamage > 0) { BuffedCharacterStats stats = chr.Stats; if (stats.LifeStealProp > 0 && stats.LifeStealR > 0) { if (Functions.MakeChance(stats.LifeStealProp)) { int lifesteal = (int)((stats.LifeStealR / 100.0) * totalDamage); chr.AddHP(lifesteal); } } if (chr.IsMagician) { #region ArcaneAim int arcaneAimId = 0; if (chr.Job == JobConstants.FIREPOISON4) { arcaneAimId = FirePoison4.ARCANE_AIM; } else if (chr.Job == JobConstants.ICELIGHTNING4) { arcaneAimId = IceLightning4.ARCANE_AIM; } else if (chr.Job == JobConstants.BISHOP) { arcaneAimId = Bishop.ARCANE_AIM; } if (arcaneAimId > 0) { byte skillLevel = chr.GetSkillLevel(arcaneAimId); if (skillLevel > 0) { if ((DateTime.UtcNow.Subtract(chr.LastAttackTime).TotalMilliseconds) < 5000) { Buff oldBuff = chr.GetBuff(arcaneAimId); if (oldBuff != null) { int prop = oldBuff.Effect.Info[CharacterSkillStat.prop]; if (Functions.MakeChance(prop)) { Buff newBuff = new Buff(arcaneAimId, oldBuff.Effect, oldBuff.Duration, chr); int oldStacks = oldBuff.Stacks / 6; newBuff.Stacks = Math.Min(30, (oldStacks + 1) * 6); chr.GiveBuff(newBuff); } } else { SkillEffect arcaneAimEffect = DataBuffer.GetCharacterSkillById(arcaneAimId).GetEffect(skillLevel); int prop = arcaneAimEffect.Info[CharacterSkillStat.prop]; if (Functions.MakeChance(prop)) { Buff newBuff = new Buff(arcaneAimId, arcaneAimEffect, 5000, chr); newBuff.Stacks = 6; chr.GiveBuff(newBuff); } } } } } #endregion } else if (chr.IsThief) { if (chr.IsBandit) { chr.IncreaseCriticalGrowth(true); byte skillLevel = chr.GetSkillLevel(Shadower.SHADOWER_INSTINCT); if (skillLevel > 0) { ((BodyCountSystem)chr.Resource).IncreaseBodyCount(c); } } } } #endregion chr.LastAttackTime = DateTime.UtcNow; }