From e310a9e9d9b476968af3049b04746c551fffd8c8 Mon Sep 17 00:00:00 2001 From: algernon-A Date: Sun, 27 Feb 2022 19:53:59 +1100 Subject: [PATCH] Enable live reset of schools to vanilla calcs. --- Code/Patches/StudentCount.cs | 2 +- Code/Patches/VanillaPopMethods.cs | 20 +++++++++++++++++ Code/VolumetricData/CalcPacks.cs | 29 ++++++++++++++++++++++++- Code/VolumetricData/PopData.cs | 8 +++++++ Code/VolumetricData/SchoolData.cs | 36 ++++++++++++++++++++++++++++++- 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/Code/Patches/StudentCount.cs b/Code/Patches/StudentCount.cs index 9b69d2a..1c5794d 100644 --- a/Code/Patches/StudentCount.cs +++ b/Code/Patches/StudentCount.cs @@ -22,7 +22,7 @@ public static bool Prefix(SchoolAI __instance, ref int __result) { // We are - set the result to our realistic population lookup. BuildingInfo thisInfo = __instance.m_info; - __result = (int)(PopData.instance.Population(thisInfo, (int)__instance.m_info.GetClassLevel(), Multipliers.instance.ActiveMultiplier(thisInfo))); + __result = PopData.instance.Students(thisInfo); // Don't continue on to original method. return false; diff --git a/Code/Patches/VanillaPopMethods.cs b/Code/Patches/VanillaPopMethods.cs index 529b928..4492ad8 100644 --- a/Code/Patches/VanillaPopMethods.cs +++ b/Code/Patches/VanillaPopMethods.cs @@ -182,5 +182,25 @@ public static void OfficeWorkplaceCount(object instance, ItemClass.Level level, Logging.Error(message, instance, level, r, width, length); throw new NotImplementedException(message); } + + + /// + /// Reverse patch for SchoolAI.StudentCount to access original game method without any Harmony patches (including ours). + /// + /// Object instance + /// Building level + /// Randomizer + /// Building lot width (in cells) + /// Building lot depth (in cells) + /// Harmony reverse patch wasn't applied + [HarmonyReversePatch] + [HarmonyPatch((typeof(SchoolAI)), nameof(SchoolAI.StudentCount), MethodType.Getter)] + [MethodImpl(MethodImplOptions.NoInlining)] + public static int StudentCount(object instance) + { + string message = "SchoolAI.StudentCount reverse Harmony patch wasn't applied"; + Logging.Error(message, instance); + throw new NotImplementedException(message); + } } } \ No newline at end of file diff --git a/Code/VolumetricData/CalcPacks.cs b/Code/VolumetricData/CalcPacks.cs index 64f8950..11f660c 100644 --- a/Code/VolumetricData/CalcPacks.cs +++ b/Code/VolumetricData/CalcPacks.cs @@ -82,11 +82,19 @@ public class PopDataPack : DataPack /// Building level /// Workplace breakdowns and visitor count public virtual WorkplaceLevels Workplaces(BuildingInfo buildingPrefab, int level) => new WorkplaceLevels { level0 = 1, level1 = 0, level2 = 0, level3 = 0}; + + + /// + /// Returns the student count for the given building prefab and level. + /// + /// Building prefab record + /// Student count (0 if not a school building) + public virtual int Students(BuildingInfo buildingPrefab) => buildingPrefab.m_buildingAI is SchoolAI ? Population(buildingPrefab, (int)buildingPrefab.m_class.m_level, Multipliers.instance.ActiveMultiplier(buildingPrefab)) : 0; } /// - /// Population clculation data pack - provides parameters for calculating building populations. + /// Population calculation data pack - provides parameters for calculating building populations. /// public class SchoolDataPack : DataPack { @@ -308,5 +316,24 @@ public override WorkplaceLevels Workplaces(BuildingInfo buildingPrefab, int leve level3 = (ushort)workLevel3 }; } + + + /// + /// Returns the vanilla student count for the given building prefab and level. + /// + /// Building prefab record + /// Workplace breakdown + public override int Students(BuildingInfo buildingPrefab) + { + // Set m_studentCount to original value. + if (buildingPrefab.m_buildingAI is SchoolAI schoolAI) + { + schoolAI.m_studentCount = SchoolData.instance.OriginalStudentCount(buildingPrefab); + return VanillaPopMethods.StudentCount(schoolAI); + } + + // If we got here, no valid vanilla settings were found; return 0. + return 0; + } } } \ No newline at end of file diff --git a/Code/VolumetricData/PopData.cs b/Code/VolumetricData/PopData.cs index 53836de..e8a2c1d 100644 --- a/Code/VolumetricData/PopData.cs +++ b/Code/VolumetricData/PopData.cs @@ -30,6 +30,14 @@ internal class PopData : CalcData internal WorkplaceLevels Workplaces(BuildingInfo buildingPrefab, int level) => ((PopDataPack)ActivePack(buildingPrefab)).Workplaces(buildingPrefab, level); + /// + /// Returns the student count for the given building prefab. + /// + /// Building prefab + /// Student count + internal int Students(BuildingInfo buildingPrefab) => ((PopDataPack)ActivePack(buildingPrefab)).Students(buildingPrefab); + + /// /// Adds or updates cached housholds for the specified building prefab and level. /// diff --git a/Code/VolumetricData/SchoolData.cs b/Code/VolumetricData/SchoolData.cs index 2aba564..fcf83b0 100644 --- a/Code/VolumetricData/SchoolData.cs +++ b/Code/VolumetricData/SchoolData.cs @@ -11,6 +11,7 @@ namespace RealPop2 /// public class OriginalSchoolStats { + public int students; public int jobs0, jobs1, jobs2, jobs3; public int cost, maintenance; } @@ -103,6 +104,30 @@ public SchoolData() } + /// + /// Returns the original student count for the given school prefab. + /// + /// Building prefab + /// Original student count, if available (300 if no record available) + internal int OriginalStudentCount(BuildingInfo prefab) + { + if (originalStats == null) + { + if (prefab.m_buildingAI is SchoolAI schoolAI) + { + return schoolAI.m_studentCount; + } + } + else if (originalStats.ContainsKey(prefab.name)) + { + return originalStats[prefab.name].students; + } + + // If we got here, no record was found; return 300 (vanilla elementary). + return 300; + } + + /// /// Updates our building setting dictionary for the selected building prefab to the indicated calculation pack. /// IMPORTANT: make sure student count is called before calling this. @@ -255,6 +280,7 @@ internal void OnLoad() // Found a school; add it to our dictionary. originalStats.Add(building.name, new OriginalSchoolStats { + students = schoolAI.m_studentCount, jobs0 = schoolAI.m_workPlaceCount0, jobs1 = schoolAI.m_workPlaceCount1, jobs2 = schoolAI.m_workPlaceCount2, @@ -263,6 +289,8 @@ internal void OnLoad() maintenance = schoolAI.m_maintenanceCost }); + Logging.KeyMessage("found school prefab ", building.name, " with student count ", schoolAI.m_studentCount); + // If setting is set, get currently active pack and apply it. if (ModSettings.enableSchoolProperties) { @@ -305,6 +333,7 @@ internal void UpdateSchools() if (thisInfo?.m_buildingAI is SchoolAI schoolAI && thisInfo.m_class.m_level <= ItemClass.Level.Level2) { // Found a school - set local references for passing to SimulationManager. + Logging.KeyMessage("updating school building ", i, ": ", thisInfo.name, " to student count of ", schoolAI.StudentCount); SchoolAI thisAI = schoolAI; ushort buildingID = (ushort)i; @@ -406,7 +435,7 @@ private void ApplyPack(BuildingInfo prefab, SchoolDataPack schoolPack) schoolAI.m_constructionCost = CalcCost(schoolPack, schoolAI.StudentCount); schoolAI.m_maintenanceCost = CalcMaint(schoolPack, schoolAI.StudentCount); - // Force update of m_studentCount. + // Update prefab population record. schoolAI.m_studentCount = schoolAI.StudentCount; // Update prefab and tooltip. @@ -435,9 +464,14 @@ private void UpdateSchoolPrefab(BuildingInfo prefab, SchoolAI schoolAI) return; } + Logging.KeyMessage("updating school prefab ", prefab.name, " with studentCount ", schoolAI.m_studentCount); + Logging.KeyMessage("applying calculation pack ", PopData.instance.ActivePack(prefab).DisplayName, " with multiplier ", Multipliers.instance.ActiveMultiplier(prefab)); + // Update prefab population record. schoolAI.m_studentCount = schoolAI.StudentCount; + Logging.KeyMessage("new student count is ", schoolAI.m_studentCount); + // Update tooltip. UpdateSchoolTooltip(prefab); }