Exemple #1
0
    // Call()ed State

    #region Attacking Support Members

    private AutoPilotDestinationProxy MakePilotAttackTgtProxy(IShipAttackable attackTgt) {
        RangeDistance weapRange = Data.WeaponsRange;
        D.Assert(weapRange.Max > Constants.ZeroF);
        ShipCombatStance combatStance = Data.CombatStance;
        D.AssertNotEqual(ShipCombatStance.Disengage, combatStance);
        D.AssertNotEqual(ShipCombatStance.Defensive, combatStance);

        float maxRangeToTgtSurface = Constants.ZeroF;
        float minRangeToTgtSurface = Constants.ZeroF;
        bool hasOperatingLRWeapons = weapRange.Long > Constants.ZeroF;
        bool hasOperatingMRWeapons = weapRange.Medium > Constants.ZeroF;
        bool hasOperatingSRWeapons = weapRange.Short > Constants.ZeroF;
        float weapRangeMultiplier = Owner.WeaponRangeMultiplier;
        switch (combatStance) {
            case ShipCombatStance.Standoff:
                if (hasOperatingLRWeapons) {
                    maxRangeToTgtSurface = weapRange.Long;
                    minRangeToTgtSurface = RangeCategory.Medium.GetBaselineWeaponRange() * weapRangeMultiplier;
                }
                else if (hasOperatingMRWeapons) {
                    maxRangeToTgtSurface = weapRange.Medium;
                    minRangeToTgtSurface = RangeCategory.Short.GetBaselineWeaponRange() * weapRangeMultiplier;
                }
                else {
                    D.Assert(hasOperatingSRWeapons);
                    maxRangeToTgtSurface = weapRange.Short;
                    minRangeToTgtSurface = Constants.ZeroF;
                }
                break;
            case ShipCombatStance.Balanced:
                if (hasOperatingMRWeapons) {
                    maxRangeToTgtSurface = weapRange.Medium;
                    minRangeToTgtSurface = RangeCategory.Short.GetBaselineWeaponRange() * weapRangeMultiplier;
                }
                else if (hasOperatingLRWeapons) {
                    maxRangeToTgtSurface = weapRange.Long;
                    minRangeToTgtSurface = RangeCategory.Medium.GetBaselineWeaponRange() * weapRangeMultiplier;
                }
                else {
                    D.Assert(hasOperatingSRWeapons);
                    maxRangeToTgtSurface = weapRange.Short;
                    minRangeToTgtSurface = Constants.ZeroF;
                }
                break;
            case ShipCombatStance.PointBlank:
                if (hasOperatingSRWeapons) {
                    maxRangeToTgtSurface = weapRange.Short;
                    minRangeToTgtSurface = Constants.ZeroF;
                }
                else if (hasOperatingMRWeapons) {
                    maxRangeToTgtSurface = weapRange.Medium;
                    minRangeToTgtSurface = RangeCategory.Short.GetBaselineWeaponRange() * weapRangeMultiplier;
                }
                else {
                    D.Assert(hasOperatingLRWeapons);
                    maxRangeToTgtSurface = weapRange.Long;
                    minRangeToTgtSurface = RangeCategory.Medium.GetBaselineWeaponRange() * weapRangeMultiplier;
                }
                break;
            case ShipCombatStance.Defensive:
            case ShipCombatStance.Disengage:
            case ShipCombatStance.None:
            default:
                throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(combatStance));
        }

        minRangeToTgtSurface = Mathf.Max(minRangeToTgtSurface, CollisionDetectionZoneRadius);
        D.Assert(maxRangeToTgtSurface > minRangeToTgtSurface);
        return attackTgt.GetApAttackTgtProxy(minRangeToTgtSurface, maxRangeToTgtSurface);
    }
Exemple #2
0
    // 4.22.16: Currently Order is issued only by user or fleet. Once HQ has arrived at the IUnitAttackable target, 
    // individual ships can still be a long way off trying to get there. In addition, the element a ship picks as its
    // primary target could also be a long way off so we need to rely on the AutoPilot to manage speed.

    #region ExecuteAttackOrder Support Members

    /// <summary>
    /// Tries to pick a primary target for the ship derived from the provided UnitTarget. Returns <c>true</c> if an acceptable
    /// target belonging to unitAttackTgt is found within SensorRange and the ship decides to attack, <c>false</c> otherwise.
    /// A ship can decide not to attack even if it finds an acceptable target - e.g. it has no currently operational weapons.
    /// </summary>
    /// <param name="unitAttackTgt">The unit target to Attack.</param>
    /// <param name="allowLogging">if set to <c>true</c> [allow logging].</param>
    /// <param name="shipPrimaryAttackTgt">The ship's primary attack target. Will be null when returning false.</param>
    /// <returns></returns>
    private bool TryPickPrimaryAttackTgt(IUnitAttackable unitAttackTgt, bool allowLogging, out IShipAttackable shipPrimaryAttackTgt) {
        D.AssertNotNull(unitAttackTgt);
        if (!unitAttackTgt.IsOperational) {
            D.Error("{0}'s unit attack target {1} is dead.", DebugName, unitAttackTgt.DebugName);
        }
        D.AssertNotEqual(ShipCombatStance.Defensive, Data.CombatStance);
        D.AssertNotEqual(ShipCombatStance.Disengage, Data.CombatStance);

        if (Data.WeaponsRange.Max == Constants.ZeroF) {
            if (ShowDebugLog && allowLogging) {
                D.Log("{0} is declining to engage with target {1} as it has no operational weapons.", DebugName, unitAttackTgt.DebugName);
            }
            shipPrimaryAttackTgt = null;
            return false;
        }

        var uniqueEnemyTargetsInSensorRange = Enumerable.Empty<IShipAttackable>();
        Command.SensorRangeMonitors.ForAll(srm => {
            var attackableEnemyTgtsDetected = srm.EnemyTargetsDetected.Cast<IShipAttackable>();
            uniqueEnemyTargetsInSensorRange = uniqueEnemyTargetsInSensorRange.Union(attackableEnemyTgtsDetected);
        });

        IShipAttackable primaryTgt = null;
        var cmdTarget = unitAttackTgt as AUnitCmdItem;
        if (cmdTarget != null) {
            var primaryTargets = cmdTarget.Elements.Cast<IShipAttackable>();
            var primaryTargetsInSensorRange = primaryTargets.Intersect(uniqueEnemyTargetsInSensorRange);
            if (primaryTargetsInSensorRange.Any()) {
                primaryTgt = __SelectHighestPriorityAttackTgt(primaryTargetsInSensorRange);
            }
        }
        else {
            // Planetoid
            var planetoidTarget = unitAttackTgt as APlanetoidItem;
            D.AssertNotNull(planetoidTarget);

            if (uniqueEnemyTargetsInSensorRange.Contains(planetoidTarget)) {
                primaryTgt = planetoidTarget;
            }
        }
        if (primaryTgt == null) {
            if (allowLogging) {
                D.Warn("{0} found no target within sensor range to attack!", DebugName); // UNCLEAR how this could happen. Sensors damaged?
            }
            shipPrimaryAttackTgt = null;
            return false;
        }

        shipPrimaryAttackTgt = primaryTgt;
        return true;
    }