/// <summary> /// Saves the current RICO settings to file and then applies them live in-game. /// </summary> private void SaveAndApply() { // Find current prefab instance. BuildingData currentBuildingData = Loading.xmlManager.prefabHash[currentSelection.prefab]; // Save first. Save(); // If we're converting a residential building to something else, then we first should clear out all households. if (currentBuildingData.prefab.GetService() == ItemClass.Service.Residential && !IsCurrentResidential()) { // removeAll argument to true to remove all households. UpdateHouseholds(currentBuildingData.prefab.name, removeAll: true); } // Get the currently applied RICO settings (local, author, mod). RICOBuilding currentData = RICOUtils.CurrentRICOSetting(currentSelection); if (currentData != null) { // Convert the 'live' prefab (instance in PrefabCollection) and update household count and builidng level for all current instances. Loading.convertPrefabs.ConvertPrefab(currentData, PrefabCollection <BuildingInfo> .FindLoaded(currentBuildingData.prefab.name)); UpdateHouseholds(currentBuildingData.prefab.name, currentData.level); } else { Debugging.Message("no current RICO settings to apply to prefab " + currentBuildingData); } // Force an update of all panels with current values. SettingsPanel.Panel.UpdateSelectedBuilding(currentSelection); }
/// <summary> /// Saves the current RICO settings to file and then applies them live in-game. /// </summary> private void SaveAndApply() { // Find current prefab instance. BuildingData currentBuildingData = Loading.xmlManager.prefabHash[currentSelection.prefab]; // Save first. Save(); // Get the currently applied RICO settings (local, author, mod). RICOBuilding currentData = RICOUtils.CurrentRICOSetting(currentSelection); if (currentData != null) { // Convert the 'live' prefab (instance in PrefabCollection) and update household count and builidng level for all current instances. Loading.convertPrefabs.ConvertPrefab(currentData, PrefabCollection <BuildingInfo> .FindLoaded(currentBuildingData.prefab.name)); CitizenUnitUtils.UpdateCitizenUnits(currentBuildingData.prefab.name); } else { Logging.Message("no current RICO settings to apply to prefab ", currentBuildingData.prefab.name); } // Force an update of all panels with current values. SettingsPanel.Panel.UpdateSelectedBuilding(currentSelection); }
/// <summary> /// Checks to see if a building should be demolished if it's not in a district with the relevant specialisation. /// Called via Harmony Transpiler patches. /// </summary> /// <param name="buildingData">Building instance data</param> internal static void CheckSpecial(ref Building buildingData) { bool isRICO = RICOUtils.IsRICOAI(buildingData.Info.GetAI() as PrivateBuildingAI); // Check if the relevant 'ignore specialisation' setting is set. // If it is, we just don't do anything. Otherwise, we mimic the base game's code for this ocurrence. if (!(ModSettings.noSpecOther && !isRICO) && !(ModSettings.noSpecRico && isRICO)) { buildingData.m_flags |= Building.Flags.Demolishing; Singleton <SimulationManager> .instance.m_currentBuildIndex++; } }
/// <summary> /// Harmony Postfix patch to force 'too few services' complaints off for all buildings. /// </summary> /// <param name="tooFewServices">If a 'too few services' complaint has been calculated</param> /// <param name="buildingID">Building instance ID</param> public static void Postfix(ref bool tooFewServices, ushort buildingID) { // Check if this building is RICO or not. bool isRICO = RICOUtils.IsRICOBuilding(buildingID); // Check if the relevant 'ignore too few services complaint' setting is set. if ((ModSettings.noServicesOther && !isRICO) || (ModSettings.noServicesRicoGrow && isRICO) || (ModSettings.noServicesRicoPlop && RICOUtils.IsRICOPloppable(buildingID))) { // It is - force too few services complaint off. tooFewServices = false; } }
/// <summary> /// Harmony Postfix patch to force 'land value too low' complaints off for all buildings. /// </summary> /// <param name="landValueTooLow">If a 'land value too low' complaint has been calculated</param> /// <param name="buildingID">Building instance ID</param> public static void Postfix(ref bool landValueTooLow, ushort buildingID) { // Check if this building is RICO or not. bool isRICO = RICOUtils.IsRICOBuilding(buildingID); // Check if the relevant 'ignore low land value complaint' setting is set. if ((ModSettings.noValueOther && !isRICO) || (ModSettings.noValueRicoGrow && isRICO) || (ModSettings.noValueRicoPlop && RICOUtils.IsRICOPloppable(buildingID))) { // It is - force land value complaint off. landValueTooLow = false; } }
/// <summary> /// Simple Prefix patch to toggle excecution of game method based on current settings. /// </summary> /// <param name="__instance">Harmony original instance reference</param> /// <returns>False if the base method shouldn't be called (collapse has been prevented), true otherwise</returns> public static bool Prefix(ref bool __result, CommonBuildingAI __instance) { if (ModSettings.noCollapse && RICOUtils.IsRICOPloppableAI(__instance as PrivateBuildingAI)) { __result = false; // Don't call base method after this. return(false); } // Continue on to base method return(true); }
/// <summary> /// Handles click events for Ploppable Tool panel tabs. /// </summary> /// <param name="panel">The Ploppable Tool panel for the selected tab</param> /// <param name="sprite">The sprite icon for the selected tab</param> public void TabClicked(int uiCategory, UISprite sprite) { // Clear the scroll panel. scrollPanel.Clear(); // List of buildings in this category. List <BuildingData> buildingList = new List <BuildingData>(); // Iterate through each prefab in our collection and see if it has RICO settings with a matching UI category. foreach (BuildingData buildingData in Loading.xmlManager.prefabHash.Values) { // Get the currently active RICO setting (if any) for this building. RICOBuilding ricoSetting = RICOUtils.CurrentRICOSetting(buildingData); // See if there's a valid RICO setting. if (ricoSetting != null) { // Valid setting - if the UI category matches this one, add it to the list. if (UICategoryIndex(ricoSetting.UiCategory) == uiCategory) { buildingList.Add(buildingData); } } } // Set display FastList using our list of selected buildings, sorted alphabetically. scrollPanel.itemsData.m_buffer = buildingList.OrderBy(x => x.DisplayName).ToArray(); scrollPanel.itemsData.m_size = buildingList.Count; // Display the scroll panel. scrollPanel.DisplayAt(0); // Redraw all tab sprites in their base state (unfocused). for (int i = 0; i <= NumTypes; i++) { if (i <= 5) { TabSprites[i].spriteName = "Zoning" + Names[i]; } else { TabSprites[i].spriteName = "IconPolicy" + Names[i]; } } // Focus this sprite (no focused versions for AD or GC sprites so exclude those). if (sprite.spriteName != "IconPolicyLeisure" && sprite.spriteName != "IconPolicyTourist" && sprite.spriteName != "IconPolicyHightech" && sprite.spriteName != "IconPolicyOrganic" && sprite.spriteName != "IconPolicySelfsufficient") { sprite.spriteName += "Focused"; } }
public static bool NewZoneCheck(ref Building buildingData, ItemClass.Zone zone1, ItemClass.Zone zone2, bool allowCollapse) { // Check if this building is RICO or not. bool isRICO = RICOUtils.IsRICOAI(buildingData.Info.GetAI() as PrivateBuildingAI); // Check if the relevant 'ignore zoning' setting is set. if ((ModSettings.noZonesOther && !isRICO) || (ModSettings.noZonesRico && isRICO)) { // It is - return true (tell the game we're in a valid zone). return(true); } // If we got here, this isn't a building covered by our settings: call original method and return its result. return(buildingData.CheckZoning(zone1, zone2, allowCollapse)); }
/// <summary> /// Harmony Postfix patch to skip 'gradual construction' for plopped RICO growables, and/or to apply the 'Make Historical' and/or 'Lock level' settings on building creation, accoriding to settings. /// </summary> /// <param name="__result">Original method result (unchanged)</param> /// <param name="info">BuildingInfo prefab for this building (unchanged)</param> /// <param name="position">Building position (ignored)</param> /// <param name="angle">Building rotation (ignored)</param> /// <param name="relocating">Building relocation (ignored)</param> /// <param name="needMoney">Is money needed (ignored)</param> /// <param name="fixedHeight">Fixed height (ignored)</param> internal static void Postfix(ref ushort __result, ref BuildingInfo info, Vector3 position, float angle, int relocating, bool needMoney, bool fixedHeight) { // Check that we have a valid building ID. if (__result == 0) { return; } // Get building AI. PrivateBuildingAI buildingAI = info.GetAI() as PrivateBuildingAI; // Only interested in private building AI. if (buildingAI != null) { // Check if AI is a RICO custom AI type. bool isRICO = RICOUtils.IsRICOAI(buildingAI); // Check if it's a RICO custom AI type. // Enable 'ploppable growables' if option is set. if ((ModSettings.plopOther && !isRICO) || (ModSettings.plopRico && isRICO)) { // Check to see if construction time is greater than zero. if (buildingAI.m_constructionTime > 0) { Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result].m_frame0.m_constructState = byte.MaxValue; BuildingCompletedRev(buildingAI, __result, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result]); // Have to do this manually as CommonBuildingAI.BuildingCompleted won't if construction time isn't zero. Singleton <BuildingManager> .instance.UpdateBuildingRenderer(__result, updateGroup : true); } } // Enable 'Make Historical' if option is set. if ((ModSettings.historicalOther && !isRICO) || (ModSettings.historicalRico && isRICO)) { info.m_buildingAI.SetHistorical(__result, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result], historical: true); } // Enable ABLC level lock if option is set and ABLC is running. if (ModUtils.ablcLockBuildingLevel != null && ((ModSettings.lockLevelOther && !isRICO) || (ModSettings.lockLevelRico && isRICO))) { ModUtils.ablcLockBuildingLevel.Invoke(null, new object[] { __result, Singleton <BuildingManager> .instance.m_buildings.m_buffer[__result].m_level }); } } }
/// <summary> /// Called by other mods to determine whether or not Ploppable RICO Revisited is controlling the population of this prefab. /// </summary> /// <param name="prefab">Prefab reference</param> /// <returns>True if Ploppable RICO is controlling the population of this prefab, false otherwise.</returns> public static bool IsRICOPopManaged(BuildingInfo prefab) { // First, do we have a setting at all? if (prefab != null && Loading.xmlManager.prefabHash.ContainsKey(prefab)) { // Get active RICO settings. RICOBuilding building = RICOUtils.CurrentRICOSetting(Loading.xmlManager.prefabHash[prefab]); // Check that it's enabled and isn't using reality. if (building != null && building.ricoEnabled && !building.UseReality) { return(true); } } // If we got here, we don't have an active setting. return(false); }
/// <summary> /// Event handler for demolish warning checkbox. /// </summary> /// <param name="control">Calling UIComponent</param> /// <param name="isChecked">New isChecked state</param> private void DemolishWarnCheckChanged(UIComponent control, bool isChecked) { // Update mod settings. ModSettings.warnBulldoze = isChecked; // If we're in-game (dictionary has been initialized), iterate through dictionary, looking for RICO ploppable buildings and updating their auto-remove flags. if (Loading.xmlManager?.prefabHash != null) { foreach (BuildingInfo prefab in Loading.xmlManager.prefabHash.Keys) { // Get active RICO settings. RICOBuilding building = RICOUtils.CurrentRICOSetting(Loading.xmlManager.prefabHash[prefab]); // Check that it's enabled and isn't growable. if (building != null && building.ricoEnabled && !building.growable) { // Apply flag. prefab.m_autoRemove = !isChecked; } } } }
/// <summary> /// Checks to see whether or not the specified building is a Ploppable RICO building. /// </summary> /// <param name="buildingID">Building instance ID</param> /// <returns>True if this is a Ploppable RICO building, false otherwise</returns> private bool IsRICOBuilding(ushort buildingID) => RICOUtils.IsRICOAI(Singleton <BuildingManager> .instance.m_buildings.m_buffer[buildingID].Info.GetAI() as PrivateBuildingAI);