/// <summary>
        /// Custom implementation of PrivateBuildingAI.BuildingUpgraded that takes into account that our levels can be upgraded OR downgraded; for use when current building level is below the set prefb leve.
        /// </summary>
        /// <param name="buildingAI">Building AI instance</param>
        /// <param name="buildingID">Building instance ID</param>
        /// <param name="data">Building data record</param>
        private static void CustomBuildingUpgraded(PrivateBuildingAI buildingAI, ushort buildingID, ref Building data)
        {
            buildingAI.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);
            buildingAI.AdjustWorkplaceCount(buildingID, ref data, ref level, ref level2, ref level3, ref level4);
            int workCount  = level + level2 + level3 + level4;
            int homeCount  = buildingAI.CalculateHomeCount((ItemClass.Level)data.m_level, new Randomizer(buildingID), data.Width, data.Length);
            int visitCount = buildingAI.CalculateVisitplaceCount((ItemClass.Level)data.m_level, new Randomizer(buildingID), data.Width, data.Length);

            ReversePatches.EnsureCitizenUnits(buildingAI, buildingID, ref data, homeCount, workCount, visitCount, 0);
        }
        /// <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");
        }
Exemple #3
0
        /// <summary>
        /// Harmony Postfix patch to handle *reductions* in homecounts when a building upgrades.
        /// </summary>
        /// <param name="__instance">Instance reference</param>
        /// <param name="buildingID">Building instance ID</param>
        /// <param name="data">Building data</param>
        public static void Postfix(PrivateBuildingAI __instance, ushort buildingID, ref Building data)
        {
            // Only interested in residential builidngs.
            if (__instance is ResidentialBuildingAI)
            {
                // Recalculate homecount.
                int homeCount = (__instance.CalculateHomeCount((ItemClass.Level)data.m_level, new Randomizer(buildingID), data.Width, data.Length));

                Logging.Message("residential building ", buildingID.ToString(), " (", data.Info.name, ") upgraded to level ", (data.m_level + 1).ToString(), "; calculated homecount is ", homeCount.ToString());

                // Remove any extra households.
                CitizenUnitUtils.RemoveCitizenUnits(ref data, homeCount, 0, 0, false);
            }
        }
        /// <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);
        }