Esempio n. 1
0
        /// <summary>
        /// Harmony Prefix patch to OfficeBuildingAI.CalculateProductionCapacity to implement mod production calculations.
        /// </summary>
        /// <param name="__result">Original method result</param>
        /// <param name="__instance">Original AI instance reference</param>
        /// <param name="level">Building level</param>
        /// <returns>False (don't execute base game method after this)</returns>
        public static bool Prefix(ref int __result, OfficeBuildingAI __instance, ItemClass.Level level)
        {
            // Get builidng info.
            BuildingInfo info = __instance.m_info;

            ItemClass.SubService subService = info.GetSubService();

            // Get cached workplace count and calculate total workplaces.
            int[] workplaces   = PopData.instance.WorkplaceCache(info, (int)level);
            int   totalWorkers = workplaces[0] + workplaces[1] + workplaces[2] + workplaces[3];

            // Using legacy settings?
            if (PopData.instance.ActivePack(info).version == (int)DataVersion.legacy)
            {
                // Legacy settings.
                int[] array = LegacyAIUtils.GetOfficeArray(info, (int)level);

                // Original method return value.
                __result = totalWorkers / array[DataStore.PRODUCTION];
            }
            else
            {
                // Hew settings - multiply total workers by overall multiplier (from settings) to get result; divisor is 1,000 to match original mod 1/10th when at 100% production.
                __result = (totalWorkers * (subService == ItemClass.SubService.OfficeHightech ? highTechOfficeProdMult : genericOfficeProdMult)) / 1000;
            }

            // Always set at least one.
            if (__result < 1)
            {
                __result = 1;
            }

            // Don't execute base method after this.
            return(false);
        }
Esempio n. 2
0
        /// <summary>
        /// Pre-emptive Harmony Prefix patch for IndustrialExtractorAI.GetConsumptionRates, to implement the mod's consumption calculations.
        /// </summary>
        /// <param name="__instance">AI instance reference</param>
        /// <param name="r">Randomizer</param>
        /// <param name="productionRate">Building production rate</param>
        /// <param name="electricityConsumption">Building electricity consumption</param>
        /// <param name="waterConsumption">Building water consumption</param>
        /// <param name="sewageAccumulation">Building sewage accumulation</param>
        /// <param name="garbageAccumulation">Building garbage accumulation</param>
        /// <param name="incomeAccumulation">Building income accumulation</param>
        /// <param name="mailAccumulation">Building mail accumulation</param>
        /// <returns>Always false (never execute original method)</returns>
        public static bool Prefix(IndustrialExtractorAI __instance, Randomizer r, int productionRate, out int electricityConsumption, out int waterConsumption, out int sewageAccumulation, out int garbageAccumulation, out int incomeAccumulation, out int mailAccumulation)
        {
            // Get relevant array from datastore.
            int[] array = LegacyAIUtils.GetExtractorArray(__instance.m_info);

            // Get consumption rates from array.
            electricityConsumption = array[DataStore.POWER];
            waterConsumption       = array[DataStore.WATER];
            sewageAccumulation     = array[DataStore.SEWAGE];
            garbageAccumulation    = array[DataStore.GARBAGE];
            mailAccumulation       = array[DataStore.MAIL];

            // Calculate land value.
            int landValue = LegacyAIUtils.GetLandValueIncomeComponent(r.seed);

            incomeAccumulation = array[DataStore.INCOME] + landValue;

            // Apply consumption rates.
            electricityConsumption = Mathf.Max(100, productionRate * electricityConsumption) / 100;
            waterConsumption       = Mathf.Max(100, productionRate * waterConsumption) / 100;
            sewageAccumulation     = Mathf.Max(100, productionRate * sewageAccumulation) / 100;
            garbageAccumulation    = Mathf.Max(100, productionRate * garbageAccumulation) / 100;
            incomeAccumulation     = productionRate * incomeAccumulation;
            mailAccumulation       = Mathf.Max(100, productionRate * mailAccumulation) / 100;

            // Don't execute base method after this.
            return(false);
        }
        /// <summary>
        /// Harmony Prefix patch to IndustrialBuildingAI.CalculateProductionCapacity to implement mod production calculations.
        /// </summary>
        /// <param name="__result">Original method result</param>
        /// <param name="__instance">Original AI instance reference</param>
        /// <param name="level">Building level</param>
        /// <returns>False (don't execute base game method after this)</returns>
        public static bool Prefix(ref int __result, IndustrialBuildingAI __instance, ItemClass.Level level, int width, int length)
        {
            // Get builidng info.
            BuildingInfo info = __instance.m_info;

            ItemClass.SubService subService = info.GetSubService();

            // Array index.
            int arrayIndex = GetIndex(subService);

            // New or old method?
            if (prodModes[arrayIndex] == (int)ProdModes.popCalcs)
            {
                // New settings, based on population.
                float multiplier;
                switch (info.GetClassLevel())
                {
                case ItemClass.Level.Level1:
                    multiplier = 1f;
                    break;

                case ItemClass.Level.Level2:
                    multiplier = 0.933333f;
                    break;

                default:
                    multiplier = 0.8f;
                    break;
                }

                // Get cached workplace count and calculate total workplaces.
                int[] workplaces = PopData.instance.WorkplaceCache(info, (int)level);

                float totalWorkers = workplaces[0] + workplaces[1] + workplaces[2] + workplaces[3];
                // Multiply total workers by multipler and overall multiplier (from settings) to get result.
                __result = (int)((totalWorkers * multiplier * prodMults[arrayIndex]) / 100f);
            }
            else
            {
                // Legacy calcs.
                int[] array = LegacyAIUtils.GetIndustryArray(__instance.m_info, (int)level);

                // Original method return value.
                __result = Mathf.Max(100, width * length * array[DataStore.PRODUCTION]) / 100;
            }


            // Always set at least one.
            if (__result < 1)
            {
                Logging.Error("invalid production result ", __result.ToString(), " for ", __instance.m_info.name, "; setting to 1");
                __result = 1;
            }

            // Don't execute base method after this.
            return(false);
        }
        public static bool Prefix(OfficeBuildingAI __instance, ItemClass.Level level, out int groundPollution, out int noisePollution)
        {
            int[] array = LegacyAIUtils.GetOfficeArray(__instance.m_info, (int)level);

            groundPollution = array[DataStore.GROUND_POLLUTION];
            noisePollution  = array[DataStore.NOISE_POLLUTION];

            // Don't execute base method after this.
            return(false);
        }
        public static bool Prefix(IndustrialExtractorAI __instance, int productionRate, out int groundPollution, out int noisePollution)
        {
            int[] array = LegacyAIUtils.GetExtractorArray(__instance.m_info);

            groundPollution = (productionRate * array[DataStore.GROUND_POLLUTION]) / 100;
            noisePollution  = (productionRate * array[DataStore.NOISE_POLLUTION]) / 100;

            // Don't execute base method after this.
            return(false);
        }
