From 10de5657df3d3bbedf57af8df469e538bb8e2875 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sat, 29 Aug 2020 18:09:38 +0800 Subject: [PATCH 01/38] Update --- CustomAI/RealCityCommercialBuildingAI.cs | 5 +- CustomAI/RealCityCommonBuildingAI.cs | 5 +- CustomAI/RealCityIndustrialBuildingAI.cs | 7 +- CustomAI/RealCityIndustrialExtractorAI.cs | 6 +- CustomAI/RealCityIndustryBuildingAI.cs | 26 +- CustomAI/RealCityMarketAI.cs | 5 +- CustomAI/RealCityPlayerBuildingAI.cs | 11 +- CustomAI/RealCityPrivateBuildingAI.cs | 226 +-- CustomAI/RealCityResidentAI.cs | 244 +-- CustomData/BuildingData.cs | 20 +- CustomData/CitizenData.cs | 26 +- CustomData/CitizenUnitData.cs | 20 +- CustomData/TransportLineData.cs | 20 +- CustomData/VehicleData.cs | 20 +- CustomManager/RealCityEconomyManager.cs | 25 +- Loader.cs | 861 ++++----- Patch/CargoTruckAIArriveAtTargetPatch.cs | 32 +- ...esidentAICitizenUnitSimulationStepPatch.cs | 1256 ++++++------- Properties/AssemblyInfo.cs | 4 +- RealCity.cs | 126 +- RealCity.csproj | 42 +- RealCityEconomyExtension.cs | 1645 ++++++++--------- RealCityThreading.cs | 362 ++-- RebalancedIndustries/Mod.cs | 48 +- RebalancedIndustries/RI_Data.cs | 81 +- RebalancedIndustries/RI_Detours.cs | 525 +++--- UI/BuildingButton.cs | 34 +- UI/BuildingUI.cs | 174 +- UI/EcnomicButton.cs | 64 +- UI/EcnomicUI.cs | 35 +- UI/HumanUI.cs | 55 +- UI/IncompatibleModsPanel.cs | 61 +- UI/OptionUI.cs | 92 +- UI/PBLUI.cs | 62 +- UI/PlayerBuildingButton.cs | 30 +- UI/PlayerBuildingUI.cs | 35 +- UI/PoliticsButton.cs | 67 +- UI/PoliticsUI.cs | 69 +- UI/RealCityButton.cs | 67 +- UI/RealCityUI.cs | 169 +- UI/TouristUI.cs | 28 +- Util/DebugLog.cs | 22 +- Util/FastDelegateFactory.cs | 124 +- Util/HarmonyDetours.cs | 34 +- Util/Localization.cs | 67 +- Util/MainDataStore.cs | 450 +++-- Util/ModsCompatibilityChecker.cs | 122 +- Util/Politics.cs | 545 +++--- Util/SaveAndRestore.cs | 992 +++++----- Util/SpriteUtilities.cs | 327 ++-- .../RealCity.csproj.FileListAbsolute.txt | 0 51 files changed, 4037 insertions(+), 5336 deletions(-) create mode 100644 obj/Debug/RealCity.csproj.FileListAbsolute.txt diff --git a/CustomAI/RealCityCommercialBuildingAI.cs b/CustomAI/RealCityCommercialBuildingAI.cs index ab96ffd..06f2216 100644 --- a/CustomAI/RealCityCommercialBuildingAI.cs +++ b/CustomAI/RealCityCommercialBuildingAI.cs @@ -15,8 +15,7 @@ public class RealCityCommercialBuildingAI public delegate void CommercialBuildingAIGetVisitBehaviour(CommercialBuildingAI CommercialBuildingAI, ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount); public static CommercialBuildingAIGetVisitBehaviour GetVisitBehaviour; - public static void InitDelegate() - { + public static void InitDelegate() { if (GetIncomingTransferReason != null) return; if (MaxIncomingLoadSize != null) @@ -28,4 +27,4 @@ public static void InitDelegate() MaxIncomingLoadSize = FastDelegateFactory.Create(typeof(CommercialBuildingAI), "MaxIncomingLoadSize", instanceMethod: true); } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityCommonBuildingAI.cs b/CustomAI/RealCityCommonBuildingAI.cs index 4c8f0fa..c499b12 100644 --- a/CustomAI/RealCityCommonBuildingAI.cs +++ b/CustomAI/RealCityCommonBuildingAI.cs @@ -20,8 +20,7 @@ public class RealCityCommonBuildingAI public delegate void CommonBuildingAIGetWorkBehaviour(CommonBuildingAI CommonBuildingAI, ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount); public static CommonBuildingAIGetWorkBehaviour GetWorkBehaviour; - public static void InitDelegate() - { + public static void InitDelegate() { if (CalculateOwnVehicles != null) return; if (GetWorkBehaviour != null) @@ -36,4 +35,4 @@ public static void InitDelegate() CalculateGuestVehicles1 = FastDelegateFactory.Create(typeof(CommonBuildingAI), "CalculateGuestVehicles", instanceMethod: true); } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityIndustrialBuildingAI.cs b/CustomAI/RealCityIndustrialBuildingAI.cs index 157f0da..a006175 100644 --- a/CustomAI/RealCityIndustrialBuildingAI.cs +++ b/CustomAI/RealCityIndustrialBuildingAI.cs @@ -19,12 +19,11 @@ public class RealCityIndustrialBuildingAI public delegate int IndustrialBuildingAIMaxIncomingLoadSize(IndustrialBuildingAI IndustrialBuildingAI); public static IndustrialBuildingAIMaxIncomingLoadSize MaxIncomingLoadSize; - + public delegate int IndustrialBuildingAIGetConsumptionDivider(IndustrialBuildingAI IndustrialBuildingAI); public static IndustrialBuildingAIGetConsumptionDivider GetConsumptionDivider; - public static void InitDelegate() - { + public static void InitDelegate() { if (GetIncomingTransferReason != null) return; if (GetOutgoingTransferReason != null) @@ -42,4 +41,4 @@ public static void InitDelegate() GetConsumptionDivider = FastDelegateFactory.Create(typeof(IndustrialBuildingAI), "GetConsumptionDivider", instanceMethod: true); } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityIndustrialExtractorAI.cs b/CustomAI/RealCityIndustrialExtractorAI.cs index 218c140..5c43389 100644 --- a/CustomAI/RealCityIndustrialExtractorAI.cs +++ b/CustomAI/RealCityIndustrialExtractorAI.cs @@ -7,12 +7,10 @@ public class RealCityIndustrialExtractorAI public delegate TransferManager.TransferReason IndustrialExtractorAIGetOutgoingTransferReason(IndustrialExtractorAI IndustrialExtractorAI); public static IndustrialExtractorAIGetOutgoingTransferReason GetOutgoingTransferReason; - public static void InitDelegate() - { + public static void InitDelegate() { if (GetOutgoingTransferReason != null) return; GetOutgoingTransferReason = FastDelegateFactory.Create(typeof(IndustrialExtractorAI), "GetOutgoingTransferReason", instanceMethod: true); } } -} - +} \ No newline at end of file diff --git a/CustomAI/RealCityIndustryBuildingAI.cs b/CustomAI/RealCityIndustryBuildingAI.cs index 1ae7b3e..2c27fd7 100644 --- a/CustomAI/RealCityIndustryBuildingAI.cs +++ b/CustomAI/RealCityIndustryBuildingAI.cs @@ -5,48 +5,41 @@ namespace RealCity.CustomAI { public class RealCityIndustryBuildingAI { - public static float GetResourcePrice(TransferManager.TransferReason material) - { + public static float GetResourcePrice(TransferManager.TransferReason material) { int priceInt = 0; float price; - switch (material) - { + switch (material) { case TransferManager.TransferReason.Goods: price = 3.5f; - if (RealCity.reduceVehicle) - { + if (RealCity.reduceVehicle) { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Petrol: price = 3f; - if (RealCity.reduceVehicle) - { + if (RealCity.reduceVehicle) { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Food: price = 1.5f; - if (RealCity.reduceVehicle) - { + if (RealCity.reduceVehicle) { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Lumber: price = 2f; - if (RealCity.reduceVehicle) - { + if (RealCity.reduceVehicle) { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Coal: price = 2.5f; - if (RealCity.reduceVehicle) - { + if (RealCity.reduceVehicle) { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); @@ -58,8 +51,7 @@ public static float GetResourcePrice(TransferManager.TransferReason material) case TransferManager.TransferReason.ShoppingE: case TransferManager.TransferReason.ShoppingH: price = 5f; - if (RealCity.reduceVehicle) - { + if (RealCity.reduceVehicle) { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); @@ -76,4 +68,4 @@ public static float GetResourcePrice(TransferManager.TransferReason material) return price; } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityMarketAI.cs b/CustomAI/RealCityMarketAI.cs index 1026985..c512dd4 100644 --- a/CustomAI/RealCityMarketAI.cs +++ b/CustomAI/RealCityMarketAI.cs @@ -9,11 +9,10 @@ public class RealCityMarketAI public delegate void MarketAIGetVisitBehaviour(MarketAI MarketAI, ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount); public static MarketAIGetVisitBehaviour GetVisitBehaviour; - public static void InitDelegate() - { + public static void InitDelegate() { if (GetVisitBehaviour != null) return; GetVisitBehaviour = FastDelegateFactory.Create(typeof(MarketAI), "GetVisitBehaviour", instanceMethod: true); } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityPlayerBuildingAI.cs b/CustomAI/RealCityPlayerBuildingAI.cs index 2f7f186..14a7073 100644 --- a/CustomAI/RealCityPlayerBuildingAI.cs +++ b/CustomAI/RealCityPlayerBuildingAI.cs @@ -7,8 +7,7 @@ namespace RealCity.CustomAI { public class RealCityPlayerBuildingAI { - public static float CaculateEmployeeOutcome(ushort buildingID, Building building) - { + public static float CaculateEmployeeOutcome(ushort buildingID, Building building) { float allSalary = 0; Citizen.BehaviourData behaviour = default(Citizen.BehaviourData); int aliveWorkerCount = 0; @@ -25,13 +24,11 @@ public static float CaculateEmployeeOutcome(ushort buildingID, Building building allSalary += behaviour.m_educated2Count * education2Salary; allSalary += behaviour.m_educated3Count * education3Salary; int allWorkCount = RealCityResidentAI.TotalWorkCount(buildingID, building, true, false); - if (totalWorkerCount > allWorkCount) - { + if (totalWorkerCount > allWorkCount) { allWorkCount = RealCityResidentAI.TotalWorkCount(buildingID, building, true, true); } - if ((aliveWorkerCount == 0) && (allWorkCount != 0)) - { + if ((aliveWorkerCount == 0) && (allWorkCount != 0)) { allSalary = education3Salary * allWorkCount; } @@ -39,4 +36,4 @@ public static float CaculateEmployeeOutcome(ushort buildingID, Building building return allSalary * outsideWorkerRatio / 16f; } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityPrivateBuildingAI.cs b/CustomAI/RealCityPrivateBuildingAI.cs index 83fe065..259ece3 100644 --- a/CustomAI/RealCityPrivateBuildingAI.cs +++ b/CustomAI/RealCityPrivateBuildingAI.cs @@ -27,8 +27,7 @@ public class RealCityPrivateBuildingAI public static ushort profitBuildingCountFinal = 0; public static ushort allBuildingsFinal = 0; - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { //60 int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref preBuidlingId); @@ -49,14 +48,12 @@ public static void Load(ref byte[] saveData) SaveAndRestore.LoadData(ref i, saveData, ref profitBuildingCount); SaveAndRestore.LoadData(ref i, saveData, ref profitBuildingCountFinal); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"RealCityPrivateBuildingAI Load Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { //60 int i = 0; SaveAndRestore.SaveData(ref i, preBuidlingId, ref saveData); @@ -77,22 +74,16 @@ public static void Save(ref byte[] saveData) SaveAndRestore.SaveData(ref i, profitBuildingCount, ref saveData); SaveAndRestore.SaveData(ref i, profitBuildingCountFinal, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"RealCityPrivateBuildingAI Save Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static TransferManager.TransferReason GetIncomingProductionType(ushort buildingID, Building data) - { + public static TransferManager.TransferReason GetIncomingProductionType(ushort buildingID, Building data) { RealCityIndustrialBuildingAI.InitDelegate(); - if (data.Info.m_buildingAI is IndustrialExtractorAI) - { - } - else - { - switch (data.Info.m_class.m_subService) - { + if (data.Info.m_buildingAI is IndustrialExtractorAI) { + } else { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialEco: @@ -111,27 +102,20 @@ public static TransferManager.TransferReason GetIncomingProductionType(ushort bu return TransferManager.TransferReason.None; } - public static string GetProductionType(bool isSelling, ushort buildingID, Building data) - { + public static string GetProductionType(bool isSelling, ushort buildingID, Building data) { RealCityIndustrialBuildingAI.InitDelegate(); string material = ""; - if (!isSelling) - { - if (data.Info.m_buildingAI is IndustrialExtractorAI) - { - } - else - { - switch (data.Info.m_class.m_subService) - { + if (!isSelling) { + if (data.Info.m_buildingAI is IndustrialExtractorAI) { + } else { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialEco: case ItemClass.SubService.CommercialLeisure: case ItemClass.SubService.CommercialTourist: CommercialBuildingAI commercialBuildingAI = data.Info.m_buildingAI as CommercialBuildingAI; - switch (commercialBuildingAI.m_incomingResource) - { + switch (commercialBuildingAI.m_incomingResource) { case TransferManager.TransferReason.Goods: material = Localization.Get("PREGOODS") + Localization.Get("LUXURY_PRODUCTS"); break; case TransferManager.TransferReason.Food: @@ -155,8 +139,7 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi case ItemClass.SubService.IndustrialFarming: case ItemClass.SubService.IndustrialOil: case ItemClass.SubService.IndustrialOre: - switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) - { + switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { case TransferManager.TransferReason.Grain: material = Localization.Get("GRAIN_MEAT"); break; case TransferManager.TransferReason.Logs: @@ -169,8 +152,7 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi } break; case ItemClass.SubService.IndustrialGeneric: - switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) - { + switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { case TransferManager.TransferReason.Food: material = Localization.Get("FOOD"); break; case TransferManager.TransferReason.Lumber: @@ -181,8 +163,7 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi material = Localization.Get("COAL"); break; default: break; } - switch (RealCityIndustrialBuildingAI.GetSecondaryIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) - { + switch (RealCityIndustrialBuildingAI.GetSecondaryIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { case TransferManager.TransferReason.AnimalProducts: material += Localization.Get("ANIMALPRODUCTS"); break; case TransferManager.TransferReason.Flours: @@ -206,13 +187,9 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi material = ""; break; } } - } - else - { - if (data.Info.m_buildingAI is IndustrialExtractorAI) - { - switch (data.Info.m_class.m_subService) - { + } else { + if (data.Info.m_buildingAI is IndustrialExtractorAI) { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.IndustrialForestry: material = Localization.Get("LOG"); break; case ItemClass.SubService.IndustrialFarming: @@ -224,11 +201,8 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi default: material = ""; break; } - } - else - { - switch (data.Info.m_class.m_subService) - { + } else { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.IndustrialForestry: material = Localization.Get("LUMBER"); break; case ItemClass.SubService.IndustrialFarming: @@ -253,29 +227,22 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi return material; } - public static float GetPrice(bool isSelling, ushort buildingID, Building data) - { + public static float GetPrice(bool isSelling, ushort buildingID, Building data) { RealCityIndustrialBuildingAI.InitDelegate(); float price = 0f; - if (!isSelling) - { - if (!(data.Info.m_buildingAI is IndustrialExtractorAI)) - { - switch (data.Info.m_class.m_subService) - { + if (!isSelling) { + if (!(data.Info.m_buildingAI is IndustrialExtractorAI)) { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialEco: case ItemClass.SubService.CommercialLeisure: case ItemClass.SubService.CommercialTourist: CommercialBuildingAI commercialBuildingAI = data.Info.m_buildingAI as CommercialBuildingAI; - if (commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Food || commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Goods) - { + if (commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Food || commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Goods) { //SecondaryIncoming : FirstIncoming = 1:3 price = (3f * RealCityIndustryBuildingAI.GetResourcePrice(commercialBuildingAI.m_incomingResource) + (RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.LuxuryProducts))) / 4f; - } - else - { + } else { price = RealCityIndustryBuildingAI.GetResourcePrice(commercialBuildingAI.m_incomingResource); } break; @@ -296,13 +263,9 @@ public static float GetPrice(bool isSelling, ushort buildingID, Building data) price = 0; break; } } - } - else - { - if (data.Info.m_buildingAI is IndustrialExtractorAI) - { - switch (data.Info.m_class.m_subService) - { + } else { + if (data.Info.m_buildingAI is IndustrialExtractorAI) { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.IndustrialForestry: price = RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Logs); break; case ItemClass.SubService.IndustrialFarming: @@ -314,11 +277,8 @@ public static float GetPrice(bool isSelling, ushort buildingID, Building data) default: price = 0; break; } - } - else - { - switch (data.Info.m_class.m_subService) - { + } else { + switch (data.Info.m_class.m_subService) { case ItemClass.SubService.IndustrialForestry: price = RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Lumber); break; case ItemClass.SubService.IndustrialFarming: @@ -343,55 +303,41 @@ public static float GetPrice(bool isSelling, ushort buildingID, Building data) return price; } - public static int GetTaxRate(Building data) - { - if (data.Info.m_class.m_service == ItemClass.Service.Commercial) - { + public static int GetTaxRate(Building data) { + if (data.Info.m_class.m_service == ItemClass.Service.Commercial) { return Politics.commercialTax; - } - else if (data.Info.m_class.m_service == ItemClass.Service.Industrial) - { + } else if (data.Info.m_class.m_service == ItemClass.Service.Industrial) { return Politics.industryTax; } return 0; } - public static float GetComsumptionDivider(Building data, ushort buildingID) - { + public static float GetComsumptionDivider(Building data, ushort buildingID) { Citizen.BehaviourData behaviourData = default; int aliveWorkerCount = 0; int totalWorkerCount = 0; RealCityCommonBuildingAI.GetWorkBehaviour((CommonBuildingAI)data.Info.m_buildingAI, buildingID, ref data, ref behaviourData, ref aliveWorkerCount, ref totalWorkerCount); float comsumptionDivider = aliveWorkerCount / 8f; - if (comsumptionDivider < 1f) - { + if (comsumptionDivider < 1f) { comsumptionDivider = 1f; } - if (data.Info.m_class.m_service == ItemClass.Service.Industrial) - { + if (data.Info.m_class.m_service == ItemClass.Service.Industrial) { RealCityIndustrialBuildingAI.InitDelegate(); var incomingTransferReason = RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)data.Info.m_buildingAI, buildingID); //petrol related - if (incomingTransferReason == TransferManager.TransferReason.Petrol) - { + if (incomingTransferReason == TransferManager.TransferReason.Petrol) { //*2 / 4 comsumptionDivider /= 2f; - } - else if (incomingTransferReason == TransferManager.TransferReason.Coal) - { + } else if (incomingTransferReason == TransferManager.TransferReason.Coal) { //*1.67 / 4 comsumptionDivider /= 2.4f; - } - else if (incomingTransferReason == TransferManager.TransferReason.Lumber) - { + } else if (incomingTransferReason == TransferManager.TransferReason.Lumber) { //*1.33 / 4 comsumptionDivider /= 3f; - } - else if (incomingTransferReason == TransferManager.TransferReason.Food) - { + } else if (incomingTransferReason == TransferManager.TransferReason.Food) { comsumptionDivider /= 4f; } } @@ -399,91 +345,62 @@ public static float GetComsumptionDivider(Building data, ushort buildingID) return comsumptionDivider; } - public static void ProcessAdditionProduct(ushort buildingID, ref Building buildingData, ref ushort[] __state, bool is16Times = true) - { + public static void ProcessAdditionProduct(ushort buildingID, ref Building buildingData, ref ushort[] __state, bool is16Times = true) { //add production pre 16times byte shift = 0; - if (is16Times) - { + if (is16Times) { shift = 4; } - if ((RealCityEconomyExtension.Can16timesUpdate(buildingID)) || (!is16Times)) - { + if ((RealCityEconomyExtension.Can16timesUpdate(buildingID)) || (!is16Times)) { float comsumptionDivider = GetComsumptionDivider(buildingData, buildingID); int deltaCustomBuffer1 = __state[0] - buildingData.m_customBuffer1; - if (deltaCustomBuffer1 > 0) - { - if (RealCity.reduceVehicle) - { - if (!Singleton.instance.m_isNightTime) - { + if (deltaCustomBuffer1 > 0) { + if (RealCity.reduceVehicle) { + if (!Singleton.instance.m_isNightTime) { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)(deltaCustomBuffer1 / (comsumptionDivider * MainDataStore.reduceCargoDiv)) << shift)); - } - else - { + } else { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)(deltaCustomBuffer1 / comsumptionDivider) << shift)); } - } - else - { - if (!Singleton.instance.m_isNightTime) - { + } else { + if (!Singleton.instance.m_isNightTime) { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)(deltaCustomBuffer1 / comsumptionDivider) << shift)); - } - else - { + } else { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)((deltaCustomBuffer1 << 1) / comsumptionDivider) << shift)); } } } int deltaCustomBuffer2 = buildingData.m_customBuffer2 - __state[1]; - if (deltaCustomBuffer2 > 0) - { - if (RealCity.reduceVehicle) - { - if (!Singleton.instance.m_isNightTime) - { + if (deltaCustomBuffer2 > 0) { + if (RealCity.reduceVehicle) { + if (!Singleton.instance.m_isNightTime) { buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + ((deltaCustomBuffer2 >> MainDataStore.reduceCargoDivShift) << shift)); - } - else - { + } else { //NightTime 2x , reduceVehicle 1/2, so do nothing buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + (((int)(deltaCustomBuffer2 / (float)MainDataStore.reduceCargoDiv) << 1) << shift)); } - } - else - { - if (!Singleton.instance.m_isNightTime) - { + } else { + if (!Singleton.instance.m_isNightTime) { buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + (deltaCustomBuffer2 << shift)); - } - else - { + } else { buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + ((deltaCustomBuffer2 << MainDataStore.reduceCargoDivShift) << shift)); //buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 + (deltaCustomBuffer2 << 4)); } } } - } - else - { + } else { //DebugLog.LogToFileOnly($"Process buildingID outside 16times = {buildingID}"); buildingData.m_customBuffer1 = (ushort)Mathf.Clamp(__state[0], 0, 64000); buildingData.m_customBuffer2 = (ushort)Mathf.Clamp(__state[1], 0, 64000); } } - public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[] __state) - { + public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[] __state) { int deltaCustomBuffer1 = buildingData.m_customBuffer1 - __state[0]; - if (deltaCustomBuffer1 > 0) - { - if (RealCity.reduceVehicle) - { - if (!Singleton.instance.m_isNightTime) - { + if (deltaCustomBuffer1 > 0) { + if (RealCity.reduceVehicle) { + if (!Singleton.instance.m_isNightTime) { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + (deltaCustomBuffer1 >> MainDataStore.reduceCargoDivShift)); } //else @@ -491,15 +408,10 @@ public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[ //NightTime 2x , reduceVehicle 1/2, so do nothing //buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + (deltaCustomBuffer1 / (float)MainDataStore.reduceCargoDiv) * 2f); //} - } - else - { - if (!Singleton.instance.m_isNightTime) - { + } else { + if (!Singleton.instance.m_isNightTime) { //buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + deltaCustomBuffer1); - } - else - { + } else { //buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + 2 * deltaCustomBuffer1); buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1); } @@ -507,4 +419,4 @@ public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[ } } } -} +} \ No newline at end of file diff --git a/CustomAI/RealCityResidentAI.cs b/CustomAI/RealCityResidentAI.cs index 4bfc468..c00b218 100644 --- a/CustomAI/RealCityResidentAI.cs +++ b/CustomAI/RealCityResidentAI.cs @@ -21,8 +21,7 @@ public static class RealCityResidentAI public static uint familyWeightStableHigh = 0; public static uint familyWeightStableLow = 0; - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref preCitizenId); SaveAndRestore.LoadData(ref i, saveData, ref familyCount); @@ -37,14 +36,12 @@ public static void Load(ref byte[] saveData) SaveAndRestore.LoadData(ref i, saveData, ref familyWeightStableLow); SaveAndRestore.LoadData(ref i, saveData, ref citizenCount); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"RealCityResidentAI Load Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { int i = 0; //48 @@ -61,18 +58,15 @@ public static void Save(ref byte[] saveData) SaveAndRestore.SaveData(ref i, familyWeightStableLow, ref saveData); SaveAndRestore.SaveData(ref i, citizenCount, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"RealCityResidentAI Save Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static bool IsGoverment(ushort buildingID) - { + public static bool IsGoverment(ushort buildingID) { bool isGoverment = false; Building buildingData = Singleton.instance.m_buildings.m_buffer[buildingID]; - switch (buildingData.Info.m_class.m_service) - { + switch (buildingData.Info.m_class.m_service) { case ItemClass.Service.Disaster: case ItemClass.Service.PoliceDepartment: case ItemClass.Service.Education: @@ -95,33 +89,24 @@ public static bool IsGoverment(ushort buildingID) return isGoverment; } - public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) - { + public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { int salary = 0; - if (citizenId != 0u) - { + if (citizenId != 0u) { Citizen.Flags citizenFlag = Singleton.instance.m_citizens.m_buffer[citizenId].m_flags; - if ((citizenFlag & Citizen.Flags.Student) != Citizen.Flags.None) - { + if ((citizenFlag & Citizen.Flags.Student) != Citizen.Flags.None) { return salary; } ushort workBuilding = Singleton.instance.m_citizens.m_buffer[citizenId].m_workBuilding; - if (workBuilding != 0u) - { + if (workBuilding != 0u) { Building buildingData = Singleton.instance.m_buildings.m_buffer[workBuilding]; - if (!IsGoverment(workBuilding)) - { + if (!IsGoverment(workBuilding)) { salary = BuildingData.buildingWorkCount[workBuilding]; - if (!checkOnly) - { - if (buildingData.Info.m_class.m_service != ItemClass.Service.Office) - { + if (!checkOnly) { + if (buildingData.Info.m_class.m_service != ItemClass.Service.Office) { BuildingData.buildingMoney[workBuilding] -= salary; } } - } - else - { + } else { //Goverment int aliveWorkCount = 0; int totalWorkCount = 0; @@ -129,8 +114,7 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) RealCityCommonBuildingAI.InitDelegate(); RealCityCommonBuildingAI.GetWorkBehaviour((CommonBuildingAI)buildingData.Info.m_buildingAI, workBuilding, ref buildingData, ref behaviour, ref aliveWorkCount, ref totalWorkCount); int salaryMax = 0; - switch (Singleton.instance.m_citizens.m_buffer[citizenId].EducationLevel) - { + switch (Singleton.instance.m_citizens.m_buffer[citizenId].EducationLevel) { case Citizen.Education.Uneducated: salaryMax = (int)(MainDataStore.govermentSalary * 0.5); salary = MainDataStore.govermentEducation0SalaryFixed; break; @@ -149,8 +133,7 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) //If a building have 10 workers and have 100 workplacecount, we assume that the other 90 vitual workers are from outside //Which will give addition cost allWorkCount = TotalWorkCount(workBuilding, buildingData, false, false); - if (totalWorkCount > allWorkCount) - { + if (totalWorkCount > allWorkCount) { Singleton.instance.m_citizens.m_buffer[citizenId].SetWorkplace(citizenId, 0, 0u); } float vitualWorkersRatio = (totalWorkCount != 0) ? (allWorkCount / (float)totalWorkCount) : 1f; @@ -163,8 +146,7 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) DebugLog.LogToFileOnly("DebugInfo: LandPrice offset for Salary is " + landPriceOffset.ToString()); #endif salary = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, salary); - if (!checkOnly) - { + if (!checkOnly) { var m_class = Singleton.instance.m_buildings.m_buffer[workBuilding].Info.m_class; Singleton.instance.FetchResource((EconomyManager.Resource)16, (int)(salary * vitualWorkersRatio), m_class); MainDataStore.outsideTouristMoney += (salary * (vitualWorkersRatio - 1f) * MainDataStore.outsideTouristSalaryProfitRatio); @@ -176,238 +158,146 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) return salary; }//public - public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnly, bool update) - { + public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnly, bool update) { int totalWorkCount = 0; //For performance #if FASTRUN update = false; #endif - if (BuildingData.isBuildingWorkerUpdated[buildingID] && !update) - { + if (BuildingData.isBuildingWorkerUpdated[buildingID] && !update) { totalWorkCount = BuildingData.buildingWorkCount[buildingID]; - } - else - { - if (data.Info.m_buildingAI is LandfillSiteAI) - { + } else { + if (data.Info.m_buildingAI is LandfillSiteAI) { LandfillSiteAI buildingAI = data.Info.m_buildingAI as LandfillSiteAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is ExtractingFacilityAI) - { + } else if (data.Info.m_buildingAI is ExtractingFacilityAI) { ExtractingFacilityAI buildingAI = data.Info.m_buildingAI as ExtractingFacilityAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is ProcessingFacilityAI) - { + } else if (data.Info.m_buildingAI is ProcessingFacilityAI) { ProcessingFacilityAI buildingAI = data.Info.m_buildingAI as ProcessingFacilityAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is PoliceStationAI) - { + } else if (data.Info.m_buildingAI is PoliceStationAI) { PoliceStationAI buildingAI = data.Info.m_buildingAI as PoliceStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is FireStationAI) - { + } else if (data.Info.m_buildingAI is FireStationAI) { FireStationAI buildingAI = data.Info.m_buildingAI as FireStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is HospitalAI) - { + } else if (data.Info.m_buildingAI is HospitalAI) { HospitalAI buildingAI = data.Info.m_buildingAI as HospitalAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is CargoStationAI) - { + } else if (data.Info.m_buildingAI is CargoStationAI) { CargoStationAI buildingAI = data.Info.m_buildingAI as CargoStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is TransportStationAI) - { + } else if (data.Info.m_buildingAI is TransportStationAI) { TransportStationAI buildingAI = data.Info.m_buildingAI as TransportStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is CemeteryAI) - { + } else if (data.Info.m_buildingAI is CemeteryAI) { CemeteryAI buildingAI = data.Info.m_buildingAI as CemeteryAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MedicalCenterAI) - { + } else if (data.Info.m_buildingAI is MedicalCenterAI) { MedicalCenterAI buildingAI = data.Info.m_buildingAI as MedicalCenterAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MonumentAI) - { + } else if (data.Info.m_buildingAI is MonumentAI) { MonumentAI buildingAI = data.Info.m_buildingAI as MonumentAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is DepotAI) - { + } else if (data.Info.m_buildingAI is DepotAI) { DepotAI buildingAI = data.Info.m_buildingAI as DepotAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is HelicopterDepotAI) - { + } else if (data.Info.m_buildingAI is HelicopterDepotAI) { HelicopterDepotAI buildingAI = data.Info.m_buildingAI as HelicopterDepotAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MaintenanceDepotAI) - { + } else if (data.Info.m_buildingAI is MaintenanceDepotAI) { MaintenanceDepotAI buildingAI = data.Info.m_buildingAI as MaintenanceDepotAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is FirewatchTowerAI) - { + } else if (data.Info.m_buildingAI is FirewatchTowerAI) { FirewatchTowerAI buildingAI = data.Info.m_buildingAI as FirewatchTowerAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is DoomsdayVaultAI) - { + } else if (data.Info.m_buildingAI is DoomsdayVaultAI) { DoomsdayVaultAI buildingAI = data.Info.m_buildingAI as DoomsdayVaultAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is DisasterResponseBuildingAI) - { + } else if (data.Info.m_buildingAI is DisasterResponseBuildingAI) { DisasterResponseBuildingAI buildingAI = data.Info.m_buildingAI as DisasterResponseBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is HadronColliderAI) - { + } else if (data.Info.m_buildingAI is HadronColliderAI) { HadronColliderAI buildingAI = data.Info.m_buildingAI as HadronColliderAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is SchoolAI) - { + } else if (data.Info.m_buildingAI is SchoolAI) { SchoolAI buildingAI = data.Info.m_buildingAI as SchoolAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is PowerPlantAI) - { + } else if (data.Info.m_buildingAI is PowerPlantAI) { PowerPlantAI buildingAI = data.Info.m_buildingAI as PowerPlantAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is SnowDumpAI) - { + } else if (data.Info.m_buildingAI is SnowDumpAI) { SnowDumpAI buildingAI = data.Info.m_buildingAI as SnowDumpAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is WarehouseAI) - { + } else if (data.Info.m_buildingAI is WarehouseAI) { WarehouseAI buildingAI = data.Info.m_buildingAI as WarehouseAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is WaterFacilityAI) - { + } else if (data.Info.m_buildingAI is WaterFacilityAI) { WaterFacilityAI buildingAI = data.Info.m_buildingAI as WaterFacilityAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is SaunaAI) - { + } else if (data.Info.m_buildingAI is SaunaAI) { SaunaAI buildingAI = data.Info.m_buildingAI as SaunaAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is PostOfficeAI) - { + } else if (data.Info.m_buildingAI is PostOfficeAI) { PostOfficeAI buildingAI = data.Info.m_buildingAI as PostOfficeAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is RadioMastAI) - { + } else if (data.Info.m_buildingAI is RadioMastAI) { RadioMastAI buildingAI = data.Info.m_buildingAI as RadioMastAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is SpaceElevatorAI) - { + } else if (data.Info.m_buildingAI is SpaceElevatorAI) { SpaceElevatorAI buildingAI = data.Info.m_buildingAI as SpaceElevatorAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is SpaceRadarAI) - { + } else if (data.Info.m_buildingAI is SpaceRadarAI) { SpaceRadarAI buildingAI = data.Info.m_buildingAI as SpaceRadarAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MainIndustryBuildingAI) - { + } else if (data.Info.m_buildingAI is MainIndustryBuildingAI) { MainIndustryBuildingAI buildingAI = data.Info.m_buildingAI as MainIndustryBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is AuxiliaryBuildingAI) - { + } else if (data.Info.m_buildingAI is AuxiliaryBuildingAI) { AuxiliaryBuildingAI buildingAI = data.Info.m_buildingAI as AuxiliaryBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is ShelterAI) - { + } else if (data.Info.m_buildingAI is ShelterAI) { ShelterAI buildingAI = data.Info.m_buildingAI as ShelterAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is HeatingPlantAI) - { + } else if (data.Info.m_buildingAI is HeatingPlantAI) { HeatingPlantAI buildingAI = data.Info.m_buildingAI as HeatingPlantAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MainCampusBuildingAI) - { + } else if (data.Info.m_buildingAI is MainCampusBuildingAI) { MainCampusBuildingAI buildingAI = data.Info.m_buildingAI as MainCampusBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MuseumAI) - { + } else if (data.Info.m_buildingAI is MuseumAI) { MuseumAI buildingAI = data.Info.m_buildingAI as MuseumAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is UniqueFactoryAI) - { + } else if (data.Info.m_buildingAI is UniqueFactoryAI) { UniqueFactoryAI buildingAI = data.Info.m_buildingAI as UniqueFactoryAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is UniqueFacultyAI) - { + } else if (data.Info.m_buildingAI is UniqueFacultyAI) { UniqueFacultyAI buildingAI = data.Info.m_buildingAI as UniqueFacultyAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is VarsitySportsArenaAI) - { + } else if (data.Info.m_buildingAI is VarsitySportsArenaAI) { VarsitySportsArenaAI buildingAI = data.Info.m_buildingAI as VarsitySportsArenaAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is LibraryAI) - { + } else if (data.Info.m_buildingAI is LibraryAI) { LibraryAI buildingAI = data.Info.m_buildingAI as LibraryAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is FishFarmAI) - { + } else if (data.Info.m_buildingAI is FishFarmAI) { FishFarmAI buildingAI = data.Info.m_buildingAI as FishFarmAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is FishingHarborAI) - { + } else if (data.Info.m_buildingAI is FishingHarborAI) { FishingHarborAI buildingAI = data.Info.m_buildingAI as FishingHarborAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is EldercareAI) - { + } else if (data.Info.m_buildingAI is EldercareAI) { EldercareAI buildingAI = data.Info.m_buildingAI as EldercareAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is ChildcareAI) - { + } else if (data.Info.m_buildingAI is ChildcareAI) { ChildcareAI buildingAI = data.Info.m_buildingAI as ChildcareAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else if (data.Info.m_buildingAI is MarketAI) - { + } else if (data.Info.m_buildingAI is MarketAI) { MarketAI buildingAI = data.Info.m_buildingAI as MarketAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } - else - { - if (!checkOnly) - { + } else { + if (!checkOnly) { DebugLog.LogToFileOnly("Error: find unknow building = " + data.Info.m_buildingAI.ToString()); } } @@ -416,6 +306,6 @@ public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnl BuildingData.buildingWorkCount[buildingID] = totalWorkCount; } return totalWorkCount; - } + } } -} +} \ No newline at end of file diff --git a/CustomData/BuildingData.cs b/CustomData/BuildingData.cs index 396ca59..dd27deb 100644 --- a/CustomData/BuildingData.cs +++ b/CustomData/BuildingData.cs @@ -15,10 +15,8 @@ public class BuildingData public static ushort commBuildingNumFinal = 0; - public static void DataInit() - { - for (int i = 0; i < buildingWorkCount.Length; i++) - { + public static void DataInit() { + for (int i = 0; i < buildingWorkCount.Length; i++) { buildingMoney[i] = 0; buildingWorkCount[i] = 0; isBuildingWorkerUpdated[i] = false; @@ -27,31 +25,27 @@ public static void DataInit() } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { //442368 int i = 0; SaveAndRestore.SaveData(ref i, buildingMoney, ref saveData); SaveAndRestore.SaveData(ref i, buildingWorkCount, ref saveData); SaveAndRestore.SaveData(ref i, isBuildingWorkerUpdated, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"BuildingData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref buildingMoney); SaveAndRestore.LoadData(ref i, saveData, ref buildingWorkCount); SaveAndRestore.LoadData(ref i, saveData, ref isBuildingWorkerUpdated); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"BuildingData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } } -} +} \ No newline at end of file diff --git a/CustomData/CitizenData.cs b/CustomData/CitizenData.cs index f5a5aad..3413e31 100644 --- a/CustomData/CitizenData.cs +++ b/CustomData/CitizenData.cs @@ -8,44 +8,36 @@ public class CitizenData public static float[] citizenMoney = new float[1048576]; public static uint lastCitizenID = 0; - public static void DataInit() - { - for (int i = 0; i < citizenMoney.Length; i++) - { + public static void DataInit() { + for (int i = 0; i < citizenMoney.Length; i++) { citizenMoney[i] = 0f; } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { //4194304 int i = 0; SaveAndRestore.SaveData(ref i, citizenMoney, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"CitizenData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref citizenMoney); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"CitizenData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static uint GetCitizenUnit(ushort buildingId) - { - if (buildingId != 0) - { + public static uint GetCitizenUnit(ushort buildingId) { + if (buildingId != 0) { return Singleton.instance.m_buildings.m_buffer[(int)buildingId].m_citizenUnits; } return 0u; } } -} +} \ No newline at end of file diff --git a/CustomData/CitizenUnitData.cs b/CustomData/CitizenUnitData.cs index 9958376..2f24875 100644 --- a/CustomData/CitizenUnitData.cs +++ b/CustomData/CitizenUnitData.cs @@ -7,39 +7,33 @@ public class CitizenUnitData public static float[] familyMoney = new float[524288]; public static ushort[] familyGoods = new ushort[524288]; - public static void DataInit() - { - for (int i = 0; i < familyMoney.Length; i++) - { + public static void DataInit() { + for (int i = 0; i < familyMoney.Length; i++) { familyMoney[i] = 0f; //default; familyGoods[i] = 65535; } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { //3145728; int i = 0; SaveAndRestore.SaveData(ref i, familyMoney, ref saveData); SaveAndRestore.SaveData(ref i, familyGoods, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"CitizenData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref familyMoney); SaveAndRestore.LoadData(ref i, saveData, ref familyGoods); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"CitizenData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } } -} +} \ No newline at end of file diff --git a/CustomData/TransportLineData.cs b/CustomData/TransportLineData.cs index d6ee9d2..ff06077 100644 --- a/CustomData/TransportLineData.cs +++ b/CustomData/TransportLineData.cs @@ -8,37 +8,31 @@ public class TransportLineData public static byte[] WeekEndPlan = new byte[256]; public static ushort lastLineID = 0; - public static void DataInit() - { - for (int i = 0; i < WeekDayPlan.Length; i++) - { + public static void DataInit() { + for (int i = 0; i < WeekDayPlan.Length; i++) { WeekDayPlan[i] = 1; WeekEndPlan[i] = 2; } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { int i = 0; SaveAndRestore.SaveData(ref i, WeekDayPlan, ref saveData); SaveAndRestore.SaveData(ref i, WeekEndPlan, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"TransportLineData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref WeekDayPlan); SaveAndRestore.LoadData(ref i, saveData, ref WeekEndPlan); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"TransportLineData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } } -} +} \ No newline at end of file diff --git a/CustomData/VehicleData.cs b/CustomData/VehicleData.cs index dd0a0f9..a8191db 100644 --- a/CustomData/VehicleData.cs +++ b/CustomData/VehicleData.cs @@ -7,38 +7,32 @@ public class VehicleData public static ushort[] vehicleTransferTime = new ushort[65536]; public static bool[] isVehicleCharged = new bool[65536]; - public static void DataInit() - { - for (int i = 0; i < isVehicleCharged.Length; i++) - { + public static void DataInit() { + for (int i = 0; i < isVehicleCharged.Length; i++) { vehicleTransferTime[i] = 0; isVehicleCharged[i] = false; } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { //3 * 65536 = 196608; int i = 0; SaveAndRestore.SaveData(ref i, vehicleTransferTime, ref saveData); SaveAndRestore.SaveData(ref i, isVehicleCharged, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"VehicleData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref vehicleTransferTime); SaveAndRestore.LoadData(ref i, saveData, ref isVehicleCharged); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"VehicleData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } } -} +} \ No newline at end of file diff --git a/CustomManager/RealCityEconomyManager.cs b/CustomManager/RealCityEconomyManager.cs index 6159cdd..a7cb706 100644 --- a/CustomManager/RealCityEconomyManager.cs +++ b/CustomManager/RealCityEconomyManager.cs @@ -4,7 +4,7 @@ namespace RealCity.CustomManager { public class RealCityEconomyManager { - + public static int[] citizenTaxIncomeForUI = new int[17]; public static int[] citizenIncomeForUI = new int[17]; public static int[] touristIncomeForUI = new int[17]; @@ -45,8 +45,7 @@ public class RealCityEconomyManager public static int[] healthCareIncomeForUI = new int[17]; public static int[] fireStationIncomeForUI = new int[17]; - public static void CleanCurrent(int current_idex) - { + public static void CleanCurrent(int current_idex) { citizenTaxIncomeForUI[current_idex] = 0; citizenIncomeForUI[current_idex] = 0; touristIncomeForUI[current_idex] = 0; @@ -85,10 +84,8 @@ public static void CleanCurrent(int current_idex) healthCareIncomeForUI[current_idex] = 0; } - public static void DataInit() - { - for (int i = 0; i < citizenTaxIncomeForUI.Length; i++) - { + public static void DataInit() { + for (int i = 0; i < citizenTaxIncomeForUI.Length; i++) { citizenTaxIncomeForUI[i] = 0; citizenIncomeForUI[i] = 0; touristIncomeForUI[i] = 0; @@ -128,8 +125,7 @@ public static void DataInit() } } - public static void Load(ref byte[] saveData) - { + public static void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref citizenTaxIncomeForUI); SaveAndRestore.LoadData(ref i, saveData, ref citizenIncomeForUI); @@ -168,14 +164,12 @@ public static void Load(ref byte[] saveData) SaveAndRestore.LoadData(ref i, saveData, ref healthCareIncomeForUI); SaveAndRestore.LoadData(ref i, saveData, ref fireStationIncomeForUI); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"RealCityEconomyManager Load Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static void Save(ref byte[] saveData) - { + public static void Save(ref byte[] saveData) { int i = 0; //36 * 4 * 17 = 2448 SaveAndRestore.SaveData(ref i, citizenTaxIncomeForUI, ref saveData); @@ -215,10 +209,9 @@ public static void Save(ref byte[] saveData) SaveAndRestore.SaveData(ref i, healthCareIncomeForUI, ref saveData); SaveAndRestore.SaveData(ref i, fireStationIncomeForUI, ref saveData); - if (i != saveData.Length) - { + if (i != saveData.Length) { DebugLog.LogToFileOnly($"RealCityEconomyManager Save Error: saveData.Length = {saveData.Length} + i = {i}"); } } } -} +} \ No newline at end of file diff --git a/Loader.cs b/Loader.cs index 7a93109..b289f4d 100644 --- a/Loader.cs +++ b/Loader.cs @@ -14,474 +14,393 @@ namespace RealCity { - public class Loader : LoadingExtensionBase - { - public static bool HarmonyDetourInited = false; - public static bool HarmonyDetourFailed = true; - public static UIView parentGuiView; - public static UIPanel HumanInfo; - public static UIPanel TouristInfo; - public static EcnomicUI ecnomicUI; - public static RealCityUI realCityUI; - public static HumanUI humanUI; - public static PoliticsUI politicsUI; - public static TouristUI touristUI; - public static GameObject buildingWindowGameObject; - public static GameObject HumanWindowGameObject; - public static GameObject TouristWindowGameObject; - public static LoadMode CurrentLoadMode; - public static bool isGuiRunning = false; - public static PoliticsButton PlButton; - public static EcnomicButton EcButton; - public static RealCityButton RcButton; - public static BuildingButton BButton; - public static PlayerBuildingButton PBButton; - public static string m_atlasName = "RealCity"; - public static bool m_atlasLoaded; - public static UIPanel PBLInfo; - public static PBLUI PBLUI; - public static GameObject PBLWindowGameObject; - public static bool isTransportLinesManagerRunning = false; - public static bool isRealTimeRunning = false; - - public override void OnCreated(ILoading loading) - { - HarmonyInitDetour(); - base.OnCreated(loading); - } - - public override void OnLevelLoaded(LoadMode mode) - { - base.OnLevelLoaded(mode); - CurrentLoadMode = mode; - if (RealCity.IsEnabled) - { - if (mode == LoadMode.LoadGame || mode == LoadMode.NewGame) - { - isTransportLinesManagerRunning = CheckTransportLinesManagerIsLoaded(); - DebugLog.LogToFileOnly($"Check TLM running = {isTransportLinesManagerRunning}"); - isRealTimeRunning = CheckRealTimeIsLoaded(); - DebugLog.LogToFileOnly($"Check RealTime running = {isRealTimeRunning}"); - isTransportLinesManagerRunning = isTransportLinesManagerRunning || (!isRealTimeRunning); - //refresh OptionsMainPanel - MethodInfo method = typeof(OptionsMainPanel).GetMethod("OnLocaleChanged", BindingFlags.Instance | BindingFlags.NonPublic); - method.Invoke(UIView.library.Get("OptionsPanel"), new object[0]); - SetupGui(); - HarmonyInitDetour(); - OptionUI.LoadSetting(); - RealCityThreading.isFirstTime = true; - DebugLog.LogToFileOnly("OnLevelLoaded"); - if (mode == LoadMode.NewGame) - { - InitData(); - } - } - else - { - if (RealCity.IsEnabled) - { - HarmonyRevertDetour(); - } - } - } - } - - public static void InitData() - { - DebugLog.LogToFileOnly("InitData"); - TransportLineData.DataInit(); - VehicleData.DataInit(); - BuildingData.DataInit(); - CitizenUnitData.DataInit(); - CitizenData.DataInit(); - RealCityEconomyManager.DataInit(); - System.Random rand = new System.Random(); - RealCityEconomyExtension.partyTrend = (byte)rand.Next(5); - RealCityEconomyExtension.partyTrendStrength = (byte)rand.Next(300); - - DebugLog.LogToFileOnly("InitData Done"); - } - - public override void OnLevelUnloading() - { - base.OnLevelUnloading(); - if (CurrentLoadMode == LoadMode.LoadGame || CurrentLoadMode == LoadMode.NewGame) - { - if (RealCity.IsEnabled && isGuiRunning) - { - RemoveGui(); - } - if (RealCity.IsEnabled) - { - RealCityThreading.isFirstTime = true; - HarmonyRevertDetour(); - } - } - } - - public override void OnReleased() - { - base.OnReleased(); - } - - private static void LoadSprites() - { - if (SpriteUtilities.GetAtlas(m_atlasName) != null) return; - var modPath = PluginManager.instance.FindPluginInfo(Assembly.GetExecutingAssembly()).modPath; - m_atlasLoaded = SpriteUtilities.InitialiseAtlas(Path.Combine(modPath, "Icon/RealCity.png"), m_atlasName); - if (m_atlasLoaded) - { - var spriteSuccess = true; - spriteSuccess = SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(382, 0), new Vector2(191, 191)), "EcButton", m_atlasName) - && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(0, 0), new Vector2(191, 191)), "Blank", m_atlasName) - && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(191, 0), new Vector2(191, 191)), "BuildingButton", m_atlasName) - && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(573, 0), new Vector2(191, 191)), "Politics", m_atlasName) - && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(764, 0), new Vector2(191, 191)), "RcButton", m_atlasName) - && spriteSuccess; - if (!spriteSuccess) DebugLog.LogToFileOnly("Some sprites haven't been loaded. This is abnormal; you should probably report this to the mod creator."); - } - else DebugLog.LogToFileOnly("The texture atlas (provides custom icons) has not loaded. All icons have reverted to text prompts."); - } - - public static void SetupGui() - { - LoadSprites(); - if (m_atlasLoaded) - { - parentGuiView = null; - parentGuiView = UIView.GetAView(); - if (ecnomicUI == null) - { - ecnomicUI = (EcnomicUI)parentGuiView.AddUIComponent(typeof(EcnomicUI)); - } - - if (realCityUI == null) - { - realCityUI = (RealCityUI)parentGuiView.AddUIComponent(typeof(RealCityUI)); - } - - if (politicsUI == null) - { - politicsUI = (PoliticsUI)parentGuiView.AddUIComponent(typeof(PoliticsUI)); - } - - SetupHumanGui(); - SetupTouristGui(); - SetupEcnomicButton(); - SetupPLButton(); - SetupCityButton(); - SetupBuildingButton(); - SetupPlayerBuildingButton(); - if (!isTransportLinesManagerRunning) - SetupPBLUIGui(); - isGuiRunning = true; - } - } - public static void SetupPBLUIGui() - { - PBLWindowGameObject = new GameObject("PBLWindowGameObject"); - PBLUI = (PBLUI)PBLWindowGameObject.AddComponent(typeof(PBLUI)); - PBLInfo = UIView.Find("(Library) PublicTransportWorldInfoPanel"); - if (PBLInfo == null) - { - DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) PublicTransportWorldInfoPanel\nAvailable panels are:\n"); - } - else - { - PBLUI.transform.parent = PBLInfo.transform; - PBLUI.size = new Vector3(150, 100); - PBLUI.baseBuildingWindow = PBLInfo.gameObject.transform.GetComponentInChildren(); - UILabel UILabel = PBLUI.baseBuildingWindow.Find("ModelLabel"); - PBLUI.position = new Vector3(UILabel.relativePosition.x + 50f, PBLInfo.size.y - (UILabel.relativePosition.y + 160f)); - PBLInfo.eventVisibilityChanged += PBLInfo_eventVisibilityChanged; - } - } - public static void PBLInfo_eventVisibilityChanged(UIComponent component, bool value) - { - PBLUI.isEnabled = value; - if (value) - { - //initialize PBL ui again - PBLUI.transform.parent = PBLInfo.transform; - PBLUI.size = new Vector3(150, 100); - PBLUI.baseBuildingWindow = PBLInfo.gameObject.transform.GetComponentInChildren(); - UILabel UILabel = PBLUI.baseBuildingWindow.Find("ModelLabel"); - //DebugLog.LogToFileOnly(UILabel.relativePosition.x.ToString() + " " + UILabel.relativePosition.y.ToString()); - PBLUI.position = new Vector3(UILabel.relativePosition.x + 50f, PBLInfo.size.y - (UILabel.relativePosition.y + 160f)); - PBLUI.refeshOnce = true; - PBLUI.Show(); - } - else - { - PBLUI.Hide(); - } - } - public static void SetupHumanGui() - { - HumanWindowGameObject = new GameObject("HumanWindowGameObject"); - humanUI = (HumanUI)HumanWindowGameObject.AddComponent(typeof(HumanUI)); - HumanInfo = UIView.Find("(Library) CitizenWorldInfoPanel"); - if (HumanInfo == null) - { - DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) CitizenWorldInfoPanel\nAvailable panels are:\n"); - } - humanUI.transform.parent = HumanInfo.transform; - humanUI.size = new Vector3(HumanInfo.size.x, HumanInfo.size.y); - humanUI.baseBuildingWindow = HumanInfo.gameObject.transform.GetComponentInChildren(); - humanUI.position = new Vector3(HumanInfo.size.x, HumanInfo.size.y); - HumanInfo.eventVisibilityChanged += HumanInfo_eventVisibilityChanged; - } - - public static void SetupTouristGui() - { - TouristWindowGameObject = new GameObject("TouristWindowGameObject"); - touristUI = (TouristUI)TouristWindowGameObject.AddComponent(typeof(TouristUI)); - TouristInfo = UIView.Find("(Library) TouristWorldInfoPanel"); - if (TouristInfo == null) - { - DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) TouristWorldInfoPanel\nAvailable panels are:\n"); - } - touristUI.transform.parent = TouristInfo.transform; - touristUI.size = new Vector3(TouristInfo.size.x, TouristInfo.size.y); - touristUI.baseBuildingWindow = TouristInfo.gameObject.transform.GetComponentInChildren(); - touristUI.position = new Vector3(TouristInfo.size.x, TouristInfo.size.y); - TouristInfo.eventVisibilityChanged += TouristInfo_eventVisibilityChanged; - } - - public static void SetupEcnomicButton() - { - if (EcButton == null) - { - EcButton = (parentGuiView.AddUIComponent(typeof(EcnomicButton)) as EcnomicButton); - } - EcButton.Show(); - } - - public static void SetupCityButton() - { - if (RcButton == null) - { - RcButton = (parentGuiView.AddUIComponent(typeof(RealCityButton)) as RealCityButton); - } - RcButton.Show(); - } - - public static void SetupBuildingButton() - { - var buildingInfo = UIView.Find("(Library) ZonedBuildingWorldInfoPanel"); - if (BButton == null) - { - BButton = (buildingInfo.AddUIComponent(typeof(BuildingButton)) as BuildingButton); - } - BButton.width = 40f; - BButton.height = 35f; - BButton.relativePosition = new Vector3(120, buildingInfo.size.y - BButton.height); - BButton.Show(); - } - - public static void SetupPlayerBuildingButton() - { - var playerBuildingInfo = UIView.Find("(Library) CityServiceWorldInfoPanel"); - if (PBButton == null) - { - PBButton = (playerBuildingInfo.AddUIComponent(typeof(PlayerBuildingButton)) as PlayerBuildingButton); - } - PBButton.width = 40f; - PBButton.height = 35f; - PBButton.relativePosition = new Vector3(120, playerBuildingInfo.size.y - PBButton.height); - PBButton.Show(); - } - - public static void SetupPLButton() - { - if (PlButton == null) - { - PlButton = (parentGuiView.AddUIComponent(typeof(PoliticsButton)) as PoliticsButton); - } - PlButton.Show(); - } - - public static void HumanInfo_eventVisibilityChanged(UIComponent component, bool value) - { - humanUI.isEnabled = value; - if (value) - { - //initialize human ui again - humanUI.transform.parent = HumanInfo.transform; - humanUI.size = new Vector3(HumanInfo.size.x, HumanInfo.size.y); - humanUI.baseBuildingWindow = HumanInfo.gameObject.transform.GetComponentInChildren(); - humanUI.position = new Vector3(HumanInfo.size.x, HumanInfo.size.y); - HumanUI.refeshOnce = true; - humanUI.Show(); - } - else - { - humanUI.Hide(); - } - } - - public static void TouristInfo_eventVisibilityChanged(UIComponent component, bool value) - { - touristUI.isEnabled = value; - if (value) - { - //initialize human ui again - touristUI.transform.parent = TouristInfo.transform; - touristUI.size = new Vector3(TouristInfo.size.x, HumanInfo.size.y); - touristUI.baseBuildingWindow = TouristInfo.gameObject.transform.GetComponentInChildren(); - touristUI.position = new Vector3(TouristInfo.size.x, TouristInfo.size.y); - TouristUI.refeshOnce = true; - touristUI.Show(); - } - else - { - touristUI.Hide(); - } - } - - public static void RemoveGui() - { - isGuiRunning = false; - if (parentGuiView != null) - { - parentGuiView = null; - UnityEngine.Object.Destroy(ecnomicUI); - UnityEngine.Object.Destroy(realCityUI); - UnityEngine.Object.Destroy(politicsUI); - UnityEngine.Object.Destroy(EcButton); - UnityEngine.Object.Destroy(RcButton); - UnityEngine.Object.Destroy(PlButton); - ecnomicUI = null; - realCityUI = null; - politicsUI = null; - EcButton = null; - RcButton = null; - PlButton = null; - } - - if (BButton != null) - { - UnityEngine.Object.Destroy(BButton); - BButton = null; - } - - if (PBButton != null) - { - UnityEngine.Object.Destroy(PBButton); - PBButton = null; - } - - if (buildingWindowGameObject != null) - { - UnityEngine.Object.Destroy(buildingWindowGameObject); - } - //remove HumanUI - if (humanUI != null) - { - if (humanUI.parent != null) - { - humanUI.parent.eventVisibilityChanged -= HumanInfo_eventVisibilityChanged; - } - } - if (HumanWindowGameObject != null) - { - UnityEngine.Object.Destroy(HumanWindowGameObject); - } - //remove TouristUI - if (touristUI != null) - { - if (touristUI.parent != null) - { - touristUI.parent.eventVisibilityChanged -= TouristInfo_eventVisibilityChanged; - } - } - - if (TouristWindowGameObject != null) - { - UnityEngine.Object.Destroy(TouristWindowGameObject); - } - - if (!isTransportLinesManagerRunning) - { - if (PBLUI != null) - { - if (PBLUI.parent != null) - { - PBLUI.parent.eventVisibilityChanged -= PBLInfo_eventVisibilityChanged; - } - } - - if (PBLWindowGameObject != null) - { - UnityEngine.Object.Destroy(PBLWindowGameObject); - } - PBLUI._initialized = false; - } - } - - private bool Check3rdPartyModLoaded(string namespaceStr, bool printAll = false) - { - bool result = false; - FieldInfo field = typeof(LoadingWrapper).GetField("m_LoadingExtensions", BindingFlags.Instance | BindingFlags.NonPublic); - List list = (List)field.GetValue(Singleton.instance.m_LoadingWrapper); - if (list != null) - { - foreach (ILoadingExtension current in list) - { - if (printAll) - { - DebugLog.LogToFileOnly(string.Format("Detected extension: {0} in namespace {1}", current.GetType().Name, current.GetType().Namespace)); - } - if (current.GetType().Namespace != null) - { - string value = current.GetType().Namespace.ToString(); - if (namespaceStr.Equals(value)) - { - DebugLog.LogToFileOnly(string.Format("The mod '{0}' has been detected.", namespaceStr)); - result = true; - break; - } - } - } - } - return result; - } - - public static void HarmonyInitDetour() - { - if (HarmonyHelper.IsHarmonyInstalled) - { - if (!HarmonyDetourInited) - { - DebugLog.LogToFileOnly("Init harmony detours"); - HarmonyDetours.Apply(); - HarmonyDetourInited = true; - } - } - } - - public static void HarmonyRevertDetour() - { - if (HarmonyHelper.IsHarmonyInstalled) - { - if (HarmonyDetourInited) - { - DebugLog.LogToFileOnly("Revert harmony detours"); - HarmonyDetours.DeApply(); - HarmonyDetourFailed = true; - HarmonyDetourInited = false; - } - } - } - - private bool CheckTransportLinesManagerIsLoaded() - { - return Check3rdPartyModLoaded("Klyte.TransportLinesManager", false); - } - - private bool CheckRealTimeIsLoaded() - { - return Check3rdPartyModLoaded("RealTime.Core", false); - } - } -} + public class Loader : LoadingExtensionBase + { + public static bool HarmonyDetourInited = false; + public static bool HarmonyDetourFailed = true; + public static UIView parentGuiView; + public static UIPanel HumanInfo; + public static UIPanel TouristInfo; + public static EcnomicUI ecnomicUI; + public static RealCityUI realCityUI; + public static HumanUI humanUI; + public static PoliticsUI politicsUI; + public static TouristUI touristUI; + public static GameObject buildingWindowGameObject; + public static GameObject HumanWindowGameObject; + public static GameObject TouristWindowGameObject; + public static LoadMode CurrentLoadMode; + public static bool isGuiRunning = false; + public static PoliticsButton PlButton; + public static EcnomicButton EcButton; + public static RealCityButton RcButton; + public static BuildingButton BButton; + public static PlayerBuildingButton PBButton; + public static string m_atlasName = "RealCity"; + public static bool m_atlasLoaded; + public static UIPanel PBLInfo; + public static PBLUI PBLUI; + public static GameObject PBLWindowGameObject; + public static bool isTransportLinesManagerRunning = false; + public static bool isRealTimeRunning = false; + + public override void OnCreated(ILoading loading) { + HarmonyInitDetour(); + base.OnCreated(loading); + } + + public override void OnLevelLoaded(LoadMode mode) { + base.OnLevelLoaded(mode); + CurrentLoadMode = mode; + if (RealCity.IsEnabled) { + if (mode == LoadMode.LoadGame || mode == LoadMode.NewGame) { + isTransportLinesManagerRunning = CheckTransportLinesManagerIsLoaded(); + DebugLog.LogToFileOnly($"Check TLM running = {isTransportLinesManagerRunning}"); + isRealTimeRunning = CheckRealTimeIsLoaded(); + DebugLog.LogToFileOnly($"Check RealTime running = {isRealTimeRunning}"); + isTransportLinesManagerRunning = isTransportLinesManagerRunning || (!isRealTimeRunning); + //refresh OptionsMainPanel + MethodInfo method = typeof(OptionsMainPanel).GetMethod("OnLocaleChanged", BindingFlags.Instance | BindingFlags.NonPublic); + method.Invoke(UIView.library.Get("OptionsPanel"), new object[0]); + SetupGui(); + HarmonyInitDetour(); + OptionUI.LoadSetting(); + RealCityThreading.isFirstTime = true; + DebugLog.LogToFileOnly("OnLevelLoaded"); + if (mode == LoadMode.NewGame) { + InitData(); + } + } else { + if (RealCity.IsEnabled) { + HarmonyRevertDetour(); + } + } + } + } + + public static void InitData() { + DebugLog.LogToFileOnly("InitData"); + TransportLineData.DataInit(); + VehicleData.DataInit(); + BuildingData.DataInit(); + CitizenUnitData.DataInit(); + CitizenData.DataInit(); + RealCityEconomyManager.DataInit(); + System.Random rand = new System.Random(); + RealCityEconomyExtension.partyTrend = (byte)rand.Next(5); + RealCityEconomyExtension.partyTrendStrength = (byte)rand.Next(300); + + DebugLog.LogToFileOnly("InitData Done"); + } + + public override void OnLevelUnloading() { + base.OnLevelUnloading(); + if (CurrentLoadMode == LoadMode.LoadGame || CurrentLoadMode == LoadMode.NewGame) { + if (RealCity.IsEnabled && isGuiRunning) { + RemoveGui(); + } + if (RealCity.IsEnabled) { + RealCityThreading.isFirstTime = true; + HarmonyRevertDetour(); + } + } + } + + public override void OnReleased() { + base.OnReleased(); + } + + private static void LoadSprites() { + if (SpriteUtilities.GetAtlas(m_atlasName) != null) return; + var modPath = PluginManager.instance.FindPluginInfo(Assembly.GetExecutingAssembly()).modPath; + m_atlasLoaded = SpriteUtilities.InitialiseAtlas(Path.Combine(modPath, "Icon/RealCity.png"), m_atlasName); + if (m_atlasLoaded) { + var spriteSuccess = true; + spriteSuccess = SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(382, 0), new Vector2(191, 191)), "EcButton", m_atlasName) + && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(0, 0), new Vector2(191, 191)), "Blank", m_atlasName) + && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(191, 0), new Vector2(191, 191)), "BuildingButton", m_atlasName) + && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(573, 0), new Vector2(191, 191)), "Politics", m_atlasName) + && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(764, 0), new Vector2(191, 191)), "RcButton", m_atlasName) + && spriteSuccess; + if (!spriteSuccess) DebugLog.LogToFileOnly("Some sprites haven't been loaded. This is abnormal; you should probably report this to the mod creator."); + } else DebugLog.LogToFileOnly("The texture atlas (provides custom icons) has not loaded. All icons have reverted to text prompts."); + } + + public static void SetupGui() { + LoadSprites(); + if (m_atlasLoaded) { + parentGuiView = null; + parentGuiView = UIView.GetAView(); + if (ecnomicUI == null) { + ecnomicUI = (EcnomicUI)parentGuiView.AddUIComponent(typeof(EcnomicUI)); + } + + if (realCityUI == null) { + realCityUI = (RealCityUI)parentGuiView.AddUIComponent(typeof(RealCityUI)); + } + + if (politicsUI == null) { + politicsUI = (PoliticsUI)parentGuiView.AddUIComponent(typeof(PoliticsUI)); + } + + SetupHumanGui(); + SetupTouristGui(); + SetupEcnomicButton(); + SetupPLButton(); + SetupCityButton(); + SetupBuildingButton(); + SetupPlayerBuildingButton(); + if (!isTransportLinesManagerRunning) + SetupPBLUIGui(); + isGuiRunning = true; + } + } + public static void SetupPBLUIGui() { + PBLWindowGameObject = new GameObject("PBLWindowGameObject"); + PBLUI = (PBLUI)PBLWindowGameObject.AddComponent(typeof(PBLUI)); + PBLInfo = UIView.Find("(Library) PublicTransportWorldInfoPanel"); + if (PBLInfo == null) { + DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) PublicTransportWorldInfoPanel\nAvailable panels are:\n"); + } else { + PBLUI.transform.parent = PBLInfo.transform; + PBLUI.size = new Vector3(150, 100); + PBLUI.baseBuildingWindow = PBLInfo.gameObject.transform.GetComponentInChildren(); + UILabel UILabel = PBLUI.baseBuildingWindow.Find("ModelLabel"); + PBLUI.position = new Vector3(UILabel.relativePosition.x + 50f, PBLInfo.size.y - (UILabel.relativePosition.y + 160f)); + PBLInfo.eventVisibilityChanged += PBLInfo_eventVisibilityChanged; + } + } + public static void PBLInfo_eventVisibilityChanged(UIComponent component, bool value) { + PBLUI.isEnabled = value; + if (value) { + //initialize PBL ui again + PBLUI.transform.parent = PBLInfo.transform; + PBLUI.size = new Vector3(150, 100); + PBLUI.baseBuildingWindow = PBLInfo.gameObject.transform.GetComponentInChildren(); + UILabel UILabel = PBLUI.baseBuildingWindow.Find("ModelLabel"); + //DebugLog.LogToFileOnly(UILabel.relativePosition.x.ToString() + " " + UILabel.relativePosition.y.ToString()); + PBLUI.position = new Vector3(UILabel.relativePosition.x + 50f, PBLInfo.size.y - (UILabel.relativePosition.y + 160f)); + PBLUI.refeshOnce = true; + PBLUI.Show(); + } else { + PBLUI.Hide(); + } + } + public static void SetupHumanGui() { + HumanWindowGameObject = new GameObject("HumanWindowGameObject"); + humanUI = (HumanUI)HumanWindowGameObject.AddComponent(typeof(HumanUI)); + HumanInfo = UIView.Find("(Library) CitizenWorldInfoPanel"); + if (HumanInfo == null) { + DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) CitizenWorldInfoPanel\nAvailable panels are:\n"); + } + humanUI.transform.parent = HumanInfo.transform; + humanUI.size = new Vector3(HumanInfo.size.x, HumanInfo.size.y); + humanUI.baseBuildingWindow = HumanInfo.gameObject.transform.GetComponentInChildren(); + humanUI.position = new Vector3(HumanInfo.size.x, HumanInfo.size.y); + HumanInfo.eventVisibilityChanged += HumanInfo_eventVisibilityChanged; + } + + public static void SetupTouristGui() { + TouristWindowGameObject = new GameObject("TouristWindowGameObject"); + touristUI = (TouristUI)TouristWindowGameObject.AddComponent(typeof(TouristUI)); + TouristInfo = UIView.Find("(Library) TouristWorldInfoPanel"); + if (TouristInfo == null) { + DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) TouristWorldInfoPanel\nAvailable panels are:\n"); + } + touristUI.transform.parent = TouristInfo.transform; + touristUI.size = new Vector3(TouristInfo.size.x, TouristInfo.size.y); + touristUI.baseBuildingWindow = TouristInfo.gameObject.transform.GetComponentInChildren(); + touristUI.position = new Vector3(TouristInfo.size.x, TouristInfo.size.y); + TouristInfo.eventVisibilityChanged += TouristInfo_eventVisibilityChanged; + } + + public static void SetupEcnomicButton() { + if (EcButton == null) { + EcButton = (parentGuiView.AddUIComponent(typeof(EcnomicButton)) as EcnomicButton); + } + EcButton.Show(); + } + + public static void SetupCityButton() { + if (RcButton == null) { + RcButton = (parentGuiView.AddUIComponent(typeof(RealCityButton)) as RealCityButton); + } + RcButton.Show(); + } + + public static void SetupBuildingButton() { + var buildingInfo = UIView.Find("(Library) ZonedBuildingWorldInfoPanel"); + if (BButton == null) { + BButton = (buildingInfo.AddUIComponent(typeof(BuildingButton)) as BuildingButton); + } + BButton.width = 40f; + BButton.height = 35f; + BButton.relativePosition = new Vector3(120, buildingInfo.size.y - BButton.height); + BButton.Show(); + } + + public static void SetupPlayerBuildingButton() { + var playerBuildingInfo = UIView.Find("(Library) CityServiceWorldInfoPanel"); + if (PBButton == null) { + PBButton = (playerBuildingInfo.AddUIComponent(typeof(PlayerBuildingButton)) as PlayerBuildingButton); + } + PBButton.width = 40f; + PBButton.height = 35f; + PBButton.relativePosition = new Vector3(120, playerBuildingInfo.size.y - PBButton.height); + PBButton.Show(); + } + + public static void SetupPLButton() { + if (PlButton == null) { + PlButton = (parentGuiView.AddUIComponent(typeof(PoliticsButton)) as PoliticsButton); + } + PlButton.Show(); + } + + public static void HumanInfo_eventVisibilityChanged(UIComponent component, bool value) { + humanUI.isEnabled = value; + if (value) { + //initialize human ui again + humanUI.transform.parent = HumanInfo.transform; + humanUI.size = new Vector3(HumanInfo.size.x, HumanInfo.size.y); + humanUI.baseBuildingWindow = HumanInfo.gameObject.transform.GetComponentInChildren(); + humanUI.position = new Vector3(HumanInfo.size.x, HumanInfo.size.y); + HumanUI.refeshOnce = true; + humanUI.Show(); + } else { + humanUI.Hide(); + } + } + + public static void TouristInfo_eventVisibilityChanged(UIComponent component, bool value) { + touristUI.isEnabled = value; + if (value) { + //initialize human ui again + touristUI.transform.parent = TouristInfo.transform; + touristUI.size = new Vector3(TouristInfo.size.x, HumanInfo.size.y); + touristUI.baseBuildingWindow = TouristInfo.gameObject.transform.GetComponentInChildren(); + touristUI.position = new Vector3(TouristInfo.size.x, TouristInfo.size.y); + TouristUI.refeshOnce = true; + touristUI.Show(); + } else { + touristUI.Hide(); + } + } + + public static void RemoveGui() { + isGuiRunning = false; + if (parentGuiView != null) { + parentGuiView = null; + UnityEngine.Object.Destroy(ecnomicUI); + UnityEngine.Object.Destroy(realCityUI); + UnityEngine.Object.Destroy(politicsUI); + UnityEngine.Object.Destroy(EcButton); + UnityEngine.Object.Destroy(RcButton); + UnityEngine.Object.Destroy(PlButton); + ecnomicUI = null; + realCityUI = null; + politicsUI = null; + EcButton = null; + RcButton = null; + PlButton = null; + } + + if (BButton != null) { + UnityEngine.Object.Destroy(BButton); + BButton = null; + } + + if (PBButton != null) { + UnityEngine.Object.Destroy(PBButton); + PBButton = null; + } + + if (buildingWindowGameObject != null) { + UnityEngine.Object.Destroy(buildingWindowGameObject); + } + //remove HumanUI + if (humanUI != null) { + if (humanUI.parent != null) { + humanUI.parent.eventVisibilityChanged -= HumanInfo_eventVisibilityChanged; + } + } + if (HumanWindowGameObject != null) { + UnityEngine.Object.Destroy(HumanWindowGameObject); + } + //remove TouristUI + if (touristUI != null) { + if (touristUI.parent != null) { + touristUI.parent.eventVisibilityChanged -= TouristInfo_eventVisibilityChanged; + } + } + + if (TouristWindowGameObject != null) { + UnityEngine.Object.Destroy(TouristWindowGameObject); + } + + if (!isTransportLinesManagerRunning) { + if (PBLUI != null) { + if (PBLUI.parent != null) { + PBLUI.parent.eventVisibilityChanged -= PBLInfo_eventVisibilityChanged; + } + } + + if (PBLWindowGameObject != null) { + UnityEngine.Object.Destroy(PBLWindowGameObject); + } + PBLUI._initialized = false; + } + } + + private bool Check3rdPartyModLoaded(string namespaceStr, bool printAll = false) { + bool result = false; + FieldInfo field = typeof(LoadingWrapper).GetField("m_LoadingExtensions", BindingFlags.Instance | BindingFlags.NonPublic); + List list = (List)field.GetValue(Singleton.instance.m_LoadingWrapper); + if (list != null) { + foreach (ILoadingExtension current in list) { + if (printAll) { + DebugLog.LogToFileOnly(string.Format("Detected extension: {0} in namespace {1}", current.GetType().Name, current.GetType().Namespace)); + } + if (current.GetType().Namespace != null) { + string value = current.GetType().Namespace.ToString(); + if (namespaceStr.Equals(value)) { + DebugLog.LogToFileOnly(string.Format("The mod '{0}' has been detected.", namespaceStr)); + result = true; + break; + } + } + } + } + return result; + } + + public static void HarmonyInitDetour() { + if (HarmonyHelper.IsHarmonyInstalled) { + if (!HarmonyDetourInited) { + DebugLog.LogToFileOnly("Init harmony detours"); + HarmonyDetours.Apply(); + HarmonyDetourInited = true; + } + } + } + + public static void HarmonyRevertDetour() { + if (HarmonyHelper.IsHarmonyInstalled) { + if (HarmonyDetourInited) { + DebugLog.LogToFileOnly("Revert harmony detours"); + HarmonyDetours.DeApply(); + HarmonyDetourFailed = true; + HarmonyDetourInited = false; + } + } + } + + private bool CheckTransportLinesManagerIsLoaded() { + return Check3rdPartyModLoaded("Klyte.TransportLinesManager", false); + } + + private bool CheckRealTimeIsLoaded() { + return Check3rdPartyModLoaded("RealTime.Core", false); + } + } +} \ No newline at end of file diff --git a/Patch/CargoTruckAIArriveAtTargetPatch.cs b/Patch/CargoTruckAIArriveAtTargetPatch.cs index 0e40874..aefea04 100644 --- a/Patch/CargoTruckAIArriveAtTargetPatch.cs +++ b/Patch/CargoTruckAIArriveAtTargetPatch.cs @@ -3,10 +3,7 @@ using RealCity.CustomAI; using RealCity.Util; using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using System.Text; using UnityEngine; namespace RealCity.Patch @@ -14,36 +11,28 @@ namespace RealCity.Patch [HarmonyPatch] public static class CargoTruckAIArriveAtTargetPatch { - public static MethodBase TargetMethod() - { + public static MethodBase TargetMethod() { return typeof(CargoTruckAI).GetMethod("ArriveAtTarget", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }, null); } - public static void Prefix(ref CargoTruckAI __instance, ref Vehicle data) - { + public static void Prefix(ref CargoTruckAI __instance, ref Vehicle data) { int transferSize = 0; - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) - { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) { transferSize = data.m_transferSize; } - if ((data.m_flags & Vehicle.Flags.TransferToSource) != 0) - { + if ((data.m_flags & Vehicle.Flags.TransferToSource) != 0) { transferSize = Mathf.Min(0, data.m_transferSize - __instance.m_cargoCapacity); } // NON-STOCK CODE START ProcessResourceArriveAtTarget(ref data, ref transferSize); } - public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int transferSize) - { + public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int transferSize) { BuildingManager instance = Singleton.instance; BuildingInfo info = instance.m_buildings.m_buffer[data.m_targetBuilding].Info; - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) - { - if ((info.m_class.m_service == ItemClass.Service.Electricity) || (info.m_class.m_service == ItemClass.Service.Water) || (info.m_class.m_service == ItemClass.Service.Disaster)) - { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) { + if ((info.m_class.m_service == ItemClass.Service.Electricity) || (info.m_class.m_service == ItemClass.Service.Water) || (info.m_class.m_service == ItemClass.Service.Disaster)) { info.m_buildingAI.ModifyMaterialBuffer(data.m_targetBuilding, ref instance.m_buildings.m_buffer[data.m_targetBuilding], (TransferManager.TransferReason)data.m_transferType, ref transferSize); float productValue; - switch ((TransferManager.TransferReason)data.m_transferType) - { + switch ((TransferManager.TransferReason)data.m_transferType) { case TransferManager.TransferReason.Petrol: productValue = transferSize * RealCityIndustryBuildingAI.GetResourcePrice((TransferManager.TransferReason)data.m_transferType); Singleton.instance.FetchResource(EconomyManager.Resource.ResourcePrice, (int)productValue, ItemClass.Service.PlayerIndustry, ItemClass.SubService.PlayerIndustryOil, ItemClass.Level.Level1); @@ -60,12 +49,11 @@ public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int trans case (TransferManager.TransferReason)125: break; default: DebugLog.LogToFileOnly("Error: ProcessResourceArriveAtTarget find unknow play building transition" + info.m_class.ToString() + "transfer reason " + data.m_transferType.ToString()); break; } - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) - { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) { data.m_transferSize = (ushort)Mathf.Clamp(data.m_transferSize - transferSize, 0, data.m_transferSize); } } } } } -} +} \ No newline at end of file diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index 03550d8..072dae9 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -1,6 +1,5 @@ using System; using ColossalFramework; -using UnityEngine; using RealCity.Util; using HarmonyLib; using System.Reflection; @@ -9,746 +8,523 @@ namespace RealCity.Patch { - [HarmonyPatch] - public class ResidentAICitizenUnitSimulationStepPatch - { - public static MethodBase TargetMethod() - { - return typeof(ResidentAI).GetMethod("SimulationStep", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint), typeof(CitizenUnit).MakeByRefType() }, null); - } - - public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) - { - if (isPre) - { - CitizenUnitData.familyMoney[homeID] = 0; - if (data.m_citizen0 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen0]; - if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) - { - if (citizenData.Dead == false) - { - RealCityResidentAI.citizenCount++; - CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[data.m_citizen0]; - } - } - } - if (data.m_citizen1 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen1]; - if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) - { - if (citizenData.Dead == false) - { - RealCityResidentAI.citizenCount++; - CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[data.m_citizen1]; - } - } - } - if (data.m_citizen2 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen2]; - if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) - { - if (citizenData.Dead == false) - { - RealCityResidentAI.citizenCount++; - CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[data.m_citizen2]; - } - } - } - if (data.m_citizen3 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen3]; - if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) - { - if (citizenData.Dead == false) - { - RealCityResidentAI.citizenCount++; - CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[data.m_citizen3]; - } - } - } - if (data.m_citizen4 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen4]; - if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) - { - if (citizenData.Dead == false) - { - RealCityResidentAI.citizenCount++; - CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[data.m_citizen4]; - } - } - } - } - else - { - if (CitizenUnitData.familyMoney[homeID] < MainDataStore.lowWealth) - { - RealCityResidentAI.familyWeightStableLow++; - } - else if (CitizenUnitData.familyMoney[homeID] >= MainDataStore.highWealth) - { - RealCityResidentAI.familyWeightStableHigh++; - } - - int temp = 0; - if (data.m_citizen0 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen0]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { - temp++; + [HarmonyPatch] + public class ResidentAICitizenUnitSimulationStepPatch + { + public static MethodBase TargetMethod() { + return typeof(ResidentAI).GetMethod( + "SimulationStep", + BindingFlags.Public | BindingFlags.Instance, + null, + new Type[] { typeof(uint), typeof(CitizenUnit).MakeByRefType() }, + null); + } + + /// + /// 处理市民 + /// + /// + /// + /// + public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) { + FieldInfo fieldInfo; + if (isPre) { + CitizenUnitData.familyMoney[homeID] = 0; + for (int i = 0; i <= 4; i++) { + fieldInfo = data.GetType().GetField($"m_citizen{i}"); + uint m_citizenI = (uint)fieldInfo.GetValue(data); + if (m_citizenI != 0) { + Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; + if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) { + if (citizenData.Dead == false) { + RealCityResidentAI.citizenCount++; + CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[m_citizenI]; + } + } + } + } + } else { + // + if (CitizenUnitData.familyMoney[homeID] < MainDataStore.lowWealth) { + RealCityResidentAI.familyWeightStableLow++; + } else if (CitizenUnitData.familyMoney[homeID] >= MainDataStore.highWealth) { + RealCityResidentAI.familyWeightStableHigh++; + } + + int temp = 0; + for (int i = 0; i <= 4; i++) { + fieldInfo = data.GetType().GetField($"m_citizen{i}"); + uint m_citizenI = (uint)fieldInfo.GetValue(data); + + if (m_citizenI != 0) { + Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; + if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) { + ++temp; #if FASTRUN #else - GetVoteChance(data.m_citizen0, citizenData, homeID); + GetVoteChance(m_citizenI, citizenData, homeID); #endif - } - } - if (data.m_citizen1 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen1]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { -#if FASTRUN -#else - GetVoteChance(data.m_citizen1, citizenData, homeID); -#endif - temp++; - } - } - if (data.m_citizen2 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen2]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { -#if FASTRUN -#else - GetVoteChance(data.m_citizen2, citizenData, homeID); -#endif - temp++; - } - } - if (data.m_citizen3 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen3]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { -#if FASTRUN -#else - GetVoteChance(data.m_citizen3, citizenData, homeID); -#endif - temp++; - } - } - if (data.m_citizen4 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen4]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { -#if FASTRUN -#else - GetVoteChance(data.m_citizen4, citizenData, homeID); -#endif - temp++; - } - } - - if (temp != 0) - { - if (data.m_citizen0 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen0]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { - CitizenData.citizenMoney[data.m_citizen0] = CitizenUnitData.familyMoney[homeID] / temp; - } - } - if (data.m_citizen1 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen1]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { - CitizenData.citizenMoney[data.m_citizen1] = CitizenUnitData.familyMoney[homeID] / temp; - } - } - if (data.m_citizen2 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen2]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { - CitizenData.citizenMoney[data.m_citizen2] = CitizenUnitData.familyMoney[homeID] / temp; - } - } - if (data.m_citizen3 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen3]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { - CitizenData.citizenMoney[data.m_citizen3] = CitizenUnitData.familyMoney[homeID] / temp; - } - } - if (data.m_citizen4 != 0) - { - Citizen citizenData = Singleton.instance.m_citizens.m_buffer[data.m_citizen4]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) - { - CitizenData.citizenMoney[data.m_citizen4] = CitizenUnitData.familyMoney[homeID] / temp; - } - } - } - } - - } - - public static void ProcessFamily(uint homeID, ref CitizenUnit data) - { - if (RealCityResidentAI.preCitizenId > homeID) - { - //DebugLog.LogToFileOnly("Another period started"); - MainDataStore.familyCount = RealCityResidentAI.familyCount; - MainDataStore.citizenCount = RealCityResidentAI.citizenCount; - MainDataStore.level2HighWealth = RealCityResidentAI.level2HighWealth; - MainDataStore.level3HighWealth = RealCityResidentAI.level3HighWealth; - MainDataStore.level1HighWealth = RealCityResidentAI.level1HighWealth; - if (RealCityResidentAI.familyCount != 0) - { - MainDataStore.citizenSalaryPerFamily = ((RealCityResidentAI.citizenSalaryCount / RealCityResidentAI.familyCount)); - MainDataStore.citizenExpensePerFamily = ((RealCityResidentAI.citizenExpenseCount / RealCityResidentAI.familyCount)); - } - MainDataStore.citizenExpense = RealCityResidentAI.citizenExpenseCount; - MainDataStore.citizenSalaryTaxTotal = RealCityResidentAI.citizenSalaryTaxTotal; - MainDataStore.citizenSalaryTotal = RealCityResidentAI.citizenSalaryCount; - if (MainDataStore.familyCount < MainDataStore.familyWeightStableHigh) - { - MainDataStore.familyWeightStableHigh = (uint)MainDataStore.familyCount; - } - else - { - MainDataStore.familyWeightStableHigh = RealCityResidentAI.familyWeightStableHigh; - } - if (MainDataStore.familyCount < MainDataStore.familyWeightStableLow) - { - MainDataStore.familyWeightStableLow = (uint)MainDataStore.familyCount; - } - else - { - MainDataStore.familyWeightStableLow = RealCityResidentAI.familyWeightStableLow; - } - - RealCityPrivateBuildingAI.profitBuildingMoneyFinal = RealCityPrivateBuildingAI.profitBuildingMoney; - - RealCityResidentAI.level3HighWealth = 0; - RealCityResidentAI.level2HighWealth = 0; - RealCityResidentAI.level1HighWealth = 0; - RealCityResidentAI.familyCount = 0; - RealCityResidentAI.citizenCount = 0; - RealCityResidentAI.citizenSalaryCount = 0; - RealCityResidentAI.citizenExpenseCount = 0; - RealCityResidentAI.citizenSalaryTaxTotal = 0; - RealCityResidentAI.tempCitizenSalaryTaxTotal = 0f; - RealCityResidentAI.familyWeightStableHigh = 0; - RealCityResidentAI.familyWeightStableLow = 0; - RealCityPrivateBuildingAI.profitBuildingMoney = 0; - } - - RealCityResidentAI.preCitizenId = homeID; - RealCityResidentAI.familyCount++; - - if (homeID > 524288) - { - DebugLog.LogToFileOnly("Error: citizen ID greater than 524288"); - } - - //DebugLog.LogToFileOnly($"ProcessCitizen pre family {homeID} moneny {CitizenUnitData.familyMoney[homeID]}"); - //ProcessCitizen pre, gather all citizenMoney to familyMoney - ProcessCitizen(homeID, ref data, true); - //DebugLog.LogToFileOnly($"ProcessCitizen post family {homeID} moneny {CitizenUnitData.familyMoney[homeID]}"); - //1.We calculate citizen income - int familySalaryCurrent = 0; - familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen0, false); - familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen1, false); - familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen2, false); - familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen3, false); - familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen4, false); - RealCityResidentAI.citizenSalaryCount = RealCityResidentAI.citizenSalaryCount + familySalaryCurrent; - if (familySalaryCurrent < 0) - { - DebugLog.LogToFileOnly("familySalaryCurrent< 0 in ResidentAI"); - familySalaryCurrent = 0; - } - - //2.We calculate salary tax - float tax = (float)(Politics.residentTax << 1) * familySalaryCurrent / 100f; - RealCityResidentAI.tempCitizenSalaryTaxTotal = RealCityResidentAI.tempCitizenSalaryTaxTotal + (int)tax; - RealCityResidentAI.citizenSalaryTaxTotal = (int)RealCityResidentAI.tempCitizenSalaryTaxTotal; - ProcessCitizenIncomeTax(homeID, tax); - - //3. We calculate expense - int educationFee = 0; - int hospitalFee = 0; - int expenseRate = 0; - CitizenManager instance = Singleton.instance; - int tempEducationFee; - int tempHospitalFee; - if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) - { - GetExpenseRate(data.m_citizen4, out expenseRate, out tempEducationFee, out tempHospitalFee); - educationFee += tempEducationFee; - hospitalFee += tempHospitalFee; - } - if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) - { - GetExpenseRate(data.m_citizen3, out expenseRate, out tempEducationFee, out tempHospitalFee); - educationFee += tempEducationFee; - hospitalFee += tempHospitalFee; - } - if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) - { - GetExpenseRate(data.m_citizen2, out expenseRate, out tempEducationFee, out tempHospitalFee); - educationFee += tempEducationFee; - hospitalFee += tempHospitalFee; - } - if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) - { - GetExpenseRate(data.m_citizen1, out expenseRate, out tempEducationFee, out tempHospitalFee); - educationFee += tempEducationFee; - hospitalFee += tempHospitalFee; - } - if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) - { - GetExpenseRate(data.m_citizen0, out expenseRate, out tempEducationFee, out tempHospitalFee); - educationFee += tempEducationFee; - hospitalFee += tempHospitalFee; - } - ProcessCitizenHouseRent(homeID, expenseRate); - //campus DLC added. - expenseRate = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Economics, expenseRate); - RealCityResidentAI.citizenExpenseCount += (educationFee + expenseRate + hospitalFee); - - //4. income - expense - float incomeMinusExpense = familySalaryCurrent - tax - educationFee - expenseRate; - CitizenUnitData.familyMoney[homeID] += incomeMinusExpense; - - //5. Limit familyMoney - if (CitizenUnitData.familyMoney[homeID] > 100000000f) - { - CitizenUnitData.familyMoney[homeID] = 100000000f; - } - - if (CitizenUnitData.familyMoney[homeID] < -100000000f) - { - CitizenUnitData.familyMoney[homeID] = -100000000f; - } - - //6. Caculate minimumLivingAllowance and benefitOffset - if (CitizenUnitData.familyMoney[homeID] < (-(Politics.benefitOffset * MainDataStore.govermentSalary) / 100f)) - { - int num = (int)(-CitizenUnitData.familyMoney[homeID]); - CitizenUnitData.familyMoney[homeID] += num; - MainDataStore.minimumLivingAllowance += num; - Singleton.instance.FetchResource((EconomyManager.Resource)17, num, ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1); - } - else - { - if (Politics.benefitOffset > 0) - { - CitizenUnitData.familyMoney[homeID] += ((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f); - MainDataStore.minimumLivingAllowance += (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f); - Singleton.instance.FetchResource((EconomyManager.Resource)17, (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f), ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1); - } - } - - var canBuyGoodMoney = MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping); - var familySalaryCurrentTmp = (familySalaryCurrent > canBuyGoodMoney) ? canBuyGoodMoney : familySalaryCurrent; - - //7. Process citizen status - if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 30) - { - RealCityResidentAI.level3HighWealth++; - } - else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 20) - { - RealCityResidentAI.level2HighWealth++; - } - else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 10) - { - RealCityResidentAI.level1HighWealth++; - } - - //8 reduce goods - float reducedGoods; - if (CitizenUnitData.familyMoney[homeID] < canBuyGoodMoney) - reducedGoods = CitizenUnitData.familyGoods[homeID] / 100f; - else - reducedGoods = CitizenUnitData.familyGoods[homeID] / 50f; - - CitizenUnitData.familyGoods[homeID] = (ushort)COMath.Clamp((int)(CitizenUnitData.familyGoods[homeID] - reducedGoods), 0, 60000); - data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f); - - //9 Buy good from outside and try move family - if (data.m_goods == 0) - { - if ((CitizenUnitData.familyMoney[homeID] > canBuyGoodMoney) && (familySalaryCurrent > 1)) - { - uint citizenID = 0u; - int familySize = 0; - if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) - { - familySize++; - citizenID = data.m_citizen4; - instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; - } - if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) - { - familySize++; - citizenID = data.m_citizen3; - instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; - } - if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) - { - familySize++; - citizenID = data.m_citizen2; - instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; - } - if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) - { - familySize++; - citizenID = data.m_citizen1; - instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; - } - if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) - { - familySize++; - citizenID = data.m_citizen0; - instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; - } - - Singleton.instance.TryMoveFamily(citizenID, ref instance.m_citizens.m_buffer[citizenID], familySize); - - CitizenUnitData.familyGoods[homeID] = 5000; - data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f); - CitizenUnitData.familyMoney[homeID] -= canBuyGoodMoney; - MainDataStore.outsideGovermentMoney += (canBuyGoodMoney * MainDataStore.outsideGovermentProfitRatio); - MainDataStore.outsideTouristMoney += (canBuyGoodMoney * MainDataStore.outsideCompanyProfitRatio * MainDataStore.outsideTouristSalaryProfitRatio); - } - } - - //ProcessCitizen post, split all familyMoney to CitizenMoney - ProcessCitizen(homeID, ref data, false); - } - - - public static void ProcessCitizenIncomeTax(uint homeID, float tax) - { - CitizenManager instance = Singleton.instance; - ushort building = instance.m_units.m_buffer[(int)((UIntPtr)homeID)].m_building; - Building buildingdata = Singleton.instance.m_buildings.m_buffer[building]; - Singleton.instance.AddPrivateIncome((int)(tax), buildingdata.Info.m_class.m_service, buildingdata.Info.m_class.m_subService, buildingdata.Info.m_class.m_level, 112333); - } - - public static void ProcessCitizenHouseRent(uint homeID, int expenserate) - { - CitizenManager instance = Singleton.instance; - ushort building = instance.m_units.m_buffer[(int)((UIntPtr)homeID)].m_building; - Building buildingdata = Singleton.instance.m_buildings.m_buffer[building]; - Singleton.instance.AddPrivateIncome(expenserate * 100, buildingdata.Info.m_class.m_service, buildingdata.Info.m_class.m_subService, buildingdata.Info.m_class.m_level, 100); - } - - public static void Prefix(uint homeID, ref CitizenUnit data) - { - if (CitizenUnitData.familyGoods[homeID] == 65535) - { - //first time - if (data.m_goods < 6000) - CitizenUnitData.familyGoods[homeID] = (ushort)(data.m_goods * 10); - else - CitizenUnitData.familyGoods[homeID] = 60000; - } - } - - // ResidentAI - public static void Postfix(uint homeID, ref CitizenUnit data) - { - if ((Singleton.instance.m_buildings.m_buffer[data.m_building].m_flags & (Building.Flags.Completed | Building.Flags.Upgrading)) != Building.Flags.None) - { - ProcessFamily(homeID, ref data); - } - } - - public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, out int educationFee, out int hospitalFee) - { - BuildingManager instance1 = Singleton.instance; - CitizenManager instance2 = Singleton.instance; - var buildingID = Singleton.instance.m_citizens.m_buffer[citizenID].m_homeBuilding; - incomeAccumulation = BuildingData.buildingWorkCount[buildingID]; - - educationFee = 0; - hospitalFee = 0; - if ((Singleton.instance.m_citizens.m_buffer[citizenID].m_flags & Citizen.Flags.Student) != Citizen.Flags.None) - { - //Only university will cost money - bool isCampusDLC = false; - //Campus DLC cost 50 - ushort visitBuilding = Singleton.instance.m_citizens.m_buffer[citizenID].m_visitBuilding; - if (visitBuilding != 0u) - { - Building buildingData = Singleton.instance.m_buildings.m_buffer[visitBuilding]; - if (buildingData.Info.m_class.m_service == ItemClass.Service.PlayerEducation) - { - var tempEducationFee = (uint)((MainDataStore.govermentSalary) / 100f); - if (tempEducationFee < 1) - tempEducationFee = 1; - - educationFee = (int)tempEducationFee * 100; - isCampusDLC = true; - } - } - - if (!isCampusDLC) - { - if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education2)) - { - educationFee = MainDataStore.govermentSalary >> 1; - Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level3, 115333); - } - else if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education1)) - { - educationFee = MainDataStore.govermentSalary >> 2; - Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level2, 115333); - } - else - { - educationFee = MainDataStore.govermentSalary >> 2; - Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level1, 115333); - } - } - } - - if (Singleton.instance.m_citizens.m_buffer[citizenID].Sick) - { - ushort visitBuilding = Singleton.instance.m_citizens.m_buffer[citizenID].m_visitBuilding; - if (visitBuilding != 0u) - { - Building buildingData = Singleton.instance.m_buildings.m_buffer[visitBuilding]; - if (visitBuilding != Singleton.instance.m_citizens.m_buffer[citizenID].m_workBuilding) - { - if (buildingData.Info.m_class.m_service == ItemClass.Service.HealthCare) - { - hospitalFee = MainDataStore.govermentSalary >> 1; - Singleton.instance.AddPrivateIncome(hospitalFee, ItemClass.Service.HealthCare, ItemClass.SubService.None, ItemClass.Level.Level2, 115333); - } - } - } - } - } - - public static void GetVoteTickets() - { - System.Random rand = new System.Random(); - if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance != (800 + RealCityEconomyExtension.partyTrendStrength)) - { - if (rand.Next(64) <= 1) - { - DebugLog.LogToFileOnly($"Error: GetVoteTickets Chance is not equal 800 {(Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance)}"); - } - } - - int voteRandom = rand.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; - if (voteRandom < Politics.cPartyChance) - { - Politics.cPartyTickets++; - } - else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance) - { - Politics.gPartyTickets++; - } - else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) - { - Politics.sPartyTickets++; - } - else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) - { - Politics.lPartyTickets++; - } - else - { - Politics.nPartyTickets++; - } - } - - public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) - { - if ((int)Citizen.GetAgeGroup(citizen.m_age) >= 2) - { - if (Politics.parliamentCount == 1) - { - Politics.cPartyChance = 0; - Politics.gPartyChance = 0; - Politics.sPartyChance = 0; - Politics.lPartyChance = 0; - Politics.nPartyChance = 0; - - Politics.cPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 0] << 1); - Politics.gPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 1] << 1); - Politics.sPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 2] << 1); - Politics.lPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 3] << 1); - Politics.nPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 4] << 1); - - int idex = 14; - if (RealCityResidentAI.IsGoverment(citizen.m_workBuilding)) - { - idex = 0; - } - - switch (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_subService) - { - case ItemClass.SubService.CommercialLow: - case ItemClass.SubService.CommercialHigh: - if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) - { - idex = 1; - } - else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) - { - idex = 2; - } - else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) - { - idex = 3; - } - break; - case ItemClass.SubService.CommercialTourist: - case ItemClass.SubService.CommercialLeisure: - idex = 4; break; - case ItemClass.SubService.CommercialEco: - idex = 5; break; - case ItemClass.SubService.IndustrialGeneric: - if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) - { - idex = 6; - } - else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) - { - idex = 7; - } - else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) - { - idex = 8; - } - break; - case ItemClass.SubService.IndustrialFarming: - case ItemClass.SubService.IndustrialForestry: - case ItemClass.SubService.IndustrialOil: - case ItemClass.SubService.IndustrialOre: - idex = 9; break; - case ItemClass.SubService.OfficeGeneric: - if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) - { - idex = 10; - } - else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) - { - idex = 11; - } - else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) - { - idex = 12; - } - break; - case ItemClass.SubService.OfficeHightech: - idex = 13; break; - } - - if (idex < 0 || idex > 14) - { - DebugLog.LogToFileOnly($"Error: GetVoteChance workplace idex {idex}"); - } - - - Politics.cPartyChance += (ushort)(Politics.workplace[idex, 0] << 1); - Politics.gPartyChance += (ushort)(Politics.workplace[idex, 1] << 1); - Politics.sPartyChance += (ushort)(Politics.workplace[idex, 2] << 1); - Politics.lPartyChance += (ushort)(Politics.workplace[idex, 3] << 1); - Politics.nPartyChance += (ushort)(Politics.workplace[idex, 4] << 1); - - if (CitizenUnitData.familyMoney[homeID] < 5000) - { - idex = 0; - } - else if (CitizenUnitData.familyMoney[homeID] >= 20000) - { - idex = 2; - } - else - { - idex = 1; - } - - if (idex < 0 || idex > 3) - { - DebugLog.LogToFileOnly($"Error: GetVoteChance Invaid money idex = {idex}"); - } - Politics.cPartyChance += (ushort)(Politics.money[idex, 0] << 1); - Politics.gPartyChance += (ushort)(Politics.money[idex, 1] << 1); - Politics.sPartyChance += (ushort)(Politics.money[idex, 2] << 1); - Politics.lPartyChance += (ushort)(Politics.money[idex, 3] << 1); - Politics.nPartyChance += (ushort)(Politics.money[idex, 4] << 1); - - int temp = 0; - - temp = (int)Citizen.GetAgeGroup(citizen.m_age) - 2; - - if (temp < 0) - { - DebugLog.LogToFileOnly($"Error: GetVoteChance temp = {temp} < 0, GetAgeGroup = {Citizen.GetAgeGroup(citizen.m_age)}"); - } - - Politics.cPartyChance += Politics.age[temp, 0]; - Politics.gPartyChance += Politics.age[temp, 1]; - Politics.sPartyChance += Politics.age[temp, 2]; - Politics.lPartyChance += Politics.age[temp, 3]; - Politics.nPartyChance += Politics.age[temp, 4]; - - temp = (int)Citizen.GetGender(citizenID); - - - Politics.cPartyChance += Politics.gender[temp, 0]; - Politics.gPartyChance += Politics.gender[temp, 1]; - Politics.sPartyChance += Politics.gender[temp, 2]; - Politics.lPartyChance += Politics.gender[temp, 3]; - Politics.nPartyChance += Politics.gender[temp, 4]; - - if (RealCityEconomyExtension.partyTrend == 0) - { - Politics.cPartyChance += RealCityEconomyExtension.partyTrendStrength; - } - else if (RealCityEconomyExtension.partyTrend == 1) - { - Politics.gPartyChance += RealCityEconomyExtension.partyTrendStrength; - } - else if (RealCityEconomyExtension.partyTrend == 2) - { - Politics.sPartyChance += RealCityEconomyExtension.partyTrendStrength; - } - else if (RealCityEconomyExtension.partyTrend == 3) - { - Politics.lPartyChance += RealCityEconomyExtension.partyTrendStrength; - } - else if (RealCityEconomyExtension.partyTrend == 4) - { - Politics.nPartyChance += RealCityEconomyExtension.partyTrendStrength; - } - else - { - DebugLog.LogToFileOnly($"Error: GetVoteChance Invalid partyTrend = {RealCityEconomyExtension.partyTrend}"); - } - - GetVoteTickets(); - } - } - } - } + } + } + } + + if (temp != 0) { + for (int i = 0; i <= 4; i++) { + fieldInfo = data.GetType().GetField($"m_citizen{i}"); + uint m_citizenI = (uint)fieldInfo.GetValue(data); + + if (m_citizenI != 0) { + Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; + if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) { + CitizenData.citizenMoney[m_citizenI] = CitizenUnitData.familyMoney[homeID] / temp; + } + } + } + } + } + } + + public static void ProcessFamily(uint homeID, ref CitizenUnit data) { + if (RealCityResidentAI.preCitizenId > homeID) { + //DebugLog.LogToFileOnly("Another period started"); + MainDataStore.familyCount = RealCityResidentAI.familyCount; + MainDataStore.citizenCount = RealCityResidentAI.citizenCount; + MainDataStore.level2HighWealth = RealCityResidentAI.level2HighWealth; + MainDataStore.level3HighWealth = RealCityResidentAI.level3HighWealth; + MainDataStore.level1HighWealth = RealCityResidentAI.level1HighWealth; + if (RealCityResidentAI.familyCount != 0) { + MainDataStore.citizenSalaryPerFamily = ((RealCityResidentAI.citizenSalaryCount / RealCityResidentAI.familyCount)); + MainDataStore.citizenExpensePerFamily = ((RealCityResidentAI.citizenExpenseCount / RealCityResidentAI.familyCount)); + } + MainDataStore.citizenExpense = RealCityResidentAI.citizenExpenseCount; + MainDataStore.citizenSalaryTaxTotal = RealCityResidentAI.citizenSalaryTaxTotal; + MainDataStore.citizenSalaryTotal = RealCityResidentAI.citizenSalaryCount; + if (MainDataStore.familyCount < MainDataStore.familyWeightStableHigh) { + MainDataStore.familyWeightStableHigh = (uint)MainDataStore.familyCount; + } else { + MainDataStore.familyWeightStableHigh = RealCityResidentAI.familyWeightStableHigh; + } + if (MainDataStore.familyCount < MainDataStore.familyWeightStableLow) { + MainDataStore.familyWeightStableLow = (uint)MainDataStore.familyCount; + } else { + MainDataStore.familyWeightStableLow = RealCityResidentAI.familyWeightStableLow; + } + + RealCityPrivateBuildingAI.profitBuildingMoneyFinal = RealCityPrivateBuildingAI.profitBuildingMoney; + + RealCityResidentAI.level3HighWealth = 0; + RealCityResidentAI.level2HighWealth = 0; + RealCityResidentAI.level1HighWealth = 0; + RealCityResidentAI.familyCount = 0; + RealCityResidentAI.citizenCount = 0; + RealCityResidentAI.citizenSalaryCount = 0; + RealCityResidentAI.citizenExpenseCount = 0; + RealCityResidentAI.citizenSalaryTaxTotal = 0; + RealCityResidentAI.tempCitizenSalaryTaxTotal = 0f; + RealCityResidentAI.familyWeightStableHigh = 0; + RealCityResidentAI.familyWeightStableLow = 0; + RealCityPrivateBuildingAI.profitBuildingMoney = 0; + } + + RealCityResidentAI.preCitizenId = homeID; + RealCityResidentAI.familyCount++; + + if (homeID > 524288) { + DebugLog.LogToFileOnly("Error: citizen ID greater than 524288"); + } + + //DebugLog.LogToFileOnly($"ProcessCitizen pre family {homeID} moneny {CitizenUnitData.familyMoney[homeID]}"); + //把家庭成员的财产汇总。gather all citizenMoney to familyMoney + ProcessCitizen(homeID, ref data, true); + //DebugLog.LogToFileOnly($"ProcessCitizen post family {homeID} moneny {CitizenUnitData.familyMoney[homeID]}"); + //1.We calculate citizen income + int familySalaryCurrent = 0; + familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen0, false); + familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen1, false); + familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen2, false); + familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen3, false); + familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen4, false); + RealCityResidentAI.citizenSalaryCount = RealCityResidentAI.citizenSalaryCount + familySalaryCurrent; + if (familySalaryCurrent < 0) { + DebugLog.LogToFileOnly("familySalaryCurrent< 0 in ResidentAI"); + familySalaryCurrent = 0; + } + + //2.We calculate salary tax + float tax = (float)(Politics.residentTax << 1) * familySalaryCurrent / 100f; + RealCityResidentAI.tempCitizenSalaryTaxTotal = RealCityResidentAI.tempCitizenSalaryTaxTotal + (int)tax; + RealCityResidentAI.citizenSalaryTaxTotal = (int)RealCityResidentAI.tempCitizenSalaryTaxTotal; + ProcessCitizenIncomeTax(homeID, tax); + + //3. We calculate expense + int educationFee = 0; + int hospitalFee = 0; + int expenseRate = 0; + CitizenManager instance = Singleton.instance; + int tempEducationFee; + int tempHospitalFee; + if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) { + GetExpenseRate(data.m_citizen4, out expenseRate, out tempEducationFee, out tempHospitalFee); + educationFee += tempEducationFee; + hospitalFee += tempHospitalFee; + } + if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) { + GetExpenseRate(data.m_citizen3, out expenseRate, out tempEducationFee, out tempHospitalFee); + educationFee += tempEducationFee; + hospitalFee += tempHospitalFee; + } + if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) { + GetExpenseRate(data.m_citizen2, out expenseRate, out tempEducationFee, out tempHospitalFee); + educationFee += tempEducationFee; + hospitalFee += tempHospitalFee; + } + if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) { + GetExpenseRate(data.m_citizen1, out expenseRate, out tempEducationFee, out tempHospitalFee); + educationFee += tempEducationFee; + hospitalFee += tempHospitalFee; + } + if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) { + GetExpenseRate(data.m_citizen0, out expenseRate, out tempEducationFee, out tempHospitalFee); + educationFee += tempEducationFee; + hospitalFee += tempHospitalFee; + } + ProcessCitizenHouseRent(homeID, expenseRate); + //campus DLC added. + expenseRate = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Economics, expenseRate); + RealCityResidentAI.citizenExpenseCount += (educationFee + expenseRate + hospitalFee); + + //4. income - expense + float incomeMinusExpense = familySalaryCurrent - tax - educationFee - expenseRate; + CitizenUnitData.familyMoney[homeID] += incomeMinusExpense; + + //5. Limit familyMoney + if (CitizenUnitData.familyMoney[homeID] > 100000000f) { + CitizenUnitData.familyMoney[homeID] = 100000000f; + } + + if (CitizenUnitData.familyMoney[homeID] < -100000000f) { + CitizenUnitData.familyMoney[homeID] = -100000000f; + } + + //6. Caculate minimumLivingAllowance and benefitOffset + if (CitizenUnitData.familyMoney[homeID] < (-(Politics.benefitOffset * MainDataStore.govermentSalary) / 100f)) { + int num = (int)(-CitizenUnitData.familyMoney[homeID]); + CitizenUnitData.familyMoney[homeID] += num; + MainDataStore.minimumLivingAllowance += num; + Singleton.instance.FetchResource((EconomyManager.Resource)17, num, ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1); + } else { + if (Politics.benefitOffset > 0) { + CitizenUnitData.familyMoney[homeID] += ((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f); + MainDataStore.minimumLivingAllowance += (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f); + Singleton.instance.FetchResource((EconomyManager.Resource)17, (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f), ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1); + } + } + + var canBuyGoodMoney = MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping); + var familySalaryCurrentTmp = (familySalaryCurrent > canBuyGoodMoney) ? canBuyGoodMoney : familySalaryCurrent; + + //7. Process citizen status + if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 30) { + RealCityResidentAI.level3HighWealth++; + } else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 20) { + RealCityResidentAI.level2HighWealth++; + } else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 10) { + RealCityResidentAI.level1HighWealth++; + } + + //8 reduce goods + float reducedGoods; + if (CitizenUnitData.familyMoney[homeID] < canBuyGoodMoney) + reducedGoods = CitizenUnitData.familyGoods[homeID] / 100f; + else + reducedGoods = CitizenUnitData.familyGoods[homeID] / 50f; + + CitizenUnitData.familyGoods[homeID] = (ushort)COMath.Clamp((int)(CitizenUnitData.familyGoods[homeID] - reducedGoods), 0, 60000); + data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f); + + //9 Buy good from outside and try move family + if (data.m_goods == 0) { + if ((CitizenUnitData.familyMoney[homeID] > canBuyGoodMoney) && (familySalaryCurrent > 1)) { + uint citizenID = 0u; + int familySize = 0; + if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) { + familySize++; + citizenID = data.m_citizen4; + instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; + } + if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) { + familySize++; + citizenID = data.m_citizen3; + instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; + } + if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) { + familySize++; + citizenID = data.m_citizen2; + instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; + } + if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) { + familySize++; + citizenID = data.m_citizen1; + instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; + } + if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) { + familySize++; + citizenID = data.m_citizen0; + instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; + } + + Singleton.instance.TryMoveFamily(citizenID, ref instance.m_citizens.m_buffer[citizenID], familySize); + + CitizenUnitData.familyGoods[homeID] = 5000; + data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f); + CitizenUnitData.familyMoney[homeID] -= canBuyGoodMoney; + MainDataStore.outsideGovermentMoney += (canBuyGoodMoney * MainDataStore.outsideGovermentProfitRatio); + MainDataStore.outsideTouristMoney += (canBuyGoodMoney * MainDataStore.outsideCompanyProfitRatio * MainDataStore.outsideTouristSalaryProfitRatio); + } + } + + //把家庭财产分配给家庭成员。split all familyMoney to CitizenMoney + ProcessCitizen(homeID, ref data, false); + } + + + public static void ProcessCitizenIncomeTax(uint homeID, float tax) { + CitizenManager instance = Singleton.instance; + ushort building = instance.m_units.m_buffer[(int)((UIntPtr)homeID)].m_building; + Building buildingdata = Singleton.instance.m_buildings.m_buffer[building]; + Singleton.instance.AddPrivateIncome((int)(tax), buildingdata.Info.m_class.m_service, buildingdata.Info.m_class.m_subService, buildingdata.Info.m_class.m_level, 112333); + } + + public static void ProcessCitizenHouseRent(uint homeID, int expenserate) { + CitizenManager instance = Singleton.instance; + ushort building = instance.m_units.m_buffer[(int)((UIntPtr)homeID)].m_building; + Building buildingdata = Singleton.instance.m_buildings.m_buffer[building]; + Singleton.instance.AddPrivateIncome(expenserate * 100, buildingdata.Info.m_class.m_service, buildingdata.Info.m_class.m_subService, buildingdata.Info.m_class.m_level, 100); + } + + public static void Prefix(uint homeID, ref CitizenUnit data) { + if (CitizenUnitData.familyGoods[homeID] == 65535) { + //first time + if (data.m_goods < 6000) + CitizenUnitData.familyGoods[homeID] = (ushort)(data.m_goods * 10); + else + CitizenUnitData.familyGoods[homeID] = 60000; + } + } + + // ResidentAI + public static void Postfix(uint homeID, ref CitizenUnit data) { + if ((Singleton.instance.m_buildings.m_buffer[data.m_building].m_flags & (Building.Flags.Completed | Building.Flags.Upgrading)) != Building.Flags.None) { + ProcessFamily(homeID, ref data); + } + } + + public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, out int educationFee, out int hospitalFee) { + BuildingManager instance1 = Singleton.instance; + CitizenManager instance2 = Singleton.instance; + var buildingID = Singleton.instance.m_citizens.m_buffer[citizenID].m_homeBuilding; + incomeAccumulation = BuildingData.buildingWorkCount[buildingID]; + + educationFee = 0; + hospitalFee = 0; + if ((Singleton.instance.m_citizens.m_buffer[citizenID].m_flags & Citizen.Flags.Student) != Citizen.Flags.None) { + //Only university will cost money + bool isCampusDLC = false; + //Campus DLC cost 50 + ushort visitBuilding = Singleton.instance.m_citizens.m_buffer[citizenID].m_visitBuilding; + if (visitBuilding != 0u) { + Building buildingData = Singleton.instance.m_buildings.m_buffer[visitBuilding]; + if (buildingData.Info.m_class.m_service == ItemClass.Service.PlayerEducation) { + var tempEducationFee = (uint)((MainDataStore.govermentSalary) / 100f); + if (tempEducationFee < 1) + tempEducationFee = 1; + + educationFee = (int)tempEducationFee * 100; + isCampusDLC = true; + } + } + + if (!isCampusDLC) { + if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education2)) { + educationFee = MainDataStore.govermentSalary >> 1; + Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level3, 115333); + } else if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education1)) { + educationFee = MainDataStore.govermentSalary >> 2; + Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level2, 115333); + } else { + educationFee = MainDataStore.govermentSalary >> 2; + Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level1, 115333); + } + } + } + + if (Singleton.instance.m_citizens.m_buffer[citizenID].Sick) { + ushort visitBuilding = Singleton.instance.m_citizens.m_buffer[citizenID].m_visitBuilding; + if (visitBuilding != 0u) { + Building buildingData = Singleton.instance.m_buildings.m_buffer[visitBuilding]; + if (visitBuilding != Singleton.instance.m_citizens.m_buffer[citizenID].m_workBuilding) { + if (buildingData.Info.m_class.m_service == ItemClass.Service.HealthCare) { + hospitalFee = MainDataStore.govermentSalary >> 1; + Singleton.instance.AddPrivateIncome(hospitalFee, ItemClass.Service.HealthCare, ItemClass.SubService.None, ItemClass.Level.Level2, 115333); + } + } + } + } + } + + public static void GetVoteTickets() { + System.Random rand = new System.Random(); + if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance != (800 + RealCityEconomyExtension.partyTrendStrength)) { + if (rand.Next(64) <= 1) { + DebugLog.LogToFileOnly($"Error: GetVoteTickets Chance is not equal 800 {(Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance)}"); + } + } + + int voteRandom = rand.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; + if (voteRandom < Politics.cPartyChance) { + Politics.cPartyTickets++; + } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance) { + Politics.gPartyTickets++; + } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) { + Politics.sPartyTickets++; + } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) { + Politics.lPartyTickets++; + } else { + Politics.nPartyTickets++; + } + } + + public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { + if ((int)Citizen.GetAgeGroup(citizen.m_age) >= 2) { + if (Politics.parliamentCount == 1) { + Politics.cPartyChance = 0; + Politics.gPartyChance = 0; + Politics.sPartyChance = 0; + Politics.lPartyChance = 0; + Politics.nPartyChance = 0; + + Politics.cPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 0] << 1); + Politics.gPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 1] << 1); + Politics.sPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 2] << 1); + Politics.lPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 3] << 1); + Politics.nPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 4] << 1); + + int idex = 14; + if (RealCityResidentAI.IsGoverment(citizen.m_workBuilding)) { + idex = 0; + } + + switch (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_subService) { + case ItemClass.SubService.CommercialLow: + case ItemClass.SubService.CommercialHigh: + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + idex = 1; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + idex = 2; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + idex = 3; + } + break; + case ItemClass.SubService.CommercialTourist: + case ItemClass.SubService.CommercialLeisure: + idex = 4; break; + case ItemClass.SubService.CommercialEco: + idex = 5; break; + case ItemClass.SubService.IndustrialGeneric: + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + idex = 6; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + idex = 7; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + idex = 8; + } + break; + case ItemClass.SubService.IndustrialFarming: + case ItemClass.SubService.IndustrialForestry: + case ItemClass.SubService.IndustrialOil: + case ItemClass.SubService.IndustrialOre: + idex = 9; break; + case ItemClass.SubService.OfficeGeneric: + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + idex = 10; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + idex = 11; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + idex = 12; + } + break; + case ItemClass.SubService.OfficeHightech: + idex = 13; break; + } + + if (idex < 0 || idex > 14) { + DebugLog.LogToFileOnly($"Error: GetVoteChance workplace idex {idex}"); + } + + + Politics.cPartyChance += (ushort)(Politics.workplace[idex, 0] << 1); + Politics.gPartyChance += (ushort)(Politics.workplace[idex, 1] << 1); + Politics.sPartyChance += (ushort)(Politics.workplace[idex, 2] << 1); + Politics.lPartyChance += (ushort)(Politics.workplace[idex, 3] << 1); + Politics.nPartyChance += (ushort)(Politics.workplace[idex, 4] << 1); + + if (CitizenUnitData.familyMoney[homeID] < 5000) { + idex = 0; + } else if (CitizenUnitData.familyMoney[homeID] >= 20000) { + idex = 2; + } else { + idex = 1; + } + + if (idex < 0 || idex > 3) { + DebugLog.LogToFileOnly($"Error: GetVoteChance Invaid money idex = {idex}"); + } + Politics.cPartyChance += (ushort)(Politics.money[idex, 0] << 1); + Politics.gPartyChance += (ushort)(Politics.money[idex, 1] << 1); + Politics.sPartyChance += (ushort)(Politics.money[idex, 2] << 1); + Politics.lPartyChance += (ushort)(Politics.money[idex, 3] << 1); + Politics.nPartyChance += (ushort)(Politics.money[idex, 4] << 1); + + int temp = 0; + + temp = (int)Citizen.GetAgeGroup(citizen.m_age) - 2; + + if (temp < 0) { + DebugLog.LogToFileOnly($"Error: GetVoteChance temp = {temp} < 0, GetAgeGroup = {Citizen.GetAgeGroup(citizen.m_age)}"); + } + + Politics.cPartyChance += Politics.age[temp, 0]; + Politics.gPartyChance += Politics.age[temp, 1]; + Politics.sPartyChance += Politics.age[temp, 2]; + Politics.lPartyChance += Politics.age[temp, 3]; + Politics.nPartyChance += Politics.age[temp, 4]; + + temp = (int)Citizen.GetGender(citizenID); + + + Politics.cPartyChance += Politics.gender[temp, 0]; + Politics.gPartyChance += Politics.gender[temp, 1]; + Politics.sPartyChance += Politics.gender[temp, 2]; + Politics.lPartyChance += Politics.gender[temp, 3]; + Politics.nPartyChance += Politics.gender[temp, 4]; + + if (RealCityEconomyExtension.partyTrend == 0) { + Politics.cPartyChance += RealCityEconomyExtension.partyTrendStrength; + } else if (RealCityEconomyExtension.partyTrend == 1) { + Politics.gPartyChance += RealCityEconomyExtension.partyTrendStrength; + } else if (RealCityEconomyExtension.partyTrend == 2) { + Politics.sPartyChance += RealCityEconomyExtension.partyTrendStrength; + } else if (RealCityEconomyExtension.partyTrend == 3) { + Politics.lPartyChance += RealCityEconomyExtension.partyTrendStrength; + } else if (RealCityEconomyExtension.partyTrend == 4) { + Politics.nPartyChance += RealCityEconomyExtension.partyTrendStrength; + } else { + DebugLog.LogToFileOnly($"Error: GetVoteChance Invalid partyTrend = {RealCityEconomyExtension.partyTrend}"); + } + + GetVoteTickets(); + } + } + } + } } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 745daff..4ea8581 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RealCity")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,4 +32,4 @@ // 方法是按如下所示使用“*”: : // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("10.0.08.24")] -[assembly: AssemblyFileVersion("10.0.08.24")] +[assembly: AssemblyFileVersion("10.0.08.24")] \ No newline at end of file diff --git a/RealCity.cs b/RealCity.cs index 55c2d60..da5c23a 100644 --- a/RealCity.cs +++ b/RealCity.cs @@ -7,86 +7,70 @@ namespace RealCity { - public class RealCity : IUserMod - { - public static bool IsEnabled = false; - public static bool debugMode = false; - public static bool reduceVehicle = false; - public static bool realCityV10 = true; - public static bool noPassengerCar = true; + public class RealCity : IUserMod + { + public static bool IsEnabled = false; + public static bool debugMode = false; + public static bool reduceVehicle = false; + public static bool realCityV10 = true; + public static bool noPassengerCar = true; - public string Name - { - get { return "Real City"; } - } + public string Name { + get { return "Real City"; } + } - public string Description - { - get { return "Make your city reality, Combine CS and SimCity in game playing"; } - } + public string Description { + get { return "Make your city reality, Combine CS and SimCity in game playing"; } + } - public void OnEnabled() - { - IsEnabled = true; - FileStream fs = File.Create("RealCity.txt"); - fs.Close(); - HarmonyHelper.EnsureHarmonyInstalled(); - if (UIView.GetAView() != null) - { - OnGameIntroLoaded(); - } - else - { - LoadingManager.instance.m_introLoaded += OnGameIntroLoaded; - } - } + public void OnEnabled() { + IsEnabled = true; + FileStream fs = File.Create("RealCity.txt"); + fs.Close(); + HarmonyHelper.EnsureHarmonyInstalled(); + if (UIView.GetAView() != null) { + OnGameIntroLoaded(); + } else { + LoadingManager.instance.m_introLoaded += OnGameIntroLoaded; + } + } - public void OnDisabled() - { - IsEnabled = false; - LoadingManager.instance.m_introLoaded -= OnGameIntroLoaded; - } + public void OnDisabled() { + IsEnabled = false; + LoadingManager.instance.m_introLoaded -= OnGameIntroLoaded; + } - private static void OnGameIntroLoaded() - { - ModsCompatibilityChecker mcc = new ModsCompatibilityChecker(); - mcc.PerformModCheck(); - } + private static void OnGameIntroLoaded() { + ModsCompatibilityChecker mcc = new ModsCompatibilityChecker(); + mcc.PerformModCheck(); + } - public void OnSettingsUI(UIHelperBase helper) - { - OptionUI.MakeSettings(helper); - } + public void OnSettingsUI(UIHelperBase helper) { + OptionUI.MakeSettings(helper); + } - public static bool GetRealCityV10() - { - return realCityV10; - } + public static bool GetRealCityV10() { + return realCityV10; + } - public static int GetReduceCargoDiv() - { - return MainDataStore.reduceCargoDiv; - } + public static int GetReduceCargoDiv() { + return MainDataStore.reduceCargoDiv; + } - public static float GetOutsideTouristMoney() - { - return MainDataStore.outsideTouristMoney; - } + public static float GetOutsideTouristMoney() { + return MainDataStore.outsideTouristMoney; + } - public static void SetOutsideTouristMoney(float value) - { - MainDataStore.outsideTouristMoney = value; - } + public static void SetOutsideTouristMoney(float value) { + MainDataStore.outsideTouristMoney = value; + } - public static float GetOutsideGovermentMoney() - { - return MainDataStore.outsideGovermentMoney; - } - - public static void SetOutsideGovermentMoney(float value) - { - MainDataStore.outsideGovermentMoney = value; - } - } -} + public static float GetOutsideGovermentMoney() { + return MainDataStore.outsideGovermentMoney; + } + public static void SetOutsideGovermentMoney(float value) { + MainDataStore.outsideGovermentMoney = value; + } + } +} \ No newline at end of file diff --git a/RealCity.csproj b/RealCity.csproj index 3817879..772a52f 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -50,32 +50,32 @@ 7.3 - - packages\Lib.Harmony.2.0.1\lib\net35\0Harmony.dll + + ..\CitiesHarmony-master\libs\0Harmony.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp-firstpass.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp-firstpass.dll - - packages\CitiesHarmony.API.1.0.5\lib\net35\CitiesHarmony.API.dll + + ..\..\..\..\SteamLibrary\steamapps\workshop\content\255710\1192503086\CitiesHarmony.API.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICSharpCode.SharpZipLib.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICSharpCode.SharpZipLib.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Posix.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Posix.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Security.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Security.dll @@ -84,10 +84,10 @@ - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.UI.dll + ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.UI.dll @@ -203,19 +203,13 @@ + + + - rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086" -mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086" -copy "D:\Mod\RealCity\bin\Release\RealCity.dll" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\RealCity.dll" -copy "D:\Mod\RealCity\bin\Release\CitiesHarmony.API.dll" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\CitiesHarmony.API.dll" -rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Resources" -mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Resources" -copy "D:\Mod\RealCity\Resources\*.*" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Resources" -rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Icon" -mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Icon" -copy "D:\Mod\RealCity\Icon\*.png" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Icon" -copy "D:\Mod\RealCity\PreviewImage.png" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\PreviewImage.png" + + U;h^CdGWvv-G&Wm|5ro~(M>a4iUkxt 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

-@`ND5Evuc)X2it=qZ`d(m1zwolfAH03qdb?%WmM=26pFS*z_I(#EEYM;%l7|6+hBGaqb0Koa0R1*XPb0Ohqm=BaYNgGb?c>t)%^(y=@s-{ zv!!PW1-4U-G((G~q{Pu4XPRWYH*JZ+u2rmlkIt038==(v=k(=`InJ_WTsDiR$&w;u zEOQDDfvygj-x$(m%!XKbaLt+lJG)A!R_!Q2c9barUWBYZUNl5+_lruqJ{r^skSCoI zfCR)_50;XWOu@kZ`+zcnGR;uPnyR}bG2qq-We&EqOYuy(%VTf661`%EOHO%A)w(}J6q}BYt$R^F2CGq#wZedY3w=&3KRKt@98~ZGsBNF z!>z=8ZPZ^61aA{ftBF9Tnirpgefi?*#jhjHI2c?4C38 z@$H;j!j4p6xQra)B(LULBSe^*QBpukJF_dtDd~13`ZcdBh@{SjAm4Jslsb17Z_n{i zG!;vM0f6OA#k7NSgCd{GXd$?vuh?_^K7uGSbmDzO_^B&w*Fw#cs;m3-%c|YS=6c!h&4~C0wY$rA+F-7mMUF3%F5QO)|ez z2~8KG^nBMfeQLEN#h<(kOt!5(POA3O0nnZGaW!WyPWTldgD5P2@7ro zMx?LhC(98e(eLk7sy+H~0)5rM7F5&bBCl5Iagnpb&X`R{~U?A}*aJ=Yr`fN7F& zT(qJj1H0kQ)$7|&og*maO&IT9TY{d(R-~RC%h)6ZMa4l>la{)^afFu@P zldP_H+Qv?`DiQz$dWB9zxqSQ5Zi$aYx8R(^usdx(^>-4uw*(tA7+$kx-c7llt_{8_ z^XG2Z^d0>b)Na8uNuzqVeSjonYz46$_lL_w5svI#%F9i4d< zXR-kpP?YIaMJhpiJ)Oik0%f6Y`X;&b>gyJQj%e1V*rXdOrAAhzG{ii=yK=+F7>ySV``Q(eP{4B_W z{CyiZpi+7^(E+VPv2PRD7|@)4{C1;2RDnOPvqJ*qWQOwXh;9V-;H;<`Faj10Z1e;f z*?v@`Q{PTxGqCG$0z3iJwa@gkLn0X-sg4bv=F!zy4q#42Yc0l#*BPs?lP7#xkmh;} zA$)9LyCTykCJYEuF9Y7%4-C6@NEEo6JGAjhF{;2&U7YF$>_-f{VwjY8lq+D6s7I{B zoPgG0I-+J6yxOEs>GPaHo4}CaPMB8jM&P#s29?gXpYpSM_9G17mR%~=j@Z83+3M5J z4_RKT{1ag^u9)5{8eeXyF(6>JXE!Kqrb49GY6zk$EA(Y$}2z` zMlr$2S@5)U?8fN0P|W6v3A@~_C`aDK$Vx>ednm#c)A|ctUh6ReX(eR5YH>Vn`*UIc zEx_FWWxP&oqW)EtLn4Fe|9B1d$I*8h1R~x1IphGxr)u}VFMia8;E)j~|Ku%7xo1{} z!)o@Iv_HE0o%mkv5+Hr`=ii`&fAJ7pEi&*--@p2IX<|Gv-nFu^GIRf?QOO*^<+1k7 z>qNE`{ZxWDq~$cd&kB%^hsmB{>FUR>1%!rlWW6!XRL{r_lvOv-6o2A9{#hi*1^kDi zPQ}X^V!a*ujNtp_#0iYpD@@hAA%WJNT#~scaFHg!MJA7>pisu*muG-@De&6xZG|ArZpNu{IJRd~BjXqx26ZWny zZi5`@c*{)rnk6e)>4De!dhC^`l3 zN-c={04$mtsrhK#HTZ)aBxePAn@iN^M*RT-Fadth)s6%0?~Sec;ZEw2HdVWi0OC#- zq$>}QG70a#B;IKgi#Gm#@~)MQ&nH6sxikg@omy zn}L17^Y!n}eXS-9byWiS_>1)7anG`@kKo|E$yvZq-;6jeg&SKsOx}r3$#!eHG*_h=nfiJK_??N#1C(d{U=OI`vJ_<%HhwV{ zQ0zZ2y!L*fMyns1m6=WPi`u(R?M!3D)rQMlrwQrrJXpjWAG%I+U_`?9Hd1$ZKcYa8 z>D$=WD3`)mg_+KFCxyKTU<3LV`qT7Fn6!9n^vg&@6a4*4Fn6+V$c;<#dr7_#cy8`k zeVPZj`Ou1Z&-yy~Ns2Q(r(8hqBQC~})vYoDVQkR7#_t?Jib-=#dX87UR0ptXyp5{)n#2mq9{KqnI29aB)mC|;S%C6#aKTdLdF zOvEwQ30LszZOu*v3P67a8(7yVPR7V`kagDDfd6)Fbu+*Y+gCGji8AAm23ep7s>jyN zv;eJ0)-v$EB33Sth67BD)_Qn@sH_^dDo=N5J1}Dj!05I(nR+Q|r_XV`80L~bA_&?* zOqi15!-m(dKo} z!Uk!ppLY}}Z^BVXPjL^nJ3PDN+@-q6q3IuFG^x>7){Pd4v%{!MOH=jIR((p)^+#M^ zB-4Eu|D(O{j*2?Xwk<;|22el&kYcB&otd>}`rSY7y7#?VQ~&f@ZBf7QrE~V#d!JR&*r6mN zR-{ant89I-e}24+?pSVDZu=T|98jd{b59RZ4iy}%Txef(6m!4_60Q+TA_@;C$o@9j zu^;125!>q(;vst9Ura(mmm$rbZ+N#Te&*Pun|YjaJA>xDI(SPAl<9#%Nl4b zu)Y!otZD2<{!0>1s*4tB)P!ip~84-ga}cj}$YQ@?^5|j?;8?@V}D&OVUP!)&9+b z>8kbe!`p0p^=)lBGCF%0HnDlNo3UejYe&^E-k-JJ{BUl%`2AgD!oC0^&kwYqXkTRV zaBZkAxK=}o7`_hPPnkRJ!5w{~uR0_%_AD&mf;{EfYA*lZpkT0s;-b09Y)DaZ)%6)b zv2+6!ZiWP?HeV#*{_0Py^Z8;(8c@eL0aXKx=|*IUaM*|V8Q^{qB>kJ{%1h+{6Dd(( zA7d~QET`Q; z_b;3%i!mU5+mh7yw7rv)XQChJCkM!#)pW1h0dv9xiGffZW1W7@7Y1W0hsOQlCiE^W_PY2%T(MZRMYtL?c=~{EV}f?^ z!fk?r^5Ry_;Ilf4GeD7#G7A{&vB^DxT^-_%qB>7YRZ=v_4@5kY;cYj*BDC*ZZrJF80YIc_Uel%tXf z+zNK`nhMfTUy?>{UqSwc56|9x#sFiRq zQA9K1om2%m_*LKT1~&lZLwCG^x1bVS73%z~;qg*Wefm(t)5;(HO$#f5J~KDV@d=gxgo&0`<958f%jS>$b3$BvMyL8xFu~Sbq9c zK83^A|2R4q_CBbF)qP?pNX%T#9cE!`ZGD7Lt0ufRRh@G+osVwZgEmBnrXF z@b~s-Xs@~`LWy>f+a$UZuLzS0HZXLn|1q@t-!}PEggMq;a0OI1c@RwvqJkd-=LsG8 z9WV{`ek>!UM~`G+aEHx$$nT}Ii~~N8??M9U6`l?g8zn2>4zl)EPllvUV%C$0J|WS}csJ}qw@{t9?vzhI5(8B; zVnd(MsyBc8r<#_ubJ|o$HqNeTl4X;hs^vY!SMshY zlRw?x<&s0a3w2ULJHZp;93(?0d=SBj`V(fUa8_S`y3ldOK7L09-#hGb@CQO>LLH=>LpNlPJGpTIRujR>w*0s6-7X+=m@ z1>{+wUp_wfn6xnw@(XEn1Ot)UO}peCt%tfR55)k=aensQY-mZXqVQo5!6L?l2S^DL zvb@TOFS4(77vpE5;hLwU&>?Teb7p*ZvSTXJr$xL9F?C03@wquCq}pyPM@DVn9Aut= z1o0WCio>Qor|;HM*9WMj$ja=g>icn!>>Nc^(m}v_;$x@?q)rb#brLQNP;D%U8_b=0 zTg6d?MRJ`1Mw0OSL8Z`P*n6B5fe;|NB}MRwA2(K-p4x7*rc2T#&d>pz8&WSxJLRq9P3fbFj&OzlYl>X z?YX_D&@b(b1}3-P@j|k7lUO1V@h0R+=X0gA<1~@G;k1j8W-uz1Xma_Dall+Jft3CzmMVlDxjDTVexPTtbgk|%Vfsn47gzA&{t zubElaEs<>q)~|bE0+SngtBBvtf2ny0^dU}Htk}_oQc%6sKo ztFK{RRGUlj3-;>99PRybv{fK zZ`=mUD~R@;;S+fSFoD|aZ@}t2`C#aN_&JABEh24h+T=j|6%8>qEW?HaWLQoYjWVvEJp7+sMzw^ zald}JR~sZ3V?kMq9_aRjFTct(D06ez9)Z$fkFj$mYOV9yK4S;eLJ2R-ikmgSY6epg zQPxPIz~0nKdkcrrTVOAuuCHh(l_Ntftz}e-NlOR(+LWSSxvaarZtG{D5emWB>gND{ zzsB7Vd~{s_jL2Gw%+U?j%X-Yl4yb#=T1D2I?`@= zj5fv(8?Y(-+@CSNJfxKnoZcJYu|=YV<%n1{ru@=Cn`Tz2F<>=adHZYXgC4CruscR9Fz(Dbax-Sg`%XNXFHFEpPr zr9<;ffeaS~{_y#a_wC;$qyO3um}btpllg|VHI74YJDM7#WAvEnK}QJKZ$Wte{Z;aR z{!oK*))2G-vqCjiqk6xToiLJRitmIadlZNS!Z4g+M>kGYuJu+Pu`46j4Ynq(J2?=Y zJNNoAaH@qKG58}%8ZrWQNb}fOH$rAwwcq=!Yu!Ezng(>8Sh?a_OP!^zDu`Wm9a)BG zG6-e}E%ALe-qw{peh@BX2M&aP8{OYfD6iw{iu71}WL+j`F*}>*59Gl6EDOD!F-l>* zRFw}#pfr)|&e!DIL3I##LMjPKeU*>@A1g@uOO>?-PLn`iKWN1qS~a91%mN3Y;w9h* z7gI@Of~SM5HCmj}Dc7j9zzuk_4aW%L#ygA-qkQlg`lZd%;Hl>TMNujG(%7tyVH)!r zg~YE=*kL^dhuK;Bi(Ist@Fg9GCx~lH3rj4456IkbA%8>k=HiMe{?GA<15yh$jLwD2 zY|gGU0gV?v0szZy`_myMGX+3TdhG94%EAqdA#5shfdu<&Rnc7>r@qoYi270SnHw z#o6(QP83Sr&LdJ>Qd(U}nd?NCCM})j`f)|kv66BYz44h4%qrN6SV7Ki+J=7q)Rp#< zvV%+g;H~sMBh>s8_`pZmd^U0=>dMW1RJ1Y>fOy|j2hF=vst8r^3yGXT8FAYv%)}s$ zpI5mOHObAY(|ngOK|*NXg3mwm(vJ1d2kRtAG6A^0gx(AWGo(hNKmO&0 z^do}i0Q#Hse4BOyHQ-G$rs`P?;s+XTg*kQy4LyAR%In+m)f4~pyrUStnDJi$iIV#1 zs|+Uz`urQYf_rcKGviF+Lc_@X4;d$$E6r(J)B#yeC#T%vuX4-gYQl&L%WH4M?2P&e zG{CYJ=PgT?pCL~eZ29-{-2VU9=H1NF+FH=rzI#C2#U0{_1UO*i6`9ew=CoDO~(D z2yAO1xzZChE;D$mIyni-{qoMClibs5(pzxIp$uta_`y0T^3AO@{05AvH2T|f|J;o% z?U9ID#TicJcaz9gqP#Oo_>$H{PkuIdNmI8GYT#E|jxkN}`(XHalO!F~M$Np(J_8bz0FD?&b<&ZI}0|d^jh@8nD zReQ_53N>J8?>uzVOhK8B_}t!Wr8lb*O5{4Y(kl+? za^xE3F?X7M2@70x7rJU=%HxWUU5^I-KqQLci=G;9Bp1$!(4SQqn_9&hgEKa15v7Pn zP%RH)$*NVb)WkTtfZ1b|;&bIqSQJitc56$HD@B8c2*QNrN=IS?*l!{4a}p13Hjs33 zki1Goez)l$0J>sPH+=L>lR*ZXF>n%};;-a!lFN*dGUGW!M%@7Rm}^il$E5XSdRBb+NR zYs^xQ3mCuM4IJA=`_Zm46IcfuRN-w`M& zgy3nvy0wd*lek{SmBYAg)(h-D9&wTtyRvz7Dq#)-HF7~4O8;r5KY^$1c0V{WbdnGMC`e;H}XFl0EggR>z zmthso9Xc%0dzg~%kMAxRo)5u?$r)u#l5}rc^jDJmZ3+_FCoLCCMyxKEE8tdyM!Jid zhTPqao|Y$$X<$!6oOKkW78pmSv`AWpyQ=Rsub*Wy4`qaOrf1C$2Y~Wx5OQ(^)wt3O zpnw~#7Pk(fZy|20DWrC9xVugnUD0Z<36|=QUePhr6vLZlCuae-BWLV@+ z7f$Q;AI=*%qu#np^M&k!L-=L8g1+6nsi>wlcc(^vOebF@9E)mWy^}>*1J*u4hyn);LdKj5z?N*YcliGb`0CQru zJb1}?&s=AA_wBA8HJ#zd+5MIU&&wZH%>u5YLZDw3K zRLNCbA7MV2A3%{PeXO~+6TkbaQ-;-$=M$4qWb~hvIP5uqZ(O2#>_uG}DDNjK`z-j0x0Puk{Nuuu0Yd0nony0pyl*<&e(T zDy&v3JoC+wU+Hd=q^|{!1i5r~)E>fOoR${z^3gRsA`4$ zE;m$SmVgPDupHlatC~KGn>Q?b(32&FYo;W2d_`z_*3LMQqpDCS4Pe2cGoL;vH7K0R z4Wp||)zM!yyiC_v6euV(xOSyHD{P<@C0H5P9`SJ4_EDRa??2GwRo$GYd0hO>6jpcb zqHWn9F$Tt!YOWSE`eQWvPaCI?Qc*4;OnHv&HrvQ9$&OMqvHd#2S}Vh>BMwxq5U1;t znQJw=TvDuqIl4x-$jVY$qAJ3di|@S?jyh2Z0zj>U=|r8=+FP5u%tdf3Wv$~7_B$W^ zW}c#49^Km7YSv6+`=tr!;|;qVvvSQ36rGo1Anw&SeB56de9f@0=BgWy6Eq~yz->IF z<_nfes#$$MEtLj+I%T8erVxZCo!bxmNvkDQg=I~WR6xmFMV-Rt(30xA$azYoKUeca zg~LE0sib*q1juaP{6HP>iFi{c*r@NK)d;NBgyQbq(^1hTo0lL4`Atf2OYGR5 ze3a+rbIC7J)d!;T*Wa#)u{Q?#ZXV@Pi^Y!04#?o`rs#sR=S59mw*_>L92jHuv^<0{ zQuXb=dlovcKL*n=nI#Z!s&1aqR6h668yv5K9?7e5sJ2^-^yEu)&w z>I`0BPB1AsGAuc@V%G-&6QO;Rkx}k>f}wLycX$vLDRG#M1L*=%10oGCIP2<2F^~G0 zpSBknk6*NTFGBidIwLdeq+QRjRu_5v_acG#c$XflG5xI+zKhwN1?_jUq9&ht(U=1@ zk9S=^^#P4pLIpU0WuTJx(w6krU?aq}pCR^LPKbnubp-wjG?b9J^{HwOdSHRDyKFsNiPzlk~tvTZLhY z3OZ`i$76=aE|(Wj$aS4gA6Mc=CL9qfK#e&XgNkw5&ivHnTq^s(8>f=IaU5^)J`v50 zQk}DFz)(wn((Gs(Wd8{8xL{kk8WD>#I(LuPj}M#=pJ2F;OG%Ar@)!{VgN!GHH5T63 z)H%mj+Ii3c;8i?1ArNCY{h&Q9@hlN6Yb+k`oV z`a*5t!|88loC#LEXlPq@+%HbEa|VdBalW8`r~|eft%HF=r?R}spmWnaUN!&N{XL(_ zfC9AK!gE;^@ch;^zSapk#;k$Bu8zzthjAwFuq(X-k&4PF=!{ZaV{I?4S&^Q*Ooh}p z2+0LSMdR6%auCNxMqCc)f{v!_8yvtU`$_eE{$N>?+uNr3od-0s2BP^k_F}{BLbgOH zn!TgwrEI9rRJ<#h7N#(tbs<90aSy=eMpxc27LuqUW3LLY&i(SN@=>J;_7z zc2Yl%u>;3X&mHWgLL7vcbqd9-RbPJEyxbb+<>02-ypS62-M~*>H&k{$UR*O%STX;6 zPkjMXXstM7*FvgVvZd1TA1*KZJdw-Geg>L6WWh2ujj`TkdjcYkw>9;iU~Rr=fhDGH zc$dkQ6Gk_7@KdNKYg$e=y)ky-W#SRP9(@U>l~2p#xgylqc*{LvHS{4aQb(?xL~R-7 zdR9T{J>8H8_lc+!aG!sOZp^0>+^^U{x4;t}NC2)5_-G^=MmdCY*|UDrQx=#q+~pMR z7W_%#_l6(VE5IUf>WQQ?I~Z=u;-fM~;s7bpTV0>`$~t+dO^rB5u5;N)@ICvSyW!Rq zUsD2GfNgd@zbBL~@L+iGr=R{S4tSwb67a9V3l@J)Ow}}gfN-qIkf|i^PGnaU<3lfU zph?`eQtDXZ`dE?4FG}9V+z55$L`_j;Q ztE|I88yu+X`o%GArwm&RJC+YmH_;$+b9<Y3P?-+ou(!oXB{o7-xwTxvF6QMk0-Mq_bi9kf_Q9z2_%#RdIZ#G*y%#UfTlCy=a; z6g@g}rjBlifkXOH`q-Y7I(P`ij(MJu*!$IewbZ=x&y|++jXKLh;z22Lg&^1Da^Qv@ z@$h8&wDW$m6(|@+q+5At3_4pE+MjVQzq5Dc`0wLjKl1UX{fLC`7k8rUNri%wk%@{^ zt9>rHmpZH~m05?bRm4Yf&&XT$`9`Zc4~%+>M^(wz4CUG5dO5}iisVN4rmsK`F&n{k z4vOg(jF~Ou&hthcU!yWz4w4j*aU!bb-4;IO_#N5@|8Wd`%F$uNQSzV2eh})Ab?QDU z?`3_i8D^h>qm@kvI08v5tKo52cj%fGfJ#>=vB;H%{Ix~&lp&m*FMwaDRtBH{31S9Z=C5G5|Mffh&OF1^bs*~5W=!?a z_}+iS@_&N*|D;eNDg<8Y9uDMMR#p`65#V8~Ze;;!Fgil4Q94!H?VD*H#Il2c?hYHk zKeBP5!$9aew_`~fjV}MiG#W<#9U%4Ima+~ND3W>vAEqiNvt@H#*z)2AOr{v^?>2%i zImGD4Kf}-cH5&U*?ic;dKLcX_uW0H2`Y`?LnhXN(ytlnTDMKbd7D{;GipcLD!MM@C z3hCp8!P~oHWl9K&6G>b&=y(IBMDjZcD3n=LK1FAdwc^`@83lp}1~bnCzhuLH*w|a{9!)*xa zf3@fIA}szy-_+})$XXxF>3IQ9uBcX&s z+L_=!5_9`~^OJr}Kl?&nrBpQ^A$(EFYVL1M!S0y*nnxnatyWe4Sy=Y@hK#jGaqJv&w9V)ti&16q<7E*ht zk{YE;qCR*XD5yR~^NmSOcI60cUtY|fpOxy!<8C8Dk+et)R^7*lI%^HwQ_ncdoccpc zT^nW(o|($*c_!Fd$^Bzeh;z*3?UTZ#D7h8tvTT6X3y2T;Rjt&Q59MLdW zFcWNsj_p6N6v8Rn@(n2Zls5Z4x-oNFHyGi8*wHJ9aA|+46hYTcVoC|O)D7RQ%e(P? zt~udmc)uNQ$Q3CZ>;v0 z#_Rgo0s&@i4lqMGQN76Nxsg>9-J8@oOEUpYUZtyUDH|Hc&lLIC7R z|3|_&$t>%gO)vO)aZ`3|^pm(lxDy^r-?pUzH`3G)wkpimvoC+m(Y+rDe%hRq>X?kB3;`^vY0U#w1w;J8x8d$a0lkbQzf| z4<`F@2~uSfasku+9zWBz%#Y1X1Dew!qRW>hm?kK9qnGYkSU7C^@H!7U7Nuqgv35?mz zXjLo3q%$=Z@0i~qiuZ70=fod5WmHsvIYmXU5I(eb`99Eady~Lc(hZ>7)|NPrYu%@H z6(V$m&31hyKgA3+y6?m+U-(4-eh2r+J%>>_$vb6yRYi_mo4nVdh>3pZ-*PX8$NGP? z>8|&+pT&|9w|K7UcBJkbDMTg6_vC9b?lE&yup`%k)Gz>4`;8NXe4Eb5(2c0%tRxDC=@(c!4IMQcz}{&u zLij0kb0Z*Z6+~5+YoLWkrfPvvCfMSxVn+)S##g|Obkw-4sA%FvLja){R z6Qjti71P}AvTx0 zfaQpOK9`(s=+g<%rvCOfsVCBJp(Znk$;CdUs}q)DY)A7}*}`@V90x845?N55nI?}3 zO3e(F^&@KHWYx4?pIpdv(yN-~d!`hG030UKil+r;9*`QQf z*@ioKR3&T5t~URh|KWt+no1`Ndh7FuvcSQBJ)!Cu+66I?*_Jw1hZmRNjZtfxEaSsFXizcD_Pz%^15I56nZ@VY%*35dd zLSc-7iX6-A`;@CM4W^(=ig`k*(^$)#_L5!H{%i7ZqT8NGB(1;eWg90_XIDZxAras>Wrz=>xI2g)cvU)8=Qav8D<&Xi zsHl5%2aA0DOtat*y-#-?l~T_58c;LuN?-%HjKrUzc1Ns8VRB_lVYxKw@Th?E@E4gS z*RG>tPQzN?sC-o9zJ|~z4>VnG3Kwd7;`0V(JpjIrBn1bnv|cklFv5J`_U4v$%;$3^ z%UUvRrF8e+AUl>zf7Dh@hzJQ9?Ir1^uJMO z)4KHZ0h=pQ!FEdgZtrbe1}*Wj601i~XD95MrR3i+h9(fcPD8)%I4b>_@}b0|!tQY6 zti#Fr&UYROA=2adf|kILMH)gRbpZgg4v`a;|KZM@1a9U zMyN+tVhrE%^MYfMVWXYuSha5ISX$ae; zO6=Nuk1La5cE+;?R5!UMse&{IY#vu$nOttPy{tPl{Ed)keA#VN0Ek#jr(lUe)7i+y zO{vv3$9rbRkwYm+M!&ebp4eJg8fjjx-m4y$F`Lid81q3VH!QEL&PE*!Bo1C^RZrkE z@tcvz)|{A?%k8#fojq829*(}E7aM1zt#z-0v-A{p4TD;;s328)b`p&Wn@N5Nij0{=yA~z>ks_It88HeYU@;sy=}HZ}IK& z<8x2_INVe_$0V9wJLZ_lx?`Vr2S$O-qguWL*)wAbBja&SMh0& zgxJt3Srf&}@r0ohF`b32GKF`7ty~VixU)Xx^Z}PpDr?lsmaxjc0kf8>#_a8`_uNd( zRZ~}Gbxs;LBt3JZ5cQT0M7(E@I?I)J7qCxo)Q5@J2cVh3aM#GS*b3^}bQE=-07KRz zY008M4Y7Kou-2-OhSk-%!PNfH=Wv2s%8l}|OTsp~lrS>(&X>okJryHl?Zw?ICED}C zlQkE5K|RwiUItw4L7+veS5G4IBeCAN#l0A1+>}6L;11TKH{H2HtzW!>MxL?>jzjD( z%W}AQ@wt;gyv?7K5Nagm87CW+1AGUt{T8+Znxi8?`f1nR6k5%aY*hq%Av905EE4vL znMQKiWDe^|)D40}g;VCYHC*Oa2_^oIN2PO104{DwUVpgOEMS={j|GD<=!s@uK{4O{ zp;}kpC}Npd1iPG;0?A*OTlmyt_K+YKhBJK^ZJoKiP$SvOUKg1e=SdK*Xsqd>27tFS z^HC?}dFXbfkS>p@It0kX`Odd|#R zuGz6n_1!>W2944zXzVhu48N3+!9$>cgA{7KNI)$G;O^Y-9=tw1tiPF(e)^$`^s4ujHA?L(wG|eV^5u|veZ}8|ICq#gP^%xSZ)ch|HsSUU5!(t9$npiJ8Q1{ZSP$uv1ecl zalLX;g1X-CX5o##;K2D6b*}{5dmJ>%NPYUmrIG=+{(^tww0Zke2^Y-|mnw%H6~4cQ zpd=tF+(_>qLptd5YnoCMyWQ~TcNqqjTuujN`Ne z!=fXmJx6}l1vi~)OtRU^r*EfoOieNL_Pil6z(s=ADfcZI%#DccBC)u3&-SaJM?xuF z)kB=5x&eJ;c8OKlt)ufNU72{B1_QmmrWubyURS`uULoS~87v`?j{#N+iOz3BPYPOZ zGM{TAQi^arhs<0~whGHw9GqyDzSel@S@!Grb)Oa z^frTQ0zDg|5VCSH`S1rygQHa16Qo_gZ7FI8WcjuMM22={N_EN13Hz=y8kOa3qWO1uyY_fW}{wb7fZ( z9S>%%lk_W}`nn>+GGy3QbVYO2_3Oe33c%N_Kq1%j0_vhLIt)KT%x3_Z)e(Adbt7h( zL{!SzgG++#JUinj81%4VultYpcLpWqxNaA_W~BO@v9Ty-H~swww6>zoykJtswFGxb zmyN2-zQEt zJWgne;7s{#5!d-nI4U=d3HsB=3nz5cLB z6ZsdpGxzEe&k|VY==Khdb{?~3aN2rc;}Brd8K3FI1{*wHYFRPnV26cF1lGX>L?+_V zeqOIdSFflu5nYLatRi;o8wrxnf!T@7M(gC~f~)xK6~RSZMfqi?aDSL)y=c@_2-9cw zi<|E3z2_`HS~GtHo}k>O%%xW5Fy0772o`Uqyp}V(p6ZrvD0U#yg^X%NyoD61rKDzl z300oKPNFfE!Ybh)A8d1WNJa|Z>o8di(EZ3BuyO>zC)yPtG>uY(v_8nv+$gN{5U_TU zjL$0V@O;X0XL{&%^TY)$p9c%lwmpJMA34*iwjMb{;kZMHq5!{RylCEkGSGA$@kDZ} z15XF6Q9#O=hP%dN`OrDoIb=T64w|@F#iq1*`s}V2w(Szhqi^58x4l!iWHlk^5B@V5 z5cjhn|Kg`yN&1vH=FzaC#@hL#cq0mXbd!w3WWek#!^*)jj(P7U74hhO4cqhLidcqc z-RDXfH+Zb)>q2)*S@Xun@g*t_>+d@!p)0%darBJ-wgXTjI)WDiB@HARY>bQrDpnKx zYaZZwk^jBhF-5VE3&(irepPbG z{AG(Hr&6UyYbb{jEgXN1uPu`1t}T|tn>ZHBuyD4R+1T2;R|e>0PacikhF|o^*E#z z#`+VG6~hmsWB3AU)`?Lsv*Z_+vMvDgiFDrbgI}?L(gxNBva+Hq=1zz&2cWN}uK=ox zW@Z0!wXGa@HML0esna5hcrPSE5ormsn>{EGp>T)20Yex!4R6Tfw_w&laW(Q_*KE*z z{#wp?M+G3E)`B^k_Sq@nH`6NL6O_Pi-6i`v--mntkKvZrUdk8qAfuO>`=b zfJvePA0O`cFZr(UFzD0vJD^gYhj43jSK>jjEW@`#Gz8UI~B3^!NV*>hqtV literal 32885 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 Date: Sun, 30 Aug 2020 16:33:58 +0800 Subject: [PATCH 10/38] Delete PoliticsStaticModel.png --- img/PoliticsStaticModel.png | Bin 35652 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 img/PoliticsStaticModel.png diff --git a/img/PoliticsStaticModel.png b/img/PoliticsStaticModel.png deleted file mode 100644 index ffb4b9f26e518f1359b6a37b2ce957f1b2131100..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35652 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

-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 From 0788baf172334f309b7295b0ba235d3ade611a4c Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sun, 30 Aug 2020 16:34:32 +0800 Subject: [PATCH 11/38] Add files via upload --- img/PoliticsStaticModel.png | Bin 0 -> 35652 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/PoliticsStaticModel.png diff --git a/img/PoliticsStaticModel.png b/img/PoliticsStaticModel.png new file mode 100644 index 0000000000000000000000000000000000000000..ffb4b9f26e518f1359b6a37b2ce957f1b2131100 GIT binary patch literal 35652 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

-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 literal 0 HcmV?d00001 From edd9c5efc465fe3221a019125816c6320c079562 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sun, 30 Aug 2020 16:52:04 +0800 Subject: [PATCH 12/38] Add files via upload --- img/PoliticsStaticModel.png | Bin 35652 -> 35601 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/img/PoliticsStaticModel.png b/img/PoliticsStaticModel.png index ffb4b9f26e518f1359b6a37b2ce957f1b2131100..1a8731fda70393d20d3d07fc1f9e672d75c7264a 100644 GIT binary patch literal 35601 zcmeFZcTiL7+cp}@RxF^{K|Gw+(NDK-I8g zyHEZAem?U2Z)-mgh_8eDe_!f#K4B0juK14bZS!FJ6%wREWIk7NSCxwG_V~z~Uw!11 z?x#mm{5JpS#vZz_uOxADtRm__NA!iGkq0)gy`ZjgtUFTV(mySsH>11k$MzjJs`cpX zI7F5>kP!>|s0j3w!+_@BS!GE_1c{FLm3BIMrxYoBFyaU zIH+>Oj*YPvet6x4J4z5Jp@~zna)A4;&FXaU?>7&Q?f2&X0_1l42QT;amNXA~ANNh^ zA1}e&S5V!bzqk_t%0G8-iu(#0e$@utAPDs0(aHb+Oa9-QlQ(5ch22j;f;MJmX7eXO z$6-iI5U9N<>OX6i54@@S=U#Ag#Xh;?RXQM0;q4>;pIGROEKP)nnEUU$ZVN8&at)c9 zUw*+p+$Pt^w-1zX=<HbScQmA z;TZV(!-~Im{zB=+pG$=S8~!*P*!VB1JjOnKXk4u)#--bbmRWs%dZ*fL1VQHq4#c3G zqFu66M_n9Wf*QHHshYDGbM+^CF4_1TvB6u`tA#o0EA=xGJattD{p+g&I*2+oL+_C_ zZf}#X(rLTeO}_HjcT385eKN>ja@aw3>&21(e9hxeV&T8O%;bfw{goyQu}5#s#Lrv( z=_k5h|6QB#6&PLup|B4mh}e=4y4+(xl8xN%8Rjg2F_|n-+typq{gR=P=2>OnILn>l z6W7cU(oG00IQ(RQ0Z(k0hBk{hq)6MLYJ>N-$wOf-Cl6^vfJ0a3b0spjnji zvTLv!yk>LokC%tzF5gQ#(;T>Z4f^Y~c#2tXUp{&I1co(&?7pBs{^j*yGo9iKURfPs z*SrdJb@JG9i`xf4ZI}3g@WQx)@EB_e3qpK-GXD7)HrZIyy5dnCVywX%LR-l8K1Z+* z^Yo#Vm86+%dQ~xCFVrc+Nv8FE9gc(Z2ua^1+S%(5d)3d`^-3a2U9M>Ns@p|nUl^@n z?Jhp5)OjlxxjIqjs>WE4KPP>6_K`HWTt=%0e3-tKVf>9_Ah0axkXt^R{pPcL)i^Yk zxvKar(bX}+VTT@$B8{FznymCtHuMCR&++;Mnq{#nYWlBnmw2Y_iM;5_T`zCOih;CF+C5ukI(7LLE4JZ0uq2@P7~=c#a9kNXfLUe^*#5O1Hl| zt6kB~-kgT)1>H99^>afV;cBtlopfM*I~vsuSK=S;TtE`JyH2aVWJq(l)>~Uj3m-

ST>Q=E{j@wX9zJur4I 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

-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 From d1ea9e4c81086123743f28bc7f19736b8fd79395 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sun, 30 Aug 2020 17:01:10 +0800 Subject: [PATCH 13/38] Add files via upload --- img/PoliticsStaticModel-fixed.png | Bin 0 -> 30975 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png new file mode 100644 index 0000000000000000000000000000000000000000..4b7269e4563daf0984815d778639810183b7d90c GIT binary patch literal 30975 zcmeFZcT|+y@;2CpBO(ZrB!htDOp~KZlAJ+u4kD6sXi$+HB|{5BD>+Dz+<;`7WJ?Z$ z#3qB}CeGWOd(OT0oHJ|wnE7Vbtnc@StCw`Yd)KaAyQ+3QPrc#ls`7X5P}~85Kz9|M z%4mW>zxjhe*Nbmo2mbOcV!j0UxaOuQ{{&PzK(z||=cesrmB%1Zc`VME`ES7gv7Mjl zyMaJ>ZJ2-8x}5T@Kp^i#1)0a%-X@zrILoLM>K~X%x7B?&upgiPZa>F|KlLioAmj$V zgCo!9G;RleJ|owUIGkv#)R^>i3S55v##2wY%ahf!!op&NsDAw5jTlucIU6~-4lipR z_^}f(We~|Tci;o0YmU4Id^~$Aiv@g`k=&;SK7w@qclc8G*L5>2#RM!6kvj>fh-JYg zC^v}-AH=l6253bXuS$g-tA!Qw6%Q5GWNy-ppTzZdf^^7YZoC{qTywr-{96kfZr7{o z=Sv{rx24z3NJ17KO;x#qpilI!eZJG?^5La{2uL-%2+-}E@HfE{Dp1}x9Z+$rGnHM2 zE?$t<|4j3Lp|oR(lcf~Xd7V>~)TMsw-S7fy?ZTBIgoSMGTu_D|hpm=5?X59a5d0M!aaKZcGM3 z6U$GFt>s6>3W!S2o)s16p?9=7Rg)^x>~~ZeoKipPqq@J;o5F&9pE}v+{Nx}{Eo+{U zeeP4K2TlEdk1#o%BaIE3`e4Duv|hRbEa0H%9(NktbY0xGr%e0v%IChhFDH8_LHhGw zyGbRehEbmtgc0YpTI^3T@aM2Tr4H1J`QYffMBjo(#*DsfejFBF-6-K}ksLDRvST{Bf0%R=rqURts6 z%XJtjj~dTU)i}k*#+I2j4>&|U-$M;%^)|Ud{W1&CJ~Wx@#OT`g3?V01%P?4o6s|@f z*kX8v@X^Q3xw-6IL7Q#@=t)nw?**=>p3Z#!_`A#4wf-80@dnt_HrAotuzO>LU^Mz> zC=@;B9#Xq3dIvHgB^j2CSFnQnDAvN2vsId{SWPG|93@S^r9qkC+06(Nc0a z+P3dW!}ila^zNq(v95}}MSt&F`naLtRLd@^1Lr0w=5c~LF^yQI#BnT_y0Ck@<58vu z%k{kEG0{Gm6yP^>rF`kf)0CIP+DotMR^l#0`+}d!VPEbl9XX(6NPj+5B3 z%)Jtp9@z7<#Uto5c4261INp25ZQ_4^B5)x$nd|7bmiq*H=^R4}AIxxfDopv9h>BYE z-R_AOR-+j)EXnVsho>-H44(BETd(uF^txQs2NPV<2IyK01M(TBIsLPId6DGL1BS$w z$KiP(RWG#9GAZ?L70m6_XgO^41-94XM_(Hx-EzIpGU0`W5!VqdP%S=@?m{$xrNJ~GUV?e;Tj$Z)$m+GPQ@{$ONSg<7Y~uvN_!BI(vTeww>C zELU2n%=z-8(X%vDiL~9-p}dppvXh9>J>zxp(|8}9>&`@q)P6&9X|vz%R>fz3BO`I+ z)%S`x@xGk5e(heer`$j2b~@a4d)4_o{$?My=%U-TJzKm`x1%iL?&!S)G>?at{D=|f z+?)DF*Ap%5IvW1V<44Qik^ZUiwznA@F*?WMiTYb2eT-!N;| zWSDS#^@)ShSs+3~8W`Wvy6Kq*_0Tbw)dxAz;H6U8B=ULF)*a{d~5pL$08 zoW^#8dRfhwyA}cXOH-x+UA;t;W(ak7oxkKq;123R%%lF(mQt7$;=kp%?An29>Dx2Ny%Ret}t%(|9{lMlk zVAXv-%P3Uarg13g*@kRroZD_HzFI(Ew(6uGKIxec9OpjuZUVK|i)-lHa%;x)+bo3Q zC!eJyJ`ZfJw<3mLkP1nDi6iLA@a0(I0JLe0uK4GG^8+RT_!av14Y{Ml7EDIX-^z~~ zrK#S{dI{G*bP-+$R9JuiUdl=nn)VV^@#NwzTxs}bmvU1LyQ5$V{!DYAsUY=mQrOIw zdF^s`{5pS;aLV4Xs()S^O-cF6y}dQ4c4%r*R{=d)VDHu&(P*`DA(%DK@*xc8ex28^ z9O?WQ*XT+Kc^8~+xs5!yq&3OO_}TcrQIWz}lFX#YuNN+RXX{Cm=RZ5xBNp3%F=O}J zrp=H5Z|@Z@iKu~cO9L9@T9p*@9uQS|+qiiliAXMe_uDSV4PM*zq|yAtZp)noN;0n( z7JqcaZMC(U1_BtXX~byCv$C~gf?Z4`fFx5e@Rk;s((}@ov!9( z%^Pr=HgT9At|foMtN!rcaSzXKiqo*JQJ2O1P?6W{uX)bZ5WO$nX5sq}SkzRIC4x2{ z{l&RCp6_K{LVXX`OS4TO=p`VL1p+CnhWTE_N^%Qg*C1(7e?#|v5MdCt-G8TwQzh1s zcq2d*sBxM_T>EUUZ=qzSLM!Rt{X$1W1tIClg!2fy1@ABU;N~c6Bp%}#Cd|V%^a^K52C!v}rs#286Yi(zU_xA$HD9FLs?IhC#%?lx zNZiW&KY4iWV10~$nLcF)aRJ;Sv^0N{(Bl@oJTSc+@oUM31W04Ee`?4h`~24gu)zbJ zBMoV5bw5CD&^g7v#6~MIv`Fx~? zUbye&ZjnKAT$cOs{;C#a?@8EgU>`-v+!hR zPI}_#X%y`Ry)7O+O2Soy`dZ7dycV^4{e^dJD_;Te|X;LhDqqEqd8QR+gB1@GL2BfDBi1qv?-@qy+MLi9MGU-<0+rkgLE9je3-5O~)cPiwFcf6GoAvPo&Ol-8pwZFl7b6PxSEz&<-RsPh zkVjs}wGMl`ok~FxY5Mx9lO&d3S7KccX>4fNQ{Q3XWfV_K2DVPlC+$3fbhX>X>PrQ> z^v-cm#&ZW?Lv6;z_M3QIwZjW#WoJd>$oase$D?R>lZmRPv*|2gQ-%LSIHJ7Bx(%=1 zwG>#77E^hi*!0Rl(LRO3k3^1#V+QWG^`SA4u}OWtYm7Vo11g;>4bQ}kTyFbpGqz+x zD^_?cCm3${Y&aX6+573e`~_@og2aip8HCI#SLBm@yTuN?Br#FXEsz&rg5g^_b4O{bW5X2SiwjDhMi;YljaFQ;~YjTNDxZSv%kE4dVEp z9&%Eotu)iSHo1*}H}G6f{k1%+z81uSahq{iX@0|_w1GAn;dax| z(Cm&MQyNx`s)XOJJ99x8e)XB$sycLziD!H7r8mnJDP8YHY}sDB;%w)~Um)QUQmcNH zFXS}Shno(z$ra=Se~*KW@KAMkCWpnT-TNr)zpN9s>9Xv2W^Q3WK{nFgNu;EqXX3l> zAzq}O^uuyKj&N1sVOfe2dOkCA1GZbm$YZ`{TpS?zQ{9>=5#;xdb7!SUs&YNwj@O=& z@KWYYTu#o&kmpo+;uLBs7-KrAwTd!f%b$Yrch_kg(Ocvht}Fs>9X9)2toJ$OQW(DE zuNY$SNryxSjwv(Hx&_0*R6+!T)=*ejKYcsw1WUc8Iyq?>P_sWsZ@@76H3w2W!XnW0hD zvRSSxinuNCRck~n8j_?(BkW*Tq1c6HaD5-Y{K?i4WvAINPk5kx00EQ9O*J`$&pWB; zP!VEvUcyP)HC=`Kv+zhS=_cB0hV2JJeFtzooxm48mDZY;dbhNuHRN!ZlXFTN8-#7K zrNSdep#^%y1)EIV*1_o)xVhcQgsUGil+c93u+}f>tKx>(%4AKEB%V$4_xNZPgCu%J z&GtvKCIrexkMbwsatuo|!hzUQJ)3(f`WS;(-h2Zr59@7PWCc;E<`B0am^PP%cVO{| zZ&j1fmrr_mY7R;oOeh(K^v0!j^AnEZ4kuegWQS)m&UdzH1n9;r;w10EP#|9db;9}z{d_~t)Slw+pBLQouEXK zhU5V5K+%2M<$@6MZVF}i26k5!QCe8tC!hnDi#_kYu6`YhR;)R3y3(6*a@+cQ(%bBt zsg7q2u2y80NJ7c(3zp6txX@mX!r*G#3O`+JMDyMoG}U=bE*lXTd>bD*Aq$-YL9*!C zpZpP9tMD>yI-j9qR8|IVz+z;73%esI3MtH^Zt6%pU@KHF<2zcMgB6Gxd|4YW^*Wdq zF8(g?#oV2hcObz}KJ;_l3$`0CEJD<%KGr`(_VzgB(Zh22L>9}z1Qi8q%Q`B9D|7_l z{asEizM+{BTqq(q8!1h%(0fPchfeDa7aWZldLf{spwCpcTl`g-uYOz7V-xL1RnI4c zF{b-ASH=VrEMydCVrWMz9V<9yIU!;Mg$u@9ZFbl;alO{m?M?c`C+~4>6ClFROqj6r z$rOWDJDVfu>~LimRGs>0OT41u~lC#nYQj>K8V50O+_0e?9a?!O4#RO(u~0|G&*{WA<>xirl>kNTLh&d zT|cJw9}KU7{oSVyF0ent`xf`B<m;mQdX5|>8S2ZC zPNg`{on(BU^fScTG4YQzzEIeVF3}b8C8`}f$ZKq>34{V=dJm-xfIJM9PJU#85Rk_jtW7gR(}%fd)iOsgJFq_(4bo0vn3sGlR& zzHcIJ^(&%e!2A@iQns$hTzV&Mj4k&^m!RJyd&4V?)5@i$hic! zWT+&YikX_TUE|seEu@PM%SWOd-tNa|T2?6Tzr5yCHZAFrByIYMZ>(Z(y!28n@_7@`*SmtQo8|K?zSM+Wj zD>H?)h>MH2lk-6aS68#%p;%w#nGJf(4%^Gwr~=jwE?Ms@^+6(*?r|=%Npn?)981YP zpSTUE=)eSS?$T=l3Hco=MvotA|@U-#)Xlfie%0(=(=}I{TjFE&A+U z#?ngJ#QBK4?z;r9k0$}A+VnilSYFnR;!D#MLN=i61_Fpn?P%~b>pqyuV?ow0brZw|2G&rb9NRCud-&UsrOJTb*lXiC`XZE4@6Oy)=2}&6rGQV|70XlZiW=#YRXn zip3DWSGuXyq?SCTw81>_Tl)-QW?bmt$3jW-v5cQqv|jEdR(gCe#XqhT9@U;(?(A6< zcQw>P)J}torP}O0t4uz%)uA+X#z^b&A1^7k@8qy9;QzOZ4idp?B9p4r(asUwo&Loi zVlrXpYb9b-aCN|P#)_C{k0RHTcfQU)@!-#@)ELl7ntMI`dS9()uU(2ZFYtDB_DQ3Q z4Ff+chM3#Qq}EHHaQAX<`qTi7a;-mgQ04X~o^Ka#Tx{Una(u;*V0>NN`f1cHrDJ|x z_r6yzqLM8`W+|CNsn|jZA+Gb!B)V$$3J}>2M+Dm&ru61*`y2X;3M{W0zFeiQT$zqb zR36La^#$lT)&sV)v|P&qgiwBi6RmY&?)@{oyvEfWX=8E`A-^`HXQ3)m>Da=h)j`uw z-<_XP;D%abzdsqr{_a&_uKDX{l&5hsro(r66VCi?)eb@xlg^hhP-;>zQe<3JBhv|czIIq3YGnh z=Zd~gi@6IgsgP1XQT^C}lfW!GsXC%(ZqEg8IW5mR6G?xU{z@zDn~q+jU&$ilTl))= zJ~_0(YE}wr6%uIWbeB<{@~fBEk(Fl>h(BBK1uWLFTnGrdKNXzr2aF!^#jr6?s<=(| zwxk_#7UE>(k$IfpklqM#?GvDaJIb*Gm(|4;{*TO9dtiAL6(Zm~YQ;FAv`7-(Q%RxB zzT7Gk#<7$B&%MZSq?Ra*sR|j{02Z;k11mu2KA?TsU1z-=eqP$f>I7ejD_G-F#_RCr zuVCaW3C34_p0|658WU!aZXN#aFt{Qco4aV|lTS~6kbnn2mGFI+_CzO^bBacpoRQfK66X4dM)A0Z^$j}ieFsu|$y*@w9Q{)ox6qAL$4co> z+oE~D8XZw!Nt0B0o+(<63mhE_IHD~!m#w*-ZgRT*=U4{9lUmhhT{cuyC)0r9cz2(3 z9iB%AENTr4OU^V*onhGHTX#|Iw6=XizrF{?;83PzrH6RgQIZxu-)fRW*SE|1#h!MS3qZ5^YhoiaUP~m|g>v+7c`(m}-rP?WxcwNY+%-4|5tc6H( zM$+vCC$c$67S4viPajnpePp7XBI3Uw^hP21~sw1mhAeid-GK; zPXj(YcsHEU(uG4x;OZ21DJ{ecKc>U$*|_U-(KuAmknl=gR?~K}tK%)3yJhEP+70X3 zXBT4}h`zzg!IIykeKHBj41K$GLQY~vdtdm!d`8J9tq9uEtxojUfe_4dvu+KvlPi=drifK+%C9-~2tUJu#&Jk4NV_%(dS=YPkVuHao z9w%m!1K+66J1<@8D#{o_8U(K8MHP9mfb(u{jb1^n@Z@4hufe_A93T-mHLl7YH_X}6 zSq6v}{HS8x(i(#RUs?^kZ&23{JXNT<9sMY+`+SE5e-!7-a=5q*b`~bAH8@_;-j%XP zR_@Uv`;=L(1ua9T5S)IC*)k)TNBMIlS9wmTZf5`aAU$pBQ5{qDPrHtdyYzmsQj0>8 z8(PbcfN5>@*}b;P3=+N5weW~TIvd6OzqC^}CyJE(@ho>rR+8`1y5U3!5&QD67CvwK z^k#~f6<#9fky|oQof{NWmLMmcQhIo$7NxbeA1Q%Y`fYrXzsHZs?r%5}lIMxA`Yt)E zR~)bO!RvU8odb)TDZukw4okjjozalt`MfL$0`4^1#F;T(!-3D(A`#gWv;A32_77Zv zYj5jEgDC)qG99ZEO~qSR+>A*x@ES+8;Q>W4&^IWKVI7hSRi&wc)^R!CYBmUu5*>R0vIe;!t5kPy_C;w!#Kvuo2opbVbgyORaE8Lre^5g z5LKaIh#*>;n;Ge<2S_*z0i#+#th&1SVDS0W-$>lte`Ie=CH$BX{!F9?EQMPBJUNtb zGB(Mrg^ESs3P`<7R_J53DFNP*T1*|3ETF?huqoTj|h5= z>z{A@g%0v)O84c`8tDyq!0G6=wWf6e%eC=W|4k48#xW3aRQo&OB?w@d)k^%G?{fp- zr7ax(olb!VP|RZffr0S9dIIawYgHxuK7S`zl=q1SRRiq0e`53e|7CGK|Esn4|K$X> zzkoEr&L4mfQ*b+_2%@6N8*`)?@{$&E|7KlBnH~U;=6kgD1AzW^-d)9t@oS>Z0{A{iQb1o&?}h9CI3RIXi);hb2_bPC34v z(ZL34>&Zp4+RKLjMBvyGS_dc=RC@`^mx-yVKOnk-VB=z-7`^3H|4iTg*&ypD78w%n zB%Tzo{2k2R27O?Use7Fa&Pgk&%pgsSOd>bJe0NT6J`K-*8gOm zHIIJ|0Mdjq-;JzVU`wF^nhZd9%i=ZHvqhRqXaTc4j=&APya*t^h}r}2$5UTyU)tgo z#2wck`1(|Q3jaA(9Qhpw^@2~(1)55(T*I^t0MY92o7yuT;t{RU=dhjR1*-h7(pD`_ z03=Q>jFJ_=dGg#Co$s!5iW*527`pkeDrzLJ?Mdog3I+?KJl0i{dKqC^;E3pQcKXB} zfwMF*6;ftF7A5Kpl>!i^M4;|UJf5kkB+_-af{QtBEInm3e2W!)2xKU3l@+TNJ_9&; zkpimck52C{ZdBbYHHQNz3A4wGQq73(0RFoxrb0hd`V8v2+uWHW%~cP_P#CdxMRM6k zCxi`IuGNNfczhQ6bbXo=Lwa@mreNfSq#L|nSxhLoJU2(T%%cY-K{@QSu39J)g9k`# zb>){xlzvi-8oGB6B|nM;W+^J&XmUHn2 z2$?Gh1Rk0~g_M`=s}?p&GF)@aywClC?cGv|uMQ0j#UQj=`>A;&mV0`j-AfGuF#Y0g z*FtPF1CO?z|5{bGiEpZLS_qV1j;ZUV=Qaj|Ew?@npt3$nRkl}q$ZAr2=KMIq4j}V^ z^P&<8qAeK$cRgr1HR6xM;?fdaY)szXn;;A?_|?Y4tH&*?W5l=++Z2;WT6mHkLveph zSXwCMNh6g@Nx_%c?wl}iLNqJAOw|jCT9>CO@ee`r81k^on>lY)kC46ZzwK)C_OQ3<3pn2R?BL#=Cv7TV(Wd ziD^avl`M}R9)7~-F-e|KHA9@Q`kj8sT1$RrK$$`{jcXao=8o#*jqF|TjDn|pJe&E- z6hBX54 zBVhAgvjA%$vBWtF!+{neiy2EZ!8U!MB_=8_s;BxqWIHRb{voe_%^}-RhkuGBmqsfV zuTNxxno7?aRavkYp5CdOu84;i-L4cYX(!e-M-ob@7mrVn?RDTgFc)bEro$tDFEmQN z?Y!-;DXr4CQusKGGW>QMv~P^-u(P-pfGaHX=-WAbYh&V8$phx--@ufd%=VtgChVTZw6Qw`oG$GQ@BgS zoar&1p+br4mB-?lJwRy$SGKc_{WhA)wLH?MFGNUGCvKmbP$!Y=0~bneShn5e6?iWt zJ>%h|0n2nt{g{poe{MUr(#YS(EYOZa>Svn^6Dad_YDF0bo4?j7B?vB9ii-0gu{T-j zALttl<>Ho=#=%Qt)y8owWG_ec}F0ZM23ZCTI+MWmOZ2DMAPJ5PqsIn%8Z&bUoL;m>hseXk~)P_ zd*+lEjAdi9tEKhJcfkCeJ(F^YMQ{NWs%9^lLu)fYwF~5!!a@Taf=hd(;K9cqrMPGH zk=?NQsy&4@1EUBV4&jH3bXsL*A1i|g`F*_|qna7T*%=1)z7uu$Ji!KSo&e;ail)5F z^X5x0v>Hy!b7JBk9iwt^%!FAVZ^-W5&D8EB=dL<%gz{$JM@EJyHeS4#CY{XPmKlGJ zchr=&-{TTK`Sj*$`fTt_XiZ_XN|zuZIvX?GSz7yx5TZF)=YU8T5$TISf9!nOS(^6t z4S#x2<9y$mGNgKb#aBHuFZmU~>>hnG<5z8=xQ#2FcA?(N+$~Md$mpNmi1@q{W%F}& zcW0(I(JR2>zBTVNXi%xJ8q2j0vTe3hy9q{&JM(YVp8ehlQ31wmy|Se+xA6le50}D9 zn++IveA+d~1fiD2h1XFYf1DwYLzXPVlY@*&=VYNj64XOpirydD*vQhaLB;R9gP^38qp)R+o3q2%Mz z)O|-0P8RL7AY`RShlE^TSh9y(e!EzALne2=&iywqY~c<%I@`sE&R)KQ!o!1F?NT0* z9#}Eofha*Qwm|r-OCKEVgDwxNT&Baw%y+WWq3%>cZ8$%^u1Z>zS}-bNewKiJ+hyUP zs!a)Xh^C_H56$eGnK?akIW2eD?|BUzx=-LQ@w(cCi!v+Q6DOOj_~ydT205L2Sz*0Irzt`%$@WJ2ju{wl+q!P zTmA&lTG$C-M}~tUjr&N}7u~g}W1z`;A2Gfe@8 z7wg*St$OK+n?%F}K|0ePC_eIWnaqbNz4i#a=#}-hAz!_mEkPAUB zFW@&J#k?N=qHN5mm_l5r+%n9b8mWcKl@c1D8u8Fw^a%}yCML8PA0Pi( zFumAKDV|&fC{cAq!GXoQ2N~3@%@+q{6(qN=EsAA}5n0Q``MBe)HnsLA?DalYKiyz8limYNxwPN|5h#5ich87grQ)?n z`FngH*3fB^%MQkOby;lhXgV_*Ji~Fxk$w_`dg#pUYf3rsQU{SsTjYO4bYJT7tkNmb zDgqM?C$LglL|q{QQjC&H?^!!IUf7I0V1n{)_NBIA+p9+8>T+3FZbaN}!~RZ^7ioOZ zzlIbmB`I^N8}BTQS@h(TcWO9CqP9(ln+fGx3EW(sw;WTvQe8-;Z{_t>>2MD}8Z+ zpYkx5?=$;Aav5aNXB#*Ev;Tpmo)@2yl9HEYSo`oX{JX0HYlJj?8!XuN6}HPN()uk> zl9gSi9gvXREF<}xaw!m*`<<3FI$EosWFAVu2{0b5@vwQ{1)mC@J?#KmfqI)_Dx8WD zw(E)F8!aqXA^(W;RRdu{zUXQ?AyMI+e{BS|rs}IFUe}Z7FOk^h(9i9{?LE@&sn^zE#$y-BgMc80@Iahwp#K@z%c7O z+T8EXr{I)9gtFt&Val$VwM*%HbTM}hK7|+UFV7Kdn20WT)$GrQ4k;lUh0$l599-Jv zMKq}s8KEgZEYVrN7M!dg@UMiY3N!*IYwk-qazL)%3pl2f5-Rm*$V;n@rCbv+ZoT1(NlwIc&UG4WT&QIr*omgyi0oJxh6R}0<@y-s96l(;w&QZj# zKq1I`uH+q&CdfGj>vq5Qde2@?8``{+YT(Ro-loARwoA&TwPIWT;Qq30fQN-hqkE?L z+8Hb0dk*FC+ijhKIX~i897c*e#En`XL?qwAxuQ0q*pkvcX$! zw4^7M(L;!@l2!rujN&^$pgW<%X|{SCd!^IuWRN&~kgD{+S!};gd?QY6!pQ6Ex;pfa zDPjxo#exCKrGeLn-y`!6!k~#VgP@{Rv`y$bBt!Z?2VVyK9|j&(63?pqAPuzfMQpez z1pyblO+(3v3;P|SSZCw9+Ha>i!)J>fXEp7dJGPX0NpAwWPiPdq4UUu;0|s7y#N>va zHHQ5=|i487PSA;>O9 z7w?c^-H&CCX!uiTQDAjs1MEtKDxj`PRYJ8PkD0|8Z|Rm9$%zf76gVDRyqz69M}@fC z!nWU!q2Pa}#q36#NFrsB&PoQR`P59RqA8Rx#EnG=RP;><)0_Ggg3&)NO5G8po9%Q9 zC=tFn$E=%dAbT2A{A3mv)7g3&4~WPEm9D$?Om-D|EnPQV{KNB4twp;WIlzx{+y_7^ z>?$DT#W3Ctul?lv^rC#Fg&uJiRE6O&TR-*Q+1XL|1hrTzj#>Qcp|5IE=h`8`x>TUr z!tV{w+|3A-D9L$t&6XWVL{8VsnwKx`JHK^8TRgXjTbC~N5&{5&hd3;^@O}t_; zkaOMlfVHjwXaS&z65Iu|f4V1$2BU~2i zYDpLFv~DZsin0^F$MikBvp~XedEqy47i7y8@aIpIC6@0YM%xazxb04OaX`te)PH<6 za0c+@t@nkz`{)v>L$l3~%&}-IKxS#*mXl6l=<)GQ%hOr%+qWYx6rEI3fSWJvK9R+o#!UL%Fd<(>1m#jNZ?@h z{afM*LDW@zZ%C@y9%PXl|IK(&uN*?&KAApRwwy+eCRS9a&<5StR3v!Z?^~}s>;?}>9s01>TWdNwc3#H1uME& z!i*-CXCvuAW9p(LKki%!lg=l|FM9JQg<@Wgp*hCj4YWE#=>mydVv`K zwsJ4%1Hda0-{4yT-~i9j4l0g5cSIlx$exO#8*b9VjXN3 zbsKP-UOCcN_A;sc|Kv|F&iRuVGW*KJU$QaCSjvF7c81iXlD1?*e>duasC$1d0`N~g zk)#-$jR@M7a|2Yh3e@>Ul%oO>Odw$`Pe$MbDM#P|f5v#%1sMieP%;~Jcxmt_Vrr0` zE;%y=>-Eptt54k-IX~_#VHa_)HObEyyOxB`2O9q?8mRqt~hl%*9_6MHEeZ?OCDw!+OGGO?S`- zeQT)Q$J;HMpBRuypA!Ko``P~Qi1Ln<8{p)t3w{-edIAg%1h~F<3+x*$X%)2C$h<@q zXFS+FkliS-dH37ef%-AwtswAHgfv^mPau2)@6=dWlXlB?czqS8S>A&m4FPYS5YmXC z-cSZA_)3@z=DQMz{|Y?&H2!rU@s4v1=00Z!O8}+j{0Z`veZO9u6RmpPEaFdmuTc@_ zbA+HMb`a~ou|qb_7PiTihoD@$KVie7s{a}6e{{yO_dllb569_{>BSap;F(6Na&IFW z=FJ+863DG+o9*F4t+U-;ZkL}@m*_#lW&cQUpq92lkWLj+fg|Baav#75fupVlz@Y$| zDFb&Cfkrel_KD`S$dre-63MdkYI^T2_XDlH0D@^mZ>*3xozuq3SEdMZw7~zwmAm4T zA&vae2!M(}wVH8FN8f!swIHqpl5R01UU!JRFJ^M1Mn3VX^ls74;XH7m6xkN zkP0}__MGMfU^Ks@E#u^5U?eF?Nzd8Y$a%~qw}>=PJVQ2A%gO|3(Ql_wGΞnPUce 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 Date: Sun, 30 Aug 2020 17:02:12 +0800 Subject: [PATCH 14/38] Delete PoliticsStaticModel-fixed.png --- img/PoliticsStaticModel-fixed.png | Bin 30975 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png deleted file mode 100644 index 4b7269e4563daf0984815d778639810183b7d90c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30975 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ΞnPUce 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 Date: Sun, 30 Aug 2020 17:02:30 +0800 Subject: [PATCH 15/38] Add files via upload --- img/PoliticsStaticModel-fixed.png | Bin 0 -> 30975 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png new file mode 100644 index 0000000000000000000000000000000000000000..4b7269e4563daf0984815d778639810183b7d90c GIT binary patch literal 30975 zcmeFZcT|+y@;2CpBO(ZrB!htDOp~KZlAJ+u4kD6sXi$+HB|{5BD>+Dz+<;`7WJ?Z$ z#3qB}CeGWOd(OT0oHJ|wnE7Vbtnc@StCw`Yd)KaAyQ+3QPrc#ls`7X5P}~85Kz9|M z%4mW>zxjhe*Nbmo2mbOcV!j0UxaOuQ{{&PzK(z||=cesrmB%1Zc`VME`ES7gv7Mjl zyMaJ>ZJ2-8x}5T@Kp^i#1)0a%-X@zrILoLM>K~X%x7B?&upgiPZa>F|KlLioAmj$V zgCo!9G;RleJ|owUIGkv#)R^>i3S55v##2wY%ahf!!op&NsDAw5jTlucIU6~-4lipR z_^}f(We~|Tci;o0YmU4Id^~$Aiv@g`k=&;SK7w@qclc8G*L5>2#RM!6kvj>fh-JYg zC^v}-AH=l6253bXuS$g-tA!Qw6%Q5GWNy-ppTzZdf^^7YZoC{qTywr-{96kfZr7{o z=Sv{rx24z3NJ17KO;x#qpilI!eZJG?^5La{2uL-%2+-}E@HfE{Dp1}x9Z+$rGnHM2 zE?$t<|4j3Lp|oR(lcf~Xd7V>~)TMsw-S7fy?ZTBIgoSMGTu_D|hpm=5?X59a5d0M!aaKZcGM3 z6U$GFt>s6>3W!S2o)s16p?9=7Rg)^x>~~ZeoKipPqq@J;o5F&9pE}v+{Nx}{Eo+{U zeeP4K2TlEdk1#o%BaIE3`e4Duv|hRbEa0H%9(NktbY0xGr%e0v%IChhFDH8_LHhGw zyGbRehEbmtgc0YpTI^3T@aM2Tr4H1J`QYffMBjo(#*DsfejFBF-6-K}ksLDRvST{Bf0%R=rqURts6 z%XJtjj~dTU)i}k*#+I2j4>&|U-$M;%^)|Ud{W1&CJ~Wx@#OT`g3?V01%P?4o6s|@f z*kX8v@X^Q3xw-6IL7Q#@=t)nw?**=>p3Z#!_`A#4wf-80@dnt_HrAotuzO>LU^Mz> zC=@;B9#Xq3dIvHgB^j2CSFnQnDAvN2vsId{SWPG|93@S^r9qkC+06(Nc0a z+P3dW!}ila^zNq(v95}}MSt&F`naLtRLd@^1Lr0w=5c~LF^yQI#BnT_y0Ck@<58vu z%k{kEG0{Gm6yP^>rF`kf)0CIP+DotMR^l#0`+}d!VPEbl9XX(6NPj+5B3 z%)Jtp9@z7<#Uto5c4261INp25ZQ_4^B5)x$nd|7bmiq*H=^R4}AIxxfDopv9h>BYE z-R_AOR-+j)EXnVsho>-H44(BETd(uF^txQs2NPV<2IyK01M(TBIsLPId6DGL1BS$w z$KiP(RWG#9GAZ?L70m6_XgO^41-94XM_(Hx-EzIpGU0`W5!VqdP%S=@?m{$xrNJ~GUV?e;Tj$Z)$m+GPQ@{$ONSg<7Y~uvN_!BI(vTeww>C zELU2n%=z-8(X%vDiL~9-p}dppvXh9>J>zxp(|8}9>&`@q)P6&9X|vz%R>fz3BO`I+ z)%S`x@xGk5e(heer`$j2b~@a4d)4_o{$?My=%U-TJzKm`x1%iL?&!S)G>?at{D=|f z+?)DF*Ap%5IvW1V<44Qik^ZUiwznA@F*?WMiTYb2eT-!N;| zWSDS#^@)ShSs+3~8W`Wvy6Kq*_0Tbw)dxAz;H6U8B=ULF)*a{d~5pL$08 zoW^#8dRfhwyA}cXOH-x+UA;t;W(ak7oxkKq;123R%%lF(mQt7$;=kp%?An29>Dx2Ny%Ret}t%(|9{lMlk zVAXv-%P3Uarg13g*@kRroZD_HzFI(Ew(6uGKIxec9OpjuZUVK|i)-lHa%;x)+bo3Q zC!eJyJ`ZfJw<3mLkP1nDi6iLA@a0(I0JLe0uK4GG^8+RT_!av14Y{Ml7EDIX-^z~~ zrK#S{dI{G*bP-+$R9JuiUdl=nn)VV^@#NwzTxs}bmvU1LyQ5$V{!DYAsUY=mQrOIw zdF^s`{5pS;aLV4Xs()S^O-cF6y}dQ4c4%r*R{=d)VDHu&(P*`DA(%DK@*xc8ex28^ z9O?WQ*XT+Kc^8~+xs5!yq&3OO_}TcrQIWz}lFX#YuNN+RXX{Cm=RZ5xBNp3%F=O}J zrp=H5Z|@Z@iKu~cO9L9@T9p*@9uQS|+qiiliAXMe_uDSV4PM*zq|yAtZp)noN;0n( z7JqcaZMC(U1_BtXX~byCv$C~gf?Z4`fFx5e@Rk;s((}@ov!9( z%^Pr=HgT9At|foMtN!rcaSzXKiqo*JQJ2O1P?6W{uX)bZ5WO$nX5sq}SkzRIC4x2{ z{l&RCp6_K{LVXX`OS4TO=p`VL1p+CnhWTE_N^%Qg*C1(7e?#|v5MdCt-G8TwQzh1s zcq2d*sBxM_T>EUUZ=qzSLM!Rt{X$1W1tIClg!2fy1@ABU;N~c6Bp%}#Cd|V%^a^K52C!v}rs#286Yi(zU_xA$HD9FLs?IhC#%?lx zNZiW&KY4iWV10~$nLcF)aRJ;Sv^0N{(Bl@oJTSc+@oUM31W04Ee`?4h`~24gu)zbJ zBMoV5bw5CD&^g7v#6~MIv`Fx~? zUbye&ZjnKAT$cOs{;C#a?@8EgU>`-v+!hR zPI}_#X%y`Ry)7O+O2Soy`dZ7dycV^4{e^dJD_;Te|X;LhDqqEqd8QR+gB1@GL2BfDBi1qv?-@qy+MLi9MGU-<0+rkgLE9je3-5O~)cPiwFcf6GoAvPo&Ol-8pwZFl7b6PxSEz&<-RsPh zkVjs}wGMl`ok~FxY5Mx9lO&d3S7KccX>4fNQ{Q3XWfV_K2DVPlC+$3fbhX>X>PrQ> z^v-cm#&ZW?Lv6;z_M3QIwZjW#WoJd>$oase$D?R>lZmRPv*|2gQ-%LSIHJ7Bx(%=1 zwG>#77E^hi*!0Rl(LRO3k3^1#V+QWG^`SA4u}OWtYm7Vo11g;>4bQ}kTyFbpGqz+x zD^_?cCm3${Y&aX6+573e`~_@og2aip8HCI#SLBm@yTuN?Br#FXEsz&rg5g^_b4O{bW5X2SiwjDhMi;YljaFQ;~YjTNDxZSv%kE4dVEp z9&%Eotu)iSHo1*}H}G6f{k1%+z81uSahq{iX@0|_w1GAn;dax| z(Cm&MQyNx`s)XOJJ99x8e)XB$sycLziD!H7r8mnJDP8YHY}sDB;%w)~Um)QUQmcNH zFXS}Shno(z$ra=Se~*KW@KAMkCWpnT-TNr)zpN9s>9Xv2W^Q3WK{nFgNu;EqXX3l> zAzq}O^uuyKj&N1sVOfe2dOkCA1GZbm$YZ`{TpS?zQ{9>=5#;xdb7!SUs&YNwj@O=& z@KWYYTu#o&kmpo+;uLBs7-KrAwTd!f%b$Yrch_kg(Ocvht}Fs>9X9)2toJ$OQW(DE zuNY$SNryxSjwv(Hx&_0*R6+!T)=*ejKYcsw1WUc8Iyq?>P_sWsZ@@76H3w2W!XnW0hD zvRSSxinuNCRck~n8j_?(BkW*Tq1c6HaD5-Y{K?i4WvAINPk5kx00EQ9O*J`$&pWB; zP!VEvUcyP)HC=`Kv+zhS=_cB0hV2JJeFtzooxm48mDZY;dbhNuHRN!ZlXFTN8-#7K zrNSdep#^%y1)EIV*1_o)xVhcQgsUGil+c93u+}f>tKx>(%4AKEB%V$4_xNZPgCu%J z&GtvKCIrexkMbwsatuo|!hzUQJ)3(f`WS;(-h2Zr59@7PWCc;E<`B0am^PP%cVO{| zZ&j1fmrr_mY7R;oOeh(K^v0!j^AnEZ4kuegWQS)m&UdzH1n9;r;w10EP#|9db;9}z{d_~t)Slw+pBLQouEXK zhU5V5K+%2M<$@6MZVF}i26k5!QCe8tC!hnDi#_kYu6`YhR;)R3y3(6*a@+cQ(%bBt zsg7q2u2y80NJ7c(3zp6txX@mX!r*G#3O`+JMDyMoG}U=bE*lXTd>bD*Aq$-YL9*!C zpZpP9tMD>yI-j9qR8|IVz+z;73%esI3MtH^Zt6%pU@KHF<2zcMgB6Gxd|4YW^*Wdq zF8(g?#oV2hcObz}KJ;_l3$`0CEJD<%KGr`(_VzgB(Zh22L>9}z1Qi8q%Q`B9D|7_l z{asEizM+{BTqq(q8!1h%(0fPchfeDa7aWZldLf{spwCpcTl`g-uYOz7V-xL1RnI4c zF{b-ASH=VrEMydCVrWMz9V<9yIU!;Mg$u@9ZFbl;alO{m?M?c`C+~4>6ClFROqj6r z$rOWDJDVfu>~LimRGs>0OT41u~lC#nYQj>K8V50O+_0e?9a?!O4#RO(u~0|G&*{WA<>xirl>kNTLh&d zT|cJw9}KU7{oSVyF0ent`xf`B<m;mQdX5|>8S2ZC zPNg`{on(BU^fScTG4YQzzEIeVF3}b8C8`}f$ZKq>34{V=dJm-xfIJM9PJU#85Rk_jtW7gR(}%fd)iOsgJFq_(4bo0vn3sGlR& zzHcIJ^(&%e!2A@iQns$hTzV&Mj4k&^m!RJyd&4V?)5@i$hic! zWT+&YikX_TUE|seEu@PM%SWOd-tNa|T2?6Tzr5yCHZAFrByIYMZ>(Z(y!28n@_7@`*SmtQo8|K?zSM+Wj zD>H?)h>MH2lk-6aS68#%p;%w#nGJf(4%^Gwr~=jwE?Ms@^+6(*?r|=%Npn?)981YP zpSTUE=)eSS?$T=l3Hco=MvotA|@U-#)Xlfie%0(=(=}I{TjFE&A+U z#?ngJ#QBK4?z;r9k0$}A+VnilSYFnR;!D#MLN=i61_Fpn?P%~b>pqyuV?ow0brZw|2G&rb9NRCud-&UsrOJTb*lXiC`XZE4@6Oy)=2}&6rGQV|70XlZiW=#YRXn zip3DWSGuXyq?SCTw81>_Tl)-QW?bmt$3jW-v5cQqv|jEdR(gCe#XqhT9@U;(?(A6< zcQw>P)J}torP}O0t4uz%)uA+X#z^b&A1^7k@8qy9;QzOZ4idp?B9p4r(asUwo&Loi zVlrXpYb9b-aCN|P#)_C{k0RHTcfQU)@!-#@)ELl7ntMI`dS9()uU(2ZFYtDB_DQ3Q z4Ff+chM3#Qq}EHHaQAX<`qTi7a;-mgQ04X~o^Ka#Tx{Una(u;*V0>NN`f1cHrDJ|x z_r6yzqLM8`W+|CNsn|jZA+Gb!B)V$$3J}>2M+Dm&ru61*`y2X;3M{W0zFeiQT$zqb zR36La^#$lT)&sV)v|P&qgiwBi6RmY&?)@{oyvEfWX=8E`A-^`HXQ3)m>Da=h)j`uw z-<_XP;D%abzdsqr{_a&_uKDX{l&5hsro(r66VCi?)eb@xlg^hhP-;>zQe<3JBhv|czIIq3YGnh z=Zd~gi@6IgsgP1XQT^C}lfW!GsXC%(ZqEg8IW5mR6G?xU{z@zDn~q+jU&$ilTl))= zJ~_0(YE}wr6%uIWbeB<{@~fBEk(Fl>h(BBK1uWLFTnGrdKNXzr2aF!^#jr6?s<=(| zwxk_#7UE>(k$IfpklqM#?GvDaJIb*Gm(|4;{*TO9dtiAL6(Zm~YQ;FAv`7-(Q%RxB zzT7Gk#<7$B&%MZSq?Ra*sR|j{02Z;k11mu2KA?TsU1z-=eqP$f>I7ejD_G-F#_RCr zuVCaW3C34_p0|658WU!aZXN#aFt{Qco4aV|lTS~6kbnn2mGFI+_CzO^bBacpoRQfK66X4dM)A0Z^$j}ieFsu|$y*@w9Q{)ox6qAL$4co> z+oE~D8XZw!Nt0B0o+(<63mhE_IHD~!m#w*-ZgRT*=U4{9lUmhhT{cuyC)0r9cz2(3 z9iB%AENTr4OU^V*onhGHTX#|Iw6=XizrF{?;83PzrH6RgQIZxu-)fRW*SE|1#h!MS3qZ5^YhoiaUP~m|g>v+7c`(m}-rP?WxcwNY+%-4|5tc6H( zM$+vCC$c$67S4viPajnpePp7XBI3Uw^hP21~sw1mhAeid-GK; zPXj(YcsHEU(uG4x;OZ21DJ{ecKc>U$*|_U-(KuAmknl=gR?~K}tK%)3yJhEP+70X3 zXBT4}h`zzg!IIykeKHBj41K$GLQY~vdtdm!d`8J9tq9uEtxojUfe_4dvu+KvlPi=drifK+%C9-~2tUJu#&Jk4NV_%(dS=YPkVuHao z9w%m!1K+66J1<@8D#{o_8U(K8MHP9mfb(u{jb1^n@Z@4hufe_A93T-mHLl7YH_X}6 zSq6v}{HS8x(i(#RUs?^kZ&23{JXNT<9sMY+`+SE5e-!7-a=5q*b`~bAH8@_;-j%XP zR_@Uv`;=L(1ua9T5S)IC*)k)TNBMIlS9wmTZf5`aAU$pBQ5{qDPrHtdyYzmsQj0>8 z8(PbcfN5>@*}b;P3=+N5weW~TIvd6OzqC^}CyJE(@ho>rR+8`1y5U3!5&QD67CvwK z^k#~f6<#9fky|oQof{NWmLMmcQhIo$7NxbeA1Q%Y`fYrXzsHZs?r%5}lIMxA`Yt)E zR~)bO!RvU8odb)TDZukw4okjjozalt`MfL$0`4^1#F;T(!-3D(A`#gWv;A32_77Zv zYj5jEgDC)qG99ZEO~qSR+>A*x@ES+8;Q>W4&^IWKVI7hSRi&wc)^R!CYBmUu5*>R0vIe;!t5kPy_C;w!#Kvuo2opbVbgyORaE8Lre^5g z5LKaIh#*>;n;Ge<2S_*z0i#+#th&1SVDS0W-$>lte`Ie=CH$BX{!F9?EQMPBJUNtb zGB(Mrg^ESs3P`<7R_J53DFNP*T1*|3ETF?huqoTj|h5= z>z{A@g%0v)O84c`8tDyq!0G6=wWf6e%eC=W|4k48#xW3aRQo&OB?w@d)k^%G?{fp- zr7ax(olb!VP|RZffr0S9dIIawYgHxuK7S`zl=q1SRRiq0e`53e|7CGK|Esn4|K$X> zzkoEr&L4mfQ*b+_2%@6N8*`)?@{$&E|7KlBnH~U;=6kgD1AzW^-d)9t@oS>Z0{A{iQb1o&?}h9CI3RIXi);hb2_bPC34v z(ZL34>&Zp4+RKLjMBvyGS_dc=RC@`^mx-yVKOnk-VB=z-7`^3H|4iTg*&ypD78w%n zB%Tzo{2k2R27O?Use7Fa&Pgk&%pgsSOd>bJe0NT6J`K-*8gOm zHIIJ|0Mdjq-;JzVU`wF^nhZd9%i=ZHvqhRqXaTc4j=&APya*t^h}r}2$5UTyU)tgo z#2wck`1(|Q3jaA(9Qhpw^@2~(1)55(T*I^t0MY92o7yuT;t{RU=dhjR1*-h7(pD`_ z03=Q>jFJ_=dGg#Co$s!5iW*527`pkeDrzLJ?Mdog3I+?KJl0i{dKqC^;E3pQcKXB} zfwMF*6;ftF7A5Kpl>!i^M4;|UJf5kkB+_-af{QtBEInm3e2W!)2xKU3l@+TNJ_9&; zkpimck52C{ZdBbYHHQNz3A4wGQq73(0RFoxrb0hd`V8v2+uWHW%~cP_P#CdxMRM6k zCxi`IuGNNfczhQ6bbXo=Lwa@mreNfSq#L|nSxhLoJU2(T%%cY-K{@QSu39J)g9k`# zb>){xlzvi-8oGB6B|nM;W+^J&XmUHn2 z2$?Gh1Rk0~g_M`=s}?p&GF)@aywClC?cGv|uMQ0j#UQj=`>A;&mV0`j-AfGuF#Y0g z*FtPF1CO?z|5{bGiEpZLS_qV1j;ZUV=Qaj|Ew?@npt3$nRkl}q$ZAr2=KMIq4j}V^ z^P&<8qAeK$cRgr1HR6xM;?fdaY)szXn;;A?_|?Y4tH&*?W5l=++Z2;WT6mHkLveph zSXwCMNh6g@Nx_%c?wl}iLNqJAOw|jCT9>CO@ee`r81k^on>lY)kC46ZzwK)C_OQ3<3pn2R?BL#=Cv7TV(Wd ziD^avl`M}R9)7~-F-e|KHA9@Q`kj8sT1$RrK$$`{jcXao=8o#*jqF|TjDn|pJe&E- z6hBX54 zBVhAgvjA%$vBWtF!+{neiy2EZ!8U!MB_=8_s;BxqWIHRb{voe_%^}-RhkuGBmqsfV zuTNxxno7?aRavkYp5CdOu84;i-L4cYX(!e-M-ob@7mrVn?RDTgFc)bEro$tDFEmQN z?Y!-;DXr4CQusKGGW>QMv~P^-u(P-pfGaHX=-WAbYh&V8$phx--@ufd%=VtgChVTZw6Qw`oG$GQ@BgS zoar&1p+br4mB-?lJwRy$SGKc_{WhA)wLH?MFGNUGCvKmbP$!Y=0~bneShn5e6?iWt zJ>%h|0n2nt{g{poe{MUr(#YS(EYOZa>Svn^6Dad_YDF0bo4?j7B?vB9ii-0gu{T-j zALttl<>Ho=#=%Qt)y8owWG_ec}F0ZM23ZCTI+MWmOZ2DMAPJ5PqsIn%8Z&bUoL;m>hseXk~)P_ zd*+lEjAdi9tEKhJcfkCeJ(F^YMQ{NWs%9^lLu)fYwF~5!!a@Taf=hd(;K9cqrMPGH zk=?NQsy&4@1EUBV4&jH3bXsL*A1i|g`F*_|qna7T*%=1)z7uu$Ji!KSo&e;ail)5F z^X5x0v>Hy!b7JBk9iwt^%!FAVZ^-W5&D8EB=dL<%gz{$JM@EJyHeS4#CY{XPmKlGJ zchr=&-{TTK`Sj*$`fTt_XiZ_XN|zuZIvX?GSz7yx5TZF)=YU8T5$TISf9!nOS(^6t z4S#x2<9y$mGNgKb#aBHuFZmU~>>hnG<5z8=xQ#2FcA?(N+$~Md$mpNmi1@q{W%F}& zcW0(I(JR2>zBTVNXi%xJ8q2j0vTe3hy9q{&JM(YVp8ehlQ31wmy|Se+xA6le50}D9 zn++IveA+d~1fiD2h1XFYf1DwYLzXPVlY@*&=VYNj64XOpirydD*vQhaLB;R9gP^38qp)R+o3q2%Mz z)O|-0P8RL7AY`RShlE^TSh9y(e!EzALne2=&iywqY~c<%I@`sE&R)KQ!o!1F?NT0* z9#}Eofha*Qwm|r-OCKEVgDwxNT&Baw%y+WWq3%>cZ8$%^u1Z>zS}-bNewKiJ+hyUP zs!a)Xh^C_H56$eGnK?akIW2eD?|BUzx=-LQ@w(cCi!v+Q6DOOj_~ydT205L2Sz*0Irzt`%$@WJ2ju{wl+q!P zTmA&lTG$C-M}~tUjr&N}7u~g}W1z`;A2Gfe@8 z7wg*St$OK+n?%F}K|0ePC_eIWnaqbNz4i#a=#}-hAz!_mEkPAUB zFW@&J#k?N=qHN5mm_l5r+%n9b8mWcKl@c1D8u8Fw^a%}yCML8PA0Pi( zFumAKDV|&fC{cAq!GXoQ2N~3@%@+q{6(qN=EsAA}5n0Q``MBe)HnsLA?DalYKiyz8limYNxwPN|5h#5ich87grQ)?n z`FngH*3fB^%MQkOby;lhXgV_*Ji~Fxk$w_`dg#pUYf3rsQU{SsTjYO4bYJT7tkNmb zDgqM?C$LglL|q{QQjC&H?^!!IUf7I0V1n{)_NBIA+p9+8>T+3FZbaN}!~RZ^7ioOZ zzlIbmB`I^N8}BTQS@h(TcWO9CqP9(ln+fGx3EW(sw;WTvQe8-;Z{_t>>2MD}8Z+ zpYkx5?=$;Aav5aNXB#*Ev;Tpmo)@2yl9HEYSo`oX{JX0HYlJj?8!XuN6}HPN()uk> zl9gSi9gvXREF<}xaw!m*`<<3FI$EosWFAVu2{0b5@vwQ{1)mC@J?#KmfqI)_Dx8WD zw(E)F8!aqXA^(W;RRdu{zUXQ?AyMI+e{BS|rs}IFUe}Z7FOk^h(9i9{?LE@&sn^zE#$y-BgMc80@Iahwp#K@z%c7O z+T8EXr{I)9gtFt&Val$VwM*%HbTM}hK7|+UFV7Kdn20WT)$GrQ4k;lUh0$l599-Jv zMKq}s8KEgZEYVrN7M!dg@UMiY3N!*IYwk-qazL)%3pl2f5-Rm*$V;n@rCbv+ZoT1(NlwIc&UG4WT&QIr*omgyi0oJxh6R}0<@y-s96l(;w&QZj# zKq1I`uH+q&CdfGj>vq5Qde2@?8``{+YT(Ro-loARwoA&TwPIWT;Qq30fQN-hqkE?L z+8Hb0dk*FC+ijhKIX~i897c*e#En`XL?qwAxuQ0q*pkvcX$! zw4^7M(L;!@l2!rujN&^$pgW<%X|{SCd!^IuWRN&~kgD{+S!};gd?QY6!pQ6Ex;pfa zDPjxo#exCKrGeLn-y`!6!k~#VgP@{Rv`y$bBt!Z?2VVyK9|j&(63?pqAPuzfMQpez z1pyblO+(3v3;P|SSZCw9+Ha>i!)J>fXEp7dJGPX0NpAwWPiPdq4UUu;0|s7y#N>va zHHQ5=|i487PSA;>O9 z7w?c^-H&CCX!uiTQDAjs1MEtKDxj`PRYJ8PkD0|8Z|Rm9$%zf76gVDRyqz69M}@fC z!nWU!q2Pa}#q36#NFrsB&PoQR`P59RqA8Rx#EnG=RP;><)0_Ggg3&)NO5G8po9%Q9 zC=tFn$E=%dAbT2A{A3mv)7g3&4~WPEm9D$?Om-D|EnPQV{KNB4twp;WIlzx{+y_7^ z>?$DT#W3Ctul?lv^rC#Fg&uJiRE6O&TR-*Q+1XL|1hrTzj#>Qcp|5IE=h`8`x>TUr z!tV{w+|3A-D9L$t&6XWVL{8VsnwKx`JHK^8TRgXjTbC~N5&{5&hd3;^@O}t_; zkaOMlfVHjwXaS&z65Iu|f4V1$2BU~2i zYDpLFv~DZsin0^F$MikBvp~XedEqy47i7y8@aIpIC6@0YM%xazxb04OaX`te)PH<6 za0c+@t@nkz`{)v>L$l3~%&}-IKxS#*mXl6l=<)GQ%hOr%+qWYx6rEI3fSWJvK9R+o#!UL%Fd<(>1m#jNZ?@h z{afM*LDW@zZ%C@y9%PXl|IK(&uN*?&KAApRwwy+eCRS9a&<5StR3v!Z?^~}s>;?}>9s01>TWdNwc3#H1uME& z!i*-CXCvuAW9p(LKki%!lg=l|FM9JQg<@Wgp*hCj4YWE#=>mydVv`K zwsJ4%1Hda0-{4yT-~i9j4l0g5cSIlx$exO#8*b9VjXN3 zbsKP-UOCcN_A;sc|Kv|F&iRuVGW*KJU$QaCSjvF7c81iXlD1?*e>duasC$1d0`N~g zk)#-$jR@M7a|2Yh3e@>Ul%oO>Odw$`Pe$MbDM#P|f5v#%1sMieP%;~Jcxmt_Vrr0` zE;%y=>-Eptt54k-IX~_#VHa_)HObEyyOxB`2O9q?8mRqt~hl%*9_6MHEeZ?OCDw!+OGGO?S`- zeQT)Q$J;HMpBRuypA!Ko``P~Qi1Ln<8{p)t3w{-edIAg%1h~F<3+x*$X%)2C$h<@q zXFS+FkliS-dH37ef%-AwtswAHgfv^mPau2)@6=dWlXlB?czqS8S>A&m4FPYS5YmXC z-cSZA_)3@z=DQMz{|Y?&H2!rU@s4v1=00Z!O8}+j{0Z`veZO9u6RmpPEaFdmuTc@_ zbA+HMb`a~ou|qb_7PiTihoD@$KVie7s{a}6e{{yO_dllb569_{>BSap;F(6Na&IFW z=FJ+863DG+o9*F4t+U-;ZkL}@m*_#lW&cQUpq92lkWLj+fg|Baav#75fupVlz@Y$| zDFb&Cfkrel_KD`S$dre-63MdkYI^T2_XDlH0D@^mZ>*3xozuq3SEdMZw7~zwmAm4T zA&vae2!M(}wVH8FN8f!swIHqpl5R01UU!JRFJ^M1Mn3VX^ls74;XH7m6xkN zkP0}__MGMfU^Ks@E#u^5U?eF?Nzd8Y$a%~qw}>=PJVQ2A%gO|3(Ql_wGΞnPUce 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 Date: Sun, 30 Aug 2020 17:02:58 +0800 Subject: [PATCH 16/38] Delete PoliticsStaticModel-fixed.png --- img/PoliticsStaticModel-fixed.png | Bin 30975 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png deleted file mode 100644 index 4b7269e4563daf0984815d778639810183b7d90c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30975 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ΞnPUce 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 Date: Sun, 30 Aug 2020 17:05:34 +0800 Subject: [PATCH 17/38] Fix the picture again and again --- img/PoliticsStaticModel-fixed.png | Bin 0 -> 37425 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png new file mode 100644 index 0000000000000000000000000000000000000000..298fb078650869ac5ce3ca5811be773046c7708f GIT binary patch literal 37425 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 z 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 z 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 BpOF9n literal 0 HcmV?d00001 From e958b8e826e55bf13bfbb0e713e2890cc4d2638d Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sun, 30 Aug 2020 17:08:16 +0800 Subject: [PATCH 18/38] Delete PoliticsStaticModel-fixed.png --- img/PoliticsStaticModel-fixed.png | Bin 37425 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png deleted file mode 100644 index 298fb078650869ac5ce3ca5811be773046c7708f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37425 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 z 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 z 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 BpOF9n From f1c0e5c1949042388fffe7fd9555fd4ad939f0da Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sun, 30 Aug 2020 17:09:42 +0800 Subject: [PATCH 19/38] Add files via upload --- img/PoliticsStaticModel-fixed.png | Bin 0 -> 37425 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/PoliticsStaticModel-fixed.png diff --git a/img/PoliticsStaticModel-fixed.png b/img/PoliticsStaticModel-fixed.png new file mode 100644 index 0000000000000000000000000000000000000000..298fb078650869ac5ce3ca5811be773046c7708f GIT binary patch literal 37425 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 z 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 z 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 BpOF9n literal 0 HcmV?d00001 From 2ad187955647eb9f36e588db0e37dfa5c147273e Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Mon, 31 Aug 2020 04:23:39 +0800 Subject: [PATCH 20/38] Update Politic Party --- CustomData/PartyInterestData.cs | 59 ++++++------------- ...esidentAICitizenUnitSimulationStepPatch.cs | 4 +- RealCity.csproj | 2 + RealCityEconomyExtension.cs | 49 ++++++++------- Util/ArrayExtension.cs | 36 +++++++++++ Util/Politic/BillFactory.cs | 22 +++++++ Util/Politic/Party.cs | 6 +- Util/Politics.cs | 42 ++++++++----- 8 files changed, 137 insertions(+), 83 deletions(-) create mode 100644 Util/ArrayExtension.cs create mode 100644 Util/Politic/BillFactory.cs diff --git a/CustomData/PartyInterestData.cs b/CustomData/PartyInterestData.cs index bcdf336..0721f39 100644 --- a/CustomData/PartyInterestData.cs +++ b/CustomData/PartyInterestData.cs @@ -1,4 +1,5 @@ using RealCity.Attributes; +using RealCity.Util; using System; namespace RealCity.CustomData @@ -13,57 +14,31 @@ public class PartyInterestData private static byte FamilyMoneyNum { get; } = 3; private static byte AgeNum { get; } = 3; private static byte GenderNum { get; } = 2; - [ArrayLength(4)] public ushort[] EducationLevel { get; private set; } - [ArrayLength(15)] public ushort[] SubService { get; private set; } - [ArrayLength(3)] public ushort[] FamilyMoney { get; private set; } - [ArrayLength(3)] public ushort[] Age { get; private set; } - [ArrayLength(2)] public ushort[] Gender { get; private set; } + [ArrayLength(4)] public byte[] EducationLevel { get; private set; } + [ArrayLength(15)] public byte[] SubService { get; private set; } + [ArrayLength(3)] public byte[] FamilyMoney { get; private set; } + [ArrayLength(3)] public byte[] Age { get; private set; } + [ArrayLength(2)] public byte[] Gender { get; private set; } ///

/// 政党兴趣度数据 /// - /// 长度为4的ushort[],代表4个学历 - /// 长度为15的ushort[],代表15种行业 - /// 长度为3的ushort[],代表3种家庭富裕程度 - /// 长度为3的ushort[],代表3种(有投票权的)年龄阶段 - /// 长度为2的ushort[],代表2种性别 - public PartyInterestData(ushort[] edu, ushort[] service, ushort[] familyMoney, ushort[] age, ushort[] gender) { - edu = EnsureDataLength(edu, EducationLevelNum); - service = EnsureDataLength(service, SubServiceNum); - familyMoney = EnsureDataLength(familyMoney, FamilyMoneyNum); - age = EnsureDataLength(age, AgeNum); - gender = EnsureDataLength(gender, GenderNum); + /// 长度为4的数组,代表4个学历 + /// 长度为15的数组,代表15种行业 + /// 长度为3的数组,代表3种家庭富裕程度 + /// 长度为3的数组,代表3种(有投票权的)年龄阶段 + /// 长度为2的数组,代表2种性别 + public PartyInterestData(byte[] edu, byte[] service, byte[] familyMoney, byte[] age, byte[] gender) { + edu = edu.EnsureLength(EducationLevelNum); + service = service.EnsureLength(SubServiceNum); + familyMoney = familyMoney.EnsureLength(FamilyMoneyNum); + age = age.EnsureLength(AgeNum); + gender = gender.EnsureLength(GenderNum); this.EducationLevel = edu; this.SubService = service; this.FamilyMoney = familyMoney; this.Age = age; this.Gender = gender; } - - /// - /// 修正数据长度 - /// - /// - /// - /// - private static ushort[] EnsureDataLength(ushort[] data, byte expectedLength) { - if (data.Length != expectedLength) { - ushort[] correctData = new ushort[expectedLength]; - if (data.Length < expectedLength) { - // expected: 5 3 4 5 - // actually: 5 3 4 _ - Array.Copy(data, correctData, data.Length); - // fill the remaining part - for (int i = data.Length; i < expectedLength; ++i) { - data[i] = default; - } - } else { - // throw the useless part - Array.Copy(data, correctData, expectedLength); - } - return correctData; - } - return data; - } } } \ No newline at end of file diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index 27fdf5a..9fd81b2 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -401,7 +401,7 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { if (Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age)) && Politics.IsOnElection()) { - Politics.OnELection(); + Politics.ResetWinChance(); Politics.Parties.ForEach(p => { PartyInterestCalc interestCalc = new PartyInterestCalc(p, ref citizen, citizenID, homeID); interestCalc.Calc(); @@ -532,6 +532,8 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { DebugLog.LogToFileOnly($"Error: GetVoteChance Invalid partyTrend = {RealCityEconomyExtension.partyTrend}"); } + + GetVoteTickets(); } } diff --git a/RealCity.csproj b/RealCity.csproj index 560edc4..cba01ae 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -94,7 +94,9 @@ + + diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 2a10aff..775f9b4 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -234,7 +234,8 @@ public byte ReturnOtherIdx(byte orgIdx) { } public void HoldMeeting() { - int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + //int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + int temp = Politics.GetAllSeatCount(); if (temp == 99) { System.Random rand = new System.Random(); switch (rand.Next(8)) { @@ -392,23 +393,24 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, commercialLackMoneyCount = 0; } - public void VoteResult(int idex) { - int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + public void VoteResult(int billId) { + //int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + int seatCount = Politics.GetAllSeatCount(); int yes = 0; int no = 0; int noAttend = 0; int residentTax = 10 - (Politics.residentTax); - int benefitOffset = 10 - (Politics.benefitOffset / 5); int commercialTax = 10 - (Politics.commercialTax); int industryTax = 10 - (Politics.industryTax); + int benefitOffset = 10 - (Politics.benefitOffset / 5); int moneyOffset = 0; // money offset int citizenOffset = 0; // citizen offset int industrialBuildingOffset = 0; //industrial building offset int commercialBuildingOffset = 0; //commercial building offset - VoteOffset(ref idex, ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); + VoteOffset(ref billId, ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); - if (temp == 99) { - switch (idex) { + if (seatCount == 99) { + switch (billId) { case 0: yes += Politics.cPartySeats * (Politics.riseSalaryTax[0, 0] + residentTax); yes += Politics.gPartySeats * (Politics.riseSalaryTax[1, 0] + residentTax); @@ -595,8 +597,9 @@ public void VoteResult(int idex) { Politics.currentNo = (byte)no; Politics.currentNoAttend = (byte)noAttend; + // if bill is passed if (Politics.currentYes >= 50) { - switch (idex) { + switch (billId) { case 0: Politics.residentTax += 1; break; @@ -716,13 +719,14 @@ public void CreateGoverment() { /// public void GetSeats() { //总票数 - int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; - if (allTickets != 0) { - Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / allTickets); - Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / allTickets); - Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / allTickets); - Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / allTickets); - Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / allTickets); + //int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; + int cnt = Politics.GetAllTicket(); + if (cnt != 0) { + Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / cnt); + Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / cnt); + Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / cnt); + Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / cnt); + Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / cnt); } else { Politics.cPartySeats = 0; Politics.gPartySeats = 0; @@ -736,20 +740,21 @@ public void GetSeats() { Politics.lPartyTickets = 0; Politics.nPartyTickets = 0; - allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; - if (allTickets < 99) { + //allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + cnt = Politics.GetAllSeatCount(); + if (cnt < 99) { System.Random rand = new System.Random(); switch (rand.Next(5)) { case 0: - Politics.cPartySeats += (ushort)(99 - allTickets); break; + Politics.cPartySeats += (ushort)(99 - cnt); break; case 1: - Politics.gPartySeats += (ushort)(99 - allTickets); break; + Politics.gPartySeats += (ushort)(99 - cnt); break; case 2: - Politics.sPartySeats += (ushort)(99 - allTickets); break; + Politics.sPartySeats += (ushort)(99 - cnt); break; case 3: - Politics.lPartySeats += (ushort)(99 - allTickets); break; + Politics.lPartySeats += (ushort)(99 - cnt); break; case 4: - Politics.nPartySeats += (ushort)(99 - allTickets); break; + Politics.nPartySeats += (ushort)(99 - cnt); break; } } } diff --git a/Util/ArrayExtension.cs b/Util/ArrayExtension.cs new file mode 100644 index 0000000..83b9edc --- /dev/null +++ b/Util/ArrayExtension.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace RealCity.Util +{ + public static class ArrayExtension + { + /// + /// 修正数据长度 + /// + /// + /// + /// + public static T[] EnsureLength(this T[] arr, int expectedLength) { + if (arr.Length != expectedLength) { + T[] correctData = new T[expectedLength]; + if (arr.Length < expectedLength) { + // expected: 5 3 4 5 + // actually: 5 3 4 _ + Array.Copy(arr, correctData, arr.Length); + // fill the remaining part + for (int i = arr.Length; i < expectedLength; ++i) { + correctData[i] = default; + } + } else { + // throw the useless part + Array.Copy(arr, correctData, expectedLength); + } + return correctData; + } + return arr; + } + } +} diff --git a/Util/Politic/BillFactory.cs b/Util/Politic/BillFactory.cs new file mode 100644 index 0000000..d0a53fb --- /dev/null +++ b/Util/Politic/BillFactory.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace RealCity.Util.Politic +{ + public class BillFactory + { + public static IBill RaiseResidentTax = new Bill(() => Politics.residentTax++); + public static IBill ReduceResidentTax = new Bill(() => Politics.residentTax--); + public static IBill RaiseCommercialTax = new Bill(() => Politics.commercialTax++); + public static IBill ReduceCommercialTax = new Bill(() => Politics.commercialTax--); + public static IBill RaiseIndustryTax = new Bill(() => Politics.industryTax++); + public static IBill ReduceIndustryTax = new Bill(() => Politics.industryTax--); + public static IBill RaiseBenefitOffset = new Bill(() => Politics.benefitOffset += 10); + public static IBill ReduceBenefitOffset = new Bill(() => Politics.benefitOffset -= 10); + IBill GetAnotherBill(IBill currentBill) { + + } + } +} \ No newline at end of file diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index 23cb935..4c2c63d 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -11,14 +11,14 @@ public class Party : IParty // maybe some customized Bill in parliament here private PartyInterestData interestData; - private List bills; + private Dictionary billInterestData; public ushort WinChance { get; private set; } = default; public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; - public Party(PartyInterestData interestData, List bills) { + public Party(PartyInterestData interestData, Dictionary billInterestData) { this.interestData = interestData; - this.bills = bills; + this.billInterestData = billInterestData; } public void AddWinChance(ushort val) { diff --git a/Util/Politics.cs b/Util/Politics.cs index 9e1821e..36b223e 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -4,6 +4,7 @@ using RealCity.Util.Politic; using System; using System.Collections.Generic; +using System.Linq; namespace RealCity.Util { @@ -74,10 +75,34 @@ public class Politics { } ); + private const Citizen.AgeGroup VotingAge = Citizen.AgeGroup.Young; public static IParty[] Parties => new IParty[] { cParty, gParty, sParty, lParty, nParty }; - public static void OnELection() { + public static void ResetWinChance() { Parties.ForEach(p => p.ResetWinChance()); } + public static int GetAllSeatCount() { + return Parties.Sum(p => { + return p.SeatCount; + }); + } + public static int GetAllTicket() { + return Parties.Sum(p => { + return p.Ticket; + }); + } + public static bool IsOnElection() { + return nextElectionInterval == 1; + } + + /// + /// 是否达到最低投票年龄 + /// + /// + /// + public static bool IsOverVotingAge(Citizen.AgeGroup age) { + //这地方不一定能解耦合...政治就是和人相关的嘛... + return age >= VotingAge; + } //学历对选举投票的影响因子 public static byte[,] education = { {30, 0, 10, 10, 50}, @@ -122,6 +147,7 @@ public static void OnELection() { { 5, 15, 40, 35, 5}}; + //5个政党对一项议案的赞成度 //riseSalaryTax public static byte[,] riseSalaryTax = { {55, 40, 5}, @@ -195,7 +221,6 @@ public static void OnELection() { {70, 30, 0}, }; - private const Citizen.AgeGroup VotingAge = Citizen.AgeGroup.Young; public static ushort cPartyChance = 0; public static ushort gPartyChance = 0; @@ -245,19 +270,6 @@ public static void OnELection() { //社会福利(0-100) public static short benefitOffset = 0; - public static bool IsOnElection() { - return nextElectionInterval == 1; - } - - /// - /// 是否达到最低投票年龄 - /// - /// - /// - public static bool IsOverVotingAge(Citizen.AgeGroup age) { - //这地方不一定能解耦合...政治就是和人相关的嘛... - return age >= VotingAge; - } public static void Save(ref byte[] saveData) { //58 From bf2643afd070d97205480163de6d9a7574db409e Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Mon, 31 Aug 2020 17:25:43 +0800 Subject: [PATCH 21/38] Parliament meeting, Add Party factory --- CustomData/CitizenData.cs | 6 +- Loader.cs | 1 + ...esidentAICitizenUnitSimulationStepPatch.cs | 2 +- RealCity.csproj | 5 +- RealCityEconomyExtension.cs | 45 ++++- Util/ArrayExtension.cs | 4 +- Util/Politic/Bill.cs | 22 ++- Util/Politic/{BillFactory.cs => Bills.cs} | 15 +- Util/Politic/IBill.cs | 4 +- Util/Politic/IParty.cs | 2 + Util/Politic/Party.cs | 28 ++- Util/Politic/PartyFactory.cs | 181 ++++++++++++++++++ Util/Politic/PartyInterestCalc.cs | 4 +- Util/Politic/Vote.cs | 13 ++ Util/Politic/VoteResult.cs | 32 ++++ Util/Politics.cs | 128 +++++-------- 16 files changed, 379 insertions(+), 113 deletions(-) rename Util/Politic/{BillFactory.cs => Bills.cs} (93%) create mode 100644 Util/Politic/PartyFactory.cs create mode 100644 Util/Politic/Vote.cs create mode 100644 Util/Politic/VoteResult.cs diff --git a/CustomData/CitizenData.cs b/CustomData/CitizenData.cs index e4d5a2f..2759767 100644 --- a/CustomData/CitizenData.cs +++ b/CustomData/CitizenData.cs @@ -26,14 +26,14 @@ public static uint GetCitizenUnit(ushort buildingId) { return 0u; } - public void DataInit() { + public void DataInit() { //for (int i = 0; i < citizenMoney.Length; i++) { // citizenMoney[i] = 0f; //} this.citizenMoney.Initialize(); } - public void Save(ref byte[] saveData) { + public void Save(ref byte[] saveData) { //4194304 int i = 0; SaveAndRestore.SaveData(ref i, citizenMoney, ref saveData); @@ -43,7 +43,7 @@ public void Save(ref byte[] saveData) { } } - public void Load(ref byte[] saveData) { + public void Load(ref byte[] saveData) { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref citizenMoney); diff --git a/Loader.cs b/Loader.cs index 161088f..48fc9d5 100644 --- a/Loader.cs +++ b/Loader.cs @@ -80,6 +80,7 @@ public override void OnLevelLoaded(LoadMode mode) { public static void InitData() { DebugLog.LogToFileOnly("InitData"); + Politics.DataInit(); TransportLineData.DataInit(); VehicleData.DataInit(); BuildingData.DataInit(); diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index 9fd81b2..ac24ed5 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -397,7 +397,7 @@ public static void GetVoteTickets() { } public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { - //达到最低投票年龄,而且即将选举 if (elder than Vote Age) and (gonna be election) + //达到最低投票年龄,而且即将选举 if (over Voting Age) and (gonna be election) if (Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age)) && Politics.IsOnElection()) { diff --git a/RealCity.csproj b/RealCity.csproj index cba01ae..5595eb3 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -96,8 +96,9 @@ - + + @@ -198,6 +199,8 @@ + +
diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 775f9b4..76333c4 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -1,8 +1,11 @@ using ColossalFramework; +using ColossalFramework.UI; using ICities; using RealCity.CustomManager; using RealCity.UI; using RealCity.Util; +using RealCity.Util.Politic; +using System.Linq; using System.Reflection; using UnityEngine; @@ -409,9 +412,47 @@ public void VoteResult(int billId) { int commercialBuildingOffset = 0; //commercial building offset VoteOffset(ref billId, ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); + IBill bill = default; + if (seatCount == 99) { - switch (billId) { - case 0: + yes += Politics.Parties.Sum(p => { + // + return p.GetBillAttitude()[bill].Agree; + }); + yes += (Politics.Parties.Length * residentTax - moneyOffset -citizenOffset); + + no += Politics.Parties.Sum(p => { + return p.GetBillAttitude()[bill].Disagree; + }); + no -= Politics.Parties.Length * residentTax; + + noAttend += Politics.Parties.Sum(p => { + return p.GetBillAttitude()[bill].NoVote; + }); + noAttend -= Politics.Parties.Length * residentTax; + } + + if (seatCount == 99) { + switch (bill) { + case Bills.RaiseResidentTax: + yes += Politics.Parties.Sum(p => { + // + return p.GetBillAttitude()[bill][0]; + }); + yes += (Politics.Parties.Length * residentTax; + + no += Politics.Parties.Sum(p => { + return p.GetBillAttitude()[bill][1]; + }); + no -= Politics.Parties.Length * residentTax; + + noAttend += Politics.Parties.Sum(p => { + return p.GetBillAttitude()[bill][2]; + }); + noAttend -= Politics.Parties.Length * residentTax; + break; + + yes += Politics.cPartySeats * (Politics.riseSalaryTax[0, 0] + residentTax); yes += Politics.gPartySeats * (Politics.riseSalaryTax[1, 0] + residentTax); yes += Politics.sPartySeats * (Politics.riseSalaryTax[2, 0] + residentTax); diff --git a/Util/ArrayExtension.cs b/Util/ArrayExtension.cs index 83b9edc..4548b95 100644 --- a/Util/ArrayExtension.cs +++ b/Util/ArrayExtension.cs @@ -8,9 +8,9 @@ namespace RealCity.Util public static class ArrayExtension { /// - /// 修正数据长度 + /// 修正数组长度 /// - /// + /// /// /// public static T[] EnsureLength(this T[] arr, int expectedLength) { diff --git a/Util/Politic/Bill.cs b/Util/Politic/Bill.cs index 0e8d8ed..af41e37 100644 --- a/Util/Politic/Bill.cs +++ b/Util/Politic/Bill.cs @@ -2,14 +2,30 @@ namespace RealCity.Util.Politic { + /// + /// 议案 + /// public class Bill : IBill { - private Action billContent; + private Action content; + + /// + /// 议案 + /// + /// 议案内容 public Bill(Action content) { - this.billContent = content; + //Bill就像一个抽象类,它并不知道content是什么,只管调用就行 + this.content = content; } + public void Implement() { - this.billContent.Invoke(); + this.content.Invoke(); + } + public static bool operator ==(Bill a, Bill b) { + return a.content == b.content; + } + public static bool operator !=(Bill a, Bill b) { + return !(a == b); } } } \ No newline at end of file diff --git a/Util/Politic/BillFactory.cs b/Util/Politic/Bills.cs similarity index 93% rename from Util/Politic/BillFactory.cs rename to Util/Politic/Bills.cs index d0a53fb..c26c70f 100644 --- a/Util/Politic/BillFactory.cs +++ b/Util/Politic/Bills.cs @@ -5,18 +5,25 @@ namespace RealCity.Util.Politic { - public class BillFactory + public class Bills { public static IBill RaiseResidentTax = new Bill(() => Politics.residentTax++); - public static IBill ReduceResidentTax = new Bill(() => Politics.residentTax--); public static IBill RaiseCommercialTax = new Bill(() => Politics.commercialTax++); - public static IBill ReduceCommercialTax = new Bill(() => Politics.commercialTax--); public static IBill RaiseIndustryTax = new Bill(() => Politics.industryTax++); - public static IBill ReduceIndustryTax = new Bill(() => Politics.industryTax--); public static IBill RaiseBenefitOffset = new Bill(() => Politics.benefitOffset += 10); + + public static IBill ReduceResidentTax = new Bill(() => Politics.residentTax--); + public static IBill ReduceCommercialTax = new Bill(() => Politics.commercialTax--); + public static IBill ReduceIndustryTax = new Bill(() => Politics.industryTax--); public static IBill ReduceBenefitOffset = new Bill(() => Politics.benefitOffset -= 10); + + //这里需要null object吗 ? + + + IBill GetAnotherBill(IBill currentBill) { } + } } \ No newline at end of file diff --git a/Util/Politic/IBill.cs b/Util/Politic/IBill.cs index 32e1472..125ffc6 100644 --- a/Util/Politic/IBill.cs +++ b/Util/Politic/IBill.cs @@ -1,4 +1,6 @@ -namespace RealCity.Util.Politic +using System; + +namespace RealCity.Util.Politic { public interface IBill { diff --git a/Util/Politic/IParty.cs b/Util/Politic/IParty.cs index 22cbf05..3ef9957 100644 --- a/Util/Politic/IParty.cs +++ b/Util/Politic/IParty.cs @@ -1,10 +1,12 @@ using RealCity.CustomData; +using System.Collections.Generic; namespace RealCity.Util.Politic { public interface IParty { PartyInterestData GetPartyInterestData(); + Dictionary GetBillAttitude(); void AddWinChance(ushort val); void ResetWinChance(); ushort WinChance { get; } diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index 4c2c63d..a1be933 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -6,29 +6,39 @@ namespace RealCity.Util.Politic { + /// + /// 政党 + /// public class Party : IParty { - // maybe some customized Bill in parliament here - private PartyInterestData interestData; - private Dictionary billInterestData; + private Dictionary billAttitude; public ushort WinChance { get; private set; } = default; public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; - public Party(PartyInterestData interestData, Dictionary billInterestData) { + /// + /// 政党 + /// + /// 民众对政党的兴趣度 + /// 政党对政策的态度 + public Party(PartyInterestData interestData, Dictionary billAttitude) { this.interestData = interestData; - this.billInterestData = billInterestData; - } - - public void AddWinChance(ushort val) { - this.WinChance += val; + this.billAttitude = billAttitude; } public PartyInterestData GetPartyInterestData() { return this.interestData; } + public Dictionary GetBillAttitude() { + return this.billAttitude; + } + + public void AddWinChance(ushort val) { + this.WinChance += val; + } + public void ResetWinChance() { this.WinChance = default; } diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs new file mode 100644 index 0000000..376a7d5 --- /dev/null +++ b/Util/Politic/PartyFactory.cs @@ -0,0 +1,181 @@ +using RealCity.CustomData; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace RealCity.Util.Politic +{ + /// + /// 政党工厂 + /// + public class PartyFactory + { + //TODO: Too much similar codes, need merge 'em + + public IParty MakeCParty() { + var billAttitudeMap = new Dictionary(); + VoteResult raiseResidentTax = new VoteResult(55, 40, 5); + VoteResult reduceResidentTax = new VoteResult(40, 55, 5); + VoteResult raiseCommercialTax = new VoteResult(80, 20, 0); + VoteResult reduceCommercialTax = new VoteResult(20, 80, 0); + VoteResult raiseIndustryTax = new VoteResult(20, 70, 10); + VoteResult reduceIndustryTax = new VoteResult(70, 20, 10); + VoteResult raiseBenefitOffset = new VoteResult(40, 50, 10); + VoteResult reduceBenefitOffset = new VoteResult(50, 40, 10); + + billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); + billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); + billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); + billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); + + IParty party = new Party( + new PartyInterestData( + new byte[4] { 30, 20, 10, 5 }, + new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, + new byte[3] { 35, 10, 0 }, + new byte[3] { 15, 10, 5 }, + new byte[2] { 10, 5 } + ), + billAttitudeMap + ); + return party; + } + + public IParty MakeGParty() { + var billAttitudeMap = new Dictionary(); + VoteResult raiseResidentTax = new VoteResult(10, 80, 10); + VoteResult reduceResidentTax = new VoteResult(80, 10, 10); + VoteResult raiseCommercialTax = new VoteResult(40, 50, 10); + VoteResult reduceCommercialTax = new VoteResult(50, 40, 10); + VoteResult raiseIndustryTax = new VoteResult(50, 50, 0); + VoteResult reduceIndustryTax = new VoteResult(50, 50, 0); + VoteResult raiseBenefitOffset = new VoteResult(70, 20, 10); + VoteResult reduceBenefitOffset = new VoteResult(20, 70, 10); + + billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); + billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); + billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); + billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); + + IParty party = new Party( + new PartyInterestData( + new byte[4] { 0, 10, 20, 25 }, + new byte[15] { 0, 20, 10, 15, 20, 30, 10, 0, 5, 10, 5, 30, 35, 40, 50, }, + new byte[3] { 0, 10, 30 }, + new byte[3] { 20, 15, 10 }, + new byte[2] { 10, 15 } + ), + billAttitudeMap + ); + return party; + } + + public IParty MakeSParty() { + var billAttitudeMap = new Dictionary(); + VoteResult raiseResidentTax = new VoteResult(30, 70, 0); + VoteResult reduceResidentTax = new VoteResult(70, 30, 0); + VoteResult raiseCommercialTax = new VoteResult(55, 40, 5); + VoteResult reduceCommercialTax = new VoteResult(40, 55, 5); + VoteResult raiseIndustryTax = new VoteResult(60, 30, 10); + VoteResult reduceIndustryTax = new VoteResult(30, 60, 10); + VoteResult raiseBenefitOffset = new VoteResult(90, 10, 0); + VoteResult reduceBenefitOffset = new VoteResult(10, 90, 0); + + billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); + billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); + billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); + billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); + + IParty party = new Party( + new PartyInterestData( + new byte[4] { 10, 25, 30, 40 }, + new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, + new byte[3] { 25, 35, 15 }, + new byte[3] { 30, 25, 20 }, + new byte[2] { 35, 40 } + ), + billAttitudeMap + ); + return party; + } + + public IParty MakeLParty() { + var billAttitudeMap = new Dictionary(); + VoteResult raiseResidentTax = new VoteResult(70, 30, 0); + VoteResult reduceResidentTax = new VoteResult(30, 70, 0); + VoteResult raiseCommercialTax = new VoteResult(10, 90, 0); + VoteResult reduceCommercialTax = new VoteResult(90, 10, 0); + VoteResult raiseIndustryTax = new VoteResult(70, 30, 0); + VoteResult reduceIndustryTax = new VoteResult(30, 70, 0); + VoteResult raiseBenefitOffset = new VoteResult(10, 90, 0); + VoteResult reduceBenefitOffset = new VoteResult(90, 10, 0); + + billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); + billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); + billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); + billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); + + IParty party = new Party( + new PartyInterestData( + new byte[4] { 10, 20, 30, 25 }, + new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, + new byte[3] { 10, 35, 40 }, + new byte[3] { 20, 30, 40 }, + new byte[2] { 35, 35 } + ), + billAttitudeMap + ); + return party; + } + + public IParty MakeNParty() { + var billAttitudeMap = new Dictionary(); + VoteResult raiseResidentTax = new VoteResult(35, 55, 10); + VoteResult reduceResidentTax = new VoteResult(55, 35, 10); + VoteResult raiseCommercialTax = new VoteResult(45, 45, 100); + VoteResult reduceCommercialTax = new VoteResult(45, 45, 10); + VoteResult raiseIndustryTax = new VoteResult(30, 70, 0); + VoteResult reduceIndustryTax = new VoteResult(70, 30, 0); + VoteResult raiseBenefitOffset = new VoteResult(30, 60, 10); + VoteResult reduceBenefitOffset = new VoteResult(60, 30, 10); + + billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); + billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); + billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); + billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); + + IParty party = new Party( + new PartyInterestData( + new byte[4] { 50, 25, 10, 5 }, + new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, + new byte[3] { 30, 10, 15 }, + new byte[3] { 15, 20, 25 }, + new byte[2] { 10, 5 } + ), + billAttitudeMap + ); + return party; + } + } +} diff --git a/Util/Politic/PartyInterestCalc.cs b/Util/Politic/PartyInterestCalc.cs index 1507bc9..1a44895 100644 --- a/Util/Politic/PartyInterestCalc.cs +++ b/Util/Politic/PartyInterestCalc.cs @@ -7,7 +7,7 @@ namespace RealCity.Util.Politic /// /// 政党兴趣度计算 /// - class PartyInterestCalc + public class PartyInterestCalc { private IParty party; private PartyInterestData partyInterestData; @@ -49,7 +49,7 @@ public void Calc() { public void AddPartyWinChance() { this.party.AddWinChance(this.val); //啊这...不加会出bug吗 - //this.val = 0; + this.val = default; } /// diff --git a/Util/Politic/Vote.cs b/Util/Politic/Vote.cs new file mode 100644 index 0000000..968c105 --- /dev/null +++ b/Util/Politic/Vote.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace RealCity.Util.Politic +{ + public class Vote + { + private IBill bill; + private IParty[] parties; + } +} diff --git a/Util/Politic/VoteResult.cs b/Util/Politic/VoteResult.cs new file mode 100644 index 0000000..d9399b2 --- /dev/null +++ b/Util/Politic/VoteResult.cs @@ -0,0 +1,32 @@ +namespace RealCity.Util.Politic +{ + /// + /// 投票结果 + /// + public class VoteResult + { + /// + /// 同意 + /// + public byte Agree { get; } + /// + /// 反对 + /// + public byte Disagree { get; } + /// + /// 弃权 + /// + public byte NoVote { get; } + /// + /// 投票结果 + /// + /// 同意 + /// 反对 + /// 弃权 + public VoteResult(byte agree, byte disagree, byte noVote) { + this.Agree = agree; + this.Disagree = disagree; + this.NoVote = noVote; + } + } +} diff --git a/Util/Politics.cs b/Util/Politics.cs index 36b223e..133821c 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -9,71 +9,11 @@ namespace RealCity.Util { public class Politics { - private static IParty cParty = new Party( - new PartyInterestData( - new ushort[4] { 30, 20, 10, 5 }, - new ushort[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, - new ushort[3] { 35, 10, 0 }, - new ushort[3] { 15, 10, 5 }, - new ushort[2] { 10, 5 } - ), - new List() { - new Bill(()=>{ }), - new Bill(()=>{ }) - } - ); - private static IParty gParty = new Party( - new PartyInterestData( - new ushort[4] { 0, 10, 20, 25 }, - new ushort[15] { 0, 20, 10, 15, 20, 30, 10, 0, 5, 10, 5, 30, 35, 40, 50, }, - new ushort[3] { 0, 10, 30 }, - new ushort[3] { 20, 15, 10 }, - new ushort[2] { 10, 15 } - ), - new List() { - new Bill(()=>{ }), - new Bill(()=>{ }) - } - ); - private static IParty sParty = new Party( - new PartyInterestData( - new ushort[4] { 10, 25, 30, 40 }, - new ushort[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, - new ushort[3] { 25, 35, 15 }, - new ushort[3] { 30, 25, 20 }, - new ushort[2] { 35, 40 } - ), - new List() { - new Bill(()=>{ }), - new Bill(()=>{ }) - } - ); - private static IParty lParty = new Party( - new PartyInterestData( - new ushort[4] { 10, 20, 30, 25 }, - new ushort[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, - new ushort[3] { 10, 35, 40 }, - new ushort[3] { 20, 30, 40 }, - new ushort[2] { 35, 35 } - ), - new List() { - new Bill(()=>{ }), - new Bill(()=>{ }) - } - ); - private static IParty nParty = new Party( - new PartyInterestData( - new ushort[4] { 50, 25, 10, 5 }, - new ushort[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, - new ushort[3] { 30, 10, 15 }, - new ushort[3] { 15, 20, 25 }, - new ushort[2] { 10, 5 } - ), - new List() { - new Bill(()=>{ }), - new Bill(()=>{ }) - } - ); + private static IParty cParty; + private static IParty gParty; + private static IParty sParty; + private static IParty lParty; + private static IParty nParty; private const Citizen.AgeGroup VotingAge = Citizen.AgeGroup.Young; public static IParty[] Parties => new IParty[] { cParty, gParty, sParty, lParty, nParty }; @@ -104,6 +44,15 @@ public static bool IsOverVotingAge(Citizen.AgeGroup age) { return age >= VotingAge; } + /// + /// 是否达到最低投票年龄 + /// + /// + /// + public static bool IsOverVotingAge(ref Citizen citizen) { + return IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age)); + } + //学历对选举投票的影响因子 public static byte[,] education = { {30, 0, 10, 10, 50}, {20, 10, 25, 20, 25}, @@ -184,24 +133,6 @@ public static bool IsOverVotingAge(Citizen.AgeGroup age) { {45, 45, 10}, }; - //riseBenefit - public static byte[,] riseBenefit = { - {40, 50, 10}, - {70, 20, 10}, - {90, 10, 0}, - {10, 90, 0}, - {30, 60, 10}, - }; - - //fallBenefit - public static byte[,] fallBenefit = { - {50, 40, 10}, - {20, 70, 10}, - {10, 90, 0}, - {90, 10, 0}, - {60, 30, 10}, - }; - //riseIndustryTax public static byte[,] riseIndustryTax = { @@ -221,6 +152,24 @@ public static bool IsOverVotingAge(Citizen.AgeGroup age) { {70, 30, 0}, }; + //riseBenefit + public static byte[,] riseBenefit = { + {40, 50, 10}, + {70, 20, 10}, + {90, 10, 0}, + {10, 90, 0}, + {30, 60, 10}, + }; + + //fallBenefit + public static byte[,] fallBenefit = { + {50, 40, 10}, + {20, 70, 10}, + {10, 90, 0}, + {90, 10, 0}, + {60, 30, 10}, + }; + public static ushort cPartyChance = 0; public static ushort gPartyChance = 0; @@ -240,7 +189,7 @@ public static bool IsOverVotingAge(Citizen.AgeGroup age) { public static ushort lPartySeats = 0; public static ushort nPartySeats = 0; - //下一届选举倒计时 + //下一次_____倒计时 public static short nextElectionInterval = 0; public static bool case1 = false; @@ -269,7 +218,16 @@ public static bool IsOverVotingAge(Citizen.AgeGroup age) { public static int industryTax = 20; //社会福利(0-100) public static short benefitOffset = 0; - + + + public static void DataInit() { + PartyFactory factory = new PartyFactory(); + cParty = factory.MakeCParty(); + gParty = factory.MakeGParty(); + sParty = factory.MakeSParty(); + lParty = factory.MakeLParty(); + nParty = factory.MakeNParty(); + } public static void Save(ref byte[] saveData) { //58 From 4478335073bdb23af9606e143f04fb115735ba54 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Mon, 31 Aug 2020 20:32:08 +0800 Subject: [PATCH 22/38] Update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6f44aeb..f7ca3d9 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ # RealCity -Cities: Skylines Mod by [@pcfantasy](https://github.com/pcfantasy).

-Make your city act like a real world! Combine CS and Simcity in game playing!

+Cities: Skylines Mod by [@pcfantasy](https://github.com/pcfantasy). +Make your city act like a real world! Combine CS and Simcity in game playing! ## Download -It's available on Steam Workshop, but the game comtent may be somehow different from this repo.

-[![Steam Workshop](https://img.shields.io/steam/downloads/1192503086.svg?label=Steam%20Workshop&logo=steam)](https://steamcommunity.com/sharedfiles/filedetails/?id=1192503086)

+[![Steam Workshop](https://img.shields.io/steam/downloads/1192503086.svg?label=Steam%20Workshop&logo=steam)](https://steamcommunity.com/sharedfiles/filedetails/?id=1192503086) +It's available on Steam Workshop, but the game comtent may be somehow different from this fork. ## Userguide -Mod Wiki in both English and Chinese is available at [here](https://github.com/bac0id/RealCity-master/wiki). Also there are some [game guides](https://github.com/bac0id/RealCity-master/tree/master/%E4%B8%AD%E6%96%87%E6%94%BB%E7%95%A5) written in Chinese.

-[模组Wiki](https://github.com/bac0id/RealCity-master/wiki)有中文和英文版本。这里也有原作者写的一些[攻略](https://github.com/bac0id/RealCity-master/tree/master/%E4%B8%AD%E6%96%87%E6%94%BB%E7%95%A5)。您也可以移步至[原主页](https://github.com/pcfantasy/RealCity)去查阅这些信息。 +Mod Wiki is available at [here \(English and Simplified Chinese\)](https://github.com/bac0id/RealCity-master/wiki). Also there are some [game guides \(Simplified Chinese\)](https://github.com/bac0id/RealCity-master/tree/master/%E4%B8%AD%E6%96%87%E6%94%BB%E7%95%A5) +有中文和英文版本的[模组Wiki](https://github.com/bac0id/RealCity-master/wiki)。这里也有原作者写的一些[攻略](https://github.com/bac0id/RealCity-master/tree/master/%E4%B8%AD%E6%96%87%E6%94%BB%E7%95%A5)。您也可以移步至[原主页](https://github.com/pcfantasy/RealCity)去查阅这些信息。 ## Inter Relationship ![](https://github.com/bac0id/RealCity-master/blob/master/img/RealCityFlow.jpg) ## Support -You can donate something to the author [@pcfantasy](https://github.com/pcfantasy). +You can donate something to the author [@pcfantasy](https://github.com/pcfantasy). +扫码让[原作者](https://github.com/pcfantasy)恰饭 ![](https://github.com/bac0id/RealCity-master/blob/master/%E8%B5%9E%E8%B5%8F%E7%A0%81.jpg) From a1d20327bcb9baa9f9ff0129bfd27331ece47901 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Mon, 31 Aug 2020 20:37:31 +0800 Subject: [PATCH 23/38] Update New Politics --- Attributes/ArrayLengthAttribute.cs | 2 + ...esidentAICitizenUnitSimulationStepPatch.cs | 17 +- RealCity.csproj | 3 +- RealCityEconomyExtension.cs | 3 +- Util/Politic/Election.cs | 72 ++++++++ Util/Politic/PartyFactory.cs | 8 +- Util/Politic/PartyInterestCalc.cs | 9 +- .../Politic}/PartyInterestData.cs | 28 +-- Util/Politic/Vote.cs | 161 ++++++++++++++++++ Util/Politic/VoteResult.cs | 8 +- 10 files changed, 280 insertions(+), 31 deletions(-) create mode 100644 Util/Politic/Election.cs rename {CustomData => Util/Politic}/PartyInterestData.cs (65%) diff --git a/Attributes/ArrayLengthAttribute.cs b/Attributes/ArrayLengthAttribute.cs index 88fe83a..b85a003 100644 --- a/Attributes/ArrayLengthAttribute.cs +++ b/Attributes/ArrayLengthAttribute.cs @@ -5,6 +5,8 @@ namespace RealCity.Attributes [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class ArrayLengthAttribute : Attribute { + //TODO: use ArrayExtension.Ensure() to auto-fix bad arrays + public int MaximumLength { get; } public ArrayLengthAttribute(int maxLength) { this.MaximumLength = maxLength; diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index ac24ed5..cb4a029 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -376,12 +376,16 @@ public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, ou public static void GetVoteTickets() { System.Random rand = new System.Random(); - if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance != (800 + RealCityEconomyExtension.partyTrendStrength)) { + // WTF??? 这里有魔数。800参见PartyInterestCalc.GetFromEducationLevel()中的注释 + if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance + != (800 + RealCityEconomyExtension.partyTrendStrength)) { + //有1/64的机率打印这句话(WTF?) if (rand.Next(64) <= 1) { DebugLog.LogToFileOnly($"Error: GetVoteTickets Chance is not equal 800 {(Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance)}"); } } + //大转盘,政党的chance越大,得票机率就越大 int voteRandom = rand.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; if (voteRandom < Politics.cPartyChance) { Politics.cPartyTickets++; @@ -397,9 +401,9 @@ public static void GetVoteTickets() { } public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { - //达到最低投票年龄,而且即将选举 if (over Voting Age) and (gonna be election) - if (Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age)) - && Politics.IsOnElection()) { + //如果即将选举,而且达到投票年龄 if (gonna be election) and (over Voting Age) + if (Politics.IsOnElection() + && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age))) { Politics.ResetWinChance(); Politics.Parties.ForEach(p => { @@ -408,8 +412,7 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { interestCalc.AddPartyWinChance(); }); - - + #region old politics code ////重置机率 //Politics.cPartyChance = 0; //Politics.gPartyChance = 0; @@ -516,7 +519,7 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { //Politics.sPartyChance += Politics.gender[temp, 2]; //Politics.lPartyChance += Politics.gender[temp, 3]; //Politics.nPartyChance += Politics.gender[temp, 4]; - + #endregion if (RealCityEconomyExtension.partyTrend == 0) { Politics.cPartyChance += RealCityEconomyExtension.partyTrendStrength; diff --git a/RealCity.csproj b/RealCity.csproj index 5595eb3..8cee080 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -97,10 +97,11 @@ + - + diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 76333c4..137ff0c 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -258,7 +258,8 @@ public void HoldMeeting() { Politics.currentBillId = ReturnOtherIdx(6); break; case 7: Politics.currentBillId = ReturnOtherIdx(7); break; - default: Politics.currentBillId = 8; break; + default: + Politics.currentBillId = 8; break; } VoteResult(Politics.currentBillId); } diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs new file mode 100644 index 0000000..ef9dea1 --- /dev/null +++ b/Util/Politic/Election.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace RealCity.Util.Politic +{ + ///

+ /// 选举 + /// + public class Election + { + private Random r = new Random(); + private IParty[] parties; + //得票计数器 + private int[] ticketCounter; + public Election(IParty[] parties) { + if (parties.Length <= 0) + throw new ArgumentException(); + this.parties = parties; + this.ticketCounter = new int[parties.Length]; + } + /// + /// 是否即将选举 + /// + /// + public static bool IsOnElection() { + return Politics.IsOnElection(); + //return Politics.nextElectionInterval == 1; + } + private void CalcPartiesWinChance() { + + } + private void VoteTicket() { + // It's like Roulette Wheel Selection + // 大转盘,政党的WinChance越大,得票机率就越大 + + int i = 0; + int segment = this.parties[0].WinChance; + int vote = r.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; + /* + * [ Party A ][ P.B ][ P.C ] + * ^ vote ^ length is the sum of party.WinChance + * ^ initial Segment + * [ Party A ][ P.B ][ P.C ] + * ^ S move forward, now vote is smaller than SR, which means P.B gets a ticket + */ + + while (i < parties.Length) { + if (vote < segment) { + this.ticketCounter[i]++; + break; + } + segment += parties[++i].WinChance; + } + + #region old codes + //if (vote < Politics.cPartyChance) { + // Politics.cPartyTickets++; + //} else if (vote < Politics.cPartyChance + Politics.gPartyChance) { + // Politics.gPartyTickets++; + //} else if (vote < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) { + // Politics.sPartyTickets++; + //} else if (vote < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) { + // Politics.lPartyTickets++; + //} else { + // Politics.nPartyTickets++; + //} + #endregion + } + } +} diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs index 376a7d5..0aa3577 100644 --- a/Util/Politic/PartyFactory.cs +++ b/Util/Politic/PartyFactory.cs @@ -1,8 +1,4 @@ -using RealCity.CustomData; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; namespace RealCity.Util.Politic { @@ -11,7 +7,7 @@ namespace RealCity.Util.Politic ///
public class PartyFactory { - //TODO: Too much similar codes, need merge 'em + //TODO: Too much similar codes, need extract same parts public IParty MakeCParty() { var billAttitudeMap = new Dictionary(); diff --git a/Util/Politic/PartyInterestCalc.cs b/Util/Politic/PartyInterestCalc.cs index 1a44895..63192b2 100644 --- a/Util/Politic/PartyInterestCalc.cs +++ b/Util/Politic/PartyInterestCalc.cs @@ -58,7 +58,14 @@ public void AddPartyWinChance() { /// /// private ushort GetFromEducationLevel(Citizen.Education education) { - return this.partyInterestData.EducationLevel[(int)education]; + /* + * 根据ResidentAICitizenUnitSimulationStepPatch.GetVoteTickets()方法 + * 似乎所有政党的WinChance加起来应该是800 + * 而同一个类里的GetVoteChance()也曾把Politics.education[i,j]的参数乘2 + * 这地方要问一下作者... + */ + ushort val = (ushort)(this.partyInterestData.EducationLevel[(int)education] << 1); + return val; } /// diff --git a/CustomData/PartyInterestData.cs b/Util/Politic/PartyInterestData.cs similarity index 65% rename from CustomData/PartyInterestData.cs rename to Util/Politic/PartyInterestData.cs index 0721f39..8b69655 100644 --- a/CustomData/PartyInterestData.cs +++ b/Util/Politic/PartyInterestData.cs @@ -2,23 +2,29 @@ using RealCity.Util; using System; -namespace RealCity.CustomData +namespace RealCity.Util.Politic { /// /// 政党兴趣度数据 /// public class PartyInterestData { - private static byte EducationLevelNum { get; } = 4; - private static byte SubServiceNum { get; } = 15; - private static byte FamilyMoneyNum { get; } = 3; - private static byte AgeNum { get; } = 3; - private static byte GenderNum { get; } = 2; - [ArrayLength(4)] public byte[] EducationLevel { get; private set; } - [ArrayLength(15)] public byte[] SubService { get; private set; } - [ArrayLength(3)] public byte[] FamilyMoney { get; private set; } - [ArrayLength(3)] public byte[] Age { get; private set; } - [ArrayLength(2)] public byte[] Gender { get; private set; } + private const byte EducationLevelNum = 4; + private const byte SubServiceNum = 15; + private const byte FamilyMoneyNum = 3; + private const byte AgeNum = 3; + private const byte GenderNum = 2; + + [ArrayLength(4)] + public byte[] EducationLevel { get; private set; } + [ArrayLength(15)] + public byte[] SubService { get; private set; } + [ArrayLength(3)] + public byte[] FamilyMoney { get; private set; } + [ArrayLength(3)] + public byte[] Age { get; private set; } + [ArrayLength(2)] + public byte[] Gender { get; private set; } /// /// 政党兴趣度数据 diff --git a/Util/Politic/Vote.cs b/Util/Politic/Vote.cs index 968c105..9387340 100644 --- a/Util/Politic/Vote.cs +++ b/Util/Politic/Vote.cs @@ -5,9 +5,170 @@ namespace RealCity.Util.Politic { + /// + /// 议会投票 + /// public class Vote { private IBill bill; private IParty[] parties; + + + public Vote(IBill bill) { + this.bill = bill; + } + + //public Vote(IBill bill):this(bill, Politics.Parties) { } + //public Vote(IBill bill, IParty[] parties) { } + + + public VoteResult Calc() { + int agree = default; + int disagree = default; + int noVote = default; + + int residentTax = 10 - (Politics.residentTax); + int commercialTax = 10 - (Politics.commercialTax); + int industryTax = 10 - (Politics.industryTax); + int benefitOffset = 10 - (Politics.benefitOffset / 5); + int moneyOffset = 0; // money offset + int citizenOffset = 0; // citizen offset + int industrialBuildingOffset = 0; //industrial building offset + int commercialBuildingOffset = 0; //commercial building offset + + return new VoteResult(agree, disagree, noVote); + } + + private void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, ref int buildingOffset, ref int commBuildingOffset) { + //MoneyOffset; + MoneyOffset = 0; + FieldInfo cashAmount; + cashAmount = typeof(EconomyManager).GetField("m_cashAmount", BindingFlags.NonPublic | BindingFlags.Instance); + long _cashAmount = (long)cashAmount.GetValue(Singleton.instance); + if (_cashAmount < 0) { + MoneyOffset = -4000; + System.Random rand = new System.Random(); + if (rand.Next(10) < 8) { + switch (rand.Next(15)) { + case 0: + case 1: + case 2: + if (Politics.residentTax < 20) { + idex = 0; + } else if (Politics.benefitOffset > 0) { + idex = 3; + } else if (Politics.industryTax < 20) { + idex = 6; + } else if (Politics.commercialTax < 20) { + idex = 4; + } + break; + case 3: + case 4: + case 5: + if (Politics.benefitOffset > 0) { + idex = 3; + } else if (Politics.industryTax < 20) { + idex = 6; + } else if (Politics.commercialTax < 20) { + idex = 4; + } else if (Politics.residentTax < 20) { + idex = 0; + } + break; + case 6: + case 7: + case 8: + if (Politics.commercialTax < 20) { + idex = 4; + } else if (Politics.benefitOffset > 0) { + idex = 3; + } else if (Politics.industryTax < 20) { + idex = 6; + } else if (Politics.residentTax < 20) { + idex = 0; + } else if (Politics.commercialTax < 20) { + idex = 4; + } + break; + case 9: + case 10: + case 11: + if (Politics.industryTax < 20) { + idex = 6; + } else if (Politics.commercialTax < 20) { + idex = 4; + } else if (Politics.benefitOffset > 0) { + idex = 3; + } else if (Politics.residentTax < 20) { + idex = 0; + } + break; + case 12: + case 13: + case 14: + if (Politics.benefitOffset > 0) { + idex = 3; + } else if (Politics.industryTax < 20) { + idex = 6; + } else if (Politics.residentTax < 20) { + idex = 0; + } else if (Politics.commercialTax < 20) { + idex = 4; + } + break; + } + } + Politics.currentBillId = (byte)idex; + } else if (_cashAmount > 24000000) { + MoneyOffset = 4000; + } else { + MoneyOffset = -4000 + (int)(_cashAmount / 3000); + } + + //citizenOffset + int citizenOffsetBySalary = 0; + if (MainDataStore.familyCount > 0) { + citizenOffsetBySalary = (int)(MainDataStore.citizenSalaryPerFamily - (MainDataStore.citizenSalaryTaxTotal / MainDataStore.familyCount) - MainDataStore.citizenExpensePerFamily); + } + + if (citizenOffsetBySalary < 100) { + citizenOffset = 500; + } else if (citizenOffsetBySalary > 300) { + citizenOffset = -500; + } else { + citizenOffset = 1000 - 5 * citizenOffsetBySalary; + } + + //buildingOffset + buildingOffset = 0; + if (industrialEarnMoneyCount + industrialLackMoneyCount > 0) { + buildingOffset = ((int)(100f * (industrialEarnMoneyCount - industrialLackMoneyCount) / (industrialEarnMoneyCount + industrialLackMoneyCount))) << 4; + if (buildingOffset > 1500) { + buildingOffset = 1500; + } + + if (buildingOffset < -1500) { + buildingOffset = -1500; + } + } + + commBuildingOffset = 0; + if (commercialEarnMoneyCount + commercialLackMoneyCount > 0) { + commBuildingOffset = ((int)(100f * (commercialEarnMoneyCount - commercialLackMoneyCount) / (commercialEarnMoneyCount + commercialLackMoneyCount))) << 4; + if (commBuildingOffset > 1500) { + commBuildingOffset = 1500; + } + + if (commBuildingOffset < -1500) { + commBuildingOffset = -1500; + } + } + + industrialEarnMoneyCount = 0; + industrialLackMoneyCount = 0; + commercialEarnMoneyCount = 0; + commercialLackMoneyCount = 0; + } } } diff --git a/Util/Politic/VoteResult.cs b/Util/Politic/VoteResult.cs index d9399b2..ad5c9f5 100644 --- a/Util/Politic/VoteResult.cs +++ b/Util/Politic/VoteResult.cs @@ -8,22 +8,22 @@ public class VoteResult /// /// 同意 /// - public byte Agree { get; } + public int Agree { get; } /// /// 反对 /// - public byte Disagree { get; } + public int Disagree { get; } /// /// 弃权 /// - public byte NoVote { get; } + public int NoVote { get; } /// /// 投票结果 /// /// 同意 /// 反对 /// 弃权 - public VoteResult(byte agree, byte disagree, byte noVote) { + public VoteResult(int agree, int disagree, int noVote) { this.Agree = agree; this.Disagree = disagree; this.NoVote = noVote; From 373dbbfbf109b068d4d9cb39a821a13b38799268 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Mon, 31 Aug 2020 21:30:42 +0800 Subject: [PATCH 24/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7ca3d9..7bc8c33 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Mod Wiki is available at [here \(English and Simplified Chinese\)](https://githu 有中文和英文版本的[模组Wiki](https://github.com/bac0id/RealCity-master/wiki)。这里也有原作者写的一些[攻略](https://github.com/bac0id/RealCity-master/tree/master/%E4%B8%AD%E6%96%87%E6%94%BB%E7%95%A5)。您也可以移步至[原主页](https://github.com/pcfantasy/RealCity)去查阅这些信息。 ## Inter Relationship ![](https://github.com/bac0id/RealCity-master/blob/master/img/RealCityFlow.jpg) -## Support +## Sponsor You can donate something to the author [@pcfantasy](https://github.com/pcfantasy). 扫码让[原作者](https://github.com/pcfantasy)恰饭 ![](https://github.com/bac0id/RealCity-master/blob/master/%E8%B5%9E%E8%B5%8F%E7%A0%81.jpg) From 2d62124c709bf82cf3c40c1892f0fd7c55cea716 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Tue, 1 Sep 2020 19:52:22 +0800 Subject: [PATCH 25/38] Abstract bill --- RealCity.csproj | 12 +++- RealCityEconomyExtension.cs | 22 +----- Util/ObjectPrivateDataExtension.cs | 76 ++++++++++++++++++++ Util/Politic/AbstractBill.cs | 16 +++++ Util/Politic/Bill.cs | 31 -------- Util/Politic/Bill/ReduceBenefitBill.cs | 13 ++++ Util/Politic/Bill/ReduceCommercialTaxBill.cs | 13 ++++ Util/Politic/Bill/ReduceIndustryTaxBill.cs | 13 ++++ Util/Politic/Bill/ReduceResidentTaxBill.cs | 13 ++++ Util/Politic/Bill/RiseBenefitBill.cs | 13 ++++ Util/Politic/Bill/RiseCommercialTaxBill.cs | 13 ++++ Util/Politic/Bill/RiseIndustryTaxBill.cs | 13 ++++ Util/Politic/Bill/RiseResidentTaxBill.cs | 13 ++++ Util/Politic/Bills.cs | 71 ++++++++++++++---- Util/Politic/Election.cs | 11 +-- Util/Politic/PartyFactory.cs | 40 +++++------ Util/Politic/Vote.cs | 32 +++++++-- Util/Politic/bill-desc.txt | 16 +++++ 18 files changed, 336 insertions(+), 95 deletions(-) create mode 100644 Util/ObjectPrivateDataExtension.cs create mode 100644 Util/Politic/AbstractBill.cs delete mode 100644 Util/Politic/Bill.cs create mode 100644 Util/Politic/Bill/ReduceBenefitBill.cs create mode 100644 Util/Politic/Bill/ReduceCommercialTaxBill.cs create mode 100644 Util/Politic/Bill/ReduceIndustryTaxBill.cs create mode 100644 Util/Politic/Bill/ReduceResidentTaxBill.cs create mode 100644 Util/Politic/Bill/RiseBenefitBill.cs create mode 100644 Util/Politic/Bill/RiseCommercialTaxBill.cs create mode 100644 Util/Politic/Bill/RiseIndustryTaxBill.cs create mode 100644 Util/Politic/Bill/RiseResidentTaxBill.cs create mode 100644 Util/Politic/bill-desc.txt diff --git a/RealCity.csproj b/RealCity.csproj index 8cee080..117fcd1 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -95,8 +95,17 @@ - + + + + + + + + + + @@ -213,6 +222,7 @@ + diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 137ff0c..34cf0ca 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -434,26 +434,8 @@ public void VoteResult(int billId) { } if (seatCount == 99) { - switch (bill) { - case Bills.RaiseResidentTax: - yes += Politics.Parties.Sum(p => { - // - return p.GetBillAttitude()[bill][0]; - }); - yes += (Politics.Parties.Length * residentTax; - - no += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[bill][1]; - }); - no -= Politics.Parties.Length * residentTax; - - noAttend += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[bill][2]; - }); - noAttend -= Politics.Parties.Length * residentTax; - break; - - + switch (billId) { + case 0: yes += Politics.cPartySeats * (Politics.riseSalaryTax[0, 0] + residentTax); yes += Politics.gPartySeats * (Politics.riseSalaryTax[1, 0] + residentTax); yes += Politics.sPartySeats * (Politics.riseSalaryTax[2, 0] + residentTax); diff --git a/Util/ObjectPrivateDataExtension.cs b/Util/ObjectPrivateDataExtension.cs new file mode 100644 index 0000000..d27ac2c --- /dev/null +++ b/Util/ObjectPrivateDataExtension.cs @@ -0,0 +1,76 @@ +using System; +using System.Reflection; + +namespace RealCity.Util +{ + /// + /// Object私有成员扩展 + /// + public static class ObjectPrivateDataExtension + { + /// + /// 访问私有字段 + /// + /// 字段类型 + /// 实例 + /// 字段名 + /// + public static T GetPrivateField(this object instance, string fieldName) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + FieldInfo field = type.GetField(fieldName, flag); + return (T)field.GetValue(instance); + } + /// + /// 访问私有属性 + /// + /// 属性类型 + /// 实例 + /// 属性名 + /// + public static T GetPrivateProperty(this object instance, string propertyName) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + PropertyInfo field = type.GetProperty(propertyName, flag); + return (T)field.GetValue(instance, null); + } + /// + /// 设置私有字段 + /// + /// 实例 + /// 字段名 + /// 新值 + public static void SetPrivateField(this object instance, string fieldName, object value) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + FieldInfo field = type.GetField(fieldName, flag); + field.SetValue(instance, value); + } + /// + /// 设置私有属性 + /// + /// 实例 + /// 属性名 + /// 新值 + public static void SetPrivateProperty(this object instance, string propertyName, object value) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + PropertyInfo field = type.GetProperty(propertyName, flag); + field.SetValue(instance, value, null); + } + /// + /// 访问私有方法 + /// + /// 方法返回值 + /// 实例 + /// 方法名 + /// 参数 + /// + public static T CallPrivateMethod(this object instance, string name, params object[] param) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + MethodInfo method = type.GetMethod(name, flag); + return (T)method.Invoke(instance, param); + } + } +} diff --git a/Util/Politic/AbstractBill.cs b/Util/Politic/AbstractBill.cs new file mode 100644 index 0000000..713dda9 --- /dev/null +++ b/Util/Politic/AbstractBill.cs @@ -0,0 +1,16 @@ +using System; + +namespace RealCity.Util.Politic +{ + /// + /// 议案 + /// + public abstract class AbstractBill : IBill + { + protected int effectVal; + public AbstractBill(int effectVal) { + this.effectVal = effectVal; + } + public abstract void Implement(); + } +} \ No newline at end of file diff --git a/Util/Politic/Bill.cs b/Util/Politic/Bill.cs deleted file mode 100644 index af41e37..0000000 --- a/Util/Politic/Bill.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; - -namespace RealCity.Util.Politic -{ - /// - /// 议案 - /// - public class Bill : IBill - { - private Action content; - - /// - /// 议案 - /// - /// 议案内容 - public Bill(Action content) { - //Bill就像一个抽象类,它并不知道content是什么,只管调用就行 - this.content = content; - } - - public void Implement() { - this.content.Invoke(); - } - public static bool operator ==(Bill a, Bill b) { - return a.content == b.content; - } - public static bool operator !=(Bill a, Bill b) { - return !(a == b); - } - } -} \ No newline at end of file diff --git a/Util/Politic/Bill/ReduceBenefitBill.cs b/Util/Politic/Bill/ReduceBenefitBill.cs new file mode 100644 index 0000000..43540ef --- /dev/null +++ b/Util/Politic/Bill/ReduceBenefitBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class ReduceBenefitBill : AbstractBill + { + public ReduceBenefitBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.benefitOffset -= base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/ReduceCommercialTaxBill.cs b/Util/Politic/Bill/ReduceCommercialTaxBill.cs new file mode 100644 index 0000000..9b18604 --- /dev/null +++ b/Util/Politic/Bill/ReduceCommercialTaxBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class ReduceCommercialTaxBill : AbstractBill + { + public ReduceCommercialTaxBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.commercialTax -= base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/ReduceIndustryTaxBill.cs b/Util/Politic/Bill/ReduceIndustryTaxBill.cs new file mode 100644 index 0000000..aa5fb2a --- /dev/null +++ b/Util/Politic/Bill/ReduceIndustryTaxBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class ReduceIndustryTaxBill : AbstractBill + { + public ReduceIndustryTaxBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.industryTax -= base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/ReduceResidentTaxBill.cs b/Util/Politic/Bill/ReduceResidentTaxBill.cs new file mode 100644 index 0000000..6e8a3ea --- /dev/null +++ b/Util/Politic/Bill/ReduceResidentTaxBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class ReduceResidentTaxBill : AbstractBill + { + public ReduceResidentTaxBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.residentTax -= base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/RiseBenefitBill.cs b/Util/Politic/Bill/RiseBenefitBill.cs new file mode 100644 index 0000000..bec724e --- /dev/null +++ b/Util/Politic/Bill/RiseBenefitBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class RiseBenefitBill : AbstractBill + { + public RiseBenefitBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.benefitOffset += base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/RiseCommercialTaxBill.cs b/Util/Politic/Bill/RiseCommercialTaxBill.cs new file mode 100644 index 0000000..1a7de1e --- /dev/null +++ b/Util/Politic/Bill/RiseCommercialTaxBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class RiseCommercialTaxBill : AbstractBill + { + public RiseCommercialTaxBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.commercialTax += base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/RiseIndustryTaxBill.cs b/Util/Politic/Bill/RiseIndustryTaxBill.cs new file mode 100644 index 0000000..46c5362 --- /dev/null +++ b/Util/Politic/Bill/RiseIndustryTaxBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class RiseIndustryTaxBill : AbstractBill + { + public RiseIndustryTaxBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.industryTax += base.effectVal; + } + } +} diff --git a/Util/Politic/Bill/RiseResidentTaxBill.cs b/Util/Politic/Bill/RiseResidentTaxBill.cs new file mode 100644 index 0000000..fd9cfa8 --- /dev/null +++ b/Util/Politic/Bill/RiseResidentTaxBill.cs @@ -0,0 +1,13 @@ +namespace RealCity.Util.Politic.Bill +{ + public class RiseResidentTaxBill : AbstractBill + { + public RiseResidentTaxBill(int val) + : base(val) { + + } + public override void Implement() { + Politics.residentTax += base.effectVal; + } + } +} diff --git a/Util/Politic/Bills.cs b/Util/Politic/Bills.cs index c26c70f..0cb8872 100644 --- a/Util/Politic/Bills.cs +++ b/Util/Politic/Bills.cs @@ -1,29 +1,72 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using RealCity.Util.Politic.Bill; namespace RealCity.Util.Politic { public class Bills { - public static IBill RaiseResidentTax = new Bill(() => Politics.residentTax++); - public static IBill RaiseCommercialTax = new Bill(() => Politics.commercialTax++); - public static IBill RaiseIndustryTax = new Bill(() => Politics.industryTax++); - public static IBill RaiseBenefitOffset = new Bill(() => Politics.benefitOffset += 10); + public static IBill RiseResidentTax = new RiseResidentTaxBill(1); + public static IBill RiseCommercialTax = new RiseCommercialTaxBill(1); + public static IBill RiseIndustryTax = new RiseIndustryTaxBill(1); + public static IBill RiseBenefitOffset = new RiseBenefitBill(10); - public static IBill ReduceResidentTax = new Bill(() => Politics.residentTax--); - public static IBill ReduceCommercialTax = new Bill(() => Politics.commercialTax--); - public static IBill ReduceIndustryTax = new Bill(() => Politics.industryTax--); - public static IBill ReduceBenefitOffset = new Bill(() => Politics.benefitOffset -= 10); + public static IBill ReduceResidentTax => new ReduceResidentTaxBill(1); + public static IBill ReduceCommercialTax = new ReduceCommercialTaxBill(1); + public static IBill ReduceIndustryTax = new ReduceIndustryTaxBill(1); + public static IBill ReduceBenefitOffset = new ReduceBenefitBill(10); //这里需要null object吗 ? - IBill GetAnotherBill(IBill currentBill) { + public IBill GetAnotherBill(IBill bill) { - } + //需要获得一个逆向的Bill RiseBill => ReduceBill + + #region old codes + System.Random rand = new System.Random(); + + int avoidIdx0 = 8; + int avoidIdx1 = 8; + int avoidIdx2 = 8; + int avoidIdx3 = 8; + if (Politics.residentTax >= 20) { + avoidIdx0 = 0; + } else if (Politics.residentTax <= 1) { + avoidIdx0 = 1; + } + + if (Politics.benefitOffset >= 100) { + avoidIdx1 = 2; + } else if (Politics.benefitOffset <= 0) { + avoidIdx1 = 3; + } + if (Politics.commercialTax >= 20) { + avoidIdx2 = 4; + } else if (Politics.commercialTax <= 1) { + avoidIdx2 = 5; + } + + if (Politics.industryTax >= 20) { + avoidIdx3 = 6; + } else if (Politics.industryTax <= 1) { + avoidIdx3 = 7; + } + + if ((orgIdx == avoidIdx0) + || (orgIdx == avoidIdx1) + || (orgIdx == avoidIdx2) + || (orgIdx == avoidIdx3)) { + while (true) { + byte returnValue = (byte)rand.Next(8); + if (!((returnValue == avoidIdx0) || (returnValue == avoidIdx1) || (returnValue == avoidIdx2) || (returnValue == avoidIdx3))) { + return returnValue; + } + } + } else { + return orgIdx; + } + #endregion + } } } \ No newline at end of file diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs index ef9dea1..3c4fe8e 100644 --- a/Util/Politic/Election.cs +++ b/Util/Politic/Election.cs @@ -32,18 +32,19 @@ private void CalcPartiesWinChance() { } private void VoteTicket() { - // It's like Roulette Wheel Selection + // It's Roulette Wheel Selection // 大转盘,政党的WinChance越大,得票机率就越大 int i = 0; int segment = this.parties[0].WinChance; int vote = r.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; - /* - * [ Party A ][ P.B ][ P.C ] + /* + * Party A P.B P.C + * |<--------------->|<------>|<-------->| * ^ vote ^ length is the sum of party.WinChance * ^ initial Segment - * [ Party A ][ P.B ][ P.C ] - * ^ S move forward, now vote is smaller than SR, which means P.B gets a ticket + * |<--------------->|<------>|<-------->| + * ^ S move forward, now vote is smaller than S, which means P.B gets 1 ticket */ while (i < parties.Length) { diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs index 0aa3577..c5d76f3 100644 --- a/Util/Politic/PartyFactory.cs +++ b/Util/Politic/PartyFactory.cs @@ -20,13 +20,13 @@ public IParty MakeCParty() { VoteResult raiseBenefitOffset = new VoteResult(40, 50, 10); VoteResult reduceBenefitOffset = new VoteResult(50, 40, 10); - billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); - billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.RiseCommercialTax, raiseCommercialTax); billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); - billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( @@ -53,13 +53,13 @@ public IParty MakeGParty() { VoteResult raiseBenefitOffset = new VoteResult(70, 20, 10); VoteResult reduceBenefitOffset = new VoteResult(20, 70, 10); - billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); - billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.RiseCommercialTax, raiseCommercialTax); billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); - billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( @@ -86,13 +86,13 @@ public IParty MakeSParty() { VoteResult raiseBenefitOffset = new VoteResult(90, 10, 0); VoteResult reduceBenefitOffset = new VoteResult(10, 90, 0); - billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); - billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.RiseCommercialTax, raiseCommercialTax); billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); - billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( @@ -119,13 +119,13 @@ public IParty MakeLParty() { VoteResult raiseBenefitOffset = new VoteResult(10, 90, 0); VoteResult reduceBenefitOffset = new VoteResult(90, 10, 0); - billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); - billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.RiseCommercialTax, raiseCommercialTax); billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); - billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( @@ -152,13 +152,13 @@ public IParty MakeNParty() { VoteResult raiseBenefitOffset = new VoteResult(30, 60, 10); VoteResult reduceBenefitOffset = new VoteResult(60, 30, 10); - billAttitudeMap.Add(Bills.RaiseResidentTax, raiseResidentTax); + billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); - billAttitudeMap.Add(Bills.RaiseCommercialTax, raiseCommercialTax); + billAttitudeMap.Add(Bills.RiseCommercialTax, raiseCommercialTax); billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); - billAttitudeMap.Add(Bills.RaiseIndustryTax, raiseIndustryTax); + billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RaiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( diff --git a/Util/Politic/Vote.cs b/Util/Politic/Vote.cs index 9387340..097c484 100644 --- a/Util/Politic/Vote.cs +++ b/Util/Politic/Vote.cs @@ -1,6 +1,8 @@ -using System; +using ColossalFramework; +using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; namespace RealCity.Util.Politic @@ -27,6 +29,8 @@ public VoteResult Calc() { int disagree = default; int noVote = default; + int seatCount = Politics.GetAllSeatCount(); + int residentTax = 10 - (Politics.residentTax); int commercialTax = 10 - (Politics.commercialTax); int industryTax = 10 - (Politics.industryTax); @@ -35,6 +39,25 @@ public VoteResult Calc() { int citizenOffset = 0; // citizen offset int industrialBuildingOffset = 0; //industrial building offset int commercialBuildingOffset = 0; //commercial building offset + VoteOffset(ref billId, ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); + + if (seatCount == 99) { + agree += Politics.Parties.Sum(p => { + // + return p.GetBillAttitude()[this.bill].Agree; + }); + agree += (Politics.Parties.Length * residentTax - moneyOffset - citizenOffset); + + disagree += Politics.Parties.Sum(p => { + return p.GetBillAttitude()[this.bill].Disagree; + }); + disagree -= Politics.Parties.Length * residentTax; + + noVote += Politics.Parties.Sum(p => { + return p.GetBillAttitude()[this.bill].NoVote; + }); + noVote -= Politics.Parties.Length * residentTax; + } return new VoteResult(agree, disagree, noVote); } @@ -42,9 +65,10 @@ public VoteResult Calc() { private void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, ref int buildingOffset, ref int commBuildingOffset) { //MoneyOffset; MoneyOffset = 0; - FieldInfo cashAmount; - cashAmount = typeof(EconomyManager).GetField("m_cashAmount", BindingFlags.NonPublic | BindingFlags.Instance); - long _cashAmount = (long)cashAmount.GetValue(Singleton.instance); + //FieldInfo cashAmount; + //cashAmount = typeof(EconomyManager).GetField("m_cashAmount", BindingFlags.NonPublic | BindingFlags.Instance); + //long _cashAmount = (long)cashAmount.GetValue(Singleton.instance); + long _cashAmount = Singleton.instance.GetPrivateField("m_cashAmount"); if (_cashAmount < 0) { MoneyOffset = -4000; System.Random rand = new System.Random(); diff --git a/Util/Politic/bill-desc.txt b/Util/Politic/bill-desc.txt new file mode 100644 index 0000000..f75718d --- /dev/null +++ b/Util/Politic/bill-desc.txt @@ -0,0 +1,16 @@ +case 0: +Politics.residentTax += 1; +case 1: +Politics.residentTax -= 1; +case 2: +Politics.benefitOffset += 10; +case 3: +Politics.benefitOffset -= 10; +case 4: +Politics.commercialTax += 1; +case 5: +Politics.commercialTax -= 1; +case 6: +Politics.industryTax += 1; +case 7: +Politics.industryTax -= 1; \ No newline at end of file From 7e74b692195d9e26074184053ca9bdeab8dce158 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Wed, 2 Sep 2020 18:00:15 +0800 Subject: [PATCH 26/38] Update Bill and add supportive logics for politics --- Util/ArrayExtension.cs | 61 +++++----- Util/ObjectPrivateDataExtension.cs | 133 +++++++++++---------- Util/Politic/Bills.cs | 182 ++++++++++++++++++++--------- Util/Politic/IBill.cs | 4 +- Util/Politics.cs | 17 ++- 5 files changed, 244 insertions(+), 153 deletions(-) diff --git a/Util/ArrayExtension.cs b/Util/ArrayExtension.cs index 4548b95..7ced24a 100644 --- a/Util/ArrayExtension.cs +++ b/Util/ArrayExtension.cs @@ -1,36 +1,41 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace RealCity.Util +public static class ArrayExtension { - public static class ArrayExtension - { - /// - /// 修正数组长度 - /// - /// - /// - /// - public static T[] EnsureLength(this T[] arr, int expectedLength) { - if (arr.Length != expectedLength) { - T[] correctData = new T[expectedLength]; - if (arr.Length < expectedLength) { - // expected: 5 3 4 5 - // actually: 5 3 4 _ - Array.Copy(arr, correctData, arr.Length); - // fill the remaining part - for (int i = arr.Length; i < expectedLength; ++i) { - correctData[i] = default; - } - } else { - // throw the useless part - Array.Copy(arr, correctData, expectedLength); + /// + /// 修正数组长度 + /// + /// + /// + /// + public static T[] EnsureLength(this T[] arr, int expectedLength) { + if (arr.Length != expectedLength) { + T[] correctData = new T[expectedLength]; + if (arr.Length < expectedLength) { + // expected: 5 3 4 5 + // actually: 5 3 4 _ + Array.Copy(arr, correctData, arr.Length); + // fill the remaining part + for (int i = arr.Length; i < expectedLength; ++i) { + correctData[i] = default; } - return correctData; + } else { + // throw the useless part + Array.Copy(arr, correctData, expectedLength); } - return arr; + return correctData; + } + return arr; + } + /// + /// Initializes every element of the value-type System.Array by a given value. + /// + /// + /// + /// + public static void Initialize(this Array arr, T value) { + for (int i = 0; i < arr.Length; i++) { + arr.SetValue(value, i); } } } diff --git a/Util/ObjectPrivateDataExtension.cs b/Util/ObjectPrivateDataExtension.cs index d27ac2c..96342fd 100644 --- a/Util/ObjectPrivateDataExtension.cs +++ b/Util/ObjectPrivateDataExtension.cs @@ -1,76 +1,73 @@ using System; using System.Reflection; -namespace RealCity.Util +/// +/// Object私有成员扩展 +/// +public static class ObjectPrivateDataExtension { /// - /// Object私有成员扩展 + /// 访问私有字段 /// - public static class ObjectPrivateDataExtension - { - /// - /// 访问私有字段 - /// - /// 字段类型 - /// 实例 - /// 字段名 - /// - public static T GetPrivateField(this object instance, string fieldName) { - Type type = instance.GetType(); - BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; - FieldInfo field = type.GetField(fieldName, flag); - return (T)field.GetValue(instance); - } - /// - /// 访问私有属性 - /// - /// 属性类型 - /// 实例 - /// 属性名 - /// - public static T GetPrivateProperty(this object instance, string propertyName) { - Type type = instance.GetType(); - BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; - PropertyInfo field = type.GetProperty(propertyName, flag); - return (T)field.GetValue(instance, null); - } - /// - /// 设置私有字段 - /// - /// 实例 - /// 字段名 - /// 新值 - public static void SetPrivateField(this object instance, string fieldName, object value) { - Type type = instance.GetType(); - BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; - FieldInfo field = type.GetField(fieldName, flag); - field.SetValue(instance, value); - } - /// - /// 设置私有属性 - /// - /// 实例 - /// 属性名 - /// 新值 - public static void SetPrivateProperty(this object instance, string propertyName, object value) { - Type type = instance.GetType(); - BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; - PropertyInfo field = type.GetProperty(propertyName, flag); - field.SetValue(instance, value, null); - } - /// - /// 访问私有方法 - /// - /// 方法返回值 - /// 实例 - /// 方法名 - /// 参数 - /// - public static T CallPrivateMethod(this object instance, string name, params object[] param) { - Type type = instance.GetType(); - BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; - MethodInfo method = type.GetMethod(name, flag); - return (T)method.Invoke(instance, param); - } + /// 字段类型 + /// 实例 + /// 字段名 + /// + public static T GetPrivateField(this object instance, string fieldName) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + FieldInfo field = type.GetField(fieldName, flag); + return (T)field.GetValue(instance); + } + /// + /// 访问私有属性 + /// + /// 属性类型 + /// 实例 + /// 属性名 + /// + public static T GetPrivateProperty(this object instance, string propertyName) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + PropertyInfo field = type.GetProperty(propertyName, flag); + return (T)field.GetValue(instance, null); + } + /// + /// 设置私有字段 + /// + /// 实例 + /// 字段名 + /// 新值 + public static void SetPrivateField(this object instance, string fieldName, object value) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + FieldInfo field = type.GetField(fieldName, flag); + field.SetValue(instance, value); + } + /// + /// 设置私有属性 + /// + /// 实例 + /// 属性名 + /// 新值 + public static void SetPrivateProperty(this object instance, string propertyName, object value) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + PropertyInfo field = type.GetProperty(propertyName, flag); + field.SetValue(instance, value, null); + } + /// + /// 访问私有方法 + /// + /// 方法返回值 + /// 实例 + /// 方法名 + /// 参数 + /// + public static T CallPrivateMethod(this object instance, string name, params object[] param) { + Type type = instance.GetType(); + BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic; + MethodInfo method = type.GetMethod(name, flag); + return (T)method.Invoke(instance, param); } } diff --git a/Util/Politic/Bills.cs b/Util/Politic/Bills.cs index 0cb8872..13b5cd6 100644 --- a/Util/Politic/Bills.cs +++ b/Util/Politic/Bills.cs @@ -1,72 +1,150 @@ -using RealCity.Util.Politic.Bill; +using System; +using System.Linq; +using RealCity.Util.Politic.Bill; namespace RealCity.Util.Politic { - public class Bills + public static class Bills { - public static IBill RiseResidentTax = new RiseResidentTaxBill(1); - public static IBill RiseCommercialTax = new RiseCommercialTaxBill(1); - public static IBill RiseIndustryTax = new RiseIndustryTaxBill(1); - public static IBill RiseBenefitOffset = new RiseBenefitBill(10); - public static IBill ReduceResidentTax => new ReduceResidentTaxBill(1); - public static IBill ReduceCommercialTax = new ReduceCommercialTaxBill(1); - public static IBill ReduceIndustryTax = new ReduceIndustryTaxBill(1); - public static IBill ReduceBenefitOffset = new ReduceBenefitBill(10); + public readonly static IBill RiseResidentTax = new RiseResidentTaxBill(1); + public readonly static IBill ReduceResidentTax = new ReduceResidentTaxBill(1); - //这里需要null object吗 ? + public readonly static IBill RiseCommercialTax = new RiseCommercialTaxBill(1); + public readonly static IBill ReduceCommercialTax = new ReduceCommercialTaxBill(1); + public readonly static IBill RiseIndustryTax = new RiseIndustryTaxBill(1); + public readonly static IBill ReduceIndustryTax = new ReduceIndustryTaxBill(1); + public readonly static IBill RiseBenefit = new RiseBenefitBill(10); + public readonly static IBill ReduceBenefit = new ReduceBenefitBill(10); - public IBill GetAnotherBill(IBill bill) { - //需要获得一个逆向的Bill RiseBill => ReduceBill + //这里需要null object吗 ? - #region old codes - System.Random rand = new System.Random(); - - int avoidIdx0 = 8; - int avoidIdx1 = 8; - int avoidIdx2 = 8; - int avoidIdx3 = 8; - if (Politics.residentTax >= 20) { - avoidIdx0 = 0; - } else if (Politics.residentTax <= 1) { - avoidIdx0 = 1; - } + private readonly static IBill[] AllBills = { + RiseResidentTax, + ReduceResidentTax, + RiseCommercialTax, + ReduceCommercialTax, + RiseIndustryTax, + ReduceIndustryTax, + RiseBenefit, + ReduceBenefit, + // must pair the Rise and Reduce bills, + // which is NOT elegant + }; - if (Politics.benefitOffset >= 100) { - avoidIdx1 = 2; - } else if (Politics.benefitOffset <= 0) { - avoidIdx1 = 3; - } + private readonly static string[] AllBillsNameStr = { + nameof(RiseResidentTax), + nameof(ReduceResidentTax), + nameof(RiseCommercialTax), + nameof(ReduceCommercialTax), + nameof(RiseIndustryTax), + nameof(ReduceIndustryTax), + nameof(RiseBenefit), + nameof(ReduceBenefit), + }; - if (Politics.commercialTax >= 20) { - avoidIdx2 = 4; - } else if (Politics.commercialTax <= 1) { - avoidIdx2 = 5; + public static IBill GetReversedBill(IBill bill) { + //string revStr; + //int index = Array.IndexOf(AllBills, bill); + //// even = rise, odd = reduce + //if ((index & 1) == 1) { + // revStr = AllBillsNameStr[index - 1]; + //} else { + // revStr = AllBillsNameStr[index + 1]; + //} + //var ms = typeof(Bills).GetField(revStr, System.Reflection.BindingFlags.Static); + //return ms.GetValue(null) as IBill; + IBill revBill; + int index = Array.IndexOf(AllBills, bill); + // even = rise, odd = reduce + if ((index & 1) == 1) { + revBill = AllBills[index - 1]; + } else { + revBill = AllBills[index + 1]; } + return revBill; + } - if (Politics.industryTax >= 20) { - avoidIdx3 = 6; - } else if (Politics.industryTax <= 1) { - avoidIdx3 = 7; + public static IBill GetAnotherBill(IBill bill) { + int idx = Array.IndexOf(AllBills, bill); + int[] avoidIdxs = new int[AllBills.Length >> 1]; + int i = 0; + // bad codes + if (Politics.CanRiseResidentTax == false) { + avoidIdxs[i] = 0; + } else if (Politics.CanReduceResidentTax == false) { + avoidIdxs[i] = 1; } - - if ((orgIdx == avoidIdx0) - || (orgIdx == avoidIdx1) - || (orgIdx == avoidIdx2) - || (orgIdx == avoidIdx3)) { - while (true) { - byte returnValue = (byte)rand.Next(8); - if (!((returnValue == avoidIdx0) || (returnValue == avoidIdx1) || (returnValue == avoidIdx2) || (returnValue == avoidIdx3))) { - return returnValue; - } - } - } else { - return orgIdx; + ++i; + if (Politics.CanRiseCommercialTax == false) { + avoidIdxs[i] = 2; + } else if (Politics.CanReduceCommercialTax == false) { + avoidIdxs[i] = 3; + } + ++i; + if (Politics.CanRiseIndustryTax == false) { + avoidIdxs[i] = 4; + } else if (Politics.CanReduceIndustryTax == false) { + avoidIdxs[i] = 5; } + ++i; + if (Politics.CanRiseBenefit == false) { + avoidIdxs[i] = 6; + } else if (Politics.CanReduceBenefit == false) { + avoidIdxs[i] = 7; + } + + Random r = new Random(); + for (; avoidIdxs.Contains(idx); idx = r.Next(AllBills.Length)) ; + IBill bi = AllBills[idx]; + return bi; + + #region old codes + //System.Random rand = new System.Random(); + + //// 8 is a id of non-exist bill + //int avoidIdx0 = 8; + //int avoidIdx1 = 8; + //int avoidIdx2 = 8; + //int avoidIdx3 = 8; + //if (Politics.residentTax >= 20) { + // avoidIdx0 = 0; + //} else if (Politics.residentTax <= 1) { + // avoidIdx0 = 1; + //} + + //if (Politics.commercialTax >= 20) { + // avoidIdx2 = 4; + //} else if (Politics.commercialTax <= 1) { + // avoidIdx2 = 5; + //} + + //if (Politics.industryTax >= 20) { + // avoidIdx3 = 6; + //} else if (Politics.industryTax <= 1) { + // avoidIdx3 = 7; + //} + + //if (Politics.benefitOffset >= 100) { + // avoidIdx1 = 2; + //} else if (Politics.benefitOffset <= 0) { + // avoidIdx1 = 3; + //} + + //if ((orgIdx == avoidIdx0) || (orgIdx == avoidIdx1) || (orgIdx == avoidIdx2) || (orgIdx == avoidIdx3)) { + // while (true) { + // byte returnValue = (byte)rand.Next(8); + // if (!((returnValue == avoidIdx0) || (returnValue == avoidIdx1) || (returnValue == avoidIdx2) || (returnValue == avoidIdx3))) { + // return returnValue; + // } + // } + //} else { + // return orgIdx; + //} #endregion } } -} \ No newline at end of file +} diff --git a/Util/Politic/IBill.cs b/Util/Politic/IBill.cs index 125ffc6..32e1472 100644 --- a/Util/Politic/IBill.cs +++ b/Util/Politic/IBill.cs @@ -1,6 +1,4 @@ -using System; - -namespace RealCity.Util.Politic +namespace RealCity.Util.Politic { public interface IBill { diff --git a/Util/Politics.cs b/Util/Politics.cs index 133821c..c59825d 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -9,13 +9,17 @@ namespace RealCity.Util { public class Politics { + private const Citizen.AgeGroup VotingAge = Citizen.AgeGroup.Young; + private const int MaxTaxValue = 20; + private const int MinTaxValue = 0; + private const int MaxBenefitValue = 100; + private const int MinBenefitValue = 0; + private static IParty cParty; private static IParty gParty; private static IParty sParty; private static IParty lParty; private static IParty nParty; - - private const Citizen.AgeGroup VotingAge = Citizen.AgeGroup.Young; public static IParty[] Parties => new IParty[] { cParty, gParty, sParty, lParty, nParty }; public static void ResetWinChance() { Parties.ForEach(p => p.ResetWinChance()); @@ -53,6 +57,15 @@ public static bool IsOverVotingAge(ref Citizen citizen) { return IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age)); } + public static bool CanRiseResidentTax => residentTax < MaxTaxValue; + public static bool CanReduceResidentTax => residentTax > MinTaxValue; + public static bool CanRiseCommercialTax => commercialTax < MaxTaxValue; + public static bool CanReduceCommercialTax => commercialTax > MinTaxValue; + public static bool CanRiseIndustryTax => industryTax < MaxTaxValue; + public static bool CanReduceIndustryTax => industryTax > MinTaxValue; + public static bool CanRiseBenefit => benefitOffset < MaxBenefitValue; + public static bool CanReduceBenefit => benefitOffset > MinBenefitValue; + //学历对选举投票的影响因子 public static byte[,] education = { {30, 0, 10, 10, 50}, {20, 10, 25, 20, 25}, From d51f5bd864a9ed01c1191c6eeb1ef6f5426ad2e8 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Wed, 2 Sep 2020 18:17:49 +0800 Subject: [PATCH 27/38] Update Bills.cs --- Util/Politic/Bills.cs | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/Util/Politic/Bills.cs b/Util/Politic/Bills.cs index 13b5cd6..00f249e 100644 --- a/Util/Politic/Bills.cs +++ b/Util/Politic/Bills.cs @@ -70,35 +70,19 @@ public static IBill GetReversedBill(IBill bill) { public static IBill GetAnotherBill(IBill bill) { int idx = Array.IndexOf(AllBills, bill); - int[] avoidIdxs = new int[AllBills.Length >> 1]; + bool[] implementable = new bool[AllBills.Length]; int i = 0; - // bad codes - if (Politics.CanRiseResidentTax == false) { - avoidIdxs[i] = 0; - } else if (Politics.CanReduceResidentTax == false) { - avoidIdxs[i] = 1; - } - ++i; - if (Politics.CanRiseCommercialTax == false) { - avoidIdxs[i] = 2; - } else if (Politics.CanReduceCommercialTax == false) { - avoidIdxs[i] = 3; - } - ++i; - if (Politics.CanRiseIndustryTax == false) { - avoidIdxs[i] = 4; - } else if (Politics.CanReduceIndustryTax == false) { - avoidIdxs[i] = 5; - } - ++i; - if (Politics.CanRiseBenefit == false) { - avoidIdxs[i] = 6; - } else if (Politics.CanReduceBenefit == false) { - avoidIdxs[i] = 7; - } + implementable[i++] = Politics.CanRiseResidentTax; + implementable[i++] = Politics.CanReduceResidentTax; + implementable[i++] = Politics.CanRiseCommercialTax; + implementable[i++] = Politics.CanReduceCommercialTax; + implementable[i++] = Politics.CanRiseIndustryTax; + implementable[i++] = Politics.CanReduceIndustryTax; + implementable[i++] = Politics.CanRiseBenefit; + implementable[i++] = Politics.CanReduceBenefit; Random r = new Random(); - for (; avoidIdxs.Contains(idx); idx = r.Next(AllBills.Length)) ; + for (; implementable[idx] == false; idx = r.Next(AllBills.Length)) ; IBill bi = AllBills[idx]; return bi; From e5d22ab8705e75e65daacaa57fd4c0a711df7787 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Wed, 2 Sep 2020 18:26:54 +0800 Subject: [PATCH 28/38] Update interface IBill --- Util/Politic/AbstractBill.cs | 1 + Util/Politic/Bill/ReduceBenefitBill.cs | 4 ++++ Util/Politic/Bill/ReduceCommercialTaxBill.cs | 4 ++++ Util/Politic/Bill/ReduceIndustryTaxBill.cs | 4 ++++ Util/Politic/Bill/ReduceResidentTaxBill.cs | 4 ++++ Util/Politic/Bill/RiseBenefitBill.cs | 4 ++++ Util/Politic/Bill/RiseCommercialTaxBill.cs | 4 ++++ Util/Politic/Bill/RiseIndustryTaxBill.cs | 4 ++++ Util/Politic/Bill/RiseResidentTaxBill.cs | 4 ++++ Util/Politic/Bills.cs | 24 +++++++------------- Util/Politic/IBill.cs | 1 + 11 files changed, 42 insertions(+), 16 deletions(-) diff --git a/Util/Politic/AbstractBill.cs b/Util/Politic/AbstractBill.cs index 713dda9..d6c13de 100644 --- a/Util/Politic/AbstractBill.cs +++ b/Util/Politic/AbstractBill.cs @@ -12,5 +12,6 @@ public AbstractBill(int effectVal) { this.effectVal = effectVal; } public abstract void Implement(); + public abstract bool IsImplementable(); } } \ No newline at end of file diff --git a/Util/Politic/Bill/ReduceBenefitBill.cs b/Util/Politic/Bill/ReduceBenefitBill.cs index 43540ef..7be49e5 100644 --- a/Util/Politic/Bill/ReduceBenefitBill.cs +++ b/Util/Politic/Bill/ReduceBenefitBill.cs @@ -9,5 +9,9 @@ public ReduceBenefitBill(int val) public override void Implement() { Politics.benefitOffset -= base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanReduceBenefit; + } } } diff --git a/Util/Politic/Bill/ReduceCommercialTaxBill.cs b/Util/Politic/Bill/ReduceCommercialTaxBill.cs index 9b18604..0e162fa 100644 --- a/Util/Politic/Bill/ReduceCommercialTaxBill.cs +++ b/Util/Politic/Bill/ReduceCommercialTaxBill.cs @@ -9,5 +9,9 @@ public ReduceCommercialTaxBill(int val) public override void Implement() { Politics.commercialTax -= base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanReduceCommercialTax; + } } } diff --git a/Util/Politic/Bill/ReduceIndustryTaxBill.cs b/Util/Politic/Bill/ReduceIndustryTaxBill.cs index aa5fb2a..ce5a654 100644 --- a/Util/Politic/Bill/ReduceIndustryTaxBill.cs +++ b/Util/Politic/Bill/ReduceIndustryTaxBill.cs @@ -9,5 +9,9 @@ public ReduceIndustryTaxBill(int val) public override void Implement() { Politics.industryTax -= base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanReduceIndustryTax; + } } } diff --git a/Util/Politic/Bill/ReduceResidentTaxBill.cs b/Util/Politic/Bill/ReduceResidentTaxBill.cs index 6e8a3ea..fccf314 100644 --- a/Util/Politic/Bill/ReduceResidentTaxBill.cs +++ b/Util/Politic/Bill/ReduceResidentTaxBill.cs @@ -9,5 +9,9 @@ public ReduceResidentTaxBill(int val) public override void Implement() { Politics.residentTax -= base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanReduceResidentTax; + } } } diff --git a/Util/Politic/Bill/RiseBenefitBill.cs b/Util/Politic/Bill/RiseBenefitBill.cs index bec724e..e1b5e41 100644 --- a/Util/Politic/Bill/RiseBenefitBill.cs +++ b/Util/Politic/Bill/RiseBenefitBill.cs @@ -9,5 +9,9 @@ public RiseBenefitBill(int val) public override void Implement() { Politics.benefitOffset += base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanRiseBenefit; + } } } diff --git a/Util/Politic/Bill/RiseCommercialTaxBill.cs b/Util/Politic/Bill/RiseCommercialTaxBill.cs index 1a7de1e..505ea40 100644 --- a/Util/Politic/Bill/RiseCommercialTaxBill.cs +++ b/Util/Politic/Bill/RiseCommercialTaxBill.cs @@ -9,5 +9,9 @@ public RiseCommercialTaxBill(int val) public override void Implement() { Politics.commercialTax += base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanRiseCommercialTax; + } } } diff --git a/Util/Politic/Bill/RiseIndustryTaxBill.cs b/Util/Politic/Bill/RiseIndustryTaxBill.cs index 46c5362..6e0b7b7 100644 --- a/Util/Politic/Bill/RiseIndustryTaxBill.cs +++ b/Util/Politic/Bill/RiseIndustryTaxBill.cs @@ -9,5 +9,9 @@ public RiseIndustryTaxBill(int val) public override void Implement() { Politics.industryTax += base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanRiseIndustryTax; + } } } diff --git a/Util/Politic/Bill/RiseResidentTaxBill.cs b/Util/Politic/Bill/RiseResidentTaxBill.cs index fd9cfa8..b111522 100644 --- a/Util/Politic/Bill/RiseResidentTaxBill.cs +++ b/Util/Politic/Bill/RiseResidentTaxBill.cs @@ -9,5 +9,9 @@ public RiseResidentTaxBill(int val) public override void Implement() { Politics.residentTax += base.effectVal; } + + public override bool IsImplementable() { + return Politics.CanRiseResidentTax; + } } } diff --git a/Util/Politic/Bills.cs b/Util/Politic/Bills.cs index 00f249e..5959a99 100644 --- a/Util/Politic/Bills.cs +++ b/Util/Politic/Bills.cs @@ -1,11 +1,13 @@ using System; using System.Linq; +using ColossalFramework; using RealCity.Util.Politic.Bill; namespace RealCity.Util.Politic { public static class Bills { + private static Random r = new Random(); public readonly static IBill RiseResidentTax = new RiseResidentTaxBill(1); public readonly static IBill ReduceResidentTax = new ReduceResidentTaxBill(1); @@ -46,6 +48,10 @@ public static class Bills nameof(ReduceBenefit), }; + public static IBill GetRandomBill() { + return AllBills[r.Next(AllBills.Length)]; + } + public static IBill GetReversedBill(IBill bill) { //string revStr; //int index = Array.IndexOf(AllBills, bill); @@ -69,22 +75,8 @@ public static IBill GetReversedBill(IBill bill) { } public static IBill GetAnotherBill(IBill bill) { - int idx = Array.IndexOf(AllBills, bill); - bool[] implementable = new bool[AllBills.Length]; - int i = 0; - implementable[i++] = Politics.CanRiseResidentTax; - implementable[i++] = Politics.CanReduceResidentTax; - implementable[i++] = Politics.CanRiseCommercialTax; - implementable[i++] = Politics.CanReduceCommercialTax; - implementable[i++] = Politics.CanRiseIndustryTax; - implementable[i++] = Politics.CanReduceIndustryTax; - implementable[i++] = Politics.CanRiseBenefit; - implementable[i++] = Politics.CanReduceBenefit; - - Random r = new Random(); - for (; implementable[idx] == false; idx = r.Next(AllBills.Length)) ; - IBill bi = AllBills[idx]; - return bi; + for (; bill.IsImplementable() == false; bill = GetRandomBill()) ; + return bill; #region old codes //System.Random rand = new System.Random(); diff --git a/Util/Politic/IBill.cs b/Util/Politic/IBill.cs index 32e1472..00395b8 100644 --- a/Util/Politic/IBill.cs +++ b/Util/Politic/IBill.cs @@ -3,5 +3,6 @@ public interface IBill { void Implement(); + bool IsImplementable(); } } From 8c9efc7186109525f6125936baba66d2624b9df0 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Thu, 3 Sep 2020 03:42:04 +0800 Subject: [PATCH 29/38] Update Election, add annotation, etc --- CustomData/CitizenData.cs | 5 +- CustomData/CitizenUnitData.cs | 12 +- CustomData/ICustomGameData.cs | 12 +- ...esidentAICitizenUnitSimulationStepPatch.cs | 59 ++++----- RealCity.csproj | 6 +- RealCityEconomyExtension.cs | 26 ++-- UI/PoliticsUI.cs | 2 +- Util/ArrayExtension.cs | 10 ++ Util/CustomGameDataFactory.cs | 33 +++++ Util/MainDataStore.cs | 2 +- Util/Politic/AbstractBill.cs | 2 +- Util/Politic/Bills.cs | 4 +- Util/Politic/Election.cs | 69 ++--------- Util/Politic/ElectionUtil/ElectionInfo.cs | 27 ++++ Util/Politic/ElectionUtil/ElectionVoter.cs | 80 ++++++++++++ .../{ => ElectionUtil}/PartyInterestCalc.cs | 115 +++++++++--------- Util/Politic/Government.cs | 16 +++ Util/Politic/IParty.cs | 1 + Util/Politic/Party.cs | 4 +- Util/Politic/PartyFactory.cs | 20 ++- Util/Politic/PartyInterestData.cs | 2 - Util/Politic/Vote.cs | 2 +- Util/Politic/VoteResult.cs | 10 +- Util/Politics.cs | 23 ++-- 24 files changed, 347 insertions(+), 195 deletions(-) create mode 100644 Util/CustomGameDataFactory.cs create mode 100644 Util/Politic/ElectionUtil/ElectionInfo.cs create mode 100644 Util/Politic/ElectionUtil/ElectionVoter.cs rename Util/Politic/{ => ElectionUtil}/PartyInterestCalc.cs (56%) create mode 100644 Util/Politic/Government.cs diff --git a/CustomData/CitizenData.cs b/CustomData/CitizenData.cs index 2759767..293864d 100644 --- a/CustomData/CitizenData.cs +++ b/CustomData/CitizenData.cs @@ -12,12 +12,13 @@ public class CitizenData : ICustomGameData public static CitizenData Instance { get { if (_inst == null) { - _inst = new CitizenData(); + CustomGameDataFactory f = new CustomGameDataFactory(); + _inst = f.MakeCitizenData(); } return _inst; } } - private CitizenData() { } + public CitizenData() { } public static uint GetCitizenUnit(ushort buildingId) { if (buildingId != 0) { diff --git a/CustomData/CitizenUnitData.cs b/CustomData/CitizenUnitData.cs index 64f0612..3bde58f 100644 --- a/CustomData/CitizenUnitData.cs +++ b/CustomData/CitizenUnitData.cs @@ -9,11 +9,13 @@ public class CitizenUnitData public static ushort[] familyGoods = new ushort[524288]; public static void DataInit() { - for (int i = 0; i < familyMoney.Length; i++) { - familyMoney[i] = 0f; - //default; - familyGoods[i] = 65535; - } + //for (int i = 0; i < familyMoney.Length; i++) { + // familyMoney[i] = 0f; + // //default; + // familyGoods[i] = 65535; + //} + familyMoney.Initialize(); + familyGoods.Initialize(ushort.MaxValue); } public static void Save(ref byte[] saveData) { diff --git a/CustomData/ICustomGameData.cs b/CustomData/ICustomGameData.cs index 18433f9..6da9038 100644 --- a/CustomData/ICustomGameData.cs +++ b/CustomData/ICustomGameData.cs @@ -1,9 +1,13 @@ -namespace RealCity.CustomData +using System; + +namespace RealCity.CustomData { public interface ICustomGameData { - void DataInit(); - void Save(ref byte[] saveData); - void Load(ref byte[] saveData); + void DataInit(); + + //TODO: let ICustomGameData obey the SRP + void Save(ref byte[] saveData); + void Load(ref byte[] saveData); } } \ No newline at end of file diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index cb4a029..b67170d 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -5,6 +5,7 @@ using RealCity.CustomData; using RealCity.Util; using RealCity.Util.Politic; +using RealCity.Util.Politic.ElectionUtil; using System; using System.Reflection; @@ -46,7 +47,7 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) } } } else { - // + // post-process if (CitizenUnitData.familyMoney[homeID] < MainDataStore.lowWealth) { RealCityResidentAI.familyWeightStableLow++; } else if (CitizenUnitData.familyMoney[homeID] >= MainDataStore.highWealth) { @@ -64,6 +65,7 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) ++temp; #if FASTRUN #else + //add a party.chancce by its citizen data GetVoteChance(m_citizenI, citizenData, homeID); #endif } @@ -374,37 +376,13 @@ public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, ou } } - public static void GetVoteTickets() { - System.Random rand = new System.Random(); - // WTF??? 这里有魔数。800参见PartyInterestCalc.GetFromEducationLevel()中的注释 - if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance - != (800 + RealCityEconomyExtension.partyTrendStrength)) { - //有1/64的机率打印这句话(WTF?) - if (rand.Next(64) <= 1) { - DebugLog.LogToFileOnly($"Error: GetVoteTickets Chance is not equal 800 {(Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance)}"); - } - } - - //大转盘,政党的chance越大,得票机率就越大 - int voteRandom = rand.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; - if (voteRandom < Politics.cPartyChance) { - Politics.cPartyTickets++; - } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance) { - Politics.gPartyTickets++; - } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) { - Politics.sPartyTickets++; - } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) { - Politics.lPartyTickets++; - } else { - Politics.nPartyTickets++; - } - } - public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { //如果即将选举,而且达到投票年龄 if (gonna be election) and (over Voting Age) if (Politics.IsOnElection() && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age))) { + ElectionVoter voter = new ElectionVoter(citizenID, ref citizen, homeID,); + Politics.ResetWinChance(); Politics.Parties.ForEach(p => { PartyInterestCalc interestCalc = new PartyInterestCalc(p, ref citizen, citizenID, homeID); @@ -534,10 +512,33 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { } else { DebugLog.LogToFileOnly($"Error: GetVoteChance Invalid partyTrend = {RealCityEconomyExtension.partyTrend}"); } + GetVoteTickets(); + } + } + public static void GetVoteTickets() { + System.Random rand = new System.Random(); + //魔数800参见PartyInterestCalc.GetFromEducationLevel()中的注释 + if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance + != (800 + RealCityEconomyExtension.partyTrendStrength)) { + //有1/64的机率打印这句话(WTF?) + if (rand.Next(64) <= 1) { + DebugLog.LogToFileOnly($"Error: GetVoteTickets Chance is not equal 800 {(Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance)}"); + } + } - - GetVoteTickets(); + //大转盘,政党的chance越大,得票机率就越大 + int voteRandom = rand.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; + if (voteRandom < Politics.cPartyChance) { + Politics.cPartyTickets++; + } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance) { + Politics.gPartyTickets++; + } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) { + Politics.sPartyTickets++; + } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) { + Politics.lPartyTickets++; + } else { + Politics.nPartyTickets++; } } } diff --git a/RealCity.csproj b/RealCity.csproj index 117fcd1..4b9a388 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -95,6 +95,7 @@ + @@ -107,9 +108,12 @@ + + + - + diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 34cf0ca..543e4ec 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -13,8 +13,8 @@ namespace RealCity { public class RealCityEconomyExtension : EconomyExtensionBase { - public static byte partyTrend = 0; - public static ushort partyTrendStrength = 0; + public static byte partyTrend => 0; + public static ushort partyTrendStrength => 0; public static ushort industrialLackMoneyCount = 0; public static ushort industrialEarnMoneyCount = 0; public static ushort commercialLackMoneyCount = 0; @@ -27,9 +27,9 @@ public override long OnUpdateMoneyAmount(long internalMoneyAmount) { uint frameIndex = currentFrameIndex & 255u; if ((frameIndex == 255u) && (MainDataStore.currentTime != MainDataStore.prevTime)) { if (MainDataStore.updateMoneyCount == 16) { - Politics.nextElectionInterval--; - if (Politics.nextElectionInterval < 0) { - Politics.nextElectionInterval = 10; + Politics.nextMeetingInterval--; + if (Politics.nextMeetingInterval < 0) { + Politics.nextMeetingInterval = 10; } //1. Caculate minimumLivingAllowance and unfinishedTransitionLost MainDataStore.minimumLivingAllowanceFinal = MainDataStore.minimumLivingAllowance; @@ -136,16 +136,18 @@ public void CaculateCitizenTransportFee() { /// /// public void CitizenStatus() { - if (Politics.nextElectionInterval == 0) { - System.Random rand = new System.Random(); - partyTrend = (byte)rand.Next(5); - partyTrendStrength = (byte)rand.Next(300); + if (Politics.nextMeetingInterval == 0) { + + Election e = new Election(Politics.Parties); + + GetSeats(); CreateGoverment(); + } if ((MainDataStore.updateMoneyCount & 3u) == 0) { - if (Politics.nextElectionInterval != 0) { + if (Politics.nextMeetingInterval != 0) { HoldMeeting(); } } @@ -428,7 +430,7 @@ public void VoteResult(int billId) { no -= Politics.Parties.Length * residentTax; noAttend += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[bill].NoVote; + return p.GetBillAttitude()[bill].Neutral; }); noAttend -= Politics.Parties.Length * residentTax; } @@ -792,4 +794,4 @@ public static bool Can16timesUpdate(ushort ID) { return false; } } -} \ No newline at end of file +} diff --git a/UI/PoliticsUI.cs b/UI/PoliticsUI.cs index adaffa8..7b2314b 100644 --- a/UI/PoliticsUI.cs +++ b/UI/PoliticsUI.cs @@ -161,7 +161,7 @@ private void RefreshDisplayData() { socialist.text = string.Format(Localization.Get("SOCIALIST") + " [{0}]", Politics.sPartySeats); liberal.text = string.Format(Localization.Get("LIBERAL") + " [{0}]", Politics.lPartySeats); national.text = string.Format(Localization.Get("NATIONAL") + " [{0}]", Politics.nPartySeats); - nextVote.text = string.Format(Localization.Get("NEXT_VOTE") + " [{0}]", Politics.nextElectionInterval); + nextVote.text = string.Format(Localization.Get("NEXT_VOTE") + " [{0}]", Politics.nextMeetingInterval); if (Politics.currentBillId > 7) { currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ": N/A"); diff --git a/Util/ArrayExtension.cs b/Util/ArrayExtension.cs index 7ced24a..1fd8cdb 100644 --- a/Util/ArrayExtension.cs +++ b/Util/ArrayExtension.cs @@ -38,4 +38,14 @@ public static void Initialize(this Array arr, T value) { arr.SetValue(value, i); } } + /// + /// Returns a random element in the Array. + /// + /// + /// + /// + /// + public static T GetRandomElement(this T[] arr, Random random) { + return arr[random.Next(arr.Length)]; + } } diff --git a/Util/CustomGameDataFactory.cs b/Util/CustomGameDataFactory.cs new file mode 100644 index 0000000..cc35182 --- /dev/null +++ b/Util/CustomGameDataFactory.cs @@ -0,0 +1,33 @@ +using RealCity.CustomData; + +namespace RealCity.Util +{ + public class CustomGameDataFactory + { + public BuildingData MakeBuildingData() { + ICustomGameData d = new BuildingData(); + d.DataInit(); + return d as BuildingData; + } + public CitizenData MakeCitizenData() { + ICustomGameData d = new CitizenData(); + d.DataInit(); + return d as CitizenData; + } + public CitizenUnitData MakeCitizenUnitData() { + ICustomGameData d = new CitizenUnitData(); + d.DataInit(); + return d as CitizenUnitData; + } + public TransportLineData MakeTransportLineData() { + ICustomGameData d = new TransportLineData(); + d.DataInit(); + return d as TransportLineData; + } + public VehicleData MakeVehicleData() { + ICustomGameData d = new VehicleData(); + d.DataInit(); + return d as VehicleData; + } + } +} diff --git a/Util/MainDataStore.cs b/Util/MainDataStore.cs index 47c0bf8..c250c63 100644 --- a/Util/MainDataStore.cs +++ b/Util/MainDataStore.cs @@ -122,7 +122,7 @@ public class MainDataStore public static uint familyWeightStableLow = 0; //other in-game variable - public static byte updateMoneyCount = 0; + public static byte updateMoneyCount = 0; // see RealCityEconomyExtension.OnUpdateMoneyAmount() public static float currentTime = 0f; public static float prevTime = 0f; diff --git a/Util/Politic/AbstractBill.cs b/Util/Politic/AbstractBill.cs index d6c13de..5d92b0a 100644 --- a/Util/Politic/AbstractBill.cs +++ b/Util/Politic/AbstractBill.cs @@ -3,7 +3,7 @@ namespace RealCity.Util.Politic { /// - /// 议案 + /// 议案(抽象的) /// public abstract class AbstractBill : IBill { diff --git a/Util/Politic/Bills.cs b/Util/Politic/Bills.cs index 5959a99..c8be3c9 100644 --- a/Util/Politic/Bills.cs +++ b/Util/Politic/Bills.cs @@ -1,6 +1,4 @@ using System; -using System.Linq; -using ColossalFramework; using RealCity.Util.Politic.Bill; namespace RealCity.Util.Politic @@ -49,7 +47,7 @@ public static class Bills }; public static IBill GetRandomBill() { - return AllBills[r.Next(AllBills.Length)]; + return AllBills.GetRandomElement(r); } public static IBill GetReversedBill(IBill bill) { diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs index 3c4fe8e..a7b716c 100644 --- a/Util/Politic/Election.cs +++ b/Util/Politic/Election.cs @@ -1,73 +1,30 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using RealCity.Util.Politic.ElectionUtil; +using System; namespace RealCity.Util.Politic { /// /// 选举 /// - public class Election + public static class Election { - private Random r = new Random(); - private IParty[] parties; - //得票计数器 - private int[] ticketCounter; - public Election(IParty[] parties) { - if (parties.Length <= 0) - throw new ArgumentException(); - this.parties = parties; - this.ticketCounter = new int[parties.Length]; + private static IParty[] Parties { get; set; } + /// + /// 选举信息 + /// + public static ElectionInfo Info { get; private set; } + + + public static void NextElection() { + Info = new ElectionInfo(Parties); } + /// /// 是否即将选举 /// /// public static bool IsOnElection() { return Politics.IsOnElection(); - //return Politics.nextElectionInterval == 1; - } - private void CalcPartiesWinChance() { - - } - private void VoteTicket() { - // It's Roulette Wheel Selection - // 大转盘,政党的WinChance越大,得票机率就越大 - - int i = 0; - int segment = this.parties[0].WinChance; - int vote = r.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; - /* - * Party A P.B P.C - * |<--------------->|<------>|<-------->| - * ^ vote ^ length is the sum of party.WinChance - * ^ initial Segment - * |<--------------->|<------>|<-------->| - * ^ S move forward, now vote is smaller than S, which means P.B gets 1 ticket - */ - - while (i < parties.Length) { - if (vote < segment) { - this.ticketCounter[i]++; - break; - } - segment += parties[++i].WinChance; - } - - #region old codes - //if (vote < Politics.cPartyChance) { - // Politics.cPartyTickets++; - //} else if (vote < Politics.cPartyChance + Politics.gPartyChance) { - // Politics.gPartyTickets++; - //} else if (vote < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) { - // Politics.sPartyTickets++; - //} else if (vote < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) { - // Politics.lPartyTickets++; - //} else { - // Politics.nPartyTickets++; - //} - #endregion } } } diff --git a/Util/Politic/ElectionUtil/ElectionInfo.cs b/Util/Politic/ElectionUtil/ElectionInfo.cs new file mode 100644 index 0000000..85bb583 --- /dev/null +++ b/Util/Politic/ElectionUtil/ElectionInfo.cs @@ -0,0 +1,27 @@ +using System; + +namespace RealCity.Util.Politic.ElectionUtil +{ + /// + /// 选举信息 + /// + public class ElectionInfo + { + public int PartiesCount => this.Parties.Length; + public IParty[] Parties { get; } + /// + /// 得票计数器 + /// + public int[] TicketCounter { get; } + /// + /// 选举信息 + /// + /// 参选政党 + public ElectionInfo(IParty[] parties) { + if (parties.Length <= 0) + throw new ArgumentException("No party joins in an election."); + this.Parties = parties; + this.TicketCounter = new int[parties.Length]; + } + } +} diff --git a/Util/Politic/ElectionUtil/ElectionVoter.cs b/Util/Politic/ElectionUtil/ElectionVoter.cs new file mode 100644 index 0000000..5c2080c --- /dev/null +++ b/Util/Politic/ElectionUtil/ElectionVoter.cs @@ -0,0 +1,80 @@ +using System; +using System.Linq; + +namespace RealCity.Util.Politic.ElectionUtil +{ + /// + /// 选民 + /// + class ElectionVoter + { + private const int MaxTrandStrength = 300; + //private const int ChanceSum = 800; + + private Random r = new Random(); + + private Citizen citizen; + private int trandPartyIdx; + private int trendStrength; + + public uint CitizenId { get; } + public Citizen Citizen => this.citizen; + public uint HomeId { get; } + public ElectionInfo EleInfo { get; } + public PartyInterestCalc[] Interests{ get; } + public int[] Chance { get; } + public ElectionVoter(uint citizenID, ref Citizen citizen, uint homeID,ElectionInfo eleInfo) { + this.CitizenId = citizenID; + this.citizen = citizen; + this.HomeId = homeID; + this.EleInfo = eleInfo; + + this.Interests = new PartyInterestCalc[this.EleInfo.PartiesCount]; + for (int i = 0; i < this.Interests.Length; i++) { + this.Interests[i] = new PartyInterestCalc( + this.EleInfo.Parties[i], + ref this.citizen, + this.CitizenId, + this.HomeId + ); + } + this.Chance = new int[this.EleInfo.PartiesCount]; + } + public void VoteTicket() { + int i; + for (i = 0; i < this.EleInfo.PartiesCount; i++) { + this.Interests[i].Calc(); + this.Chance[i] = this.Interests[i].Val; + } + // choose a lucky party as trend party + this.trandPartyIdx = this.r.Next(this.EleInfo.PartiesCount); + this.trendStrength = this.r.Next(MaxTrandStrength); + // add its chance + this.Chance[trandPartyIdx] += this.trendStrength; + + // It's Roulette Wheel Selection + // 大转盘,政党的Chance越大,得票机率就越大 + + i = 0; + int segment = this.Chance[0]; + // assert this.Chance.Sum() == 800 ? + int vote = this.r.Next(this.Chance.Sum() + this.trendStrength); + /* + * Party A P.B P.C + * |<--------------->|<------>|<-------->| + * ^ vote ^ length is the sum of party.WinChance + * ^ initial Segment + * |<--------------->|<------>|<-------->| + * ^ S move forward, now vote is smaller than S, which means P.B gets 1 ticket + */ + + while (i < this.EleInfo.Parties.Length) { + if (vote < segment) { + this.EleInfo.TicketCounter[i]++; + break; + } + segment += this.Chance[0]; + } + } + } +} diff --git a/Util/Politic/PartyInterestCalc.cs b/Util/Politic/ElectionUtil/PartyInterestCalc.cs similarity index 56% rename from Util/Politic/PartyInterestCalc.cs rename to Util/Politic/ElectionUtil/PartyInterestCalc.cs index 63192b2..9e30d5d 100644 --- a/Util/Politic/PartyInterestCalc.cs +++ b/Util/Politic/ElectionUtil/PartyInterestCalc.cs @@ -2,20 +2,20 @@ using RealCity.CustomAI; using RealCity.CustomData; -namespace RealCity.Util.Politic +namespace RealCity.Util.Politic.ElectionUtil { /// /// 政党兴趣度计算 /// public class PartyInterestCalc { - private IParty party; private PartyInterestData partyInterestData; private Citizen citizen; private uint citizenId; private uint homeId; - private ushort val = 0; + public IParty Party { get; } + public ushort Val { get; private set; } = 0; /// /// 政党兴趣度计算 @@ -25,7 +25,7 @@ public class PartyInterestCalc /// 市民Id /// 家庭Id public PartyInterestCalc(IParty party, ref Citizen citizen, uint citizenId, uint homeId) { - this.party = party; + this.Party = party; this.partyInterestData = party.GetPartyInterestData(); this.citizen = citizen; this.citizenId = citizenId; @@ -36,20 +36,20 @@ public PartyInterestCalc(IParty party, ref Citizen citizen, uint citizenId, uint /// 计算市民对政党的兴趣度 /// public void Calc() { - this.val += GetFromEducationLevel(this.citizen.EducationLevel); - this.val += GetFromSubService(this.citizen.m_workBuilding); - this.val += GetFromFamilyMoney(CitizenUnitData.familyMoney[this.homeId]); - this.val += GetFromAgeGroup(Citizen.GetAgeGroup(this.citizen.Age)); - this.val += GetFromGender(Citizen.GetGender(this.citizenId)); + this.Val += GetFromEducationLevel(this.citizen.EducationLevel); + this.Val += GetFromSubService(this.citizen.m_workBuilding); + this.Val += GetFromFamilyMoney(CitizenUnitData.familyMoney[this.homeId]); + this.Val += GetFromAgeGroup(Citizen.GetAgeGroup(this.citizen.Age)); + this.Val += GetFromGender(Citizen.GetGender(this.citizenId)); } /// /// 增加政党胜算 /// public void AddPartyWinChance() { - this.party.AddWinChance(this.val); + this.Party.AddWinChance(this.Val); //啊这...不加会出bug吗 - this.val = default; + this.Val = default; } /// @@ -79,54 +79,53 @@ private ushort GetFromSubService(ushort workplaceId) { //自定义行业:在政府工作 if (RealCityResidentAI.IsGoverment(workplaceId)) { choiceIndex = 1; + } else { + ItemClass workplaceItemClass = Singleton.instance + .m_buildings.m_buffer[workplaceId].Info.m_class; + //其他游戏内置行业 + switch (workplaceItemClass.m_subService) { + case ItemClass.SubService.CommercialLow: + case ItemClass.SubService.CommercialHigh: + if (workplaceItemClass.m_level == ItemClass.Level.Level1) { + choiceIndex = 2; + } else if (workplaceItemClass.m_level == ItemClass.Level.Level2) { + choiceIndex = 3; + } else if (workplaceItemClass.m_level == ItemClass.Level.Level3) { + choiceIndex = 4; + } + break; + case ItemClass.SubService.CommercialTourist: + case ItemClass.SubService.CommercialLeisure: + choiceIndex = 5; break; + case ItemClass.SubService.CommercialEco: + choiceIndex = 6; break; + case ItemClass.SubService.IndustrialGeneric: + if (workplaceItemClass.m_level == ItemClass.Level.Level1) { + choiceIndex = 7; + } else if (workplaceItemClass.m_level == ItemClass.Level.Level2) { + choiceIndex = 8; + } else if (workplaceItemClass.m_level == ItemClass.Level.Level3) { + choiceIndex = 9; + } + break; + case ItemClass.SubService.IndustrialFarming: + case ItemClass.SubService.IndustrialForestry: + case ItemClass.SubService.IndustrialOil: + case ItemClass.SubService.IndustrialOre: + choiceIndex = 10; break; + case ItemClass.SubService.OfficeGeneric: + if (workplaceItemClass.m_level == ItemClass.Level.Level1) { + choiceIndex = 11; + } else if (workplaceItemClass.m_level == ItemClass.Level.Level2) { + choiceIndex = 12; + } else if (workplaceItemClass.m_level == ItemClass.Level.Level3) { + choiceIndex = 13; + } + break; + case ItemClass.SubService.OfficeHightech: + choiceIndex = 14; break; + } } - // here is not very nice - ItemClass workplaceItemClass = Singleton.instance - .m_buildings.m_buffer[workplaceId].Info.m_class; - //其他游戏内置行业 - switch (workplaceItemClass.m_subService) { - case ItemClass.SubService.CommercialLow: - case ItemClass.SubService.CommercialHigh: - if (workplaceItemClass.m_level == ItemClass.Level.Level1) { - choiceIndex = 2; - } else if (workplaceItemClass.m_level == ItemClass.Level.Level2) { - choiceIndex = 3; - } else if (workplaceItemClass.m_level == ItemClass.Level.Level3) { - choiceIndex = 4; - } - break; - case ItemClass.SubService.CommercialTourist: - case ItemClass.SubService.CommercialLeisure: - choiceIndex = 5; break; - case ItemClass.SubService.CommercialEco: - choiceIndex = 6; break; - case ItemClass.SubService.IndustrialGeneric: - if (workplaceItemClass.m_level == ItemClass.Level.Level1) { - choiceIndex = 7; - } else if (workplaceItemClass.m_level == ItemClass.Level.Level2) { - choiceIndex = 8; - } else if (workplaceItemClass.m_level == ItemClass.Level.Level3) { - choiceIndex = 9; - } - break; - case ItemClass.SubService.IndustrialFarming: - case ItemClass.SubService.IndustrialForestry: - case ItemClass.SubService.IndustrialOil: - case ItemClass.SubService.IndustrialOre: - choiceIndex = 10; break; - case ItemClass.SubService.OfficeGeneric: - if (workplaceItemClass.m_level == ItemClass.Level.Level1) { - choiceIndex = 11; - } else if (workplaceItemClass.m_level == ItemClass.Level.Level2) { - choiceIndex = 12; - } else if (workplaceItemClass.m_level == ItemClass.Level.Level3) { - choiceIndex = 13; - } - break; - case ItemClass.SubService.OfficeHightech: - choiceIndex = 14; break; - } - return this.partyInterestData.SubService[choiceIndex]; } diff --git a/Util/Politic/Government.cs b/Util/Politic/Government.cs new file mode 100644 index 0000000..cabda1e --- /dev/null +++ b/Util/Politic/Government.cs @@ -0,0 +1,16 @@ +namespace RealCity.Util.Politic +{ + /// + /// 政府 + /// + public class Government + { + private Government _inst; + + private IParty[] rulingParty; + // refer RealCityEconomyExtension.cs + public void HoldMeeting() { + + } + } +} diff --git a/Util/Politic/IParty.cs b/Util/Politic/IParty.cs index 3ef9957..b31d310 100644 --- a/Util/Politic/IParty.cs +++ b/Util/Politic/IParty.cs @@ -12,5 +12,6 @@ public interface IParty ushort WinChance { get; } ushort Ticket { get; } ushort SeatCount { get; } + ushort Id { get; } } } \ No newline at end of file diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index a1be933..636e015 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -16,13 +16,15 @@ public class Party : IParty public ushort WinChance { get; private set; } = default; public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; + public ushort Id { get; } /// /// 政党 /// /// 民众对政党的兴趣度 /// 政党对政策的态度 - public Party(PartyInterestData interestData, Dictionary billAttitude) { + public Party(ushort id,PartyInterestData interestData, Dictionary billAttitude) { + this.Id = id; this.interestData = interestData; this.billAttitude = billAttitude; } diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs index c5d76f3..bc80c62 100644 --- a/Util/Politic/PartyFactory.cs +++ b/Util/Politic/PartyFactory.cs @@ -9,6 +9,11 @@ public class PartyFactory { //TODO: Too much similar codes, need extract same parts + /// + /// 下一个政党的Id + /// + public ushort NextPartyId { get; private set; } = 0; + public IParty MakeCParty() { var billAttitudeMap = new Dictionary(); VoteResult raiseResidentTax = new VoteResult(55, 40, 5); @@ -26,10 +31,11 @@ public IParty MakeCParty() { billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefit, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + this.NextPartyId++, new PartyInterestData( new byte[4] { 30, 20, 10, 5 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, @@ -59,10 +65,11 @@ public IParty MakeGParty() { billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefit, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + this.NextPartyId++, new PartyInterestData( new byte[4] { 0, 10, 20, 25 }, new byte[15] { 0, 20, 10, 15, 20, 30, 10, 0, 5, 10, 5, 30, 35, 40, 50, }, @@ -92,10 +99,11 @@ public IParty MakeSParty() { billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefit, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + this.NextPartyId++, new PartyInterestData( new byte[4] { 10, 25, 30, 40 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, @@ -125,10 +133,11 @@ public IParty MakeLParty() { billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefit, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + this.NextPartyId++, new PartyInterestData( new byte[4] { 10, 20, 30, 25 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, @@ -158,10 +167,11 @@ public IParty MakeNParty() { billAttitudeMap.Add(Bills.ReduceCommercialTax, reduceCommercialTax); billAttitudeMap.Add(Bills.RiseIndustryTax, raiseIndustryTax); billAttitudeMap.Add(Bills.ReduceIndustryTax, reduceIndustryTax); - billAttitudeMap.Add(Bills.RiseBenefitOffset, raiseBenefitOffset); + billAttitudeMap.Add(Bills.RiseBenefit, raiseBenefitOffset); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + this.NextPartyId++, new PartyInterestData( new byte[4] { 50, 25, 10, 5 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, diff --git a/Util/Politic/PartyInterestData.cs b/Util/Politic/PartyInterestData.cs index 8b69655..0c45f46 100644 --- a/Util/Politic/PartyInterestData.cs +++ b/Util/Politic/PartyInterestData.cs @@ -1,6 +1,4 @@ using RealCity.Attributes; -using RealCity.Util; -using System; namespace RealCity.Util.Politic { diff --git a/Util/Politic/Vote.cs b/Util/Politic/Vote.cs index 097c484..890f303 100644 --- a/Util/Politic/Vote.cs +++ b/Util/Politic/Vote.cs @@ -54,7 +54,7 @@ public VoteResult Calc() { disagree -= Politics.Parties.Length * residentTax; noVote += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[this.bill].NoVote; + return p.GetBillAttitude()[this.bill].Neutral; }); noVote -= Politics.Parties.Length * residentTax; } diff --git a/Util/Politic/VoteResult.cs b/Util/Politic/VoteResult.cs index ad5c9f5..f1befd3 100644 --- a/Util/Politic/VoteResult.cs +++ b/Util/Politic/VoteResult.cs @@ -3,7 +3,7 @@ /// /// 投票结果 /// - public class VoteResult + public class VoteResult //TODO: consider a better name { /// /// 同意 @@ -16,17 +16,17 @@ public class VoteResult /// /// 弃权 /// - public int NoVote { get; } + public int Neutral { get; } /// /// 投票结果 /// /// 同意 /// 反对 - /// 弃权 - public VoteResult(int agree, int disagree, int noVote) { + /// 弃权 + public VoteResult(int agree, int disagree, int neutral) { this.Agree = agree; this.Disagree = disagree; - this.NoVote = noVote; + this.Neutral = neutral; } } } diff --git a/Util/Politics.cs b/Util/Politics.cs index c59825d..605105f 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -1,6 +1,5 @@ using ColossalFramework; using ColossalFramework.UI; -using RealCity.CustomData; using RealCity.Util.Politic; using System; using System.Collections.Generic; @@ -20,7 +19,8 @@ public class Politics { private static IParty sParty; private static IParty lParty; private static IParty nParty; - public static IParty[] Parties => new IParty[] { cParty, gParty, sParty, lParty, nParty }; + + public static IParty[] Parties; public static void ResetWinChance() { Parties.ForEach(p => p.ResetWinChance()); } @@ -35,7 +35,7 @@ public static int GetAllTicket() { }); } public static bool IsOnElection() { - return nextElectionInterval == 1; + return nextMeetingInterval == 1; } /// @@ -203,7 +203,7 @@ public static bool IsOverVotingAge(ref Citizen citizen) { public static ushort nPartySeats = 0; //下一次_____倒计时 - public static short nextElectionInterval = 0; + public static short nextMeetingInterval = 0; public static bool case1 = false; public static bool case2 = false; @@ -230,8 +230,8 @@ public static bool IsOverVotingAge(ref Citizen citizen) { //工业税(0-20) public static int industryTax = 20; //社会福利(0-100) - public static short benefitOffset = 0; - + public static int benefitOffset = 0; + public static void DataInit() { PartyFactory factory = new PartyFactory(); @@ -240,6 +240,13 @@ public static void DataInit() { sParty = factory.MakeSParty(); lParty = factory.MakeLParty(); nParty = factory.MakeNParty(); + IParty[] ps = new IParty[] { + cParty, gParty, sParty, lParty, nParty + }; + // sort ps using p.Id as key + // maybe this can help improve performance + Array.Sort(ps, ps.Select(p => p.Id).ToArray()); + Parties = ps; } public static void Save(ref byte[] saveData) { @@ -266,7 +273,7 @@ public static void Save(ref byte[] saveData) { SaveAndRestore.SaveData(ref i, nPartySeats, ref saveData); //14 - SaveAndRestore.SaveData(ref i, nextElectionInterval, ref saveData); + SaveAndRestore.SaveData(ref i, nextMeetingInterval, ref saveData); SaveAndRestore.SaveData(ref i, case1, ref saveData); SaveAndRestore.SaveData(ref i, case2, ref saveData); SaveAndRestore.SaveData(ref i, case3, ref saveData); @@ -318,7 +325,7 @@ public static void Load(ref byte[] saveData) { SaveAndRestore.LoadData(ref i, saveData, ref lPartySeats); SaveAndRestore.LoadData(ref i, saveData, ref nPartySeats); - SaveAndRestore.LoadData(ref i, saveData, ref nextElectionInterval); + SaveAndRestore.LoadData(ref i, saveData, ref nextMeetingInterval); SaveAndRestore.LoadData(ref i, saveData, ref case1); SaveAndRestore.LoadData(ref i, saveData, ref case2); From 202a4e600f490f08ac95f66dee85a016c7d0800d Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Thu, 3 Sep 2020 17:09:01 +0800 Subject: [PATCH 30/38] Add Government, decoupling election etc --- ...esidentAICitizenUnitSimulationStepPatch.cs | 2 +- RealCity.csproj | 5 +- RealCityEconomyExtension.cs | 97 +++++++------ Util/Politic/Election.cs | 5 +- Util/Politic/ElectionUtil/ElectionInfo.cs | 8 +- Util/Politic/Government.cs | 128 +++++++++++++++++- Util/Politic/IGovernment.cs | 24 ++++ Util/Politic/IParty.cs | 4 +- Util/Politic/IVoteRusult.cs | 36 +++++ Util/Politic/{Vote.cs => ParliamentalVote.cs} | 33 ++--- Util/Politic/Party.cs | 6 +- Util/Politic/PartyFactory.cs | 5 + Util/Politic/VoteResult.cs | 22 +-- Util/Politic/gov-desc.txt | 18 +++ Util/Politics.cs | 2 + 15 files changed, 303 insertions(+), 92 deletions(-) create mode 100644 Util/Politic/IGovernment.cs create mode 100644 Util/Politic/IVoteRusult.cs rename Util/Politic/{Vote.cs => ParliamentalVote.cs} (89%) create mode 100644 Util/Politic/gov-desc.txt diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index b67170d..2f2e40e 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -381,7 +381,7 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { if (Politics.IsOnElection() && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age))) { - ElectionVoter voter = new ElectionVoter(citizenID, ref citizen, homeID,); + ElectionVoter voter = new ElectionVoter(citizenID, ref citizen, homeID, Election.CurrentElectionInfo); Politics.ResetWinChance(); Politics.Parties.ForEach(p => { diff --git a/RealCity.csproj b/RealCity.csproj index 4b9a388..c706971 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -112,6 +112,8 @@ + + @@ -213,7 +215,7 @@ - + @@ -227,6 +229,7 @@ + diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 543e4ec..4555d97 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -5,6 +5,7 @@ using RealCity.UI; using RealCity.Util; using RealCity.Util.Politic; +using System; using System.Linq; using System.Reflection; using UnityEngine; @@ -138,17 +139,19 @@ public void CaculateCitizenTransportFee() { public void CitizenStatus() { if (Politics.nextMeetingInterval == 0) { - Election e = new Election(Politics.Parties); - + Election.NextElection(); - GetSeats(); - CreateGoverment(); + Government.Instance.UpdateSeats(Election.CurrentElectionInfo); + Government.Instance.UpdateGovType(); + //GetSeats(); + //CreateGoverment(); } if ((MainDataStore.updateMoneyCount & 3u) == 0) { if (Politics.nextMeetingInterval != 0) { - HoldMeeting(); + Government.Instance.HoldMeeting(); + //HoldMeeting(); } } @@ -238,6 +241,7 @@ public byte ReturnOtherIdx(byte orgIdx) { } } + [Obsolete("call Government.Instance.HoldMeeting() instead")] public void HoldMeeting() { //int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; int temp = Politics.GetAllSeatCount(); @@ -652,7 +656,7 @@ public void VoteResult(int billId) { } } } - + [Obsolete("call Governemt.Instance.UpdateGovType() instead")] public void CreateGoverment() { if (Politics.cPartySeats >= 50) { //c only @@ -740,49 +744,52 @@ public void CreateGoverment() { } } + [Obsolete("call Government.Instance.UpdateSeats() instead")] /// /// 更新议会席位数量 /// public void GetSeats() { - //总票数 - //int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; - int cnt = Politics.GetAllTicket(); - if (cnt != 0) { - Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / cnt); - Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / cnt); - Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / cnt); - Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / cnt); - Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / cnt); - } else { - Politics.cPartySeats = 0; - Politics.gPartySeats = 0; - Politics.sPartySeats = 0; - Politics.lPartySeats = 0; - Politics.nPartySeats = 0; - } - Politics.cPartyTickets = 0; - Politics.gPartyTickets = 0; - Politics.sPartyTickets = 0; - Politics.lPartyTickets = 0; - Politics.nPartyTickets = 0; - - //allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; - cnt = Politics.GetAllSeatCount(); - if (cnt < 99) { - System.Random rand = new System.Random(); - switch (rand.Next(5)) { - case 0: - Politics.cPartySeats += (ushort)(99 - cnt); break; - case 1: - Politics.gPartySeats += (ushort)(99 - cnt); break; - case 2: - Politics.sPartySeats += (ushort)(99 - cnt); break; - case 3: - Politics.lPartySeats += (ushort)(99 - cnt); break; - case 4: - Politics.nPartySeats += (ushort)(99 - cnt); break; - } - } + + Government.Instance.UpdateSeats(Election.CurrentElectionInfo); + ////总票数 + ////int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; + //int cnt = Politics.GetAllTicket(); + //if (cnt != 0) { + // Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / cnt); + // Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / cnt); + // Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / cnt); + // Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / cnt); + // Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / cnt); + //} else { + // Politics.cPartySeats = 0; + // Politics.gPartySeats = 0; + // Politics.sPartySeats = 0; + // Politics.lPartySeats = 0; + // Politics.nPartySeats = 0; + //} + //Politics.cPartyTickets = 0; + //Politics.gPartyTickets = 0; + //Politics.sPartyTickets = 0; + //Politics.lPartyTickets = 0; + //Politics.nPartyTickets = 0; + + ////allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + //cnt = Politics.GetAllSeatCount(); + //if (cnt < 99) { + // System.Random rand = new System.Random(); + // switch (rand.Next(5)) { + // case 0: + // Politics.cPartySeats += (ushort)(99 - cnt); break; + // case 1: + // Politics.gPartySeats += (ushort)(99 - cnt); break; + // case 2: + // Politics.sPartySeats += (ushort)(99 - cnt); break; + // case 3: + // Politics.lPartySeats += (ushort)(99 - cnt); break; + // case 4: + // Politics.nPartySeats += (ushort)(99 - cnt); break; + // } + //} } public static bool Can16timesUpdate(ushort ID) { diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs index a7b716c..8ff751d 100644 --- a/Util/Politic/Election.cs +++ b/Util/Politic/Election.cs @@ -1,5 +1,4 @@ using RealCity.Util.Politic.ElectionUtil; -using System; namespace RealCity.Util.Politic { @@ -12,11 +11,11 @@ public static class Election /// /// 选举信息 /// - public static ElectionInfo Info { get; private set; } + public static ElectionInfo CurrentElectionInfo { get; private set; } public static void NextElection() { - Info = new ElectionInfo(Parties); + CurrentElectionInfo = new ElectionInfo(Parties); } /// diff --git a/Util/Politic/ElectionUtil/ElectionInfo.cs b/Util/Politic/ElectionUtil/ElectionInfo.cs index 85bb583..0a717ce 100644 --- a/Util/Politic/ElectionUtil/ElectionInfo.cs +++ b/Util/Politic/ElectionUtil/ElectionInfo.cs @@ -1,4 +1,6 @@ -using System; +using ColossalFramework.UI; +using System; +using System.Linq; namespace RealCity.Util.Politic.ElectionUtil { @@ -23,5 +25,9 @@ public ElectionInfo(IParty[] parties) { this.Parties = parties; this.TicketCounter = new int[parties.Length]; } + public int GetAllTickets() { + // possible overflow? + return TicketCounter.Sum(); + } } } diff --git a/Util/Politic/Government.cs b/Util/Politic/Government.cs index cabda1e..abf4af6 100644 --- a/Util/Politic/Government.cs +++ b/Util/Politic/Government.cs @@ -1,16 +1,134 @@ -namespace RealCity.Util.Politic +using RealCity.Util.Politic.ElectionUtil; +using System.Linq; + +namespace RealCity.Util.Politic { /// /// 政府 /// - public class Government + public class Government : IGovernment { - private Government _inst; + private const int MinSeatCount = 99; + public static IGovernment Instance { get; } + + private IBill currentBill = default; - private IParty[] rulingParty; + public IParty[] Parties { get; private set; } + public GovernmentType GovernmentType { get; private set; } + public IParty[] RulingParties { get; private set; } // refer RealCityEconomyExtension.cs - public void HoldMeeting() { + public int[] Seats { get; private set; } + public int AllSeatCount => this.Seats.Sum(); + public void UpdateSeats(ElectionInfo info) { + int cnt = info.GetAllTickets(); + this.Seats = new int[info.PartiesCount]; + for (int i = 0; i < info.PartiesCount; i++) { + this.Seats[i] = GetSeatCount(info.TicketCounter[i], ref cnt); + } + this.FixSeatCount(); + + #region old codes + ////int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; + //int cnt = Politics.GetAllTicket(); + //if (cnt != 0) { + // Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / cnt); + // Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / cnt); + // Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / cnt); + // Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / cnt); + // Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / cnt); + //} else { + // Politics.cPartySeats = 0; + // Politics.gPartySeats = 0; + // Politics.sPartySeats = 0; + // Politics.lPartySeats = 0; + // Politics.nPartySeats = 0; + //} + //Politics.cPartyTickets = 0; + //Politics.gPartyTickets = 0; + //Politics.sPartyTickets = 0; + //Politics.lPartyTickets = 0; + //Politics.nPartyTickets = 0; + + ////allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + //cnt = Politics.GetAllSeatCount(); + //if (cnt < 99) { + // System.Random rand = new System.Random(); + // switch (rand.Next(5)) { + // case 0: + // Politics.cPartySeats += (ushort)(99 - cnt); break; + // case 1: + // Politics.gPartySeats += (ushort)(99 - cnt); break; + // case 2: + // Politics.sPartySeats += (ushort)(99 - cnt); break; + // case 3: + // Politics.lPartySeats += (ushort)(99 - cnt); break; + // case 4: + // Politics.nPartySeats += (ushort)(99 - cnt); break; + // } + //} + #endregion + } + public void UpdateGovType() { + bool isOk = default; + int halfSeatCount = (MinSeatCount >> 1) + 1; + for (int i = 0; i < this.Seats.Length; i++) { + if (this.Seats[i] >= halfSeatCount) { + this.GovernmentType = GovernmentType.Single; + this.RulingParties = new IParty[] { this.Parties[i] }; + isOk = true; + } + } + if (isOk == false) { + // bad codes + int left, wideLeft, right; + left = wideLeft = right = default; + for (int i = 0; i < this.Seats.Length; i++) { + if (this.Parties[i].Name == "Green" || this.Parties[i].Name == "Socialist") { + left += this.Seats[i]; + } else if (this.Parties[i].Name == "Communist") { + wideLeft += this.Seats[i]; + } else if (this.Parties[i].Name == "Liberal" || this.Parties[i].Name == "National") { + right += this.Seats[i]; + } + } + wideLeft += left; + if(left>= halfSeatCount) { + this.GovernmentType = GovernmentType.LeftUnion; + }else if(wideLeft>= halfSeatCount) { + this.GovernmentType = GovernmentType.WideLeftUnion; + } else if(right>= halfSeatCount) { + this.GovernmentType = GovernmentType.RightUnion; + } else { + this.GovernmentType = GovernmentType.Grand; + } + } + } + public ParliamentalVote HoldMeeting() { + if(this.currentBill == null) { + this.currentBill = Bills.GetRandomBill(); + } + ParliamentalVote v = new ParliamentalVote(this.Parties,Bills.GetAnotherBill(this.currentBill)); + if (v.VoteResult.IsApprovable) { + v.Implement(); + } + return v; + } + + private int GetSeatCount(int ticketCount, ref int ticketSum) { + return (int)(99 * ticketCount / ticketSum); + } + /// + /// 修正Seat数量至MinSeatCount个 + /// + private void FixSeatCount() { + int missingCount = MinSeatCount - this.AllSeatCount; + // if have missing seats + if (missingCount > 0) { + System.Random r = new System.Random(); + int idx = r.Next(this.Seats.Length); + this.Seats[idx] += missingCount; + } } } } diff --git a/Util/Politic/IGovernment.cs b/Util/Politic/IGovernment.cs new file mode 100644 index 0000000..0d2077c --- /dev/null +++ b/Util/Politic/IGovernment.cs @@ -0,0 +1,24 @@ +using RealCity.Util.Politic.ElectionUtil; + +namespace RealCity.Util.Politic +{ + public interface IGovernment + { + int[] Seats { get; } + int AllSeatCount { get; } + IParty[] Parties { get; } + GovernmentType GovernmentType { get; } + IParty[] RulingParties { get; } + void UpdateSeats(ElectionInfo info); + void UpdateGovType(); + ParliamentalVote HoldMeeting(); + } + public enum GovernmentType + { + Single, + LeftUnion, + WideLeftUnion, + RightUnion, + Grand, + } +} diff --git a/Util/Politic/IParty.cs b/Util/Politic/IParty.cs index b31d310..e7b6245 100644 --- a/Util/Politic/IParty.cs +++ b/Util/Politic/IParty.cs @@ -1,5 +1,4 @@ -using RealCity.CustomData; -using System.Collections.Generic; +using System.Collections.Generic; namespace RealCity.Util.Politic { @@ -9,6 +8,7 @@ public interface IParty Dictionary GetBillAttitude(); void AddWinChance(ushort val); void ResetWinChance(); + string Name { get; } ushort WinChance { get; } ushort Ticket { get; } ushort SeatCount { get; } diff --git a/Util/Politic/IVoteRusult.cs b/Util/Politic/IVoteRusult.cs new file mode 100644 index 0000000..5103001 --- /dev/null +++ b/Util/Politic/IVoteRusult.cs @@ -0,0 +1,36 @@ +namespace RealCity.Util.Politic +{ + /// + /// 投票结果(抽象的) + /// + public abstract class AbstractVoteResult //TODO: consider a better name + { + /// + /// 同意 + /// + public int Agree { get; } + /// + /// 反对 + /// + public int Disagree { get; } + /// + /// 弃权 + /// + public int Neutral { get; } + public int Sum => this.Agree + this.Disagree + this.Neutral; + + // define under what circumstances will the result be approvable here + public abstract bool IsApprovable { get; } + /// + /// 投票结果 + /// + /// 同意 + /// 反对 + /// 弃权 + public AbstractVoteResult(int agree, int disagree, int neutral) { + this.Agree = agree; + this.Disagree = disagree; + this.Neutral = neutral; + } + } +} diff --git a/Util/Politic/Vote.cs b/Util/Politic/ParliamentalVote.cs similarity index 89% rename from Util/Politic/Vote.cs rename to Util/Politic/ParliamentalVote.cs index 890f303..25ea669 100644 --- a/Util/Politic/Vote.cs +++ b/Util/Politic/ParliamentalVote.cs @@ -1,30 +1,30 @@ using ColossalFramework; -using System; -using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text; namespace RealCity.Util.Politic { /// /// 议会投票 /// - public class Vote + public class ParliamentalVote { - private IBill bill; private IParty[] parties; - public Vote(IBill bill) { - this.bill = bill; + public IBill Bill { get; } + public AbstractVoteResult VoteResult { get; private set; } + + public ParliamentalVote(IParty[] parties, IBill bill) { + this.parties = parties; + this.Bill = bill; } - //public Vote(IBill bill):this(bill, Politics.Parties) { } - //public Vote(IBill bill, IParty[] parties) { } + public void Implement() { + this.Bill.Implement(); + } - public VoteResult Calc() { + public AbstractVoteResult Calc() { int agree = default; int disagree = default; int noVote = default; @@ -44,22 +44,23 @@ public VoteResult Calc() { if (seatCount == 99) { agree += Politics.Parties.Sum(p => { // - return p.GetBillAttitude()[this.bill].Agree; + return p.GetBillAttitude()[this.Bill].Agree; }); agree += (Politics.Parties.Length * residentTax - moneyOffset - citizenOffset); disagree += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[this.bill].Disagree; + return p.GetBillAttitude()[this.Bill].Disagree; }); disagree -= Politics.Parties.Length * residentTax; noVote += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[this.bill].Neutral; + return p.GetBillAttitude()[this.Bill].Neutral; }); noVote -= Politics.Parties.Length * residentTax; } - - return new VoteResult(agree, disagree, noVote); + AbstractVoteResult result = new VoteResult(agree, disagree, noVote); + this.VoteResult = result; + return result; } private void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, ref int buildingOffset, ref int commBuildingOffset) { diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index 636e015..5c2056f 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -13,6 +13,7 @@ public class Party : IParty { private PartyInterestData interestData; private Dictionary billAttitude; + public string Name { get; } public ushort WinChance { get; private set; } = default; public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; @@ -21,9 +22,12 @@ public class Party : IParty /// /// 政党 /// + /// 名称 + /// Id /// 民众对政党的兴趣度 /// 政党对政策的态度 - public Party(ushort id,PartyInterestData interestData, Dictionary billAttitude) { + public Party(string name, ushort id,PartyInterestData interestData, Dictionary billAttitude) { + this.Name = name; this.Id = id; this.interestData = interestData; this.billAttitude = billAttitude; diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs index bc80c62..45c1485 100644 --- a/Util/Politic/PartyFactory.cs +++ b/Util/Politic/PartyFactory.cs @@ -35,6 +35,7 @@ public IParty MakeCParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + "Communist", this.NextPartyId++, new PartyInterestData( new byte[4] { 30, 20, 10, 5 }, @@ -69,6 +70,7 @@ public IParty MakeGParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + "Green", this.NextPartyId++, new PartyInterestData( new byte[4] { 0, 10, 20, 25 }, @@ -103,6 +105,7 @@ public IParty MakeSParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + "Socialist", this.NextPartyId++, new PartyInterestData( new byte[4] { 10, 25, 30, 40 }, @@ -137,6 +140,7 @@ public IParty MakeLParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + "Liberal", this.NextPartyId++, new PartyInterestData( new byte[4] { 10, 20, 30, 25 }, @@ -171,6 +175,7 @@ public IParty MakeNParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( + "National", this.NextPartyId++, new PartyInterestData( new byte[4] { 50, 25, 10, 5 }, diff --git a/Util/Politic/VoteResult.cs b/Util/Politic/VoteResult.cs index f1befd3..4eb99ea 100644 --- a/Util/Politic/VoteResult.cs +++ b/Util/Politic/VoteResult.cs @@ -3,30 +3,18 @@ /// /// 投票结果 /// - public class VoteResult //TODO: consider a better name + public class VoteResult : AbstractVoteResult { - /// - /// 同意 - /// - public int Agree { get; } - /// - /// 反对 - /// - public int Disagree { get; } - /// - /// 弃权 - /// - public int Neutral { get; } + public override bool IsApprovable => this.Agree >= (this.Sum >> 1); /// /// 投票结果 /// /// 同意 /// 反对 /// 弃权 - public VoteResult(int agree, int disagree, int neutral) { - this.Agree = agree; - this.Disagree = disagree; - this.Neutral = neutral; + public VoteResult(int agree, int disagree, int neutral) + : base(agree, disagree, neutral) { + } } } diff --git a/Util/Politic/gov-desc.txt b/Util/Politic/gov-desc.txt new file mode 100644 index 0000000..82ad09f --- /dev/null +++ b/Util/Politic/gov-desc.txt @@ -0,0 +1,18 @@ +case1 +COMMUNIST +case2 +GREEN +case3 +SOCIALIST +case4 +LIBERAL +case5 +NATIONAL +case6 +LEFT_UNION GREEN SOCIALIST +case7 +WIDE_LEFT_UNION COMMUNIST GREEN SOCIALIST +case8 +RIGHT_UNION LIBERAL NATIONAL +none of above +ALL_UNION COMMUNIST GREEN SOCIALIST LIBERAL NATIONAL \ No newline at end of file diff --git a/Util/Politics.cs b/Util/Politics.cs index 605105f..be618dc 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -214,6 +214,8 @@ public static bool IsOverVotingAge(ref Citizen citizen) { public static bool case7 = false; public static bool case8 = false; + + //当前议案Id public static byte currentBillId = 14; //赞成票数 From 0226737008a600011bf505938b0f6e5c0162ffd6 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Fri, 4 Sep 2020 21:26:46 +0800 Subject: [PATCH 31/38] Add governmental meeting, update interfaces --- CustomData/CitizenData.cs | 88 +++---- Loader.cs | 2 +- Patch/BuildingAIVisitorEnterPatch.cs | 10 +- ...itizenManagerCreateCitizenInstancePatch.cs | 6 +- ...anagerReleaseCitizenImplementationPatch.cs | 2 +- .../CommercialBuildingAIVisitorEnterPatch.cs | 2 +- Patch/HumanAIEnterVehiclePatch.cs | 10 +- Patch/MarketAIVisitorEnterPatch.cs | 2 +- Patch/PassengerCarAIArriveAtTargetPatch.cs | 2 +- ...esidentAICitizenUnitSimulationStepPatch.cs | 232 +++++++++--------- Patch/TaxiAIUnloadPassengersPatch.cs | 8 +- Patch/TouristAISimulationStepPatch.cs | 2 +- RealCity.csproj | 6 +- RealCityEconomyExtension.cs | 170 ++++++------- UI/HumanUI.cs | 12 +- UI/TouristUI.cs | 6 +- Util/ArrayExtension.cs | 13 +- Util/CustomGameDataFactory.cs | 33 --- Util/Politic/AbstractBill.cs | 6 +- .../{IVoteRusult.cs => AbstractVoteResult.cs} | 20 +- Util/Politic/Bill/RiseBenefitBill.cs | 13 +- Util/Politic/Bill/RiseCommercialTaxBill.cs | 13 +- Util/Politic/Bill/RiseIndustryTaxBill.cs | 13 +- Util/Politic/Bill/RiseResidentTaxBill.cs | 13 +- Util/Politic/Bills.cs | 13 - Util/Politic/Election.cs | 2 +- Util/Politic/ElectionUtil/ElectionVoter.cs | 30 ++- Util/Politic/Government.cs | 72 +++--- Util/Politic/GovernmentalMeeting.cs | 181 ++++++++++++++ Util/Politic/IGovernment.cs | 4 +- Util/Politic/IGovernmentalMeeting.cs | 9 + Util/Politic/IParty.cs | 2 +- Util/Politic/ParliamentalVote.cs | 199 --------------- Util/Politic/Party.cs | 18 +- Util/Politic/PartyFactory.cs | 90 +++---- Util/Politic/VoteResult.cs | 8 + Util/SaveAndRestore.cs | 4 +- 37 files changed, 656 insertions(+), 660 deletions(-) delete mode 100644 Util/CustomGameDataFactory.cs rename Util/Politic/{IVoteRusult.cs => AbstractVoteResult.cs} (61%) create mode 100644 Util/Politic/GovernmentalMeeting.cs create mode 100644 Util/Politic/IGovernmentalMeeting.cs delete mode 100644 Util/Politic/ParliamentalVote.cs diff --git a/CustomData/CitizenData.cs b/CustomData/CitizenData.cs index 293864d..ca24ac9 100644 --- a/CustomData/CitizenData.cs +++ b/CustomData/CitizenData.cs @@ -3,54 +3,42 @@ namespace RealCity.CustomData { - public class CitizenData : ICustomGameData - { - public float[] citizenMoney = new float[1048576]; - public uint lastCitizenID = 0; - - private static CitizenData _inst = null; - public static CitizenData Instance { - get { - if (_inst == null) { - CustomGameDataFactory f = new CustomGameDataFactory(); - _inst = f.MakeCitizenData(); - } - return _inst; - } - } - public CitizenData() { } - - public static uint GetCitizenUnit(ushort buildingId) { - if (buildingId != 0) { - return Singleton.instance.m_buildings.m_buffer[buildingId].m_citizenUnits; - } - return 0u; - } - - public void DataInit() { - //for (int i = 0; i < citizenMoney.Length; i++) { - // citizenMoney[i] = 0f; - //} - this.citizenMoney.Initialize(); - } - - public void Save(ref byte[] saveData) { - //4194304 - int i = 0; - SaveAndRestore.SaveData(ref i, citizenMoney, ref saveData); - - if (i != saveData.Length) { - DebugLog.LogToFileOnly($"CitizenData Save Error: saveData.Length = {saveData.Length} actually = {i}"); - } - } - - public void Load(ref byte[] saveData) { - int i = 0; - SaveAndRestore.LoadData(ref i, saveData, ref citizenMoney); - - if (i != saveData.Length) { - DebugLog.LogToFileOnly($"CitizenData Load Error: saveData.Length = {saveData.Length} actually = {i}"); - } - } - } + public class CitizenData + { + public static float[] citizenMoney = new float[1048576]; + public static uint lastCitizenID = 0; + + public static void DataInit() { + //for (int i = 0; i < citizenMoney.Length; i++) { + // citizenMoney[i] = 0f; + //} + citizenMoney.Initialize(); + } + + public static void Save(ref byte[] saveData) { + //4194304 + int i = 0; + SaveAndRestore.SaveData(ref i, citizenMoney, ref saveData); + + if (i != saveData.Length) { + DebugLog.LogToFileOnly($"CitizenData Save Error: saveData.Length = {saveData.Length} actually = {i}"); + } + } + + public static void Load(ref byte[] saveData) { + int i = 0; + SaveAndRestore.LoadData(ref i, saveData, ref citizenMoney); + + if (i != saveData.Length) { + DebugLog.LogToFileOnly($"CitizenData Load Error: saveData.Length = {saveData.Length} actually = {i}"); + } + } + + public static uint GetCitizenUnit(ushort buildingId) { + if (buildingId != 0) { + return Singleton.instance.m_buildings.m_buffer[(int)buildingId].m_citizenUnits; + } + return 0u; + } + } } \ No newline at end of file diff --git a/Loader.cs b/Loader.cs index 48fc9d5..f73a648 100644 --- a/Loader.cs +++ b/Loader.cs @@ -86,7 +86,7 @@ public static void InitData() { BuildingData.DataInit(); CitizenUnitData.DataInit(); //CitizenData.DataInit(); - CitizenData.Instance.DataInit(); + CitizenData.DataInit(); RealCityEconomyManager.DataInit(); System.Random rand = new System.Random(); RealCityEconomyExtension.partyTrend = (byte)rand.Next(5); diff --git a/Patch/BuildingAIVisitorEnterPatch.cs b/Patch/BuildingAIVisitorEnterPatch.cs index 7c699c3..20da515 100644 --- a/Patch/BuildingAIVisitorEnterPatch.cs +++ b/Patch/BuildingAIVisitorEnterPatch.cs @@ -26,7 +26,7 @@ public static void Postfix(ushort buildingID, ref Building data, uint citizen) { if ((Singleton.instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { MainDataStore.outsideTouristMoney -= instance.m_events.m_buffer[(int)eventIndex].m_ticketPrice; } else { - CitizenData.Instance.citizenMoney[citizen] -= instance.m_events.m_buffer[(int)eventIndex].m_ticketPrice; + CitizenData.citizenMoney[citizen] -= instance.m_events.m_buffer[(int)eventIndex].m_ticketPrice; } } } @@ -68,9 +68,9 @@ public static void ProcessMonumentTourismTouristIncome(ref Building data, uint c } public static void ProcessMonumentTourismResidentIncome(ref Building data, uint citizen) { - int tourism_fee = (int)(0.2f * CitizenData.Instance.citizenMoney[citizen]); + int tourism_fee = (int)(0.2f * CitizenData.citizenMoney[citizen]); if (tourism_fee > 0) { - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] - tourism_fee); + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - tourism_fee); Singleton.instance.AddPrivateIncome(tourism_fee, ItemClass.Service.Commercial, ItemClass.SubService.CommercialTourist, ItemClass.Level.Level1, 114333); } } @@ -93,8 +93,8 @@ public static void ProcessParkIncome(ref Building data, uint citizen, bool isTou ticketPrice = 0; } } else { - if (CitizenData.Instance.citizenMoney[citizen] > ticketPrice) { - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] - ticketPrice); + if (CitizenData.citizenMoney[citizen] > ticketPrice) { + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - ticketPrice); Singleton.instance.AddResource(EconomyManager.Resource.PublicIncome, (int)ticketPrice, data.Info.m_class); } } diff --git a/Patch/CitizenManagerCreateCitizenInstancePatch.cs b/Patch/CitizenManagerCreateCitizenInstancePatch.cs index 2a22607..e1a0810 100644 --- a/Patch/CitizenManagerCreateCitizenInstancePatch.cs +++ b/Patch/CitizenManagerCreateCitizenInstancePatch.cs @@ -28,11 +28,11 @@ public static bool Prefix(ref CitizenManager __instance, uint citizen, ref bool if (data.m_flags.IsFlagSet(Citizen.Flags.MovingIn)) { //Add initial money if (data.WealthLevel == Citizen.Wealth.Low) { - CitizenData.Instance.citizenMoney[citizen] = 2048; + CitizenData.citizenMoney[citizen] = 2048; } else if (data.WealthLevel == Citizen.Wealth.Medium) { - CitizenData.Instance.citizenMoney[citizen] = 4096; + CitizenData.citizenMoney[citizen] = 4096; } else { - CitizenData.Instance.citizenMoney[citizen] = 8192; + CitizenData.citizenMoney[citizen] = 8192; } } } diff --git a/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs b/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs index d03684b..f3faa1a 100644 --- a/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs +++ b/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs @@ -12,7 +12,7 @@ public static MethodBase TargetMethod() { return typeof(CitizenManager).GetMethod("ReleaseCitizenImplementation", BindingFlags.NonPublic | BindingFlags.Instance); } public static void Postfix(uint citizen) { - CitizenData.Instance.citizenMoney[citizen] = 0; + CitizenData.citizenMoney[citizen] = 0; } } } diff --git a/Patch/CommercialBuildingAIVisitorEnterPatch.cs b/Patch/CommercialBuildingAIVisitorEnterPatch.cs index 0b6a3c1..9a3cf5c 100644 --- a/Patch/CommercialBuildingAIVisitorEnterPatch.cs +++ b/Patch/CommercialBuildingAIVisitorEnterPatch.cs @@ -83,7 +83,7 @@ public static bool Prefix(ushort buildingID, ref Building data, uint citizen) { consumptionMoney = 0; } - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] + consumptionMoney + goodAmount * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)); + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] + consumptionMoney + goodAmount * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)); CitizenUnitData.familyMoney[containingUnit] = CitizenUnitData.familyMoney[containingUnit] + consumptionMoney + goodAmount * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping); } } diff --git a/Patch/HumanAIEnterVehiclePatch.cs b/Patch/HumanAIEnterVehiclePatch.cs index 3b42f3c..fa7d20b 100644 --- a/Patch/HumanAIEnterVehiclePatch.cs +++ b/Patch/HumanAIEnterVehiclePatch.cs @@ -28,13 +28,13 @@ public static void Prefix(ref CitizenInstance citizenData) { // NON-STOCK CODE START CitizenManager citizenManager = Singleton.instance; if ((citizenManager.m_citizens.m_buffer[citizenData.m_citizen].m_flags & Citizen.Flags.Tourist) == Citizen.Flags.None) { - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] - (ticketPrice)); + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - (ticketPrice)); } else { - if (CitizenData.Instance.citizenMoney[citizen] < ticketPrice) { - ticketPrice = (CitizenData.Instance.citizenMoney[citizen] > 0) ? (int)CitizenData.Instance.citizenMoney[citizen] + 1 : 1; - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] - ticketPrice); + if (CitizenData.citizenMoney[citizen] < ticketPrice) { + ticketPrice = (CitizenData.citizenMoney[citizen] > 0) ? (int)CitizenData.citizenMoney[citizen] + 1 : 1; + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - ticketPrice); } else { - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] - (ticketPrice)); + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - (ticketPrice)); } MainDataStore.outsideTouristMoney -= ticketPrice; } diff --git a/Patch/MarketAIVisitorEnterPatch.cs b/Patch/MarketAIVisitorEnterPatch.cs index 66f491f..db3ec2b 100644 --- a/Patch/MarketAIVisitorEnterPatch.cs +++ b/Patch/MarketAIVisitorEnterPatch.cs @@ -49,7 +49,7 @@ public static bool Prefix(ushort buildingID, ref Building data, uint citizen) { goodAmount = 0; } - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] + goodAmount * m_goodsSellPrice); + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] + goodAmount * m_goodsSellPrice); CitizenUnitData.familyMoney[containingUnit] = CitizenUnitData.familyMoney[containingUnit] + goodAmount * m_goodsSellPrice; } } diff --git a/Patch/PassengerCarAIArriveAtTargetPatch.cs b/Patch/PassengerCarAIArriveAtTargetPatch.cs index 8386436..de10358 100644 --- a/Patch/PassengerCarAIArriveAtTargetPatch.cs +++ b/Patch/PassengerCarAIArriveAtTargetPatch.cs @@ -33,7 +33,7 @@ public static void GetVehicleRunningTiming(ushort vehicleID, ref Vehicle vehicle if (!IsOutSide(citizenManager.m_instances.m_buffer[instanceID].GetLastFramePosition())) { MainDataStore.totalCitizenDrivingTime += VehicleData.vehicleTransferTime[vehicleID]; if (vehicleData.m_citizenUnits != 0) { - CitizenData.Instance.citizenMoney[citizenID] -= VehicleData.vehicleTransferTime[vehicleID]; + CitizenData.citizenMoney[citizenID] -= VehicleData.vehicleTransferTime[vehicleID]; } } else { MainDataStore.outsideTouristMoney -= VehicleData.vehicleTransferTime[vehicleID]; diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index 2f2e40e..314f393 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -41,7 +41,7 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) { if (citizenData.Dead == false) { RealCityResidentAI.citizenCount++; - CitizenUnitData.familyMoney[homeID] += CitizenData.Instance.citizenMoney[m_citizenI]; + CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[m_citizenI]; } } } @@ -66,7 +66,11 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) #if FASTRUN #else //add a party.chancce by its citizen data - GetVoteChance(m_citizenI, citizenData, homeID); + //GetVoteChance(m_citizenI, citizenData, homeID); + if (Politics.IsOnElection() && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizenData.m_age))) { + ElectionVoter v = new ElectionVoter(m_citizenI, ref citizenData, homeID, Election.CurrentElectionInfo); + v.VoteTicket(); + } #endif } } @@ -80,7 +84,7 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) if (m_citizenI != 0) { Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) { - CitizenData.Instance.citizenMoney[m_citizenI] = CitizenUnitData.familyMoney[homeID] / temp; + CitizenData.citizenMoney[m_citizenI] = CitizenUnitData.familyMoney[homeID] / temp; } } } @@ -376,128 +380,119 @@ public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, ou } } + [Obsolete("It's calculated in ElectionVoter. If wants to vote, call ElectionVoter.VoteTicket() instead.")] public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { //如果即将选举,而且达到投票年龄 if (gonna be election) and (over Voting Age) if (Politics.IsOnElection() && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age))) { - ElectionVoter voter = new ElectionVoter(citizenID, ref citizen, homeID, Election.CurrentElectionInfo); + ////重置机率 + Politics.cPartyChance = 0; + Politics.gPartyChance = 0; + Politics.sPartyChance = 0; + Politics.lPartyChance = 0; + Politics.nPartyChance = 0; - Politics.ResetWinChance(); - Politics.Parties.ForEach(p => { - PartyInterestCalc interestCalc = new PartyInterestCalc(p, ref citizen, citizenID, homeID); - interestCalc.Calc(); - interestCalc.AddPartyWinChance(); - }); - #region old politics code - ////重置机率 - //Politics.cPartyChance = 0; - //Politics.gPartyChance = 0; - //Politics.sPartyChance = 0; - //Politics.lPartyChance = 0; - //Politics.nPartyChance = 0; - - - //Politics.cPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 0] << 1); - //Politics.gPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 1] << 1); - //Politics.sPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 2] << 1); - //Politics.lPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 3] << 1); - //Politics.nPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 4] << 1); - - - //int choiceIndex = 14; - ////根据工作地点决定投票策略 - //if (RealCityResidentAI.IsGoverment(citizen.m_workBuilding)) { - // choiceIndex = 0; - //} - //switch (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_subService) { - // case ItemClass.SubService.CommercialLow: - // case ItemClass.SubService.CommercialHigh: - // if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { - // choiceIndex = 1; - // } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { - // choiceIndex = 2; - // } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { - // choiceIndex = 3; - // } - // break; - // case ItemClass.SubService.CommercialTourist: - // case ItemClass.SubService.CommercialLeisure: - // choiceIndex = 4; break; - // case ItemClass.SubService.CommercialEco: - // choiceIndex = 5; break; - // case ItemClass.SubService.IndustrialGeneric: - // if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { - // choiceIndex = 6; - // } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { - // choiceIndex = 7; - // } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { - // choiceIndex = 8; - // } - // break; - // case ItemClass.SubService.IndustrialFarming: - // case ItemClass.SubService.IndustrialForestry: - // case ItemClass.SubService.IndustrialOil: - // case ItemClass.SubService.IndustrialOre: - // choiceIndex = 9; break; - // case ItemClass.SubService.OfficeGeneric: - // if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { - // choiceIndex = 10; - // } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { - // choiceIndex = 11; - // } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { - // choiceIndex = 12; - // } - // break; - // case ItemClass.SubService.OfficeHightech: - // choiceIndex = 13; break; - //} - //if (choiceIndex < 0 || choiceIndex > 14) { - // DebugLog.LogToFileOnly($"Error: GetVoteChance workplace idex {choiceIndex}"); - //} - //Politics.cPartyChance += (ushort)(Politics.workplace[choiceIndex, 0] << 1); - //Politics.gPartyChance += (ushort)(Politics.workplace[choiceIndex, 1] << 1); - //Politics.sPartyChance += (ushort)(Politics.workplace[choiceIndex, 2] << 1); - //Politics.lPartyChance += (ushort)(Politics.workplace[choiceIndex, 3] << 1); - //Politics.nPartyChance += (ushort)(Politics.workplace[choiceIndex, 4] << 1); - - - //if (CitizenUnitData.familyMoney[homeID] < 5000) { - // choiceIndex = 0; - //} else if (CitizenUnitData.familyMoney[homeID] >= 20000) { - // choiceIndex = 2; - //} else { - // choiceIndex = 1; - //} - //if (choiceIndex < 0 || choiceIndex > 3) { - // DebugLog.LogToFileOnly($"Error: GetVoteChance Invaid money idex = {choiceIndex}"); - //} - //Politics.cPartyChance += (ushort)(Politics.money[choiceIndex, 0] << 1); - //Politics.gPartyChance += (ushort)(Politics.money[choiceIndex, 1] << 1); - //Politics.sPartyChance += (ushort)(Politics.money[choiceIndex, 2] << 1); - //Politics.lPartyChance += (ushort)(Politics.money[choiceIndex, 3] << 1); - //Politics.nPartyChance += (ushort)(Politics.money[choiceIndex, 4] << 1); - - - //int temp = (int)Citizen.GetAgeGroup(citizen.m_age) - 2; - //if (temp < 0) { - // DebugLog.LogToFileOnly($"Error: GetVoteChance temp = {temp} < 0, GetAgeGroup = {Citizen.GetAgeGroup(citizen.m_age)}"); - //} - //Politics.cPartyChance += Politics.age[temp, 0]; - //Politics.gPartyChance += Politics.age[temp, 1]; - //Politics.sPartyChance += Politics.age[temp, 2]; - //Politics.lPartyChance += Politics.age[temp, 3]; - //Politics.nPartyChance += Politics.age[temp, 4]; - - - //temp = (int)Citizen.GetGender(citizenID); - //Politics.cPartyChance += Politics.gender[temp, 0]; - //Politics.gPartyChance += Politics.gender[temp, 1]; - //Politics.sPartyChance += Politics.gender[temp, 2]; - //Politics.lPartyChance += Politics.gender[temp, 3]; - //Politics.nPartyChance += Politics.gender[temp, 4]; - #endregion + Politics.cPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 0] << 1); + Politics.gPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 1] << 1); + Politics.sPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 2] << 1); + Politics.lPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 3] << 1); + Politics.nPartyChance += (ushort)(Politics.education[(int)citizen.EducationLevel, 4] << 1); + + + int choiceIndex = 14; + //根据工作地点决定投票策略 + if (RealCityResidentAI.IsGoverment(citizen.m_workBuilding)) { + choiceIndex = 0; + } + switch (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_subService) { + case ItemClass.SubService.CommercialLow: + case ItemClass.SubService.CommercialHigh: + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + choiceIndex = 1; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + choiceIndex = 2; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + choiceIndex = 3; + } + break; + case ItemClass.SubService.CommercialTourist: + case ItemClass.SubService.CommercialLeisure: + choiceIndex = 4; break; + case ItemClass.SubService.CommercialEco: + choiceIndex = 5; break; + case ItemClass.SubService.IndustrialGeneric: + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + choiceIndex = 6; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + choiceIndex = 7; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + choiceIndex = 8; + } + break; + case ItemClass.SubService.IndustrialFarming: + case ItemClass.SubService.IndustrialForestry: + case ItemClass.SubService.IndustrialOil: + case ItemClass.SubService.IndustrialOre: + choiceIndex = 9; break; + case ItemClass.SubService.OfficeGeneric: + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + choiceIndex = 10; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + choiceIndex = 11; + } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + choiceIndex = 12; + } + break; + case ItemClass.SubService.OfficeHightech: + choiceIndex = 13; break; + } + if (choiceIndex < 0 || choiceIndex > 14) { + DebugLog.LogToFileOnly($"Error: GetVoteChance workplace idex {choiceIndex}"); + } + Politics.cPartyChance += (ushort)(Politics.workplace[choiceIndex, 0] << 1); + Politics.gPartyChance += (ushort)(Politics.workplace[choiceIndex, 1] << 1); + Politics.sPartyChance += (ushort)(Politics.workplace[choiceIndex, 2] << 1); + Politics.lPartyChance += (ushort)(Politics.workplace[choiceIndex, 3] << 1); + Politics.nPartyChance += (ushort)(Politics.workplace[choiceIndex, 4] << 1); + + + if (CitizenUnitData.familyMoney[homeID] < 5000) { + choiceIndex = 0; + } else if (CitizenUnitData.familyMoney[homeID] >= 20000) { + choiceIndex = 2; + } else { + choiceIndex = 1; + } + if (choiceIndex < 0 || choiceIndex > 3) { + DebugLog.LogToFileOnly($"Error: GetVoteChance Invaid money idex = {choiceIndex}"); + } + Politics.cPartyChance += (ushort)(Politics.money[choiceIndex, 0] << 1); + Politics.gPartyChance += (ushort)(Politics.money[choiceIndex, 1] << 1); + Politics.sPartyChance += (ushort)(Politics.money[choiceIndex, 2] << 1); + Politics.lPartyChance += (ushort)(Politics.money[choiceIndex, 3] << 1); + Politics.nPartyChance += (ushort)(Politics.money[choiceIndex, 4] << 1); + + + int temp = (int)Citizen.GetAgeGroup(citizen.m_age) - 2; + if (temp < 0) { + DebugLog.LogToFileOnly($"Error: GetVoteChance temp = {temp} < 0, GetAgeGroup = {Citizen.GetAgeGroup(citizen.m_age)}"); + } + Politics.cPartyChance += Politics.age[temp, 0]; + Politics.gPartyChance += Politics.age[temp, 1]; + Politics.sPartyChance += Politics.age[temp, 2]; + Politics.lPartyChance += Politics.age[temp, 3]; + Politics.nPartyChance += Politics.age[temp, 4]; + + + temp = (int)Citizen.GetGender(citizenID); + Politics.cPartyChance += Politics.gender[temp, 0]; + Politics.gPartyChance += Politics.gender[temp, 1]; + Politics.sPartyChance += Politics.gender[temp, 2]; + Politics.lPartyChance += Politics.gender[temp, 3]; + Politics.nPartyChance += Politics.gender[temp, 4]; + if (RealCityEconomyExtension.partyTrend == 0) { Politics.cPartyChance += RealCityEconomyExtension.partyTrendStrength; @@ -516,6 +511,7 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { } } + [Obsolete("Call ElectionVoter.VoteTicket() instead.")] public static void GetVoteTickets() { System.Random rand = new System.Random(); //魔数800参见PartyInterestCalc.GetFromEducationLevel()中的注释 diff --git a/Patch/TaxiAIUnloadPassengersPatch.cs b/Patch/TaxiAIUnloadPassengersPatch.cs index ff23182..0af133a 100644 --- a/Patch/TaxiAIUnloadPassengersPatch.cs +++ b/Patch/TaxiAIUnloadPassengersPatch.cs @@ -32,11 +32,11 @@ public static void Prefix(ref TaxiAI __instance, ref Vehicle data) { if (expense != 0) { //DebugLog.LogToFileOnly("UnloadPassengers ticketPrice pre = " + num4.ToString()); if ((Singleton.instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) == Citizen.Flags.None) { - CitizenData.Instance.citizenMoney[citizen] -= (expense); + CitizenData.citizenMoney[citizen] -= (expense); } else { - if (CitizenData.Instance.citizenMoney[citizen] < expense) { - expense = (CitizenData.Instance.citizenMoney[citizen] > 0) ? (int)CitizenData.Instance.citizenMoney[citizen] + 1 : 1; - CitizenData.Instance.citizenMoney[citizen] = (CitizenData.Instance.citizenMoney[citizen] - (expense) - 1); + if (CitizenData.citizenMoney[citizen] < expense) { + expense = (CitizenData.citizenMoney[citizen] > 0) ? (int)CitizenData.citizenMoney[citizen] + 1 : 1; + CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - (expense) - 1); MainDataStore.outsideTouristMoney -= (expense + 1); } } diff --git a/Patch/TouristAISimulationStepPatch.cs b/Patch/TouristAISimulationStepPatch.cs index 766e180..b30bee4 100644 --- a/Patch/TouristAISimulationStepPatch.cs +++ b/Patch/TouristAISimulationStepPatch.cs @@ -16,7 +16,7 @@ public static MethodBase TargetMethod() { } public static void Postfix(uint citizenID, ref Citizen data) { if (!data.m_flags.IsFlagSet(Citizen.Flags.DummyTraffic)) { - if (CitizenData.Instance.citizenMoney[citizenID] < 100) { + if (CitizenData.citizenMoney[citizenID] < 100) { FindVisitPlace(citizenID, data.m_visitBuilding, GetLeavingReason(ref data)); } } diff --git a/RealCity.csproj b/RealCity.csproj index c706971..a609c5d 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -95,7 +95,6 @@ - @@ -113,7 +112,8 @@ - + + @@ -215,7 +215,7 @@ - + diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 4555d97..79b1363 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -14,8 +14,8 @@ namespace RealCity { public class RealCityEconomyExtension : EconomyExtensionBase { - public static byte partyTrend => 0; - public static ushort partyTrendStrength => 0; + public static byte partyTrend = 0; + public static ushort partyTrendStrength = 0; public static ushort industrialLackMoneyCount = 0; public static ushort industrialEarnMoneyCount = 0; public static ushort commercialLackMoneyCount = 0; @@ -133,9 +133,6 @@ public void CaculateCitizenTransportFee() { } } - /// - /// - /// public void CitizenStatus() { if (Politics.nextMeetingInterval == 0) { @@ -151,6 +148,7 @@ public void CitizenStatus() { if ((MainDataStore.updateMoneyCount & 3u) == 0) { if (Politics.nextMeetingInterval != 0) { Government.Instance.HoldMeeting(); + ClearBuildingStats(); //HoldMeeting(); } } @@ -271,8 +269,17 @@ public void HoldMeeting() { } } + /* + * MoneyOffset = -4000 + EconomyManager.instance.m_cashAmount / 3000, [-4000, 4000] + * citizenOffset = 1000 - 5 * citizenOffsetBySalary, [-500, 500] + * citizenOffsetBySalary是家庭工资减去赋税和开销的值 + * + * + */ + + [Obsolete] public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, ref int buildingOffset, ref int commBuildingOffset) { - //MoneyOffset; + //MoneyOffset MoneyOffset = 0; FieldInfo cashAmount; cashAmount = typeof(EconomyManager).GetField("m_cashAmount", BindingFlags.NonPublic | BindingFlags.Instance); @@ -280,19 +287,20 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, if (_cashAmount < 0) { MoneyOffset = -4000; System.Random rand = new System.Random(); + // 80% chance to change a bill if (rand.Next(10) < 8) { switch (rand.Next(15)) { case 0: case 1: case 2: if (Politics.residentTax < 20) { - idex = 0; + idex = 0; // rise resi } else if (Politics.benefitOffset > 0) { - idex = 3; + idex = 3; // rise bene } else if (Politics.industryTax < 20) { - idex = 6; + idex = 6; // rise indu } else if (Politics.commercialTax < 20) { - idex = 4; + idex = 4; // rise comm } break; case 3: @@ -352,18 +360,20 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, } } Politics.currentBillId = (byte)idex; - } else if (_cashAmount > 24000000) { + } else if (_cashAmount > 24000000) { // 2.4e7 MoneyOffset = 4000; } else { MoneyOffset = -4000 + (int)(_cashAmount / 3000); } + //citizenOffset int citizenOffsetBySalary = 0; if (MainDataStore.familyCount > 0) { + //citizenOffsetBySalary is the salary of its family excluding the tax and expense. + //citizenOffsetBySalary是家庭工资减去赋税和开销的值 citizenOffsetBySalary = (int)(MainDataStore.citizenSalaryPerFamily - (MainDataStore.citizenSalaryTaxTotal / MainDataStore.familyCount) - MainDataStore.citizenExpensePerFamily); } - if (citizenOffsetBySalary < 100) { citizenOffset = 500; } else if (citizenOffsetBySalary > 300) { @@ -372,10 +382,15 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, citizenOffset = 1000 - 5 * citizenOffsetBySalary; } + //buildingOffset buildingOffset = 0; + // if have industrial buildings if (industrialEarnMoneyCount + industrialLackMoneyCount > 0) { - buildingOffset = ((int)(100f * (industrialEarnMoneyCount - industrialLackMoneyCount) / (industrialEarnMoneyCount + industrialLackMoneyCount))) << 4; + buildingOffset = ( + (int)(100f * (industrialEarnMoneyCount - industrialLackMoneyCount) + / (industrialEarnMoneyCount + industrialLackMoneyCount)) + ) << 4; if (buildingOffset > 1500) { buildingOffset = 1500; } @@ -386,6 +401,7 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, } commBuildingOffset = 0; + // if have commercial buildings if (commercialEarnMoneyCount + commercialLackMoneyCount > 0) { commBuildingOffset = ((int)(100f * (commercialEarnMoneyCount - commercialLackMoneyCount) / (commercialEarnMoneyCount + commercialLackMoneyCount))) << 4; if (commBuildingOffset > 1500) { @@ -397,15 +413,12 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, } } - industrialEarnMoneyCount = 0; - industrialLackMoneyCount = 0; - commercialEarnMoneyCount = 0; - commercialLackMoneyCount = 0; + ClearBuildingStats(); } - + + [Obsolete] public void VoteResult(int billId) { - //int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; - int seatCount = Politics.GetAllSeatCount(); + int seatCount = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; int yes = 0; int no = 0; int noAttend = 0; @@ -419,29 +432,10 @@ public void VoteResult(int billId) { int commercialBuildingOffset = 0; //commercial building offset VoteOffset(ref billId, ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); - IBill bill = default; - - if (seatCount == 99) { - yes += Politics.Parties.Sum(p => { - // - return p.GetBillAttitude()[bill].Agree; - }); - yes += (Politics.Parties.Length * residentTax - moneyOffset -citizenOffset); - - no += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[bill].Disagree; - }); - no -= Politics.Parties.Length * residentTax; - - noAttend += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[bill].Neutral; - }); - noAttend -= Politics.Parties.Length * residentTax; - } - if (seatCount == 99) { switch (billId) { case 0: + //提高居民税,受到当前税率、政府资金、居民工资的制约 yes += Politics.cPartySeats * (Politics.riseSalaryTax[0, 0] + residentTax); yes += Politics.gPartySeats * (Politics.riseSalaryTax[1, 0] + residentTax); yes += Politics.sPartySeats * (Politics.riseSalaryTax[2, 0] + residentTax); @@ -656,6 +650,7 @@ public void VoteResult(int billId) { } } } + [Obsolete("call Governemt.Instance.UpdateGovType() instead")] public void CreateGoverment() { if (Politics.cPartySeats >= 50) { @@ -744,52 +739,51 @@ public void CreateGoverment() { } } - [Obsolete("call Government.Instance.UpdateSeats() instead")] + [Obsolete("Call Government.UpdateSeats() instead.")] /// /// 更新议会席位数量 /// public void GetSeats() { - - Government.Instance.UpdateSeats(Election.CurrentElectionInfo); - ////总票数 - ////int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; - //int cnt = Politics.GetAllTicket(); - //if (cnt != 0) { - // Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / cnt); - // Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / cnt); - // Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / cnt); - // Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / cnt); - // Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / cnt); - //} else { - // Politics.cPartySeats = 0; - // Politics.gPartySeats = 0; - // Politics.sPartySeats = 0; - // Politics.lPartySeats = 0; - // Politics.nPartySeats = 0; - //} - //Politics.cPartyTickets = 0; - //Politics.gPartyTickets = 0; - //Politics.sPartyTickets = 0; - //Politics.lPartyTickets = 0; - //Politics.nPartyTickets = 0; - - ////allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; - //cnt = Politics.GetAllSeatCount(); - //if (cnt < 99) { - // System.Random rand = new System.Random(); - // switch (rand.Next(5)) { - // case 0: - // Politics.cPartySeats += (ushort)(99 - cnt); break; - // case 1: - // Politics.gPartySeats += (ushort)(99 - cnt); break; - // case 2: - // Politics.sPartySeats += (ushort)(99 - cnt); break; - // case 3: - // Politics.lPartySeats += (ushort)(99 - cnt); break; - // case 4: - // Politics.nPartySeats += (ushort)(99 - cnt); break; - // } - //} + //Government.Instance.UpdateSeats(Election.CurrentElectionInfo); + //总票数 + //int allTickets = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; + int cnt = Politics.cPartyTickets + Politics.gPartyTickets + Politics.sPartyTickets + Politics.lPartyTickets + Politics.nPartyTickets; + if (cnt != 0) { + Politics.cPartySeats = (ushort)(99 * Politics.cPartyTickets / cnt); + Politics.gPartySeats = (ushort)(99 * Politics.gPartyTickets / cnt); + Politics.sPartySeats = (ushort)(99 * Politics.sPartyTickets / cnt); + Politics.lPartySeats = (ushort)(99 * Politics.lPartyTickets / cnt); + Politics.nPartySeats = (ushort)(99 * Politics.nPartyTickets / cnt); + } else { + Politics.cPartySeats = 0; + Politics.gPartySeats = 0; + Politics.sPartySeats = 0; + Politics.lPartySeats = 0; + Politics.nPartySeats = 0; + } + Politics.cPartyTickets = 0; + Politics.gPartyTickets = 0; + Politics.sPartyTickets = 0; + Politics.lPartyTickets = 0; + Politics.nPartyTickets = 0; + + //allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; + cnt = Politics.GetAllSeatCount(); + if (cnt < 99) { + System.Random rand = new System.Random(); + switch (rand.Next(5)) { + case 0: + Politics.cPartySeats += (ushort)(99 - cnt); break; + case 1: + Politics.gPartySeats += (ushort)(99 - cnt); break; + case 2: + Politics.sPartySeats += (ushort)(99 - cnt); break; + case 3: + Politics.lPartySeats += (ushort)(99 - cnt); break; + case 4: + Politics.nPartySeats += (ushort)(99 - cnt); break; + } + } } public static bool Can16timesUpdate(ushort ID) { @@ -800,5 +794,17 @@ public static bool Can16timesUpdate(ushort ID) { } return false; } + /// + /// Set , + /// , + /// , + /// to 0. + /// + public static void ClearBuildingStats() { + industrialEarnMoneyCount = default; + industrialLackMoneyCount = default; + commercialEarnMoneyCount = default; + commercialLackMoneyCount = default; + } } } diff --git a/UI/HumanUI.cs b/UI/HumanUI.cs index 3071d6c..f798214 100644 --- a/UI/HumanUI.cs +++ b/UI/HumanUI.cs @@ -67,18 +67,18 @@ private void ShowOnGui() { } private void RefreshDisplayData() { - if (refeshOnce || (CitizenData.Instance.lastCitizenID != WorldInfoPanel.GetCurrentInstanceID().Citizen)) { + if (refeshOnce || (CitizenData.lastCitizenID != WorldInfoPanel.GetCurrentInstanceID().Citizen)) { if (isVisible) { - CitizenData.Instance.lastCitizenID = WorldInfoPanel.GetCurrentInstanceID().Citizen; + CitizenData.lastCitizenID = WorldInfoPanel.GetCurrentInstanceID().Citizen; CitizenManager instance3 = Singleton.instance; - ushort homeBuilding = instance3.m_citizens.m_buffer[(int)((UIntPtr)CitizenData.Instance.lastCitizenID)].m_homeBuilding; + ushort homeBuilding = instance3.m_citizens.m_buffer[(int)((UIntPtr)CitizenData.lastCitizenID)].m_homeBuilding; BuildingManager instance2 = Singleton.instance; - uint homeId = instance3.m_citizens.m_buffer[CitizenData.Instance.lastCitizenID].GetContainingUnit(CitizenData.Instance.lastCitizenID, instance2.m_buildings.m_buffer[homeBuilding].m_citizenUnits, CitizenUnit.Flags.Home); + uint homeId = instance3.m_citizens.m_buffer[CitizenData.lastCitizenID].GetContainingUnit(CitizenData.lastCitizenID, instance2.m_buildings.m_buffer[homeBuilding].m_citizenUnits, CitizenUnit.Flags.Home); familyMoney.text = string.Format(Localization.Get("FAMILY_MONEY") + " [{0}]", CitizenUnitData.familyMoney[homeId]) + $"ID = ({homeId})"; - citizenMoney.text = string.Format(Localization.Get("CITIZEN_MONEY") + " [{0}]", CitizenData.Instance.citizenMoney[CitizenData.Instance.lastCitizenID]); + citizenMoney.text = string.Format(Localization.Get("CITIZEN_MONEY") + " [{0}]", CitizenData.citizenMoney[CitizenData.lastCitizenID]); familySalary.text = string.Format(Localization.Get("FAMILY_SALARY") + " [{0}]", CaculateFamilySalary(homeId).ToString()); - if ((instance3.m_citizens.m_buffer[CitizenData.Instance.lastCitizenID].m_flags & Citizen.Flags.NeedGoods) != 0) { + if ((instance3.m_citizens.m_buffer[CitizenData.lastCitizenID].m_flags & Citizen.Flags.NeedGoods) != 0) { familyGoods.text = string.Format(Localization.Get("FAMILY_GOODS") + " [{0}] " + Localization.Get("FAMILY_NEED_GOODS"), (CitizenUnitData.familyGoods[homeId] / 10f).ToString()) + $"({instance3.m_units.m_buffer[homeId].m_goods})"; } else { familyGoods.text = string.Format(Localization.Get("FAMILY_GOODS") + " [{0}]", (CitizenUnitData.familyGoods[homeId] / 10f).ToString()) + $"({instance3.m_units.m_buffer[homeId].m_goods})"; diff --git a/UI/TouristUI.cs b/UI/TouristUI.cs index 90b6687..927662c 100644 --- a/UI/TouristUI.cs +++ b/UI/TouristUI.cs @@ -46,10 +46,10 @@ private void ShowOnGui() { } private void RefreshDisplayData() { - if (refeshOnce || (CitizenData.Instance.lastCitizenID != WorldInfoPanel.GetCurrentInstanceID().Citizen)) { + if (refeshOnce || (CitizenData.lastCitizenID != WorldInfoPanel.GetCurrentInstanceID().Citizen)) { if (isVisible) { - CitizenData.Instance.lastCitizenID = WorldInfoPanel.GetCurrentInstanceID().Citizen; - TouristMoney.text = string.Format(Localization.Get("TOURIST_MONEY") + " [{0}]", CitizenData.Instance.citizenMoney[CitizenData.Instance.lastCitizenID]); + CitizenData.lastCitizenID = WorldInfoPanel.GetCurrentInstanceID().Citizen; + TouristMoney.text = string.Format(Localization.Get("TOURIST_MONEY") + " [{0}]", CitizenData.citizenMoney[CitizenData.lastCitizenID]); refeshOnce = false; } } diff --git a/Util/ArrayExtension.cs b/Util/ArrayExtension.cs index 1fd8cdb..d1a03de 100644 --- a/Util/ArrayExtension.cs +++ b/Util/ArrayExtension.cs @@ -3,7 +3,7 @@ public static class ArrayExtension { /// - /// 修正数组长度 + /// Ensure the length of a is same to a given number. /// /// /// @@ -12,12 +12,13 @@ public static T[] EnsureLength(this T[] arr, int expectedLength) { if (arr.Length != expectedLength) { T[] correctData = new T[expectedLength]; if (arr.Length < expectedLength) { - // expected: 5 3 4 5 - // actually: 5 3 4 _ + // expected: arr = { _, _, _, _, _, _, }, len = 6; + // inputs: arr = { 4, 2, 1, 3, }, len = 4; + // return: arr = { 4, 2, 1, 3, 0, 0, }, len = 6; Array.Copy(arr, correctData, arr.Length); // fill the remaining part for (int i = arr.Length; i < expectedLength; ++i) { - correctData[i] = default; + correctData[i] = (T)Activator.CreateInstance(typeof(T)); } } else { // throw the useless part @@ -28,7 +29,7 @@ public static T[] EnsureLength(this T[] arr, int expectedLength) { return arr; } /// - /// Initializes every element of the value-type System.Array by a given value. + /// Initializes every element of the value-type by a given value. /// /// /// @@ -39,7 +40,7 @@ public static void Initialize(this Array arr, T value) { } } /// - /// Returns a random element in the Array. + /// Returns a random element in an . /// /// /// diff --git a/Util/CustomGameDataFactory.cs b/Util/CustomGameDataFactory.cs deleted file mode 100644 index cc35182..0000000 --- a/Util/CustomGameDataFactory.cs +++ /dev/null @@ -1,33 +0,0 @@ -using RealCity.CustomData; - -namespace RealCity.Util -{ - public class CustomGameDataFactory - { - public BuildingData MakeBuildingData() { - ICustomGameData d = new BuildingData(); - d.DataInit(); - return d as BuildingData; - } - public CitizenData MakeCitizenData() { - ICustomGameData d = new CitizenData(); - d.DataInit(); - return d as CitizenData; - } - public CitizenUnitData MakeCitizenUnitData() { - ICustomGameData d = new CitizenUnitData(); - d.DataInit(); - return d as CitizenUnitData; - } - public TransportLineData MakeTransportLineData() { - ICustomGameData d = new TransportLineData(); - d.DataInit(); - return d as TransportLineData; - } - public VehicleData MakeVehicleData() { - ICustomGameData d = new VehicleData(); - d.DataInit(); - return d as VehicleData; - } - } -} diff --git a/Util/Politic/AbstractBill.cs b/Util/Politic/AbstractBill.cs index 5d92b0a..2c201f1 100644 --- a/Util/Politic/AbstractBill.cs +++ b/Util/Politic/AbstractBill.cs @@ -1,6 +1,4 @@ -using System; - -namespace RealCity.Util.Politic +namespace RealCity.Util.Politic { /// /// 议案(抽象的) @@ -14,4 +12,4 @@ public AbstractBill(int effectVal) { public abstract void Implement(); public abstract bool IsImplementable(); } -} \ No newline at end of file +} diff --git a/Util/Politic/IVoteRusult.cs b/Util/Politic/AbstractVoteResult.cs similarity index 61% rename from Util/Politic/IVoteRusult.cs rename to Util/Politic/AbstractVoteResult.cs index 5103001..194f04f 100644 --- a/Util/Politic/IVoteRusult.cs +++ b/Util/Politic/AbstractVoteResult.cs @@ -8,15 +8,15 @@ public abstract class AbstractVoteResult //TODO: consider a better name /// /// 同意 /// - public int Agree { get; } + public int Agree { get; private set; } /// /// 反对 /// - public int Disagree { get; } + public int Disagree { get; private set; } /// /// 弃权 /// - public int Neutral { get; } + public int Neutral { get; private set; } public int Sum => this.Agree + this.Disagree + this.Neutral; // define under what circumstances will the result be approvable here @@ -24,6 +24,12 @@ public abstract class AbstractVoteResult //TODO: consider a better name /// /// 投票结果 /// + public AbstractVoteResult() + : this(default, default, default) { + } + /// + /// 投票结果 + /// /// 同意 /// 反对 /// 弃权 @@ -32,5 +38,13 @@ public AbstractVoteResult(int agree, int disagree, int neutral) { this.Disagree = disagree; this.Neutral = neutral; } + public void AppendChange(int dAgree, int dDisagree) { + this.AppendChange(dAgree, dDisagree, 0); + } + public void AppendChange(int dAgree, int dDisagree, int dNeutral) { + this.Agree += dAgree; + this.Disagree += dDisagree; + this.Neutral += dNeutral; + } } } diff --git a/Util/Politic/Bill/RiseBenefitBill.cs b/Util/Politic/Bill/RiseBenefitBill.cs index e1b5e41..912127c 100644 --- a/Util/Politic/Bill/RiseBenefitBill.cs +++ b/Util/Politic/Bill/RiseBenefitBill.cs @@ -1,4 +1,7 @@ -namespace RealCity.Util.Politic.Bill +using ColossalFramework; +using System; + +namespace RealCity.Util.Politic.Bill { public class RiseBenefitBill : AbstractBill { @@ -11,7 +14,13 @@ public override void Implement() { } public override bool IsImplementable() { - return Politics.CanRiseBenefit; + // 20% oppotunity to implement though financial shortage + if (new Random().Next(5) == 0) { + return Politics.CanRiseBenefit + && Singleton.instance.GetPrivateField("m_cashAmount") < 0L; + } else { + return Politics.CanRiseBenefit; + } } } } diff --git a/Util/Politic/Bill/RiseCommercialTaxBill.cs b/Util/Politic/Bill/RiseCommercialTaxBill.cs index 505ea40..28b728e 100644 --- a/Util/Politic/Bill/RiseCommercialTaxBill.cs +++ b/Util/Politic/Bill/RiseCommercialTaxBill.cs @@ -1,4 +1,7 @@ -namespace RealCity.Util.Politic.Bill +using ColossalFramework; +using System; + +namespace RealCity.Util.Politic.Bill { public class RiseCommercialTaxBill : AbstractBill { @@ -11,7 +14,13 @@ public override void Implement() { } public override bool IsImplementable() { - return Politics.CanRiseCommercialTax; + // 20% oppotunity to implement though financial shortage + if (new Random().Next(5) == 0) { + return Politics.CanRiseCommercialTax + && Singleton.instance.GetPrivateField("m_cashAmount") < 0L; + } else { + return Politics.CanRiseCommercialTax; + } } } } diff --git a/Util/Politic/Bill/RiseIndustryTaxBill.cs b/Util/Politic/Bill/RiseIndustryTaxBill.cs index 6e0b7b7..76486a2 100644 --- a/Util/Politic/Bill/RiseIndustryTaxBill.cs +++ b/Util/Politic/Bill/RiseIndustryTaxBill.cs @@ -1,4 +1,7 @@ -namespace RealCity.Util.Politic.Bill +using ColossalFramework; +using System; + +namespace RealCity.Util.Politic.Bill { public class RiseIndustryTaxBill : AbstractBill { @@ -11,7 +14,13 @@ public override void Implement() { } public override bool IsImplementable() { - return Politics.CanRiseIndustryTax; + // 20% oppotunity to implement though financial shortage + if (new Random().Next(5) == 0) { + return Politics.CanRiseIndustryTax + && Singleton.instance.GetPrivateField("m_cashAmount") < 0L; + } else { + return Politics.CanRiseIndustryTax; + } } } } diff --git a/Util/Politic/Bill/RiseResidentTaxBill.cs b/Util/Politic/Bill/RiseResidentTaxBill.cs index b111522..401a953 100644 --- a/Util/Politic/Bill/RiseResidentTaxBill.cs +++ b/Util/Politic/Bill/RiseResidentTaxBill.cs @@ -1,4 +1,7 @@ -namespace RealCity.Util.Politic.Bill +using ColossalFramework; +using System; + +namespace RealCity.Util.Politic.Bill { public class RiseResidentTaxBill : AbstractBill { @@ -11,7 +14,13 @@ public override void Implement() { } public override bool IsImplementable() { - return Politics.CanRiseResidentTax; + // 20% oppotunity to implement though financial shortage + if (new Random().Next(5) == 0) { + return Politics.CanRiseResidentTax + && Singleton.instance.GetPrivateField("m_cashAmount") < 0L; + } else { + return Politics.CanRiseResidentTax; + } } } } diff --git a/Util/Politic/Bills.cs b/Util/Politic/Bills.cs index c8be3c9..08d58a3 100644 --- a/Util/Politic/Bills.cs +++ b/Util/Politic/Bills.cs @@ -20,8 +20,6 @@ public static class Bills public readonly static IBill ReduceBenefit = new ReduceBenefitBill(10); - //这里需要null object吗 ? - private readonly static IBill[] AllBills = { RiseResidentTax, ReduceResidentTax, @@ -35,17 +33,6 @@ public static class Bills // which is NOT elegant }; - private readonly static string[] AllBillsNameStr = { - nameof(RiseResidentTax), - nameof(ReduceResidentTax), - nameof(RiseCommercialTax), - nameof(ReduceCommercialTax), - nameof(RiseIndustryTax), - nameof(ReduceIndustryTax), - nameof(RiseBenefit), - nameof(ReduceBenefit), - }; - public static IBill GetRandomBill() { return AllBills.GetRandomElement(r); } diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs index 8ff751d..a9b9168 100644 --- a/Util/Politic/Election.cs +++ b/Util/Politic/Election.cs @@ -7,7 +7,7 @@ namespace RealCity.Util.Politic /// public static class Election { - private static IParty[] Parties { get; set; } + private static IParty[] Parties { get; set; } = Politics.Parties; /// /// 选举信息 /// diff --git a/Util/Politic/ElectionUtil/ElectionVoter.cs b/Util/Politic/ElectionUtil/ElectionVoter.cs index 5c2080c..ca0954e 100644 --- a/Util/Politic/ElectionUtil/ElectionVoter.cs +++ b/Util/Politic/ElectionUtil/ElectionVoter.cs @@ -6,7 +6,7 @@ namespace RealCity.Util.Politic.ElectionUtil /// /// 选民 /// - class ElectionVoter + public class ElectionVoter { private const int MaxTrandStrength = 300; //private const int ChanceSum = 800; @@ -40,22 +40,15 @@ public ElectionVoter(uint citizenID, ref Citizen citizen, uint homeID,ElectionIn } this.Chance = new int[this.EleInfo.PartiesCount]; } + /// + /// Vote to a based on its interest. + /// public void VoteTicket() { - int i; - for (i = 0; i < this.EleInfo.PartiesCount; i++) { - this.Interests[i].Calc(); - this.Chance[i] = this.Interests[i].Val; - } - // choose a lucky party as trend party - this.trandPartyIdx = this.r.Next(this.EleInfo.PartiesCount); - this.trendStrength = this.r.Next(MaxTrandStrength); - // add its chance - this.Chance[trandPartyIdx] += this.trendStrength; + CalcChance(); // It's Roulette Wheel Selection // 大转盘,政党的Chance越大,得票机率就越大 - - i = 0; + int i = 0; int segment = this.Chance[0]; // assert this.Chance.Sum() == 800 ? int vote = this.r.Next(this.Chance.Sum() + this.trendStrength); @@ -76,5 +69,16 @@ public void VoteTicket() { segment += this.Chance[0]; } } + private void CalcChance() { + for (int i = 0; i < this.EleInfo.PartiesCount; i++) { + this.Interests[i].Calc(); + this.Chance[i] = this.Interests[i].Val; + } + // choose a lucky party as trend party + this.trandPartyIdx = this.r.Next(this.EleInfo.PartiesCount); + this.trendStrength = this.r.Next(MaxTrandStrength); + // add its chance + this.Chance[trandPartyIdx] += this.trendStrength; + } } } diff --git a/Util/Politic/Government.cs b/Util/Politic/Government.cs index abf4af6..50a7197 100644 --- a/Util/Politic/Government.cs +++ b/Util/Politic/Government.cs @@ -11,11 +11,11 @@ public class Government : IGovernment private const int MinSeatCount = 99; public static IGovernment Instance { get; } - private IBill currentBill = default; + private IBill currentBill = Bills.GetRandomBill(); public IParty[] Parties { get; private set; } public GovernmentType GovernmentType { get; private set; } - public IParty[] RulingParties { get; private set; } + //public IParty[] RulingParties { get; private set; } // refer RealCityEconomyExtension.cs public int[] Seats { get; private set; } public int AllSeatCount => this.Seats.Sum(); @@ -74,42 +74,50 @@ public void UpdateGovType() { for (int i = 0; i < this.Seats.Length; i++) { if (this.Seats[i] >= halfSeatCount) { this.GovernmentType = GovernmentType.Single; - this.RulingParties = new IParty[] { this.Parties[i] }; + //this.RulingParties = new IParty[] { this.Parties[i] }; isOk = true; } } - if (isOk == false) { - // bad codes - int left, wideLeft, right; - left = wideLeft = right = default; - for (int i = 0; i < this.Seats.Length; i++) { - if (this.Parties[i].Name == "Green" || this.Parties[i].Name == "Socialist") { - left += this.Seats[i]; - } else if (this.Parties[i].Name == "Communist") { - wideLeft += this.Seats[i]; - } else if (this.Parties[i].Name == "Liberal" || this.Parties[i].Name == "National") { - right += this.Seats[i]; - } - } - wideLeft += left; - if(left>= halfSeatCount) { - this.GovernmentType = GovernmentType.LeftUnion; - }else if(wideLeft>= halfSeatCount) { - this.GovernmentType = GovernmentType.WideLeftUnion; - } else if(right>= halfSeatCount) { - this.GovernmentType = GovernmentType.RightUnion; - } else { - this.GovernmentType = GovernmentType.Grand; + + if (isOk) + return; + + // bad codes + int left, wideLeft, right; + left = wideLeft = right = default; + for (int i = 0; i < this.Seats.Length; i++) { + if (this.Parties[i].Name == "Green" || this.Parties[i].Name == "Socialist") { + left += this.Seats[i]; + } else if (this.Parties[i].Name == "Communist") { + wideLeft += this.Seats[i]; + } else if (this.Parties[i].Name == "Liberal" || this.Parties[i].Name == "National") { + right += this.Seats[i]; } } - } - public ParliamentalVote HoldMeeting() { - if(this.currentBill == null) { - this.currentBill = Bills.GetRandomBill(); + wideLeft += left; + if (left >= halfSeatCount) { + this.GovernmentType = GovernmentType.LeftUnion; + } else if (wideLeft >= halfSeatCount) { + this.GovernmentType = GovernmentType.WideLeftUnion; + } else if (right >= halfSeatCount) { + this.GovernmentType = GovernmentType.RightUnion; + } else { + this.GovernmentType = GovernmentType.Grand; } - ParliamentalVote v = new ParliamentalVote(this.Parties,Bills.GetAnotherBill(this.currentBill)); + } + + /// + /// Hold a governmental meeting and decide a to implement. + /// + /// + public IGovernmentalMeeting HoldMeeting() { + //if(this.currentBill == null) { + // this.currentBill = Bills.GetRandomBill(); + //} + IGovernmentalMeeting v = new GovernmentalMeeting(this, Bills.GetAnotherBill(this.currentBill)); + v.Start(); if (v.VoteResult.IsApprovable) { - v.Implement(); + v.Bill.Implement(); } return v; } @@ -119,7 +127,7 @@ private int GetSeatCount(int ticketCount, ref int ticketSum) { } /// - /// 修正Seat数量至MinSeatCount个 + /// 修正Seat数量至 个 /// private void FixSeatCount() { int missingCount = MinSeatCount - this.AllSeatCount; diff --git a/Util/Politic/GovernmentalMeeting.cs b/Util/Politic/GovernmentalMeeting.cs new file mode 100644 index 0000000..65b26c4 --- /dev/null +++ b/Util/Politic/GovernmentalMeeting.cs @@ -0,0 +1,181 @@ +using RealCity.Util.Politic.Bill; +using System.Linq; + +namespace RealCity.Util.Politic +{ + /// + /// 会议 + /// + public class GovernmentalMeeting : IGovernmentalMeeting + { + private IGovernment gov; + private IParty[] parties; + + public IBill Bill { get; } + public AbstractVoteResult VoteResult { get; private set; } + + public GovernmentalMeeting(IGovernment gov, IBill bill) { + this.gov = gov; + this.parties = gov.Parties; + this.Bill = bill; + } + + public void Start() { + AbstractVoteResult r = new VoteResult(); + + int seatCount = this.gov.AllSeatCount; + int resiTaxOffset = 10 - (Politics.residentTax); + int commTaxOffset = 10 - (Politics.commercialTax); + int induTaxOffset = 10 - (Politics.industryTax); + int beneOffset = 10 - (Politics.benefitOffset / 5); + int moneyOffset = 0; // money offset + int citizenOffset = 0; // citizen offset + int industrialBuildingOffset = 0; //industrial building offset + int commercialBuildingOffset = 0; //commercial building offset + + VoteOffset(ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); + + r.AppendChange( + +this.parties.Sum(p => p.BillAttitude[this.Bill].Agree), + +this.parties.Sum(p => p.BillAttitude[this.Bill].Disagree), + +this.parties.Sum(p => p.BillAttitude[this.Bill].Neutral) + ); + + // offset the value of agree by the class of IBill + // bad codes + if (this.Bill is RiseResidentTaxBill) { + //agree += resiTaxOffset * this.parties.Length; + //agree -= moneyOffset; + //agree -= citizenOffset; + //disagree -= resiTaxOffset * this.parties.Length; + r.AppendChange( + +(resiTaxOffset * this.parties.Length - moneyOffset - citizenOffset), + -(resiTaxOffset * this.parties.Length) + ); + } else if (this.Bill is ReduceResidentTaxBill) { + //agree -= resiTaxOffset * this.parties.Length; + //agree += moneyOffset; + //agree += citizenOffset; + //disagree += resiTaxOffset * this.parties.Length; + r.AppendChange( + -(resiTaxOffset * this.parties.Length - moneyOffset - citizenOffset), + +(resiTaxOffset * this.parties.Length) + ); + } else if (this.Bill is RiseCommercialTaxBill) { + //agree += commTaxOffset * this.parties.Length; + //agree -= moneyOffset; + //agree += commercialBuildingOffset; + //disagree -= commTaxOffset * this.parties.Length; + r.AppendChange( + +(commTaxOffset * this.parties.Length - moneyOffset + commercialBuildingOffset), + -(resiTaxOffset * this.parties.Length) + ); + } else if (this.Bill is ReduceCommercialTaxBill) { + //agree -= commTaxOffset * this.parties.Length; + //agree += moneyOffset; + //agree -= commercialBuildingOffset; + //disagree += commTaxOffset * this.parties.Length; + r.AppendChange( + -(commTaxOffset * this.parties.Length - moneyOffset + commercialBuildingOffset), + +(resiTaxOffset * this.parties.Length) + ); + } else if (this.Bill is RiseIndustryTaxBill) { + //agree += induTaxOffset * this.parties.Length; + //agree -= moneyOffset; + //agree += industrialBuildingOffset; + //disagree -= induTaxOffset * this.parties.Length; + r.AppendChange( + +(induTaxOffset * this.parties.Length - moneyOffset + industrialBuildingOffset), + -(induTaxOffset * this.parties.Length) + ); + } else if (this.Bill is ReduceIndustryTaxBill) { + //agree -= induTaxOffset * this.parties.Length; + //agree += moneyOffset; + //agree -= industrialBuildingOffset; + //disagree += induTaxOffset * this.parties.Length; + r.AppendChange( + -(induTaxOffset * this.parties.Length - moneyOffset + industrialBuildingOffset), + +(induTaxOffset * this.parties.Length) + ); + } else if (this.Bill is RiseBenefitBill) { + //agree += beneOffset * this.parties.Length; + //agree += moneyOffset; + //disagree -= beneOffset * this.parties.Length; + r.AppendChange( + +(beneOffset * this.parties.Length + moneyOffset), + -(beneOffset * this.parties.Length) + ); + } else if (this.Bill is ReduceBenefitBill) { + //agree -= beneOffset * this.parties.Length; + //agree -= moneyOffset; + //disagree += beneOffset * this.parties.Length; + r.AppendChange( + -(beneOffset * this.parties.Length + moneyOffset), + +(beneOffset * this.parties.Length) + ); + } + this.VoteResult = r; + } + + private void VoteOffset(ref int moneyOffset, ref int citizenOffset, ref int buildingOffset, ref int commBuildingOffset) { + //moenyOffset + //FieldInfo cashAmountField = typeof(EconomyManager).GetField("m_cashAmount", BindingFlags.NonPublic | BindingFlags.Instance); + //long cashAmount = (long)cashAmountField.GetValue(Singleton.instance); + long cashAmount = EconomyManager.instance.GetPrivateField("m_cashAmount"); + if (cashAmount < 0) { + moneyOffset = -4000; + } else if (cashAmount > 24000000) { // 2.4e7 + moneyOffset = 4000; + } else { + moneyOffset = -4000 + (int)(cashAmount / 3000); // equals 0 when cashAmount = 1.2e7 + } + + + //citizenOffset + int citizenOffsetBySalary = 0; + if (MainDataStore.familyCount > 0) { + //citizenOffsetBySalary is the salary of its family excluding the tax and expense. + //citizenOffsetBySalary是家庭工资减去赋税和开销的值 + citizenOffsetBySalary = (int)(MainDataStore.citizenSalaryPerFamily - (MainDataStore.citizenSalaryTaxTotal / MainDataStore.familyCount) - MainDataStore.citizenExpensePerFamily); + } + if (citizenOffsetBySalary < 100) { + citizenOffset = 500; + } else if (citizenOffsetBySalary > 300) { + citizenOffset = -500; + } else { + citizenOffset = 1000 - 5 * citizenOffsetBySalary; + } + + + //buildingOffset + buildingOffset = 0; + // if have industrial buildings + if (RealCityEconomyExtension.industrialEarnMoneyCount + RealCityEconomyExtension.industrialLackMoneyCount > 0) { + buildingOffset = ( + (int)(100f * (RealCityEconomyExtension.industrialEarnMoneyCount - RealCityEconomyExtension.industrialLackMoneyCount) + / (RealCityEconomyExtension.industrialEarnMoneyCount + RealCityEconomyExtension.industrialLackMoneyCount)) + ) << 4; + if (buildingOffset > 1500) { + buildingOffset = 1500; + } + + if (buildingOffset < -1500) { + buildingOffset = -1500; + } + } + + commBuildingOffset = 0; + // if have commercial buildings + if (RealCityEconomyExtension.commercialEarnMoneyCount + RealCityEconomyExtension.commercialLackMoneyCount > 0) { + commBuildingOffset = ((int)(100f * (RealCityEconomyExtension.commercialEarnMoneyCount - RealCityEconomyExtension.commercialLackMoneyCount) / (RealCityEconomyExtension.commercialEarnMoneyCount + RealCityEconomyExtension.commercialLackMoneyCount))) << 4; + if (commBuildingOffset > 1500) { + commBuildingOffset = 1500; + } + + if (commBuildingOffset < -1500) { + commBuildingOffset = -1500; + } + } + } + } +} diff --git a/Util/Politic/IGovernment.cs b/Util/Politic/IGovernment.cs index 0d2077c..c1dd6d3 100644 --- a/Util/Politic/IGovernment.cs +++ b/Util/Politic/IGovernment.cs @@ -8,10 +8,10 @@ public interface IGovernment int AllSeatCount { get; } IParty[] Parties { get; } GovernmentType GovernmentType { get; } - IParty[] RulingParties { get; } + //IParty[] RulingParties { get; } void UpdateSeats(ElectionInfo info); void UpdateGovType(); - ParliamentalVote HoldMeeting(); + IGovernmentalMeeting HoldMeeting(); } public enum GovernmentType { diff --git a/Util/Politic/IGovernmentalMeeting.cs b/Util/Politic/IGovernmentalMeeting.cs new file mode 100644 index 0000000..0d02380 --- /dev/null +++ b/Util/Politic/IGovernmentalMeeting.cs @@ -0,0 +1,9 @@ +namespace RealCity.Util.Politic +{ + public interface IGovernmentalMeeting + { + IBill Bill { get; } + AbstractVoteResult VoteResult { get; } + void Start(); + } +} diff --git a/Util/Politic/IParty.cs b/Util/Politic/IParty.cs index e7b6245..7d5d6af 100644 --- a/Util/Politic/IParty.cs +++ b/Util/Politic/IParty.cs @@ -5,7 +5,6 @@ namespace RealCity.Util.Politic public interface IParty { PartyInterestData GetPartyInterestData(); - Dictionary GetBillAttitude(); void AddWinChance(ushort val); void ResetWinChance(); string Name { get; } @@ -13,5 +12,6 @@ public interface IParty ushort Ticket { get; } ushort SeatCount { get; } ushort Id { get; } + IDictionary BillAttitude { get; } } } \ No newline at end of file diff --git a/Util/Politic/ParliamentalVote.cs b/Util/Politic/ParliamentalVote.cs deleted file mode 100644 index 25ea669..0000000 --- a/Util/Politic/ParliamentalVote.cs +++ /dev/null @@ -1,199 +0,0 @@ -using ColossalFramework; -using System.Linq; - -namespace RealCity.Util.Politic -{ - /// - /// 议会投票 - /// - public class ParliamentalVote - { - private IParty[] parties; - - - public IBill Bill { get; } - public AbstractVoteResult VoteResult { get; private set; } - - public ParliamentalVote(IParty[] parties, IBill bill) { - this.parties = parties; - this.Bill = bill; - } - - public void Implement() { - this.Bill.Implement(); - } - - - public AbstractVoteResult Calc() { - int agree = default; - int disagree = default; - int noVote = default; - - int seatCount = Politics.GetAllSeatCount(); - - int residentTax = 10 - (Politics.residentTax); - int commercialTax = 10 - (Politics.commercialTax); - int industryTax = 10 - (Politics.industryTax); - int benefitOffset = 10 - (Politics.benefitOffset / 5); - int moneyOffset = 0; // money offset - int citizenOffset = 0; // citizen offset - int industrialBuildingOffset = 0; //industrial building offset - int commercialBuildingOffset = 0; //commercial building offset - VoteOffset(ref billId, ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); - - if (seatCount == 99) { - agree += Politics.Parties.Sum(p => { - // - return p.GetBillAttitude()[this.Bill].Agree; - }); - agree += (Politics.Parties.Length * residentTax - moneyOffset - citizenOffset); - - disagree += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[this.Bill].Disagree; - }); - disagree -= Politics.Parties.Length * residentTax; - - noVote += Politics.Parties.Sum(p => { - return p.GetBillAttitude()[this.Bill].Neutral; - }); - noVote -= Politics.Parties.Length * residentTax; - } - AbstractVoteResult result = new VoteResult(agree, disagree, noVote); - this.VoteResult = result; - return result; - } - - private void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, ref int buildingOffset, ref int commBuildingOffset) { - //MoneyOffset; - MoneyOffset = 0; - //FieldInfo cashAmount; - //cashAmount = typeof(EconomyManager).GetField("m_cashAmount", BindingFlags.NonPublic | BindingFlags.Instance); - //long _cashAmount = (long)cashAmount.GetValue(Singleton.instance); - long _cashAmount = Singleton.instance.GetPrivateField("m_cashAmount"); - if (_cashAmount < 0) { - MoneyOffset = -4000; - System.Random rand = new System.Random(); - if (rand.Next(10) < 8) { - switch (rand.Next(15)) { - case 0: - case 1: - case 2: - if (Politics.residentTax < 20) { - idex = 0; - } else if (Politics.benefitOffset > 0) { - idex = 3; - } else if (Politics.industryTax < 20) { - idex = 6; - } else if (Politics.commercialTax < 20) { - idex = 4; - } - break; - case 3: - case 4: - case 5: - if (Politics.benefitOffset > 0) { - idex = 3; - } else if (Politics.industryTax < 20) { - idex = 6; - } else if (Politics.commercialTax < 20) { - idex = 4; - } else if (Politics.residentTax < 20) { - idex = 0; - } - break; - case 6: - case 7: - case 8: - if (Politics.commercialTax < 20) { - idex = 4; - } else if (Politics.benefitOffset > 0) { - idex = 3; - } else if (Politics.industryTax < 20) { - idex = 6; - } else if (Politics.residentTax < 20) { - idex = 0; - } else if (Politics.commercialTax < 20) { - idex = 4; - } - break; - case 9: - case 10: - case 11: - if (Politics.industryTax < 20) { - idex = 6; - } else if (Politics.commercialTax < 20) { - idex = 4; - } else if (Politics.benefitOffset > 0) { - idex = 3; - } else if (Politics.residentTax < 20) { - idex = 0; - } - break; - case 12: - case 13: - case 14: - if (Politics.benefitOffset > 0) { - idex = 3; - } else if (Politics.industryTax < 20) { - idex = 6; - } else if (Politics.residentTax < 20) { - idex = 0; - } else if (Politics.commercialTax < 20) { - idex = 4; - } - break; - } - } - Politics.currentBillId = (byte)idex; - } else if (_cashAmount > 24000000) { - MoneyOffset = 4000; - } else { - MoneyOffset = -4000 + (int)(_cashAmount / 3000); - } - - //citizenOffset - int citizenOffsetBySalary = 0; - if (MainDataStore.familyCount > 0) { - citizenOffsetBySalary = (int)(MainDataStore.citizenSalaryPerFamily - (MainDataStore.citizenSalaryTaxTotal / MainDataStore.familyCount) - MainDataStore.citizenExpensePerFamily); - } - - if (citizenOffsetBySalary < 100) { - citizenOffset = 500; - } else if (citizenOffsetBySalary > 300) { - citizenOffset = -500; - } else { - citizenOffset = 1000 - 5 * citizenOffsetBySalary; - } - - //buildingOffset - buildingOffset = 0; - if (industrialEarnMoneyCount + industrialLackMoneyCount > 0) { - buildingOffset = ((int)(100f * (industrialEarnMoneyCount - industrialLackMoneyCount) / (industrialEarnMoneyCount + industrialLackMoneyCount))) << 4; - if (buildingOffset > 1500) { - buildingOffset = 1500; - } - - if (buildingOffset < -1500) { - buildingOffset = -1500; - } - } - - commBuildingOffset = 0; - if (commercialEarnMoneyCount + commercialLackMoneyCount > 0) { - commBuildingOffset = ((int)(100f * (commercialEarnMoneyCount - commercialLackMoneyCount) / (commercialEarnMoneyCount + commercialLackMoneyCount))) << 4; - if (commBuildingOffset > 1500) { - commBuildingOffset = 1500; - } - - if (commBuildingOffset < -1500) { - commBuildingOffset = -1500; - } - } - - industrialEarnMoneyCount = 0; - industrialLackMoneyCount = 0; - commercialEarnMoneyCount = 0; - commercialLackMoneyCount = 0; - } - } -} diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index 5c2056f..d257dc5 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -1,8 +1,4 @@ -using RealCity.CustomData; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; namespace RealCity.Util.Politic { @@ -12,12 +8,12 @@ namespace RealCity.Util.Politic public class Party : IParty { private PartyInterestData interestData; - private Dictionary billAttitude; public string Name { get; } public ushort WinChance { get; private set; } = default; public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; public ushort Id { get; } + public IDictionary BillAttitude { get; } /// /// 政党 @@ -26,21 +22,17 @@ public class Party : IParty /// Id /// 民众对政党的兴趣度 /// 政党对政策的态度 - public Party(string name, ushort id,PartyInterestData interestData, Dictionary billAttitude) { + public Party(string name, ushort id, PartyInterestData interestData, Dictionary billAttitude) { this.Name = name; this.Id = id; this.interestData = interestData; - this.billAttitude = billAttitude; + this.BillAttitude = billAttitude; } public PartyInterestData GetPartyInterestData() { return this.interestData; } - public Dictionary GetBillAttitude() { - return this.billAttitude; - } - public void AddWinChance(ushort val) { this.WinChance += val; } @@ -49,4 +41,4 @@ public void ResetWinChance() { this.WinChance = default; } } -} \ No newline at end of file +} diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs index 45c1485..d43d7c3 100644 --- a/Util/Politic/PartyFactory.cs +++ b/Util/Politic/PartyFactory.cs @@ -15,15 +15,15 @@ public class PartyFactory public ushort NextPartyId { get; private set; } = 0; public IParty MakeCParty() { - var billAttitudeMap = new Dictionary(); - VoteResult raiseResidentTax = new VoteResult(55, 40, 5); - VoteResult reduceResidentTax = new VoteResult(40, 55, 5); - VoteResult raiseCommercialTax = new VoteResult(80, 20, 0); - VoteResult reduceCommercialTax = new VoteResult(20, 80, 0); - VoteResult raiseIndustryTax = new VoteResult(20, 70, 10); - VoteResult reduceIndustryTax = new VoteResult(70, 20, 10); - VoteResult raiseBenefitOffset = new VoteResult(40, 50, 10); - VoteResult reduceBenefitOffset = new VoteResult(50, 40, 10); + var billAttitudeMap = new Dictionary(); + AbstractVoteResult raiseResidentTax = new VoteResult(55, 40, 5); + AbstractVoteResult reduceResidentTax = new VoteResult(40, 55, 5); + AbstractVoteResult raiseCommercialTax = new VoteResult(80, 20, 0); + AbstractVoteResult reduceCommercialTax = new VoteResult(20, 80, 0); + AbstractVoteResult raiseIndustryTax = new VoteResult(20, 70, 10); + AbstractVoteResult reduceIndustryTax = new VoteResult(70, 20, 10); + AbstractVoteResult raiseBenefitOffset = new VoteResult(40, 50, 10); + AbstractVoteResult reduceBenefitOffset = new VoteResult(50, 40, 10); billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); @@ -50,15 +50,15 @@ public IParty MakeCParty() { } public IParty MakeGParty() { - var billAttitudeMap = new Dictionary(); - VoteResult raiseResidentTax = new VoteResult(10, 80, 10); - VoteResult reduceResidentTax = new VoteResult(80, 10, 10); - VoteResult raiseCommercialTax = new VoteResult(40, 50, 10); - VoteResult reduceCommercialTax = new VoteResult(50, 40, 10); - VoteResult raiseIndustryTax = new VoteResult(50, 50, 0); - VoteResult reduceIndustryTax = new VoteResult(50, 50, 0); - VoteResult raiseBenefitOffset = new VoteResult(70, 20, 10); - VoteResult reduceBenefitOffset = new VoteResult(20, 70, 10); + var billAttitudeMap = new Dictionary(); + AbstractVoteResult raiseResidentTax = new VoteResult(10, 80, 10); + AbstractVoteResult reduceResidentTax = new VoteResult(80, 10, 10); + AbstractVoteResult raiseCommercialTax = new VoteResult(40, 50, 10); + AbstractVoteResult reduceCommercialTax = new VoteResult(50, 40, 10); + AbstractVoteResult raiseIndustryTax = new VoteResult(50, 50, 0); + AbstractVoteResult reduceIndustryTax = new VoteResult(50, 50, 0); + AbstractVoteResult raiseBenefitOffset = new VoteResult(70, 20, 10); + AbstractVoteResult reduceBenefitOffset = new VoteResult(20, 70, 10); billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); @@ -85,15 +85,15 @@ public IParty MakeGParty() { } public IParty MakeSParty() { - var billAttitudeMap = new Dictionary(); - VoteResult raiseResidentTax = new VoteResult(30, 70, 0); - VoteResult reduceResidentTax = new VoteResult(70, 30, 0); - VoteResult raiseCommercialTax = new VoteResult(55, 40, 5); - VoteResult reduceCommercialTax = new VoteResult(40, 55, 5); - VoteResult raiseIndustryTax = new VoteResult(60, 30, 10); - VoteResult reduceIndustryTax = new VoteResult(30, 60, 10); - VoteResult raiseBenefitOffset = new VoteResult(90, 10, 0); - VoteResult reduceBenefitOffset = new VoteResult(10, 90, 0); + var billAttitudeMap = new Dictionary(); + AbstractVoteResult raiseResidentTax = new VoteResult(30, 70, 0); + AbstractVoteResult reduceResidentTax = new VoteResult(70, 30, 0); + AbstractVoteResult raiseCommercialTax = new VoteResult(55, 40, 5); + AbstractVoteResult reduceCommercialTax = new VoteResult(40, 55, 5); + AbstractVoteResult raiseIndustryTax = new VoteResult(60, 30, 10); + AbstractVoteResult reduceIndustryTax = new VoteResult(30, 60, 10); + AbstractVoteResult raiseBenefitOffset = new VoteResult(90, 10, 0); + AbstractVoteResult reduceBenefitOffset = new VoteResult(10, 90, 0); billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); @@ -120,15 +120,15 @@ public IParty MakeSParty() { } public IParty MakeLParty() { - var billAttitudeMap = new Dictionary(); - VoteResult raiseResidentTax = new VoteResult(70, 30, 0); - VoteResult reduceResidentTax = new VoteResult(30, 70, 0); - VoteResult raiseCommercialTax = new VoteResult(10, 90, 0); - VoteResult reduceCommercialTax = new VoteResult(90, 10, 0); - VoteResult raiseIndustryTax = new VoteResult(70, 30, 0); - VoteResult reduceIndustryTax = new VoteResult(30, 70, 0); - VoteResult raiseBenefitOffset = new VoteResult(10, 90, 0); - VoteResult reduceBenefitOffset = new VoteResult(90, 10, 0); + var billAttitudeMap = new Dictionary(); + AbstractVoteResult raiseResidentTax = new VoteResult(70, 30, 0); + AbstractVoteResult reduceResidentTax = new VoteResult(30, 70, 0); + AbstractVoteResult raiseCommercialTax = new VoteResult(10, 90, 0); + AbstractVoteResult reduceCommercialTax = new VoteResult(90, 10, 0); + AbstractVoteResult raiseIndustryTax = new VoteResult(70, 30, 0); + AbstractVoteResult reduceIndustryTax = new VoteResult(30, 70, 0); + AbstractVoteResult raiseBenefitOffset = new VoteResult(10, 90, 0); + AbstractVoteResult reduceBenefitOffset = new VoteResult(90, 10, 0); billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); @@ -155,15 +155,15 @@ public IParty MakeLParty() { } public IParty MakeNParty() { - var billAttitudeMap = new Dictionary(); - VoteResult raiseResidentTax = new VoteResult(35, 55, 10); - VoteResult reduceResidentTax = new VoteResult(55, 35, 10); - VoteResult raiseCommercialTax = new VoteResult(45, 45, 100); - VoteResult reduceCommercialTax = new VoteResult(45, 45, 10); - VoteResult raiseIndustryTax = new VoteResult(30, 70, 0); - VoteResult reduceIndustryTax = new VoteResult(70, 30, 0); - VoteResult raiseBenefitOffset = new VoteResult(30, 60, 10); - VoteResult reduceBenefitOffset = new VoteResult(60, 30, 10); + var billAttitudeMap = new Dictionary(); + AbstractVoteResult raiseResidentTax = new VoteResult(35, 55, 10); + AbstractVoteResult reduceResidentTax = new VoteResult(55, 35, 10); + AbstractVoteResult raiseCommercialTax = new VoteResult(45, 45, 100); + AbstractVoteResult reduceCommercialTax = new VoteResult(45, 45, 10); + AbstractVoteResult raiseIndustryTax = new VoteResult(30, 70, 0); + AbstractVoteResult reduceIndustryTax = new VoteResult(70, 30, 0); + AbstractVoteResult raiseBenefitOffset = new VoteResult(30, 60, 10); + AbstractVoteResult reduceBenefitOffset = new VoteResult(60, 30, 10); billAttitudeMap.Add(Bills.RiseResidentTax, raiseResidentTax); billAttitudeMap.Add(Bills.ReduceResidentTax, reduceResidentTax); diff --git a/Util/Politic/VoteResult.cs b/Util/Politic/VoteResult.cs index 4eb99ea..816b6c8 100644 --- a/Util/Politic/VoteResult.cs +++ b/Util/Politic/VoteResult.cs @@ -6,6 +6,14 @@ public class VoteResult : AbstractVoteResult { public override bool IsApprovable => this.Agree >= (this.Sum >> 1); + + /// + /// 投票结果 + /// + public VoteResult() + : base() { + + } /// /// 投票结果 /// diff --git a/Util/SaveAndRestore.cs b/Util/SaveAndRestore.cs index f608a3f..0bd4c85 100644 --- a/Util/SaveAndRestore.cs +++ b/Util/SaveAndRestore.cs @@ -346,7 +346,7 @@ public override void OnSaveData() { //5 saveData = new byte[4194304]; - CitizenData.Instance.Save(ref saveData); + CitizenData.Save(ref saveData); _serializableData.SaveData("RealCity CitizenData", saveData); //6 @@ -412,7 +412,7 @@ public override void OnLoadData() { if (saveData == null) DebugLog.LogToFileOnly("no RealCity CitizenData, please check"); else - CitizenData.Instance.Load(ref saveData); + CitizenData.Load(ref saveData); //6 saveData = _serializableData.LoadData("RealCity Politics"); From d7c84ee2a3428fe5fdaf65a4bd5dd5c4863ea372 Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sat, 5 Sep 2020 14:24:47 +0800 Subject: [PATCH 32/38] Ipdate IParty interface, fix coding style --- Attributes/ArrayLengthAttribute.cs | 15 ------------- CustomAI/RealCityCommercialBuildingAI.cs | 5 +++-- CustomAI/RealCityCommonBuildingAI.cs | 5 +++-- CustomAI/RealCityIndustrialBuildingAI.cs | 2 +- CustomAI/RealCityIndustrialExtractorAI.cs | 2 +- CustomAI/RealCityIndustryBuildingAI.cs | 2 +- CustomAI/RealCityMarketAI.cs | 2 +- CustomAI/RealCityPlayerBuildingAI.cs | 2 +- CustomAI/RealCityPrivateBuildingAI.cs | 2 +- CustomAI/RealCityResidentAI.cs | 2 +- CustomData/BuildingData.cs | 2 +- CustomData/CitizenData.cs | 2 +- CustomData/CitizenUnitData.cs | 2 +- CustomData/ICustomGameData.cs | 2 +- CustomData/TransportLineData.cs | 2 +- CustomData/VehicleData.cs | 4 ++-- CustomManager/RealCityEconomyManager.cs | 2 +- Loader.cs | 7 +++--- ...AuxiliaryBuildingAIGetResourceRatePatch.cs | 2 +- Patch/CargoTruckAIArriveAtSourcePatch.cs | 14 +++++------- Patch/CargoTruckAIArriveAtTargetPatch.cs | 2 +- RealCity.cs | 2 +- RealCity.csproj | 1 - RealCityEconomyExtension.cs | 14 +++++------- RealCityThreading.cs | 2 +- RebalancedIndustries/Mod.cs | 2 +- RebalancedIndustries/RI_Data.cs | 2 +- RebalancedIndustries/RI_Detours.cs | 2 +- UI/BuildingButton.cs | 2 +- UI/BuildingUI.cs | 2 +- UI/EcnomicButton.cs | 2 +- UI/EcnomicUI.cs | 2 +- UI/HumanUI.cs | 2 +- UI/IncompatibleModsPanel.cs | 2 +- UI/OptionUI.cs | 2 +- UI/PBLUI.cs | 2 +- UI/PlayerBuildingUI.cs | 2 +- UI/PoliticsButton.cs | 2 +- UI/RealCityButton.cs | 2 +- UI/RealCityUI.cs | 2 +- UI/TouristUI.cs | 2 +- Util/DebugLog.cs | 2 +- Util/FastDelegateFactory.cs | 2 +- Util/HarmonyDetours.cs | 2 +- Util/Localization.cs | 2 +- Util/MainDataStore.cs | 2 +- Util/ModsCompatibilityChecker.cs | 2 +- Util/Politic/Election.cs | 2 +- Util/Politic/GovernmentalMeeting.cs | 6 ++--- Util/Politic/IParty.cs | 5 +++-- Util/Politic/Party.cs | 11 ++++++++-- Util/Politic/PartyInterestData.cs | 11 ++-------- Util/Politics.cs | 22 ++++++------------- Util/SaveAndRestore.cs | 10 ++++----- Util/SpriteUtilities.cs | 2 +- 55 files changed, 93 insertions(+), 119 deletions(-) delete mode 100644 Attributes/ArrayLengthAttribute.cs diff --git a/Attributes/ArrayLengthAttribute.cs b/Attributes/ArrayLengthAttribute.cs deleted file mode 100644 index b85a003..0000000 --- a/Attributes/ArrayLengthAttribute.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace RealCity.Attributes -{ - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public class ArrayLengthAttribute : Attribute - { - //TODO: use ArrayExtension.Ensure() to auto-fix bad arrays - - public int MaximumLength { get; } - public ArrayLengthAttribute(int maxLength) { - this.MaximumLength = maxLength; - } - } -} diff --git a/CustomAI/RealCityCommercialBuildingAI.cs b/CustomAI/RealCityCommercialBuildingAI.cs index 322bf14..84a8591 100644 --- a/CustomAI/RealCityCommercialBuildingAI.cs +++ b/CustomAI/RealCityCommercialBuildingAI.cs @@ -15,7 +15,8 @@ public class RealCityCommercialBuildingAI public delegate void CommercialBuildingAIGetVisitBehaviour(CommercialBuildingAI CommercialBuildingAI, ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount); public static CommercialBuildingAIGetVisitBehaviour GetVisitBehaviour; - public static void InitDelegate() { + public static void InitDelegate() + { if (GetIncomingTransferReason != null) return; if (MaxIncomingLoadSize != null) @@ -27,4 +28,4 @@ public static void InitDelegate() { MaxIncomingLoadSize = FastDelegateFactory.Create(typeof(CommercialBuildingAI), "MaxIncomingLoadSize", instanceMethod: true); } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityCommonBuildingAI.cs b/CustomAI/RealCityCommonBuildingAI.cs index 16af981..e49949f 100644 --- a/CustomAI/RealCityCommonBuildingAI.cs +++ b/CustomAI/RealCityCommonBuildingAI.cs @@ -20,7 +20,8 @@ public class RealCityCommonBuildingAI public delegate void CommonBuildingAIGetWorkBehaviour(CommonBuildingAI CommonBuildingAI, ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount); public static CommonBuildingAIGetWorkBehaviour GetWorkBehaviour; - public static void InitDelegate() { + public static void InitDelegate() + { if (CalculateOwnVehicles != null) return; if (GetWorkBehaviour != null) @@ -35,4 +36,4 @@ public static void InitDelegate() { CalculateGuestVehicles1 = FastDelegateFactory.Create(typeof(CommonBuildingAI), "CalculateGuestVehicles", instanceMethod: true); } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityIndustrialBuildingAI.cs b/CustomAI/RealCityIndustrialBuildingAI.cs index d7b2595..2981ef7 100644 --- a/CustomAI/RealCityIndustrialBuildingAI.cs +++ b/CustomAI/RealCityIndustrialBuildingAI.cs @@ -41,4 +41,4 @@ public static void InitDelegate() { GetConsumptionDivider = FastDelegateFactory.Create(typeof(IndustrialBuildingAI), "GetConsumptionDivider", instanceMethod: true); } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityIndustrialExtractorAI.cs b/CustomAI/RealCityIndustrialExtractorAI.cs index 56da64c..77402e8 100644 --- a/CustomAI/RealCityIndustrialExtractorAI.cs +++ b/CustomAI/RealCityIndustrialExtractorAI.cs @@ -13,4 +13,4 @@ public static void InitDelegate() { GetOutgoingTransferReason = FastDelegateFactory.Create(typeof(IndustrialExtractorAI), "GetOutgoingTransferReason", instanceMethod: true); } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityIndustryBuildingAI.cs b/CustomAI/RealCityIndustryBuildingAI.cs index 7836cbe..0227052 100644 --- a/CustomAI/RealCityIndustryBuildingAI.cs +++ b/CustomAI/RealCityIndustryBuildingAI.cs @@ -68,4 +68,4 @@ public static float GetResourcePrice(TransferManager.TransferReason material) { return price; } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityMarketAI.cs b/CustomAI/RealCityMarketAI.cs index c439d2e..18b5a5c 100644 --- a/CustomAI/RealCityMarketAI.cs +++ b/CustomAI/RealCityMarketAI.cs @@ -15,4 +15,4 @@ public static void InitDelegate() { GetVisitBehaviour = FastDelegateFactory.Create(typeof(MarketAI), "GetVisitBehaviour", instanceMethod: true); } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityPlayerBuildingAI.cs b/CustomAI/RealCityPlayerBuildingAI.cs index 3b1c19f..0718eb8 100644 --- a/CustomAI/RealCityPlayerBuildingAI.cs +++ b/CustomAI/RealCityPlayerBuildingAI.cs @@ -36,4 +36,4 @@ public static float CaculateEmployeeOutcome(ushort buildingID, Building building return allSalary * outsideWorkerRatio / 16f; } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityPrivateBuildingAI.cs b/CustomAI/RealCityPrivateBuildingAI.cs index 2dafca2..741553a 100644 --- a/CustomAI/RealCityPrivateBuildingAI.cs +++ b/CustomAI/RealCityPrivateBuildingAI.cs @@ -419,4 +419,4 @@ public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[ } } } -} \ No newline at end of file +} diff --git a/CustomAI/RealCityResidentAI.cs b/CustomAI/RealCityResidentAI.cs index 4426843..05df2f2 100644 --- a/CustomAI/RealCityResidentAI.cs +++ b/CustomAI/RealCityResidentAI.cs @@ -308,4 +308,4 @@ public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnl return totalWorkCount; } } -} \ No newline at end of file +} diff --git a/CustomData/BuildingData.cs b/CustomData/BuildingData.cs index 57d42f3..633fbc6 100644 --- a/CustomData/BuildingData.cs +++ b/CustomData/BuildingData.cs @@ -47,4 +47,4 @@ public static void Load(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/CustomData/CitizenData.cs b/CustomData/CitizenData.cs index ca24ac9..b44f561 100644 --- a/CustomData/CitizenData.cs +++ b/CustomData/CitizenData.cs @@ -41,4 +41,4 @@ public static uint GetCitizenUnit(ushort buildingId) { return 0u; } } -} \ No newline at end of file +} diff --git a/CustomData/CitizenUnitData.cs b/CustomData/CitizenUnitData.cs index 3bde58f..733e616 100644 --- a/CustomData/CitizenUnitData.cs +++ b/CustomData/CitizenUnitData.cs @@ -39,4 +39,4 @@ public static void Load(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/CustomData/ICustomGameData.cs b/CustomData/ICustomGameData.cs index 6da9038..3422108 100644 --- a/CustomData/ICustomGameData.cs +++ b/CustomData/ICustomGameData.cs @@ -10,4 +10,4 @@ public interface ICustomGameData void Save(ref byte[] saveData); void Load(ref byte[] saveData); } -} \ No newline at end of file +} diff --git a/CustomData/TransportLineData.cs b/CustomData/TransportLineData.cs index 4f413db..d556644 100644 --- a/CustomData/TransportLineData.cs +++ b/CustomData/TransportLineData.cs @@ -35,4 +35,4 @@ public static void Load(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/CustomData/VehicleData.cs b/CustomData/VehicleData.cs index 39f7a42..bdf2120 100644 --- a/CustomData/VehicleData.cs +++ b/CustomData/VehicleData.cs @@ -2,7 +2,7 @@ namespace RealCity.CustomData { - public class VehicleData + public class VehicleData { public static ushort[] vehicleTransferTime = new ushort[65536]; public static bool[] isVehicleCharged = new bool[65536]; @@ -37,4 +37,4 @@ public static void Load(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/CustomManager/RealCityEconomyManager.cs b/CustomManager/RealCityEconomyManager.cs index 7c550e9..bbd08ef 100644 --- a/CustomManager/RealCityEconomyManager.cs +++ b/CustomManager/RealCityEconomyManager.cs @@ -214,4 +214,4 @@ public static void Save(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/Loader.cs b/Loader.cs index f73a648..daf0e73 100644 --- a/Loader.cs +++ b/Loader.cs @@ -80,14 +80,15 @@ public override void OnLevelLoaded(LoadMode mode) { public static void InitData() { DebugLog.LogToFileOnly("InitData"); - Politics.DataInit(); TransportLineData.DataInit(); VehicleData.DataInit(); BuildingData.DataInit(); CitizenUnitData.DataInit(); - //CitizenData.DataInit(); CitizenData.DataInit(); RealCityEconomyManager.DataInit(); + + Politics.DataInit(); + System.Random rand = new System.Random(); RealCityEconomyExtension.partyTrend = (byte)rand.Next(5); RealCityEconomyExtension.partyTrendStrength = (byte)rand.Next(300); @@ -405,4 +406,4 @@ private bool CheckRealTimeIsLoaded() { return Check3rdPartyModLoaded("RealTime.Core", false); } } -} \ No newline at end of file +} diff --git a/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs b/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs index f35ea28..7ab58da 100644 --- a/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs +++ b/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs @@ -20,4 +20,4 @@ public static void Postfix(ushort buildingID, ref Building data, EconomyManager. } } } -} \ No newline at end of file +} diff --git a/Patch/CargoTruckAIArriveAtSourcePatch.cs b/Patch/CargoTruckAIArriveAtSourcePatch.cs index b8b9486..2e0711d 100644 --- a/Patch/CargoTruckAIArriveAtSourcePatch.cs +++ b/Patch/CargoTruckAIArriveAtSourcePatch.cs @@ -11,19 +11,15 @@ namespace RealCity.Patch [HarmonyPatch] public class CargoTruckAIArriveAtSourcePatch { - public static MethodBase TargetMethod() - { - return typeof(CargoTruckAI).GetMethod("ArriveAtSource", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType()}, null); + public static MethodBase TargetMethod() { + return typeof(CargoTruckAI).GetMethod("ArriveAtSource", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }, null); } - public static bool Prefix(ref Vehicle data) - { - if (data.m_sourceBuilding == 0) - { + public static bool Prefix(ref Vehicle data) { + if (data.m_sourceBuilding == 0) { return true; } - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != (Vehicle.Flags)0) - { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != (Vehicle.Flags)0) { int transferSize = (int)data.m_transferSize; BuildingInfo info = Singleton.instance.m_buildings.m_buffer[(int)data.m_sourceBuilding].Info; info.m_buildingAI.ModifyMaterialBuffer(data.m_sourceBuilding, ref Singleton.instance.m_buildings.m_buffer[(int)data.m_sourceBuilding], (TransferManager.TransferReason)data.m_transferType, ref transferSize); diff --git a/Patch/CargoTruckAIArriveAtTargetPatch.cs b/Patch/CargoTruckAIArriveAtTargetPatch.cs index 629adce..c0736a8 100644 --- a/Patch/CargoTruckAIArriveAtTargetPatch.cs +++ b/Patch/CargoTruckAIArriveAtTargetPatch.cs @@ -56,4 +56,4 @@ public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int trans } } } -} \ No newline at end of file +} diff --git a/RealCity.cs b/RealCity.cs index da5c23a..d32cd4b 100644 --- a/RealCity.cs +++ b/RealCity.cs @@ -73,4 +73,4 @@ public static void SetOutsideGovermentMoney(float value) { MainDataStore.outsideGovermentMoney = value; } } -} \ No newline at end of file +} diff --git a/RealCity.csproj b/RealCity.csproj index a609c5d..f46991e 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -91,7 +91,6 @@ - diff --git a/RealCityEconomyExtension.cs b/RealCityEconomyExtension.cs index 79b1363..d6221fe 100644 --- a/RealCityEconomyExtension.cs +++ b/RealCityEconomyExtension.cs @@ -241,8 +241,7 @@ public byte ReturnOtherIdx(byte orgIdx) { [Obsolete("call Government.Instance.HoldMeeting() instead")] public void HoldMeeting() { - //int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; - int temp = Politics.GetAllSeatCount(); + int temp = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; if (temp == 99) { System.Random rand = new System.Random(); switch (rand.Next(8)) { @@ -262,7 +261,7 @@ public void HoldMeeting() { Politics.currentBillId = ReturnOtherIdx(6); break; case 7: Politics.currentBillId = ReturnOtherIdx(7); break; - default: + default: Politics.currentBillId = 8; break; } VoteResult(Politics.currentBillId); @@ -388,7 +387,7 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, // if have industrial buildings if (industrialEarnMoneyCount + industrialLackMoneyCount > 0) { buildingOffset = ( - (int)(100f * (industrialEarnMoneyCount - industrialLackMoneyCount) + (int)(100f * (industrialEarnMoneyCount - industrialLackMoneyCount) / (industrialEarnMoneyCount + industrialLackMoneyCount)) ) << 4; if (buildingOffset > 1500) { @@ -415,7 +414,7 @@ public void VoteOffset(ref int idex, ref int MoneyOffset, ref int citizenOffset, ClearBuildingStats(); } - + [Obsolete] public void VoteResult(int billId) { int seatCount = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; @@ -650,7 +649,7 @@ public void VoteResult(int billId) { } } } - + [Obsolete("call Governemt.Instance.UpdateGovType() instead")] public void CreateGoverment() { if (Politics.cPartySeats >= 50) { @@ -767,8 +766,7 @@ public void GetSeats() { Politics.lPartyTickets = 0; Politics.nPartyTickets = 0; - //allTickets = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; - cnt = Politics.GetAllSeatCount(); + cnt = Politics.cPartySeats + Politics.gPartySeats + Politics.sPartySeats + Politics.lPartySeats + Politics.nPartySeats; if (cnt < 99) { System.Random rand = new System.Random(); switch (rand.Next(5)) { diff --git a/RealCityThreading.cs b/RealCityThreading.cs index 65ea403..4453d71 100644 --- a/RealCityThreading.cs +++ b/RealCityThreading.cs @@ -177,4 +177,4 @@ protected void GetVehicleCapacity(ushort vehicleID, ref Vehicle vehicleData, ref } } } -} \ No newline at end of file +} diff --git a/RebalancedIndustries/Mod.cs b/RebalancedIndustries/Mod.cs index e5e61b5..7a40746 100644 --- a/RebalancedIndustries/Mod.cs +++ b/RebalancedIndustries/Mod.cs @@ -25,4 +25,4 @@ public static void SplitBytes(ushort value, ref byte large, ref byte small) { small = (byte)(value & 0xFF); } } -} \ No newline at end of file +} diff --git a/RebalancedIndustries/RI_Data.cs b/RebalancedIndustries/RI_Data.cs index b8acc9f..9a2ff61 100644 --- a/RebalancedIndustries/RI_Data.cs +++ b/RebalancedIndustries/RI_Data.cs @@ -39,4 +39,4 @@ public static float GetFactorCargo(TransferManager.TransferReason material) { return 1f; } } -} \ No newline at end of file +} diff --git a/RebalancedIndustries/RI_Detours.cs b/RebalancedIndustries/RI_Detours.cs index 1bfa739..55b87c6 100644 --- a/RebalancedIndustries/RI_Detours.cs +++ b/RebalancedIndustries/RI_Detours.cs @@ -244,4 +244,4 @@ public static void Postfix(ref Building buildingData, ref ushort[] __state) { buildingData.m_customBuffer2 = (ushort)Mathf.Clamp(__state[1] + cargoDiff, 0, 64000); } } -} \ No newline at end of file +} diff --git a/UI/BuildingButton.cs b/UI/BuildingButton.cs index f5d8234..246dd0d 100644 --- a/UI/BuildingButton.cs +++ b/UI/BuildingButton.cs @@ -64,4 +64,4 @@ public override void Update() { base.Update(); } } -} \ No newline at end of file +} diff --git a/UI/BuildingUI.cs b/UI/BuildingUI.cs index 2c7fbce..b97fac0 100644 --- a/UI/BuildingUI.cs +++ b/UI/BuildingUI.cs @@ -364,4 +364,4 @@ public void GetLandRent(Building building, out int incomeAccumulation) { } } } -} \ No newline at end of file +} diff --git a/UI/EcnomicButton.cs b/UI/EcnomicButton.cs index 0574043..9a94430 100644 --- a/UI/EcnomicButton.cs +++ b/UI/EcnomicButton.cs @@ -102,4 +102,4 @@ public override void Update() { base.Update(); } } -} \ No newline at end of file +} diff --git a/UI/EcnomicUI.cs b/UI/EcnomicUI.cs index a1201da..90ddae6 100644 --- a/UI/EcnomicUI.cs +++ b/UI/EcnomicUI.cs @@ -249,4 +249,4 @@ private void RefreshDisplayData() { } } } -} \ No newline at end of file +} diff --git a/UI/HumanUI.cs b/UI/HumanUI.cs index f798214..8c4a9c8 100644 --- a/UI/HumanUI.cs +++ b/UI/HumanUI.cs @@ -115,4 +115,4 @@ public int CaculateFamilySalary(uint homeid) { return totalSalary; } } -} \ No newline at end of file +} diff --git a/UI/IncompatibleModsPanel.cs b/UI/IncompatibleModsPanel.cs index 94f3126..231a0ee 100644 --- a/UI/IncompatibleModsPanel.cs +++ b/UI/IncompatibleModsPanel.cs @@ -204,4 +204,4 @@ private void TryPopModal() { } } } -} \ No newline at end of file +} diff --git a/UI/OptionUI.cs b/UI/OptionUI.cs index cd09b14..a07860f 100644 --- a/UI/OptionUI.cs +++ b/UI/OptionUI.cs @@ -387,4 +387,4 @@ private static void onOtherBudgetMinChanged(float newVal) { SaveSetting(); } } -} \ No newline at end of file +} diff --git a/UI/PBLUI.cs b/UI/PBLUI.cs index 7bfdca6..904a868 100644 --- a/UI/PBLUI.cs +++ b/UI/PBLUI.cs @@ -164,4 +164,4 @@ private ushort GetLineID() { return 0; } } -} \ No newline at end of file +} diff --git a/UI/PlayerBuildingUI.cs b/UI/PlayerBuildingUI.cs index 305c4b5..ec3f303 100644 --- a/UI/PlayerBuildingUI.cs +++ b/UI/PlayerBuildingUI.cs @@ -97,4 +97,4 @@ private void RefreshDisplayData() { } } } -} \ No newline at end of file +} diff --git a/UI/PoliticsButton.cs b/UI/PoliticsButton.cs index 2f950ad..f9ed7a0 100644 --- a/UI/PoliticsButton.cs +++ b/UI/PoliticsButton.cs @@ -107,4 +107,4 @@ public override void Update() { base.Update(); } } -} \ No newline at end of file +}\ \ No newline at end of file diff --git a/UI/RealCityButton.cs b/UI/RealCityButton.cs index b3e052f..05fec1d 100644 --- a/UI/RealCityButton.cs +++ b/UI/RealCityButton.cs @@ -105,4 +105,4 @@ public override void Update() { base.Update(); } } -} \ No newline at end of file +} diff --git a/UI/RealCityUI.cs b/UI/RealCityUI.cs index 4d40034..7f4d158 100644 --- a/UI/RealCityUI.cs +++ b/UI/RealCityUI.cs @@ -623,4 +623,4 @@ private void ProcessData() { } } } -} \ No newline at end of file +} diff --git a/UI/TouristUI.cs b/UI/TouristUI.cs index 927662c..49cfdd3 100644 --- a/UI/TouristUI.cs +++ b/UI/TouristUI.cs @@ -55,4 +55,4 @@ private void RefreshDisplayData() { } } } -} \ No newline at end of file +} diff --git a/Util/DebugLog.cs b/Util/DebugLog.cs index b876e8d..994ee99 100644 --- a/Util/DebugLog.cs +++ b/Util/DebugLog.cs @@ -13,4 +13,4 @@ public static void LogToFileOnly(string msg) { } } } -} \ No newline at end of file +} diff --git a/Util/FastDelegateFactory.cs b/Util/FastDelegateFactory.cs index b3a9efd..7f41bf6 100644 --- a/Util/FastDelegateFactory.cs +++ b/Util/FastDelegateFactory.cs @@ -70,4 +70,4 @@ private static MethodInfo GetMethodInfo(Type type, string name, bool return methodInfo; } } -} \ No newline at end of file +} diff --git a/Util/HarmonyDetours.cs b/Util/HarmonyDetours.cs index 7947dfe..60a9864 100644 --- a/Util/HarmonyDetours.cs +++ b/Util/HarmonyDetours.cs @@ -18,4 +18,4 @@ public static void DeApply() { DebugLog.LogToFileOnly("Harmony patches DeApplied"); } } -} \ No newline at end of file +} diff --git a/Util/Localization.cs b/Util/Localization.cs index 1adf629..d4e22f7 100644 --- a/Util/Localization.cs +++ b/Util/Localization.cs @@ -40,4 +40,4 @@ public static string Get(string id) { return localeStore[lang].Get(new Locale.Key { m_Identifier = id }); } } -} \ No newline at end of file +} diff --git a/Util/MainDataStore.cs b/Util/MainDataStore.cs index c250c63..82afa5f 100644 --- a/Util/MainDataStore.cs +++ b/Util/MainDataStore.cs @@ -222,4 +222,4 @@ public static void Load(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/Util/ModsCompatibilityChecker.cs b/Util/ModsCompatibilityChecker.cs index 80aa3eb..91e86ee 100644 --- a/Util/ModsCompatibilityChecker.cs +++ b/Util/ModsCompatibilityChecker.cs @@ -72,4 +72,4 @@ private ulong[] GetUserModsList() { return ids.Select(id => id.AsUInt64).ToArray(); } } -} \ No newline at end of file +} diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs index a9b9168..aca52c1 100644 --- a/Util/Politic/Election.cs +++ b/Util/Politic/Election.cs @@ -11,7 +11,7 @@ public static class Election /// /// 选举信息 /// - public static ElectionInfo CurrentElectionInfo { get; private set; } + public static ElectionInfo CurrentElectionInfo { get; private set; }; public static void NextElection() { diff --git a/Util/Politic/GovernmentalMeeting.cs b/Util/Politic/GovernmentalMeeting.cs index 65b26c4..df87277 100644 --- a/Util/Politic/GovernmentalMeeting.cs +++ b/Util/Politic/GovernmentalMeeting.cs @@ -36,9 +36,9 @@ public void Start() { VoteOffset(ref moneyOffset, ref citizenOffset, ref industrialBuildingOffset, ref commercialBuildingOffset); r.AppendChange( - +this.parties.Sum(p => p.BillAttitude[this.Bill].Agree), - +this.parties.Sum(p => p.BillAttitude[this.Bill].Disagree), - +this.parties.Sum(p => p.BillAttitude[this.Bill].Neutral) + +this.parties.Sum(p => p.BillAttitudes[this.Bill].Agree), + +this.parties.Sum(p => p.BillAttitudes[this.Bill].Disagree), + +this.parties.Sum(p => p.BillAttitudes[this.Bill].Neutral) ); // offset the value of agree by the class of IBill diff --git a/Util/Politic/IParty.cs b/Util/Politic/IParty.cs index 7d5d6af..00ee7c1 100644 --- a/Util/Politic/IParty.cs +++ b/Util/Politic/IParty.cs @@ -12,6 +12,7 @@ public interface IParty ushort Ticket { get; } ushort SeatCount { get; } ushort Id { get; } - IDictionary BillAttitude { get; } + IDictionary BillAttitudes { get; } + AbstractVoteResult GetBillAttitude(IBill bill); } -} \ No newline at end of file +} diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index d257dc5..7bd9ab0 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -13,7 +13,7 @@ public class Party : IParty public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; public ushort Id { get; } - public IDictionary BillAttitude { get; } + public IDictionary BillAttitudes { get; } /// /// 政党 @@ -26,7 +26,7 @@ public Party(string name, ushort id, PartyInterestData interestData, Dictionary< this.Name = name; this.Id = id; this.interestData = interestData; - this.BillAttitude = billAttitude; + this.BillAttitudes = billAttitude; } public PartyInterestData GetPartyInterestData() { @@ -40,5 +40,12 @@ public void AddWinChance(ushort val) { public void ResetWinChance() { this.WinChance = default; } + + public AbstractVoteResult GetBillAttitude(IBill bill) { + if (this.BillAttitudes.ContainsKey(bill)) { + return this.BillAttitudes[bill]; + } + return null; + } } } diff --git a/Util/Politic/PartyInterestData.cs b/Util/Politic/PartyInterestData.cs index 0c45f46..fa6eefd 100644 --- a/Util/Politic/PartyInterestData.cs +++ b/Util/Politic/PartyInterestData.cs @@ -1,6 +1,4 @@ -using RealCity.Attributes; - -namespace RealCity.Util.Politic +namespace RealCity.Util.Politic { /// /// 政党兴趣度数据 @@ -13,15 +11,10 @@ public class PartyInterestData private const byte AgeNum = 3; private const byte GenderNum = 2; - [ArrayLength(4)] public byte[] EducationLevel { get; private set; } - [ArrayLength(15)] public byte[] SubService { get; private set; } - [ArrayLength(3)] public byte[] FamilyMoney { get; private set; } - [ArrayLength(3)] public byte[] Age { get; private set; } - [ArrayLength(2)] public byte[] Gender { get; private set; } /// @@ -45,4 +38,4 @@ public PartyInterestData(byte[] edu, byte[] service, byte[] familyMoney, byte[] this.Gender = gender; } } -} \ No newline at end of file +} diff --git a/Util/Politics.cs b/Util/Politics.cs index be618dc..7f08dab 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -7,7 +7,8 @@ namespace RealCity.Util { - public class Politics { + public class Politics + { private const Citizen.AgeGroup VotingAge = Citizen.AgeGroup.Young; private const int MaxTaxValue = 20; private const int MinTaxValue = 0; @@ -21,19 +22,7 @@ public class Politics { private static IParty nParty; public static IParty[] Parties; - public static void ResetWinChance() { - Parties.ForEach(p => p.ResetWinChance()); - } - public static int GetAllSeatCount() { - return Parties.Sum(p => { - return p.SeatCount; - }); - } - public static int GetAllTicket() { - return Parties.Sum(p => { - return p.Ticket; - }); - } + public static bool IsOnElection() { return nextMeetingInterval == 1; } @@ -249,6 +238,9 @@ public static void DataInit() { // maybe this can help improve performance Array.Sort(ps, ps.Select(p => p.Id).ToArray()); Parties = ps; + + Government.Instance.UpdateSeats(Election.CurrentElectionInfo); + } public static void Save(ref byte[] saveData) { @@ -352,4 +344,4 @@ public static void Load(ref byte[] saveData) { } } } -} \ No newline at end of file +} diff --git a/Util/SaveAndRestore.cs b/Util/SaveAndRestore.cs index 0bd4c85..088dc19 100644 --- a/Util/SaveAndRestore.cs +++ b/Util/SaveAndRestore.cs @@ -76,7 +76,7 @@ public static void SaveData(ref int idex, int[] item, ref byte[] container) { public static void SaveData(ref int idex, byte item, ref byte[] container) { container[idex] = item; - idex ++; + idex++; } @@ -296,7 +296,7 @@ public static void LoadData(ref int idex, byte[] container, ref byte item) { DebugLog.LogToFileOnly($"load data is too short, please check {container.Length}"); item = 0; } - idex ++; + idex++; } public static void LoadData(ref int idex, byte[] container, ref byte[] item) { @@ -304,11 +304,11 @@ public static void LoadData(ref int idex, byte[] container, ref byte[] item) { if (idex < container.Length) { for (i = 0; i < item.Length; i++) { item[i] = container[idex]; - idex ++; + idex++; } } else { for (i = 0; i < item.Length; i++) { - idex ++; + idex++; } DebugLog.LogToFileOnly($"load data is too short, please check {container.Length}"); } @@ -450,4 +450,4 @@ public override void OnLoadData() { CitizenUnitData.Load(ref saveData); } } -} \ No newline at end of file +} diff --git a/Util/SpriteUtilities.cs b/Util/SpriteUtilities.cs index 48be35c..b0d7ff4 100644 --- a/Util/SpriteUtilities.cs +++ b/Util/SpriteUtilities.cs @@ -159,4 +159,4 @@ private static bool TryAdjacent(ref Color32 pixel, Color32 adjacent) { } //========================================================================= } -} \ No newline at end of file +} From ce78138b808f95223bb3f57edd40f3cfd7dfc01f Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sat, 5 Sep 2020 19:25:50 +0800 Subject: [PATCH 33/38] Update UI --- UI/PoliticsUI.cs | 166 +++++++++++------- Util/Politic/AbstractBill.cs | 3 + Util/Politic/Bill/ReduceBenefitBill.cs | 3 + Util/Politic/Bill/ReduceCommercialTaxBill.cs | 3 + Util/Politic/Bill/ReduceIndustryTaxBill.cs | 3 + Util/Politic/Bill/ReduceResidentTaxBill.cs | 3 + Util/Politic/Bill/RiseBenefitBill.cs | 3 + Util/Politic/Bill/RiseCommercialTaxBill.cs | 3 + Util/Politic/Bill/RiseIndustryTaxBill.cs | 3 + Util/Politic/Bill/RiseResidentTaxBill.cs | 3 + Util/Politic/Election.cs | 6 +- Util/Politic/ElectionUtil/ElectionInfo.cs | 4 +- .../Politic/ElectionUtil/PartyInterestCalc.cs | 9 - Util/Politic/Government.cs | 37 +++- Util/Politic/IBill.cs | 1 + Util/Politic/IParty.cs | 9 + Util/Politic/Party.cs | 11 +- Util/Politic/PartyFactory.cs | 15 +- Util/Politics.cs | 28 +-- 19 files changed, 214 insertions(+), 99 deletions(-) diff --git a/UI/PoliticsUI.cs b/UI/PoliticsUI.cs index 7b2314b..b3a6a72 100644 --- a/UI/PoliticsUI.cs +++ b/UI/PoliticsUI.cs @@ -2,6 +2,8 @@ using ColossalFramework.UI; using UnityEngine; using RealCity.Util; +using RealCity.Util.Politic; +using System.Text; namespace RealCity.UI { @@ -17,11 +19,12 @@ public class PoliticsUI : UIPanel private UIButton m_closeButton; private UILabel m_title; private UILabel parliamentSeats; - private UILabel communist; + private UILabel communist { get; set; } private UILabel green; private UILabel socialist; private UILabel liberal; private UILabel national; + private UILabel[] parties; private UILabel goverment; private UILabel nextVote; private UILabel currentMeetingItem; @@ -78,34 +81,46 @@ private void ShowOnGui() { parliamentSeats.relativePosition = new Vector3(SPACING, 50f); parliamentSeats.autoSize = true; - communist = AddUIComponent(); - communist.text = Localization.Get("COMMUNIST"); - communist.relativePosition = new Vector3(SPACING, parliamentSeats.relativePosition.y + SPACING22); - communist.autoSize = true; + this.parties = new UILabel[Politics.Parties.Length]; + var posX = SPACING; + var posY = parliamentSeats.relativePosition.y + SPACING22; + for (int i = 0; i < this.parties.Length; i++) { + this.parties[i] = AddUIComponent(); + this.parties[i].text = Localization.Get(Politics.Parties[0].PartyType.ToString("G").ToUpper()); + this.parties[i].relativePosition = new Vector3(posX, posY); + this.parties[i].autoSize = true; + posX += 160f; + //posY = this.parties[i].relativePosition.y; + } + + //communist = AddUIComponent(); + //communist.text = Localization.Get("COMMUNIST"); + //communist.relativePosition = new Vector3(SPACING, parliamentSeats.relativePosition.y + SPACING22); + //communist.autoSize = true; - green = AddUIComponent(); - green.text = Localization.Get("GREEN"); - green.relativePosition = new Vector3(communist.relativePosition.x + 160f, communist.relativePosition.y); - green.autoSize = true; + //green = AddUIComponent(); + //green.text = Localization.Get("GREEN"); + //green.relativePosition = new Vector3(communist.relativePosition.x + 160f, communist.relativePosition.y); + //green.autoSize = true; - socialist = AddUIComponent(); - socialist.text = Localization.Get("SOCIALIST"); - socialist.relativePosition = new Vector3(green.relativePosition.x + 160f, green.relativePosition.y); - socialist.autoSize = true; + //socialist = AddUIComponent(); + //socialist.text = Localization.Get("SOCIALIST"); + //socialist.relativePosition = new Vector3(green.relativePosition.x + 160f, green.relativePosition.y); + //socialist.autoSize = true; - liberal = AddUIComponent(); - liberal.text = Localization.Get("LIBERAL"); - liberal.relativePosition = new Vector3(socialist.relativePosition.x + 160f, socialist.relativePosition.y); - liberal.autoSize = true; + //liberal = AddUIComponent(); + //liberal.text = Localization.Get("LIBERAL"); + //liberal.relativePosition = new Vector3(socialist.relativePosition.x + 160f, socialist.relativePosition.y); + //liberal.autoSize = true; - national = AddUIComponent(); - national.text = Localization.Get("NATIONAL"); - national.relativePosition = new Vector3(liberal.relativePosition.x + 160f, liberal.relativePosition.y); - national.autoSize = true; + //national = AddUIComponent(); + //national.text = Localization.Get("NATIONAL"); + //national.relativePosition = new Vector3(liberal.relativePosition.x + 160f, liberal.relativePosition.y); + //national.autoSize = true; goverment = AddUIComponent(); goverment.text = Localization.Get("GOVERMENT"); - goverment.relativePosition = new Vector3(SPACING, communist.relativePosition.y + SPACING22 + 20f); + goverment.relativePosition = new Vector3(SPACING, this.parties[0].relativePosition.y + SPACING22 + 20f); goverment.autoSize = true; nextVote = AddUIComponent(); @@ -156,45 +171,60 @@ private void RefreshDisplayData() { if (isVisible) { m_title.text = Localization.Get("PARLIAMENT_HALL"); parliamentSeats.text = Localization.Get("PARLIAMENT_SEATS"); - communist.text = string.Format(Localization.Get("COMMUNIST") + " [{0}]", Politics.cPartySeats); - green.text = string.Format(Localization.Get("GREEN") + " [{0}]", Politics.gPartySeats); - socialist.text = string.Format(Localization.Get("SOCIALIST") + " [{0}]", Politics.sPartySeats); - liberal.text = string.Format(Localization.Get("LIBERAL") + " [{0}]", Politics.lPartySeats); - national.text = string.Format(Localization.Get("NATIONAL") + " [{0}]", Politics.nPartySeats); - nextVote.text = string.Format(Localization.Get("NEXT_VOTE") + " [{0}]", Politics.nextMeetingInterval); - - if (Politics.currentBillId > 7) { - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ": N/A"); - } else { - switch (Politics.currentBillId) { - case 0: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_RESIDENT_TAX")); - break; - case 1: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_RESIDENT_TAX")); - break; - case 2: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_BENEFIT")); - break; - case 3: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_BENEFIT")); - break; - case 4: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_COMMERIAL_TAX")); - break; - case 5: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_COMMERIAL_TAX")); - break; - case 6: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_INDUSTRIAL_TAX")); - break; - case 7: - currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_INDUSTRIAL_TAX")); - break; - } + //communist.text = string.Format(Localization.Get("COMMUNIST") + " [{0}]", Politics.cPartySeats); + //green.text = string.Format(Localization.Get("GREEN") + " [{0}]", Politics.gPartySeats); + //socialist.text = string.Format(Localization.Get("SOCIALIST") + " [{0}]", Politics.sPartySeats); + //liberal.text = string.Format(Localization.Get("LIBERAL") + " [{0}]", Politics.lPartySeats); + //national.text = string.Format(Localization.Get("NATIONAL") + " [{0}]", Politics.nPartySeats); + //nextVote.text = string.Format(Localization.Get("NEXT_VOTE") + " [{0}]", Politics.nextMeetingInterval); + + for (int i = 0; i < this.parties.Length; i++) { + this.parties[i].text = $"{Localization.Get(Politics.Parties[i].PartyType.ToString("G").ToUpper())} [{Government.Instance.Seats[i]}]"; } - voteResult.text = string.Format(Localization.Get("VOTE_RESULT") + ": " + Localization.Get("YES") + ":" + Politics.currentYes.ToString() + " " + Localization.Get("NO") + ":" + Politics.currentNo.ToString() + " " + Localization.Get("NO_ATTEND") + ":" + Politics.currentNoAttend.ToString()); + currentMeetingItem.text = $"{Localization.Get("CURRENT_MEETING_ITEM")}:{Localization.Get(Government.Instance.currentBill.Name)}"; + + //if (Politics.currentBillId > 7) { + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ": N/A"); + //} else { + // switch (Politics.currentBillId) { + // case 0: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_RESIDENT_TAX")); + // break; + // case 1: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_RESIDENT_TAX")); + // break; + // case 2: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_BENEFIT")); + // break; + // case 3: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_BENEFIT")); + // break; + // case 4: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_COMMERIAL_TAX")); + // break; + // case 5: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_COMMERIAL_TAX")); + // break; + // case 6: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("RISE_INDUSTRIAL_TAX")); + // break; + // case 7: + // currentMeetingItem.text = string.Format(Localization.Get("CURRENT_MEETING_ITEM") + ":" + Localization.Get("FALL_INDUSTRIAL_TAX")); + // break; + // } + //} + + //voteResult.text = string.Format(Localization.Get("VOTE_RESULT") + ": " + Localization.Get("YES") + ":" + Politics.currentYes.ToString() + " " + Localization.Get("NO") + ":" + Politics.currentNo.ToString() + " " + Localization.Get("NO_ATTEND") + ":" + Politics.currentNoAttend.ToString()); + voteResult.text = string.Format("{0}: {1}:{2} {3}:{4} {5}:{6}", + Localization.Get("VOTE_RESULT"), + Localization.Get("YES"), + Government.Instance.LastMeeting.VoteResult.Agree, + Localization.Get("NO"), + Government.Instance.LastMeeting.VoteResult.Disagree, + Localization.Get("NO_ATTEND"), + Government.Instance.LastMeeting.VoteResult.Neutral + ); currentPolitics.text = string.Format(Localization.Get("CURRENT_POLICY")); benefit.text = string.Format(Localization.Get("BENEFIT") + " " + ((int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f)).ToString()); resident.text = string.Format(Localization.Get("RESIDENT_SALARY_TAX") + " " + (Politics.residentTax << 1).ToString() + "%"); @@ -221,6 +251,24 @@ private void RefreshDisplayData() { goverment.text = string.Format(Localization.Get("GOVERMENT") + Localization.Get("COMMUNIST") + " " + Localization.Get("GREEN") + " " + Localization.Get("SOCIALIST") + " " + Localization.Get("LIBERAL") + " " + Localization.Get("NATIONAL") + " " + Localization.Get("ALL_UNION")); } + StringBuilder sb = new StringBuilder(); + sb.Append(Localization.Get("GOVERMENT")).Append(' '); + Government.Instance.RulingParties.ForEach(p => + //sb.Append(Localization.Get(p.PartyType.ToString("G").ToUpper())) + sb.Append(p.ToString()).Append(' ') + ); + // bad codes + if (Government.Instance.GovernmentType == GovernmentType.LeftUnion) { + sb.Append(Localization.Get("LEFT_UNION")); + } else if (Government.Instance.GovernmentType == GovernmentType.WideLeftUnion) { + sb.Append(Localization.Get("WIDE_LEFT_UNION")); + } else if (Government.Instance.GovernmentType == GovernmentType.RightUnion) { + sb.Append(Localization.Get("RIGHT_UNION")); + } else if (Government.Instance.GovernmentType == GovernmentType.RightUnion) { + sb.Append(Localization.Get("ALL_UNION")); + } + goverment.text = sb.ToString(); + refeshOnce = false; } } diff --git a/Util/Politic/AbstractBill.cs b/Util/Politic/AbstractBill.cs index 2c201f1..63a295a 100644 --- a/Util/Politic/AbstractBill.cs +++ b/Util/Politic/AbstractBill.cs @@ -6,9 +6,12 @@ public abstract class AbstractBill : IBill { protected int effectVal; + public abstract string Name { get; } + public AbstractBill(int effectVal) { this.effectVal = effectVal; } + public abstract void Implement(); public abstract bool IsImplementable(); } diff --git a/Util/Politic/Bill/ReduceBenefitBill.cs b/Util/Politic/Bill/ReduceBenefitBill.cs index 7be49e5..a991323 100644 --- a/Util/Politic/Bill/ReduceBenefitBill.cs +++ b/Util/Politic/Bill/ReduceBenefitBill.cs @@ -2,10 +2,13 @@ { public class ReduceBenefitBill : AbstractBill { + public override string Name { get; } = "FALL_BENEFIT"; + public ReduceBenefitBill(int val) : base(val) { } + public override void Implement() { Politics.benefitOffset -= base.effectVal; } diff --git a/Util/Politic/Bill/ReduceCommercialTaxBill.cs b/Util/Politic/Bill/ReduceCommercialTaxBill.cs index 0e162fa..f86d900 100644 --- a/Util/Politic/Bill/ReduceCommercialTaxBill.cs +++ b/Util/Politic/Bill/ReduceCommercialTaxBill.cs @@ -2,10 +2,13 @@ { public class ReduceCommercialTaxBill : AbstractBill { + public override string Name => "FALL_COMMERIAL_TAX"; + public ReduceCommercialTaxBill(int val) : base(val) { } + public override void Implement() { Politics.commercialTax -= base.effectVal; } diff --git a/Util/Politic/Bill/ReduceIndustryTaxBill.cs b/Util/Politic/Bill/ReduceIndustryTaxBill.cs index ce5a654..aa910cc 100644 --- a/Util/Politic/Bill/ReduceIndustryTaxBill.cs +++ b/Util/Politic/Bill/ReduceIndustryTaxBill.cs @@ -2,10 +2,13 @@ { public class ReduceIndustryTaxBill : AbstractBill { + public override string Name => "FALL_INDUSTRIAL_TAX"; + public ReduceIndustryTaxBill(int val) : base(val) { } + public override void Implement() { Politics.industryTax -= base.effectVal; } diff --git a/Util/Politic/Bill/ReduceResidentTaxBill.cs b/Util/Politic/Bill/ReduceResidentTaxBill.cs index fccf314..8d9ec80 100644 --- a/Util/Politic/Bill/ReduceResidentTaxBill.cs +++ b/Util/Politic/Bill/ReduceResidentTaxBill.cs @@ -2,10 +2,13 @@ { public class ReduceResidentTaxBill : AbstractBill { + public override string Name => "FALL_RESIDENT_TAX"; + public ReduceResidentTaxBill(int val) : base(val) { } + public override void Implement() { Politics.residentTax -= base.effectVal; } diff --git a/Util/Politic/Bill/RiseBenefitBill.cs b/Util/Politic/Bill/RiseBenefitBill.cs index 912127c..c887211 100644 --- a/Util/Politic/Bill/RiseBenefitBill.cs +++ b/Util/Politic/Bill/RiseBenefitBill.cs @@ -5,10 +5,13 @@ namespace RealCity.Util.Politic.Bill { public class RiseBenefitBill : AbstractBill { + public override string Name => "RISE_BENEFIT"; + public RiseBenefitBill(int val) : base(val) { } + public override void Implement() { Politics.benefitOffset += base.effectVal; } diff --git a/Util/Politic/Bill/RiseCommercialTaxBill.cs b/Util/Politic/Bill/RiseCommercialTaxBill.cs index 28b728e..9d429ab 100644 --- a/Util/Politic/Bill/RiseCommercialTaxBill.cs +++ b/Util/Politic/Bill/RiseCommercialTaxBill.cs @@ -5,10 +5,13 @@ namespace RealCity.Util.Politic.Bill { public class RiseCommercialTaxBill : AbstractBill { + public override string Name => "RISE_COMMERIAL_TAX"; + public RiseCommercialTaxBill(int val) : base(val) { } + public override void Implement() { Politics.commercialTax += base.effectVal; } diff --git a/Util/Politic/Bill/RiseIndustryTaxBill.cs b/Util/Politic/Bill/RiseIndustryTaxBill.cs index 76486a2..fe64134 100644 --- a/Util/Politic/Bill/RiseIndustryTaxBill.cs +++ b/Util/Politic/Bill/RiseIndustryTaxBill.cs @@ -5,10 +5,13 @@ namespace RealCity.Util.Politic.Bill { public class RiseIndustryTaxBill : AbstractBill { + public override string Name => "RISE_INDUSTRIAL_TAX"; + public RiseIndustryTaxBill(int val) : base(val) { } + public override void Implement() { Politics.industryTax += base.effectVal; } diff --git a/Util/Politic/Bill/RiseResidentTaxBill.cs b/Util/Politic/Bill/RiseResidentTaxBill.cs index 401a953..cc83243 100644 --- a/Util/Politic/Bill/RiseResidentTaxBill.cs +++ b/Util/Politic/Bill/RiseResidentTaxBill.cs @@ -5,10 +5,13 @@ namespace RealCity.Util.Politic.Bill { public class RiseResidentTaxBill : AbstractBill { + public override string Name => "RISE_RESIDENT_TAX"; + public RiseResidentTaxBill(int val) : base(val) { } + public override void Implement() { Politics.residentTax += base.effectVal; } diff --git a/Util/Politic/Election.cs b/Util/Politic/Election.cs index aca52c1..78825fa 100644 --- a/Util/Politic/Election.cs +++ b/Util/Politic/Election.cs @@ -8,18 +8,18 @@ namespace RealCity.Util.Politic public static class Election { private static IParty[] Parties { get; set; } = Politics.Parties; + /// /// 选举信息 /// - public static ElectionInfo CurrentElectionInfo { get; private set; }; - + public static ElectionInfo CurrentElectionInfo { get; private set; } public static void NextElection() { CurrentElectionInfo = new ElectionInfo(Parties); } /// - /// 是否即将选举 + /// Is on election? /// /// public static bool IsOnElection() { diff --git a/Util/Politic/ElectionUtil/ElectionInfo.cs b/Util/Politic/ElectionUtil/ElectionInfo.cs index 0a717ce..1301bf1 100644 --- a/Util/Politic/ElectionUtil/ElectionInfo.cs +++ b/Util/Politic/ElectionUtil/ElectionInfo.cs @@ -1,5 +1,4 @@ -using ColossalFramework.UI; -using System; +using System; using System.Linq; namespace RealCity.Util.Politic.ElectionUtil @@ -26,7 +25,6 @@ public ElectionInfo(IParty[] parties) { this.TicketCounter = new int[parties.Length]; } public int GetAllTickets() { - // possible overflow? return TicketCounter.Sum(); } } diff --git a/Util/Politic/ElectionUtil/PartyInterestCalc.cs b/Util/Politic/ElectionUtil/PartyInterestCalc.cs index 9e30d5d..a541df0 100644 --- a/Util/Politic/ElectionUtil/PartyInterestCalc.cs +++ b/Util/Politic/ElectionUtil/PartyInterestCalc.cs @@ -43,15 +43,6 @@ public void Calc() { this.Val += GetFromGender(Citizen.GetGender(this.citizenId)); } - /// - /// 增加政党胜算 - /// - public void AddPartyWinChance() { - this.Party.AddWinChance(this.Val); - //啊这...不加会出bug吗 - this.Val = default; - } - /// /// 以教育背景计算对政党的兴趣度 /// diff --git a/Util/Politic/Government.cs b/Util/Politic/Government.cs index 50a7197..0c19347 100644 --- a/Util/Politic/Government.cs +++ b/Util/Politic/Government.cs @@ -1,4 +1,6 @@ using RealCity.Util.Politic.ElectionUtil; +using System.Collections; +using System.Collections.Generic; using System.Linq; namespace RealCity.Util.Politic @@ -9,16 +11,20 @@ namespace RealCity.Util.Politic public class Government : IGovernment { private const int MinSeatCount = 99; - public static IGovernment Instance { get; } - private IBill currentBill = Bills.GetRandomBill(); + public static Government Null = new Government(); + public static Government Instance { get; set; } + public IGovernmentalMeeting LastMeeting { get; private set; } + + public IBill currentBill = Bills.GetRandomBill(); public IParty[] Parties { get; private set; } public GovernmentType GovernmentType { get; private set; } - //public IParty[] RulingParties { get; private set; } + public IParty[] RulingParties { get; private set; } // refer RealCityEconomyExtension.cs public int[] Seats { get; private set; } public int AllSeatCount => this.Seats.Sum(); + public void UpdateSeats(ElectionInfo info) { int cnt = info.GetAllTickets(); this.Seats = new int[info.PartiesCount]; @@ -68,13 +74,14 @@ public void UpdateSeats(ElectionInfo info) { //} #endregion } + public void UpdateGovType() { bool isOk = default; int halfSeatCount = (MinSeatCount >> 1) + 1; for (int i = 0; i < this.Seats.Length; i++) { if (this.Seats[i] >= halfSeatCount) { this.GovernmentType = GovernmentType.Single; - //this.RulingParties = new IParty[] { this.Parties[i] }; + this.RulingParties = new IParty[] { this.Parties[i] }; isOk = true; } } @@ -86,23 +93,33 @@ public void UpdateGovType() { int left, wideLeft, right; left = wideLeft = right = default; for (int i = 0; i < this.Seats.Length; i++) { - if (this.Parties[i].Name == "Green" || this.Parties[i].Name == "Socialist") { + if (this.Parties[i].PartyType == PartyType.Green || this.Parties[i].PartyType == PartyType.Socialist) { left += this.Seats[i]; - } else if (this.Parties[i].Name == "Communist") { + } else if (this.Parties[i].PartyType == PartyType.Communist) { wideLeft += this.Seats[i]; - } else if (this.Parties[i].Name == "Liberal" || this.Parties[i].Name == "National") { + } else if (this.Parties[i].PartyType == PartyType.Liberal || this.Parties[i].PartyType == PartyType.National) { right += this.Seats[i]; } } wideLeft += left; if (left >= halfSeatCount) { this.GovernmentType = GovernmentType.LeftUnion; + this.RulingParties = this.Parties + .Where(p => p.PartyType == PartyType.Green || p.PartyType == PartyType.Socialist) + .ToArray(); } else if (wideLeft >= halfSeatCount) { this.GovernmentType = GovernmentType.WideLeftUnion; + this.RulingParties = this.Parties + .Where(p => p.PartyType == PartyType.Green || p.PartyType == PartyType.Socialist || p.PartyType == PartyType.Communist) + .ToArray(); } else if (right >= halfSeatCount) { this.GovernmentType = GovernmentType.RightUnion; + this.RulingParties = this.Parties + .Where(p => p.PartyType == PartyType.Liberal || p.PartyType == PartyType.National) + .ToArray(); } else { this.GovernmentType = GovernmentType.Grand; + this.RulingParties = this.Parties; } } @@ -119,6 +136,7 @@ public IGovernmentalMeeting HoldMeeting() { if (v.VoteResult.IsApprovable) { v.Bill.Implement(); } + this.LastMeeting = v; return v; } @@ -138,5 +156,10 @@ private void FixSeatCount() { this.Seats[idx] += missingCount; } } + + public static void Start() { + Instance = Null as Government; + Instance.Parties = Politics.Parties; + } } } diff --git a/Util/Politic/IBill.cs b/Util/Politic/IBill.cs index 00395b8..dda5d1d 100644 --- a/Util/Politic/IBill.cs +++ b/Util/Politic/IBill.cs @@ -2,6 +2,7 @@ { public interface IBill { + string Name { get; } void Implement(); bool IsImplementable(); } diff --git a/Util/Politic/IParty.cs b/Util/Politic/IParty.cs index 00ee7c1..a891c00 100644 --- a/Util/Politic/IParty.cs +++ b/Util/Politic/IParty.cs @@ -12,7 +12,16 @@ public interface IParty ushort Ticket { get; } ushort SeatCount { get; } ushort Id { get; } + PartyType PartyType { get; } IDictionary BillAttitudes { get; } AbstractVoteResult GetBillAttitude(IBill bill); } + public enum PartyType + { + Communist, + Green, + Socialist, + Liberal, + National, + } } diff --git a/Util/Politic/Party.cs b/Util/Politic/Party.cs index 7bd9ab0..a55faea 100644 --- a/Util/Politic/Party.cs +++ b/Util/Politic/Party.cs @@ -13,7 +13,8 @@ public class Party : IParty public ushort Ticket { get; } = default; public ushort SeatCount { get; } = default; public ushort Id { get; } - public IDictionary BillAttitudes { get; } + public PartyType PartyType { get; } + public IDictionary BillAttitudes { get; } /// /// 政党 @@ -22,9 +23,10 @@ public class Party : IParty /// Id /// 民众对政党的兴趣度 /// 政党对政策的态度 - public Party(string name, ushort id, PartyInterestData interestData, Dictionary billAttitude) { + public Party(string name, ushort id, PartyType type, PartyInterestData interestData, Dictionary billAttitude) { this.Name = name; this.Id = id; + this.PartyType = type; this.interestData = interestData; this.BillAttitudes = billAttitude; } @@ -45,7 +47,12 @@ public AbstractVoteResult GetBillAttitude(IBill bill) { if (this.BillAttitudes.ContainsKey(bill)) { return this.BillAttitudes[bill]; } + // dont wanna Party know VoteResult... return null; } + + public override string ToString() { + return Localization.Get(this.PartyType.ToString("G").ToUpper()); + } } } diff --git a/Util/Politic/PartyFactory.cs b/Util/Politic/PartyFactory.cs index d43d7c3..fc4e7c6 100644 --- a/Util/Politic/PartyFactory.cs +++ b/Util/Politic/PartyFactory.cs @@ -35,8 +35,9 @@ public IParty MakeCParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( - "Communist", + "COMMUNIST", this.NextPartyId++, + PartyType.Communist, new PartyInterestData( new byte[4] { 30, 20, 10, 5 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, @@ -70,8 +71,9 @@ public IParty MakeGParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( - "Green", + "GREEN", this.NextPartyId++, + PartyType.Green, new PartyInterestData( new byte[4] { 0, 10, 20, 25 }, new byte[15] { 0, 20, 10, 15, 20, 30, 10, 0, 5, 10, 5, 30, 35, 40, 50, }, @@ -105,8 +107,9 @@ public IParty MakeSParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( - "Socialist", + "SOCIALIST", this.NextPartyId++, + PartyType.Socialist, new PartyInterestData( new byte[4] { 10, 25, 30, 40 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, @@ -140,8 +143,9 @@ public IParty MakeLParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( - "Liberal", + "LIBERAL", this.NextPartyId++, + PartyType.Liberal, new PartyInterestData( new byte[4] { 10, 20, 30, 25 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, @@ -175,8 +179,9 @@ public IParty MakeNParty() { billAttitudeMap.Add(Bills.ReduceResidentTax, reduceBenefitOffset); IParty party = new Party( - "National", + "NATIONAL", this.NextPartyId++, + PartyType.National, new PartyInterestData( new byte[4] { 50, 25, 10, 5 }, new byte[15] { 35, 0, 20, 10, 0, 0, 35, 50, 30, 15, 25, 10, 5, 0, 0, }, diff --git a/Util/Politics.cs b/Util/Politics.cs index 7f08dab..587c7e1 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -1,8 +1,6 @@ using ColossalFramework; -using ColossalFramework.UI; using RealCity.Util.Politic; using System; -using System.Collections.Generic; using System.Linq; namespace RealCity.Util @@ -22,6 +20,22 @@ public class Politics private static IParty nParty; public static IParty[] Parties; + public static bool CanRiseResidentTax => residentTax < MaxTaxValue; + public static bool CanReduceResidentTax => residentTax > MinTaxValue; + public static bool CanRiseCommercialTax => commercialTax < MaxTaxValue; + public static bool CanReduceCommercialTax => commercialTax > MinTaxValue; + public static bool CanRiseIndustryTax => industryTax < MaxTaxValue; + public static bool CanReduceIndustryTax => industryTax > MinTaxValue; + public static bool CanRiseBenefit => benefitOffset < MaxBenefitValue; + public static bool CanReduceBenefit => benefitOffset > MinBenefitValue; + + public static IParty[] FindPartiesByType(PartyType type) { + var q = + from p in Parties + where p.PartyType == type + select p; + return q.ToArray(); + } public static bool IsOnElection() { return nextMeetingInterval == 1; @@ -33,7 +47,6 @@ public static bool IsOnElection() { /// /// public static bool IsOverVotingAge(Citizen.AgeGroup age) { - //这地方不一定能解耦合...政治就是和人相关的嘛... return age >= VotingAge; } @@ -46,14 +59,6 @@ public static bool IsOverVotingAge(ref Citizen citizen) { return IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age)); } - public static bool CanRiseResidentTax => residentTax < MaxTaxValue; - public static bool CanReduceResidentTax => residentTax > MinTaxValue; - public static bool CanRiseCommercialTax => commercialTax < MaxTaxValue; - public static bool CanReduceCommercialTax => commercialTax > MinTaxValue; - public static bool CanRiseIndustryTax => industryTax < MaxTaxValue; - public static bool CanReduceIndustryTax => industryTax > MinTaxValue; - public static bool CanRiseBenefit => benefitOffset < MaxBenefitValue; - public static bool CanReduceBenefit => benefitOffset > MinBenefitValue; //学历对选举投票的影响因子 public static byte[,] education = { {30, 0, 10, 10, 50}, @@ -239,6 +244,7 @@ public static void DataInit() { Array.Sort(ps, ps.Select(p => p.Id).ToArray()); Parties = ps; + Government.Start(); Government.Instance.UpdateSeats(Election.CurrentElectionInfo); } From 0d1fced7534a99b905770a4c73f0c75d2cca6fea Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Sun, 6 Sep 2020 21:19:17 +0800 Subject: [PATCH 34/38] Update extension method for Array and delete redundant codes --- Loader.cs | 6 +++--- UI/PoliticsUI.cs | 4 ++-- Util/ArrayExtension.cs | 12 ++++++++++++ Util/Politics.cs | 1 - 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Loader.cs b/Loader.cs index daf0e73..bcfbd01 100644 --- a/Loader.cs +++ b/Loader.cs @@ -89,9 +89,9 @@ public static void InitData() { Politics.DataInit(); - System.Random rand = new System.Random(); - RealCityEconomyExtension.partyTrend = (byte)rand.Next(5); - RealCityEconomyExtension.partyTrendStrength = (byte)rand.Next(300); + //System.Random rand = new System.Random(); + //RealCityEconomyExtension.partyTrend = (byte)rand.Next(5); + //RealCityEconomyExtension.partyTrendStrength = (byte)rand.Next(300); DebugLog.LogToFileOnly("InitData Done"); } diff --git a/UI/PoliticsUI.cs b/UI/PoliticsUI.cs index b3a6a72..7b6347c 100644 --- a/UI/PoliticsUI.cs +++ b/UI/PoliticsUI.cs @@ -1,5 +1,4 @@ -using ColossalFramework; -using ColossalFramework.UI; +using ColossalFramework.UI; using UnityEngine; using RealCity.Util; using RealCity.Util.Politic; @@ -257,6 +256,7 @@ private void RefreshDisplayData() { //sb.Append(Localization.Get(p.PartyType.ToString("G").ToUpper())) sb.Append(p.ToString()).Append(' ') ); + // bad codes if (Government.Instance.GovernmentType == GovernmentType.LeftUnion) { sb.Append(Localization.Get("LEFT_UNION")); diff --git a/Util/ArrayExtension.cs b/Util/ArrayExtension.cs index d1a03de..51697d6 100644 --- a/Util/ArrayExtension.cs +++ b/Util/ArrayExtension.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; public static class ArrayExtension { @@ -49,4 +50,15 @@ public static void Initialize(this Array arr, T value) { public static T GetRandomElement(this T[] arr, Random random) { return arr[random.Next(arr.Length)]; } + /// + /// Performs the specified action on each element of the + /// + /// + /// + /// The delegate to perform on each element of the + public static void ForEach(this IEnumerable value, Action action) { + foreach (T item in value) { + action(item); + } + } } diff --git a/Util/Politics.cs b/Util/Politics.cs index 587c7e1..a5232c7 100644 --- a/Util/Politics.cs +++ b/Util/Politics.cs @@ -246,7 +246,6 @@ public static void DataInit() { Government.Start(); Government.Instance.UpdateSeats(Election.CurrentElectionInfo); - } public static void Save(ref byte[] saveData) { From ce7db955b39fa08ff2e36e4401c32d3510ffc04f Mon Sep 17 00:00:00 2001 From: BAC <41997195+bac0id@users.noreply.github.com> Date: Mon, 7 Sep 2020 16:00:55 +0800 Subject: [PATCH 35/38] Fix coding style --- CustomAI/RealCityIndustrialBuildingAI.cs | 3 +- CustomAI/RealCityIndustrialExtractorAI.cs | 3 +- CustomAI/RealCityIndustryBuildingAI.cs | 24 +- CustomAI/RealCityMarketAI.cs | 3 +- CustomAI/RealCityPlayerBuildingAI.cs | 9 +- CustomAI/RealCityPrivateBuildingAI.cs | 224 +++++++---- CustomAI/RealCityResidentAI.cs | 240 ++++++++---- CustomData/BuildingData.cs | 18 +- CustomData/CitizenData.cs | 21 +- CustomData/CitizenUnitData.cs | 15 +- CustomData/ICustomGameData.cs | 13 - CustomData/TransportLineData.cs | 18 +- CustomData/VehicleData.cs | 15 +- CustomManager/RealCityEconomyManager.cs | 21 +- Loader.cs | 233 ++++++++---- ...AuxiliaryBuildingAIGetResourceRatePatch.cs | 9 +- Patch/BuildingAIVisitorEnterPatch.cs | 100 +++-- Patch/CargoTruckAIArriveAtSourcePatch.cs | 12 +- Patch/CargoTruckAIArriveAtTargetPatch.cs | 27 +- ...itizenManagerCreateCitizenInstancePatch.cs | 33 +- ...anagerReleaseCitizenImplementationPatch.cs | 6 +- .../CitizenManagerReleaseUnitCitizenPatch.cs | 6 +- ...CommercialBuildingAICreateBuildingPatch.cs | 6 +- ...cialBuildingAIModifyMaterialBufferPatch.cs | 43 ++- ...cialBuildingAISimulationStepActivePatch.cs | 9 +- .../CommercialBuildingAIVisitorEnterPatch.cs | 64 +++- Patch/CommonBuildingAIGetColorPatch.cs | 12 +- Patch/CommonBuildingAIReleaseBuildingPatch.cs | 6 +- ...istrictParkCalculatePolicyExpensesPatch.cs | 15 +- ...strictParkCalculateVarsityExpensesPatch.cs | 6 +- Patch/EconomyManagerAddPrivateIncomePatch.cs | 86 +++-- ...EconomyManagerAddResourceItemClassPatch.cs | 28 +- ...yManagerAddResourcePatchItemClassDetail.cs | 19 +- Patch/EconomyManagerFetchResourcePatch.cs | 48 ++- Patch/EconomyPanelIncomeExpensesPollPatch.cs | 30 +- ...xtractingFacilityAIGetResourceRatePatch.cs | 9 +- Patch/HumanAIEnterParkAreaPatch.cs | 6 +- Patch/HumanAIEnterVehiclePatch.cs | 32 +- Patch/HumanAIStartMovingPatch.cs | 32 +- ...IndustrialBuildingAICreateBuildingPatch.cs | 6 +- ...rialBuildingAIModifyMaterialBufferPatch.cs | 34 +- ...rialBuildingAISimulationStepActivePatch.cs | 9 +- ...ialExtractorAIModifyMaterialBufferPatch.cs | 27 +- ...ialExtractorAISimulationStepActivePatch.cs | 9 +- .../IndustryBuildingGetResourcePricePatch.cs | 26 +- ...LandfillSiteAIModifyMaterialBufferPatch.cs | 36 +- Patch/MarketAIModifyMaterialBufferPatch.cs | 18 +- Patch/MarketAIVisitorEnterPatch.cs | 29 +- ...uildingAIGetOutgoingTransferReasonPatch.cs | 6 +- ...deConnectionAIModifyMaterialBufferPatch.cs | 12 +- Patch/PassengerCarAIArriveAtTargetPatch.cs | 72 ++-- Patch/PlayerBuildingAIGetResourceRatePatch.cs | 9 +- Patch/PlayerBuildingAISimulationStepPatch.cs | 25 +- ...vateBuildingAISimulationStepActivePatch.cs | 352 ++++++++++++------ ...rocessingFacilityAIGetResourceRatePatch.cs | 9 +- ...entAICitizenInstanceSimulationStepPatch.cs | 21 +- Patch/ResidentAICitizenSimulationStepPatch.cs | 20 +- ...esidentAICitizenUnitSimulationStepPatch.cs | 320 +++++++++++----- Patch/ResidentAIGetCarProbabilityPatch.cs | 19 +- Patch/TaxiAIUnloadPassengersPatch.cs | 34 +- Patch/TollBoothAIGetResourceRatePatch.cs | 9 +- Patch/TollBoothEnterBuildingSegmentPatch.cs | 46 ++- Patch/TouristAISimulationStepPatch.cs | 21 +- Patch/TransferManagerAddIncomingOfferPatch.cs | 68 ++-- Patch/TransferManagerAddOutgoingOfferPatch.cs | 48 ++- ...ortLineCalculateTargetVehicleCountPatch.cs | 254 +++++++++---- ...anagerReleaseVehicleImplementationPatch.cs | 6 +- RealCity.cs | 43 ++- RealCity.csproj | 40 +- RealCityEconomyExtension.cs | 343 ++++++++++++----- RealCityThreading.cs | 96 +++-- RebalancedIndustries/Mod.cs | 12 +- RebalancedIndustries/RI_Data.cs | 13 +- RebalancedIndustries/RI_Detours.cs | 149 +++++--- UI/BuildingButton.cs | 29 +- UI/BuildingUI.cs | 168 ++++++--- UI/EcnomicButton.cs | 47 ++- UI/EcnomicUI.cs | 28 +- UI/HumanUI.cs | 49 ++- UI/IncompatibleModsPanel.cs | 61 ++- UI/OptionUI.cs | 86 +++-- UI/PBLUI.cs | 51 ++- UI/PlayerBuildingButton.cs | 25 +- UI/PlayerBuildingUI.cs | 31 +- UI/PoliticsButton.cs | 50 ++- UI/PoliticsUI.cs | 77 ++-- UI/RealCityButton.cs | 50 ++- UI/RealCityUI.cs | 30 +- UI/TouristUI.cs | 24 +- Util/ArrayExtension.cs | 31 +- Util/DebugLog.cs | 6 +- Util/FastDelegateFactory.cs | 18 +- Util/HarmonyDetours.cs | 6 +- Util/Localization.cs | 21 +- Util/MainDataStore.cs | 12 +- Util/ModsCompatibilityChecker.cs | 40 +- Util/ObjectPrivateDataExtension.cs | 15 +- Util/Politic/AbstractBill.cs | 3 +- Util/Politic/AbstractVoteResult.cs | 12 +- Util/Politic/Bill/ReduceBenefitBill.cs | 9 +- Util/Politic/Bill/ReduceCommercialTaxBill.cs | 9 +- Util/Politic/Bill/ReduceIndustryTaxBill.cs | 9 +- Util/Politic/Bill/ReduceResidentTaxBill.cs | 9 +- Util/Politic/Bill/RiseBenefitBill.cs | 16 +- Util/Politic/Bill/RiseCommercialTaxBill.cs | 16 +- Util/Politic/Bill/RiseIndustryTaxBill.cs | 16 +- Util/Politic/Bill/RiseResidentTaxBill.cs | 16 +- Util/Politic/Bills.cs | 16 +- Util/Politic/Election.cs | 6 +- Util/Politic/ElectionUtil/ElectionInfo.cs | 6 +- Util/Politic/ElectionUtil/ElectionVoter.cs | 23 +- .../Politic/ElectionUtil/PartyInterestCalc.cs | 75 ++-- Util/Politic/Government.cs | 64 +++- Util/Politic/GovernmentalMeeting.cs | 83 +++-- Util/Politic/Party.cs | 21 +- Util/Politic/PartyFactory.cs | 15 +- Util/Politic/PartyInterestData.cs | 3 +- Util/Politic/VoteResult.cs | 6 +- Util/Politics.cs | 27 +- Util/SaveAndRestore.cs | 278 +++++++++----- Util/SpriteUtilities.cs | 57 ++- 121 files changed, 3773 insertions(+), 1722 deletions(-) delete mode 100644 CustomData/ICustomGameData.cs diff --git a/CustomAI/RealCityIndustrialBuildingAI.cs b/CustomAI/RealCityIndustrialBuildingAI.cs index 2981ef7..34208ec 100644 --- a/CustomAI/RealCityIndustrialBuildingAI.cs +++ b/CustomAI/RealCityIndustrialBuildingAI.cs @@ -23,7 +23,8 @@ public class RealCityIndustrialBuildingAI public delegate int IndustrialBuildingAIGetConsumptionDivider(IndustrialBuildingAI IndustrialBuildingAI); public static IndustrialBuildingAIGetConsumptionDivider GetConsumptionDivider; - public static void InitDelegate() { + public static void InitDelegate() + { if (GetIncomingTransferReason != null) return; if (GetOutgoingTransferReason != null) diff --git a/CustomAI/RealCityIndustrialExtractorAI.cs b/CustomAI/RealCityIndustrialExtractorAI.cs index 77402e8..b564ea1 100644 --- a/CustomAI/RealCityIndustrialExtractorAI.cs +++ b/CustomAI/RealCityIndustrialExtractorAI.cs @@ -7,7 +7,8 @@ public class RealCityIndustrialExtractorAI public delegate TransferManager.TransferReason IndustrialExtractorAIGetOutgoingTransferReason(IndustrialExtractorAI IndustrialExtractorAI); public static IndustrialExtractorAIGetOutgoingTransferReason GetOutgoingTransferReason; - public static void InitDelegate() { + public static void InitDelegate() + { if (GetOutgoingTransferReason != null) return; GetOutgoingTransferReason = FastDelegateFactory.Create(typeof(IndustrialExtractorAI), "GetOutgoingTransferReason", instanceMethod: true); diff --git a/CustomAI/RealCityIndustryBuildingAI.cs b/CustomAI/RealCityIndustryBuildingAI.cs index 0227052..5a7f337 100644 --- a/CustomAI/RealCityIndustryBuildingAI.cs +++ b/CustomAI/RealCityIndustryBuildingAI.cs @@ -5,41 +5,48 @@ namespace RealCity.CustomAI { public class RealCityIndustryBuildingAI { - public static float GetResourcePrice(TransferManager.TransferReason material) { + public static float GetResourcePrice(TransferManager.TransferReason material) + { int priceInt = 0; float price; - switch (material) { + switch (material) + { case TransferManager.TransferReason.Goods: price = 3.5f; - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Petrol: price = 3f; - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Food: price = 1.5f; - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Lumber: price = 2f; - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); break; case TransferManager.TransferReason.Coal: price = 2.5f; - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); @@ -51,7 +58,8 @@ public static float GetResourcePrice(TransferManager.TransferReason material) { case TransferManager.TransferReason.ShoppingE: case TransferManager.TransferReason.ShoppingH: price = 5f; - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { price *= MainDataStore.reduceCargoDiv; } price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f); diff --git a/CustomAI/RealCityMarketAI.cs b/CustomAI/RealCityMarketAI.cs index 18b5a5c..d76e0a4 100644 --- a/CustomAI/RealCityMarketAI.cs +++ b/CustomAI/RealCityMarketAI.cs @@ -9,7 +9,8 @@ public class RealCityMarketAI public delegate void MarketAIGetVisitBehaviour(MarketAI MarketAI, ushort buildingID, ref Building buildingData, ref Citizen.BehaviourData behaviour, ref int aliveCount, ref int totalCount); public static MarketAIGetVisitBehaviour GetVisitBehaviour; - public static void InitDelegate() { + public static void InitDelegate() + { if (GetVisitBehaviour != null) return; GetVisitBehaviour = FastDelegateFactory.Create(typeof(MarketAI), "GetVisitBehaviour", instanceMethod: true); diff --git a/CustomAI/RealCityPlayerBuildingAI.cs b/CustomAI/RealCityPlayerBuildingAI.cs index 0718eb8..6957264 100644 --- a/CustomAI/RealCityPlayerBuildingAI.cs +++ b/CustomAI/RealCityPlayerBuildingAI.cs @@ -7,7 +7,8 @@ namespace RealCity.CustomAI { public class RealCityPlayerBuildingAI { - public static float CaculateEmployeeOutcome(ushort buildingID, Building building) { + public static float CaculateEmployeeOutcome(ushort buildingID, Building building) + { float allSalary = 0; Citizen.BehaviourData behaviour = default(Citizen.BehaviourData); int aliveWorkerCount = 0; @@ -24,11 +25,13 @@ public static float CaculateEmployeeOutcome(ushort buildingID, Building building allSalary += behaviour.m_educated2Count * education2Salary; allSalary += behaviour.m_educated3Count * education3Salary; int allWorkCount = RealCityResidentAI.TotalWorkCount(buildingID, building, true, false); - if (totalWorkerCount > allWorkCount) { + if (totalWorkerCount > allWorkCount) + { allWorkCount = RealCityResidentAI.TotalWorkCount(buildingID, building, true, true); } - if ((aliveWorkerCount == 0) && (allWorkCount != 0)) { + if ((aliveWorkerCount == 0) && (allWorkCount != 0)) + { allSalary = education3Salary * allWorkCount; } diff --git a/CustomAI/RealCityPrivateBuildingAI.cs b/CustomAI/RealCityPrivateBuildingAI.cs index 741553a..553dbc9 100644 --- a/CustomAI/RealCityPrivateBuildingAI.cs +++ b/CustomAI/RealCityPrivateBuildingAI.cs @@ -27,7 +27,8 @@ public class RealCityPrivateBuildingAI public static ushort profitBuildingCountFinal = 0; public static ushort allBuildingsFinal = 0; - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { //60 int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref preBuidlingId); @@ -48,12 +49,14 @@ public static void Load(ref byte[] saveData) { SaveAndRestore.LoadData(ref i, saveData, ref profitBuildingCount); SaveAndRestore.LoadData(ref i, saveData, ref profitBuildingCountFinal); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"RealCityPrivateBuildingAI Load Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { //60 int i = 0; SaveAndRestore.SaveData(ref i, preBuidlingId, ref saveData); @@ -74,16 +77,22 @@ public static void Save(ref byte[] saveData) { SaveAndRestore.SaveData(ref i, profitBuildingCount, ref saveData); SaveAndRestore.SaveData(ref i, profitBuildingCountFinal, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"RealCityPrivateBuildingAI Save Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static TransferManager.TransferReason GetIncomingProductionType(ushort buildingID, Building data) { + public static TransferManager.TransferReason GetIncomingProductionType(ushort buildingID, Building data) + { RealCityIndustrialBuildingAI.InitDelegate(); - if (data.Info.m_buildingAI is IndustrialExtractorAI) { - } else { - switch (data.Info.m_class.m_subService) { + if (data.Info.m_buildingAI is IndustrialExtractorAI) + { + } + else + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialEco: @@ -102,20 +111,27 @@ public static TransferManager.TransferReason GetIncomingProductionType(ushort bu return TransferManager.TransferReason.None; } - public static string GetProductionType(bool isSelling, ushort buildingID, Building data) { + public static string GetProductionType(bool isSelling, ushort buildingID, Building data) + { RealCityIndustrialBuildingAI.InitDelegate(); string material = ""; - if (!isSelling) { - if (data.Info.m_buildingAI is IndustrialExtractorAI) { - } else { - switch (data.Info.m_class.m_subService) { + if (!isSelling) + { + if (data.Info.m_buildingAI is IndustrialExtractorAI) + { + } + else + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialEco: case ItemClass.SubService.CommercialLeisure: case ItemClass.SubService.CommercialTourist: CommercialBuildingAI commercialBuildingAI = data.Info.m_buildingAI as CommercialBuildingAI; - switch (commercialBuildingAI.m_incomingResource) { + switch (commercialBuildingAI.m_incomingResource) + { case TransferManager.TransferReason.Goods: material = Localization.Get("PREGOODS") + Localization.Get("LUXURY_PRODUCTS"); break; case TransferManager.TransferReason.Food: @@ -139,7 +155,8 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi case ItemClass.SubService.IndustrialFarming: case ItemClass.SubService.IndustrialOil: case ItemClass.SubService.IndustrialOre: - switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { + switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) + { case TransferManager.TransferReason.Grain: material = Localization.Get("GRAIN_MEAT"); break; case TransferManager.TransferReason.Logs: @@ -152,7 +169,8 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi } break; case ItemClass.SubService.IndustrialGeneric: - switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { + switch (RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) + { case TransferManager.TransferReason.Food: material = Localization.Get("FOOD"); break; case TransferManager.TransferReason.Lumber: @@ -163,7 +181,8 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi material = Localization.Get("COAL"); break; default: break; } - switch (RealCityIndustrialBuildingAI.GetSecondaryIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { + switch (RealCityIndustrialBuildingAI.GetSecondaryIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) + { case TransferManager.TransferReason.AnimalProducts: material += Localization.Get("ANIMALPRODUCTS"); break; case TransferManager.TransferReason.Flours: @@ -187,9 +206,13 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi material = ""; break; } } - } else { - if (data.Info.m_buildingAI is IndustrialExtractorAI) { - switch (data.Info.m_class.m_subService) { + } + else + { + if (data.Info.m_buildingAI is IndustrialExtractorAI) + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.IndustrialForestry: material = Localization.Get("LOG"); break; case ItemClass.SubService.IndustrialFarming: @@ -201,8 +224,11 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi default: material = ""; break; } - } else { - switch (data.Info.m_class.m_subService) { + } + else + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.IndustrialForestry: material = Localization.Get("LUMBER"); break; case ItemClass.SubService.IndustrialFarming: @@ -227,22 +253,29 @@ public static string GetProductionType(bool isSelling, ushort buildingID, Buildi return material; } - public static float GetPrice(bool isSelling, ushort buildingID, Building data) { + public static float GetPrice(bool isSelling, ushort buildingID, Building data) + { RealCityIndustrialBuildingAI.InitDelegate(); float price = 0f; - if (!isSelling) { - if (!(data.Info.m_buildingAI is IndustrialExtractorAI)) { - switch (data.Info.m_class.m_subService) { + if (!isSelling) + { + if (!(data.Info.m_buildingAI is IndustrialExtractorAI)) + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialEco: case ItemClass.SubService.CommercialLeisure: case ItemClass.SubService.CommercialTourist: CommercialBuildingAI commercialBuildingAI = data.Info.m_buildingAI as CommercialBuildingAI; - if (commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Food || commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Goods) { + if (commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Food || commercialBuildingAI.m_incomingResource == TransferManager.TransferReason.Goods) + { //SecondaryIncoming : FirstIncoming = 1:3 price = (3f * RealCityIndustryBuildingAI.GetResourcePrice(commercialBuildingAI.m_incomingResource) + (RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.LuxuryProducts))) / 4f; - } else { + } + else + { price = RealCityIndustryBuildingAI.GetResourcePrice(commercialBuildingAI.m_incomingResource); } break; @@ -263,9 +296,13 @@ public static float GetPrice(bool isSelling, ushort buildingID, Building data) { price = 0; break; } } - } else { - if (data.Info.m_buildingAI is IndustrialExtractorAI) { - switch (data.Info.m_class.m_subService) { + } + else + { + if (data.Info.m_buildingAI is IndustrialExtractorAI) + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.IndustrialForestry: price = RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Logs); break; case ItemClass.SubService.IndustrialFarming: @@ -277,8 +314,11 @@ public static float GetPrice(bool isSelling, ushort buildingID, Building data) { default: price = 0; break; } - } else { - switch (data.Info.m_class.m_subService) { + } + else + { + switch (data.Info.m_class.m_subService) + { case ItemClass.SubService.IndustrialForestry: price = RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Lumber); break; case ItemClass.SubService.IndustrialFarming: @@ -303,41 +343,55 @@ public static float GetPrice(bool isSelling, ushort buildingID, Building data) { return price; } - public static int GetTaxRate(Building data) { - if (data.Info.m_class.m_service == ItemClass.Service.Commercial) { + public static int GetTaxRate(Building data) + { + if (data.Info.m_class.m_service == ItemClass.Service.Commercial) + { return Politics.commercialTax; - } else if (data.Info.m_class.m_service == ItemClass.Service.Industrial) { + } + else if (data.Info.m_class.m_service == ItemClass.Service.Industrial) + { return Politics.industryTax; } return 0; } - public static float GetComsumptionDivider(Building data, ushort buildingID) { + public static float GetComsumptionDivider(Building data, ushort buildingID) + { Citizen.BehaviourData behaviourData = default; int aliveWorkerCount = 0; int totalWorkerCount = 0; RealCityCommonBuildingAI.GetWorkBehaviour((CommonBuildingAI)data.Info.m_buildingAI, buildingID, ref data, ref behaviourData, ref aliveWorkerCount, ref totalWorkerCount); float comsumptionDivider = aliveWorkerCount / 8f; - if (comsumptionDivider < 1f) { + if (comsumptionDivider < 1f) + { comsumptionDivider = 1f; } - if (data.Info.m_class.m_service == ItemClass.Service.Industrial) { + if (data.Info.m_class.m_service == ItemClass.Service.Industrial) + { RealCityIndustrialBuildingAI.InitDelegate(); var incomingTransferReason = RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)data.Info.m_buildingAI, buildingID); //petrol related - if (incomingTransferReason == TransferManager.TransferReason.Petrol) { + if (incomingTransferReason == TransferManager.TransferReason.Petrol) + { //*2 / 4 comsumptionDivider /= 2f; - } else if (incomingTransferReason == TransferManager.TransferReason.Coal) { + } + else if (incomingTransferReason == TransferManager.TransferReason.Coal) + { //*1.67 / 4 comsumptionDivider /= 2.4f; - } else if (incomingTransferReason == TransferManager.TransferReason.Lumber) { + } + else if (incomingTransferReason == TransferManager.TransferReason.Lumber) + { //*1.33 / 4 comsumptionDivider /= 3f; - } else if (incomingTransferReason == TransferManager.TransferReason.Food) { + } + else if (incomingTransferReason == TransferManager.TransferReason.Food) + { comsumptionDivider /= 4f; } } @@ -345,62 +399,91 @@ public static float GetComsumptionDivider(Building data, ushort buildingID) { return comsumptionDivider; } - public static void ProcessAdditionProduct(ushort buildingID, ref Building buildingData, ref ushort[] __state, bool is16Times = true) { + public static void ProcessAdditionProduct(ushort buildingID, ref Building buildingData, ref ushort[] __state, bool is16Times = true) + { //add production pre 16times byte shift = 0; - if (is16Times) { + if (is16Times) + { shift = 4; } - if ((RealCityEconomyExtension.Can16timesUpdate(buildingID)) || (!is16Times)) { + if ((RealCityEconomyExtension.Can16timesUpdate(buildingID)) || (!is16Times)) + { float comsumptionDivider = GetComsumptionDivider(buildingData, buildingID); int deltaCustomBuffer1 = __state[0] - buildingData.m_customBuffer1; - if (deltaCustomBuffer1 > 0) { - if (RealCity.reduceVehicle) { - if (!Singleton.instance.m_isNightTime) { + if (deltaCustomBuffer1 > 0) + { + if (RealCity.reduceVehicle) + { + if (!Singleton.instance.m_isNightTime) + { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)(deltaCustomBuffer1 / (comsumptionDivider * MainDataStore.reduceCargoDiv)) << shift)); - } else { + } + else + { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)(deltaCustomBuffer1 / comsumptionDivider) << shift)); } - } else { - if (!Singleton.instance.m_isNightTime) { + } + else + { + if (!Singleton.instance.m_isNightTime) + { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)(deltaCustomBuffer1 / comsumptionDivider) << shift)); - } else { + } + else + { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1 - ((int)((deltaCustomBuffer1 << 1) / comsumptionDivider) << shift)); } } } int deltaCustomBuffer2 = buildingData.m_customBuffer2 - __state[1]; - if (deltaCustomBuffer2 > 0) { - if (RealCity.reduceVehicle) { - if (!Singleton.instance.m_isNightTime) { + if (deltaCustomBuffer2 > 0) + { + if (RealCity.reduceVehicle) + { + if (!Singleton.instance.m_isNightTime) + { buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + ((deltaCustomBuffer2 >> MainDataStore.reduceCargoDivShift) << shift)); - } else { + } + else + { //NightTime 2x , reduceVehicle 1/2, so do nothing buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + (((int)(deltaCustomBuffer2 / (float)MainDataStore.reduceCargoDiv) << 1) << shift)); } - } else { - if (!Singleton.instance.m_isNightTime) { + } + else + { + if (!Singleton.instance.m_isNightTime) + { buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + (deltaCustomBuffer2 << shift)); - } else { + } + else + { buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 - deltaCustomBuffer2 + ((deltaCustomBuffer2 << MainDataStore.reduceCargoDivShift) << shift)); //buildingData.m_customBuffer2 = (ushort)(buildingData.m_customBuffer2 + (deltaCustomBuffer2 << 4)); } } } - } else { + } + else + { //DebugLog.LogToFileOnly($"Process buildingID outside 16times = {buildingID}"); buildingData.m_customBuffer1 = (ushort)Mathf.Clamp(__state[0], 0, 64000); buildingData.m_customBuffer2 = (ushort)Mathf.Clamp(__state[1], 0, 64000); } } - public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[] __state) { + public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[] __state) + { int deltaCustomBuffer1 = buildingData.m_customBuffer1 - __state[0]; - if (deltaCustomBuffer1 > 0) { - if (RealCity.reduceVehicle) { - if (!Singleton.instance.m_isNightTime) { + if (deltaCustomBuffer1 > 0) + { + if (RealCity.reduceVehicle) + { + if (!Singleton.instance.m_isNightTime) + { buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + (deltaCustomBuffer1 >> MainDataStore.reduceCargoDivShift)); } //else @@ -408,10 +491,15 @@ public static void ProcessAdditionProduct(ref Building buildingData, ref ushort[ //NightTime 2x , reduceVehicle 1/2, so do nothing //buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + (deltaCustomBuffer1 / (float)MainDataStore.reduceCargoDiv) * 2f); //} - } else { - if (!Singleton.instance.m_isNightTime) { + } + else + { + if (!Singleton.instance.m_isNightTime) + { //buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + deltaCustomBuffer1); - } else { + } + else + { //buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 - deltaCustomBuffer1 + 2 * deltaCustomBuffer1); buildingData.m_customBuffer1 = (ushort)(buildingData.m_customBuffer1 + deltaCustomBuffer1); } diff --git a/CustomAI/RealCityResidentAI.cs b/CustomAI/RealCityResidentAI.cs index 05df2f2..7352184 100644 --- a/CustomAI/RealCityResidentAI.cs +++ b/CustomAI/RealCityResidentAI.cs @@ -21,7 +21,8 @@ public static class RealCityResidentAI public static uint familyWeightStableHigh = 0; public static uint familyWeightStableLow = 0; - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref preCitizenId); SaveAndRestore.LoadData(ref i, saveData, ref familyCount); @@ -36,12 +37,14 @@ public static void Load(ref byte[] saveData) { SaveAndRestore.LoadData(ref i, saveData, ref familyWeightStableLow); SaveAndRestore.LoadData(ref i, saveData, ref citizenCount); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"RealCityResidentAI Load Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { int i = 0; //48 @@ -58,15 +61,18 @@ public static void Save(ref byte[] saveData) { SaveAndRestore.SaveData(ref i, familyWeightStableLow, ref saveData); SaveAndRestore.SaveData(ref i, citizenCount, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"RealCityResidentAI Save Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static bool IsGoverment(ushort buildingID) { + public static bool IsGoverment(ushort buildingID) + { bool isGoverment = false; Building buildingData = Singleton.instance.m_buildings.m_buffer[buildingID]; - switch (buildingData.Info.m_class.m_service) { + switch (buildingData.Info.m_class.m_service) + { case ItemClass.Service.Disaster: case ItemClass.Service.PoliceDepartment: case ItemClass.Service.Education: @@ -89,24 +95,33 @@ public static bool IsGoverment(ushort buildingID) { return isGoverment; } - public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { + public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) + { int salary = 0; - if (citizenId != 0u) { + if (citizenId != 0u) + { Citizen.Flags citizenFlag = Singleton.instance.m_citizens.m_buffer[citizenId].m_flags; - if ((citizenFlag & Citizen.Flags.Student) != Citizen.Flags.None) { + if ((citizenFlag & Citizen.Flags.Student) != Citizen.Flags.None) + { return salary; } ushort workBuilding = Singleton.instance.m_citizens.m_buffer[citizenId].m_workBuilding; - if (workBuilding != 0u) { + if (workBuilding != 0u) + { Building buildingData = Singleton.instance.m_buildings.m_buffer[workBuilding]; - if (!IsGoverment(workBuilding)) { + if (!IsGoverment(workBuilding)) + { salary = BuildingData.buildingWorkCount[workBuilding]; - if (!checkOnly) { - if (buildingData.Info.m_class.m_service != ItemClass.Service.Office) { + if (!checkOnly) + { + if (buildingData.Info.m_class.m_service != ItemClass.Service.Office) + { BuildingData.buildingMoney[workBuilding] -= salary; } } - } else { + } + else + { //Goverment int aliveWorkCount = 0; int totalWorkCount = 0; @@ -114,7 +129,8 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { RealCityCommonBuildingAI.InitDelegate(); RealCityCommonBuildingAI.GetWorkBehaviour((CommonBuildingAI)buildingData.Info.m_buildingAI, workBuilding, ref buildingData, ref behaviour, ref aliveWorkCount, ref totalWorkCount); int salaryMax = 0; - switch (Singleton.instance.m_citizens.m_buffer[citizenId].EducationLevel) { + switch (Singleton.instance.m_citizens.m_buffer[citizenId].EducationLevel) + { case Citizen.Education.Uneducated: salaryMax = (int)(MainDataStore.govermentSalary * 0.5); salary = MainDataStore.govermentEducation0SalaryFixed; break; @@ -133,7 +149,8 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { //If a building have 10 workers and have 100 workplacecount, we assume that the other 90 vitual workers are from outside //Which will give addition cost allWorkCount = TotalWorkCount(workBuilding, buildingData, false, false); - if (totalWorkCount > allWorkCount) { + if (totalWorkCount > allWorkCount) + { Singleton.instance.m_citizens.m_buffer[citizenId].SetWorkplace(citizenId, 0, 0u); } float vitualWorkersRatio = (totalWorkCount != 0) ? (allWorkCount / (float)totalWorkCount) : 1f; @@ -146,7 +163,8 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { DebugLog.LogToFileOnly("DebugInfo: LandPrice offset for Salary is " + landPriceOffset.ToString()); #endif salary = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, salary); - if (!checkOnly) { + if (!checkOnly) + { var m_class = Singleton.instance.m_buildings.m_buffer[workBuilding].Info.m_class; Singleton.instance.FetchResource((EconomyManager.Resource)16, (int)(salary * vitualWorkersRatio), m_class); MainDataStore.outsideTouristMoney += (salary * (vitualWorkersRatio - 1f) * MainDataStore.outsideTouristSalaryProfitRatio); @@ -158,146 +176,238 @@ public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { return salary; }//public - public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnly, bool update) { + public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnly, bool update) + { int totalWorkCount = 0; //For performance #if FASTRUN update = false; #endif - if (BuildingData.isBuildingWorkerUpdated[buildingID] && !update) { + if (BuildingData.isBuildingWorkerUpdated[buildingID] && !update) + { totalWorkCount = BuildingData.buildingWorkCount[buildingID]; - } else { - if (data.Info.m_buildingAI is LandfillSiteAI) { + } + else + { + if (data.Info.m_buildingAI is LandfillSiteAI) + { LandfillSiteAI buildingAI = data.Info.m_buildingAI as LandfillSiteAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is ExtractingFacilityAI) { + } + else if (data.Info.m_buildingAI is ExtractingFacilityAI) + { ExtractingFacilityAI buildingAI = data.Info.m_buildingAI as ExtractingFacilityAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is ProcessingFacilityAI) { + } + else if (data.Info.m_buildingAI is ProcessingFacilityAI) + { ProcessingFacilityAI buildingAI = data.Info.m_buildingAI as ProcessingFacilityAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is PoliceStationAI) { + } + else if (data.Info.m_buildingAI is PoliceStationAI) + { PoliceStationAI buildingAI = data.Info.m_buildingAI as PoliceStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is FireStationAI) { + } + else if (data.Info.m_buildingAI is FireStationAI) + { FireStationAI buildingAI = data.Info.m_buildingAI as FireStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is HospitalAI) { + } + else if (data.Info.m_buildingAI is HospitalAI) + { HospitalAI buildingAI = data.Info.m_buildingAI as HospitalAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is CargoStationAI) { + } + else if (data.Info.m_buildingAI is CargoStationAI) + { CargoStationAI buildingAI = data.Info.m_buildingAI as CargoStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is TransportStationAI) { + } + else if (data.Info.m_buildingAI is TransportStationAI) + { TransportStationAI buildingAI = data.Info.m_buildingAI as TransportStationAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is CemeteryAI) { + } + else if (data.Info.m_buildingAI is CemeteryAI) + { CemeteryAI buildingAI = data.Info.m_buildingAI as CemeteryAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MedicalCenterAI) { + } + else if (data.Info.m_buildingAI is MedicalCenterAI) + { MedicalCenterAI buildingAI = data.Info.m_buildingAI as MedicalCenterAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MonumentAI) { + } + else if (data.Info.m_buildingAI is MonumentAI) + { MonumentAI buildingAI = data.Info.m_buildingAI as MonumentAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is DepotAI) { + } + else if (data.Info.m_buildingAI is DepotAI) + { DepotAI buildingAI = data.Info.m_buildingAI as DepotAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is HelicopterDepotAI) { + } + else if (data.Info.m_buildingAI is HelicopterDepotAI) + { HelicopterDepotAI buildingAI = data.Info.m_buildingAI as HelicopterDepotAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MaintenanceDepotAI) { + } + else if (data.Info.m_buildingAI is MaintenanceDepotAI) + { MaintenanceDepotAI buildingAI = data.Info.m_buildingAI as MaintenanceDepotAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is FirewatchTowerAI) { + } + else if (data.Info.m_buildingAI is FirewatchTowerAI) + { FirewatchTowerAI buildingAI = data.Info.m_buildingAI as FirewatchTowerAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is DoomsdayVaultAI) { + } + else if (data.Info.m_buildingAI is DoomsdayVaultAI) + { DoomsdayVaultAI buildingAI = data.Info.m_buildingAI as DoomsdayVaultAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is DisasterResponseBuildingAI) { + } + else if (data.Info.m_buildingAI is DisasterResponseBuildingAI) + { DisasterResponseBuildingAI buildingAI = data.Info.m_buildingAI as DisasterResponseBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is HadronColliderAI) { + } + else if (data.Info.m_buildingAI is HadronColliderAI) + { HadronColliderAI buildingAI = data.Info.m_buildingAI as HadronColliderAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is SchoolAI) { + } + else if (data.Info.m_buildingAI is SchoolAI) + { SchoolAI buildingAI = data.Info.m_buildingAI as SchoolAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is PowerPlantAI) { + } + else if (data.Info.m_buildingAI is PowerPlantAI) + { PowerPlantAI buildingAI = data.Info.m_buildingAI as PowerPlantAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is SnowDumpAI) { + } + else if (data.Info.m_buildingAI is SnowDumpAI) + { SnowDumpAI buildingAI = data.Info.m_buildingAI as SnowDumpAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is WarehouseAI) { + } + else if (data.Info.m_buildingAI is WarehouseAI) + { WarehouseAI buildingAI = data.Info.m_buildingAI as WarehouseAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is WaterFacilityAI) { + } + else if (data.Info.m_buildingAI is WaterFacilityAI) + { WaterFacilityAI buildingAI = data.Info.m_buildingAI as WaterFacilityAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is SaunaAI) { + } + else if (data.Info.m_buildingAI is SaunaAI) + { SaunaAI buildingAI = data.Info.m_buildingAI as SaunaAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is PostOfficeAI) { + } + else if (data.Info.m_buildingAI is PostOfficeAI) + { PostOfficeAI buildingAI = data.Info.m_buildingAI as PostOfficeAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is RadioMastAI) { + } + else if (data.Info.m_buildingAI is RadioMastAI) + { RadioMastAI buildingAI = data.Info.m_buildingAI as RadioMastAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is SpaceElevatorAI) { + } + else if (data.Info.m_buildingAI is SpaceElevatorAI) + { SpaceElevatorAI buildingAI = data.Info.m_buildingAI as SpaceElevatorAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is SpaceRadarAI) { + } + else if (data.Info.m_buildingAI is SpaceRadarAI) + { SpaceRadarAI buildingAI = data.Info.m_buildingAI as SpaceRadarAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MainIndustryBuildingAI) { + } + else if (data.Info.m_buildingAI is MainIndustryBuildingAI) + { MainIndustryBuildingAI buildingAI = data.Info.m_buildingAI as MainIndustryBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is AuxiliaryBuildingAI) { + } + else if (data.Info.m_buildingAI is AuxiliaryBuildingAI) + { AuxiliaryBuildingAI buildingAI = data.Info.m_buildingAI as AuxiliaryBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is ShelterAI) { + } + else if (data.Info.m_buildingAI is ShelterAI) + { ShelterAI buildingAI = data.Info.m_buildingAI as ShelterAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is HeatingPlantAI) { + } + else if (data.Info.m_buildingAI is HeatingPlantAI) + { HeatingPlantAI buildingAI = data.Info.m_buildingAI as HeatingPlantAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MainCampusBuildingAI) { + } + else if (data.Info.m_buildingAI is MainCampusBuildingAI) + { MainCampusBuildingAI buildingAI = data.Info.m_buildingAI as MainCampusBuildingAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MuseumAI) { + } + else if (data.Info.m_buildingAI is MuseumAI) + { MuseumAI buildingAI = data.Info.m_buildingAI as MuseumAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is UniqueFactoryAI) { + } + else if (data.Info.m_buildingAI is UniqueFactoryAI) + { UniqueFactoryAI buildingAI = data.Info.m_buildingAI as UniqueFactoryAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is UniqueFacultyAI) { + } + else if (data.Info.m_buildingAI is UniqueFacultyAI) + { UniqueFacultyAI buildingAI = data.Info.m_buildingAI as UniqueFacultyAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is VarsitySportsArenaAI) { + } + else if (data.Info.m_buildingAI is VarsitySportsArenaAI) + { VarsitySportsArenaAI buildingAI = data.Info.m_buildingAI as VarsitySportsArenaAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is LibraryAI) { + } + else if (data.Info.m_buildingAI is LibraryAI) + { LibraryAI buildingAI = data.Info.m_buildingAI as LibraryAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is FishFarmAI) { + } + else if (data.Info.m_buildingAI is FishFarmAI) + { FishFarmAI buildingAI = data.Info.m_buildingAI as FishFarmAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is FishingHarborAI) { + } + else if (data.Info.m_buildingAI is FishingHarborAI) + { FishingHarborAI buildingAI = data.Info.m_buildingAI as FishingHarborAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is EldercareAI) { + } + else if (data.Info.m_buildingAI is EldercareAI) + { EldercareAI buildingAI = data.Info.m_buildingAI as EldercareAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is ChildcareAI) { + } + else if (data.Info.m_buildingAI is ChildcareAI) + { ChildcareAI buildingAI = data.Info.m_buildingAI as ChildcareAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else if (data.Info.m_buildingAI is MarketAI) { + } + else if (data.Info.m_buildingAI is MarketAI) + { MarketAI buildingAI = data.Info.m_buildingAI as MarketAI; totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3; - } else { - if (!checkOnly) { + } + else + { + if (!checkOnly) + { DebugLog.LogToFileOnly("Error: find unknow building = " + data.Info.m_buildingAI.ToString()); } } diff --git a/CustomData/BuildingData.cs b/CustomData/BuildingData.cs index 633fbc6..d25e5c1 100644 --- a/CustomData/BuildingData.cs +++ b/CustomData/BuildingData.cs @@ -14,8 +14,10 @@ public class BuildingData public static ushort commBuildingNumFinal = 0; - public static void DataInit() { - for (int i = 0; i < buildingWorkCount.Length; i++) { + public static void DataInit() + { + for (int i = 0; i < buildingWorkCount.Length; i++) + { buildingMoney[i] = 0; buildingWorkCount[i] = 0; isBuildingWorkerUpdated[i] = false; @@ -24,25 +26,29 @@ public static void DataInit() { } } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { //442368 int i = 0; SaveAndRestore.SaveData(ref i, buildingMoney, ref saveData); SaveAndRestore.SaveData(ref i, buildingWorkCount, ref saveData); SaveAndRestore.SaveData(ref i, isBuildingWorkerUpdated, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"BuildingData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref buildingMoney); SaveAndRestore.LoadData(ref i, saveData, ref buildingWorkCount); SaveAndRestore.LoadData(ref i, saveData, ref isBuildingWorkerUpdated); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"BuildingData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } diff --git a/CustomData/CitizenData.cs b/CustomData/CitizenData.cs index b44f561..7ad281e 100644 --- a/CustomData/CitizenData.cs +++ b/CustomData/CitizenData.cs @@ -8,34 +8,41 @@ public class CitizenData public static float[] citizenMoney = new float[1048576]; public static uint lastCitizenID = 0; - public static void DataInit() { + public static void DataInit() + { //for (int i = 0; i < citizenMoney.Length; i++) { // citizenMoney[i] = 0f; //} citizenMoney.Initialize(); } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { //4194304 int i = 0; SaveAndRestore.SaveData(ref i, citizenMoney, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"CitizenData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref citizenMoney); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"CitizenData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static uint GetCitizenUnit(ushort buildingId) { - if (buildingId != 0) { + public static uint GetCitizenUnit(ushort buildingId) + { + if (buildingId != 0) + { return Singleton.instance.m_buildings.m_buffer[(int)buildingId].m_citizenUnits; } return 0u; diff --git a/CustomData/CitizenUnitData.cs b/CustomData/CitizenUnitData.cs index 733e616..c0947d8 100644 --- a/CustomData/CitizenUnitData.cs +++ b/CustomData/CitizenUnitData.cs @@ -8,7 +8,8 @@ public class CitizenUnitData public static float[] familyMoney = new float[524288]; public static ushort[] familyGoods = new ushort[524288]; - public static void DataInit() { + public static void DataInit() + { //for (int i = 0; i < familyMoney.Length; i++) { // familyMoney[i] = 0f; // //default; @@ -18,23 +19,27 @@ public static void DataInit() { familyGoods.Initialize(ushort.MaxValue); } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { //3145728; int i = 0; SaveAndRestore.SaveData(ref i, familyMoney, ref saveData); SaveAndRestore.SaveData(ref i, familyGoods, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"CitizenData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref familyMoney); SaveAndRestore.LoadData(ref i, saveData, ref familyGoods); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"CitizenData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } diff --git a/CustomData/ICustomGameData.cs b/CustomData/ICustomGameData.cs deleted file mode 100644 index 3422108..0000000 --- a/CustomData/ICustomGameData.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace RealCity.CustomData -{ - public interface ICustomGameData - { - void DataInit(); - - //TODO: let ICustomGameData obey the SRP - void Save(ref byte[] saveData); - void Load(ref byte[] saveData); - } -} diff --git a/CustomData/TransportLineData.cs b/CustomData/TransportLineData.cs index d556644..9e15897 100644 --- a/CustomData/TransportLineData.cs +++ b/CustomData/TransportLineData.cs @@ -8,29 +8,35 @@ public class TransportLineData public static byte[] WeekEndPlan = new byte[256]; public static ushort lastLineID = 0; - public static void DataInit() { - for (int i = 0; i < WeekDayPlan.Length; i++) { + public static void DataInit() + { + for (int i = 0; i < WeekDayPlan.Length; i++) + { WeekDayPlan[i] = 1; WeekEndPlan[i] = 2; } } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { int i = 0; SaveAndRestore.SaveData(ref i, WeekDayPlan, ref saveData); SaveAndRestore.SaveData(ref i, WeekEndPlan, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"TransportLineData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref WeekDayPlan); SaveAndRestore.LoadData(ref i, saveData, ref WeekEndPlan); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"TransportLineData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } diff --git a/CustomData/VehicleData.cs b/CustomData/VehicleData.cs index bdf2120..697236d 100644 --- a/CustomData/VehicleData.cs +++ b/CustomData/VehicleData.cs @@ -7,7 +7,8 @@ public class VehicleData public static ushort[] vehicleTransferTime = new ushort[65536]; public static bool[] isVehicleCharged = new bool[65536]; - public static void DataInit() { + public static void DataInit() + { //for (int i = 0; i < isVehicleCharged.Length; i++) { // vehicleTransferTime[i] = 0; // isVehicleCharged[i] = false; @@ -16,23 +17,27 @@ public static void DataInit() { isVehicleCharged.Initialize(); } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { //3 * 65536 = 196608; int i = 0; SaveAndRestore.SaveData(ref i, vehicleTransferTime, ref saveData); SaveAndRestore.SaveData(ref i, isVehicleCharged, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"VehicleData Save Error: saveData.Length = {saveData.Length} actually = {i}"); } } - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref vehicleTransferTime); SaveAndRestore.LoadData(ref i, saveData, ref isVehicleCharged); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"VehicleData Load Error: saveData.Length = {saveData.Length} actually = {i}"); } } diff --git a/CustomManager/RealCityEconomyManager.cs b/CustomManager/RealCityEconomyManager.cs index bbd08ef..266d889 100644 --- a/CustomManager/RealCityEconomyManager.cs +++ b/CustomManager/RealCityEconomyManager.cs @@ -45,7 +45,8 @@ public class RealCityEconomyManager public static int[] healthCareIncomeForUI = new int[17]; public static int[] fireStationIncomeForUI = new int[17]; - public static void CleanCurrent(int current_idex) { + public static void CleanCurrent(int current_idex) + { citizenTaxIncomeForUI[current_idex] = 0; citizenIncomeForUI[current_idex] = 0; touristIncomeForUI[current_idex] = 0; @@ -84,8 +85,10 @@ public static void CleanCurrent(int current_idex) { healthCareIncomeForUI[current_idex] = 0; } - public static void DataInit() { - for (int i = 0; i < citizenTaxIncomeForUI.Length; i++) { + public static void DataInit() + { + for (int i = 0; i < citizenTaxIncomeForUI.Length; i++) + { citizenTaxIncomeForUI[i] = 0; citizenIncomeForUI[i] = 0; touristIncomeForUI[i] = 0; @@ -125,7 +128,8 @@ public static void DataInit() { } } - public static void Load(ref byte[] saveData) { + public static void Load(ref byte[] saveData) + { int i = 0; SaveAndRestore.LoadData(ref i, saveData, ref citizenTaxIncomeForUI); SaveAndRestore.LoadData(ref i, saveData, ref citizenIncomeForUI); @@ -164,12 +168,14 @@ public static void Load(ref byte[] saveData) { SaveAndRestore.LoadData(ref i, saveData, ref healthCareIncomeForUI); SaveAndRestore.LoadData(ref i, saveData, ref fireStationIncomeForUI); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"RealCityEconomyManager Load Error: saveData.Length = {saveData.Length} + i = {i}"); } } - public static void Save(ref byte[] saveData) { + public static void Save(ref byte[] saveData) + { int i = 0; //36 * 4 * 17 = 2448 SaveAndRestore.SaveData(ref i, citizenTaxIncomeForUI, ref saveData); @@ -209,7 +215,8 @@ public static void Save(ref byte[] saveData) { SaveAndRestore.SaveData(ref i, healthCareIncomeForUI, ref saveData); SaveAndRestore.SaveData(ref i, fireStationIncomeForUI, ref saveData); - if (i != saveData.Length) { + if (i != saveData.Length) + { DebugLog.LogToFileOnly($"RealCityEconomyManager Save Error: saveData.Length = {saveData.Length} + i = {i}"); } } diff --git a/Loader.cs b/Loader.cs index bcfbd01..cf00e80 100644 --- a/Loader.cs +++ b/Loader.cs @@ -44,16 +44,20 @@ public class Loader : LoadingExtensionBase public static bool isTransportLinesManagerRunning = false; public static bool isRealTimeRunning = false; - public override void OnCreated(ILoading loading) { + public override void OnCreated(ILoading loading) + { HarmonyInitDetour(); base.OnCreated(loading); } - public override void OnLevelLoaded(LoadMode mode) { + public override void OnLevelLoaded(LoadMode mode) + { base.OnLevelLoaded(mode); CurrentLoadMode = mode; - if (RealCity.IsEnabled) { - if (mode == LoadMode.LoadGame || mode == LoadMode.NewGame) { + if (RealCity.IsEnabled) + { + if (mode == LoadMode.LoadGame || mode == LoadMode.NewGame) + { isTransportLinesManagerRunning = CheckTransportLinesManagerIsLoaded(); DebugLog.LogToFileOnly($"Check TLM running = {isTransportLinesManagerRunning}"); isRealTimeRunning = CheckRealTimeIsLoaded(); @@ -67,18 +71,23 @@ public override void OnLevelLoaded(LoadMode mode) { OptionUI.LoadSetting(); RealCityThreading.isFirstTime = true; DebugLog.LogToFileOnly("OnLevelLoaded"); - if (mode == LoadMode.NewGame) { + if (mode == LoadMode.NewGame) + { InitData(); } - } else { - if (RealCity.IsEnabled) { + } + else + { + if (RealCity.IsEnabled) + { HarmonyRevertDetour(); } } } } - public static void InitData() { + public static void InitData() + { DebugLog.LogToFileOnly("InitData"); TransportLineData.DataInit(); VehicleData.DataInit(); @@ -96,28 +105,35 @@ public static void InitData() { DebugLog.LogToFileOnly("InitData Done"); } - public override void OnLevelUnloading() { + public override void OnLevelUnloading() + { base.OnLevelUnloading(); - if (CurrentLoadMode == LoadMode.LoadGame || CurrentLoadMode == LoadMode.NewGame) { - if (RealCity.IsEnabled && isGuiRunning) { + if (CurrentLoadMode == LoadMode.LoadGame || CurrentLoadMode == LoadMode.NewGame) + { + if (RealCity.IsEnabled && isGuiRunning) + { RemoveGui(); } - if (RealCity.IsEnabled) { + if (RealCity.IsEnabled) + { RealCityThreading.isFirstTime = true; HarmonyRevertDetour(); } } } - public override void OnReleased() { + public override void OnReleased() + { base.OnReleased(); } - private static void LoadSprites() { + private static void LoadSprites() + { if (SpriteUtilities.GetAtlas(m_atlasName) != null) return; var modPath = PluginManager.instance.FindPluginInfo(Assembly.GetExecutingAssembly()).modPath; m_atlasLoaded = SpriteUtilities.InitialiseAtlas(Path.Combine(modPath, "Icon/RealCity.png"), m_atlasName); - if (m_atlasLoaded) { + if (m_atlasLoaded) + { var spriteSuccess = true; spriteSuccess = SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(382, 0), new Vector2(191, 191)), "EcButton", m_atlasName) && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(0, 0), new Vector2(191, 191)), "Blank", m_atlasName) @@ -126,23 +142,29 @@ private static void LoadSprites() { && SpriteUtilities.AddSpriteToAtlas(new Rect(new Vector2(764, 0), new Vector2(191, 191)), "RcButton", m_atlasName) && spriteSuccess; if (!spriteSuccess) DebugLog.LogToFileOnly("Some sprites haven't been loaded. This is abnormal; you should probably report this to the mod creator."); - } else DebugLog.LogToFileOnly("The texture atlas (provides custom icons) has not loaded. All icons have reverted to text prompts."); + } + else DebugLog.LogToFileOnly("The texture atlas (provides custom icons) has not loaded. All icons have reverted to text prompts."); } - public static void SetupGui() { + public static void SetupGui() + { LoadSprites(); - if (m_atlasLoaded) { + if (m_atlasLoaded) + { parentGuiView = null; parentGuiView = UIView.GetAView(); - if (ecnomicUI == null) { + if (ecnomicUI == null) + { ecnomicUI = (EcnomicUI)parentGuiView.AddUIComponent(typeof(EcnomicUI)); } - if (realCityUI == null) { + if (realCityUI == null) + { realCityUI = (RealCityUI)parentGuiView.AddUIComponent(typeof(RealCityUI)); } - if (politicsUI == null) { + if (politicsUI == null) + { politicsUI = (PoliticsUI)parentGuiView.AddUIComponent(typeof(PoliticsUI)); } @@ -158,13 +180,17 @@ public static void SetupGui() { isGuiRunning = true; } } - public static void SetupPBLUIGui() { + public static void SetupPBLUIGui() + { PBLWindowGameObject = new GameObject("PBLWindowGameObject"); PBLUI = (PBLUI)PBLWindowGameObject.AddComponent(typeof(PBLUI)); PBLInfo = UIView.Find("(Library) PublicTransportWorldInfoPanel"); - if (PBLInfo == null) { + if (PBLInfo == null) + { DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) PublicTransportWorldInfoPanel\nAvailable panels are:\n"); - } else { + } + else + { PBLUI.transform.parent = PBLInfo.transform; PBLUI.size = new Vector3(150, 100); PBLUI.baseBuildingWindow = PBLInfo.gameObject.transform.GetComponentInChildren(); @@ -173,9 +199,11 @@ public static void SetupPBLUIGui() { PBLInfo.eventVisibilityChanged += PBLInfo_eventVisibilityChanged; } } - public static void PBLInfo_eventVisibilityChanged(UIComponent component, bool value) { + public static void PBLInfo_eventVisibilityChanged(UIComponent component, bool value) + { PBLUI.isEnabled = value; - if (value) { + if (value) + { //initialize PBL ui again PBLUI.transform.parent = PBLInfo.transform; PBLUI.size = new Vector3(150, 100); @@ -185,15 +213,19 @@ public static void PBLInfo_eventVisibilityChanged(UIComponent component, bool va PBLUI.position = new Vector3(UILabel.relativePosition.x + 50f, PBLInfo.size.y - (UILabel.relativePosition.y + 160f)); PBLUI.refeshOnce = true; PBLUI.Show(); - } else { + } + else + { PBLUI.Hide(); } } - public static void SetupHumanGui() { + public static void SetupHumanGui() + { HumanWindowGameObject = new GameObject("HumanWindowGameObject"); humanUI = (HumanUI)HumanWindowGameObject.AddComponent(typeof(HumanUI)); HumanInfo = UIView.Find("(Library) CitizenWorldInfoPanel"); - if (HumanInfo == null) { + if (HumanInfo == null) + { DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) CitizenWorldInfoPanel\nAvailable panels are:\n"); } humanUI.transform.parent = HumanInfo.transform; @@ -203,11 +235,13 @@ public static void SetupHumanGui() { HumanInfo.eventVisibilityChanged += HumanInfo_eventVisibilityChanged; } - public static void SetupTouristGui() { + public static void SetupTouristGui() + { TouristWindowGameObject = new GameObject("TouristWindowGameObject"); touristUI = (TouristUI)TouristWindowGameObject.AddComponent(typeof(TouristUI)); TouristInfo = UIView.Find("(Library) TouristWorldInfoPanel"); - if (TouristInfo == null) { + if (TouristInfo == null) + { DebugLog.LogToFileOnly("UIPanel not found (update broke the mod!): (Library) TouristWorldInfoPanel\nAvailable panels are:\n"); } touristUI.transform.parent = TouristInfo.transform; @@ -217,23 +251,29 @@ public static void SetupTouristGui() { TouristInfo.eventVisibilityChanged += TouristInfo_eventVisibilityChanged; } - public static void SetupEcnomicButton() { - if (EcButton == null) { + public static void SetupEcnomicButton() + { + if (EcButton == null) + { EcButton = (parentGuiView.AddUIComponent(typeof(EcnomicButton)) as EcnomicButton); } EcButton.Show(); } - public static void SetupCityButton() { - if (RcButton == null) { + public static void SetupCityButton() + { + if (RcButton == null) + { RcButton = (parentGuiView.AddUIComponent(typeof(RealCityButton)) as RealCityButton); } RcButton.Show(); } - public static void SetupBuildingButton() { + public static void SetupBuildingButton() + { var buildingInfo = UIView.Find("(Library) ZonedBuildingWorldInfoPanel"); - if (BButton == null) { + if (BButton == null) + { BButton = (buildingInfo.AddUIComponent(typeof(BuildingButton)) as BuildingButton); } BButton.width = 40f; @@ -242,9 +282,11 @@ public static void SetupBuildingButton() { BButton.Show(); } - public static void SetupPlayerBuildingButton() { + public static void SetupPlayerBuildingButton() + { var playerBuildingInfo = UIView.Find("(Library) CityServiceWorldInfoPanel"); - if (PBButton == null) { + if (PBButton == null) + { PBButton = (playerBuildingInfo.AddUIComponent(typeof(PlayerBuildingButton)) as PlayerBuildingButton); } PBButton.width = 40f; @@ -253,16 +295,20 @@ public static void SetupPlayerBuildingButton() { PBButton.Show(); } - public static void SetupPLButton() { - if (PlButton == null) { + public static void SetupPLButton() + { + if (PlButton == null) + { PlButton = (parentGuiView.AddUIComponent(typeof(PoliticsButton)) as PoliticsButton); } PlButton.Show(); } - public static void HumanInfo_eventVisibilityChanged(UIComponent component, bool value) { + public static void HumanInfo_eventVisibilityChanged(UIComponent component, bool value) + { humanUI.isEnabled = value; - if (value) { + if (value) + { //initialize human ui again humanUI.transform.parent = HumanInfo.transform; humanUI.size = new Vector3(HumanInfo.size.x, HumanInfo.size.y); @@ -270,14 +316,18 @@ public static void HumanInfo_eventVisibilityChanged(UIComponent component, bool humanUI.position = new Vector3(HumanInfo.size.x, HumanInfo.size.y); HumanUI.refeshOnce = true; humanUI.Show(); - } else { + } + else + { humanUI.Hide(); } } - public static void TouristInfo_eventVisibilityChanged(UIComponent component, bool value) { + public static void TouristInfo_eventVisibilityChanged(UIComponent component, bool value) + { touristUI.isEnabled = value; - if (value) { + if (value) + { //initialize human ui again touristUI.transform.parent = TouristInfo.transform; touristUI.size = new Vector3(TouristInfo.size.x, HumanInfo.size.y); @@ -285,14 +335,18 @@ public static void TouristInfo_eventVisibilityChanged(UIComponent component, boo touristUI.position = new Vector3(TouristInfo.size.x, TouristInfo.size.y); TouristUI.refeshOnce = true; touristUI.Show(); - } else { + } + else + { touristUI.Hide(); } } - public static void RemoveGui() { + public static void RemoveGui() + { isGuiRunning = false; - if (parentGuiView != null) { + if (parentGuiView != null) + { parentGuiView = null; UnityEngine.Object.Destroy(ecnomicUI); UnityEngine.Object.Destroy(realCityUI); @@ -308,65 +362,84 @@ public static void RemoveGui() { PlButton = null; } - if (BButton != null) { + if (BButton != null) + { UnityEngine.Object.Destroy(BButton); BButton = null; } - if (PBButton != null) { + if (PBButton != null) + { UnityEngine.Object.Destroy(PBButton); PBButton = null; } - if (buildingWindowGameObject != null) { + if (buildingWindowGameObject != null) + { UnityEngine.Object.Destroy(buildingWindowGameObject); } //remove HumanUI - if (humanUI != null) { - if (humanUI.parent != null) { + if (humanUI != null) + { + if (humanUI.parent != null) + { humanUI.parent.eventVisibilityChanged -= HumanInfo_eventVisibilityChanged; } } - if (HumanWindowGameObject != null) { + if (HumanWindowGameObject != null) + { UnityEngine.Object.Destroy(HumanWindowGameObject); } //remove TouristUI - if (touristUI != null) { - if (touristUI.parent != null) { + if (touristUI != null) + { + if (touristUI.parent != null) + { touristUI.parent.eventVisibilityChanged -= TouristInfo_eventVisibilityChanged; } } - if (TouristWindowGameObject != null) { + if (TouristWindowGameObject != null) + { UnityEngine.Object.Destroy(TouristWindowGameObject); } - if (!isTransportLinesManagerRunning) { - if (PBLUI != null) { - if (PBLUI.parent != null) { + if (!isTransportLinesManagerRunning) + { + if (PBLUI != null) + { + if (PBLUI.parent != null) + { PBLUI.parent.eventVisibilityChanged -= PBLInfo_eventVisibilityChanged; } } - if (PBLWindowGameObject != null) { + if (PBLWindowGameObject != null) + { UnityEngine.Object.Destroy(PBLWindowGameObject); } PBLUI._initialized = false; } } - private bool Check3rdPartyModLoaded(string namespaceStr, bool printAll = false) { + private bool Check3rdPartyModLoaded(string namespaceStr, bool printAll = false) + { bool result = false; FieldInfo field = typeof(LoadingWrapper).GetField("m_LoadingExtensions", BindingFlags.Instance | BindingFlags.NonPublic); List list = (List)field.GetValue(Singleton.instance.m_LoadingWrapper); - if (list != null) { - foreach (ILoadingExtension current in list) { - if (printAll) { + if (list != null) + { + foreach (ILoadingExtension current in list) + { + if (printAll) + { DebugLog.LogToFileOnly(string.Format("Detected extension: {0} in namespace {1}", current.GetType().Name, current.GetType().Namespace)); } - if (current.GetType().Namespace != null) { + if (current.GetType().Namespace != null) + { string value = current.GetType().Namespace.ToString(); - if (namespaceStr.Equals(value)) { + if (namespaceStr.Equals(value)) + { DebugLog.LogToFileOnly(string.Format("The mod '{0}' has been detected.", namespaceStr)); result = true; break; @@ -377,9 +450,12 @@ private bool Check3rdPartyModLoaded(string namespaceStr, bool printAll = false) return result; } - public static void HarmonyInitDetour() { - if (HarmonyHelper.IsHarmonyInstalled) { - if (!HarmonyDetourInited) { + public static void HarmonyInitDetour() + { + if (HarmonyHelper.IsHarmonyInstalled) + { + if (!HarmonyDetourInited) + { DebugLog.LogToFileOnly("Init harmony detours"); HarmonyDetours.Apply(); HarmonyDetourInited = true; @@ -387,9 +463,12 @@ public static void HarmonyInitDetour() { } } - public static void HarmonyRevertDetour() { - if (HarmonyHelper.IsHarmonyInstalled) { - if (HarmonyDetourInited) { + public static void HarmonyRevertDetour() + { + if (HarmonyHelper.IsHarmonyInstalled) + { + if (HarmonyDetourInited) + { DebugLog.LogToFileOnly("Revert harmony detours"); HarmonyDetours.DeApply(); HarmonyDetourFailed = true; @@ -398,11 +477,13 @@ public static void HarmonyRevertDetour() { } } - private bool CheckTransportLinesManagerIsLoaded() { + private bool CheckTransportLinesManagerIsLoaded() + { return Check3rdPartyModLoaded("Klyte.TransportLinesManager", false); } - private bool CheckRealTimeIsLoaded() { + private bool CheckRealTimeIsLoaded() + { return Check3rdPartyModLoaded("RealTime.Core", false); } } diff --git a/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs b/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs index 7ab58da..43e4ba6 100644 --- a/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs +++ b/Patch/AuxiliaryBuildingAIGetResourceRatePatch.cs @@ -10,11 +10,14 @@ namespace RealCity.Patch [HarmonyPatch] public class AuxiliaryBuildingAIGetResourceRatePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(AuxiliaryBuildingAI).GetMethod("GetResourceRate", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(EconomyManager.Resource) }, null); } - public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) { - if (resource == EconomyManager.Resource.Maintenance) { + public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) + { + if (resource == EconomyManager.Resource.Maintenance) + { float salary = RealCityPlayerBuildingAI.CaculateEmployeeOutcome(buildingID, data); __result = (int)((float)__result / MainDataStore.gameExpenseDivide - salary * 100f); } diff --git a/Patch/BuildingAIVisitorEnterPatch.cs b/Patch/BuildingAIVisitorEnterPatch.cs index 20da515..d9b130d 100644 --- a/Patch/BuildingAIVisitorEnterPatch.cs +++ b/Patch/BuildingAIVisitorEnterPatch.cs @@ -11,21 +11,31 @@ namespace RealCity.Patch [HarmonyPatch] public class BuildingAIVisitorEnterPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(BuildingAI).GetMethod("VisitorEnter", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(uint) }, null); } - public static void Postfix(ushort buildingID, ref Building data, uint citizen) { + public static void Postfix(ushort buildingID, ref Building data, uint citizen) + { ushort eventIndex = data.m_eventIndex; - if (eventIndex == 0) { + if (eventIndex == 0) + { ProcessTourismIncome(buildingID, ref data, citizen); - } else { + } + else + { EventManager instance = Singleton.instance; EventInfo info = instance.m_events.m_buffer[(int)eventIndex].Info; - if ((info.m_eventAI is SportMatchAI) || (info.m_eventAI is VarsitySportsMatchAI)) { - if (buildingID == instance.m_events.m_buffer[(int)eventIndex].m_building && (instance.m_events.m_buffer[(int)eventIndex].m_flags & (EventData.Flags.Preparing | EventData.Flags.Active)) != EventData.Flags.None) { - if ((Singleton.instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { + if ((info.m_eventAI is SportMatchAI) || (info.m_eventAI is VarsitySportsMatchAI)) + { + if (buildingID == instance.m_events.m_buffer[(int)eventIndex].m_building && (instance.m_events.m_buffer[(int)eventIndex].m_flags & (EventData.Flags.Preparing | EventData.Flags.Active)) != EventData.Flags.None) + { + if ((Singleton.instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) + { MainDataStore.outsideTouristMoney -= instance.m_events.m_buffer[(int)eventIndex].m_ticketPrice; - } else { + } + else + { CitizenData.citizenMoney[citizen] -= instance.m_events.m_buffer[(int)eventIndex].m_ticketPrice; } } @@ -33,27 +43,39 @@ public static void Postfix(ushort buildingID, ref Building data, uint citizen) { } } - public static void ProcessTourismIncome(ushort buildingID, ref Building data, uint citizen) { + public static void ProcessTourismIncome(ushort buildingID, ref Building data, uint citizen) + { CitizenManager instance = Singleton.instance; BuildingInfo info = data.Info; - if (info.m_class.m_service == ItemClass.Service.Monument) { - if (IsRealUniqueBuilding(buildingID)) { - if ((instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { + if (info.m_class.m_service == ItemClass.Service.Monument) + { + if (IsRealUniqueBuilding(buildingID)) + { + if ((instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) + { ProcessMonumentTourismTouristIncome(ref data, citizen); - } else { + } + else + { ProcessMonumentTourismResidentIncome(ref data, citizen); } } - } else if (info.m_buildingAI is ParkBuildingAI) { - if ((instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { + } + else if (info.m_buildingAI is ParkBuildingAI) + { + if ((instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) + { ProcessParkIncome(ref data, citizen, true); - } else { + } + else + { ProcessParkIncome(ref data, citizen, false); } } } - public static void ProcessMonumentTourismTouristIncome(ref Building data, uint citizen) { + public static void ProcessMonumentTourismTouristIncome(ref Building data, uint citizen) + { CitizenManager instance = Singleton.instance; int tourism_fee = 1000; if (instance.m_citizens.m_buffer[citizen].WealthLevel == Citizen.Wealth.High) @@ -61,39 +83,52 @@ public static void ProcessMonumentTourismTouristIncome(ref Building data, uint c else if (instance.m_citizens.m_buffer[citizen].WealthLevel == Citizen.Wealth.Medium) tourism_fee <<= 1; - if (MainDataStore.outsideTouristMoney > 0) { + if (MainDataStore.outsideTouristMoney > 0) + { MainDataStore.outsideTouristMoney -= tourism_fee; Singleton.instance.AddPrivateIncome(tourism_fee, ItemClass.Service.Commercial, ItemClass.SubService.CommercialTourist, ItemClass.Level.Level1, 113333); } } - public static void ProcessMonumentTourismResidentIncome(ref Building data, uint citizen) { + public static void ProcessMonumentTourismResidentIncome(ref Building data, uint citizen) + { int tourism_fee = (int)(0.2f * CitizenData.citizenMoney[citizen]); - if (tourism_fee > 0) { + if (tourism_fee > 0) + { CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - tourism_fee); Singleton.instance.AddPrivateIncome(tourism_fee, ItemClass.Service.Commercial, ItemClass.SubService.CommercialTourist, ItemClass.Level.Level1, 114333); } } - public static void ProcessParkIncome(ref Building data, uint citizen, bool isTourist) { + public static void ProcessParkIncome(ref Building data, uint citizen, bool isTourist) + { DistrictManager instance2 = Singleton.instance; byte b = instance2.GetPark(data.m_position); - if (b != 0 && !instance2.m_parks.m_buffer[b].IsPark) { + if (b != 0 && !instance2.m_parks.m_buffer[b].IsPark) + { b = 0; } - if (b != 0) { + if (b != 0) + { int ticketPrice = instance2.m_parks.m_buffer[b].GetTicketPrice(); //Negetive price to help identify tourist and resident. - if (isTourist) { - if (MainDataStore.outsideTouristMoney > 0) { + if (isTourist) + { + if (MainDataStore.outsideTouristMoney > 0) + { Singleton.instance.AddResource(EconomyManager.Resource.PublicIncome, -(int)ticketPrice, data.Info.m_class); MainDataStore.outsideTouristMoney -= ticketPrice; - } else { + } + else + { ticketPrice = 0; } - } else { - if (CitizenData.citizenMoney[citizen] > ticketPrice) { + } + else + { + if (CitizenData.citizenMoney[citizen] > ticketPrice) + { CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - ticketPrice); Singleton.instance.AddResource(EconomyManager.Resource.PublicIncome, (int)ticketPrice, data.Info.m_class); } @@ -104,13 +139,16 @@ public static void ProcessParkIncome(ref Building data, uint citizen, bool isTou } } - public static bool IsRealUniqueBuilding(ushort buildingId) { - if (buildingId == 0) { + public static bool IsRealUniqueBuilding(ushort buildingId) + { + if (buildingId == 0) + { return false; } var buildingInfo = BuildingManager.instance.m_buildings.m_buffer[buildingId].Info; - if (buildingInfo?.m_class?.m_service != ItemClass.Service.Monument) { + if (buildingInfo?.m_class?.m_service != ItemClass.Service.Monument) + { return false; } diff --git a/Patch/CargoTruckAIArriveAtSourcePatch.cs b/Patch/CargoTruckAIArriveAtSourcePatch.cs index 2e0711d..3d65c36 100644 --- a/Patch/CargoTruckAIArriveAtSourcePatch.cs +++ b/Patch/CargoTruckAIArriveAtSourcePatch.cs @@ -11,15 +11,19 @@ namespace RealCity.Patch [HarmonyPatch] public class CargoTruckAIArriveAtSourcePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CargoTruckAI).GetMethod("ArriveAtSource", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }, null); } - public static bool Prefix(ref Vehicle data) { - if (data.m_sourceBuilding == 0) { + public static bool Prefix(ref Vehicle data) + { + if (data.m_sourceBuilding == 0) + { return true; } - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != (Vehicle.Flags)0) { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != (Vehicle.Flags)0) + { int transferSize = (int)data.m_transferSize; BuildingInfo info = Singleton.instance.m_buildings.m_buffer[(int)data.m_sourceBuilding].Info; info.m_buildingAI.ModifyMaterialBuffer(data.m_sourceBuilding, ref Singleton.instance.m_buildings.m_buffer[(int)data.m_sourceBuilding], (TransferManager.TransferReason)data.m_transferType, ref transferSize); diff --git a/Patch/CargoTruckAIArriveAtTargetPatch.cs b/Patch/CargoTruckAIArriveAtTargetPatch.cs index c0736a8..d15c0f6 100644 --- a/Patch/CargoTruckAIArriveAtTargetPatch.cs +++ b/Patch/CargoTruckAIArriveAtTargetPatch.cs @@ -11,28 +11,36 @@ namespace RealCity.Patch [HarmonyPatch] public static class CargoTruckAIArriveAtTargetPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CargoTruckAI).GetMethod("ArriveAtTarget", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }, null); } - public static void Prefix(ref CargoTruckAI __instance, ref Vehicle data) { + public static void Prefix(ref CargoTruckAI __instance, ref Vehicle data) + { int transferSize = 0; - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) + { transferSize = data.m_transferSize; } - if ((data.m_flags & Vehicle.Flags.TransferToSource) != 0) { + if ((data.m_flags & Vehicle.Flags.TransferToSource) != 0) + { transferSize = Mathf.Min(0, data.m_transferSize - __instance.m_cargoCapacity); } // NON-STOCK CODE START ProcessResourceArriveAtTarget(ref data, ref transferSize); } - public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int transferSize) { + public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int transferSize) + { BuildingManager instance = Singleton.instance; BuildingInfo info = instance.m_buildings.m_buffer[data.m_targetBuilding].Info; - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) { - if ((info.m_class.m_service == ItemClass.Service.Electricity) || (info.m_class.m_service == ItemClass.Service.Water) || (info.m_class.m_service == ItemClass.Service.Disaster)) { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) + { + if ((info.m_class.m_service == ItemClass.Service.Electricity) || (info.m_class.m_service == ItemClass.Service.Water) || (info.m_class.m_service == ItemClass.Service.Disaster)) + { info.m_buildingAI.ModifyMaterialBuffer(data.m_targetBuilding, ref instance.m_buildings.m_buffer[data.m_targetBuilding], (TransferManager.TransferReason)data.m_transferType, ref transferSize); float productValue; - switch ((TransferManager.TransferReason)data.m_transferType) { + switch ((TransferManager.TransferReason)data.m_transferType) + { case TransferManager.TransferReason.Petrol: productValue = transferSize * RealCityIndustryBuildingAI.GetResourcePrice((TransferManager.TransferReason)data.m_transferType); Singleton.instance.FetchResource(EconomyManager.Resource.ResourcePrice, (int)productValue, ItemClass.Service.PlayerIndustry, ItemClass.SubService.PlayerIndustryOil, ItemClass.Level.Level1); @@ -49,7 +57,8 @@ public static void ProcessResourceArriveAtTarget(ref Vehicle data, ref int trans case (TransferManager.TransferReason)125: break; default: DebugLog.LogToFileOnly("Error: ProcessResourceArriveAtTarget find unknow play building transition" + info.m_class.ToString() + "transfer reason " + data.m_transferType.ToString()); break; } - if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) { + if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0) + { data.m_transferSize = (ushort)Mathf.Clamp(data.m_transferSize - transferSize, 0, data.m_transferSize); } } diff --git a/Patch/CitizenManagerCreateCitizenInstancePatch.cs b/Patch/CitizenManagerCreateCitizenInstancePatch.cs index e1a0810..b47fc49 100644 --- a/Patch/CitizenManagerCreateCitizenInstancePatch.cs +++ b/Patch/CitizenManagerCreateCitizenInstancePatch.cs @@ -11,27 +11,40 @@ namespace RealCity.Patch [HarmonyPatch] public class CitizenManagerCreateCitizenInstancePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CitizenManager).GetMethod("CreateCitizenInstance", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort).MakeByRefType(), typeof(Randomizer).MakeByRefType(), typeof(CitizenInfo), typeof(uint) }, null); } - public static bool Prefix(ref CitizenManager __instance, uint citizen, ref bool __result) { + public static bool Prefix(ref CitizenManager __instance, uint citizen, ref bool __result) + { var data = __instance.m_citizens.m_buffer[citizen]; - if (data.m_flags.IsFlagSet(Citizen.Flags.DummyTraffic)) { - if (RealCity.realCityV10) { - if (MainDataStore.outsideTouristMoney < 0) { + if (data.m_flags.IsFlagSet(Citizen.Flags.DummyTraffic)) + { + if (RealCity.realCityV10) + { + if (MainDataStore.outsideTouristMoney < 0) + { __result = false; return false; } } - } else if (data.m_flags.IsFlagSet(Citizen.Flags.Tourist)) { - if (data.m_flags.IsFlagSet(Citizen.Flags.MovingIn)) { + } + else if (data.m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { + if (data.m_flags.IsFlagSet(Citizen.Flags.MovingIn)) + { //Add initial money - if (data.WealthLevel == Citizen.Wealth.Low) { + if (data.WealthLevel == Citizen.Wealth.Low) + { CitizenData.citizenMoney[citizen] = 2048; - } else if (data.WealthLevel == Citizen.Wealth.Medium) { + } + else if (data.WealthLevel == Citizen.Wealth.Medium) + { CitizenData.citizenMoney[citizen] = 4096; - } else { + } + else + { CitizenData.citizenMoney[citizen] = 8192; } } diff --git a/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs b/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs index f3faa1a..6be0cb7 100644 --- a/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs +++ b/Patch/CitizenManagerReleaseCitizenImplementationPatch.cs @@ -8,10 +8,12 @@ namespace RealCity.Patch [HarmonyPatch] public class CitizenManagerReleaseCitizenImplementationPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CitizenManager).GetMethod("ReleaseCitizenImplementation", BindingFlags.NonPublic | BindingFlags.Instance); } - public static void Postfix(uint citizen) { + public static void Postfix(uint citizen) + { CitizenData.citizenMoney[citizen] = 0; } } diff --git a/Patch/CitizenManagerReleaseUnitCitizenPatch.cs b/Patch/CitizenManagerReleaseUnitCitizenPatch.cs index 4bca7d6..21fc5f4 100644 --- a/Patch/CitizenManagerReleaseUnitCitizenPatch.cs +++ b/Patch/CitizenManagerReleaseUnitCitizenPatch.cs @@ -7,10 +7,12 @@ namespace RealCity.Patch [HarmonyPatch] public class CitizenManagerReleaseUnitCitizenPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CitizenManager).GetMethod("ReleaseUnitCitizen", BindingFlags.NonPublic | BindingFlags.Instance); } - public static void Postfix(uint unit) { + public static void Postfix(uint unit) + { CitizenUnitData.familyMoney[unit] = 0; //65535 stand for uninitial money CitizenUnitData.familyGoods[unit] = 65535; diff --git a/Patch/CommercialBuildingAICreateBuildingPatch.cs b/Patch/CommercialBuildingAICreateBuildingPatch.cs index deb6627..f51e671 100644 --- a/Patch/CommercialBuildingAICreateBuildingPatch.cs +++ b/Patch/CommercialBuildingAICreateBuildingPatch.cs @@ -10,10 +10,12 @@ namespace RealCity.Patch [HarmonyPatch] public class CommercialBuildingAICreateBuildingPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CommercialBuildingAI).GetMethod("CreateBuilding", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType() }, null); } - public static void Postfix(ushort buildingID, ref Building data) { + public static void Postfix(ushort buildingID, ref Building data) + { var material = TransferManager.TransferReason.Goods; float initialMaterialFee = data.m_customBuffer1 * RealCityIndustryBuildingAI.GetResourcePrice(material) + 10000; BuildingData.buildingMoney[buildingID] = -initialMaterialFee; diff --git a/Patch/CommercialBuildingAIModifyMaterialBufferPatch.cs b/Patch/CommercialBuildingAIModifyMaterialBufferPatch.cs index a8b637b..60bdf80 100644 --- a/Patch/CommercialBuildingAIModifyMaterialBufferPatch.cs +++ b/Patch/CommercialBuildingAIModifyMaterialBufferPatch.cs @@ -11,15 +11,21 @@ namespace RealCity.Patch [HarmonyPatch] public class CommercialBuildingAIModifyMaterialBufferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CommercialBuildingAI).GetMethod("ModifyMaterialBuffer", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(TransferManager.TransferReason), typeof(int).MakeByRefType() }, null); } - public static bool Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (material == TransferManager.TransferReason.Entertainment) { + public static bool Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (material == TransferManager.TransferReason.Entertainment) + { CaculateTradeIncome(buildingID, ref data, material, ref amountDelta); - } else { - switch (material) { + } + else + { + switch (material) + { case TransferManager.TransferReason.Shopping: case TransferManager.TransferReason.ShoppingB: case TransferManager.TransferReason.ShoppingC: @@ -28,7 +34,8 @@ public static bool Prefix(ushort buildingID, ref Building data, TransferManager. case TransferManager.TransferReason.ShoppingF: case TransferManager.TransferReason.ShoppingG: case TransferManager.TransferReason.ShoppingH: - if (amountDelta == -100) { + if (amountDelta == -100) + { // Disable other - 100 ModifyMaterialBuffer return false; } @@ -38,8 +45,10 @@ public static bool Prefix(ushort buildingID, ref Building data, TransferManager. return true; } - public static void Postfix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - switch (material) { + public static void Postfix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + switch (material) + { case TransferManager.TransferReason.ShoppingB: case TransferManager.TransferReason.ShoppingC: case TransferManager.TransferReason.ShoppingD: @@ -49,8 +58,10 @@ public static void Postfix(ushort buildingID, ref Building data, TransferManager case TransferManager.TransferReason.ShoppingH: break; default: - if (material != TransferManager.TransferReason.Shopping) { - if (material == TransferManager.TransferReason.Goods || material == TransferManager.TransferReason.Petrol || material == TransferManager.TransferReason.Food || material == TransferManager.TransferReason.LuxuryProducts) { + if (material != TransferManager.TransferReason.Shopping) + { + if (material == TransferManager.TransferReason.Goods || material == TransferManager.TransferReason.Petrol || material == TransferManager.TransferReason.Food || material == TransferManager.TransferReason.LuxuryProducts) + { ProcessIncoming(buildingID, ref data, material, ref amountDelta); } return; @@ -60,15 +71,19 @@ public static void Postfix(ushort buildingID, ref Building data, TransferManager CaculateTradeIncome(buildingID, ref data, material, ref amountDelta); } - public static void ProcessIncoming(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (amountDelta > 0) { + public static void ProcessIncoming(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (amountDelta > 0) + { float tradeIncome1 = amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); BuildingData.buildingMoney[buildingID] = BuildingData.buildingMoney[buildingID] - tradeIncome1; } } - public static void CaculateTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (amountDelta < 0) { + public static void CaculateTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (amountDelta < 0) + { float tradeIncome = amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); float tradeTax = -tradeIncome * RealCityPrivateBuildingAI.GetTaxRate(data) / 100f; Singleton.instance.AddPrivateIncome((int)tradeTax, ItemClass.Service.Commercial, data.Info.m_class.m_subService, data.Info.m_class.m_level, 111333); diff --git a/Patch/CommercialBuildingAISimulationStepActivePatch.cs b/Patch/CommercialBuildingAISimulationStepActivePatch.cs index 6a50453..bf93a4e 100644 --- a/Patch/CommercialBuildingAISimulationStepActivePatch.cs +++ b/Patch/CommercialBuildingAISimulationStepActivePatch.cs @@ -13,17 +13,20 @@ namespace RealCity.Patch [HarmonyPatch] public class CommercialBuildingAISimulationStepActivePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CommercialBuildingAI).GetMethod("SimulationStepActive", BindingFlags.NonPublic | BindingFlags.Instance); } - public static void Prefix(ref Building buildingData, ref ushort[] __state) { + public static void Prefix(ref Building buildingData, ref ushort[] __state) + { __state = new ushort[2]; __state[0] = buildingData.m_customBuffer1; __state[1] = buildingData.m_customBuffer2; } - public static void Postfix(ushort buildingID, ref Building buildingData, ref ushort[] __state) { + public static void Postfix(ushort buildingID, ref Building buildingData, ref ushort[] __state) + { RealCityPrivateBuildingAI.ProcessAdditionProduct(buildingID, ref buildingData, ref __state, false); } } diff --git a/Patch/CommercialBuildingAIVisitorEnterPatch.cs b/Patch/CommercialBuildingAIVisitorEnterPatch.cs index 9a3cf5c..6bf12e6 100644 --- a/Patch/CommercialBuildingAIVisitorEnterPatch.cs +++ b/Patch/CommercialBuildingAIVisitorEnterPatch.cs @@ -11,23 +11,29 @@ namespace RealCity.Patch [HarmonyPatch] public class CommercialBuildingAIVisitorEnterPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CommercialBuildingAI).GetMethod("VisitorEnter", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(uint) }, null); } - public static bool Prefix(ushort buildingID, ref Building data, uint citizen) { + public static bool Prefix(ushort buildingID, ref Building data, uint citizen) + { CitizenManager citizenManager = Singleton.instance; BuildingInfo buildingInfo = data.Info; - if ((citizenManager.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { + if ((citizenManager.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) + { int consumptionMoney = MainDataStore.govermentSalary << 4; - if (citizenManager.m_citizens.m_buffer[citizen].WealthLevel == Citizen.Wealth.High) { + if (citizenManager.m_citizens.m_buffer[citizen].WealthLevel == Citizen.Wealth.High) + { consumptionMoney <<= 2; } - if (citizenManager.m_citizens.m_buffer[citizen].WealthLevel == Citizen.Wealth.Medium) { + if (citizenManager.m_citizens.m_buffer[citizen].WealthLevel == Citizen.Wealth.Medium) + { consumptionMoney <<= 1; } consumptionMoney = -consumptionMoney; - if (MainDataStore.outsideTouristMoney > 0) { + if (MainDataStore.outsideTouristMoney > 0) + { buildingInfo.m_buildingAI.ModifyMaterialBuffer(buildingID, ref data, TransferManager.TransferReason.Entertainment, ref consumptionMoney); MainDataStore.outsideTouristMoney += (consumptionMoney); } @@ -37,49 +43,69 @@ public static bool Prefix(ushort buildingID, ref Building data, uint citizen) { IndustryBuildingGetResourcePricePatch.Prefix(ref priceInt, TransferManager.TransferReason.Shopping, data.Info.m_class.m_service); var m_goodsSellPrice = priceInt / 100; MainDataStore.outsideTouristMoney += (consumptionMoney * m_goodsSellPrice); - } else { + } + else + { ushort homeBuilding = citizenManager.m_citizens.m_buffer[citizen].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = citizenManager.m_citizens.m_buffer[citizen].GetContainingUnit((uint)citizen, citizenUnit, CitizenUnit.Flags.Home); - if (containingUnit != 0) { + if (containingUnit != 0) + { //int goodAmount = (int)(-(CitizenUnitData.familyMoney[containingUnit]) / RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)); int goodAmount = -MainDataStore.maxGoodPurchase; - if (goodAmount < 0) { + if (goodAmount < 0) + { buildingInfo.m_buildingAI.ModifyMaterialBuffer(buildingID, ref data, TransferManager.TransferReason.Shopping, ref goodAmount); - if (goodAmount != 0) { + if (goodAmount != 0) + { CitizenUnitData.familyGoods[containingUnit] = (ushort)(CitizenUnitData.familyGoods[containingUnit] - (goodAmount * 10)); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { citizenManager.m_citizens.m_buffer[citizen].m_flags &= ~Citizen.Flags.NeedGoods; } } - } else { + } + else + { goodAmount = 0; } var familyMoney = (CitizenUnitData.familyMoney[containingUnit] + goodAmount * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)); float consumptionIndex; - if (buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialLeisure) { + if (buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialLeisure) + { consumptionIndex = 0.25f; - } else if ((buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialTourist)) { + } + else if ((buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialTourist)) + { consumptionIndex = 0.2f; - } else if ((buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialEco)) { + } + else if ((buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialEco)) + { consumptionIndex = 0.05f; - } else if ((buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialHigh)) { + } + else if ((buildingInfo.m_class.m_subService == ItemClass.SubService.CommercialHigh)) + { consumptionIndex = 0.15f; - } else { + } + else + { consumptionIndex = 0.1f; } int consumptionMoney = -(int)(consumptionIndex * familyMoney); - if (consumptionMoney < 0) { + if (consumptionMoney < 0) + { int money = consumptionMoney; buildingInfo.m_buildingAI.ModifyMaterialBuffer(buildingID, ref data, TransferManager.TransferReason.Entertainment, ref money); - } else { + } + else + { consumptionMoney = 0; } diff --git a/Patch/CommonBuildingAIGetColorPatch.cs b/Patch/CommonBuildingAIGetColorPatch.cs index 907f6ec..2bf56a4 100644 --- a/Patch/CommonBuildingAIGetColorPatch.cs +++ b/Patch/CommonBuildingAIGetColorPatch.cs @@ -10,7 +10,8 @@ namespace RealCity.Patch [HarmonyPatch] public class CommonBuildingAIGetColorPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CommonBuildingAI).GetMethod( "GetColor", BindingFlags.Instance | BindingFlags.Public, @@ -19,11 +20,14 @@ public static MethodBase TargetMethod() { new ParameterModifier[0]); } - public static void Postfix(ushort buildingID, ref Building data, InfoManager.InfoMode infoMode, ref Color __result) { - if (infoMode == InfoManager.InfoMode.LandValue) { + public static void Postfix(ushort buildingID, ref Building data, InfoManager.InfoMode infoMode, ref Color __result) + { + if (infoMode == InfoManager.InfoMode.LandValue) + { ItemClass @class = data.Info.m_class; ItemClass.Service service = @class.m_service; - switch (service) { + switch (service) + { case ItemClass.Service.Residential: case ItemClass.Service.Office: case ItemClass.Service.Industrial: diff --git a/Patch/CommonBuildingAIReleaseBuildingPatch.cs b/Patch/CommonBuildingAIReleaseBuildingPatch.cs index d595ff0..61e3d02 100644 --- a/Patch/CommonBuildingAIReleaseBuildingPatch.cs +++ b/Patch/CommonBuildingAIReleaseBuildingPatch.cs @@ -7,10 +7,12 @@ namespace RealCity.Patch [HarmonyPatch] public class CommonBuildingAIReleaseBuildingPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(CommonBuildingAI).GetMethod("ReleaseBuilding"); } - public static void Postfix(ushort buildingID) { + public static void Postfix(ushort buildingID) + { BuildingData.buildingMoney[buildingID] = 0; BuildingData.buildingWorkCount[buildingID] = 0; BuildingData.isBuildingWorkerUpdated[buildingID] = false; diff --git a/Patch/DistrictParkCalculatePolicyExpensesPatch.cs b/Patch/DistrictParkCalculatePolicyExpensesPatch.cs index f1d795d..29f8e7a 100644 --- a/Patch/DistrictParkCalculatePolicyExpensesPatch.cs +++ b/Patch/DistrictParkCalculatePolicyExpensesPatch.cs @@ -7,24 +7,29 @@ namespace RealCity.Patch [HarmonyPatch] public class DistrictParkCalculatePolicyExpensesPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(DistrictPark).GetMethod("CalculatePolicyExpenses", BindingFlags.Public | BindingFlags.Instance); } - public static void Postfix(ref uint __result) { + public static void Postfix(ref uint __result) + { __result /= MainDataStore.gameExpenseDivide; } - public static void CalculateVarsityExpenses(ref DistrictPark district, out ulong upkeep, out int coaching, out int cheerleading, out int policies, out ulong total) { + public static void CalculateVarsityExpenses(ref DistrictPark district, out ulong upkeep, out int coaching, out int cheerleading, out int policies, out ulong total) + { upkeep = district.FetchArenasUpkeep(); coaching = district.CalculateCoachingStaffCost() / 100; int activeArenasCount = district.GetActiveArenasCount(); cheerleading = district.m_cheerleadingBudget * activeArenasCount; policies = 0; DistrictPolicies.Park parkPolicies = district.m_parkPolicies; - if ((parkPolicies & DistrictPolicies.Park.FreeFanMerchandise) != 0) { + if ((parkPolicies & DistrictPolicies.Park.FreeFanMerchandise) != 0) + { policies += 180 * activeArenasCount; } - if ((parkPolicies & DistrictPolicies.Park.VarsitySportsAds) != 0) { + if ((parkPolicies & DistrictPolicies.Park.VarsitySportsAds) != 0) + { policies += 200 * activeArenasCount; } upkeep /= MainDataStore.gameExpenseDivide; diff --git a/Patch/DistrictParkCalculateVarsityExpensesPatch.cs b/Patch/DistrictParkCalculateVarsityExpensesPatch.cs index 245fb13..13fedc4 100644 --- a/Patch/DistrictParkCalculateVarsityExpensesPatch.cs +++ b/Patch/DistrictParkCalculateVarsityExpensesPatch.cs @@ -8,11 +8,13 @@ namespace RealCity.Patch [HarmonyPatch] public class DistrictParkCalculateVarsityExpensesPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(DistrictPark).GetMethod("CalculateVarsityExpenses", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ulong).MakeByRefType(), typeof(int).MakeByRefType(), typeof(int).MakeByRefType(), typeof(int).MakeByRefType(), typeof(ulong).MakeByRefType() }, null); } - public static void Postfix(ref ulong upkeep, ref int coaching, ref int cheerleading, ref int policies, ref ulong total) { + public static void Postfix(ref ulong upkeep, ref int coaching, ref int cheerleading, ref int policies, ref ulong total) + { upkeep /= MainDataStore.gameExpenseDivide; coaching /= MainDataStore.gameExpenseDivide; cheerleading /= MainDataStore.gameExpenseDivide; diff --git a/Patch/EconomyManagerAddPrivateIncomePatch.cs b/Patch/EconomyManagerAddPrivateIncomePatch.cs index 740d26f..dcee590 100644 --- a/Patch/EconomyManagerAddPrivateIncomePatch.cs +++ b/Patch/EconomyManagerAddPrivateIncomePatch.cs @@ -47,12 +47,15 @@ public class EconomyManagerAddPrivateIncomePatch public static float healthCareIncome = 0f; public static float fireStationIncome = 0f; - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(EconomyManager).GetMethod("AddPrivateIncome", BindingFlags.Public | BindingFlags.Instance); } - public static void CustomAddGovermentIncome(ref int amount, ItemClass.Service service) { - switch (service) { + public static void CustomAddGovermentIncome(ref int amount, ItemClass.Service service) + { + switch (service) + { case ItemClass.Service.Garbage: ProcessUnitTax100(ref amount, ref garbageIncome); RealCityEconomyManager.garbageIncomeForUI[MainDataStore.updateMoneyCount] += amount; @@ -80,8 +83,10 @@ public static void CustomAddGovermentIncome(ref int amount, ItemClass.Service se } } - public static void CustomAddPersonalTaxIncome(ref int amount, ItemClass.Service service) { - switch (service) { + public static void CustomAddPersonalTaxIncome(ref int amount, ItemClass.Service service) + { + switch (service) + { case ItemClass.Service.Residential: ProcessUnitTax100(ref amount, ref residentTaxIncome); break; @@ -92,18 +97,24 @@ public static void CustomAddPersonalTaxIncome(ref int amount, ItemClass.Service RealCityEconomyManager.citizenTaxIncomeForUI[MainDataStore.updateMoneyCount] = RealCityEconomyManager.citizenTaxIncomeForUI[MainDataStore.updateMoneyCount] + amount; } - public static void CustomAddTourismIncome(ref int amount, int taxRate) { - if (taxRate == 114333) { + public static void CustomAddTourismIncome(ref int amount, int taxRate) + { + if (taxRate == 114333) + { ProcessUnitTax100(ref amount, ref citizenIncome); RealCityEconomyManager.citizenIncomeForUI[MainDataStore.updateMoneyCount] += amount; - } else { + } + else + { ProcessUnitTax100(ref amount, ref touristIncome); RealCityEconomyManager.touristIncomeForUI[MainDataStore.updateMoneyCount] += amount; } } - public static void CustomAddPrivateTradeIncome(ref int amount, ItemClass.SubService subService) { - switch (subService) { + public static void CustomAddPrivateTradeIncome(ref int amount, ItemClass.SubService subService) + { + switch (subService) + { case ItemClass.SubService.IndustrialFarming: ProcessUnitTax100(ref amount, ref industyFarmTradeIncome); RealCityEconomyManager.induFarmerTradeIncomeForUI[MainDataStore.updateMoneyCount] += amount; @@ -151,8 +162,10 @@ public static void CustomAddPrivateTradeIncome(ref int amount, ItemClass.SubServ } } - public static void CustomAddPrivateLandIncome(ref int amount, ItemClass.SubService subService, int taxRate) { - switch (subService) { + public static void CustomAddPrivateLandIncome(ref int amount, ItemClass.SubService subService, int taxRate) + { + switch (subService) + { case ItemClass.SubService.IndustrialFarming: ProcessUnit(ref amount, ref industyFarmIncome, taxRate); RealCityEconomyManager.induFarmerLandIncomeForUI[MainDataStore.updateMoneyCount] += amount; @@ -224,53 +237,74 @@ public static void CustomAddPrivateLandIncome(ref int amount, ItemClass.SubServi } } - public static void ProcessUnit(ref int amount, ref float container, int taxRate) { + public static void ProcessUnit(ref int amount, ref float container, int taxRate) + { container += (amount * taxRate / 100f); - if (container > 1) { + if (container > 1) + { amount = (int)container; container -= (int)container; - } else { + } + else + { amount = 0; } } - public static void ProcessUnitTax100(ref int amount, ref float container) { + public static void ProcessUnitTax100(ref int amount, ref float container) + { container += amount; - if (container > 1) { + if (container > 1) + { amount = (int)container; container -= (int)container; - } else { + } + else + { amount = 0; } } - public static bool Prefix(int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, int taxRate) { - if (amount < 0) { + public static bool Prefix(int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, int taxRate) + { + if (amount < 0) + { DebugLog.LogToFileOnly($"Error: EconomyManagerAddPrivateIncomePatch amount < 0 {service} {subService} {level}"); amount = 0; } - if (taxRate == 115333) { + if (taxRate == 115333) + { //115333 means playerbuilding income //taxRate = 100; no need to send taxRate. CustomAddGovermentIncome(ref amount, service); service = ItemClass.Service.Industrial; subService = ItemClass.SubService.IndustrialGeneric; level = ItemClass.Level.Level3; - } else if ((taxRate == 113333) || (taxRate == 114333)) { + } + else if ((taxRate == 113333) || (taxRate == 114333)) + { //113333 means tourist tourism income // 114333 means resident tourism income CustomAddTourismIncome(ref amount, taxRate); - } else if (taxRate == 112333) { + } + else if (taxRate == 112333) + { //112333 means personal slary tax income //taxRate = 100; no need to send taxRate. CustomAddPersonalTaxIncome(ref amount, service); - } else if (taxRate == 111333) { + } + else if (taxRate == 111333) + { //111333 means trade income //taxRate = 100; no need to send taxRate. CustomAddPrivateTradeIncome(ref amount, subService); - } else if (taxRate >= 100) { + } + else if (taxRate >= 100) + { taxRate = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Economics, taxRate); taxRate /= 100; CustomAddPrivateLandIncome(ref amount, subService, taxRate); - } else { + } + else + { amount = 0; } diff --git a/Patch/EconomyManagerAddResourceItemClassPatch.cs b/Patch/EconomyManagerAddResourceItemClassPatch.cs index 8de372c..77c762d 100644 --- a/Patch/EconomyManagerAddResourceItemClassPatch.cs +++ b/Patch/EconomyManagerAddResourceItemClassPatch.cs @@ -9,25 +9,37 @@ namespace RealCity.Patch [HarmonyPatch] public class EconomyManagerAddResourceItemClassPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(EconomyManager).GetMethod("AddResource", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(EconomyManager.Resource), typeof(int), typeof(ItemClass) }, null); } - public static void Prefix(EconomyManager.Resource resource, ref int amount, ItemClass itemClass) { + public static void Prefix(EconomyManager.Resource resource, ref int amount, ItemClass itemClass) + { // NON-STOCK CODE START - if (resource == EconomyManager.Resource.TourismIncome) { + if (resource == EconomyManager.Resource.TourismIncome) + { amount = 0; - } else if (resource == EconomyManager.Resource.ResourcePrice) { + } + else if (resource == EconomyManager.Resource.ResourcePrice) + { RealCityEconomyManager.playerIndustryIncomeForUI[MainDataStore.updateMoneyCount] += amount; - } else if (resource == EconomyManager.Resource.PublicIncome && itemClass.m_service == ItemClass.Service.Beautification) { - if (amount > 0) { + } + else if (resource == EconomyManager.Resource.PublicIncome && itemClass.m_service == ItemClass.Service.Beautification) + { + if (amount > 0) + { RealCityEconomyManager.citizenIncomeForUI[MainDataStore.updateMoneyCount] += amount; - } else { + } + else + { //We use negetive amount to identify tourist income amount = -amount; RealCityEconomyManager.touristIncomeForUI[MainDataStore.updateMoneyCount] += amount; } - } else if (resource == EconomyManager.Resource.PublicIncome && itemClass.m_service == ItemClass.Service.PlayerEducation) { + } + else if (resource == EconomyManager.Resource.PublicIncome && itemClass.m_service == ItemClass.Service.PlayerEducation) + { RealCityEconomyManager.schoolIncomeForUI[MainDataStore.updateMoneyCount] += amount; } } diff --git a/Patch/EconomyManagerAddResourcePatchItemClassDetail.cs b/Patch/EconomyManagerAddResourcePatchItemClassDetail.cs index 11bd598..5c6e983 100644 --- a/Patch/EconomyManagerAddResourcePatchItemClassDetail.cs +++ b/Patch/EconomyManagerAddResourcePatchItemClassDetail.cs @@ -9,24 +9,31 @@ namespace RealCity.Patch [HarmonyPatch] public class EconomyManagerAddResourcePatchItemClassDetail { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(EconomyManager).GetMethod("AddResource", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(EconomyManager.Resource), typeof(int), typeof(ItemClass.Service), typeof(ItemClass.SubService), typeof(ItemClass.Level) }, null); } - public static void Prefix(EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { + public static void Prefix(EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) + { // NON-STOCK CODE START - if (resource == EconomyManager.Resource.PublicIncome) { - if (service == ItemClass.Service.Vehicles) { + if (resource == EconomyManager.Resource.PublicIncome) + { + if (service == ItemClass.Service.Vehicles) + { RealCityEconomyManager.roadIncomeForUI[MainDataStore.updateMoneyCount] += amount; - if (subService == ItemClass.SubService.None) { + if (subService == ItemClass.SubService.None) + { if (level == ItemClass.Level.Level2) MainDataStore.outsideGovermentMoney -= amount; else MainDataStore.outsideTouristMoney -= amount; } } - } else if (resource == EconomyManager.Resource.ResourcePrice) { + } + else if (resource == EconomyManager.Resource.ResourcePrice) + { RealCityEconomyManager.playerIndustryIncomeForUI[MainDataStore.updateMoneyCount] += amount; } /// NON-STOCK CODE END /// diff --git a/Patch/EconomyManagerFetchResourcePatch.cs b/Patch/EconomyManagerFetchResourcePatch.cs index f21a8d3..1342a8d 100644 --- a/Patch/EconomyManagerFetchResourcePatch.cs +++ b/Patch/EconomyManagerFetchResourcePatch.cs @@ -26,11 +26,14 @@ public class EconomyManagerFetchResourcePatch public static float Museums = 0f; public static float Fishing = 0f; public static float VarsitySports = 0f; - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(EconomyManager).GetMethod("FetchResource", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(EconomyManager.Resource), typeof(int), typeof(ItemClass.Service), typeof(ItemClass.SubService), typeof(ItemClass.Level) }, null); } - public static void OnFetchResourceMaintenance(EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { - switch (service) { + public static void OnFetchResourceMaintenance(EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) + { + switch (service) + { case ItemClass.Service.Road: ProcessUnit(ref amount, ref Road); break; @@ -86,45 +89,60 @@ public static void OnFetchResourceMaintenance(EconomyManager.Resource resource, } } - public static void OnFetchResourcePolicy(EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) { + public static void OnFetchResourcePolicy(EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level) + { ProcessUnit(ref amount, ref Policy_cost); } - public static void ProcessUnit(ref int amount, ref float container) { + public static void ProcessUnit(ref int amount, ref float container) + { container += amount / MainDataStore.gameExpenseDivide; - if (container > 1) { + if (container > 1) + { amount = (int)container; container -= (int)container; - } else { + } + else + { amount = 0; } } - public static void Prefix(ref EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, ref uint __state) { - if (amount < 0) { + public static void Prefix(ref EconomyManager.Resource resource, ref int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, ref uint __state) + { + if (amount < 0) + { DebugLog.LogToFileOnly($"Error: EconomyManagerFetchResourcePatch: amount < 0 {service} {subService} {level}"); amount = 0; } __state = 0xdeadbeaf; - if (resource == EconomyManager.Resource.PolicyCost) { + if (resource == EconomyManager.Resource.PolicyCost) + { OnFetchResourcePolicy(resource, ref amount, service, subService, level); } - if (resource == EconomyManager.Resource.Maintenance) { + if (resource == EconomyManager.Resource.Maintenance) + { //we must return right amount for playerbuilding to work normally. if (amount > 0) __state = (uint)amount; OnFetchResourceMaintenance(resource, ref amount, service, subService, level); - } else if (resource == (EconomyManager.Resource)16) { + } + else if (resource == (EconomyManager.Resource)16) + { resource = EconomyManager.Resource.Maintenance; - } else if (resource == (EconomyManager.Resource)17) { + } + else if (resource == (EconomyManager.Resource)17) + { resource = EconomyManager.Resource.PolicyCost; } } - public static void Postfix(ref int __result, ref uint __state) { - if (__state != 0xdeadbeaf) { + public static void Postfix(ref int __result, ref uint __state) + { + if (__state != 0xdeadbeaf) + { __result = (int)__state; } } diff --git a/Patch/EconomyPanelIncomeExpensesPollPatch.cs b/Patch/EconomyPanelIncomeExpensesPollPatch.cs index 50266b8..88a4f62 100644 --- a/Patch/EconomyPanelIncomeExpensesPollPatch.cs +++ b/Patch/EconomyPanelIncomeExpensesPollPatch.cs @@ -10,38 +10,48 @@ namespace RealCity.Patch [HarmonyPatch] public class EconomyPanelIncomeExpensesPollPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(EconomyPanel).GetNestedType("IncomeExpensesPoll", BindingFlags.NonPublic).GetMethod("CalculateArenasExpenses", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(EconomyPanel.ArenaIndex), typeof(long).MakeByRefType() }, null); } - public static void Init() { + public static void Init() + { DebugLog.LogToFileOnly("Init fake RealCityEconomyPanel"); - try { + try + { var inst = Singleton.instance; var arenas = typeof(EconomyPanel).GetField("m_arenas", BindingFlags.NonPublic | BindingFlags.Static); - if (inst == null) { + if (inst == null) + { DebugLog.LogToFileOnly("No instance of EconomyPanel found!"); return; } m_arenas = arenas.GetValue(inst) as List[]; - if (m_arenas == null) { + if (m_arenas == null) + { DebugLog.LogToFileOnly("EconomyPanel Arrays are null"); } } - catch (Exception ex) { + catch (Exception ex) + { DebugLog.LogToFileOnly("EconomyPanel Exception: " + ex.Message); } } - public static bool Prefix(EconomyPanel.ArenaIndex arenaIndex, ref long expenses) { - if (!init) { + public static bool Prefix(EconomyPanel.ArenaIndex arenaIndex, ref long expenses) + { + if (!init) + { Init(); init = true; } - for (int i = 0; i < m_arenas[(int)arenaIndex].Count; i++) { + for (int i = 0; i < m_arenas[(int)arenaIndex].Count; i++) + { ushort buildingID = m_arenas[(int)arenaIndex][i]; var Info = Singleton.instance.m_buildings.m_buffer[buildingID].Info; - if (Info != null) { + if (Info != null) + { Singleton.instance.GetIncomeAndExpenses(Info.m_class.m_service, Info.m_class.m_subService, Info.m_class.m_level, out long _, out long expense); expenses += expense; return false; diff --git a/Patch/ExtractingFacilityAIGetResourceRatePatch.cs b/Patch/ExtractingFacilityAIGetResourceRatePatch.cs index ea53a31..ba81905 100644 --- a/Patch/ExtractingFacilityAIGetResourceRatePatch.cs +++ b/Patch/ExtractingFacilityAIGetResourceRatePatch.cs @@ -10,11 +10,14 @@ namespace RealCity.Patch [HarmonyPatch] public class ExtractingFacilityAIGetResourceRatePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(ExtractingFacilityAI).GetMethod("GetResourceRate", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(EconomyManager.Resource) }, null); } - public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) { - if (resource == EconomyManager.Resource.Maintenance) { + public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) + { + if (resource == EconomyManager.Resource.Maintenance) + { float salary = RealCityPlayerBuildingAI.CaculateEmployeeOutcome(buildingID, data); __result = (int)((float)__result / MainDataStore.gameExpenseDivide - salary * 100f); } diff --git a/Patch/HumanAIEnterParkAreaPatch.cs b/Patch/HumanAIEnterParkAreaPatch.cs index 9c9e66d..38b27bd 100644 --- a/Patch/HumanAIEnterParkAreaPatch.cs +++ b/Patch/HumanAIEnterParkAreaPatch.cs @@ -10,10 +10,12 @@ namespace RealCity.Patch [HarmonyPatch] public class HumanAIEnterParkAreaPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(HumanAI).GetMethod("EnterParkArea", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(CitizenInstance).MakeByRefType(), typeof(byte), typeof(ushort) }, null); } - public static bool Prefix() { + public static bool Prefix() + { //do not allow ticket price return false; } diff --git a/Patch/HumanAIEnterVehiclePatch.cs b/Patch/HumanAIEnterVehiclePatch.cs index fa7d20b..de01195 100644 --- a/Patch/HumanAIEnterVehiclePatch.cs +++ b/Patch/HumanAIEnterVehiclePatch.cs @@ -10,30 +10,42 @@ namespace RealCity.Patch [HarmonyPatch] public class HumanAIEnterVehiclePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(HumanAI).GetMethod("EnterVehicle", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(CitizenInstance).MakeByRefType() }, null); } - public static void Prefix(ref CitizenInstance citizenData) { + public static void Prefix(ref CitizenInstance citizenData) + { uint citizen = citizenData.m_citizen; - if (citizen != 0u) { + if (citizen != 0u) + { VehicleManager vehicleManager = Singleton.instance; ushort vehicleID = Singleton.instance.m_citizens.m_buffer[citizen].m_vehicle; - if (vehicleID != 0) { + if (vehicleID != 0) + { vehicleID = vehicleManager.m_vehicles.m_buffer[vehicleID].GetFirstVehicle(vehicleID); } - if (vehicleID != 0) { + if (vehicleID != 0) + { VehicleInfo info = vehicleManager.m_vehicles.m_buffer[vehicleID].Info; int ticketPrice = info.m_vehicleAI.GetTicketPrice(vehicleID, ref vehicleManager.m_vehicles.m_buffer[vehicleID]); - if (ticketPrice != 0) { + if (ticketPrice != 0) + { // NON-STOCK CODE START CitizenManager citizenManager = Singleton.instance; - if ((citizenManager.m_citizens.m_buffer[citizenData.m_citizen].m_flags & Citizen.Flags.Tourist) == Citizen.Flags.None) { + if ((citizenManager.m_citizens.m_buffer[citizenData.m_citizen].m_flags & Citizen.Flags.Tourist) == Citizen.Flags.None) + { CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - (ticketPrice)); - } else { - if (CitizenData.citizenMoney[citizen] < ticketPrice) { + } + else + { + if (CitizenData.citizenMoney[citizen] < ticketPrice) + { ticketPrice = (CitizenData.citizenMoney[citizen] > 0) ? (int)CitizenData.citizenMoney[citizen] + 1 : 1; CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - ticketPrice); - } else { + } + else + { CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - (ticketPrice)); } MainDataStore.outsideTouristMoney -= ticketPrice; diff --git a/Patch/HumanAIStartMovingPatch.cs b/Patch/HumanAIStartMovingPatch.cs index c351b24..8329788 100644 --- a/Patch/HumanAIStartMovingPatch.cs +++ b/Patch/HumanAIStartMovingPatch.cs @@ -13,15 +13,19 @@ namespace RealCity.Patch [HarmonyPatch] public class HumanAIStartMovingPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { var method = typeof(HumanAI).GetMethod("StartMoving", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint), typeof(Citizen).MakeByRefType(), typeof(ushort), typeof(ushort) }, null); return method; } - public static void Prefix(uint citizenID, ref Citizen data, ref ushort sourceBuilding, ref ushort targetBuilding) { - if (data.m_workBuilding != targetBuilding) { + public static void Prefix(uint citizenID, ref Citizen data, ref ushort sourceBuilding, ref ushort targetBuilding) + { + if (data.m_workBuilding != targetBuilding) + { var building = Singleton.instance.m_buildings.m_buffer[targetBuilding]; - if (building.Info.m_class.m_service == ItemClass.Service.Commercial) { + if (building.Info.m_class.m_service == ItemClass.Service.Commercial) + { CitizenManager instance = Singleton.instance; ushort homeBuilding = data.m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); @@ -35,7 +39,8 @@ public static void Prefix(uint citizenID, ref Citizen data, ref ushort sourceBui var amount = building.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount; var CommercialBuildingAI = building.Info.m_buildingAI as CommercialBuildingAI; var maxCount = CommercialBuildingAI.CalculateVisitplaceCount((ItemClass.Level)building.m_level, new Randomizer(targetBuilding), building.m_width, building.m_length); - if ((amount <= 0) || (maxCount <= totalVisitCount)) { + if ((amount <= 0) || (maxCount <= totalVisitCount)) + { //Close CommercialBuilding //Reject citizen to building which lack of goods sourceBuilding = targetBuilding; @@ -43,19 +48,26 @@ public static void Prefix(uint citizenID, ref Citizen data, ref ushort sourceBui return; } - if (data.m_flags.IsFlagSet(Citizen.Flags.Tourist)) { + if (data.m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { //DebugLog.LogToFileOnly("Find Tourist in HumanAIStartMovingPatch"); - } else { + } + else + { //DebugLog.LogToFileOnly("Find Resident in HumanAIStartMovingPatch"); - if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)) { + if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)) + { //Reject poor citizen to building - if (CitizenUnitData.familyGoods[containingUnit] > 1000) { + if (CitizenUnitData.familyGoods[containingUnit] > 1000) + { //If a family is lacking goods very seriously, even they do not have enough money, they can buy goods. //minimumLivingAllowance will cover this expense. sourceBuilding = targetBuilding; return; } - } else if (CitizenUnitData.familyGoods[containingUnit] > 2000) { + } + else if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { //Reject citizen who already have enough goods to building sourceBuilding = targetBuilding; return; diff --git a/Patch/IndustrialBuildingAICreateBuildingPatch.cs b/Patch/IndustrialBuildingAICreateBuildingPatch.cs index aab79c0..ca4a968 100644 --- a/Patch/IndustrialBuildingAICreateBuildingPatch.cs +++ b/Patch/IndustrialBuildingAICreateBuildingPatch.cs @@ -10,10 +10,12 @@ namespace RealCity.Patch [HarmonyPatch] public class IndustrialBuildingAICreateBuildingPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(IndustrialBuildingAI).GetMethod("CreateBuilding", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType() }, null); } - public static void Postfix(ushort buildingID, ref Building data) { + public static void Postfix(ushort buildingID, ref Building data) + { RealCityIndustrialBuildingAI.InitDelegate(); var material = RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID); float initialMaterialFee = data.m_customBuffer1 * RealCityIndustryBuildingAI.GetResourcePrice(material) + 10000; diff --git a/Patch/IndustrialBuildingAIModifyMaterialBufferPatch.cs b/Patch/IndustrialBuildingAIModifyMaterialBufferPatch.cs index 4ced287..90cf202 100644 --- a/Patch/IndustrialBuildingAIModifyMaterialBufferPatch.cs +++ b/Patch/IndustrialBuildingAIModifyMaterialBufferPatch.cs @@ -12,34 +12,44 @@ namespace RealCity.Patch [HarmonyPatch] public class IndustrialBuildingAIModifyMaterialBufferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(IndustrialBuildingAI).GetMethod("ModifyMaterialBuffer", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(TransferManager.TransferReason), typeof(int).MakeByRefType() }, null); } - public static void Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { + public static void Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { RealCityIndustrialBuildingAI.InitDelegate(); - if (material == RealCityIndustrialBuildingAI.GetOutgoingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI))) { + if (material == RealCityIndustrialBuildingAI.GetOutgoingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI))) + { RevertTradeIncome(buildingID, ref data, material, ref amountDelta); } } - public static void Postfix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { + public static void Postfix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { RealCityIndustrialBuildingAI.InitDelegate(); - if (material == RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID) || material == RealCityIndustrialBuildingAI.GetSecondaryIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) { + if (material == RealCityIndustrialBuildingAI.GetIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID) || material == RealCityIndustrialBuildingAI.GetSecondaryIncomingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI), buildingID)) + { ProcessIncoming(buildingID, material, ref amountDelta); - } else if (material == RealCityIndustrialBuildingAI.GetOutgoingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI))) { + } + else if (material == RealCityIndustrialBuildingAI.GetOutgoingTransferReason((IndustrialBuildingAI)(data.Info.m_buildingAI))) + { CaculateTradeIncome(buildingID, ref data, material, ref amountDelta); } } - public static void ProcessIncoming(ushort buildingID, TransferManager.TransferReason material, ref int amountDelta) { + public static void ProcessIncoming(ushort buildingID, TransferManager.TransferReason material, ref int amountDelta) + { float tradeIncome = amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); BuildingData.buildingMoney[buildingID] = BuildingData.buildingMoney[buildingID] - tradeIncome; } - public static void RevertTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (amountDelta > 0) { + public static void RevertTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (amountDelta > 0) + { //revert data.m_customBuffer2 = (ushort)Mathf.Clamp(data.m_customBuffer2 + amountDelta, 0, 65535); float tradeIncome = -amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); @@ -50,8 +60,10 @@ public static void RevertTradeIncome(ushort buildingID, ref Building data, Trans } } - public static void CaculateTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (amountDelta < 0) { + public static void CaculateTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (amountDelta < 0) + { float tradeIncome = amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); float tradeTax = -tradeIncome * RealCityPrivateBuildingAI.GetTaxRate(data) / 100f; Singleton.instance.AddPrivateIncome((int)tradeTax, ItemClass.Service.Industrial, data.Info.m_class.m_subService, data.Info.m_class.m_level, 111333); diff --git a/Patch/IndustrialBuildingAISimulationStepActivePatch.cs b/Patch/IndustrialBuildingAISimulationStepActivePatch.cs index 16cc8b9..2da7627 100644 --- a/Patch/IndustrialBuildingAISimulationStepActivePatch.cs +++ b/Patch/IndustrialBuildingAISimulationStepActivePatch.cs @@ -13,17 +13,20 @@ namespace RealCity.Patch [HarmonyPatch] public class IndustrialBuildingAISimulationStepActivePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(IndustrialBuildingAI).GetMethod("SimulationStepActive", BindingFlags.NonPublic | BindingFlags.Instance); } - public static void Prefix(ref Building buildingData, ref ushort[] __state) { + public static void Prefix(ref Building buildingData, ref ushort[] __state) + { __state = new ushort[2]; __state[0] = buildingData.m_customBuffer1; __state[1] = buildingData.m_customBuffer2; } - public static void Postfix(ushort buildingID, ref Building buildingData, ref ushort[] __state) { + public static void Postfix(ushort buildingID, ref Building buildingData, ref ushort[] __state) + { RealCityPrivateBuildingAI.ProcessAdditionProduct(buildingID, ref buildingData, ref __state); } diff --git a/Patch/IndustrialExtractorAIModifyMaterialBufferPatch.cs b/Patch/IndustrialExtractorAIModifyMaterialBufferPatch.cs index b699c44..a331065 100644 --- a/Patch/IndustrialExtractorAIModifyMaterialBufferPatch.cs +++ b/Patch/IndustrialExtractorAIModifyMaterialBufferPatch.cs @@ -12,26 +12,33 @@ namespace RealCity.Patch [HarmonyPatch] public class IndustrialExtractorAIModifyMaterialBufferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(IndustrialExtractorAI).GetMethod("ModifyMaterialBuffer", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(TransferManager.TransferReason), typeof(int).MakeByRefType() }, null); } - public static void Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { + public static void Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { RealCityIndustrialExtractorAI.InitDelegate(); - if (material == RealCityIndustrialExtractorAI.GetOutgoingTransferReason((IndustrialExtractorAI)(data.Info.m_buildingAI))) { + if (material == RealCityIndustrialExtractorAI.GetOutgoingTransferReason((IndustrialExtractorAI)(data.Info.m_buildingAI))) + { RevertTradeIncome(buildingID, ref data, material, ref amountDelta); } } - public static void Postfix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { + public static void Postfix(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { RealCityIndustrialExtractorAI.InitDelegate(); - if (material == RealCityIndustrialExtractorAI.GetOutgoingTransferReason((IndustrialExtractorAI)(data.Info.m_buildingAI))) { + if (material == RealCityIndustrialExtractorAI.GetOutgoingTransferReason((IndustrialExtractorAI)(data.Info.m_buildingAI))) + { CaculateTradeIncome(buildingID, ref data, material, ref amountDelta); } } - public static void RevertTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (amountDelta > 0) { + public static void RevertTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (amountDelta > 0) + { //revert data.m_customBuffer1 = (ushort)Mathf.Clamp(data.m_customBuffer1 + amountDelta, 0, 65535); float tradeIncome = -amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); @@ -42,8 +49,10 @@ public static void RevertTradeIncome(ushort buildingID, ref Building data, Trans } } - public static void CaculateTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if (amountDelta < 0) { + public static void CaculateTradeIncome(ushort buildingID, ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if (amountDelta < 0) + { float tradeIncome = amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); float tradeTax = -tradeIncome * RealCityPrivateBuildingAI.GetTaxRate(data) / 100f; Singleton.instance.AddPrivateIncome((int)tradeTax, ItemClass.Service.Industrial, data.Info.m_class.m_subService, data.Info.m_class.m_level, 111333); diff --git a/Patch/IndustrialExtractorAISimulationStepActivePatch.cs b/Patch/IndustrialExtractorAISimulationStepActivePatch.cs index 3dde6ff..37e233e 100644 --- a/Patch/IndustrialExtractorAISimulationStepActivePatch.cs +++ b/Patch/IndustrialExtractorAISimulationStepActivePatch.cs @@ -13,16 +13,19 @@ namespace RealCity.Patch [HarmonyPatch] public class IndustrialExtractorAISimulationStepActivePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(IndustrialExtractorAI).GetMethod("SimulationStepActive", BindingFlags.NonPublic | BindingFlags.Instance); } - public static void Prefix(ref Building buildingData, ref ushort[] __state) { + public static void Prefix(ref Building buildingData, ref ushort[] __state) + { __state = new ushort[1]; __state[0] = buildingData.m_customBuffer1; } - public static void Postfix(ref Building buildingData, ref ushort[] __state) { + public static void Postfix(ref Building buildingData, ref ushort[] __state) + { RealCityPrivateBuildingAI.ProcessAdditionProduct(ref buildingData, ref __state); } } diff --git a/Patch/IndustryBuildingGetResourcePricePatch.cs b/Patch/IndustryBuildingGetResourcePricePatch.cs index 1fc4dcf..1d01dbe 100644 --- a/Patch/IndustryBuildingGetResourcePricePatch.cs +++ b/Patch/IndustryBuildingGetResourcePricePatch.cs @@ -11,12 +11,15 @@ namespace RealCity.Patch [HarmonyPatch] public class IndustryBuildingGetResourcePricePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(IndustryBuildingAI).GetMethod("GetResourcePrice", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); } - public static bool Prefix(ref int __result, TransferManager.TransferReason material, ItemClass.Service sourceService = ItemClass.Service.None) { + public static bool Prefix(ref int __result, TransferManager.TransferReason material, ItemClass.Service sourceService = ItemClass.Service.None) + { bool canRisePrice = true; - switch (material) { + switch (material) + { case TransferManager.TransferReason.AnimalProducts: __result = 150; break; case TransferManager.TransferReason.Flours: @@ -44,9 +47,12 @@ public static bool Prefix(ref int __result, TransferManager.TransferReason mater case TransferManager.TransferReason.Grain: __result = 100; break; case TransferManager.TransferReason.Goods: - if (sourceService == ItemClass.Service.Fishing) { + if (sourceService == ItemClass.Service.Fishing) + { __result = 500; - } else { + } + else + { __result = 0; } break; @@ -66,10 +72,13 @@ public static bool Prefix(ref int __result, TransferManager.TransferReason mater case TransferManager.TransferReason.ShoppingD: case TransferManager.TransferReason.ShoppingE: case TransferManager.TransferReason.ShoppingH: - if (sourceService == ItemClass.Service.Fishing) { + if (sourceService == ItemClass.Service.Fishing) + { __result = 200; canRisePrice = false; - } else { + } + else + { __result = 0; } break; @@ -81,7 +90,8 @@ public static bool Prefix(ref int __result, TransferManager.TransferReason mater default: __result = 0; break; } - if (RealCity.reduceVehicle) { + if (RealCity.reduceVehicle) + { if (canRisePrice) __result <<= MainDataStore.reduceCargoDivShift; } diff --git a/Patch/LandfillSiteAIModifyMaterialBufferPatch.cs b/Patch/LandfillSiteAIModifyMaterialBufferPatch.cs index 4c48d20..0392557 100644 --- a/Patch/LandfillSiteAIModifyMaterialBufferPatch.cs +++ b/Patch/LandfillSiteAIModifyMaterialBufferPatch.cs @@ -12,30 +12,40 @@ namespace RealCity.Patch [HarmonyPatch] public class LandfillSiteAIModifyMaterialBufferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(LandfillSiteAI).GetMethod("ModifyMaterialBuffer", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(TransferManager.TransferReason), typeof(int).MakeByRefType() }, null); } - public static void Prefix(ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if ((material == TransferManager.TransferReason.Lumber) || (material == TransferManager.TransferReason.Coal) || (material == TransferManager.TransferReason.Petrol)) { - if (amountDelta > 0) { + public static void Prefix(ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if ((material == TransferManager.TransferReason.Lumber) || (material == TransferManager.TransferReason.Coal) || (material == TransferManager.TransferReason.Petrol)) + { + if (amountDelta > 0) + { RevertGabargeIncome(ref data, amountDelta, material); } } } - public static void Postfix(ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - if ((material == TransferManager.TransferReason.Lumber) || (material == TransferManager.TransferReason.Coal) || (material == TransferManager.TransferReason.Petrol)) { - if (amountDelta < 0) { + public static void Postfix(ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + if ((material == TransferManager.TransferReason.Lumber) || (material == TransferManager.TransferReason.Coal) || (material == TransferManager.TransferReason.Petrol)) + { + if (amountDelta < 0) + { ProcessGabargeIncome(ref data, amountDelta, material); } } } - public static void ProcessGabargeIncome(ref Building building, int amountDelta, TransferManager.TransferReason material) { - if (building.Info.m_class.m_service == ItemClass.Service.Garbage) { + public static void ProcessGabargeIncome(ref Building building, int amountDelta, TransferManager.TransferReason material) + { + if (building.Info.m_class.m_service == ItemClass.Service.Garbage) + { float product_value; - switch (material) { + switch (material) + { case TransferManager.TransferReason.Lumber: product_value = -amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); Singleton.instance.AddResource(EconomyManager.Resource.ResourcePrice, (int)product_value, ItemClass.Service.PlayerIndustry, ItemClass.SubService.PlayerIndustryForestry, ItemClass.Level.Level1); @@ -53,10 +63,12 @@ public static void ProcessGabargeIncome(ref Building building, int amountDelta, } } - public static void RevertGabargeIncome(ref Building building, int amountDelta, TransferManager.TransferReason material) { + public static void RevertGabargeIncome(ref Building building, int amountDelta, TransferManager.TransferReason material) + { building.m_customBuffer2 = (ushort)Mathf.Clamp(building.m_customBuffer2 + amountDelta, 0, 65535); float productValue; - switch (material) { + switch (material) + { case TransferManager.TransferReason.Lumber: productValue = amountDelta * RealCityIndustryBuildingAI.GetResourcePrice(material); Singleton.instance.FetchResource(EconomyManager.Resource.ResourcePrice, (int)productValue, ItemClass.Service.PlayerIndustry, ItemClass.SubService.PlayerIndustryForestry, ItemClass.Level.Level1); diff --git a/Patch/MarketAIModifyMaterialBufferPatch.cs b/Patch/MarketAIModifyMaterialBufferPatch.cs index 9fcad21..c4fd495 100644 --- a/Patch/MarketAIModifyMaterialBufferPatch.cs +++ b/Patch/MarketAIModifyMaterialBufferPatch.cs @@ -9,20 +9,25 @@ namespace RealCity.Patch [HarmonyPatch] public class MarketAIModifyMaterialBufferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(MarketAI).GetMethod("ModifyMaterialBuffer", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(TransferManager.TransferReason), typeof(int).MakeByRefType() }, null); } - public static bool Prefix(ref Building data, TransferManager.TransferReason material, ref int amountDelta) { - switch (material) { + public static bool Prefix(ref Building data, TransferManager.TransferReason material, ref int amountDelta) + { + switch (material) + { case TransferManager.TransferReason.ShoppingB: case TransferManager.TransferReason.ShoppingC: case TransferManager.TransferReason.ShoppingD: case TransferManager.TransferReason.ShoppingE: case TransferManager.TransferReason.ShoppingF: case TransferManager.TransferReason.ShoppingG: - case TransferManager.TransferReason.ShoppingH: { - if (amountDelta == -100) { + case TransferManager.TransferReason.ShoppingH: + { + if (amountDelta == -100) + { //Disable other -100 ModifyMaterialBuffer return false; } @@ -36,7 +41,8 @@ public static bool Prefix(ref Building data, TransferManager.TransferReason mate IndustryBuildingGetResourcePricePatch.Prefix(ref priceInt, material, data.Info.m_class.m_service); var m_goodsSellPrice = priceInt / 100; int num = (-amountDelta * m_goodsSellPrice + 50) / 100; - if (num != 0) { + if (num != 0) + { Singleton.instance.AddResource(EconomyManager.Resource.ResourcePrice, num, data.Info.m_class); } return false; diff --git a/Patch/MarketAIVisitorEnterPatch.cs b/Patch/MarketAIVisitorEnterPatch.cs index db3ec2b..d48e2d9 100644 --- a/Patch/MarketAIVisitorEnterPatch.cs +++ b/Patch/MarketAIVisitorEnterPatch.cs @@ -11,20 +11,25 @@ namespace RealCity.Patch [HarmonyPatch] public class MarketAIVisitorEnterPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(MarketAI).GetMethod("VisitorEnter", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(uint) }, null); } - public static bool Prefix(ushort buildingID, ref Building data, uint citizen) { + public static bool Prefix(ushort buildingID, ref Building data, uint citizen) + { CitizenManager citizenManager = Singleton.instance; BuildingInfo buildingInfo = data.Info; - if ((citizenManager.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { + if ((citizenManager.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) + { var consumptionMoney = -MainDataStore.maxGoodPurchase; buildingInfo.m_buildingAI.ModifyMaterialBuffer(buildingID, ref data, TransferManager.TransferReason.Shopping, ref consumptionMoney); int priceInt = 0; IndustryBuildingGetResourcePricePatch.Prefix(ref priceInt, TransferManager.TransferReason.Shopping, data.Info.m_class.m_service); var m_goodsSellPrice = priceInt / 100; MainDataStore.outsideTouristMoney += (consumptionMoney * m_goodsSellPrice); - } else { + } + else + { ushort homeBuilding = citizenManager.m_citizens.m_buffer[citizen].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = citizenManager.m_citizens.m_buffer[citizen].GetContainingUnit((uint)citizen, citizenUnit, CitizenUnit.Flags.Home); @@ -32,20 +37,26 @@ public static bool Prefix(ushort buildingID, ref Building data, uint citizen) { IndustryBuildingGetResourcePricePatch.Prefix(ref priceInt, TransferManager.TransferReason.Shopping, data.Info.m_class.m_service); var m_goodsSellPrice = priceInt / 100; - if (containingUnit != 0) { + if (containingUnit != 0) + { //int goodAmount = (int)(-(CitizenUnitData.familyMoney[containingUnit]) / m_goodsSellPrice); int goodAmount = -MainDataStore.maxGoodPurchase; - if (goodAmount < 0) { + if (goodAmount < 0) + { buildingInfo.m_buildingAI.ModifyMaterialBuffer(buildingID, ref data, TransferManager.TransferReason.Shopping, ref goodAmount); - if (goodAmount != 0) { + if (goodAmount != 0) + { CitizenUnitData.familyGoods[containingUnit] = (ushort)(CitizenUnitData.familyGoods[containingUnit] - (goodAmount * 10)); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { citizenManager.m_citizens.m_buffer[citizen].m_flags &= ~Citizen.Flags.NeedGoods; } } - } else { + } + else + { goodAmount = 0; } diff --git a/Patch/OfficeBuildingAIGetOutgoingTransferReasonPatch.cs b/Patch/OfficeBuildingAIGetOutgoingTransferReasonPatch.cs index 2dd940d..5a41a59 100644 --- a/Patch/OfficeBuildingAIGetOutgoingTransferReasonPatch.cs +++ b/Patch/OfficeBuildingAIGetOutgoingTransferReasonPatch.cs @@ -8,10 +8,12 @@ namespace RealCity.Patch [HarmonyPatch] public class OfficeBuildingAIGetOutgoingTransferReasonPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(OfficeBuildingAI).GetMethod("GetOutgoingTransferReason", BindingFlags.NonPublic | BindingFlags.Instance); } - public static bool Prefix(ref TransferManager.TransferReason __result) { + public static bool Prefix(ref TransferManager.TransferReason __result) + { __result = TransferManager.TransferReason.None; return false; } diff --git a/Patch/OutsideConnectionAIModifyMaterialBufferPatch.cs b/Patch/OutsideConnectionAIModifyMaterialBufferPatch.cs index a66a10b..a83cad1 100644 --- a/Patch/OutsideConnectionAIModifyMaterialBufferPatch.cs +++ b/Patch/OutsideConnectionAIModifyMaterialBufferPatch.cs @@ -10,11 +10,14 @@ namespace RealCity.Patch [HarmonyBefore("pcfantasy.moreoutsideinteraction")] public static class OutsideConnectionAIModifyMaterialBufferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(OutsideConnectionAI).GetMethod("ModifyMaterialBuffer", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(TransferManager.TransferReason), typeof(int).MakeByRefType() }, null); } - public static void Prefix(TransferManager.TransferReason material, ref int amountDelta) { - switch (material) { + public static void Prefix(TransferManager.TransferReason material, ref int amountDelta) + { + switch (material) + { case TransferManager.TransferReason.Oil: case TransferManager.TransferReason.Ore: case TransferManager.TransferReason.Coal: @@ -34,7 +37,8 @@ public static void Prefix(TransferManager.TransferReason material, ref int amoun case TransferManager.TransferReason.Glass: case TransferManager.TransferReason.PlanedTimber: case TransferManager.TransferReason.Paper: - if (amountDelta < 0) { + if (amountDelta < 0) + { int transferSize = -amountDelta; MainDataStore.outsideGovermentMoney += (transferSize * RealCityIndustryBuildingAI.GetResourcePrice(material) * MainDataStore.outsideGovermentProfitRatio); MainDataStore.outsideTouristMoney += (transferSize * RealCityIndustryBuildingAI.GetResourcePrice(material) * MainDataStore.outsideCompanyProfitRatio * MainDataStore.outsideTouristSalaryProfitRatio); diff --git a/Patch/PassengerCarAIArriveAtTargetPatch.cs b/Patch/PassengerCarAIArriveAtTargetPatch.cs index de10358..87a97bf 100644 --- a/Patch/PassengerCarAIArriveAtTargetPatch.cs +++ b/Patch/PassengerCarAIArriveAtTargetPatch.cs @@ -15,48 +15,67 @@ namespace RealCity.Patch [HarmonyPatch] public static class PassengerCarAIArriveAtTargetPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(PassengerCarAI).GetMethod("ArriveAtTarget", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }, null); } - public static void Prefix(ushort vehicleID, ref Vehicle data) { + public static void Prefix(ushort vehicleID, ref Vehicle data) + { GetVehicleRunningTiming(vehicleID, ref data); } - public static void GetVehicleRunningTiming(ushort vehicleID, ref Vehicle vehicleData) { + public static void GetVehicleRunningTiming(ushort vehicleID, ref Vehicle vehicleData) + { CitizenManager citizenManager = Singleton.instance; ushort instanceID = GetDriverInstance(vehicleID, ref vehicleData); - if (instanceID != 0) { + if (instanceID != 0) + { uint citizenID = citizenManager.m_instances.m_buffer[instanceID].m_citizen; - if (citizenID != 0) { - if (!(citizenManager.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.DummyTraffic))) { - if (!(citizenManager.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist))) { - if (!IsOutSide(citizenManager.m_instances.m_buffer[instanceID].GetLastFramePosition())) { + if (citizenID != 0) + { + if (!(citizenManager.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.DummyTraffic))) + { + if (!(citizenManager.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist))) + { + if (!IsOutSide(citizenManager.m_instances.m_buffer[instanceID].GetLastFramePosition())) + { MainDataStore.totalCitizenDrivingTime += VehicleData.vehicleTransferTime[vehicleID]; - if (vehicleData.m_citizenUnits != 0) { + if (vehicleData.m_citizenUnits != 0) + { CitizenData.citizenMoney[citizenID] -= VehicleData.vehicleTransferTime[vehicleID]; } - } else { + } + else + { MainDataStore.outsideTouristMoney -= VehicleData.vehicleTransferTime[vehicleID]; - if (RealCity.noPassengerCar) { - if (vehicleData.m_citizenUnits != 0) { - if (citizenManager.m_citizens.m_buffer[citizenID].m_vehicle == vehicleID) { + if (RealCity.noPassengerCar) + { + if (vehicleData.m_citizenUnits != 0) + { + if (citizenManager.m_citizens.m_buffer[citizenID].m_vehicle == vehicleID) + { Singleton.instance.ReleaseVehicle(vehicleID); citizenManager.m_citizens.m_buffer[citizenID].m_vehicle = 0; - } else if (citizenManager.m_citizens.m_buffer[citizenID].m_vehicle != 0) { + } + else if (citizenManager.m_citizens.m_buffer[citizenID].m_vehicle != 0) + { DebugLog.LogToFileOnly($"Warning: citizen vehicleID = {citizenManager.m_citizens.m_buffer[citizenID].m_vehicle}, but vehicleID = {vehicleID}"); Singleton.instance.ReleaseVehicle(citizenManager.m_citizens.m_buffer[citizenID].m_vehicle); Singleton.instance.ReleaseVehicle(vehicleID); citizenManager.m_citizens.m_buffer[citizenID].m_vehicle = 0; } - if (citizenManager.m_citizens.m_buffer[citizenID].m_parkedVehicle != 0) { + if (citizenManager.m_citizens.m_buffer[citizenID].m_parkedVehicle != 0) + { Singleton.instance.ReleaseParkedVehicle(citizenManager.m_citizens.m_buffer[citizenID].m_parkedVehicle); citizenManager.m_citizens.m_buffer[citizenID].m_parkedVehicle = 0; } } } } - } else { + } + else + { MainDataStore.outsideTouristMoney -= VehicleData.vehicleTransferTime[vehicleID]; } } @@ -65,29 +84,36 @@ public static void GetVehicleRunningTiming(ushort vehicleID, ref Vehicle vehicle VehicleData.vehicleTransferTime[vehicleID] = 0; } - public static bool IsOutSide(Vector3 pos) { + public static bool IsOutSide(Vector3 pos) + { if (pos.x > 8400 || pos.z > 8400 || pos.x < -8400 || pos.z < -8400) return true; return false; } - public static ushort GetDriverInstance(ushort vehicleID, ref Vehicle data) { + public static ushort GetDriverInstance(ushort vehicleID, ref Vehicle data) + { CitizenManager instance = Singleton.instance; uint num = data.m_citizenUnits; int num2 = 0; - while (num != 0u) { + while (num != 0u) + { uint nextUnit = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_nextUnit; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { uint citizen = instance.m_units.m_buffer[(int)((UIntPtr)num)].GetCitizen(i); - if (citizen != 0u) { + if (citizen != 0u) + { ushort instance2 = instance.m_citizens.m_buffer[(int)((UIntPtr)citizen)].m_instance; - if (instance2 != 0) { + if (instance2 != 0) + { return instance2; } } } num = nextUnit; - if (++num2 > 524288) { + if (++num2 > 524288) + { CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } diff --git a/Patch/PlayerBuildingAIGetResourceRatePatch.cs b/Patch/PlayerBuildingAIGetResourceRatePatch.cs index afff049..c9b79cc 100644 --- a/Patch/PlayerBuildingAIGetResourceRatePatch.cs +++ b/Patch/PlayerBuildingAIGetResourceRatePatch.cs @@ -10,11 +10,14 @@ namespace RealCity.Patch [HarmonyPatch] public class PlayerBuildingAIGetResourceRatePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(PlayerBuildingAI).GetMethod("GetResourceRate", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(EconomyManager.Resource) }, null); } - public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) { - if (resource == EconomyManager.Resource.Maintenance) { + public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) + { + if (resource == EconomyManager.Resource.Maintenance) + { float salary = RealCityPlayerBuildingAI.CaculateEmployeeOutcome(buildingID, data); __result = (int)((float)__result / MainDataStore.gameExpenseDivide - salary * 100f); } diff --git a/Patch/PlayerBuildingAISimulationStepPatch.cs b/Patch/PlayerBuildingAISimulationStepPatch.cs index 30286a6..4dd86f9 100644 --- a/Patch/PlayerBuildingAISimulationStepPatch.cs +++ b/Patch/PlayerBuildingAISimulationStepPatch.cs @@ -11,29 +11,38 @@ namespace RealCity.Patch [HarmonyPatch] public class PlayerBuildingAISimulationStepPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(PlayerBuildingAI).GetMethod("SimulationStep", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(Building.Frame).MakeByRefType() }, null); } - public static void Postfix(ushort buildingID, ref Building buildingData) { + public static void Postfix(ushort buildingID, ref Building buildingData) + { ProcessZeroWorker(buildingID, ref buildingData); } - public static void ProcessZeroWorker(ushort buildingID, ref Building data) { - if (data.m_flags.IsFlagSet(Building.Flags.Completed)) { + public static void ProcessZeroWorker(ushort buildingID, ref Building data) + { + if (data.m_flags.IsFlagSet(Building.Flags.Completed)) + { int aliveWorkCount = 0; int totalWorkCount = 0; Citizen.BehaviourData behaviour = default; RealCityCommonBuildingAI.InitDelegate(); RealCityCommonBuildingAI.GetWorkBehaviour((PlayerBuildingAI)data.Info.m_buildingAI, buildingID, ref data, ref behaviour, ref aliveWorkCount, ref totalWorkCount); int allWorkCount; - if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) { + if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) + { allWorkCount = RealCityResidentAI.TotalWorkCount(buildingID, data, true, true); - } else { + } + else + { allWorkCount = RealCityResidentAI.TotalWorkCount(buildingID, data, true, false); } - if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) { - if (totalWorkCount == 0 && allWorkCount != 0) { + if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) + { + if (totalWorkCount == 0 && allWorkCount != 0) + { int budget = Singleton.instance.GetBudget(data.Info.m_class); int education3Salary = Math.Max((int)((budget * MainDataStore.govermentEducation3SalaryFixed) / 100), (int)(MainDataStore.govermentSalary * 0.8f)); float num1 = education3Salary * allWorkCount; diff --git a/Patch/PrivateBuildingAISimulationStepActivePatch.cs b/Patch/PrivateBuildingAISimulationStepActivePatch.cs index ddc5e52..60a5e41 100644 --- a/Patch/PrivateBuildingAISimulationStepActivePatch.cs +++ b/Patch/PrivateBuildingAISimulationStepActivePatch.cs @@ -14,27 +14,33 @@ namespace RealCity.Patch [HarmonyPatch] public class PrivateBuildingAISimulationStepActivePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(PrivateBuildingAI).GetMethod("SimulationStepActive", BindingFlags.NonPublic | BindingFlags.Instance); } - public static void Prefix(ref Building buildingData, ref ushort[] __state) { + public static void Prefix(ref Building buildingData, ref ushort[] __state) + { __state = new ushort[2]; __state[0] = buildingData.m_customBuffer1; __state[1] = buildingData.m_customBuffer2; } - public static void Postfix(ushort buildingID, ref Building buildingData) { + public static void Postfix(ushort buildingID, ref Building buildingData) + { ProcessLandFeeNoOffice(buildingData, buildingID); - if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) { + if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) + { CalculateBuildingMoneyAndSalary(buildingData, buildingID); } LimitCommericalBuildingAccess(buildingID, ref buildingData); ProcessBuildingDataFinal(buildingID, ref buildingData); } - public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buildingData) { - if (RealCityPrivateBuildingAI.preBuidlingId > buildingID) { + public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buildingData) + { + if (RealCityPrivateBuildingAI.preBuidlingId > buildingID) + { RealCityPrivateBuildingAI.allOfficeHighTechWorkCountFinal = RealCityPrivateBuildingAI.allOfficeHighTechWorkCount; RealCityPrivateBuildingAI.allOfficeLevel1WorkCountFinal = RealCityPrivateBuildingAI.allOfficeLevel1WorkCount; RealCityPrivateBuildingAI.allOfficeLevel2WorkCountFinal = RealCityPrivateBuildingAI.allOfficeLevel2WorkCount; @@ -49,13 +55,15 @@ public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buil RealCityPrivateBuildingAI.allOfficeHighTechWorkCount = 0; } RealCityPrivateBuildingAI.preBuidlingId = buildingID; - if (buildingData.Info.m_class.m_service == ItemClass.Service.Residential) { + if (buildingData.Info.m_class.m_service == ItemClass.Service.Residential) + { BuildingData.buildingMoney[buildingID] = 0; } float building_money = BuildingData.buildingMoney[buildingID]; - if (buildingData.Info.m_class.m_service == ItemClass.Service.Industrial) { + if (buildingData.Info.m_class.m_service == ItemClass.Service.Industrial) + { if (building_money < 0) RealCityEconomyExtension.industrialLackMoneyCount++; else @@ -65,7 +73,8 @@ public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buil if (building_money < 0) BuildingData.buildingMoneyThreat[buildingID] = 1.0f; - switch (buildingData.Info.m_class.m_service) { + switch (buildingData.Info.m_class.m_service) + { case ItemClass.Service.Residential: float familyMoney = GetResidentialBuildingAverageMoney(buildingData); if (familyMoney < (MainDataStore.highWealth >> 1)) @@ -81,7 +90,8 @@ public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buil case ItemClass.Service.Office: float averageBuildingSalary = BuildingUI.CaculateEmployeeOutcome(buildingData, out _); - if (MainDataStore.citizenCount > 0.0) { + if (MainDataStore.citizenCount > 0.0) + { float averageCitySalary = MainDataStore.citizenSalaryTotal / MainDataStore.citizenCount; float salaryFactor = averageBuildingSalary / averageCitySalary; if (salaryFactor > 3f) @@ -90,34 +100,47 @@ public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buil salaryFactor = 0.0f; BuildingData.buildingMoneyThreat[buildingID] = (1.0f - salaryFactor / 3f); - } else + } + else BuildingData.buildingMoneyThreat[buildingID] = 1.0f; break; } - if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) { + if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) + { //get all commercial building for resident. - if (buildingData.m_customBuffer2 > 2000) { + if (buildingData.m_customBuffer2 > 2000) + { BuildingData.commBuildingNum++; BuildingData.commBuildingID[BuildingData.commBuildingNum] = buildingID; } - if (BuildingData.buildingMoney[buildingID] < 0) { + if (BuildingData.buildingMoney[buildingID] < 0) + { RealCityEconomyExtension.commercialLackMoneyCount++; - } else { + } + else + { RealCityEconomyExtension.commercialEarnMoneyCount++; } } - if (buildingData.m_problems == Notification.Problem.None) { + if (buildingData.m_problems == Notification.Problem.None) + { //mark no good - if ((buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) && (RealCity.debugMode)) { + if ((buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) && (RealCity.debugMode)) + { Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoGoods); - if (buildingData.m_customBuffer2 < 500) { + if (buildingData.m_customBuffer2 < 500) + { problem = Notification.AddProblems(problem, Notification.Problem.NoGoods | Notification.Problem.MajorProblem); - } else if (buildingData.m_customBuffer2 < 1000) { + } + else if (buildingData.m_customBuffer2 < 1000) + { problem = Notification.AddProblems(problem, Notification.Problem.NoGoods); - } else { + } + else + { problem = Notification.Problem.None; } buildingData.m_problems = problem; @@ -125,35 +148,43 @@ public static void ProcessBuildingDataFinal(ushort buildingID, ref Building buil } } - public static float GetResidentialBuildingAverageMoney(Building buildingData) { + public static float GetResidentialBuildingAverageMoney(Building buildingData) + { CitizenManager instance = Singleton.instance; uint citzenUnit = buildingData.m_citizenUnits; int unitCount = 0; long totalMoney = 0; float averageMoney = 0; - while (citzenUnit != 0u) { - if ((ushort)(instance.m_units.m_buffer[citzenUnit].m_flags & CitizenUnit.Flags.Home) != 0) { - if ((instance.m_units.m_buffer[citzenUnit].m_citizen0 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen1 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen2 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen3 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen4 != 0)) { + while (citzenUnit != 0u) + { + if ((ushort)(instance.m_units.m_buffer[citzenUnit].m_flags & CitizenUnit.Flags.Home) != 0) + { + if ((instance.m_units.m_buffer[citzenUnit].m_citizen0 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen1 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen2 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen3 != 0) || (instance.m_units.m_buffer[citzenUnit].m_citizen4 != 0)) + { unitCount++; totalMoney += (long)CitizenUnitData.familyMoney[citzenUnit]; } } citzenUnit = instance.m_units.m_buffer[citzenUnit].m_nextUnit; - if (++unitCount > 524288) { + if (++unitCount > 524288) + { CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } - if (unitCount != 0) { + if (unitCount != 0) + { averageMoney = (float)totalMoney / unitCount; } return averageMoney; } - public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building buildingData) { - if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) { + public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building buildingData) + { + if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) + { Citizen.BehaviourData behaviour = default; int aliveVisitCount = 0; int totalVisitCount = 0; @@ -162,24 +193,31 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building var amount = buildingData.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount; var AI = buildingData.Info.m_buildingAI as CommercialBuildingAI; var maxcount = AI.CalculateVisitplaceCount((ItemClass.Level)buildingData.m_level, new Randomizer(buildingID), buildingData.m_width, buildingData.m_length); - if ((amount <= 0) || (maxcount <= totalVisitCount)) { + if ((amount <= 0) || (maxcount <= totalVisitCount)) + { buildingData.m_flags &= ~Building.Flags.Active; } - if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) { + if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) + { //Remove citizen which already have goods CitizenManager instance = Singleton.instance; uint num = buildingData.m_citizenUnits; int num2 = 0; - while (num != 0u) { - if ((ushort)(instance.m_units.m_buffer[(int)((UIntPtr)num)].m_flags & CitizenUnit.Flags.Visit) != 0) { + while (num != 0u) + { + if ((ushort)(instance.m_units.m_buffer[(int)((UIntPtr)num)].m_flags & CitizenUnit.Flags.Visit) != 0) + { var citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen0; - if (citizenID != 0u) { + if (citizenID != 0u) + { ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { - if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { + if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { BuildingManager instance1 = Singleton.instance; instance.m_citizens.m_buffer[citizenID].RemoveFromUnits(citizenID, instance1.m_buildings.m_buffer[buildingID].m_citizenUnits, CitizenUnit.Flags.Visit); return; @@ -187,12 +225,15 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building } } citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen1; - if (citizenID != 0u) { + if (citizenID != 0u) + { ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { - if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { + if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { BuildingManager instance1 = Singleton.instance; instance.m_citizens.m_buffer[citizenID].RemoveFromUnits(citizenID, instance1.m_buildings.m_buffer[buildingID].m_citizenUnits, CitizenUnit.Flags.Visit); return; @@ -200,12 +241,15 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building } } citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen2; - if (citizenID != 0u) { + if (citizenID != 0u) + { ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { - if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { + if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { BuildingManager instance1 = Singleton.instance; instance.m_citizens.m_buffer[citizenID].RemoveFromUnits(citizenID, instance1.m_buildings.m_buffer[buildingID].m_citizenUnits, CitizenUnit.Flags.Visit); return; @@ -213,12 +257,15 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building } } citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen3; - if (citizenID != 0u) { + if (citizenID != 0u) + { ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { - if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { + if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { BuildingManager instance1 = Singleton.instance; instance.m_citizens.m_buffer[citizenID].RemoveFromUnits(citizenID, instance1.m_buildings.m_buffer[buildingID].m_citizenUnits, CitizenUnit.Flags.Visit); return; @@ -226,12 +273,15 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building } } citizenID = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_citizen4; - if (citizenID != 0u) { + if (citizenID != 0u) + { ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); - if (CitizenUnitData.familyGoods[containingUnit] > 2000) { - if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) { + if (CitizenUnitData.familyGoods[containingUnit] > 2000) + { + if (!instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { BuildingManager instance1 = Singleton.instance; instance.m_citizens.m_buffer[citizenID].RemoveFromUnits(citizenID, instance1.m_buildings.m_buffer[buildingID].m_citizenUnits, CitizenUnit.Flags.Visit); return; @@ -240,7 +290,8 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building } } num = instance.m_units.m_buffer[(int)((UIntPtr)num)].m_nextUnit; - if (++num2 > 524288) { + if (++num2 > 524288) + { CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } @@ -249,15 +300,20 @@ public static void LimitCommericalBuildingAccess(ushort buildingID, ref Building } } - public static void CalculateBuildingMoneyAndSalary(Building building, ushort buildingID) { - if (BuildingData.buildingMoney[buildingID] > MainDataStore.maxBuildingMoneyLimit) { + public static void CalculateBuildingMoneyAndSalary(Building building, ushort buildingID) + { + if (BuildingData.buildingMoney[buildingID] > MainDataStore.maxBuildingMoneyLimit) + { BuildingData.buildingMoney[buildingID] = MainDataStore.maxBuildingMoneyLimit; - } else if (BuildingData.buildingMoney[buildingID] < -MainDataStore.maxBuildingMoneyLimit) { + } + else if (BuildingData.buildingMoney[buildingID] < -MainDataStore.maxBuildingMoneyLimit) + { BuildingData.buildingMoney[buildingID] = -MainDataStore.maxBuildingMoneyLimit; } - if (building.Info.m_class.m_service == ItemClass.Service.Industrial || building.Info.m_class.m_service == ItemClass.Service.Commercial || building.Info.m_class.m_service == ItemClass.Service.Office) { + if (building.Info.m_class.m_service == ItemClass.Service.Industrial || building.Info.m_class.m_service == ItemClass.Service.Commercial || building.Info.m_class.m_service == ItemClass.Service.Office) + { Citizen.BehaviourData behaviourData = default; int aliveWorkerCount = 0; int totalWorkerCount = 0; @@ -267,17 +323,21 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui float investToOffice = 0; float profitShare = 0; - switch (building.Info.m_class.m_subService) { + switch (building.Info.m_class.m_subService) + { case ItemClass.SubService.OfficeGeneric: case ItemClass.SubService.OfficeHightech: profitShare = 1f; break; case ItemClass.SubService.IndustrialFarming: case ItemClass.SubService.IndustrialForestry: - if (building.Info.m_buildingAI is IndustrialExtractorAI) { + if (building.Info.m_buildingAI is IndustrialExtractorAI) + { bossTake = MainDataStore.bossRatioInduExtractor; investToOffice = MainDataStore.investRatioInduExtractor; profitShare = MainDataStore.profitShareRatioInduExtractor; - } else { + } + else + { bossTake = MainDataStore.bossRatioInduOther; investToOffice = MainDataStore.investRatioInduOther; profitShare = MainDataStore.profitShareRatioInduOther; @@ -289,15 +349,20 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui investToOffice = MainDataStore.investRatioInduOther; profitShare = MainDataStore.profitShareRatioInduOther; break; case ItemClass.SubService.IndustrialGeneric: - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { bossTake = MainDataStore.bossRatioInduLevel1; investToOffice = MainDataStore.investRatioInduLevel1; profitShare = MainDataStore.profitShareRatioInduLevel1; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { bossTake = MainDataStore.bossRatioInduLevel2; investToOffice = MainDataStore.investRatioInduLevel2; profitShare = MainDataStore.profitShareRatioInduLevel2; - } else { + } + else + { bossTake = MainDataStore.bossRatioInduLevel3; investToOffice = MainDataStore.investRatioInduLevel3; profitShare = MainDataStore.profitShareRatioInduLevel3; @@ -305,15 +370,20 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui break; case ItemClass.SubService.CommercialHigh: case ItemClass.SubService.CommercialLow: - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { bossTake = MainDataStore.bossRatioCommLevel1; investToOffice = MainDataStore.investRatioCommLevel1; profitShare = MainDataStore.profitShareRatioCommLevel1; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { bossTake = MainDataStore.bossRatioCommLevel2; investToOffice = MainDataStore.investRatioCommLevel2; profitShare = MainDataStore.profitShareRatioCommLevel2; - } else { + } + else + { bossTake = MainDataStore.bossRatioCommLevel3; investToOffice = MainDataStore.investRatioCommLevel3; profitShare = MainDataStore.profitShareRatioCommLevel1; @@ -334,11 +404,13 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui profitShare = MainDataStore.profitShareRatioCommECO; break; } // boss take and return to office - if (BuildingData.buildingMoney[buildingID] > 0) { + if (BuildingData.buildingMoney[buildingID] > 0) + { //Reduce Boss fee long investToOfficeFee = (long)(BuildingData.buildingMoney[buildingID] * investToOffice); long bossTakeFee = (long)(BuildingData.buildingMoney[buildingID] * bossTake); - if (building.Info.m_class.m_service == ItemClass.Service.Commercial) { + if (building.Info.m_class.m_service == ItemClass.Service.Commercial) + { //Commercial have help tourism MainDataStore.outsideTouristMoney += ((bossTakeFee - investToOfficeFee) * MainDataStore.outsideCompanyProfitRatio * MainDataStore.outsideTouristSalaryProfitRatio); } @@ -346,22 +418,32 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui BuildingData.buildingMoney[buildingID] -= bossTakeFee; } - if (building.Info.m_class.m_service == ItemClass.Service.Office) { + if (building.Info.m_class.m_service == ItemClass.Service.Office) + { float allOfficeWorker = RealCityPrivateBuildingAI.allOfficeLevel1WorkCountFinal + RealCityPrivateBuildingAI.allOfficeLevel2WorkCountFinal + RealCityPrivateBuildingAI.allOfficeLevel3WorkCountFinal + RealCityPrivateBuildingAI.allOfficeHighTechWorkCountFinal; float averageOfficeSalary = 0; - if (allOfficeWorker != 0) { + if (allOfficeWorker != 0) + { averageOfficeSalary = (RealCityPrivateBuildingAI.profitBuildingMoneyFinal / allOfficeWorker); } - if (building.Info.m_class.m_subService == ItemClass.SubService.OfficeGeneric) { - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_subService == ItemClass.SubService.OfficeGeneric) + { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { BuildingData.buildingMoney[buildingID] = averageOfficeSalary * totalWorkerCount * 0.6f; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { BuildingData.buildingMoney[buildingID] = averageOfficeSalary * totalWorkerCount * 0.8f; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { BuildingData.buildingMoney[buildingID] = averageOfficeSalary * totalWorkerCount * 1f; } - } else if (building.Info.m_class.m_subService == ItemClass.SubService.OfficeHightech) { + } + else if (building.Info.m_class.m_subService == ItemClass.SubService.OfficeHightech) + { BuildingData.buildingMoney[buildingID] = averageOfficeSalary * totalWorkerCount * 0.75f; } @@ -371,9 +453,11 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui //Calculate building salary int buildingAsset = (int)(BuildingData.buildingMoney[buildingID] + building.m_customBuffer1 * RealCityIndustryBuildingAI.GetResourcePrice(RealCityPrivateBuildingAI.GetIncomingProductionType(buildingID, building))); int salary = 0; - if ((buildingAsset > 0) && (totalWorkerCount != 0)) { + if ((buildingAsset > 0) && (totalWorkerCount != 0)) + { salary = (int)(buildingAsset * profitShare / totalWorkerCount); - switch (building.Info.m_class.m_subService) { + switch (building.Info.m_class.m_subService) + { case ItemClass.SubService.IndustrialFarming: case ItemClass.SubService.IndustrialForestry: case ItemClass.SubService.IndustrialOil: @@ -409,15 +493,19 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui BuildingData.buildingWorkCount[buildingID] = salary; else BuildingData.buildingWorkCount[buildingID] = 0; - } else { + } + else + { //resident building ItemClass @class = building.Info.m_class; int incomeAccumulation = 0; DistrictManager instance = Singleton.instance; byte district = instance.GetDistrict(building.m_position); DistrictPolicies.Taxation taxationPolicies = instance.m_districts.m_buffer[district].m_taxationPolicies; - if (@class.m_subService == ItemClass.SubService.ResidentialLow) { - switch (@class.m_level) { + if (@class.m_subService == ItemClass.SubService.ResidentialLow) + { + switch (@class.m_level) + { case ItemClass.Level.Level1: incomeAccumulation = MainDataStore.residentLowLevel1Rent; break; @@ -434,8 +522,11 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui incomeAccumulation = MainDataStore.residentLowLevel5Rent; break; } - } else if (@class.m_subService == ItemClass.SubService.ResidentialLowEco) { - switch (@class.m_level) { + } + else if (@class.m_subService == ItemClass.SubService.ResidentialLowEco) + { + switch (@class.m_level) + { case ItemClass.Level.Level1: incomeAccumulation = MainDataStore.residentLowLevel1Rent << 1; break; @@ -452,8 +543,11 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui incomeAccumulation = MainDataStore.residentLowLevel5Rent << 1; break; } - } else if (@class.m_subService == ItemClass.SubService.ResidentialHigh) { - switch (@class.m_level) { + } + else if (@class.m_subService == ItemClass.SubService.ResidentialHigh) + { + switch (@class.m_level) + { case ItemClass.Level.Level1: incomeAccumulation = MainDataStore.residentHighLevel1Rent; break; @@ -470,8 +564,11 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui incomeAccumulation = MainDataStore.residentHighLevel5Rent; break; } - } else { - switch (@class.m_level) { + } + else + { + switch (@class.m_level) + { case ItemClass.Level.Level1: incomeAccumulation = MainDataStore.residentHighLevel1Rent << 1; break; @@ -496,7 +593,8 @@ public static void CalculateBuildingMoneyAndSalary(Building building, ushort bui } } - public static void ProcessLandFeeOffice(Building building, ushort buildingID, int totalWorkerCount) { + public static void ProcessLandFeeOffice(Building building, ushort buildingID, int totalWorkerCount) + { DistrictManager instance = Singleton.instance; byte district = instance.GetDistrict(building.m_position); DistrictPolicies.Services servicePolicies = instance.m_districts.m_buffer[district].m_servicePolicies; @@ -506,22 +604,27 @@ public static void ProcessLandFeeOffice(Building building, ushort buildingID, in int taxRate; taxRate = Singleton.instance.GetTaxRate(building.Info.m_class, taxationPolicies); - if (instance.IsPolicyLoaded(DistrictPolicies.Policies.ExtraInsulation)) { - if ((servicePolicies & DistrictPolicies.Services.ExtraInsulation) != DistrictPolicies.Services.None) { + if (instance.IsPolicyLoaded(DistrictPolicies.Policies.ExtraInsulation)) + { + if ((servicePolicies & DistrictPolicies.Services.ExtraInsulation) != DistrictPolicies.Services.None) + { landFee = landFee * 95 / 100; } } - if ((servicePolicies & DistrictPolicies.Services.Recycling) != DistrictPolicies.Services.None) { + if ((servicePolicies & DistrictPolicies.Services.Recycling) != DistrictPolicies.Services.None) + { landFee = landFee * 95 / 100; } - if (BuildingData.buildingMoney[buildingID] >= 0) { + if (BuildingData.buildingMoney[buildingID] >= 0) + { BuildingData.buildingMoney[buildingID] = (BuildingData.buildingMoney[buildingID] - (float)(landFee * taxRate) / 100); Singleton.instance.AddPrivateIncome(landFee, building.Info.m_class.m_service, building.Info.m_class.m_subService, building.Info.m_class.m_level, taxRate * 100); } } - public static void ProcessLandFeeNoOffice(Building building, ushort buildingID) { + public static void ProcessLandFeeNoOffice(Building building, ushort buildingID) + { DistrictManager instance = Singleton.instance; byte district = instance.GetDistrict(building.m_position); DistrictPolicies.Services servicePolicies = instance.m_districts.m_buffer[district].m_servicePolicies; @@ -533,34 +636,44 @@ public static void ProcessLandFeeNoOffice(Building building, ushort buildingID) taxRate = Singleton.instance.GetTaxRate(building.Info.m_class, taxationPolicies); - if (((taxationPolicies & DistrictPolicies.Taxation.DontTaxLeisure) != DistrictPolicies.Taxation.None) && (building.Info.m_class.m_subService == ItemClass.SubService.CommercialLeisure)) { + if (((taxationPolicies & DistrictPolicies.Taxation.DontTaxLeisure) != DistrictPolicies.Taxation.None) && (building.Info.m_class.m_subService == ItemClass.SubService.CommercialLeisure)) + { landFee = 0; } - if (instance.IsPolicyLoaded(DistrictPolicies.Policies.ExtraInsulation)) { - if ((servicePolicies & DistrictPolicies.Services.ExtraInsulation) != DistrictPolicies.Services.None) { + if (instance.IsPolicyLoaded(DistrictPolicies.Policies.ExtraInsulation)) + { + if ((servicePolicies & DistrictPolicies.Services.ExtraInsulation) != DistrictPolicies.Services.None) + { landFee = landFee * 95 / 100; } } - if ((servicePolicies & DistrictPolicies.Services.Recycling) != DistrictPolicies.Services.None) { + if ((servicePolicies & DistrictPolicies.Services.Recycling) != DistrictPolicies.Services.None) + { landFee = landFee * 95 / 100; } - if (BuildingData.buildingMoney[buildingID] <= ((landFee * taxRate) / 100f)) { + if (BuildingData.buildingMoney[buildingID] <= ((landFee * taxRate) / 100f)) + { landFee = 0; - } else { + } + else + { RealCityPrivateBuildingAI.profitBuildingCount++; } - if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) { + if (RealCityEconomyExtension.Can16timesUpdate(buildingID)) + { Singleton.instance.AddPrivateIncome(landFee, building.Info.m_class.m_service, building.Info.m_class.m_subService, building.Info.m_class.m_level, taxRate * 100); - if ((building.Info.m_class.m_service == ItemClass.Service.Commercial) || (building.Info.m_class.m_service == ItemClass.Service.Industrial)) { + if ((building.Info.m_class.m_service == ItemClass.Service.Commercial) || (building.Info.m_class.m_service == ItemClass.Service.Industrial)) + { BuildingData.buildingMoney[buildingID] = (BuildingData.buildingMoney[buildingID] - (float)(landFee * taxRate) / 100); } } } - public static void GetLandRentNoOffice(out int landRent, Building building, ushort buildingID) { + public static void GetLandRentNoOffice(out int landRent, Building building, ushort buildingID) + { ItemClass @class = building.Info.m_class; landRent = 0; Citizen.BehaviourData behaviourData = default; @@ -568,18 +681,24 @@ public static void GetLandRentNoOffice(out int landRent, Building building, usho int totalWorkerCount = 0; ItemClass.SubService subService = @class.m_subService; RealCityCommonBuildingAI.InitDelegate(); - switch (subService) { + switch (subService) + { case ItemClass.SubService.OfficeHightech: RealCityCommonBuildingAI.GetWorkBehaviour((OfficeBuildingAI)building.Info.m_buildingAI, buildingID, ref building, ref behaviourData, ref aliveWorkerCount, ref totalWorkerCount); RealCityPrivateBuildingAI.allOfficeHighTechWorkCount += totalWorkerCount; break; case ItemClass.SubService.OfficeGeneric: RealCityCommonBuildingAI.GetWorkBehaviour((OfficeBuildingAI)building.Info.m_buildingAI, buildingID, ref building, ref behaviourData, ref aliveWorkerCount, ref totalWorkerCount); - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { RealCityPrivateBuildingAI.allOfficeLevel1WorkCount += totalWorkerCount; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { RealCityPrivateBuildingAI.allOfficeLevel2WorkCount += totalWorkerCount; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { RealCityPrivateBuildingAI.allOfficeLevel3WorkCount += totalWorkerCount; } break; @@ -596,29 +715,44 @@ public static void GetLandRentNoOffice(out int landRent, Building building, usho landRent = MainDataStore.induOre; break; case ItemClass.SubService.IndustrialGeneric: - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { landRent = MainDataStore.induGenLevel1; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { landRent = MainDataStore.induGenLevel2; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { landRent = MainDataStore.induGenLevel3; } break; case ItemClass.SubService.CommercialHigh: - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { landRent = MainDataStore.commHighLevel1; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { landRent = MainDataStore.commHighLevel2; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { landRent = MainDataStore.commHighLevel3; } break; case ItemClass.SubService.CommercialLow: - if (building.Info.m_class.m_level == ItemClass.Level.Level1) { + if (building.Info.m_class.m_level == ItemClass.Level.Level1) + { landRent = MainDataStore.commLowLevel1; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level2) + { landRent = MainDataStore.commLowLevel2; - } else if (building.Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (building.Info.m_class.m_level == ItemClass.Level.Level3) + { landRent = MainDataStore.commLowLevel3; } break; diff --git a/Patch/ProcessingFacilityAIGetResourceRatePatch.cs b/Patch/ProcessingFacilityAIGetResourceRatePatch.cs index 677683a..468c658 100644 --- a/Patch/ProcessingFacilityAIGetResourceRatePatch.cs +++ b/Patch/ProcessingFacilityAIGetResourceRatePatch.cs @@ -10,11 +10,14 @@ namespace RealCity.Patch [HarmonyPatch] public class ProcessingFacilityAIGetResourceRatePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(ProcessingFacilityAI).GetMethod("GetResourceRate", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(EconomyManager.Resource) }, null); } - public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) { - if (resource == EconomyManager.Resource.Maintenance) { + public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) + { + if (resource == EconomyManager.Resource.Maintenance) + { float salary = RealCityPlayerBuildingAI.CaculateEmployeeOutcome(buildingID, data); __result = (int)((float)__result / MainDataStore.gameExpenseDivide - salary * 100f); } diff --git a/Patch/ResidentAICitizenInstanceSimulationStepPatch.cs b/Patch/ResidentAICitizenInstanceSimulationStepPatch.cs index 4ad2e5b..ea5401b 100644 --- a/Patch/ResidentAICitizenInstanceSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenInstanceSimulationStepPatch.cs @@ -9,27 +9,34 @@ namespace RealCity.Patch [HarmonyPatch] public class ResidentAICitizenInstanceSimulationStepPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(ResidentAI).GetMethod("SimulationStep", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(CitizenInstance).MakeByRefType(), typeof(CitizenInstance.Frame).MakeByRefType(), typeof(bool) }, null); } - public static void Prefix(ref CitizenInstance citizenData) { + public static void Prefix(ref CitizenInstance citizenData) + { CitizenManager instance = Singleton.instance; uint citizen = citizenData.m_citizen; - if (citizen != 0 && (instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.NeedGoods) != 0) { + if (citizen != 0 && (instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.NeedGoods) != 0) + { instance.m_citizens.m_buffer[citizen].m_flags &= ~Citizen.Flags.NeedGoods; } } - public static void Postfix(ref CitizenInstance citizenData) { + public static void Postfix(ref CitizenInstance citizenData) + { CitizenManager instance = Singleton.instance; uint citizen = citizenData.m_citizen; - if (citizen != 0) { + if (citizen != 0) + { ushort homeBuilding = instance.m_citizens.m_buffer[citizen].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizen].GetContainingUnit((uint)citizen, citizenUnit, CitizenUnit.Flags.Home); - if (containingUnit != 0) { - if (CitizenUnitData.familyGoods[containingUnit] < 2000) { + if (containingUnit != 0) + { + if (CitizenUnitData.familyGoods[containingUnit] < 2000) + { instance.m_citizens.m_buffer[citizen].m_flags |= Citizen.Flags.NeedGoods; } } diff --git a/Patch/ResidentAICitizenSimulationStepPatch.cs b/Patch/ResidentAICitizenSimulationStepPatch.cs index 8ae8ca0..24ed2b5 100644 --- a/Patch/ResidentAICitizenSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenSimulationStepPatch.cs @@ -11,20 +11,28 @@ namespace RealCity.Patch [HarmonyPatch] public class ResidentAICitizenSimulationStepPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(ResidentAI).GetMethod("SimulationStep", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint), typeof(Citizen).MakeByRefType() }, null); } - public static void Postfix(uint citizenID, ref Citizen data) { + public static void Postfix(uint citizenID, ref Citizen data) + { BuildingManager instance = Singleton.instance; ushort homeBuilding = data.m_homeBuilding; uint homeId = data.GetContainingUnit(citizenID, instance.m_buildings.m_buffer[homeBuilding].m_citizenUnits, CitizenUnit.Flags.Home); - if (homeId != 0) { + if (homeId != 0) + { //Change wealth - if (CitizenUnitData.familyMoney[homeId] > MainDataStore.highWealth) { + if (CitizenUnitData.familyMoney[homeId] > MainDataStore.highWealth) + { data.WealthLevel = Citizen.Wealth.High; - } else if (CitizenUnitData.familyMoney[homeId] < MainDataStore.lowWealth) { + } + else if (CitizenUnitData.familyMoney[homeId] < MainDataStore.lowWealth) + { data.WealthLevel = Citizen.Wealth.Low; - } else { + } + else + { data.WealthLevel = Citizen.Wealth.Medium; } } diff --git a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs index 314f393..8203786 100644 --- a/Patch/ResidentAICitizenUnitSimulationStepPatch.cs +++ b/Patch/ResidentAICitizenUnitSimulationStepPatch.cs @@ -14,7 +14,8 @@ namespace RealCity.Patch [HarmonyPatch] public class ResidentAICitizenUnitSimulationStepPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(ResidentAI).GetMethod( "SimulationStep", BindingFlags.Public | BindingFlags.Instance, @@ -29,45 +30,60 @@ public static MethodBase TargetMethod() { /// /// /// - public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) { + public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) + { FieldInfo fieldInfo; - if (isPre) { + if (isPre) + { CitizenUnitData.familyMoney[homeID] = 0; - for (int i = 0; i <= 4; i++) { + for (int i = 0; i <= 4; i++) + { fieldInfo = data.GetType().GetField($"m_citizen{i}"); uint m_citizenI = (uint)fieldInfo.GetValue(data); - if (m_citizenI != 0) { + if (m_citizenI != 0) + { Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; - if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) { - if (citizenData.Dead == false) { + if ((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) + { + if (citizenData.Dead == false) + { RealCityResidentAI.citizenCount++; CitizenUnitData.familyMoney[homeID] += CitizenData.citizenMoney[m_citizenI]; } } } } - } else { + } + else + { // post-process - if (CitizenUnitData.familyMoney[homeID] < MainDataStore.lowWealth) { + if (CitizenUnitData.familyMoney[homeID] < MainDataStore.lowWealth) + { RealCityResidentAI.familyWeightStableLow++; - } else if (CitizenUnitData.familyMoney[homeID] >= MainDataStore.highWealth) { + } + else if (CitizenUnitData.familyMoney[homeID] >= MainDataStore.highWealth) + { RealCityResidentAI.familyWeightStableHigh++; } int temp = 0; - for (int i = 0; i <= 4; i++) { + for (int i = 0; i <= 4; i++) + { fieldInfo = data.GetType().GetField($"m_citizen{i}"); uint m_citizenI = (uint)fieldInfo.GetValue(data); - if (m_citizenI != 0) { + if (m_citizenI != 0) + { Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) { + if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) + { ++temp; #if FASTRUN #else //add a party.chancce by its citizen data //GetVoteChance(m_citizenI, citizenData, homeID); - if (Politics.IsOnElection() && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizenData.m_age))) { + if (Politics.IsOnElection() && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizenData.m_age))) + { ElectionVoter v = new ElectionVoter(m_citizenI, ref citizenData, homeID, Election.CurrentElectionInfo); v.VoteTicket(); } @@ -76,14 +92,18 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) } } - if (temp != 0) { - for (int i = 0; i <= 4; i++) { + if (temp != 0) + { + for (int i = 0; i <= 4; i++) + { fieldInfo = data.GetType().GetField($"m_citizen{i}"); uint m_citizenI = (uint)fieldInfo.GetValue(data); - if (m_citizenI != 0) { + if (m_citizenI != 0) + { Citizen citizenData = Singleton.instance.m_citizens.m_buffer[m_citizenI]; - if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) { + if (((citizenData.m_flags & Citizen.Flags.MovingIn) == Citizen.Flags.None) && (citizenData.Dead == false)) + { CitizenData.citizenMoney[m_citizenI] = CitizenUnitData.familyMoney[homeID] / temp; } } @@ -92,29 +112,38 @@ public static void ProcessCitizen(uint homeID, ref CitizenUnit data, bool isPre) } } - public static void ProcessFamily(uint homeID, ref CitizenUnit data) { - if (RealCityResidentAI.preCitizenId > homeID) { + public static void ProcessFamily(uint homeID, ref CitizenUnit data) + { + if (RealCityResidentAI.preCitizenId > homeID) + { //DebugLog.LogToFileOnly("Another period started"); MainDataStore.familyCount = RealCityResidentAI.familyCount; MainDataStore.citizenCount = RealCityResidentAI.citizenCount; MainDataStore.level2HighWealth = RealCityResidentAI.level2HighWealth; MainDataStore.level3HighWealth = RealCityResidentAI.level3HighWealth; MainDataStore.level1HighWealth = RealCityResidentAI.level1HighWealth; - if (RealCityResidentAI.familyCount != 0) { + if (RealCityResidentAI.familyCount != 0) + { MainDataStore.citizenSalaryPerFamily = ((RealCityResidentAI.citizenSalaryCount / RealCityResidentAI.familyCount)); MainDataStore.citizenExpensePerFamily = ((RealCityResidentAI.citizenExpenseCount / RealCityResidentAI.familyCount)); } MainDataStore.citizenExpense = RealCityResidentAI.citizenExpenseCount; MainDataStore.citizenSalaryTaxTotal = RealCityResidentAI.citizenSalaryTaxTotal; MainDataStore.citizenSalaryTotal = RealCityResidentAI.citizenSalaryCount; - if (MainDataStore.familyCount < MainDataStore.familyWeightStableHigh) { + if (MainDataStore.familyCount < MainDataStore.familyWeightStableHigh) + { MainDataStore.familyWeightStableHigh = (uint)MainDataStore.familyCount; - } else { + } + else + { MainDataStore.familyWeightStableHigh = RealCityResidentAI.familyWeightStableHigh; } - if (MainDataStore.familyCount < MainDataStore.familyWeightStableLow) { + if (MainDataStore.familyCount < MainDataStore.familyWeightStableLow) + { MainDataStore.familyWeightStableLow = (uint)MainDataStore.familyCount; - } else { + } + else + { MainDataStore.familyWeightStableLow = RealCityResidentAI.familyWeightStableLow; } @@ -137,7 +166,8 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { RealCityResidentAI.preCitizenId = homeID; RealCityResidentAI.familyCount++; - if (homeID > 524288) { + if (homeID > 524288) + { DebugLog.LogToFileOnly("Error: citizen ID greater than 524288"); } @@ -153,7 +183,8 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen3, false); familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen4, false); RealCityResidentAI.citizenSalaryCount = RealCityResidentAI.citizenSalaryCount + familySalaryCurrent; - if (familySalaryCurrent < 0) { + if (familySalaryCurrent < 0) + { DebugLog.LogToFileOnly("familySalaryCurrent< 0 in ResidentAI"); familySalaryCurrent = 0; } @@ -171,27 +202,32 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { CitizenManager instance = Singleton.instance; int tempEducationFee; int tempHospitalFee; - if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) { + if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) + { GetExpenseRate(data.m_citizen4, out expenseRate, out tempEducationFee, out tempHospitalFee); educationFee += tempEducationFee; hospitalFee += tempHospitalFee; } - if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) { + if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) + { GetExpenseRate(data.m_citizen3, out expenseRate, out tempEducationFee, out tempHospitalFee); educationFee += tempEducationFee; hospitalFee += tempHospitalFee; } - if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) { + if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) + { GetExpenseRate(data.m_citizen2, out expenseRate, out tempEducationFee, out tempHospitalFee); educationFee += tempEducationFee; hospitalFee += tempHospitalFee; } - if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) { + if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) + { GetExpenseRate(data.m_citizen1, out expenseRate, out tempEducationFee, out tempHospitalFee); educationFee += tempEducationFee; hospitalFee += tempHospitalFee; } - if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) { + if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) + { GetExpenseRate(data.m_citizen0, out expenseRate, out tempEducationFee, out tempHospitalFee); educationFee += tempEducationFee; hospitalFee += tempHospitalFee; @@ -206,22 +242,28 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { CitizenUnitData.familyMoney[homeID] += incomeMinusExpense; //5. Limit familyMoney - if (CitizenUnitData.familyMoney[homeID] > 100000000f) { + if (CitizenUnitData.familyMoney[homeID] > 100000000f) + { CitizenUnitData.familyMoney[homeID] = 100000000f; } - if (CitizenUnitData.familyMoney[homeID] < -100000000f) { + if (CitizenUnitData.familyMoney[homeID] < -100000000f) + { CitizenUnitData.familyMoney[homeID] = -100000000f; } //6. Caculate minimumLivingAllowance and benefitOffset - if (CitizenUnitData.familyMoney[homeID] < (-(Politics.benefitOffset * MainDataStore.govermentSalary) / 100f)) { + if (CitizenUnitData.familyMoney[homeID] < (-(Politics.benefitOffset * MainDataStore.govermentSalary) / 100f)) + { int num = (int)(-CitizenUnitData.familyMoney[homeID]); CitizenUnitData.familyMoney[homeID] += num; MainDataStore.minimumLivingAllowance += num; Singleton.instance.FetchResource((EconomyManager.Resource)17, num, ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1); - } else { - if (Politics.benefitOffset > 0) { + } + else + { + if (Politics.benefitOffset > 0) + { CitizenUnitData.familyMoney[homeID] += ((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f); MainDataStore.minimumLivingAllowance += (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f); Singleton.instance.FetchResource((EconomyManager.Resource)17, (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f), ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1); @@ -232,11 +274,16 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { var familySalaryCurrentTmp = (familySalaryCurrent > canBuyGoodMoney) ? canBuyGoodMoney : familySalaryCurrent; //7. Process citizen status - if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 30) { + if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 30) + { RealCityResidentAI.level3HighWealth++; - } else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 20) { + } + else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 20) + { RealCityResidentAI.level2HighWealth++; - } else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 10) { + } + else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 10) + { RealCityResidentAI.level1HighWealth++; } @@ -251,31 +298,38 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f); //9 Buy good from outside and try move family - if (data.m_goods == 0) { - if ((CitizenUnitData.familyMoney[homeID] > canBuyGoodMoney) && (familySalaryCurrent > 1)) { + if (data.m_goods == 0) + { + if ((CitizenUnitData.familyMoney[homeID] > canBuyGoodMoney) && (familySalaryCurrent > 1)) + { uint citizenID = 0u; int familySize = 0; - if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) { + if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead) + { familySize++; citizenID = data.m_citizen4; instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; } - if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) { + if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead) + { familySize++; citizenID = data.m_citizen3; instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; } - if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) { + if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead) + { familySize++; citizenID = data.m_citizen2; instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; } - if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) { + if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead) + { familySize++; citizenID = data.m_citizen1; instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; } - if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) { + if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead) + { familySize++; citizenID = data.m_citizen0; instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods; @@ -296,22 +350,26 @@ public static void ProcessFamily(uint homeID, ref CitizenUnit data) { } - public static void ProcessCitizenIncomeTax(uint homeID, float tax) { + public static void ProcessCitizenIncomeTax(uint homeID, float tax) + { CitizenManager instance = Singleton.instance; ushort building = instance.m_units.m_buffer[(int)((UIntPtr)homeID)].m_building; Building buildingdata = Singleton.instance.m_buildings.m_buffer[building]; Singleton.instance.AddPrivateIncome((int)(tax), buildingdata.Info.m_class.m_service, buildingdata.Info.m_class.m_subService, buildingdata.Info.m_class.m_level, 112333); } - public static void ProcessCitizenHouseRent(uint homeID, int expenserate) { + public static void ProcessCitizenHouseRent(uint homeID, int expenserate) + { CitizenManager instance = Singleton.instance; ushort building = instance.m_units.m_buffer[(int)((UIntPtr)homeID)].m_building; Building buildingdata = Singleton.instance.m_buildings.m_buffer[building]; Singleton.instance.AddPrivateIncome(expenserate * 100, buildingdata.Info.m_class.m_service, buildingdata.Info.m_class.m_subService, buildingdata.Info.m_class.m_level, 100); } - public static void Prefix(uint homeID, ref CitizenUnit data) { - if (CitizenUnitData.familyGoods[homeID] == 65535) { + public static void Prefix(uint homeID, ref CitizenUnit data) + { + if (CitizenUnitData.familyGoods[homeID] == 65535) + { //first time if (data.m_goods < 6000) CitizenUnitData.familyGoods[homeID] = (ushort)(data.m_goods * 10); @@ -321,13 +379,16 @@ public static void Prefix(uint homeID, ref CitizenUnit data) { } // ResidentAI - public static void Postfix(uint homeID, ref CitizenUnit data) { - if ((Singleton.instance.m_buildings.m_buffer[data.m_building].m_flags & (Building.Flags.Completed | Building.Flags.Upgrading)) != Building.Flags.None) { + public static void Postfix(uint homeID, ref CitizenUnit data) + { + if ((Singleton.instance.m_buildings.m_buffer[data.m_building].m_flags & (Building.Flags.Completed | Building.Flags.Upgrading)) != Building.Flags.None) + { ProcessFamily(homeID, ref data); } } - public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, out int educationFee, out int hospitalFee) { + public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, out int educationFee, out int hospitalFee) + { BuildingManager instance1 = Singleton.instance; CitizenManager instance2 = Singleton.instance; var buildingID = Singleton.instance.m_citizens.m_buffer[citizenID].m_homeBuilding; @@ -335,14 +396,17 @@ public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, ou educationFee = 0; hospitalFee = 0; - if ((Singleton.instance.m_citizens.m_buffer[citizenID].m_flags & Citizen.Flags.Student) != Citizen.Flags.None) { + if ((Singleton.instance.m_citizens.m_buffer[citizenID].m_flags & Citizen.Flags.Student) != Citizen.Flags.None) + { //Only university will cost money bool isCampusDLC = false; //Campus DLC cost 50 ushort visitBuilding = Singleton.instance.m_citizens.m_buffer[citizenID].m_visitBuilding; - if (visitBuilding != 0u) { + if (visitBuilding != 0u) + { Building buildingData = Singleton.instance.m_buildings.m_buffer[visitBuilding]; - if (buildingData.Info.m_class.m_service == ItemClass.Service.PlayerEducation) { + if (buildingData.Info.m_class.m_service == ItemClass.Service.PlayerEducation) + { var tempEducationFee = (uint)((MainDataStore.govermentSalary) / 100f); if (tempEducationFee < 1) tempEducationFee = 1; @@ -352,26 +416,36 @@ public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, ou } } - if (!isCampusDLC) { - if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education2)) { + if (!isCampusDLC) + { + if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education2)) + { educationFee = MainDataStore.govermentSalary >> 1; Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level3, 115333); - } else if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education1)) { + } + else if (Singleton.instance.m_citizens.m_buffer[citizenID].m_flags.IsFlagSet(Citizen.Flags.Education1)) + { educationFee = MainDataStore.govermentSalary >> 2; Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level2, 115333); - } else { + } + else + { educationFee = MainDataStore.govermentSalary >> 2; Singleton.instance.AddPrivateIncome(educationFee, ItemClass.Service.Education, ItemClass.SubService.None, ItemClass.Level.Level1, 115333); } } } - if (Singleton.instance.m_citizens.m_buffer[citizenID].Sick) { + if (Singleton.instance.m_citizens.m_buffer[citizenID].Sick) + { ushort visitBuilding = Singleton.instance.m_citizens.m_buffer[citizenID].m_visitBuilding; - if (visitBuilding != 0u) { + if (visitBuilding != 0u) + { Building buildingData = Singleton.instance.m_buildings.m_buffer[visitBuilding]; - if (visitBuilding != Singleton.instance.m_citizens.m_buffer[citizenID].m_workBuilding) { - if (buildingData.Info.m_class.m_service == ItemClass.Service.HealthCare) { + if (visitBuilding != Singleton.instance.m_citizens.m_buffer[citizenID].m_workBuilding) + { + if (buildingData.Info.m_class.m_service == ItemClass.Service.HealthCare) + { hospitalFee = MainDataStore.govermentSalary >> 1; Singleton.instance.AddPrivateIncome(hospitalFee, ItemClass.Service.HealthCare, ItemClass.SubService.None, ItemClass.Level.Level2, 115333); } @@ -381,10 +455,12 @@ public static void GetExpenseRate(uint citizenID, out int incomeAccumulation, ou } [Obsolete("It's calculated in ElectionVoter. If wants to vote, call ElectionVoter.VoteTicket() instead.")] - public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { + public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) + { //如果即将选举,而且达到投票年龄 if (gonna be election) and (over Voting Age) if (Politics.IsOnElection() - && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age))) { + && Politics.IsOverVotingAge(Citizen.GetAgeGroup(citizen.m_age))) + { ////重置机率 Politics.cPartyChance = 0; @@ -403,17 +479,24 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { int choiceIndex = 14; //根据工作地点决定投票策略 - if (RealCityResidentAI.IsGoverment(citizen.m_workBuilding)) { + if (RealCityResidentAI.IsGoverment(citizen.m_workBuilding)) + { choiceIndex = 0; } - switch (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_subService) { + switch (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_subService) + { case ItemClass.SubService.CommercialLow: case ItemClass.SubService.CommercialHigh: - if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) + { choiceIndex = 1; - } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) + { choiceIndex = 2; - } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) + { choiceIndex = 3; } break; @@ -423,11 +506,16 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { case ItemClass.SubService.CommercialEco: choiceIndex = 5; break; case ItemClass.SubService.IndustrialGeneric: - if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) + { choiceIndex = 6; - } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) + { choiceIndex = 7; - } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) + { choiceIndex = 8; } break; @@ -437,18 +525,24 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { case ItemClass.SubService.IndustrialOre: choiceIndex = 9; break; case ItemClass.SubService.OfficeGeneric: - if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) { + if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level1) + { choiceIndex = 10; - } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) { + } + else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level2) + { choiceIndex = 11; - } else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) { + } + else if (Singleton.instance.m_buildings.m_buffer[citizen.m_workBuilding].Info.m_class.m_level == ItemClass.Level.Level3) + { choiceIndex = 12; } break; case ItemClass.SubService.OfficeHightech: choiceIndex = 13; break; } - if (choiceIndex < 0 || choiceIndex > 14) { + if (choiceIndex < 0 || choiceIndex > 14) + { DebugLog.LogToFileOnly($"Error: GetVoteChance workplace idex {choiceIndex}"); } Politics.cPartyChance += (ushort)(Politics.workplace[choiceIndex, 0] << 1); @@ -458,14 +552,20 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { Politics.nPartyChance += (ushort)(Politics.workplace[choiceIndex, 4] << 1); - if (CitizenUnitData.familyMoney[homeID] < 5000) { + if (CitizenUnitData.familyMoney[homeID] < 5000) + { choiceIndex = 0; - } else if (CitizenUnitData.familyMoney[homeID] >= 20000) { + } + else if (CitizenUnitData.familyMoney[homeID] >= 20000) + { choiceIndex = 2; - } else { + } + else + { choiceIndex = 1; } - if (choiceIndex < 0 || choiceIndex > 3) { + if (choiceIndex < 0 || choiceIndex > 3) + { DebugLog.LogToFileOnly($"Error: GetVoteChance Invaid money idex = {choiceIndex}"); } Politics.cPartyChance += (ushort)(Politics.money[choiceIndex, 0] << 1); @@ -476,7 +576,8 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { int temp = (int)Citizen.GetAgeGroup(citizen.m_age) - 2; - if (temp < 0) { + if (temp < 0) + { DebugLog.LogToFileOnly($"Error: GetVoteChance temp = {temp} < 0, GetAgeGroup = {Citizen.GetAgeGroup(citizen.m_age)}"); } Politics.cPartyChance += Politics.age[temp, 0]; @@ -494,17 +595,28 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { Politics.nPartyChance += Politics.gender[temp, 4]; - if (RealCityEconomyExtension.partyTrend == 0) { + if (RealCityEconomyExtension.partyTrend == 0) + { Politics.cPartyChance += RealCityEconomyExtension.partyTrendStrength; - } else if (RealCityEconomyExtension.partyTrend == 1) { + } + else if (RealCityEconomyExtension.partyTrend == 1) + { Politics.gPartyChance += RealCityEconomyExtension.partyTrendStrength; - } else if (RealCityEconomyExtension.partyTrend == 2) { + } + else if (RealCityEconomyExtension.partyTrend == 2) + { Politics.sPartyChance += RealCityEconomyExtension.partyTrendStrength; - } else if (RealCityEconomyExtension.partyTrend == 3) { + } + else if (RealCityEconomyExtension.partyTrend == 3) + { Politics.lPartyChance += RealCityEconomyExtension.partyTrendStrength; - } else if (RealCityEconomyExtension.partyTrend == 4) { + } + else if (RealCityEconomyExtension.partyTrend == 4) + { Politics.nPartyChance += RealCityEconomyExtension.partyTrendStrength; - } else { + } + else + { DebugLog.LogToFileOnly($"Error: GetVoteChance Invalid partyTrend = {RealCityEconomyExtension.partyTrend}"); } GetVoteTickets(); @@ -512,28 +624,40 @@ public static void GetVoteChance(uint citizenID, Citizen citizen, uint homeID) { } [Obsolete("Call ElectionVoter.VoteTicket() instead.")] - public static void GetVoteTickets() { + public static void GetVoteTickets() + { System.Random rand = new System.Random(); //魔数800参见PartyInterestCalc.GetFromEducationLevel()中的注释 if (Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance - != (800 + RealCityEconomyExtension.partyTrendStrength)) { + != (800 + RealCityEconomyExtension.partyTrendStrength)) + { //有1/64的机率打印这句话(WTF?) - if (rand.Next(64) <= 1) { + if (rand.Next(64) <= 1) + { DebugLog.LogToFileOnly($"Error: GetVoteTickets Chance is not equal 800 {(Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance + Politics.nPartyChance)}"); } } //大转盘,政党的chance越大,得票机率就越大 int voteRandom = rand.Next(800 + RealCityEconomyExtension.partyTrendStrength) + 1; - if (voteRandom < Politics.cPartyChance) { + if (voteRandom < Politics.cPartyChance) + { Politics.cPartyTickets++; - } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance) { + } + else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance) + { Politics.gPartyTickets++; - } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) { + } + else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance) + { Politics.sPartyTickets++; - } else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) { + } + else if (voteRandom < Politics.cPartyChance + Politics.gPartyChance + Politics.sPartyChance + Politics.lPartyChance) + { Politics.lPartyTickets++; - } else { + } + else + { Politics.nPartyTickets++; } } diff --git a/Patch/ResidentAIGetCarProbabilityPatch.cs b/Patch/ResidentAIGetCarProbabilityPatch.cs index ea62ba1..faca4d0 100644 --- a/Patch/ResidentAIGetCarProbabilityPatch.cs +++ b/Patch/ResidentAIGetCarProbabilityPatch.cs @@ -10,22 +10,29 @@ namespace RealCity.Patch [HarmonyPatch] public class ResidentAIGetCarProbabilityPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(ResidentAI).GetMethod("GetCarProbability", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(CitizenInstance).MakeByRefType(), typeof(Citizen.AgeGroup) }, null); } [HarmonyPriority(Priority.First)] - public static void Prefix(ref CitizenInstance citizenData, ref Citizen.AgeGroup ageGroup) { - if (RealCity.noPassengerCar) { + public static void Prefix(ref CitizenInstance citizenData, ref Citizen.AgeGroup ageGroup) + { + if (RealCity.noPassengerCar) + { CitizenManager instance = Singleton.instance; var citizenID = citizenData.m_citizen; ushort homeBuilding = instance.m_citizens.m_buffer[citizenID].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[citizenID].GetContainingUnit((uint)citizenID, citizenUnit, CitizenUnit.Flags.Home); - if ((containingUnit == 0) || (citizenID == 0)) { + if ((containingUnit == 0) || (citizenID == 0)) + { //Change ageGroup to Child to disable car. ageGroup = Citizen.AgeGroup.Child; - } else { - if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.highWealth) { + } + else + { + if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.highWealth) + { ageGroup = Citizen.AgeGroup.Child; } } diff --git a/Patch/TaxiAIUnloadPassengersPatch.cs b/Patch/TaxiAIUnloadPassengersPatch.cs index 0af133a..9e897fe 100644 --- a/Patch/TaxiAIUnloadPassengersPatch.cs +++ b/Patch/TaxiAIUnloadPassengersPatch.cs @@ -11,30 +11,41 @@ namespace RealCity.Patch [HarmonyPatch] public class TaxiAIUnloadPassengersPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TaxiAI).GetMethod("UnloadPassengers", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType(), typeof(TransportPassengerData).MakeByRefType() }, null); } - public static void Prefix(ref TaxiAI __instance, ref Vehicle data) { + public static void Prefix(ref TaxiAI __instance, ref Vehicle data) + { CitizenManager instance = Singleton.instance; Vector3 lastFramePosition = data.GetLastFramePosition(); uint num2 = data.m_citizenUnits; int num3 = 0; - while (num2 != 0u) { + while (num2 != 0u) + { uint nextUnit = instance.m_units.m_buffer[(int)((UIntPtr)num2)].m_nextUnit; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { uint citizen = instance.m_units.m_buffer[(int)((UIntPtr)num2)].GetCitizen(i); - if (citizen != 0u) { + if (citizen != 0u) + { ushort instance2 = instance.m_citizens.m_buffer[(int)((UIntPtr)citizen)].m_instance; - if (instance2 != 0) { + if (instance2 != 0) + { Vector3 lastFramePosition2 = instance.m_instances.m_buffer[instance2].GetLastFramePosition(); int expense = Mathf.RoundToInt(__instance.m_transportInfo.m_ticketPrice * Vector3.Distance(lastFramePosition2, lastFramePosition) * 0.001f); //new added begin - if (expense != 0) { + if (expense != 0) + { //DebugLog.LogToFileOnly("UnloadPassengers ticketPrice pre = " + num4.ToString()); - if ((Singleton.instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) == Citizen.Flags.None) { + if ((Singleton.instance.m_citizens.m_buffer[citizen].m_flags & Citizen.Flags.Tourist) == Citizen.Flags.None) + { CitizenData.citizenMoney[citizen] -= (expense); - } else { - if (CitizenData.citizenMoney[citizen] < expense) { + } + else + { + if (CitizenData.citizenMoney[citizen] < expense) + { expense = (CitizenData.citizenMoney[citizen] > 0) ? (int)CitizenData.citizenMoney[citizen] + 1 : 1; CitizenData.citizenMoney[citizen] = (CitizenData.citizenMoney[citizen] - (expense) - 1); MainDataStore.outsideTouristMoney -= (expense + 1); @@ -47,7 +58,8 @@ public static void Prefix(ref TaxiAI __instance, ref Vehicle data) { } } num2 = nextUnit; - if (++num3 > 524288) { + if (++num3 > 524288) + { CODebugBase.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } diff --git a/Patch/TollBoothAIGetResourceRatePatch.cs b/Patch/TollBoothAIGetResourceRatePatch.cs index 2931443..97bd116 100644 --- a/Patch/TollBoothAIGetResourceRatePatch.cs +++ b/Patch/TollBoothAIGetResourceRatePatch.cs @@ -10,11 +10,14 @@ namespace RealCity.Patch [HarmonyPatch] public class TollBoothAIGetResourceRatePatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TollBoothAI).GetMethod("GetResourceRate", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(EconomyManager.Resource) }, null); } - public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) { - if (resource == EconomyManager.Resource.Maintenance) { + public static void Postfix(ushort buildingID, ref Building data, EconomyManager.Resource resource, ref int __result) + { + if (resource == EconomyManager.Resource.Maintenance) + { float salary = RealCityPlayerBuildingAI.CaculateEmployeeOutcome(buildingID, data); __result = (int)((float)__result / MainDataStore.gameExpenseDivide - salary * 100f); } diff --git a/Patch/TollBoothEnterBuildingSegmentPatch.cs b/Patch/TollBoothEnterBuildingSegmentPatch.cs index e4bce51..56fa21d 100644 --- a/Patch/TollBoothEnterBuildingSegmentPatch.cs +++ b/Patch/TollBoothEnterBuildingSegmentPatch.cs @@ -9,51 +9,67 @@ namespace RealCity.Patch [HarmonyPatch] public class TollBoothEnterBuildingSegmentPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TollBoothAI).GetMethod("EnterBuildingSegment", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(ushort), typeof(byte), typeof(InstanceID) }, null); } - public static bool Prefix(ref Building data, InstanceID itemID) { + public static bool Prefix(ref Building data, InstanceID itemID) + { bool canCharge = false; - if ((data.m_flags & Building.Flags.Active) != Building.Flags.None) { + if ((data.m_flags & Building.Flags.Active) != Building.Flags.None) + { ushort vehicle = itemID.Vehicle; - if (vehicle != 0) { + if (vehicle != 0) + { VehicleManager instance = Singleton.instance; Vehicle vehicleData = instance.m_vehicles.m_buffer[vehicle]; VehicleInfo info = instance.m_vehicles.m_buffer[vehicle].Info; - if (vehicleData.m_transferType != 212 && vehicleData.m_transferType != 213) { - if (!VehicleData.isVehicleCharged[vehicle]) { - if (info.m_vehicleAI is CargoTruckAI && (instance.m_vehicles.m_buffer[vehicle].m_flags.IsFlagSet(Vehicle.Flags.DummyTraffic))) { + if (vehicleData.m_transferType != 212 && vehicleData.m_transferType != 213) + { + if (!VehicleData.isVehicleCharged[vehicle]) + { + if (info.m_vehicleAI is CargoTruckAI && (instance.m_vehicles.m_buffer[vehicle].m_flags.IsFlagSet(Vehicle.Flags.DummyTraffic))) + { canCharge = true; VehicleData.isVehicleCharged[vehicle] = true; - } else if (info.m_vehicleAI is PassengerCarAI) { + } + else if (info.m_vehicleAI is PassengerCarAI) + { bool isTourist = false; bool isDummy = false; - if (instance.m_vehicles.m_buffer[vehicle].m_citizenUnits != 0) { + if (instance.m_vehicles.m_buffer[vehicle].m_citizenUnits != 0) + { CitizenManager instance2 = Singleton.instance; - if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen0 != 0) { + if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen0 != 0) + { isTourist = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen0].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None); isDummy = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen0].m_flags & Citizen.Flags.DummyTraffic) != Citizen.Flags.None); } - if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen1 != 0) { + if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen1 != 0) + { isTourist = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen1].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None); isDummy = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen1].m_flags & Citizen.Flags.DummyTraffic) != Citizen.Flags.None); } - if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen2 != 0) { + if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen2 != 0) + { isTourist = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen2].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None); isDummy = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen2].m_flags & Citizen.Flags.DummyTraffic) != Citizen.Flags.None); } - if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen3 != 0) { + if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen3 != 0) + { isTourist = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen3].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None); isDummy = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen3].m_flags & Citizen.Flags.DummyTraffic) != Citizen.Flags.None); } - if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen4 != 0) { + if (instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen4 != 0) + { isTourist = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen4].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None); isDummy = ((instance2.m_citizens.m_buffer[instance2.m_units.m_buffer[instance.m_vehicles.m_buffer[vehicle].m_citizenUnits].m_citizen4].m_flags & Citizen.Flags.DummyTraffic) != Citizen.Flags.None); } } - if (isDummy || isTourist) { + if (isDummy || isTourist) + { VehicleData.isVehicleCharged[vehicle] = true; canCharge = true; } diff --git a/Patch/TouristAISimulationStepPatch.cs b/Patch/TouristAISimulationStepPatch.cs index b30bee4..abc22d8 100644 --- a/Patch/TouristAISimulationStepPatch.cs +++ b/Patch/TouristAISimulationStepPatch.cs @@ -11,19 +11,25 @@ namespace RealCity.Patch public class TouristAISimulationStepPatch { public static ushort touristCount; - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TouristAI).GetMethod("SimulationStep", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint), typeof(Citizen).MakeByRefType() }, null); } - public static void Postfix(uint citizenID, ref Citizen data) { - if (!data.m_flags.IsFlagSet(Citizen.Flags.DummyTraffic)) { - if (CitizenData.citizenMoney[citizenID] < 100) { + public static void Postfix(uint citizenID, ref Citizen data) + { + if (!data.m_flags.IsFlagSet(Citizen.Flags.DummyTraffic)) + { + if (CitizenData.citizenMoney[citizenID] < 100) + { FindVisitPlace(citizenID, data.m_visitBuilding, GetLeavingReason(ref data)); } } } - public static TransferManager.TransferReason GetLeavingReason(ref Citizen data) { - switch (data.WealthLevel) { + public static TransferManager.TransferReason GetLeavingReason(ref Citizen data) + { + switch (data.WealthLevel) + { case Citizen.Wealth.Low: return TransferManager.TransferReason.LeaveCity0; case Citizen.Wealth.Medium: @@ -35,7 +41,8 @@ public static TransferManager.TransferReason GetLeavingReason(ref Citizen data) } } - public static void FindVisitPlace(uint citizenID, ushort sourceBuilding, TransferManager.TransferReason reason) { + public static void FindVisitPlace(uint citizenID, ushort sourceBuilding, TransferManager.TransferReason reason) + { TransferManager.TransferOffer offer = default; offer.Priority = Singleton.instance.m_randomizer.Int32(7u); offer.Citizen = citizenID; diff --git a/Patch/TransferManagerAddIncomingOfferPatch.cs b/Patch/TransferManagerAddIncomingOfferPatch.cs index 13bf66e..39ea20e 100644 --- a/Patch/TransferManagerAddIncomingOfferPatch.cs +++ b/Patch/TransferManagerAddIncomingOfferPatch.cs @@ -13,13 +13,16 @@ namespace RealCity.Patch [HarmonyPatch] public class TransferManagerAddIncomingOfferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TransferManager).GetMethod("AddIncomingOffer", BindingFlags.Public | BindingFlags.Instance); } [HarmonyPriority(Priority.First)] - public static bool Prefix(TransferManager.TransferReason material, ref TransferManager.TransferOffer offer) { - switch (material) { + public static bool Prefix(TransferManager.TransferReason material, ref TransferManager.TransferOffer offer) + { + switch (material) + { case TransferManager.TransferReason.Shopping: case TransferManager.TransferReason.ShoppingB: case TransferManager.TransferReason.ShoppingC: @@ -36,8 +39,10 @@ public static bool Prefix(TransferManager.TransferReason material, ref TransferM case TransferManager.TransferReason.TouristB: case TransferManager.TransferReason.TouristC: case TransferManager.TransferReason.TouristD: - if (RealCity.realCityV10) { - if (MainDataStore.outsideTouristMoney < 0) { + if (RealCity.realCityV10) + { + if (MainDataStore.outsideTouristMoney < 0) + { if (Singleton.instance.m_buildings.m_buffer[offer.Building].Info.m_buildingAI is OutsideConnectionAI) return false; } @@ -66,23 +71,29 @@ public static bool Prefix(TransferManager.TransferReason material, ref TransferM return true; } - if (offer.Citizen != 0) { + if (offer.Citizen != 0) + { var instance = Singleton.instance; ushort homeBuilding = instance.m_citizens.m_buffer[offer.Citizen].m_homeBuilding; uint citizenUnit = CitizenData.GetCitizenUnit(homeBuilding); uint containingUnit = instance.m_citizens.m_buffer[offer.Citizen].GetContainingUnit((uint)offer.Citizen, citizenUnit, CitizenUnit.Flags.Home); - if (!instance.m_citizens.m_buffer[offer.Citizen].m_flags.IsFlagSet(Citizen.Flags.Tourist)) { - if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)) { + if (!instance.m_citizens.m_buffer[offer.Citizen].m_flags.IsFlagSet(Citizen.Flags.Tourist)) + { + if (CitizenUnitData.familyMoney[containingUnit] < MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping)) + { //Reject poor citizen to building return false; } } - } else if (offer.Building != 0) { + } + else if (offer.Building != 0) + { var instance = Singleton.instance; var buildingID = offer.Building; var buildingData = instance.m_buildings.m_buffer[buildingID]; - if (buildingData.Info.m_class.m_service == ItemClass.Service.Industrial) { + if (buildingData.Info.m_class.m_service == ItemClass.Service.Industrial) + { RealCityIndustrialBuildingAI.InitDelegate(); RealCityCommonBuildingAI.InitDelegate(); var industrialBuildingAI = buildingData.Info.m_buildingAI as IndustrialBuildingAI; @@ -93,10 +104,14 @@ public static bool Prefix(TransferManager.TransferReason material, ref TransferM int num1 = 0; int incomingCargoCapacity = 0; int value = 0; - if (incomingTransferReason != TransferManager.TransferReason.None) { - if (secondaryIncomingTransferReason != TransferManager.TransferReason.None) { + if (incomingTransferReason != TransferManager.TransferReason.None) + { + if (secondaryIncomingTransferReason != TransferManager.TransferReason.None) + { RealCityCommonBuildingAI.CalculateGuestVehicles1((IndustrialBuildingAI)(buildingData.Info.m_buildingAI), buildingID, ref buildingData, incomingTransferReason, secondaryIncomingTransferReason, ref num, ref num1, ref incomingCargoCapacity, ref value); - } else { + } + else + { RealCityCommonBuildingAI.CalculateGuestVehicles((IndustrialBuildingAI)(buildingData.Info.m_buildingAI), buildingID, ref buildingData, incomingTransferReason, ref num, ref num1, ref incomingCargoCapacity, ref value); } } @@ -106,10 +121,14 @@ public static bool Prefix(TransferManager.TransferReason material, ref TransferM int incomingAmontNeeded = fullCapacity - (int)buildingData.m_customBuffer1 - incomingCargoCapacity; incomingAmontNeeded -= 8000; - if (incomingAmontNeeded < 0) { + if (incomingAmontNeeded < 0) + { return false; - } else { - if (material == incomingTransferReason) { + } + else + { + if (material == incomingTransferReason) + { //first remove. //game bug, will send 2 incomingTransferReason per period TransferManager.TransferOffer offer1 = default; @@ -117,7 +136,9 @@ public static bool Prefix(TransferManager.TransferReason material, ref TransferM Singleton.instance.RemoveIncomingOffer(incomingTransferReason, offer1); } } - } else if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) { + } + else if (buildingData.Info.m_class.m_service == ItemClass.Service.Commercial) + { RealCityCommercialBuildingAI.InitDelegate(); RealCityCommonBuildingAI.InitDelegate(); var commercialBuildingAI = buildingData.Info.m_buildingAI as CommercialBuildingAI; @@ -129,17 +150,22 @@ public static bool Prefix(TransferManager.TransferReason material, ref TransferM int incomingCargoCapacity = 0; int value = 0; TransferManager.TransferReason incomingTransferReason = RealCityCommercialBuildingAI.GetIncomingTransferReason((CommercialBuildingAI)(buildingData.Info.m_buildingAI)); - if (incomingTransferReason != TransferManager.TransferReason.None) { - if (incomingTransferReason == TransferManager.TransferReason.Goods || incomingTransferReason == TransferManager.TransferReason.Food) { + if (incomingTransferReason != TransferManager.TransferReason.None) + { + if (incomingTransferReason == TransferManager.TransferReason.Goods || incomingTransferReason == TransferManager.TransferReason.Food) + { RealCityCommonBuildingAI.CalculateGuestVehicles1((CommercialBuildingAI)(buildingData.Info.m_buildingAI), buildingID, ref buildingData, incomingTransferReason, TransferManager.TransferReason.LuxuryProducts, ref num, ref num1, ref incomingCargoCapacity, ref value); - } else { + } + else + { RealCityCommonBuildingAI.CalculateGuestVehicles((CommercialBuildingAI)(buildingData.Info.m_buildingAI), buildingID, ref buildingData, incomingTransferReason, ref num, ref num1, ref incomingCargoCapacity, ref value); } buildingData.m_tempImport = (byte)Mathf.Clamp(value, (int)buildingData.m_tempImport, 255); } int incomingAmontNeeded = fullCapacity - (int)buildingData.m_customBuffer1 - incomingCargoCapacity; incomingAmontNeeded -= 6000; - if (incomingAmontNeeded < 0) { + if (incomingAmontNeeded < 0) + { return false; } } diff --git a/Patch/TransferManagerAddOutgoingOfferPatch.cs b/Patch/TransferManagerAddOutgoingOfferPatch.cs index 4d9b497..6aa45bb 100644 --- a/Patch/TransferManagerAddOutgoingOfferPatch.cs +++ b/Patch/TransferManagerAddOutgoingOfferPatch.cs @@ -11,13 +11,16 @@ namespace RealCity.Patch [HarmonyPatch] public class TransferManagerAddOutgoingOfferPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TransferManager).GetMethod("AddOutgoingOffer", BindingFlags.Public | BindingFlags.Instance); } [HarmonyPriority(Priority.VeryHigh)] - public static bool Prefix(ref TransferManager.TransferReason material, ref TransferManager.TransferOffer offer) { - switch (material) { + public static bool Prefix(ref TransferManager.TransferReason material, ref TransferManager.TransferOffer offer) + { + switch (material) + { case TransferManager.TransferReason.Shopping: case TransferManager.TransferReason.ShoppingB: case TransferManager.TransferReason.ShoppingC: @@ -37,9 +40,11 @@ public static bool Prefix(ref TransferManager.TransferReason material, ref Trans var instance = Singleton.instance; var buildingID = offer.Building; - if (buildingID != 0) { + if (buildingID != 0) + { var buildingData = instance.m_buildings.m_buffer[buildingID]; - if (instance.m_buildings.m_buffer[buildingID].Info.m_class.m_service == ItemClass.Service.Commercial) { + if (instance.m_buildings.m_buffer[buildingID].Info.m_class.m_service == ItemClass.Service.Commercial) + { Citizen.BehaviourData behaviour = default; int aliveVisitCount = 0; int totalVisitCount = 0; @@ -49,15 +54,20 @@ public static bool Prefix(ref TransferManager.TransferReason material, ref Trans var maxCount = AI.CalculateVisitplaceCount((ItemClass.Level)buildingData.m_level, new Randomizer(buildingID), buildingData.m_width, buildingData.m_length); var amount = Math.Min(buildingData.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount, maxCount - totalVisitCount); - if ((amount <= 0) || (maxCount <= totalVisitCount)) { + if ((amount <= 0) || (maxCount <= totalVisitCount)) + { buildingData.m_flags &= ~Building.Flags.Active; //no resource return false; - } else { + } + else + { offer.Amount = amount; return true; } - } else if (instance.m_buildings.m_buffer[buildingID].Info.m_class.m_service == ItemClass.Service.Fishing) { + } + else if (instance.m_buildings.m_buffer[buildingID].Info.m_class.m_service == ItemClass.Service.Fishing) + { Citizen.BehaviourData behaviour = default; int aliveVisitCount = 0; int totalVisitCount = 0; @@ -65,24 +75,34 @@ public static bool Prefix(ref TransferManager.TransferReason material, ref Trans RealCityMarketAI.GetVisitBehaviour((MarketAI)(buildingData.Info.m_buildingAI), buildingID, ref buildingData, ref behaviour, ref aliveVisitCount, ref totalVisitCount); var amount = buildingData.m_customBuffer2 / MainDataStore.maxGoodPurchase - totalVisitCount + aliveVisitCount; - if (amount <= 0) { + if (amount <= 0) + { buildingData.m_flags &= ~Building.Flags.Active; //no resource return false; - } else { + } + else + { return true; } } } //Remove cotenancy - if (material == TransferManager.TransferReason.Single0 || material == TransferManager.TransferReason.Single0B) { + if (material == TransferManager.TransferReason.Single0 || material == TransferManager.TransferReason.Single0B) + { material = TransferManager.TransferReason.Family0; - } else if (material == TransferManager.TransferReason.Single1 || material == TransferManager.TransferReason.Single1B) { + } + else if (material == TransferManager.TransferReason.Single1 || material == TransferManager.TransferReason.Single1B) + { material = TransferManager.TransferReason.Family1; - } else if (material == TransferManager.TransferReason.Single2 || material == TransferManager.TransferReason.Single2B) { + } + else if (material == TransferManager.TransferReason.Single2 || material == TransferManager.TransferReason.Single2B) + { material = TransferManager.TransferReason.Family2; - } else if (material == TransferManager.TransferReason.Single3 || material == TransferManager.TransferReason.Single3B) { + } + else if (material == TransferManager.TransferReason.Single3 || material == TransferManager.TransferReason.Single3B) + { material = TransferManager.TransferReason.Family3; } return true; diff --git a/Patch/TransportLineCalculateTargetVehicleCountPatch.cs b/Patch/TransportLineCalculateTargetVehicleCountPatch.cs index 84a790c..fcb9383 100644 --- a/Patch/TransportLineCalculateTargetVehicleCountPatch.cs +++ b/Patch/TransportLineCalculateTargetVehicleCountPatch.cs @@ -10,129 +10,237 @@ namespace RealCity.Patch [HarmonyPatch] public class TransportLineCalculateTargetVehicleCountPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(TransportLine).GetMethod("CalculateTargetVehicleCount", BindingFlags.Public | BindingFlags.Instance); } - public static void Postfix(ref TransportLine __instance, ref int __result) { - if (Loader.isTransportLinesManagerRunning) { + public static void Postfix(ref TransportLine __instance, ref int __result) + { + if (Loader.isTransportLinesManagerRunning) + { return; } float budget = 1f; - if (IsWeekend(Singleton.instance.m_currentGameTime)) { - if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 1) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + if (IsWeekend(Singleton.instance.m_currentGameTime)) + { + if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 1) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = OptionUI.deepNightBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetWeekDay * 0.01f; } - } else if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 2) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + } + else if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 2) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = OptionUI.deepNightBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetWeekEnd * 0.01f; } - } else if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 3) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + } + else if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 3) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = OptionUI.deepNightBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetMax * 0.01f; } - } else if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 4) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + } + else if (TransportLineData.WeekEndPlan[FindLineID(ref __instance)] == 4) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetMin * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetMin * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetMin * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetMin * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = OptionUI.deepNightBudgetMin * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetMin * 0.01f; } } - } else { + } + else + { //PlanA - if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 1) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 1) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = OptionUI.deepNightBudgetWeekDay * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetWeekDay * 0.01f; } - } else if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 2) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + } + else if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 2) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetWeekEnd * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = (OptionUI.deepNightBudgetWeekEnd) * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetWeekEnd * 0.01f; } - } else if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 3) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + } + else if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 3) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = OptionUI.morningBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = OptionUI.otherBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = OptionUI.eveningBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = OptionUI.otherBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = OptionUI.deepNightBudgetMax * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = OptionUI.otherBudgetMax * 0.01f; } - } else if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 4) { - if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) { + } + else if (TransportLineData.WeekDayPlan[FindLineID(ref __instance)] == 4) + { + if (Singleton.instance.m_currentGameTime.Hour >= 8 && Singleton.instance.m_currentGameTime.Hour < 10) + { budget = (OptionUI.morningBudgetMin) * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 10 && Singleton.instance.m_currentGameTime.Hour < 17) + { budget = (OptionUI.otherBudgetMin) * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 17 && Singleton.instance.m_currentGameTime.Hour < 19) + { budget = (OptionUI.eveningBudgetMin) * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 19 && Singleton.instance.m_currentGameTime.Hour < 24) + { budget = (OptionUI.otherBudgetMin) * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 0 && Singleton.instance.m_currentGameTime.Hour < 4) + { budget = (OptionUI.deepNightBudgetMin) * 0.01f; - } else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) { + } + else if (Singleton.instance.m_currentGameTime.Hour >= 4 && Singleton.instance.m_currentGameTime.Hour < 8) + { budget = (OptionUI.otherBudgetMin) * 0.01f; } } @@ -143,19 +251,27 @@ public static void Postfix(ref TransportLine __instance, ref int __result) { __result = 1; } - public static bool IsWeekend(DateTime dateTime) { - if (dateTime.DayOfWeek != DayOfWeek.Saturday) { + public static bool IsWeekend(DateTime dateTime) + { + if (dateTime.DayOfWeek != DayOfWeek.Saturday) + { return dateTime.DayOfWeek == DayOfWeek.Sunday; } return true; } - public static ushort FindLineID(ref TransportLine transportLine) { - for (int i = 0; i < 256; i++) { - if (Singleton.instance.m_lines.m_buffer[i].m_flags.IsFlagSet(TransportLine.Flags.Created)) { - if (transportLine.m_lineNumber != 0) { - if (transportLine.Info.m_transportType == Singleton.instance.m_lines.m_buffer[i].Info.m_transportType) { - if (transportLine.m_lineNumber == Singleton.instance.m_lines.m_buffer[i].m_lineNumber) { + public static ushort FindLineID(ref TransportLine transportLine) + { + for (int i = 0; i < 256; i++) + { + if (Singleton.instance.m_lines.m_buffer[i].m_flags.IsFlagSet(TransportLine.Flags.Created)) + { + if (transportLine.m_lineNumber != 0) + { + if (transportLine.Info.m_transportType == Singleton.instance.m_lines.m_buffer[i].Info.m_transportType) + { + if (transportLine.m_lineNumber == Singleton.instance.m_lines.m_buffer[i].m_lineNumber) + { return (ushort)i; } } diff --git a/Patch/VehicleManagerReleaseVehicleImplementationPatch.cs b/Patch/VehicleManagerReleaseVehicleImplementationPatch.cs index aa0620c..ef4f7be 100644 --- a/Patch/VehicleManagerReleaseVehicleImplementationPatch.cs +++ b/Patch/VehicleManagerReleaseVehicleImplementationPatch.cs @@ -8,10 +8,12 @@ namespace RealCity.Patch [HarmonyPatch] public class VehicleManagerReleaseVehicleImplementationPatch { - public static MethodBase TargetMethod() { + public static MethodBase TargetMethod() + { return typeof(VehicleManager).GetMethod("ReleaseVehicleImplementation", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }, null); } - public static void Postfix(ushort vehicle) { + public static void Postfix(ushort vehicle) + { VehicleData.vehicleTransferTime[vehicle] = 0; VehicleData.isVehicleCharged[vehicle] = false; } diff --git a/RealCity.cs b/RealCity.cs index d32cd4b..a35c7a9 100644 --- a/RealCity.cs +++ b/RealCity.cs @@ -15,61 +15,76 @@ public class RealCity : IUserMod public static bool realCityV10 = true; public static bool noPassengerCar = true; - public string Name { + public string Name + { get { return "Real City"; } } - public string Description { + public string Description + { get { return "Make your city reality, Combine CS and SimCity in game playing"; } } - public void OnEnabled() { + public void OnEnabled() + { IsEnabled = true; FileStream fs = File.Create("RealCity.txt"); fs.Close(); HarmonyHelper.EnsureHarmonyInstalled(); - if (UIView.GetAView() != null) { + if (UIView.GetAView() != null) + { OnGameIntroLoaded(); - } else { + } + else + { LoadingManager.instance.m_introLoaded += OnGameIntroLoaded; } } - public void OnDisabled() { + public void OnDisabled() + { IsEnabled = false; LoadingManager.instance.m_introLoaded -= OnGameIntroLoaded; } - private static void OnGameIntroLoaded() { + private static void OnGameIntroLoaded() + { ModsCompatibilityChecker mcc = new ModsCompatibilityChecker(); mcc.PerformModCheck(); } - public void OnSettingsUI(UIHelperBase helper) { + public void OnSettingsUI(UIHelperBase helper) + { OptionUI.MakeSettings(helper); } - public static bool GetRealCityV10() { + public static bool GetRealCityV10() + { return realCityV10; } - public static int GetReduceCargoDiv() { + public static int GetReduceCargoDiv() + { return MainDataStore.reduceCargoDiv; } - public static float GetOutsideTouristMoney() { + public static float GetOutsideTouristMoney() + { return MainDataStore.outsideTouristMoney; } - public static void SetOutsideTouristMoney(float value) { + public static void SetOutsideTouristMoney(float value) + { MainDataStore.outsideTouristMoney = value; } - public static float GetOutsideGovermentMoney() { + public static float GetOutsideGovermentMoney() + { return MainDataStore.outsideGovermentMoney; } - public static void SetOutsideGovermentMoney(float value) { + public static void SetOutsideGovermentMoney(float value) + { MainDataStore.outsideGovermentMoney = value; } } diff --git a/RealCity.csproj b/RealCity.csproj index f46991e..807dbed 100644 --- a/RealCity.csproj +++ b/RealCity.csproj @@ -50,32 +50,32 @@ 7.3 - - ..\CitiesHarmony-master\libs\0Harmony.dll + + packages\Lib.Harmony.2.0.1\lib\net35\0Harmony.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll + F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp-firstpass.dll + F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp-firstpass.dll - - ..\..\..\..\SteamLibrary\steamapps\workshop\content\255710\1192503086\CitiesHarmony.API.dll + + packages\CitiesHarmony.API.1.0.5\lib\net35\CitiesHarmony.API.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll + F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll + >F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICSharpCode.SharpZipLib.dll + >F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICSharpCode.SharpZipLib.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Posix.dll + >F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Posix.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Security.dll + >F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Mono.Security.dll @@ -84,15 +84,14 @@ - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll + >F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll - ..\..\..\..\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.UI.dll + >F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.UI.dll - @@ -239,8 +238,17 @@ - - + rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086" +mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086" +copy "D:\Mod\RealCity\bin\Release\RealCity.dll" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\RealCity.dll" +copy "D:\Mod\RealCity\bin\Release\CitiesHarmony.API.dll" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\CitiesHarmony.API.dll" +rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Resources" +mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Resources" +copy "D:\Mod\RealCity\Resources\*.*" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Resources" +rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Icon" +mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Icon" +copy "D:\Mod\RealCity\Icon\*.png" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\Icon" +copy "D:\Mod\RealCity\PreviewImage.png" "F:\SteamLibrary\steamapps\workshop\content\255710\1192503086\PreviewImage.png"