/// <summary>
    /// Positions the provided elements randomly inside a sphere surrounding the HQ element 
    /// in such a way that the CollisionAvoidanceZones are not in contact.
    /// </summary>
    /// <param name="radius">The radius of the sphere in units.</param>
    /// <param name="hqElement">The hq element.</param>
    /// <param name="elementsToPositionAroundHQ">The non-HQ elements to position.</param>
    /// <returns>
    ///   <c>true</c> if all elements were successfully positioned without overlap.
    /// </returns>
    private bool TryPositionRandomWithinSphere(float radius, AUnitElementItem hqElement, AUnitElementItem[] elementsToPositionAroundHQ) {
        IList<ElementSphere> allElementSpheres = new List<ElementSphere>();

        ElementSphere hqElementSphere = new ElementSphere(hqElement);
        allElementSpheres.Add(hqElementSphere);

        int iterateCount = 0;
        Vector3[] formationStationOffsets = new Vector3[elementsToPositionAroundHQ.Length];
        for (int i = 0; i < elementsToPositionAroundHQ.Length; i++) {
            Vector3 candidateStationOffset = UnityEngine.Random.insideUnitSphere * radius;
            AUnitElementItem elementCandidate = elementsToPositionAroundHQ[i];
            ElementSphere elementCandidateSphere = new ElementSphere(elementCandidate);
            elementCandidateSphere.Center = candidateStationOffset;
            if (allElementSpheres.All(es => !Intersects(es, elementCandidateSphere))) {
                // candidate doesn't intersect with any spheres already present
                allElementSpheres.Add(elementCandidateSphere);
                formationStationOffsets[i] = candidateStationOffset;
                iterateCount = Constants.Zero;
            }
            else {
                i--;
                iterateCount++;
                if (iterateCount >= 10) {    // HACK
                    D.Warn("{0}.{1} had a positioning iteration error.", _unitCmd.FullName, GetType().Name);
                    return false;
                }
            }
        }

        _unitCmd.PositionElementInFormation(hqElement, Vector3.zero);
        for (int i = 0; i < elementsToPositionAroundHQ.Length; i++) {
            _unitCmd.PositionElementInFormation(elementsToPositionAroundHQ[i], formationStationOffsets[i]);
            //elementsToPosition[i].transform.localPosition = localFormationPositions[i];   // won't work as the position of the Element's parent is arbitrary
        }
        return true;
    }
 public ElementSphere(AUnitElementItem element) {
     Center = element.Position;
     Radius = element.KeepoutZoneRadius;
 }
    /// <summary>
    /// Removes the element from the Unit.
    /// <remarks>4.19.16 Just discovered I still had asserts in place that require that the Base's HQElement die last, 
    /// a holdover from when Bases distributed damage to protect the HQ until last. I'm allowing Bases to change their
    /// HQElement if it dies now until I determine how I want Base.HQELements to operate game play wise.</remarks>
    /// </summary>
    /// <param name="element">The element.</param>
    public override void RemoveElement(AUnitElementItem element) {
        base.RemoveElement(element);

        if (!IsOperational) {
            // BaseCmd has died
            return;
        }

        var facility = element as FacilityItem;
        if (facility == HQElement) {
            // HQ Element has been removed
            HQElement = SelectHQElement();
        }
    }
 protected void Idling_UponSubordinateElementDeath(AUnitElementItem deadSubordinateElement) {
     LogEvent();
 }
Exemple #5
0
 protected virtual void HandleHQElementChanging(AUnitElementItem newHQElement) {
     Utility.ValidateNotNull(newHQElement);
     var previousHQElement = HQElement;
     if (previousHQElement != null) {
         previousHQElement.IsHQ = false;
         // don't remove previousHQElement.ShowDebugLog if ShowHQDebugLog as its probably dieing
     }
     else {
         // first assignment of HQ
         D.Assert(!IsOperational);
         // OPTIMIZE Just a FYI warning as formations currently assume this
         if (newHQElement.transform.rotation != Quaternion.identity) {
             D.Warn("{0} first HQ Element rotation = {1}.", DebugName, newHQElement.transform.rotation);
         }
     }
     if (!Elements.Contains(newHQElement)) {
         // the player will typically select/change the HQ element of a Unit from the elements already present in the unit
         D.Warn("{0} assigned HQElement {1} that is not already present in Unit.", DebugName, newHQElement.DebugName);
         AddElement(newHQElement);
     }
 }