Esempio n. 6
0
        public static bool Prefix(ref int __result, CommercialBuildingAI __instance, ItemClass.Level level, int width, int length)
        {
            int[] array = LegacyAIUtils.GetCommercialArray(__instance.m_info, (int)level);

            // Original method return value.
            __result = Mathf.Max(100, width * length * array[DataStore.PRODUCTION]) / 100;

            // Don't execute base method after this.
            return(false);
        }
        public static bool Prefix(IndustrialBuildingAI __instance, ItemClass.Level level, int productionRate, out int groundPollution, out int noisePollution)
        {
            int[] array = LegacyAIUtils.GetIndustryArray(__instance.m_info, (int)level);

            groundPollution = (productionRate * array[DataStore.GROUND_POLLUTION]) / 100;
            noisePollution  = (productionRate * array[DataStore.NOISE_POLLUTION]) / 100;

            // Don't execute base method after this.
            return(false);
        }
Esempio n. 8
0
        public static bool Prefix(CommercialBuildingAI __instance, ItemClass.Level level, int productionRate, DistrictPolicies.CityPlanning cityPlanningPolicies, out int groundPollution, out int noisePollution)
        {
            ItemClass item = __instance.m_info.m_class;

            int[] array = LegacyAIUtils.GetCommercialArray(__instance.m_info, (int)level);

            groundPollution = array[DataStore.GROUND_POLLUTION];
            noisePollution  = (productionRate * array[DataStore.NOISE_POLLUTION]) / 100;
            if (item.m_subService == ItemClass.SubService.CommercialLeisure)
            {
                if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.NoLoudNoises) != DistrictPolicies.CityPlanning.None)
                {
                    noisePollution /= 2;
                }
            }

            // Don't execute base method after this.
            return(false);
        }
