Exemple #1
0
        static bool Prefix(ref int __result, ushort instanceID, ref CitizenInstance citizenData, Citizen.AgeGroup ageGroup)
        {
            // Cache as best we can. The order of calls is car, bike, taxi
            AIUtils.citizenCache = citizenData.m_citizen;  // Not needed, but just in case

            Citizen citizen      = Singleton <CitizenManager> .instance.m_citizens.m_buffer[(int)((UIntPtr)citizenData.m_citizen)];
            ushort  homeBuilding = citizen.m_homeBuilding;

            ItemClass.SubService subService = ItemClass.SubService.ResidentialLow;
            if (homeBuilding != 0)
            {
                DistrictManager instance = Singleton <DistrictManager> .instance;
                Building        building = Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)homeBuilding];
                District        district = instance.m_districts.m_buffer[instance.GetDistrict(building.m_position)];
                DistrictPolicies.CityPlanning cityPlanningPolicies = district.m_cityPlanningPolicies;

                AIUtils.livesInBike = (cityPlanningPolicies & DistrictPolicies.CityPlanning.EncourageBiking) != DistrictPolicies.CityPlanning.None;
                subService          = Singleton <BuildingManager> .instance.m_buildings.m_buffer[homeBuilding].Info.GetSubService();
            }

            // Set the cache
            AIUtils.cacheArray = AIUtils.GetArray(citizen.WealthLevel, subService, ageGroup);

            // Original method return value.
            __result = AIUtils.cacheArray[DataStore.CAR];

            if (Debugging.UseTransportLog)
            {
                Debugging.WriteToLog(Debugging.TransportLogName, citizen.WealthLevel + "-wealth " + ageGroup + " has " + __result + "% chance of driving.");
            }

            // Don't execute base method after this.
            return(false);
        }