Exemple #6
0
 private void UponSubordinateElementDeath(AUnitElementItem deadSubordinateElement) { RelayToCurrentState(deadSubordinateElement); }
Exemple #7
0
    public virtual void RemoveElement(AUnitElementItem element) {
        bool isRemoved = Elements.Remove(element);
        D.Assert(isRemoved, element.DebugName);
        Data.RemoveElement(element.Data);

        DetachSensorsFromMonitors(element.Data.Sensors);
        if (!IsOperational) {
            return; // avoid the following work if removing during startup
        }
        if (Elements.Count == Constants.Zero) {
            if (Data.UnitHealth > Constants.ZeroF) {
                D.Error("{0} has UnitHealth of {1:0.0000} remaining.", DebugName, Data.UnitHealth);
            }
            IsOperational = false;  // tell Cmd its dead
            return;
        }
        AssessIcon();
        FormationMgr.HandleElementRemoval(element);
    }
Exemple #8
0
 private void HQElementPropChangingHandler(AUnitElementItem newHQElement) {
     HandleHQElementChanging(newHQElement);
 }
Exemple #9
0
 /// <summary>
 /// Adds the Element to this Command including parenting if needed.
 /// </summary>
 /// <param name="element">The Element to add.</param>
 public virtual void AddElement(AUnitElementItem element) {
     if (Elements.Contains(element)) {
         D.Error("{0} attempting to add {1} that is already present.", DebugName, element.DebugName);
     }
     if (element.IsHQ) {
         D.Error("{0} adding element {1} already designated as the HQ Element.", DebugName, element.DebugName);
     }
     if (element.IsOperational != IsOperational) {
         D.Error("{0}: Adding element {1} with incorrect IsOperational state.", DebugName, element.DebugName);
     }
     Elements.Add(element);
     Data.AddElement(element.Data);
     element.Command = this;
     element.AttachAsChildOf(UnitContainer);
     //TODO consider changing HQElement
     var unattachedSensors = element.Data.Sensors.Where(sensor => sensor.RangeMonitor == null);
     if (unattachedSensors.Any()) {
         //D.Log(ShowDebugLog, "{0} is attaching {1}'s sensors: {2}.", DebugName, element.DebugName, unattachedSensors.Select(s => s.Name).Concatenate());
         AttachSensorsToMonitors(unattachedSensors.ToList());
         // WARNING: IEnumerable<T> lazy evaluation GOTCHA! The IEnumerable unattachedSensors at this point (after AttachSensorsToMonitors
         // completes) no longer points to any sensors as they would now all be attached. This is because the IEnumerable is not an 
         // already constructed collection. It is a pointer to a sensor that when called evaluates the sensor against the criteria. 
         // Since the Attach method modifies the sensor, the sensor being evaluated will no longer meet the unattached criteria, 
         // so unattachedSensors will no longer point to anything. Using ToList() to feed the method delivers a fully evaluated 
         // collection to the method, but this doesn't change the fact that Sensors now has no sensors that are unattached, thus 
         // the unattachedSensors IEnumerable when used again no longer points to anything.
     }
     if (!IsOperational) {
         // avoid the following extra work if adding during Cmd construction
         D.AssertNull(HQElement);    // During Cmd construction, HQElement will be designated AFTER all Elements are
         return;                         // added resulting in _formationMgr adding all elements into the formation at once
     }
     AssessIcon();
     FormationMgr.AddAndPositionNonHQElement(element);
 }
Exemple #10
0
 void AssumingFormation_UponSubordinateElementDeath(AUnitElementItem deadSubordinateElement) {
     LogEvent();
 }
Exemple #11
0
 protected override void HandleHQElementChanging(AUnitElementItem newHQElement) {
     base.HandleHQElementChanging(newHQElement);
     _navigator.HandleHQElementChanging(HQElement, newHQElement as ShipItem);
 }
Exemple #12
0
 void ExecuteAttackOrder_UponSubordinateElementDeath(AUnitElementItem deadSubordinateElement) {
     LogEvent();
 }
Exemple #13
0
    public override void RemoveElement(AUnitElementItem element) {
        base.RemoveElement(element);

        var ship = element as ShipItem;
        // Remove FS so the GC can clean it up. Also, if joining another fleet, the joined fleet will find it null 
        // when adding the ship and therefore make a new FS with the proper reference to the joined fleet
        ship.FormationStation = null;

        if (!IsOperational) {
            // fleetCmd has died
            return;
        }

        if (ship == HQElement) {
            // HQ Element has been removed
            HQElement = SelectHQElement();
        }
    }