Esempio n. 9
0
 /// <summary>
 /// Legacy visitplace count calculations.
 /// </summary>
 /// <param name="prefab">Building prefab</param>
 /// <param name="level">Building level </param>
 /// <returns>Calculated visitplace count</returns>
 internal static int LegacyVisitCount(BuildingInfo prefab, ItemClass.Level level) => UnityEngine.Mathf.Max(200, prefab.GetWidth() * prefab.GetWidth() * LegacyAIUtils.GetCommercialArray(prefab, (int)level)[DataStore.VISIT]) / 100;
        /// <summary>
        /// Called whenever the currently selected building is changed to update the panel display.
        /// </summary>
        /// <param name="building">Newly selected building</param>
        public void SelectionChanged(BuildingInfo building)
        {
            // Make sure we have a valid selection before proceeding.
            if (building?.name == null)
            {
                return;
            }

            // Variables to compare actual counts vs. mod count, to see if there's another mod overriding counts.
            int appliedCount;
            int modCount;

            // Building model size, not plot size.
            Vector3 buildingSize = building.m_size;
            int     floorCount;

            // Array used for calculations depending on building service/subservice (via DataStore).
            int[] array;
            // Default minimum number of homes or jobs is one; different service types will override this.
            int minHomesJobs = 1;
            int customHomeJobs;

            // Check for valid building AI.
            if (!(building.GetAI() is PrivateBuildingAI buildingAI))
            {
                Logging.Error("invalid building AI type in building details for building ", building.name);
                return;
            }

            // Residential vs. workplace AI.
            if (buildingAI is ResidentialBuildingAI)
            {
                // Get appropriate calculation array.
                array = LegacyAIUtils.GetResidentialArray(building, (int)building.GetClassLevel());

                // Set calculated homes label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_HOM_CALC");

                // Set customised homes label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_HOM_CUST");
                customHomeJobs            = OverrideUtils.GetResidential(building);

                // Applied homes is what's actually being returned by the CaclulateHomeCount call to this building AI.
                // It differs from calculated homes if there's an override value for that building with this mod, or if another mod is overriding.
                appliedCount = buildingAI.CalculateHomeCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength());
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_HOM_APPL") + appliedCount;
            }
            else
            {
                // Workplace AI.
                // Default minimum number of jobs is 4.
                minHomesJobs = 4;

                // Find the correct array for the relevant building AI.
                switch (building.GetService())
                {
                case ItemClass.Service.Commercial:
                    array = LegacyAIUtils.GetCommercialArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Office:
                    array = LegacyAIUtils.GetOfficeArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Industrial:
                    if (buildingAI is IndustrialExtractorAI)
                    {
                        array = LegacyAIUtils.GetExtractorArray(building);
                    }
                    else
                    {
                        array = LegacyAIUtils.GetIndustryArray(building, (int)building.GetClassLevel());
                    }
                    break;

                default:
                    Logging.Error("invalid building service in building details for building ", building.name);
                    return;
                }

                // Set calculated jobs label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_JOB_CALC") + " ";

                // Set customised jobs label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_JOB_CUST") + " ";
                customHomeJobs            = OverrideUtils.GetWorker(building);

                // Applied jobs is what's actually being returned by the CalculateWorkplaceCount call to this building AI.
                // It differs from calculated jobs if there's an override value for that building with this mod, or if another mod is overriding.
                int[] jobs = new int[4];
                buildingAI.CalculateWorkplaceCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength(), out jobs[0], out jobs[1], out jobs[2], out jobs[3]);
                appliedCount = jobs[0] + jobs[1] + jobs[2] + jobs[3];
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_JOB_APPL") + " " + appliedCount;

                // Show visitor count for commercial buildings.
                if (buildingAI is CommercialBuildingAI commercialAI)
                {
                    visitCountLabel.Show();
                    visitCountLabel.text = Translations.Translate("RPR_CAL_VOL_VIS") + " " + commercialAI.CalculateVisitplaceCount(building.GetClassLevel(), new Randomizer(), building.GetWidth(), building.GetLength());
                }
                else
                {
                    visitCountLabel.Hide();
                }

                // Display production count, or hide the label if not a production building.
                if (building.GetAI() is PrivateBuildingAI privateAI && (privateAI is OfficeBuildingAI || privateAI is IndustrialBuildingAI || privateAI is IndustrialExtractorAI))
                {
                    productionLabel.Show();
                    productionLabel.text = Translations.Translate("RPR_CAL_VOL_PRD") + " " + privateAI.CalculateProductionCapacity(building.GetClassLevel(), new ColossalFramework.Math.Randomizer(), building.GetWidth(), building.GetLength()).ToString();
                }