private ServiceSystemDefinition( ItemClass.Service service, ItemClass.SubService subService, VehicleInfo.VehicleType vehicleType, ItemClass.Level level, bool outsideConnection = false) { this.vehicleType = vehicleType; this.service = service; this.level = level; this.subService = subService; this.outsideConnection = outsideConnection; }
/// <summary> /// Returns the pollution generated by this building. /// </summary> /// <param name="level">Building level</param> /// <param name="productionRate">Bulding production rate</param> /// <param name="cityPlanningPolicies">Any applicable policies</param> /// <param name="groundPollution">Ground pollution generated by this building</param> /// <param name="noisePollution">Noise pollution generated by this builidng</param> public override void GetPollutionRates(ItemClass.Level level, int productionRate, DistrictPolicies.CityPlanning cityPlanningPolicies, out int groundPollution, out int noisePollution) { // If pollution is disabled, return zero. if (!m_pollutionEnabled) { groundPollution = 0; noisePollution = 0; return; } // Otherwise, use base method to calculate normal pollution levels. base.GetPollutionRates(level, productionRate, cityPlanningPolicies, out groundPollution, out noisePollution); }
public override int CalculateHomeCount(ItemClass.Level level, Randomizer r, int width, int length) { BuildingInfo item = this.m_info; int returnValue = 0; if (!DataStore.prefabHouseHolds.TryGetValue(item.gameObject.GetHashCode(), out returnValue)) { int[] array = GetArray(this.m_info, (int)level); returnValue = AI_Utils.CalculatePrefabHousehold(width, length, ref item, ref array, (int)level); DataStore.prefabHouseHolds.Add(item.gameObject.GetHashCode(), returnValue); } return(returnValue); }
/// <summary> /// Harmony pre-emptive Prefix patch to replace game workplace calculations with the mod's. /// </summary> /// <param name="__instance">Original AI instance reference</param> /// <param name="level">Building level</param> /// <param name="level0">Uneducated worker count output</param> /// <param name="level1">Educated worker count output</param> /// <param name="level2">Well-educated worker count output</param> /// <param name="level3">Highly-educated worker count output</param> /// <returns>Always false (never execute original method)</returns> public static bool Prefix(PrivateBuildingAI __instance, ItemClass.Level level, out int level0, out int level1, out int level2, out int level3) { // Get cached workplace count. int[] workplaces = PopData.instance.WorkplaceCache(__instance.m_info, (int)level); // Set return values. level0 = workplaces[0]; level1 = workplaces[1]; level2 = workplaces[2]; level3 = workplaces[3]; // Don't execute base method after this. return(false); }
/// <summary> /// Updates the CitizenUnits of already existing (placed/grown) building instances of the specified prefab. /// </summary> /// <param name="prefabName">The (raw BuildingInfo) name of the prefab (null to ignore name match)</param> private static void RecalculateCitizenUnits(string prefabName) { // Local references. CitizenManager citizenManager = Singleton <CitizenManager> .instance; Building[] buildingBuffer = Singleton <BuildingManager> .instance?.m_buildings?.m_buffer; // Don't do anything if we couldn't get the building buffer. if (buildingBuffer == null) { return; } // Iterate through each building in the scene. for (ushort i = 0; i < buildingBuffer.Length; i++) { // Only interested in created buildings with private AI. if ((buildingBuffer[i].m_flags & Building.Flags.Created) != Building.Flags.None) { BuildingInfo buildingInfo = buildingBuffer[i].Info; if (buildingBuffer[i].Info?.GetAI() is PrivateBuildingAI privateAI) { // Residential building; check that either the supplier prefab name is null or it matches this building's prefab. if (buildingBuffer[i].Info.name.Equals(prefabName)) { // Got one! Log initial status. Logging.Message("Identified building ", i, " (", buildingBuffer[i].Info.name, ") with ", CountCitizenUnits(ref buildingBuffer[i]), " CitizenUnits"); // Recalculate home and visit counts. ItemClass.Level buildingLevel = (ItemClass.Level)buildingBuffer[i].m_level; byte buildingWidth = buildingBuffer[i].m_width; byte buildingLength = buildingBuffer[i].m_length; privateAI.CalculateWorkplaceCount(buildingLevel, new Randomizer(i), buildingWidth, buildingLength, out int level0, out int level1, out int level2, out int level3); int workCount = level0 + level1 + level2 + level3; int homeCount = privateAI.CalculateHomeCount(buildingLevel, new Randomizer(i), buildingWidth, buildingLength); int visitCount = privateAI.CalculateVisitplaceCount(buildingLevel, new Randomizer(i), buildingWidth, buildingLength); // Add CitizenUnits via EnsureCitizenUnits reverse patch.. EnsureCitizenUnits(privateAI, i, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[i], homeCount, workCount, visitCount, 0); // Remove any extra CitizenUnits. RemoveCitizenUnits(ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[i], homeCount, workCount, visitCount, 0); // Log changes. Logging.Message("Reset CitizenUnits for building ", i, " (", buildingInfo.name, "); building now has ", CountCitizenUnits(ref buildingBuffer[i]), " CitizenUnits, and total CitizenUnit count is now ", citizenManager.m_unitCount); } } } } }
static bool Prefix(IndustrialBuildingAI __instance, ItemClass.Level level, int productionRate, DistrictPolicies.CityPlanning cityPlanningPolicies, out int groundPollution, out int noisePollution) { ItemClass @class = __instance.m_info.m_class; groundPollution = 0; noisePollution = 0; int[] array = IndustrialBuildingAIMod.GetArray(__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); }
public override void CalculateWorkplaceCount(ItemClass.Level level, Randomizer r, int width, int length, out int level0, out int level1, out int level2, out int level3) { // For some reason CalculateWorkplaceCount gets called every two seconds or so for every rico building currently plopped. // It's the bottleneck of the mod. // So we cache the calculation results, which might save a few cpu cycles. if (workplaceCount != null) { PloppableRICO.WorkplaceAIHelper.SetWorkplaceLevels(out level0, out level1, out level2, out level3, workplaceCount); } else { PloppableRICO.WorkplaceAIHelper.CalculateWorkplaceCount(level, m_ricoData, this, r, width, length, out level0, out level1, out level2, out level3); workplaceCount = new int[] { level0, level1, level2, level3 }; } }
public PrefabData[] GetPrefabs(ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { var prefabs = subService == ItemClass.SubService.PublicTransportBus ? VehiclePrefabs.instance.GetPrefabsNoLogging(service, subService) : VehiclePrefabs.instance.GetPrefabsNoLogging(service, subService, level); if (prefabs.Length == 0) { UnityEngine.Debug.LogWarning("IPT: Vehicles of item class [serrvice: " + service + ", sub service: " + subService + ", level: " + level + "] were requested. None was found."); } return(prefabs); }
private static VehicleInfo GetVehicleInfoWithoutType( VehicleManager instance, ushort buildingID, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { if (!SerializableDataExtension.BuildingData().TryGetValue(buildingID, out var source) || source.Count <= 0) { return(instance.GetRandomVehicleInfo(ref SimulationManager.instance.m_randomizer, service, subService, level)); } return(GetRandomVehicleInfoOverride(ref SimulationManager.instance.m_randomizer, service, subService, level, source.ToArray())); }
public override void GetPollutionRates(ItemClass.Level level, int productionRate, DistrictPolicies.CityPlanning cityPlanningPolicies, out int groundPollution, out int noisePollution) { ItemClass item = this.m_info.m_class; int[] array = GetArray(this.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; } } }
public static ushort GetCapacity(ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { if (service == ItemClass.Service.PublicTransport) { if (level == ItemClass.Level.Level1) { switch (subService) { case ItemClass.SubService.PublicTransportTram: case ItemClass.SubService.PublicTransportCableCar: case ItemClass.SubService.PublicTransportMonorail: case ItemClass.SubService.PublicTransportBus: case ItemClass.SubService.PublicTransportMetro: case ItemClass.SubService.PublicTransportTrain: return(30); case ItemClass.SubService.PublicTransportShip: return(100); case ItemClass.SubService.PublicTransportPlane: return(200); } } else if (level == ItemClass.Level.Level2) { switch (subService) { case ItemClass.SubService.PublicTransportPlane: return(35); case ItemClass.SubService.PublicTransportShip: return(50); case ItemClass.SubService.PublicTransportBus: return(30); } } } UnityEngine.Debug.LogWarning("IPT: Default capacity of item class [serrvice: " + service + ", sub service: " + subService + ", level: " + level + "] were requested. Defaults aren't supported."); return(0); }
public virtual BuildingInfo GetUpgradeInfo(ushort buildingID, ref Building data) { // This method is very fragile, no logging here! BuildingInfo info = data.Info; Randomizer randomizer = new Randomizer((int)buildingID); ItemClass.Level level = info.m_class.m_level + 1; /* * return Singleton<BuildingManager>.instance.GetRandomBuildingInfo(ref randomizer, info.m_class.m_service, * info.m_class.m_subService, level, data.Width, data.Length, info.m_zoningMode); */ return(BuildingManagerDetour.GetRandomBuildingInfo_Upgrade(data.m_position, data.m_infoIndex, ref randomizer, info.m_class.m_service, info.m_class.m_subService, level, data.Width, data.Length, info.m_zoningMode)); }
internal static void CalculateWorkplaceCount(ItemClass.Level level, RICOBuilding ricoData, IWorkplaceLevelCalculator ai, Randomizer r, int width, int length, out int level0, out int level1, out int level2, out int level3) { SetWorkplaceLevels(out level0, out level1, out level2, out level3, 0, 0, 0, 0); RICOBuilding rc = ricoData; if (rc != null) { // reality mod is running and the xml file says ignore-reality="false" if (rc.UseReality) { ai.CalculateBaseWorkplaceCount(level, r, width, length, out level0, out level1, out level2, out level3); } else { SetWorkplaceLevels(out level0, out level1, out level2, out level3, ricoData.Workplaces); } } }
public static void Postfix(Resource resource, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, ref int __result, ref bool __state) { if (!__state) { return; } ResourceCommandHandler.Queue(new EconomyResourceCommand() { Action = ResourceAction.FETCH, ResourceType = resource, ResourceAmount = __result, Service = service, SubService = subService, Level = level }); }
static bool Prefix(ref int __result, ResidentialBuildingAI __instance, ItemClass.Level level, Randomizer r, int width, int length) { BuildingInfo item = __instance.m_info; int returnValue = 0; if (!DataStore.prefabHouseHolds.TryGetValue(item.gameObject.GetHashCode(), out returnValue)) { int[] array = ResidentialBuildingAIMod.GetArray(__instance.m_info, (int)level); returnValue = AI_Utils.CalculatePrefabHousehold(width, length, ref item, ref array, (int)level); DataStore.prefabHouseHolds.Add(item.gameObject.GetHashCode(), returnValue); } // Original method return value. __result = returnValue; // Don't execute base method after this. return(false); }
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 = CommercialBuildingAIMod.GetArray(__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); }
public override void CalculateWorkplaceCount(ItemClass.Level level, Randomizer r, int width, int length, out int level0, out int level1, out int level2, out int level3) { BuildingInfo item = this.m_info; PrefabEmployStruct output; // If not seen prefab, calculate if (!DataStore.prefabWorkerVisit.TryGetValue(item.gameObject.GetHashCode(), out output)) { int[] array = getArray(item, EXTRACT_LEVEL); AI_Utils.CalculateprefabWorkerVisit(width, length, ref item, 3, ref array, out output); DataStore.prefabWorkerVisit.Add(item.gameObject.GetHashCode(), output); } level0 = output.level0; level1 = output.level1; level2 = output.level2; level3 = output.level3; }
private static VehicleInfo GetVehicleInfoForDepot( //only for taxi and cable cars - and only for 1 of 4 cases VehicleManager instance, ushort buildingID, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { if ( service != ItemClass.Service.PublicTransport || subService != ItemClass.SubService.PublicTransportTaxi && subService != ItemClass.SubService.PublicTransportCableCar || !SerializableDataExtension.BuildingData().TryGetValue(buildingID, out var source) || source.Count <= 0) { return(instance.GetRandomVehicleInfo(ref SimulationManager.instance.m_randomizer, service, subService, level)); } return(GetRandomVehicleInfoOverride(ref SimulationManager.instance.m_randomizer, service, subService, level, source.ToArray())); }
public override int CalculateProductionCapacity(ItemClass.Level level, Randomizer r, int width, int length) { ulong seed = r.seed; BuildingInfo item = this.m_info; PrefabEmployStruct worker; if (DataStore.prefabWorkerVisit.TryGetValue(item.gameObject.GetHashCode(), out worker)) { // Employment is available int workers = worker.level0 + worker.level1 + worker.level2 + worker.level3; int[] array = getArray(this.m_info, (int)level); return(Mathf.Max(1, workers / array[DataStore.PRODUCTION])); } else { // Return minimum to be safe return(1); } }
/// <summary> /// Returns a list of calculation packs available for the given prefab. /// </summary> /// <param name="prefab">BuildingInfo prefab</param> /// <returns>Array of available calculation packs</returns> internal SchoolDataPack[] GetPacks(BuildingInfo prefab) { // Return list. List <SchoolDataPack> list = new List <SchoolDataPack>(); ItemClass.Level level = prefab.GetClassLevel(); // Iterate through each floor pack and see if it applies. foreach (SchoolDataPack pack in calcPacks) { // Check for matching service. if (pack.level == level) { // Service matches; add pack. list.Add(pack); } } return(list.ToArray()); }
/// <summary> /// Calculates the workplaces for this building according to RICO settings. /// </summary> /// <param name="level">Building level</param> /// <param name="r">Randomizer</param> /// <param name="width">Building plot width (in cells)</param> /// <param name="length">Building plot length (in cells)</param> /// <param name="level0">The number of uneducated jobs</param> /// <param name="level1">The number of educated jobs</param> /// <param name="level2">The number of well-educated jobs</param> /// <param name="level3">The number of highly-educated jobs</param> public override void CalculateWorkplaceCount(ItemClass.Level level, Randomizer r, int width, int length, out int level0, out int level1, out int level2, out int level3) { // CalculateWorkplaceCount is called by the game every couple of seconds. Why? Who knows? // This makes it a potential performance bottleneck; thus, we cache results to save some CPU cycles. // Results are cached in workplaceCount. // Check to see if there's a cached value, and if so, use it. if (workplaceCount != null) { WorkplaceAIHelper.SetWorkplaceLevels(out level0, out level1, out level2, out level3, workplaceCount); } else { // If nothing is cached, then perform initial calculation. WorkplaceAIHelper.CalculateWorkplaceCount(level, m_ricoData, this, r, width, length, out level0, out level1, out level2, out level3); // Cache result. workplaceCount = new int[] { level0, level1, level2, level3 }; } }
public static void Postfix(Resource resource, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, DistrictPolicies.Taxation taxationPolicies, int amount, ref bool __state) { AddPrivateIncome.DontRunPatch = false; if (!__state) { return; } ResourceCommandHandler.Queue(new EconomyResourceCommand() { Action = ResourceAction.ADD, ResourceType = resource, ResourceAmount = amount, Service = service, SubService = subService, Level = level, Taxation = taxationPolicies }); }
private static VehicleInfo GetCargoVehicleInfo( VehicleManager instance, ushort cargoStation1, ushort cargoStation2, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { var infoFrom = BuildingManager.instance.m_buildings.m_buffer[cargoStation1].Info; if (infoFrom?.m_class?.name == ItemClasses.cargoFerryFacility.name) //to support Cargo Ferries { level = ItemClass.Level.Level5; } var vehicleInfo = instance.GetRandomVehicleInfo( ref Singleton <SimulationManager> .instance.m_randomizer, service, subService, level); if (vehicleInfo == null && infoFrom?.m_class?.name == ItemClasses.cargoFerryFacility.name) { UnityEngine.Debug.LogWarning("Barges: no barges found!"); } return(vehicleInfo); }
public override void GetConsumptionRates(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) { ItemClass item = this.m_info.m_class; int[] array = GetArray(this.m_info, (int)level); electricityConsumption = array[DataStore.POWER]; waterConsumption = array[DataStore.WATER]; sewageAccumulation = array[DataStore.SEWAGE]; garbageAccumulation = array[DataStore.GARBAGE]; mailAccumulation = array[DataStore.MAIL]; int landVal = AI_Utils.GetLandValueIncomeComponent(r.seed); incomeAccumulation = array[DataStore.INCOME] + landVal; 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; }
public static bool Prefix( ref Randomizer r, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, ref VehicleInfo __result) { if (!Settings.enableCustomVehicles) { return(true); } __result = VehicleManagerMod.GetRandomVehicleInfo(ref r, service, subService, level); if (__result == null) { return(true); } else { return(false); } }
public static VehicleInfo GetRandomVehicleInfo( ref Randomizer r, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, VehicleInfo.VehicleType type) { if (CurrentSourceBuilding == 0 || BuildingUseDefaultVehicles[CurrentSourceBuilding] || BuildingToVehicles[CurrentSourceBuilding] == null || BuildingToVehicles[CurrentSourceBuilding].Count == 0) { return(null); } /* * if (service == ItemClass.Service.PlayerIndustry) * { * service = ItemClass.Service.Industrial; * } * * var buildingInfo = BuildingManager.instance.m_buildings.m_buffer[CurrentSourceBuilding].Info; * var buildingService = buildingInfo.GetService(); * var buildingSubService = buildingInfo.GetSubService(); * if (buildingService != service || buildingSubService != subService) * { * return null; * } */ var vehicles = BuildingToVehicles[CurrentSourceBuilding].Where(index => PrefabCollection <VehicleInfo> .GetPrefab((uint)index)?.m_vehicleType == type).ToArray(); if (vehicles.Length == 0) { return(null); } int index1 = r.Int32((uint)vehicles.Length); var prefab = PrefabCollection <VehicleInfo> .GetPrefab((uint)vehicles[index1]); return(prefab); }
public override BuildingInfo GetUpgradeInfo(ushort buildingID, ref Building data) { if (this.m_info.m_class.m_level == ItemClass.Level.Level5) { return(null); } Randomizer randomizer = new Randomizer((int)buildingID); for (int i = 0; i <= (int)this.m_info.m_class.m_level; i++) { randomizer.Int32(1000u); } ItemClass.Level level = this.m_info.m_class.m_level + 1; DistrictManager instance = Singleton <DistrictManager> .instance; byte district = instance.GetDistrict(data.m_position); DistrictPolicies.CityPlanning cityPlanningPolicies = instance.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; highRiseBan = ((cityPlanningPolicies & DistrictPolicies.CityPlanning.HighriseBan) != DistrictPolicies.CityPlanning.None); ushort style = instance.m_districts.m_buffer[(int)district].m_Style; return(Singleton <BuildingManager> .instance.GetRandomBuildingInfo(ref randomizer, this.m_info.m_class.m_service, this.m_info.m_class.m_subService, level, data.Width, data.Length, this.m_info.m_zoningMode, (int)style)); }
static bool Prefix(IndustrialExtractorAI __instance, ItemClass.Level level, Randomizer r, int width, int length, out int level0, out int level1, out int level2, out int level3) { BuildingInfo item = __instance.m_info; PrefabEmployStruct output; // If not seen prefab, calculate if (!DataStore.prefabWorkerVisit.TryGetValue(item.gameObject.GetHashCode(), out output)) { int[] array = IndustrialExtractorAIMod.GetArray(item, IndustrialExtractorAIMod.EXTRACT_LEVEL); AI_Utils.CalculateprefabWorkerVisit(width, length, ref item, 3, ref array, out output); DataStore.prefabWorkerVisit.Add(item.gameObject.GetHashCode(), output); } level0 = output.level0; level1 = output.level1; level2 = output.level2; level3 = output.level3; // Don't execute base method after this. return(false); }
public static ushort GetCapacity(ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { if (service == ItemClass.Service.PublicTransport) { if (level == ItemClass.Level.Level1) { switch (subService) { case ItemClass.SubService.PublicTransportTram: case ItemClass.SubService.PublicTransportCableCar: case ItemClass.SubService.PublicTransportMonorail: case ItemClass.SubService.PublicTransportBus: case ItemClass.SubService.PublicTransportMetro: case ItemClass.SubService.PublicTransportTrain: return(30); case ItemClass.SubService.PublicTransportShip: return(100); case ItemClass.SubService.PublicTransportPlane: return(200); } } else if (level == ItemClass.Level.Level2) { switch (subService) { case ItemClass.SubService.PublicTransportPlane: return(35); case ItemClass.SubService.PublicTransportShip: return(50); } } } return(0); }
public int GetServiceThreshhold(ItemClass.Level level, ItemClass.Zone zone) { if (level == ItemClass.Level.None) { return(0); } ItemClass.Level maxLevel = ItemClass.Level.Level5; int multiplier = 0, start = 0; switch (zone) { case ItemClass.Zone.ResidentialLow: case ItemClass.Zone.ResidentialHigh: multiplier = 15; break; case ItemClass.Zone.CommercialLow: case ItemClass.Zone.CommercialHigh: start = 1; multiplier = 20; break; case ItemClass.Zone.Industrial: multiplier = 30; break; case ItemClass.Zone.Office: multiplier = 45; break; } if (level == maxLevel) { return(int.MaxValue); } return(((int)level + 1) * multiplier + start); }