private float MigrationValueOfPlanet(PlanetData pData, Pops pop)
    {
        float planetValue = 0f;

        float FarmerJobsOnPlanet = 0f;
        float MinerJobsOnPlanet = 0f;
        float EngineerJobsOnPlanet = 0f;
        float FluxmenJobsOnPlanet = 0f;
        float AdministratorJobsOnPlanet = 0f;
        float ScientistJobsOnPlanet = 0f;

        float releventJobsOnPlanet = 0f;

        foreach (Region rData in pData.RegionList)
        {
            FarmerJobsOnPlanet += rData.FarmingLevel - rData.FarmsStaffed;
            MinerJobsOnPlanet += rData.MiningLevel - rData.MinesStaffed;
            EngineerJobsOnPlanet += rData.ManufacturingLevel - rData.FactoriesStaffed;
            FluxmenJobsOnPlanet += rData.HighTechLevel - rData.HighTechFacilitiesStaffed;
            AdministratorJobsOnPlanet += rData.GovernmentLevel - rData.GovernmentFacilitiesStaffed;
            ScientistJobsOnPlanet += rData.ScienceLevel - rData.LabsStaffed;
        }

        switch (pop.PopClass)
        {
        case Pops.ePopClass.Scientist:
            releventJobsOnPlanet = ScientistJobsOnPlanet;
            break;
        case Pops.ePopClass.Farmer:
            releventJobsOnPlanet = FarmerJobsOnPlanet;
            break;
        case Pops.ePopClass.Miner:
            releventJobsOnPlanet = MinerJobsOnPlanet;
            break;
        case Pops.ePopClass.Engineer:
            releventJobsOnPlanet = EngineerJobsOnPlanet;
            break;
        case Pops.ePopClass.Fluxmen:
            releventJobsOnPlanet = FluxmenJobsOnPlanet;
            break;
        case Pops.ePopClass.Merchants:
            break;
        case Pops.ePopClass.Administrators:
            releventJobsOnPlanet = AdministratorJobsOnPlanet;
            break;
        case Pops.ePopClass.None:
            break;
        default:
            break;
        }

        planetValue += (2500 - HelperFunctions.Formulas.MeasureDistanceBetweenSystems(pData.System, pop.PlanetLocated.System)) + pData.AdjustedBio + pData.BasePlanetValue + (releventJobsOnPlanet * 50);
        return planetValue;
    }
    public static void GenerateNewPop(Civilization civ, Region rData, Boolean isGraduating)
    {
        float PopSkillModifier = 0.0f;
        float HouseFarmingModifier = 1f;
        float HouseMiningModifier = 1f;
        float HouseEngineeringModifier = 1f;
        float HouseScienceModifier = 1f;
        float HouseMerchantModifier = 1f;
        float HouseFluxModifier = 1f;
        float HouseAdminModifier = 1f;

        Pops newPop = new Pops();

        // Step 1: Determine civ of pop and set location
        newPop.EmpireID = civ.ID;
        newPop.RegionLocationID = rData.ID;

        // Step 1a: Determine type/age of pop
        int popTypeChance = 0;
        popTypeChance = UnityEngine.Random.Range(0, 100);
        if (isGraduating) // there must always be fewer child pops then worker pops (for Peter Pan issue)
        {
            newPop.Age = 18;
            PopSkillModifier = YoungAdultSkillModifier;
        }

        if (popTypeChance < ChancePopIsYoungAdult && !isGraduating)
        {
            newPop.Type = Pops.ePopType.Worker;
            newPop.Age = UnityEngine.Random.Range(18,25);
            PopSkillModifier = YoungAdultSkillModifier * ((float)newPop.Age/ 18f);
        }

        if (popTypeChance < ChancePopIsWorker && !isGraduating)
        {
            newPop.Type = Pops.ePopType.Worker;
            newPop.Age = UnityEngine.Random.Range(25, 65);
            PopSkillModifier = WorkerSkillModifier;
        }

        if (popTypeChance >= ChancePopIsRetired && !isGraduating)
        {
            newPop.Type = Pops.ePopType.Retired;
            newPop.Age = UnityEngine.Random.Range(66, 85);
            PopSkillModifier = RetiredSkillModifier;
        }
        //}
        //else
        //{
        //    newPop.Type = Pops.ePopType.Worker;
        //    newPop.Age = UnityEngine.Random.Range(18, 65);
        //    PopSkillModifier = WorkerSkillModifier;
        //}

        // Step 1A: Get House Skill Modifier;
        if (rData.PlanetLocated.Viceroy.AssignedHouse != null)
        {
            //HouseFarmingModifier += ((rData.PlanetLocated.Viceroy.AssignedHouse.FarmingTradition - 50) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
            //HouseMiningModifier += ((rData.PlanetLocated.Viceroy.AssignedHouse.MiningTradition - 50) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
            //HouseEngineeringModifier += ((rData.PlanetLocated.Viceroy.AssignedHouse.ManufacturingTradition - 50) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
            //HouseFluxModifier += (((rData.PlanetLocated.Viceroy.AssignedHouse.ScienceTradition + rData.PlanetLocated.Viceroy.AssignedHouse.ManufacturingTradition) - 100) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
            //HouseScienceModifier += ((rData.PlanetLocated.Viceroy.AssignedHouse.ScienceTradition - 50) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
            //HouseAdminModifier += ((rData.PlanetLocated.Viceroy.AssignedHouse.GovernmentTradition - 50) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
            //HouseMerchantModifier += ((rData.PlanetLocated.Viceroy.AssignedHouse.TradeTradition - 50) * .01f * (rData.PlanetLocated.Viceroy.TimeInPosition / 100f));
        }

        // Step 2: Generate basic stats (eventually blend for civ speciality/tech level)
        int farmSkill = 0;
        int scienceSkill = 0;
        int miningSkill = 0;
        int highTechSkill = 0;
        int manufacturingSkill = 0;
        int merchantSkill = 0;
        int fluxSkill = 0;
        int adminSkill = 0;

        // determine the need in each region for each type of pop
        int farmDeficit = rData.FarmingLevel - rData.TotalFarmers;
        int minerDeficit = rData.MiningLevel - rData.TotalMiners;
        int fluxmenDeficit = rData.HighTechLevel - rData.TotalFluxmen;
        int adminDeficit = rData.GovernmentLevel - rData.TotalAdministrators;
        int engineerDeficit = rData.ManufacturingLevel - rData.TotalEngineers;
        int scientistDeficit = rData.ScienceLevel - rData.TotalScientists;
        int merchantDeficit = (rData.PopsInTile.Count / 4) - rData.TotalMerchants;

        // create the base skills using the house modifiers
        farmSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseFarmingModifier);
        scienceSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseScienceModifier);
        miningSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseMiningModifier);
        highTechSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseEngineeringModifier);
        manufacturingSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseEngineeringModifier);
        fluxSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseFluxModifier);
        merchantSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseMerchantModifier);
        adminSkill = (int)(UnityEngine.Random.Range(45, 55) * PopSkillModifier * HouseAdminModifier);

        // adjust for more 'needed/common' pops based on type of job and current need
        farmSkill += farmDeficit * skillNeedMultiple;
        scienceSkill += scientistDeficit * skillNeedMultiple;
        miningSkill += minerDeficit * skillNeedMultiple;
        highTechSkill += ((fluxmenDeficit + engineerDeficit) / 2) * skillNeedMultiple;
        manufacturingSkill += engineerDeficit * skillNeedMultiple;
        fluxSkill += fluxmenDeficit * skillNeedMultiple;
        merchantSkill +=  merchantDeficit * skillNeedMultiple;
        adminSkill += adminDeficit * skillNeedMultiple;

        // assign the final skill totals
        newPop.FarmingSkill = farmSkill;
        newPop.ScienceSkill = scienceSkill;
        newPop.MiningSkill = miningSkill;
        newPop.HighTechSkill = highTechSkill;
        newPop.ManufacturingSkill = manufacturingSkill;
        newPop.FluxSkill = fluxSkill;
        newPop.MerchantSkill = merchantSkill;
        newPop.AdminSkill = adminSkill;

        // put the pop into the workforce
        newPop.Employment = Pops.ePopEmployment.Unemployed;

        // Step 3: Generate popular support and unrest levels
        newPop.PopSupport = .5f; // 50% to start
        newPop.UnrestLevel = UnityEngine.Random.Range(0f, .1f);
        newPop.PlanetHappinessLevel = UnityEngine.Random.Range(30, 90) - (100-rData.PlanetLocated.AdjustedBio);

        // Step 4: Add the pop
        rData.PopsInTile.Add(newPop);
    }
    private void DetermineMigrationLocation(Pops pop, Civilization civ)
    {
        float topPlanetValue = 0f;
        PlanetData topPlanet = null;

        foreach (PlanetData pData in civ.PlanetList) // determine the top value of each planet and choose the best one
        {
            if (pData != pop.PlanetLocated)
            {
                float currentPlanetValue = MigrationValueOfPlanet(pData, pop);
                if (currentPlanetValue > topPlanetValue)
                {
                    topPlanetValue = currentPlanetValue;
                    topPlanet = pData;
                }
            }
        }

        if (topPlanetValue > Constants.Constants.StellarMigrationThreshold + UnityEngine.Random.Range(0,200)) // if the best value is above a certain threshold
        {
            List<Region> eligibleRegionList = new List<Region>();
            foreach (Region rData in topPlanet.RegionList.ToArray())
            {
                if (rData.IsHabitable)
                {
                    eligibleRegionList.Add(rData);
                }
            }

            if (eligibleRegionList.Count > 0)
            {
                int regionChoice = UnityEngine.Random.Range(0,eligibleRegionList.Count); // find an eligible region

                // move the pop from one region on a planet to another planet and a suitable region
                string oldPlanetName = pop.PlanetLocated.Name;
                pop.IsMigratingOffPlanet = false; // reset the flag
                pop.RegionLocated.PopsInTile.Remove(pop);
                pop.RegionLocated.EmigratedLastTurn += 1;
                pop.RegionLocated.PopsInTile.TrimExcess();
                pop.RegionLocationID = eligibleRegionList[regionChoice].ID;
                pop.RegionLocated.PopsInTile.Add(pop);
                pop.RegionLocated.ImmigratedLastTurn += 1;
                pop.PlanetHappinessLevel = 50; // reset planet happiness since they just moved
                Debug.Log("In " + gDataRef.GameDate.ToString("N1") +", a " + pop.PopClass.ToString() + " migrated from " + oldPlanetName + " to " + topPlanet.Name + ".");
                topPlanet.MigratePopsBetweenRegions(); // rerun migration to move the pop to a more suitable region
            }
            else
            {
                pop.UnrestLevel += .05f; // can't leave
                pop.PopSupport -= .05f; // and is pissed
            }
        }

        else
        {
            pop.UnrestLevel += .05f; // can't leave
            pop.PopSupport -= .05f; // and is pissed
        }
    }
 public bool MovePopBetweenRegions(Pops pop, Region oldRegion, Region newRegion)
 {
     if ((newRegion.MaxSafePopulationLevel * 2) > newRegion.PopsInTile.Count) // only move pops if there is room!
     {
         oldRegion.PopsInTile.Remove(pop);
         newRegion.PopsInTile.Add(pop);
         pop.RegionLocationID = newRegion.ID;
         //Debug.Log("A " + pop.PopClass.ToString().ToLower() + " from region " + oldRegion.ID + " moved to region " + newRegion.ID + ".");
         return true;
     }
     else
         return false;
 }