/// <summary> /// Updates household counts for all buildings in scene with the given prefab name. /// Can also remove all housholds, setting the total to zero. /// </summary> /// <param name="prefabName">Prefab name</param> /// <param name="removeAll">If true, all households will be removed (count set to 0)</param> private void UpdateHouseholds(string prefabName, int level = 0, bool removeAll = false) { int homeCount = 0; int visitCount = 0; int homeCountChanged = 0; // Get building manager instance. var instance = Singleton <BuildingManager> .instance; // Iterate through each building in the scene. for (ushort i = 0; i < instance.m_buildings.m_buffer.Length; i++) { // Check for matching name. if (instance.m_buildings.m_buffer[i].Info != null && instance.m_buildings.m_buffer[i].Info.name != null && instance.m_buildings.m_buffer[i].Info.name.Equals(prefabName)) { // Got a match! Check level if applicable. if (level > 0) { // m_level is one less than building.level. byte newLevel = (byte)(level - 1); if (instance.m_buildings.m_buffer[i].m_level != newLevel) { Debugging.Message("found building '" + prefabName + "' with level " + (instance.m_buildings.m_buffer[i].m_level + 1) + ", overriding to level " + level); instance.m_buildings.m_buffer[i].m_level = newLevel; } } // Update homecounts for any residential buildings. PrivateBuildingAI thisAI = instance.m_buildings.m_buffer[i].Info.GetAI() as ResidentialBuildingAI; if (thisAI != null) { // This is residential! If we're not removing all households, recalculate home and visit counts using AI method. if (!removeAll) { homeCount = thisAI.CalculateHomeCount((ItemClass.Level)instance.m_buildings.m_buffer[i].m_level, new Randomizer(i), instance.m_buildings.m_buffer[i].Width, instance.m_buildings.m_buffer[i].Length); visitCount = thisAI.CalculateVisitplaceCount((ItemClass.Level)instance.m_buildings.m_buffer[i].m_level, new Randomizer(i), instance.m_buildings.m_buffer[i].Width, instance.m_buildings.m_buffer[i].Length); } // Apply changes via direct call to EnsureCitizenUnits prefix patch from this mod and increment counter. RealisticCitizenUnits.EnsureCitizenUnits(ref thisAI, i, ref instance.m_buildings.m_buffer[i], homeCount, 0, visitCount, 0); homeCountChanged++; } // Clear any problems. instance.m_buildings.m_buffer[i].m_problems = 0; } } Debugging.Message("set household counts to " + homeCount + " for " + homeCountChanged + " '" + prefabName + "' buildings"); }
/// <summary> /// Prefix to force settings reset on load (if enabled) for RICO buildings (resetting to current settings). /// </summary> /// <param name="__instance">Original object instance reference</param> /// <param name="buildingID">Building instance ID</param> /// <param name="data">Building data</param> /// <param name="version">Version</param> private static bool Prefix(PrivateBuildingAI __instance, ushort buildingID, ref Building data, uint version) { // Don't do anything if the flag isn't set. if (!ModSettings.resetOnLoad) { // Carry on to original method. return(true); } // Check to see if we've preloaded a local settings file. if (Loading.localRicoDef != null) { // Step through each definition from the local settings file, looking for a match. foreach (RICOBuilding building in Loading.localRicoDef.Buildings) { if (building.ricoEnabled && __instance.m_info.name == building.name) { // m_level is one less than building.level. byte newLevel = (byte)(building.level - 1); if (data.m_level != newLevel) { Debugging.Message("found building '" + building.name + "' with level " + (data.m_level + 1) + ", overriding to level " + building.level); data.m_level = newLevel; } // Basic game code processing to continue initialisation. __instance.CalculateWorkplaceCount((ItemClass.Level)data.m_level, new Randomizer(buildingID), data.Width, data.Length, out int level, out int level2, out int level3, out int level4); __instance.AdjustWorkplaceCount(buildingID, ref data, ref level, ref level2, ref level3, ref level4); int workCount = level + level2 + level3 + level4; int targetHomeCount = 0; // Update visitor count. int visitCount = __instance.CalculateVisitplaceCount((ItemClass.Level)data.m_level, new Randomizer(buildingID), data.Width, data.Length); // Check to see if rsidential building homecounts differ from settings. if (building.service == "residential") { int currentHomeCount = 0; // Count currently applied citizen units (households). if (data.m_citizenUnits != 0) { // At least one household here; get the first. CitizenUnit citizenUnit = Singleton <CitizenManager> .instance.m_units.m_buffer[data.m_citizenUnits]; currentHomeCount = 1; // Step through all applied citizen units (linked via m_nextUnit), counting as we go, while (citizenUnit.m_nextUnit != 0) { citizenUnit = Singleton <CitizenManager> .instance.m_units.m_buffer[citizenUnit.m_nextUnit]; currentHomeCount++; } } // Determine target household count. targetHomeCount = __instance.CalculateHomeCount((ItemClass.Level)data.m_level, new Randomizer(buildingID), data.Width, data.Length); // If target household count is lower than the current household count, we need to perform a forced reset. // The reverse case, targets greater than current, will be caught with the base-case call to EnsureCitizenUnits below. if (targetHomeCount < currentHomeCount) { Debugging.Message("found Residential prefab " + building.name + " with target homecount " + targetHomeCount + " and citizen units " + currentHomeCount + "; forcing homecount reset"); RealisticCitizenUnits.EnsureCitizenUnits(ref __instance, buildingID, ref data, targetHomeCount, workCount, visitCount, 0); } } // Update citizen units to match new totals. EnsureCitizenUnitsRev(__instance, buildingID, ref data, targetHomeCount, workCount, visitCount, 0); // Clear any problems (so we don't have any residual issues from changing service types, for example (new) residential buildings showing 'not enough goods'. // Any 'genuine' problems will be quickly reapplied by the game. data.m_problems = 0; // We've set things up here for Ploppable RICO - don't fall through to game code. return(false); } } } // If we've hit this point, then no Ploppable RICO setup has occured - fall through to game code. return(true); }