/// <summary> /// Pre-emptive Harmony Prefix patch for ResidentialBuildingAI.GetConsumptionRates, to implement the mod's consumption calculations. /// </summary> /// <param name="__instance">AI instance reference</param> /// <param name="level">Building level</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(ResidentialBuildingAI __instance, ItemClass.Level level, 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.GetResidentialArray(__instance.m_info, (int)level); // 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); }
public static bool Prefix(ResidentialBuildingAI __instance, ItemClass.Level level, out int groundPollution, out int noisePollution) { int[] array = LegacyAIUtils.GetResidentialArray(__instance.m_info, (int)level); groundPollution = array[DataStore.GROUND_POLLUTION]; noisePollution = array[DataStore.NOISE_POLLUTION]; // Don't execute base method after this. return(false); }
/// <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(); }