/// <summary> /// Broadcasts CombatActionPack in range of pack's attacker. /// </summary> /// <param name="pack"></param> public static void CombatAction(CombatActionPack pack) { var attackerPos = pack.Attacker.GetPosition(); var packet = new Packet(Op.CombatActionPack, MabiId.Broadcast); packet.PutInt(pack.Id); packet.PutInt(pack.PrevId); packet.PutByte(pack.Hit); packet.PutByte((byte)pack.Type); packet.PutByte(pack.Flags); if ((pack.Flags & 1) == 1) { packet.PutInt(pack.BlockedByShieldPosX); packet.PutInt(pack.BlockedByShieldPosY); packet.PutLong(pack.ShieldCasterId); } // Actions packet.PutInt(pack.Actions.Count); Packet actionPacket = null; foreach (var action in pack.Actions) { var pos = action.Creature.GetPosition(); if (actionPacket == null) actionPacket = new Packet(Op.CombatAction, action.Creature.EntityId); else actionPacket.Clear(Op.CombatAction, action.Creature.EntityId); actionPacket.PutInt(pack.Id); actionPacket.PutLong(action.Creature.EntityId); actionPacket.PutByte((byte)action.Flags); actionPacket.PutShort(action.Stun); actionPacket.PutUShort((ushort)action.SkillId); actionPacket.PutUShort((ushort)action.SecondarySkillId); // Official name for CombatAction is CombatScene, and both Actions are Combatant. // Official client distinguish between Attacker and Defender simply by checking Flags. tachiorz // AttackerAction //if ((action.Flags & CombatActionFlags.Attacker) != 0) if (action.Category == CombatActionCategory.Attack) { var aAction = action as AttackerAction; actionPacket.PutLong(aAction.TargetId); actionPacket.PutUInt((uint)aAction.Options); actionPacket.PutByte(aAction.UsedWeaponSet); actionPacket.PutByte(aAction.WeaponParameterType); // !aAction.Has(AttackerOptions.KnockBackHit2) ? 2 : 1)); // ? actionPacket.PutInt(pos.X); actionPacket.PutInt(pos.Y); if ((aAction.Options & AttackerOptions.Dashed) != 0) { actionPacket.PutFloat(0); // DashedPosX actionPacket.PutFloat(0); // DashedPosY actionPacket.PutUInt(0); // DashDelay } if ((aAction.Options & AttackerOptions.PhaseAttack) != 0) actionPacket.PutByte(aAction.Phase); if ((aAction.Options & AttackerOptions.UseEffect) != 0) actionPacket.PutLong(aAction.PropId); } // TargetAction //if ((action.Flags & CombatActionFlags.TakeHit) != 0) else if (action.Category == CombatActionCategory.Target && !action.Is(CombatActionType.None)) { var tAction = action as TargetAction; // Target used Defense or Counter if ((action.Flags & CombatActionType.Attacker) != 0) { actionPacket.PutLong(tAction.Attacker.EntityId); actionPacket.PutInt(0); // attacker Options actionPacket.PutByte(tAction.UsedWeaponSet); actionPacket.PutByte(tAction.WeaponParameterType); actionPacket.PutInt(pos.X); actionPacket.PutInt(pos.Y); } actionPacket.PutUInt((uint)tAction.Options); actionPacket.PutFloat(tAction.Damage); actionPacket.PutFloat(tAction.Wound); actionPacket.PutInt((int)tAction.ManaDamage); actionPacket.PutFloat(attackerPos.X - pos.X); actionPacket.PutFloat(attackerPos.Y - pos.Y); if (tAction.IsKnockBack) { actionPacket.PutFloat(pos.X); actionPacket.PutFloat(pos.Y); // [190200, NA203 (22.04.2015)] { actionPacket.PutInt(0); } } if ((tAction.Options & TargetOptions.MultiHit) != 0) { actionPacket.PutUInt(0); // MultiHitDamageCount actionPacket.PutUInt(0); // MultiHitDamageShowTime } actionPacket.PutByte((byte)tAction.EffectFlags); actionPacket.PutInt(tAction.Delay); actionPacket.PutLong(tAction.Attacker.EntityId); } packet.PutBin(actionPacket); } pack.Attacker.Region.Broadcast(packet, pack.Attacker); }
/// <summary> /// Broadcasts CombatActionPack in range of pack's attacker. /// </summary> /// <param name="pack"></param> public static void CombatAction(CombatActionPack pack) { var attackerPos = pack.Attacker.GetPosition(); var packet = new Packet(Op.CombatActionPack, MabiId.Broadcast); packet.PutInt(pack.Id); packet.PutInt(pack.PrevId); packet.PutByte(pack.Hit); packet.PutByte(pack.MaxHits); packet.PutByte(0); // Actions packet.PutInt(pack.Actions.Count); Packet actionPacket = null; foreach (var action in pack.Actions) { var pos = action.Creature.GetPosition(); if (actionPacket == null) actionPacket = new Packet(Op.CombatAction, action.Creature.EntityId); else actionPacket.Clear(Op.CombatAction, action.Creature.EntityId); actionPacket.PutInt(pack.Id); actionPacket.PutLong(action.Creature.EntityId); actionPacket.PutByte((byte)action.Type); actionPacket.PutShort(action.Stun); actionPacket.PutUShort((ushort)action.SkillId); actionPacket.PutShort(0); // AttackerAction if (action.Category == CombatActionCategory.Attack) { var aAction = action as AttackerAction; actionPacket.PutLong(aAction.TargetId); actionPacket.PutUInt((uint)aAction.Options); actionPacket.PutByte(0); actionPacket.PutByte((byte)(!aAction.Has(AttackerOptions.KnockBackHit2) ? 2 : 1)); // ? actionPacket.PutInt(pos.X); actionPacket.PutInt(pos.Y); if (aAction.PropId != 0) actionPacket.PutLong(aAction.PropId); } // TargetAction else if (action.Category == CombatActionCategory.Target && !action.Is(CombatActionType.None)) { var tAction = action as TargetAction; // Target used Defense or Counter if (tAction.Is(CombatActionType.Defended) || tAction.Is(CombatActionType.CounteredHit) || tAction.Is(CombatActionType.CounteredHit2)) { actionPacket.PutLong(tAction.Attacker.EntityId); actionPacket.PutInt(0); actionPacket.PutByte(0); actionPacket.PutByte(1); actionPacket.PutInt(pos.X); actionPacket.PutInt(pos.Y); } actionPacket.PutUInt((uint)tAction.Options); actionPacket.PutFloat(tAction.Damage); actionPacket.PutFloat(0); // Related to mana damage? actionPacket.PutInt((int)tAction.ManaDamage); actionPacket.PutFloat(attackerPos.X - pos.X); actionPacket.PutFloat(attackerPos.Y - pos.Y); if (tAction.IsKnockBack) { actionPacket.PutFloat(pos.X); actionPacket.PutFloat(pos.Y); // [190200, NA203 (22.04.2015)] { actionPacket.PutInt(0); } } actionPacket.PutByte(0); // PDef? Seen as 0x20 in a normal attack (G18) actionPacket.PutInt(tAction.Delay); actionPacket.PutLong(tAction.Attacker.EntityId); } packet.PutBin(actionPacket); } pack.Attacker.Region.Broadcast(packet, pack.Attacker); }