public SystemCreatorConfiguration(string systemName, string starDesignName, OrbitData settlementOrbitSlot, IList<string> planetDesignNames,
     IList<OrbitData> planetOrbitSlots, IList<string[]> moonDesignNames, IList<OrbitData[]> moonOrbitSlots) {
     SystemName = systemName;
     StarDesignName = starDesignName;
     SettlementOrbitSlot = settlementOrbitSlot;
     PlanetDesignNames = planetDesignNames;
     PlanetOrbitSlots = planetOrbitSlots;
     MoonDesignNames = moonDesignNames;
     MoonOrbitSlots = moonOrbitSlots;
 }
    /// <summary>
    /// Generates an ordered array of all CelestialOrbitSlots in the system. The first slot (index = 0) is the closest to the star, just outside
    /// the star's CloseOrbitOuterRadius.
    /// Note: These are system orbit slots that can be occupied by planets and settlements.
    /// </summary>
    /// <returns></returns>
    private void GenerateSystemOrbitSlots(float sysOrbitSlotsStartRadius, out Stack<OrbitData> innerSlots, out Stack<OrbitData> goldilocksSlots, out Stack<OrbitData> outerSlots) {
        float systemRadiusAvailableForAllOrbits = TempGameValues.SystemRadius - sysOrbitSlotsStartRadius;
        __systemOrbitSlotDepth = systemRadiusAvailableForAllOrbits / (float)TempGameValues.TotalOrbitSlotsPerSystem;
        //D.Log(ShowDebugLog, "{0}: SystemOrbitSlotDepth = {1:0.#}.", DebugName, _systemOrbitSlotDepth);

        innerSlots = new Stack<OrbitData>(1);
        goldilocksSlots = new Stack<OrbitData>(3);
        outerSlots = new Stack<OrbitData>(2);

        for (int slotIndex = 0; slotIndex < TempGameValues.TotalOrbitSlotsPerSystem; slotIndex++) {
            float insideRadius = sysOrbitSlotsStartRadius + __systemOrbitSlotDepth * slotIndex;
            float outsideRadius = insideRadius + __systemOrbitSlotDepth;
            var orbitPeriod = _minSystemOrbitPeriod + (slotIndex * _systemOrbitPeriodIncrement);
            //D.Log(ShowDebugLog, "{0}: Orbit slot index {1} OrbitPeriod = {2}.", DebugName, slotIndex, orbitPeriod);
            OrbitData slot = new OrbitData(slotIndex, insideRadius, outsideRadius, orbitPeriod);

            switch (slotIndex) {
                case 0:
                    innerSlots.Push(slot);
                    break;
                case 1:
                case 2:
                case 3:
                    goldilocksSlots.Push(slot);
                    break;
                case 4:
                case 5:
                    outerSlots.Push(slot);
                    break;
                default:
                    throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(slotIndex));
            }
        }
        innerSlots.Shuffle();
        goldilocksSlots.Shuffle();
        outerSlots.Shuffle();
    }
 private bool TryFindOrbitSlot(Stack<OrbitData>[] slotStacks, out OrbitData slot) {
     foreach (var slotStack in slotStacks) {
         if (slotStack.Count > 0) {
             slot = slotStack.Pop();
             return true;
         }
     }
     slot = null;
     return false;
 }
 private bool TryAssignPlanetOrbitSlot(PlanetoidCategory pCat, Stack<OrbitData> innerSlots, Stack<OrbitData> goldilocksSlots, Stack<OrbitData> outerSlots, out OrbitData assignedSlot) {
     Stack<OrbitData>[] slots;
     switch (pCat) {
         case PlanetoidCategory.Volcanic:
             slots = new Stack<OrbitData>[] { innerSlots, goldilocksSlots };
             break;
         case PlanetoidCategory.Terrestrial:
             slots = new Stack<OrbitData>[] { goldilocksSlots, innerSlots, outerSlots };
             break;
         case PlanetoidCategory.Ice:
             slots = new Stack<OrbitData>[] { outerSlots, goldilocksSlots };
             break;
         case PlanetoidCategory.GasGiant:
             slots = new Stack<OrbitData>[] { outerSlots, goldilocksSlots };
             break;
         case PlanetoidCategory.Moon_001:
         case PlanetoidCategory.Moon_002:
         case PlanetoidCategory.Moon_003:
         case PlanetoidCategory.Moon_004:
         case PlanetoidCategory.Moon_005:
         case PlanetoidCategory.None:
         default:
             throw new NotImplementedException(ErrorMessages.UnanticipatedSwitchValue.Inject(pCat));
     }
     return TryFindOrbitSlot(slots, out assignedSlot);
 }
 private bool TryAssignMoonOrbitSlot(PlanetoidCategory mCat, int slotIndex, float startDepthForOrbitSlot, out OrbitData assignedSlot) {
     float depthAvailableForMoonOrbitsAroundPlanet = __systemOrbitSlotDepth;
     float moonObstacleZoneRadius = mCat.Radius() + TempGameValues.MoonObstacleZoneRadiusAdder;
     float depthReqdForOrbitSlot = moonObstacleZoneRadius * 2F;
     float endDepthForOrbitSlot = startDepthForOrbitSlot + depthReqdForOrbitSlot;
     if (endDepthForOrbitSlot > depthAvailableForMoonOrbitsAroundPlanet) {
         assignedSlot = null;
         return false;
     }
     GameTimeDuration orbitPeriod = _minMoonOrbitPeriod + (slotIndex * _moonOrbitPeriodIncrement);
     assignedSlot = new OrbitData(slotIndex, startDepthForOrbitSlot, endDepthForOrbitSlot, orbitPeriod);
     return true;
 }
    /// <summary>
    /// Generates an ordered array of all CelestialOrbitSlots in the system. The first slot (index = 0) is the closest to the star, just outside
    /// the star's CloseOrbitOuterRadius.
    /// Note: These are system orbit slots that can be occupied by planets and settlements.
    /// </summary>
    /// <returns></returns>
    private OrbitData[] GenerateAllSystemOrbitSlots(int settlementOrbitSlotIndex, out float systemOrbitSlotDepth) {
        D.Assert(_star.Radius != Constants.ZeroF, "{0}.Radius has not yet been set.".Inject(_star.FullName));   // confirm the star's Awake() has run so Radius is valid
        float sysOrbitSlotsStartRadius = _star.Data.CloseOrbitOuterRadius;    //_star.ShipOrbitSlot.OuterRadius;
        float systemRadiusAvailableForAllOrbits = TempGameValues.SystemRadius - sysOrbitSlotsStartRadius;
        systemOrbitSlotDepth = systemRadiusAvailableForAllOrbits / (float)TempGameValues.TotalOrbitSlotsPerSystem;
        //D.Log("{0}: SystemOrbitSlotDepth = {1:0.#}.", SystemName, systemOrbitSlotDepth);

        var allOrbitSlots = new OrbitData[TempGameValues.TotalOrbitSlotsPerSystem];
        for (int slotIndex = 0; slotIndex < TempGameValues.TotalOrbitSlotsPerSystem; slotIndex++) {
            float insideRadius = sysOrbitSlotsStartRadius + systemOrbitSlotDepth * slotIndex;
            float outsideRadius = insideRadius + systemOrbitSlotDepth;
            var orbitPeriod = _minSystemOrbitPeriod + (slotIndex * _systemOrbitPeriodIncrement);
            //D.Log("{0}'s orbit slot index {1} OrbitPeriod = {2}.", SystemName, slotIndex, orbitPeriod);
            GameObject planetsFolder = _system.transform.FindChild("Planets").gameObject;
            // planetsFolder used in place of _system so orbiters don't inherit the layer of the system
            D.Assert(planetsFolder != null);    // in case I accidentally change name of PlanetsFolder
            bool toActivelyOrbit = slotIndex == settlementOrbitSlotIndex ? TempGameValues.DoSettlementsActivelyOrbit : true;
            allOrbitSlots[slotIndex] = new OrbitData(planetsFolder, insideRadius, outsideRadius, _system.IsMobile, orbitPeriod, toActivelyOrbit);
        }
        return allOrbitSlots;
    }
    /// <summary>
    /// Assigns and applies a CelestialOrbitSlot around a planet to each moon. If the orbit slot proposed would potentially 
    /// interfere with other orbiting bodies or ships, the moon is destroyed. The position of the moon 
    /// is automatically adjusted to fit within the slot when the orbit slot is assigned. 
    /// Applies to both randomly-generated and preset moons.
    /// </summary>
    private void AssignPlanetOrbitSlotsToMoons() {
        LogEvent();
        IList<MoonItem> moonsToDestroy = null;
        foreach (var planet in _planets) {
            float depthAvailForMoonOrbitsAroundPlanet = _systemOrbitSlotDepth;

            float startDepthForMoonOrbitSlot = planet.Data.CloseOrbitOuterRadius;
            var moons = planet.GetComponentsInChildren<MoonItem>();
            if (moons.Any()) {
                int slotIndex = Constants.Zero;
                foreach (var moon in moons) {
                    float depthReqdForMoonOrbitSlot = 2F * moon.ObstacleZoneRadius;
                    float endDepthForMoonOrbitSlot = startDepthForMoonOrbitSlot + depthReqdForMoonOrbitSlot;
                    if (endDepthForMoonOrbitSlot <= depthAvailForMoonOrbitsAroundPlanet) {
                        moon.Name = planet.Name + _moonLetters[slotIndex];
                        GameTimeDuration orbitPeriod = _minMoonOrbitPeriod + (slotIndex * _moonOrbitPeriodIncrement);
                        var moonOrbitSlot = new OrbitData(planet.gameObject, startDepthForMoonOrbitSlot, endDepthForMoonOrbitSlot, planet.IsMobile, orbitPeriod);
                        _generalFactory.InstallCelestialItemInOrbit(moon.gameObject, moonOrbitSlot);
                        //D.Log("{0} has assumed orbit slot {1} around Planet {2}.", moon.FullName, slotIndex, planet.FullName);

                        startDepthForMoonOrbitSlot = endDepthForMoonOrbitSlot;
                        slotIndex++;
                    }
                    else {
                        if (moonsToDestroy == null) {
                            moonsToDestroy = new List<MoonItem>();
                        }
                        D.Warn(slotIndex == Constants.Zero, "{0}: Size of planet {1} precludes adding any moons.", GetType().Name, planet.FullName);
                        //D.Log("{0} scheduled for destruction. OrbitSlot outer depth {1} > available depth {2}.",
                        //    moon.FullName, endDepthForMoonOrbitSlot, depthAvailForMoonOrbitsAroundPlanet);
                        moonsToDestroy.Add(moon);
                    }
                }
            }
        }
        if (moonsToDestroy != null) {
            moonsToDestroy.ForAll(m => {
                _moons.Remove(m);
                //D.Log("Destroying Moon {0}.", m.FullName);
                Destroy(m.gameObject);
            });
        }
    }