Exemple #2
0
        static bool Prefix(ref int __result, ushort instanceID, ref CitizenInstance citizenData, Citizen.AgeGroup ageGroup)
        {
            // Original method return value.
            // Array cache has already been set when GetCarProbability was called.
            __result = AIUtils.cacheArray[DataStore.TAXI];

            if (Debugging.UseTransportLog)
            {
                Debugging.WriteToLog(Debugging.TransportLogName, "The same " + ageGroup + " has " + __result + "% chance of using a taxi.");
            }

            // Don't execute base method after this.
            return(false);
        }
        /// <summary>
        /// Method called by OutsideConnectionAI.StartConnectionTransferImpl Transpiler insertion.
        /// Randomises (within parameters) age and education levels of immigrants.
        /// All variables are local variables within OutsideConnectionAI.StartConnectionTransferImpl.
        /// </summary>
        /// <param name="i">Loop counter (for loop containing method call)</param>
        /// <param name="education">Education level input (StartConnectionTransferImpl local variable)</param>
        /// <param name="ageArray">Array of acceptible ages (from mod DataStore); placed on stack in advance via Transpiler insertion</param>
        /// <param name="childrenAgeMax">Maximum child immigrant age; placed on stack in advance via Transpiler insertion </param>
        /// <param name="childrenAgeMin">Minimum child immigrant age; placed on stack in advance via Transpiler insertion</param>
        /// <param name="minAdultAge">Minimum adult immigrant age; placed on stack in advance via Transpiler insertion</param>
        /// <param name="resultEducation">Resultant education level for immigrant after mod calculations (StartConnectionTransferImpl local variable 'education2')</param>
        /// <param name="resultAge">Resultant age level for immigrant after mod calculations (StartConnectionTransferImpl local variable 'age')</param>
        public static void RandomizeImmigrants(int i, Citizen.Education education, int[] ageArray, ref int childrenAgeMax, ref int childrenAgeMin, ref int minAdultAge, out Citizen.Education resultEducation, out int resultAge)
        {
            // Minimum and maximum ages.
            int min = ageArray[0];
            int max = ageArray[1];

            // We start inside an i loop.
            // i is is the family member number for this incoming family.  0 is primary adult, 1 is secondary adults, and after that are children.
            if (i == 1)
            {
                // Age of second adult - shouldn't be too far from the first. Just because.
                min = Math.Max(minAdultAge - 20, DataStore.incomingAdultAge[0]);
                max = Math.Min(minAdultAge + 20, DataStore.incomingAdultAge[1]);
            }
            else if (i >= 2)
            {
                // Children.
                min = childrenAgeMin;
                max = childrenAgeMax;
            }

            // Calculate actual age randomly between minumum and maxiumum.
            resultAge = Singleton <SimulationManager> .instance.m_randomizer.Int32(min, max);

            // Adust age brackets for subsequent family members.
            if (i == 0)
            {
                minAdultAge = resultAge;
            }
            else if (i == 1)
            {
                // Restrict to adult age. Young adult is 18 according to National Institutes of Health... even if the young adult section in a library isn't that range.
                minAdultAge = Math.Min(resultAge, minAdultAge);

                // Children should be between 80 and 180 younger than the youngest adult.
                childrenAgeMax = Math.Max(minAdultAge - 80, 0);  // Allow people 10 ticks from 'adulthood' to have kids
                childrenAgeMin = Math.Max(minAdultAge - 178, 0); // Accounting gestation, which isn't simulated yet (2 ticks)
            }

            // Set default eductation output to what the game has already determined.
            resultEducation = education;

            // Apply education level randomisation if that option is selected.
            if (ModSettings.randomImmigrantEd)
            {
                if (i < 2)
                {
                    // Adults.
                    // 24% different education levels
                    int eduModifier = Singleton <SimulationManager> .instance.m_randomizer.Int32(-12, 12) / 10;

                    resultEducation += eduModifier;
                    if (resultEducation < Citizen.Education.Uneducated)
                    {
                        resultEducation = Citizen.Education.Uneducated;
                    }
                    else if (resultEducation > Citizen.Education.ThreeSchools)
                    {
                        resultEducation = Citizen.Education.ThreeSchools;
                    }
                }
                else
                {
                    // Children.
                    switch (Citizen.GetAgeGroup(resultAge))
                    {
                    case Citizen.AgeGroup.Child:
                        resultEducation = Citizen.Education.Uneducated;
                        break;

                    case Citizen.AgeGroup.Teen:
                        resultEducation = Citizen.Education.OneSchool;
                        break;

                    default:
                        // Make it that 80% graduate from high school
                        resultEducation = (Singleton <SimulationManager> .instance.m_randomizer.Int32(0, 100) < 80) ? Citizen.Education.TwoSchools : Citizen.Education.OneSchool;
                        break;
                    }
                }
            }

            // Write to immigration log if that option is selected.
            if (Debugging.UseImmigrationLog)
            {
                Debugging.WriteToLog(Debugging.ImmigrationLogName, "Family member " + i + " immigrating with age " + resultAge + " (" + (int)(resultAge / 3.5) + " years old) and education level " + education + ".");
            }
        }
        private static bool Prefix(ref bool __result, ref ResidentAI __instance, uint citizenID, ref Citizen data)
        {
            if ((citizenID % DataStore.lifeSpanMultiplier) == Threading.counter)
            {
                int num = data.Age + 1;
                // Threading.sb.Append(citizenID + ": " + num + "\n");
                //Debugging.writeDebugToFile(citizenID + ": " + num + " " + Threading.counter);

                if (num <= 45)
                {
                    if (num == 15 || num == 45)
                    {
                        FinishSchoolOrWorkRev(__instance, citizenID, ref data);
                    }
                }
                else if (num == 90 || num >= ModSettings.retirementAge)
                {
                    FinishSchoolOrWorkRev(__instance, citizenID, ref data);
                }
                else if ((data.m_flags & Citizen.Flags.Student) != Citizen.Flags.None && (num % 15 == 0))  // Workspeed multiplier?
                {
                    FinishSchoolOrWorkRev(__instance, citizenID, ref data);
                }

                if ((data.m_flags & Citizen.Flags.Original) != Citizen.Flags.None)
                {
                    CitizenManager instance = Singleton <CitizenManager> .instance;
                    if (instance.m_tempOldestOriginalResident < num)
                    {
                        instance.m_tempOldestOriginalResident = num;
                    }
                    if (num == 240)
                    {
                        Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.FullLifespans).Add(1);
                    }
                }

                data.Age = num;

                // Checking for death and sickness chances.
                // Citizens who are currently moving or currently in a vehicle aren't affected.
                if (data.CurrentLocation != Citizen.Location.Moving && data.m_vehicle == 0)
                {
                    bool died = false;

                    if (ModSettings.VanillaCalcs)
                    {
                        // Using vanilla lifecycle calculations.
                        int num2 = 240;
                        int num3 = 255;
                        int num4 = Mathf.Max(0, 145 - (100 - data.m_health) * 3);
                        if (num4 != 0)
                        {
                            num2 += num4 / 3;
                            num3 += num4;
                        }
                        if (num >= num2)
                        {
                            bool flag = Singleton <SimulationManager> .instance.m_randomizer.Int32(2000u) < 3;

                            died = (Singleton <SimulationManager> .instance.m_randomizer.Int32(num2 * 100, num3 * 100) / 100 <= num || flag);
                        }
                    }
                    else
                    {
                        // Using custom lifecycle calculations.
                        // Game defines years as being age divided by 3.5.  Hence, 35 age increments per decade.
                        // Legacy mod behaviour worked on 25 increments per decade.
                        // If older than the maximum index - lucky them, but keep going using that final index.
                        int index = Math.Min((int)(num * ModSettings.decadeFactor), 10);

                        // Calculate 90% - 110%; using 100,000 as 100% (for precision).
                        int modifier = 100000 + ((150 * data.m_health) + (50 * data.m_wellbeing) - 10000);

                        // Death chance is simply if a random number between 0 and the modifier calculated above is less than the survival probability calculation for that decade of life.
                        // Also set maximum age of 400 (~114 years) to be consistent with the base game.
                        died = (Singleton <SimulationManager> .instance.m_randomizer.Int32(0, modifier) < DataStore.survivalProbCalc[index]) || num > 400;

                        // Check for sickness chance if they haven't died.
                        if (!died && Singleton <SimulationManager> .instance.m_randomizer.Int32(0, modifier) < DataStore.sicknessProbCalc[index])
                        {
                            // Make people sick, if they're unlucky.
                            data.Sick = true;

                            if (Debugging.UseSicknessLog)
                            {
                                Debugging.WriteToLog(Debugging.SicknessLogName, "Citizen became sick with chance factor " + DataStore.sicknessProbCalc[index] + ".");
                            }
                        }
                    }

                    if (died)
                    {
                        if (Debugging.UseDeathLog)
                        {
                            Debugging.WriteToLog(Debugging.DeathLogName, "Citizen died at age: " + data.Age + " (" + (int)(data.Age / 3.5) + " years old).");
                        }

                        // Reverse redirect to access private method Die().
                        DieRev(__instance, citizenID, ref data);

                        // Chance for 'vanishing corpse' (no need for deathcare).
                        if (!AIUtils.KeepCorpse())
                        {
                            Singleton <CitizenManager> .instance.ReleaseCitizen(citizenID);

                            return(true);
                        }
                    }
                }
            }

            // Original method return value.
            __result = false;

            // Don't execute base method after this.
            return(false);
        }