using System.Buffers.Binary; namespace AcDream.Core.Net.Messages; /// /// Outbound combat attack GameActions. /// /// Retail/ACE use distinct payloads for melee and missile: /// /// /// u32 0xF7B1 // GameAction envelope opcode /// u32 gameActionSequence // client sequence /// u32 0x0008 // TargetedMeleeAttack /// u32 targetGuid /// u32 attackHeight // 1=High, 2=Medium, 3=Low /// f32 powerLevel // [0.0, 1.0] /// /// u32 0xF7B1 /// u32 gameActionSequence /// u32 0x000A // TargetedMissileAttack /// u32 targetGuid /// u32 attackHeight /// f32 accuracyLevel // [0.0, 1.0] /// /// /// References: CM_Combat::Event_TargetedMeleeAttack 0x006A9C10, /// CM_Combat::Event_TargetedMissileAttack 0x006A9D60, ACE /// GameActionTargetedMeleeAttack/GameActionTargetedMissileAttack, and /// holtburger protocol game_action.rs. /// public static class AttackTargetRequest { public const uint GameActionEnvelope = 0xF7B1u; public const uint TargetedMeleeAttackOpcode = 0x0008u; public const uint TargetedMissileAttackOpcode = 0x000Au; public const uint CancelAttackOpcode = 0x01B7u; /// Build the wire body for a targeted melee attack. public static byte[] BuildMelee( uint gameActionSequence, uint targetGuid, uint attackHeight, float powerLevel) { byte[] body = new byte[24]; BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), gameActionSequence); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), TargetedMeleeAttackOpcode); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), targetGuid); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(16), attackHeight); BinaryPrimitives.WriteSingleLittleEndian(body.AsSpan(20), powerLevel); return body; } /// Build the wire body for a targeted missile attack. public static byte[] BuildMissile( uint gameActionSequence, uint targetGuid, uint attackHeight, float accuracyLevel) { byte[] body = new byte[24]; BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), gameActionSequence); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), TargetedMissileAttackOpcode); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), targetGuid); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(16), attackHeight); BinaryPrimitives.WriteSingleLittleEndian(body.AsSpan(20), accuracyLevel); return body; } /// Build the wire body for cancelling an active attack request. public static byte[] BuildCancel(uint gameActionSequence) { byte[] body = new byte[12]; BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), gameActionSequence); BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(8), CancelAttackOpcode); return body; } }