public AbilityEvent(BitReader bitReader, Replay replay, Player player, AbilityData abilityData, UnitData unitData)
        {
            uint flags;
            //   1.3.3 patch notes:
            //   - Fixed an issue where the APM statistic could be artificially increased.
            // This adds the "failed" flag, which is triggered usually by holding down a
            // hotkey, leading to key repeat spamming the event throughout a single tick.
            if (replay.ReplayBuild < 18574) // < 1.3.3
            {
                flags = bitReader.Read(17);
            }
            else if (replay.ReplayBuild < 22612) // < 1.5.0
            {
                flags = bitReader.Read(18);
            }
            else
            {
                flags = bitReader.Read(20);
            }
            Queued = (flags & 2) != 0;
            RightClick = (flags & 8) != 0;
            WireframeClick = (flags & 0x20) != 0;
            ToggleAbility = (flags & 0x40) != 0;
            EnableAutoCast = (flags & 0x80) != 0;
            AbilityUsed = (flags & 0x100) != 0;
            WireframeUnload = (flags & 0x200) != 0;
            WireframeCancel = (flags & 0x400) != 0;
            MinimapClick = (flags & 0x10000) != 0;
            AbilityFailed = (flags & 0x20000) != 0;

            // flags & 0xf815 -> Debug for unknown flags
            // Never found any across all test data.

            DefaultAbility = (bitReader.Read(1) == 0);
            DefaultActor = true;
            if (!DefaultAbility)
            {
                AbilityType = abilityData.GetAbilityType(
                    (int)bitReader.Read(16),
                    (int)bitReader.Read(5));
                DefaultActor = (bitReader.Read(1) == 0);
                if (!DefaultActor)
                {   // I'm thinking this would be an array type... but I can't
                    // find anything that causes this bit to be set.
                    throw new InvalidOperationException("Unsupported: non-default actor");
                }
            }
            if (DefaultActor)
            {
                // Deep copy the current wireframe as the actor list
                // -----
                // If a user wants to deal with subgroups to get a more
                // concise actor list, the data is all here.  We're not
                // going to bother, though, because there are several
                // exceptions to account for in determining event actors.
                Actors = new List<Unit>(player.Wireframe.Count);
                foreach (var unit in player.Wireframe)
                {
                    Actors.Add(new Unit(unit));
                }
            }

            var targetType = bitReader.Read(2);
            if (targetType == 1) // Location target
            {
                var targetX = bitReader.Read(20);
                var targetY = bitReader.Read(20);
                var targetZ = bitReader.Read(32);
                TargetLocation = Location.FromEventFormat(targetX, targetY, targetZ);
            }
            else if (targetType == 2) // Unit + Location target
            {
                TargetFlags = (int)bitReader.Read(8);
                WireframeIndex = (int)bitReader.Read(8);

                var unitId = (int)bitReader.Read(32);
                var unit = replay.GetUnitById(unitId);
                var unitTypeId = (int)bitReader.Read(16);
                if (unit == null)
                {
                    var unitType = unitData.GetUnitType(unitTypeId);
                    unit = new Unit(unitId, unitType);
                    unit.typeId = unitTypeId;
                    replay.GameUnits.Add(unitId, unit);
                }

                TargetUnit = unit;

                var targetHasPlayer = bitReader.Read(1) == 1;
                if (targetHasPlayer)
                {
                    TargetPlayer = (int)bitReader.Read(4);
                }

                // 1.4.0 -- Don't really know what this was meant to fix
                if (replay.ReplayBuild >= 19595)
                {
                    var targetHasTeam = bitReader.Read(1) == 1;
                    if (targetHasTeam)
                    {
                        TargetTeam = (int)bitReader.Read(4);
                    }
                }

                var targetX = bitReader.Read(20);
                var targetY = bitReader.Read(20);
                var targetZ = bitReader.Read(32);
                TargetLocation = Location.FromEventFormat(targetX, targetY, targetZ);
            }
            else if (targetType == 3) // Unit target
            {
                var id = bitReader.Read(32);
                // Again, if the user wants to determine exactly which
                // queue item is canceled in the case of a queue cancel
                // event (the most common case of this target specifier's
                // occurence), they can; however, it requires an additional
                // data structure that I don't want to bother with; however,
                // all the underlying data is available in the events list.
                TargetId = id;
            }

            var lastBit = bitReader.Read(1); // Should be 0; if not, misalignment is likely

            if (!AbilityFailed)
            {
                if (RightClick)
                {
                    this.EventType = GameEventType.RightClick;
                }
                else
                {
                    this.EventType = EventData.GetInstance().GetEventType(this.AbilityType);
                }
            }
            else
            {
                this.EventType = GameEventType.Inactive;
            }
        }
Example #2
0
 /// <summary>
 /// Copy constructor
 /// </summary>
 public Unit(Unit u)
 {
     this.id = u.id;
     this.type = u.type;
     this.typeId = u.typeId;
 }
        /// <summary>
        /// Reads the 8 {16, 8, 8}, 8 {32} struct; the result is in AddedUnits / AddedUnitTypes.
        /// </summary>
        void HandleUnitArrays(BitReader bitReader, Replay replay, UnitData data)
        {
            int wireframeLength = 8;
            if (replay.ReplayBuild >= 22612)
            {
                wireframeLength = 9; // Maximum selection size has been increased to 500, up from 255.
            }

            var typesLength = (int)bitReader.Read(wireframeLength);
            AddedUnitTypes = new Dictionary<UnitType, int>(typesLength);

            // Guarantee order is maintained
            var subgroups = new List<KeyValuePair<UnitType, int>>(typesLength);

            for (int i = 0; i < typesLength; i++)
            {
                var unitTypeId = (int)bitReader.Read(16);
                var unitType = data.GetUnitType(unitTypeId);

                var unitSubtype = bitReader.Read(8);
                if (unitSubtype == 2) // hallucination -- cheers, Graylin
                {
                    unitType = data.GetHallucination(unitType);
                }

                var unitCountType = (int)bitReader.Read(wireframeLength);
                if (unitType == UnitType.Unknown && AddedUnitTypes.ContainsKey(UnitType.Unknown))
                {
                    AddedUnitTypes[UnitType.Unknown] += unitCountType;
                }
                else
                {
                    AddedUnitTypes.Add(unitType, unitCountType);
                }
                subgroups.Add(new KeyValuePair<UnitType, int>(unitType, unitCountType));
            }

            var idsLength = (int)bitReader.Read(wireframeLength);
            AddedUnits = AddedUnits ?? new List<Unit>(idsLength);
            if (idsLength == 0) return;

            var subgroupsEnumerator = subgroups.GetEnumerator();

            int currentSubgroupIndex;
            if (subgroupsEnumerator.MoveNext())
            {
                currentSubgroupIndex = subgroupsEnumerator.Current.Value;
            }
            else return;

            for (int i = 0; i < idsLength; i++)
            {
                var unitId = (int)bitReader.Read(32);
                var unit = replay.GetUnitById(unitId);
                var unitType = subgroupsEnumerator.Current.Key;
                if (unit == null)
                {
                    unit = new Unit(unitId, unitType);
                    replay.GameUnits.Add(unitId, unit);
                }
                else
                {
                    unit.UpdateType(unitType);
                }
                AddedUnits.Add(unit);

                if (--currentSubgroupIndex <= 0)
                {
                    if (subgroupsEnumerator.MoveNext())
                    {
                        currentSubgroupIndex = subgroupsEnumerator.Current.Value;
                    }
                }
            }
        }