Beispiel #1
0
        /// <summary>
        /// Uses reflection to find the IsRICOPopManaged method of Ploppable RICO Revisited.
        /// If successful, sets ricoPopManaged to
        /// </summary>
        internal static void RICOReflection()
        {
            string methodName = "IsRICOPopManaged";

            // Iterate through each loaded plugin assembly.
            foreach (PluginManager.PluginInfo plugin in PluginManager.instance.GetPluginsInfo())
            {
                foreach (Assembly assembly in plugin.GetAssemblies())
                {
                    if (assembly.GetName().Name.Equals("ploppablerico") && plugin.isEnabled)
                    {
                        // Found ploppablerico.dll that's part of an enabled plugin; try to get its ModUtils class.
                        Type ricoModUtils = assembly.GetType("PloppableRICO.Interfaces");

                        if (ricoModUtils != null)
                        {
                            // Try to get IsRICOPopManaged method.
                            ricoPopManaged = ricoModUtils.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
                            if (ricoPopManaged != null)
                            {
                                // Success!  We're done here.
                                Debugging.Message("found " + methodName);
                                return;
                            }
                        }
                    }
                }
            }

            // If we got here, we were unsuccessful.
            Debugging.Message("didn't find " + methodName);
        }
        static bool Prefix(ref int __result, CommercialBuildingAI __instance, ItemClass.Level level, Randomizer r, int width, int length)
        {
            PrefabEmployStruct visitors;


            // All commercial places will need visitors. CalcWorkplaces is normally called first, redirected above to include a calculation of worker visits (CalculateprefabWorkerVisit).
            // However, there is a problem with some converted assets that don't come through the "front door" (i.e. Ploppable RICO - see below).

            // Try to retrieve previously calculated value.
            if (!DataStore.prefabWorkerVisit.TryGetValue(__instance.m_info.gameObject.GetHashCode(), out visitors))
            {
                // If we didn't get a value, most likely it was because the prefab wasn't properly initialised.
                // This can happen with Ploppable RICO when the underlying asset class isn't 'Default' (for example, where Ploppable RICO assets are originally Parks, Plazas or Monuments).
                // When that happens, the above line returns zero, which sets the building to 'Not Operating Properly'.
                // So, if the call returns false, we force a recalculation of workplace visits to make sure.

                // If it's still zero after this, then we'll just return a "legitimate" zero.
                visitors.visitors = 0;

                int[] array = CommercialBuildingAIMod.GetArray(__instance.m_info, (int)level);
                AI_Utils.CalculateprefabWorkerVisit(width, length, ref __instance.m_info, 4, ref array, out visitors);
                DataStore.prefabWorkerVisit.Add(__instance.m_info.gameObject.GetHashCode(), visitors);

                // Log this to help identify specific issues.  Should only occur once per prefab.
                Debugging.Message("CalculateprefabWorkerVisit redux: " + __instance.m_info.name);
            }

            // Original method return value.
            __result = visitors.visitors;

            // Don't execute base method after this.
            return(false);
        }
        /// <summary>
        /// Attaches an event hook to options panel visibility, to create/destroy our options panel as appropriate.
        /// Destroying when not visible saves UI overhead and performance impacts, especially with so many UITextFields.
        /// </summary>
        public static void OptionsEventHook()
        {
            // Get options panel instance.
            gameOptionsPanel = UIView.library.Get <UIPanel>("OptionsPanel");

            if (gameOptionsPanel == null)
            {
                Debugging.Message("couldn't find OptionsPanel");
            }
            else
            {
                // Simple event hook to create/destroy GameObject based on appropriate visibility.
                gameOptionsPanel.eventVisibilityChanged += (control, isVisible) =>
                {
                    // Create/destroy based on visible.
                    if (isVisible)
                    {
                        Create();
                    }
                    else
                    {
                        Close();
                    }
                };

                // Recreate panel on system locale change.
                LocaleManager.eventLocaleChanged += LocaleChanged;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Returns the filepath of the mod assembly.
        /// </summary>
        /// <returns>Mod assembly filepath</returns>
        private string GetAssemblyPath()
        {
            // Get list of currently active plugins.
            IEnumerable <PluginManager.PluginInfo> plugins = PluginManager.instance.GetPluginsInfo();

            // Iterate through list.
            foreach (PluginManager.PluginInfo plugin in plugins)
            {
                try
                {
                    // Get all (if any) mod instances from this plugin.
                    IUserMod[] mods = plugin.GetInstances <IUserMod>();

                    // Check to see if the primary instance is this mod.
                    if (mods.FirstOrDefault() is RealPopMod)
                    {
                        // Found it! Return path.
                        return(plugin.modPath);
                    }
                }
                catch
                {
                    // Don't care.
                }
            }

            // If we got here, then we didn't find the assembly.
            Debugging.Message("assembly path not found");
            throw new FileNotFoundException(RealPopMod.ModName + ": assembly path not found!");
        }
        public static int[] GetArray(BuildingInfo item, int level)
        {
            int[][] array = DataStore.office;

            try
            {
                switch (item.m_class.m_subService)
                {
                case ItemClass.SubService.OfficeHightech:
                    array = DataStore.officeHighTech;
                    break;

                case ItemClass.SubService.OfficeGeneric:
                default:
                    break;
                }

                return(array[level]);
            }
            catch (System.Exception)
            {
                // Prevent unnecessary log spamming due to 'level-less' buildings returning level 1 instead of level 0.
                if (level != 1)
                {
                    Debugging.Message(item.gameObject.name + " attempted to be use " + item.m_class.m_subService.ToString() + " with level " + level + ". Returning as level 0");
                }
                return(array[0]);
            }
        }
        public static int[] GetArray(BuildingInfo item, int level)
        {
            int[][] array = DataStore.residentialLow;

            try
            {
                switch (item.m_class.m_subService)
                {
                case ItemClass.SubService.ResidentialHighEco:
                    array = DataStore.resEcoHigh;
                    break;

                case ItemClass.SubService.ResidentialLowEco:
                    array = DataStore.resEcoLow;
                    break;

                case ItemClass.SubService.ResidentialHigh:
                    array = DataStore.residentialHigh;
                    break;

                case ItemClass.SubService.ResidentialLow:
                default:
                    break;
                }

                return(array[level]);
            }
            catch (System.Exception)
            {
                Debugging.Message(item.gameObject.name + " attempted to be use " + item.m_class.m_subService.ToString() + " with level " + level + ". Returning as level 0");
                return(array[0]);
            }
        }
        /// <param name="name"></param>
        /// <param name="level"></param>
        /// <param name="callingFunction">For debug purposes</param>
        /// <returns></returns>
        private static int[] getArray(string name, int level, string callingFunction)
        {
            int[] array = new int[14];

            switch (name)
            {
            case "ResidentialLow":
                array = DataStore.residentialLow[level];
                break;

            case "ResidentialHigh":
                array = DataStore.residentialHigh[level];
                break;

            case "CommercialLow":
                array = DataStore.commercialLow[level];
                break;

            case "CommercialHigh":
                array = DataStore.commercialHigh[level];
                break;

            case "CommercialTourist":
                array = DataStore.commercialTourist[level];
                break;

            case "CommercialLeisure":
                array = DataStore.commercialLeisure[level];
                break;

            case "Office":
                array = DataStore.office[level];
                break;

            case "Industry":
                array = DataStore.industry[level];
                break;

            case "IndustryOre":
                array = DataStore.industry_ore[level];
                break;

            case "IndustryOil":
                array = DataStore.industry_oil[level];
                break;

            case "IndustryForest":
                array = DataStore.industry_forest[level];
                break;

            case "IndustryFarm":
                array = DataStore.industry_farm[level];
                break;

            default:
                Debugging.Message("callingFunction " + callingFunction + ". unknown element name: " + name);
                break;
            }
            return(array);
        } // end getArray
Beispiel #8
0
        /// <summary>
        /// Checks to see if another mod is installed, based on a provided assembly name.
        /// Case-sensitive!  PloppableRICO is not the same as ploppablerico!
        /// </summary>
        /// <param name="assemblyName">Name of the mod assembly</param>
        /// <param name="enabledOnly">True if the mod needs to be enabled for the purposes of this check; false if it doesn't matter</param>
        /// <returns>True if the mod is installed (and, if enabledOnly is true, is also enabled), false otherwise</returns>
        internal static bool IsModInstalled(string assemblyName, bool enabledOnly = false)
        {
            // Iterate through the full list of plugins.
            foreach (PluginManager.PluginInfo plugin in PluginManager.instance.GetPluginsInfo())
            {
                foreach (Assembly assembly in plugin.GetAssemblies())
                {
                    if (assembly.GetName().Name.Equals(assemblyName))
                    {
                        Debugging.Message("found mod assembly " + assemblyName);
                        if (enabledOnly)
                        {
                            return(plugin.isEnabled);
                        }
                        else
                        {
                            return(true);
                        }
                    }
                }
            }

            // If we've made it here, then we haven't found a matching assembly.
            return(false);
        }
Beispiel #9
0
        /// <summary>
        /// Actions to update the UI on a language change go here.
        /// </summary>
        public void UpdateUILanguage()
        {
            Debugging.Message("setting language to " + (currentIndex < 0 ? "system" : languages.Values[currentIndex].uniqueName));

            // UI update code goes here.

            // TOOO:  Add dynamic UI update.
        }
 // Output buffer
 public static void releaseBuffer()
 {
     if (sb.Length > 0)
     {
         Debugging.Message(sb.ToString());
         sb.Remove(0, sb.Length);
     }
 }
        public override void OnCreated(ILoading loading)
        {
            // Don't do anything if not in game (e.g. if we're going into an editor).
            if (loading.currentMode != AppMode.Game)
            {
                isModEnabled = false;
                Debugging.Message("not loading into game, skipping activation");
                return;
            }


            // Check for original WG Realistic Population and Consumption Mod; if it's enabled, flag and don't activate this mod.
            if (IsModEnabled(426163185ul))
            {
                conflictingMod = true;
                Debugging.Message("Realistic Population and Consumption Mod detected, skipping activation");
            }
            else if (!isModEnabled)
            {
                isModEnabled = true;

                // Harmony patches.
                Debugging.Message("version v" + RealPopMod.Version + " loading");
                _harmony.PatchAll(GetType().Assembly);
                Debugging.Message("patching complete");

                MergeDefaultBonus();

                // Remove bonus names from over rides
                foreach (string name in DataStore.bonusHouseholdCache.Keys)
                {
                    DataStore.householdCache.Remove(name);
                }

                foreach (string name in DataStore.bonusWorkerCache.Keys)
                {
                    DataStore.workerCache.Remove(name);
                }

                DataStore.seedToId.Clear();
                for (int i = 0; i <= ushort.MaxValue; ++i)  // Up to 1M buildings apparently is ok
                {
                    // This creates a unique number
                    try
                    {
                        Randomizer number = new Randomizer(i);
                        DataStore.seedToId.Add(number.seed, (ushort)i);
                    }
                    catch (Exception)
                    {
                        //Debugging.writeDebugToFile("Seed collision at number: " + i);
                    }
                }

                // Check for Ploppable RICO Revisited.
                ModUtils.RICOReflection();
            }
        }
        /// <summary>
        /// Loads the configuration XML file and sets the datastore.
        /// </summary>
        internal static void ReadFromXML()
        {
            // Check the exe directory first
            DataStore.currentFileLocation = ColossalFramework.IO.DataLocation.executableDirectory + Path.DirectorySeparatorChar + XML_FILE;
            bool fileAvailable = File.Exists(DataStore.currentFileLocation);

            if (!fileAvailable)
            {
                // Switch to default which is the cities skylines in the application data area.
                DataStore.currentFileLocation = ColossalFramework.IO.DataLocation.localApplicationData + Path.DirectorySeparatorChar + XML_FILE;
                fileAvailable = File.Exists(DataStore.currentFileLocation);
            }

            if (fileAvailable)
            {
                Debugging.Message("loading configuration file " + DataStore.currentFileLocation);

                // Load in from XML - Designed to be flat file for ease
                WG_XMLBaseVersion reader = new XML_VersionSix();
                XmlDocument       doc    = new XmlDocument();
                try
                {
                    doc.Load(DataStore.currentFileLocation);

                    int version = Convert.ToInt32(doc.DocumentElement.Attributes["version"].InnerText);
                    if (version > 3 && version <= 5)
                    {
                        // Use version 5
                        reader = new XML_VersionFive();

                        // Make a back up copy of the old system to be safe
                        File.Copy(DataStore.currentFileLocation, DataStore.currentFileLocation + ".ver5", true);
                        string error = "Detected an old version of the XML (v5). " + DataStore.currentFileLocation + ".ver5 has been created for future reference and will be upgraded to the new version.";
                        Debugging.bufferWarning(error);
                    }
                    else if (version <= 3) // Uh oh... version 4 was a while back..
                    {
                        string error = "Detected an unsupported version of the XML (v4 or less). Backing up for a new configuration as :" + DataStore.currentFileLocation + ".ver4";
                        Debugging.bufferWarning(error);
                        File.Copy(DataStore.currentFileLocation, DataStore.currentFileLocation + ".ver4", true);
                        return;
                    }
                    reader.readXML(doc);
                }
                catch (Exception e)
                {
                    // Game will now use defaults
                    Debugging.bufferWarning("The following exception(s) were detected while loading the XML file. Some (or all) values may not be loaded.");
                    Debugging.bufferWarning(e.Message);
                }
            }
            else
            {
                Debugging.Message("configuration file not found. Will output new file to: " + DataStore.currentFileLocation);
            }
        }
        public override void OnReleased()
        {
            if (isModEnabled)
            {
                isModEnabled = false;

                // Unapply Harmony patches.
                _harmony.UnpatchAll(HarmonyID);
                Debugging.Message("patches unapplied");
            }
        }
 /// <summary>
 /// Updates (or creates a new) XML configuration file with current DataStore settings.
 /// </summary>
 internal static void WriteToXML()
 {
     try
     {
         WG_XMLBaseVersion xml = new XML_VersionSix();
         xml.writeXML(DataStore.currentFileLocation);
     }
     catch (Exception e)
     {
         Debugging.Message("XML writing exception:\r\n" + e.Message);
     }
 }
        /// <param name="doc"></param>
        public override void readXML(XmlDocument doc)
        {
            XmlElement root = doc.DocumentElement;

            try
            {
                //DataStore.enableExperimental = Convert.ToBoolean(root.Attributes["experimental"].InnerText);
                //DataStore.timeBasedRealism = Convert.ToBoolean(root.Attributes["enableTimeVariation"].InnerText);
            }
            catch (Exception)
            {
                DataStore.enableExperimental = false;
            }

            foreach (XmlNode node in root.ChildNodes)
            {
                try
                {
                    if (node.Name.Equals(popNodeName))
                    {
                        readPopulationNode(node);
                    }
                    else if (node.Name.Equals(consumeNodeName))
                    {
                        readConsumptionNode(node);
                    }
                    else if (node.Name.Equals(visitNodeName))
                    {
                        readVisitNode(node);
                    }
                    else if (node.Name.Equals(pollutionNodeName))
                    {
                        readPollutionNode(node);
                    }
                    else if (node.Name.Equals(productionNodeName))
                    {
                        readProductionNode(node);
                    }
                    else if (node.Name.Equals(bonusHouseName))
                    {
                        readBonusHouseNode(node);
                    }
                    else if (node.Name.Equals(bonusWorkName))
                    {
                        readBonusWorkers(node);
                    }
                }
                catch (Exception e)
                {
                    Debugging.Message("XML readNodes exception:\r\n" + e.ToString());
                }
            }
        } // end readXML
        public override void OnLevelLoaded(LoadMode mode)
        {
            // Check to see if a conflicting mod has been detected - if so, alert the user.
            if (conflictingMod)
            {
                UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Realistic Population Revisited", "Original Realistic Population and Consumption Mod mod detected - Realistic Population Revisited is shutting down to protect your game.  Only ONE of these mods can be enabled at the same time; please unsubscribe from the old Realistic Population and Consumption Mod, which is now deprecated!", true);
            }

            // Don't do anything further if mod hasn't activated (conflicting mod detected, or loading into editor instead of game).
            if (!isModEnabled)
            {
                return;
            }

            else if (mode == LoadMode.LoadGame || mode == LoadMode.NewGame)
            {
                if (!isLevelLoaded)
                {
                    isLevelLoaded = true;
                    // Now we can remove people
                    DataStore.allowRemovalOfCitizens = true;
                    Debugging.releaseBuffer();
                    Debugging.Message("successfully applied");
                }
            }

            // Create new XML if one doesn't already exist.
            if (!File.Exists(DataStore.currentFileLocation))
            {
                XMLUtilsWG.WriteToXML();
            }

            // Add button to building info panels.
            BuildingDetailsPanel.AddInfoPanelButton();

            // Check if we need to display update notification.
            if (UpdateNotification.notificationVersion != 2)
            {
                // No update notification "Don't show again" flag found; show the notification.
                UpdateNotification notification = new UpdateNotification();
                notification.Create();
                notification.Show();
            }

            // Set up options panel event handler.
            OptionsPanel.OptionsEventHook();
        }
Beispiel #17
0
        /// <summary>
        /// Returns the translation for the given key in the current language.
        /// </summary>
        /// <param name="key">Translation key to transate</param>
        /// <returns>Translation </returns>
        public string Translate(string key)
        {
            Language currentLanguage;


            // Check to see if we're using system settings.
            if (currentIndex < 0)
            {
                // Using system settings - initialise system language if we haven't already.
                if (systemLanguage == null)
                {
                    SetSystemLanguage();
                }

                currentLanguage = systemLanguage;
            }
            else
            {
                currentLanguage = languages.Values[currentIndex];
            }

            // Check that a valid current language is set.
            if (currentLanguage != null)
            {
                // Check that the current key is included in the translation.
                if (currentLanguage.translationDictionary.ContainsKey(key))
                {
                    // All good!  Return translation.
                    return(currentLanguage.translationDictionary[key]);
                }
                else
                {
                    Debugging.Message("no translation for language " + currentLanguage.uniqueName + " found for key " + key);

                    // Attempt fallack translation.
                    return(FallbackTranslation(currentLanguage.uniqueName, key));
                }
            }
            else
            {
                Debugging.Message("no current language when translating key " + key);
            }

            // If we've made it this far, something went wrong; just return the key.
            return(key);
        }
Beispiel #18
0
        public static int[] GetArray(BuildingInfo item, int level)
        {
            int tempLevel = 0;

            int[][] array = DataStore.industry;

            try
            {
                switch (item.m_class.m_subService)
                {
                case ItemClass.SubService.IndustrialOre:
                    array     = DataStore.industry_ore;
                    tempLevel = level + 1;
                    break;

                case ItemClass.SubService.IndustrialForestry:
                    array     = DataStore.industry_forest;
                    tempLevel = level + 1;
                    break;

                case ItemClass.SubService.IndustrialFarming:
                    array     = DataStore.industry_farm;
                    tempLevel = level + 1;
                    break;

                case ItemClass.SubService.IndustrialOil:
                    array     = DataStore.industry_oil;
                    tempLevel = level + 1;
                    break;

                case ItemClass.SubService.IndustrialGeneric:      // Deliberate fall through
                default:
                    tempLevel = level;
                    break;
                }

                return(array[tempLevel]);
            }
            catch (System.Exception)
            {
                Debugging.Message(item.gameObject.name + " attempted to be use " + item.m_class.m_subService.ToString() + " with level " + level + ". Returning as level 0");
                return(array[0]);
            }
        }
Beispiel #19
0
        /// <summary>
        /// Loads languages from XML files.
        /// </summary>
        private void LoadLanguages()
        {
            // Clear existing dictionary.
            languages.Clear();

            // Get the current assembly path and append our locale directory name.
            string assemblyPath = GetAssemblyPath();

            if (!assemblyPath.IsNullOrWhiteSpace())
            {
                string localePath = Path.Combine(assemblyPath, "Translations");

                // Ensure that the directory exists before proceeding.
                if (Directory.Exists(localePath))
                {
                    // Load each file in directory and attempt to deserialise as a translation file.
                    string[] translationFiles = Directory.GetFiles(localePath);
                    foreach (string translationFile in translationFiles)
                    {
                        using (StreamReader reader = new StreamReader(translationFile))
                        {
                            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Language));
                            if (xmlSerializer.Deserialize(reader) is Language translation)
                            {
                                // Got one!  add it to the list.
                                languages.Add(translation.uniqueName, translation);
                            }
                            else
                            {
                                Debugging.Message("couldn't deserialize translation file '" + translationFile);
                            }
                        }
                    }
                }
                else
                {
                    Debugging.Message("translations directory not found");
                }
            }
            else
            {
                Debugging.Message("assembly path was empty");
            }
        }
        public static int[] GetArray(BuildingInfo item, int level)
        {
            int[][] array = DataStore.industry;

            try
            {
                switch (item.m_class.m_subService)
                {
                case ItemClass.SubService.IndustrialOre:
                    array = DataStore.industry_ore;
                    break;

                case ItemClass.SubService.IndustrialForestry:
                    array = DataStore.industry_forest;
                    break;

                case ItemClass.SubService.IndustrialFarming:
                    array = DataStore.industry_farm;
                    break;

                case ItemClass.SubService.IndustrialOil:
                    array = DataStore.industry_oil;
                    break;

                case ItemClass.SubService.IndustrialGeneric:      // Deliberate fall through
                default:
                    break;
                }

                return(array[level]);
            }
            catch (System.Exception)
            {
                // Prevent unnecessary log spamming due to 'level-less' buildings returning level 1 instead of level 0.
                if (level != 1)
                {
                    Debugging.Message(item.gameObject.name + " attempted to be use " + item.m_class.m_subService.ToString() + " with level " + level + ". Returning as level 0");
                }
                return(array[0]);
            }
        } // end getArray
Beispiel #21
0
        /// <summary>
        /// Creates the panel object in-game.
        /// </summary>
        public void Create()
        {
            try
            {
                // Destroy existing (if any) instances.
                uiGameObject = GameObject.Find("RealPopUpgradeNotification");
                if (uiGameObject != null)
                {
                    Debugging.Message("found existing upgrade notification instance");
                    GameObject.Destroy(uiGameObject);
                }

                // Create new instance.
                // Give it a unique name for easy finding with ModTools.
                uiGameObject = new GameObject("RealPopUpgradeNotification");
                uiGameObject.transform.parent = UIView.GetAView().transform;
                _instance = uiGameObject.AddComponent <UpdateNotification>();
            }
            catch (Exception e)
            {
                Debugging.LogException(e);
            }
        }
        /// <summary>
        /// Prints an exception message to the Unity output log.
        /// </summary>
        /// <param name="message">Message to log</param>
        internal static void LogException(Exception exception)
        {
            // Use StringBuilder for efficiency since we're doing a lot of manipulation here.
            StringBuilder message = new StringBuilder();

            message.AppendLine("caught exception!");
            message.AppendLine("Exception:");
            message.AppendLine(exception.Message);
            message.AppendLine(exception.Source);
            message.AppendLine(exception.StackTrace);

            // Log inner exception as well, if there is one.
            if (exception.InnerException != null)
            {
                message.AppendLine("Inner exception:");
                message.AppendLine(exception.InnerException.Message);
                message.AppendLine(exception.InnerException.Source);
                message.AppendLine(exception.InnerException.StackTrace);
            }

            // Write to log.
            Debugging.Message(message.ToString());
        }
        /// <summary>
        /// Called whenever the currently selected building is changed to update the panel display.
        /// </summary>
        /// <param name="building"></param>
        public void SelectionChanged(BuildingInfo building)
        {
            if ((building == null) || (building.name == null))
            {
                // If no valid building selected, then hide the calculations panel.
                detailsPanel.height    = 0;
                detailsPanel.isVisible = false;
                return;
            }

            // Variables to compare actual counts vs. mod count, to see if there's another mod overriding counts.
            int appliedCount;
            int modCount;

            // Building model size, not plot size.
            Vector3 buildingSize = building.m_size;
            int     floorCount;

            // Array used for calculations depending on building service/subservice (via DataStore).
            int[] array;
            // Default minimum number of homes or jobs is one; different service types will override this.
            int minHomesJobs = 1;
            int customHomeJobs;

            // Check for valid building AI.
            if (!(building.GetAI() is PrivateBuildingAI buildingAI))
            {
                Debugging.Message("invalid building AI type in building details");
                return;
            }

            // Residential vs. workplace AI.
            if (buildingAI is ResidentialBuildingAI)
            {
                // Get appropriate calculation array.
                array = ResidentialBuildingAIMod.GetArray(building, (int)building.GetClassLevel());

                // Set calculated homes label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_HOM_CALC");

                // Set customised homes label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_HOM_CUST");
                customHomeJobs            = ExternalCalls.GetResidential(building);

                // Applied homes is what's actually being returned by the CaclulateHomeCount call to this building AI.
                // It differs from calculated homes if there's an override value for that building with this mod, or if another mod is overriding.
                appliedCount = buildingAI.CalculateHomeCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength());
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_HOM_APPL") + appliedCount;
            }
            else
            {
                // Workplace AI.
                // Default minimum number of jobs is 4.
                minHomesJobs = 4;

                // Find the correct array for the relevant building AI.
                switch (building.GetService())
                {
                case ItemClass.Service.Commercial:
                    array = CommercialBuildingAIMod.GetArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Office:
                    array = OfficeBuildingAIMod.GetArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Industrial:
                    if (buildingAI is IndustrialExtractorAI)
                    {
                        array = IndustrialExtractorAIMod.GetArray(building, (int)building.GetClassLevel());
                    }
                    else
                    {
                        array = IndustrialBuildingAIMod.GetArray(building, (int)building.GetClassLevel());
                    }
                    break;

                default:
                    Debugging.Message("invalid building service in building details");
                    return;
                }

                // Set calculated jobs label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_JOB_CALC") + " ";

                // Set customised jobs label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_JOB_CUST") + " ";
                customHomeJobs            = ExternalCalls.GetWorker(building);

                // Applied jobs is what's actually being returned by the CalculateWorkplaceCount call to this building AI.
                // It differs from calculated jobs if there's an override value for that building with this mod, or if another mod is overriding.
                int[] jobs = new int[4];
                buildingAI.CalculateWorkplaceCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength(), out jobs[0], out jobs[1], out jobs[2], out jobs[3]);
                appliedCount = jobs[0] + jobs[1] + jobs[2] + jobs[3];
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_JOB_APPL") + " " + appliedCount;
            }

            // Reproduce CalcBase calculations to get building area.
            int calcWidth  = building.GetWidth();
            int calcLength = building.GetLength();

            floorCount = Mathf.Max(1, Mathf.FloorToInt(buildingSize.y / array[DataStore.LEVEL_HEIGHT]));

            // If CALC_METHOD is zero, then calculations are based on building model size, not plot size.
            if (array[DataStore.CALC_METHOD] == 0)
            {
                // If asset has small x dimension, then use plot width in squares x 6m (75% of standard width) instead.
                if (buildingSize.x <= 1)
                {
                    calcWidth *= 6;
                }
                else
                {
                    calcWidth = (int)buildingSize.x;
                }

                // If asset has small z dimension, then use plot length in squares x 6m (75% of standard length) instead.
                if (buildingSize.z <= 1)
                {
                    calcLength *= 6;
                }
                else
                {
                    calcLength = (int)buildingSize.z;
                }
            }
            else
            {
                // If CALC_METHOD is nonzero, then caluclations are based on plot size, not building size.
                // Plot size is 8 metres per square.
                calcWidth  *= 8;
                calcLength *= 8;
            }

            // Display calculated (and retrieved) details.
            detailLabels[(int)Details.width].text       = Translations.Translate("RPR_CAL_BLD_X") + " " + calcWidth;
            detailLabels[(int)Details.length].text      = Translations.Translate("RPR_CAL_BLD_Z") + " " + calcLength;
            detailLabels[(int)Details.height].text      = Translations.Translate("RPR_CAL_BLD_Y") + " " + (int)buildingSize.y;
            detailLabels[(int)Details.personArea].text  = Translations.Translate("RPR_CAL_BLD_M2") + " " + array[DataStore.PEOPLE];
            detailLabels[(int)Details.floorHeight].text = Translations.Translate("RPR_CAL_FLR_Y") + " " + array[DataStore.LEVEL_HEIGHT];
            detailLabels[(int)Details.floors].text      = Translations.Translate("RPR_CAL_FLR") + " " + floorCount;

            // Area calculation - will need this later.
            int calculatedArea = calcWidth * calcLength;

            detailLabels[(int)Details.area].text = Translations.Translate("RPR_CAL_M2") + " " + calculatedArea;

            // Show or hide extra floor modifier as appropriate (hide for zero or less, otherwise show).
            if (array[DataStore.DENSIFICATION] > 0)
            {
                detailLabels[(int)Details.extraFloors].text      = Translations.Translate("RPR_CAL_FLR_M") + " " + array[DataStore.DENSIFICATION];
                detailLabels[(int)Details.extraFloors].isVisible = true;
            }
            else
            {
                detailLabels[(int)Details.extraFloors].isVisible = false;
            }

            // Set minimum residences for high density.
            if ((building.GetSubService() == ItemClass.SubService.ResidentialHigh) || (building.GetSubService() == ItemClass.SubService.ResidentialHighEco))
            {
                // Minimum of 2, or 90% number of floors, whichever is greater. This helps the 1x1 high density.
                minHomesJobs = Mathf.Max(2, Mathf.CeilToInt(0.9f * floorCount));
            }

            // Perform actual household or workplace calculation.
            modCount = Mathf.Max(minHomesJobs, (calculatedArea * (floorCount + Mathf.Max(0, array[DataStore.DENSIFICATION]))) / array[DataStore.PEOPLE]);
            homesJobsCalcLabel.text += modCount;

            // Set customised homes/jobs label (leave blank if no custom setting retrieved).
            if (customHomeJobs > 0)
            {
                homesJobsCustomLabel.text += customHomeJobs.ToString();

                // Update modCount to reflect the custom figures.
                modCount = customHomeJobs;
            }

            // Check to see if Ploppable RICO Revisited is controlling this building's population.
            if (ModUtils.CheckRICO(building))
            {
                messageLabel.text = Translations.Translate("RPR_CAL_RICO");
                messageLabel.Show();
            }
            else
            {
                // Hide message text by default.
                messageLabel.Hide();
            }

            // We've got a valid building and results, so show panel.
            detailsPanel.height    = 270;
            detailsPanel.isVisible = true;
        }
Beispiel #24
0
        /// <summary>
        /// Create the panel; we no longer use Start() as that's not sufficiently reliable (race conditions), and is no longer needed, with the new create/destroy process.
        /// </summary>
        public void Setup()
        {
            const int marginPadding = 10;

            // Generic setup.
            isVisible               = true;
            canFocus                = true;
            isInteractive           = true;
            backgroundSprite        = "UnlockingPanel";
            autoLayout              = false;
            autoLayoutDirection     = LayoutDirection.Vertical;
            autoLayoutPadding.top   = 5;
            autoLayoutPadding.right = 5;
            builtinKeyNavigation    = true;
            clipChildren            = true;

            // Panel title.
            UILabel title = this.AddUIComponent <UILabel>();

            title.relativePosition = new Vector3(0, 5);
            title.textAlignment    = UIHorizontalAlignment.Center;
            title.text             = Translations.Translate("RPR_CUS_TITLE");
            title.textScale        = 1.2f;
            title.autoSize         = false;
            title.width            = this.width;
            title.height           = 30;

            // Text field label.
            homeJobLabel = this.AddUIComponent <UILabel>();
            homeJobLabel.relativePosition = new Vector3(marginPadding, 40);
            homeJobLabel.textAlignment    = UIHorizontalAlignment.Left;
            homeJobLabel.text             = Translations.Translate("RPR_LBL_HOM");

            // Home or jobs count text field.
            homeJobsCount = UIUtils.CreateTextField(this, this.width - (marginPadding * 3) - homeJobLabel.width, 20);
            homeJobsCount.relativePosition = new Vector3(marginPadding + homeJobLabel.width + marginPadding, 40);

            // Save button.
            saveButton = UIUtils.CreateButton(this, 200);
            saveButton.relativePosition = new Vector3(marginPadding, 70);
            saveButton.text             = Translations.Translate("RPR_CUS_ADD");
            saveButton.tooltip          = Translations.Translate("RPR_CUS_ADD_TIP");
            saveButton.Disable();

            // Delete button.
            deleteButton = UIUtils.CreateButton(this, 200);
            deleteButton.relativePosition = new Vector3(marginPadding, 110);
            deleteButton.text             = Translations.Translate("RPR_CUS_DEL");
            deleteButton.tooltip          = Translations.Translate("RPR_CUS_DEL_TIP");
            deleteButton.Disable();

            // Save button event handler.
            saveButton.eventClick += (component, clickEvent) =>
            {
                // Hide message.
                messageLabel.isVisible = false;

                // Don't do anything with invalid entries.
                if (currentSelection == null || currentSelection.name == null)
                {
                    return;
                }

                // Read textfield if possible.
                if (int.TryParse(homeJobsCount.text, out int homesJobs))
                {
                    // Minimum value of 1.
                    if (homesJobs < 1)
                    {
                        // Print warning message in red.
                        messageLabel.textColor = new Color32(255, 0, 0, 255);
                        messageLabel.text      = Translations.Translate("RPR_ERR_ZERO");
                        messageLabel.isVisible = true;
                    }
                    else
                    {
                        // Homes or jobs?
                        if (currentSelection.GetService() == ItemClass.Service.Residential)
                        {
                            Debugging.Message("adding custom household count of " + homesJobs + " for " + currentSelection.name);

                            // Residential building.
                            ExternalCalls.SetResidential(currentSelection, homesJobs);

                            // Update household counts for existing instances of this building - only needed for residential buildings.
                            // Workplace counts will update automatically with next call to CalculateWorkplaceCount; households require more work (tied to CitizenUnits).
                            UpdateHouseholds(currentSelection.name);
                        }
                        else
                        {
                            Debugging.Message("adding custom workplace count of " + homesJobs + " for " + currentSelection.name);

                            // Employment building.
                            ExternalCalls.SetWorker(currentSelection, homesJobs);
                        }

                        // Refresh the display so that all panels reflect the updated settings.
                        BuildingDetailsPanel.Panel.UpdateSelectedBuilding(currentSelection);
                        BuildingDetailsPanel.Panel.Refresh();
                    }
                }
                else
                {
                    // TryParse couldn't parse the data; print warning message in red.
                    messageLabel.textColor = new Color32(255, 0, 0, 255);
                    messageLabel.text      = Translations.Translate("RPR_ERR_INV");
                    messageLabel.isVisible = true;
                }
            };

            // Delete button event handler.
            deleteButton.eventClick += (component, clickEvent) =>
            {
                // Hide message.
                messageLabel.isVisible = false;

                // Don't do anything with invalid entries.
                if (currentSelection == null || currentSelection.name == null)
                {
                    return;
                }

                Debugging.Message("deleting custom entry for " + currentSelection.name);

                // Homes or jobs?  Remove custom entry as appropriate.
                if (currentSelection.GetService() == ItemClass.Service.Residential)
                {
                    // Residential building.
                    ExternalCalls.RemoveResidential(currentSelection);

                    // Update household counts for existing instances of this building - only needed for residential buildings.
                    // Workplace counts will update automatically with next call to CalculateWorkplaceCount; households require more work (tied to CitizenUnits).
                    UpdateHouseholds(currentSelection.name);
                }
                else
                {
                    // Employment building.
                    ExternalCalls.RemoveWorker(currentSelection);
                }

                // Refresh the display so that all panels reflect the updated settings.
                BuildingDetailsPanel.Panel.Refresh();
                homeJobsCount.text = string.Empty;
            };

            // Message label (initially hidden).
            messageLabel = this.AddUIComponent <UILabel>();
            messageLabel.relativePosition = new Vector3(marginPadding, 160);
            messageLabel.textAlignment    = UIHorizontalAlignment.Left;
            messageLabel.autoSize         = false;
            messageLabel.autoHeight       = true;
            messageLabel.wordWrap         = true;
            messageLabel.width            = this.width - (marginPadding * 2);
            messageLabel.isVisible        = false;
            messageLabel.text             = "No message to display";
        }
Beispiel #25
0
        } // end readXML

        /// <param name="fullPathFileName"></param>
        /// <returns></returns>
        public override bool writeXML(string fullPathFileName)
        {
            XmlDocument xmlDoc = new XmlDocument();

            XmlNode      rootNode  = xmlDoc.CreateElement("WG_CityMod");
            XmlAttribute attribute = xmlDoc.CreateAttribute("version");

            attribute.Value = "6";
            rootNode.Attributes.Append(attribute);

            /*
             * attribute = xmlDoc.CreateAttribute("experimental");
             * attribute.Value = DataStore.enableExperimental ? "true" : "false";
             * rootNode.Attributes.Append(attribute);
             */

            xmlDoc.AppendChild(rootNode);

            XmlNode popNode = xmlDoc.CreateElement(popNodeName);

            attribute       = xmlDoc.CreateAttribute("strictCapacity");
            attribute.Value = DataStore.strictCapacity ? "true" : "false";
            popNode.Attributes.Append(attribute);

            XmlNode consumeNode    = xmlDoc.CreateElement(consumeNodeName);
            XmlNode visitNode      = xmlDoc.CreateElement(visitNodeName);
            XmlNode pollutionNode  = xmlDoc.CreateElement(pollutionNodeName);
            XmlNode productionNode = xmlDoc.CreateElement(productionNodeName);

            try
            {
                MakeNodes(xmlDoc, "ResidentialLow", DataStore.residentialLow, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "ResidentialHigh", DataStore.residentialHigh, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "ResEcoLow", DataStore.resEcoLow, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "ResEcoHigh", DataStore.resEcoHigh, popNode, consumeNode, visitNode, pollutionNode, productionNode);

                MakeNodes(xmlDoc, "CommercialLow", DataStore.commercialLow, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "CommercialHigh", DataStore.commercialHigh, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "CommercialEco", DataStore.commercialEco, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "CommercialTourist", DataStore.commercialTourist, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "CommercialLeisure", DataStore.commercialLeisure, popNode, consumeNode, visitNode, pollutionNode, productionNode);

                MakeNodes(xmlDoc, "Office", DataStore.office, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "OfficeHighTech", DataStore.officeHighTech, popNode, consumeNode, visitNode, pollutionNode, productionNode);

                MakeNodes(xmlDoc, "Industry", DataStore.industry, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "IndustryFarm", DataStore.industry_farm, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "IndustryForest", DataStore.industry_forest, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "IndustryOre", DataStore.industry_ore, popNode, consumeNode, visitNode, pollutionNode, productionNode);
                MakeNodes(xmlDoc, "IndustryOil", DataStore.industry_oil, popNode, consumeNode, visitNode, pollutionNode, productionNode);
            }
            catch (Exception e)
            {
                Debugging.Message("XML MakeNodes exception:\r\n" + e.ToString());
            }

            // First segment
            CreatePopulationNodeComment(xmlDoc, rootNode);
            rootNode.AppendChild(popNode);
            CreateConsumptionNodeComment(xmlDoc, rootNode);
            rootNode.AppendChild(consumeNode);
            CreateVisitNodeComment(xmlDoc, rootNode);
            rootNode.AppendChild(visitNode);
            CreateProductionNodeComment(xmlDoc, rootNode);
            rootNode.AppendChild(productionNode);
            CreatePollutionNodeComment(xmlDoc, rootNode);
            rootNode.AppendChild(pollutionNode);

            // Add mesh names to XML for house holds
            XmlComment comment = xmlDoc.CreateComment(" ******* House hold data ******* ");

            rootNode.AppendChild(comment);
            XmlNode overrideHouseholdNode = xmlDoc.CreateElement(overrideHouseName);

            attribute       = xmlDoc.CreateAttribute("printResNames");
            attribute.Value = DataStore.printResidentialNames ? "true" : "false";
            overrideHouseholdNode.Attributes.Append(attribute);
            attribute       = xmlDoc.CreateAttribute("mergeResNames");
            attribute.Value = DataStore.mergeResidentialNames ? "true" : "false";
            overrideHouseholdNode.Attributes.Append(attribute);

            SortedList <string, int> list = new SortedList <string, int>(DataStore.householdCache);

            foreach (string name in list.Keys)
            {
                XmlNode meshNameNode = xmlDoc.CreateElement(meshName);
                meshNameNode.InnerXml = SecurityElement.Escape(name);
                attribute             = xmlDoc.CreateAttribute("value");
                int value = 1;
                DataStore.householdCache.TryGetValue(name, out value);
                attribute.Value = Convert.ToString(value);
                meshNameNode.Attributes.Append(attribute);
                overrideHouseholdNode.AppendChild(meshNameNode);
            }
            rootNode.AppendChild(overrideHouseholdNode); // Append the overrideHousehold to root

            // Add mesh names to XML
            comment = xmlDoc.CreateComment(" ******* Printed out house hold data. To activate the value, move the line into the override segment ******* ");
            rootNode.AppendChild(comment);
            XmlNode printHouseholdNode = xmlDoc.CreateElement(printHouseName);

            list = new SortedList <string, int>(DataStore.housePrintOutCache);
            foreach (string data in list.Keys)
            {
                XmlNode meshNameNode = xmlDoc.CreateElement(meshName);
                meshNameNode.InnerXml = data;
                attribute             = xmlDoc.CreateAttribute("value");
                int value = 1;
                DataStore.housePrintOutCache.TryGetValue(data, out value);
                attribute.Value = Convert.ToString(value);
                meshNameNode.Attributes.Append(attribute);
                printHouseholdNode.AppendChild(meshNameNode);
            }
            rootNode.AppendChild(printHouseholdNode); // Append the printHousehold to root

            // Add mesh names to XML
            list = new SortedList <string, int>(DataStore.bonusHouseholdCache);
            if (list.Keys.Count != 0)
            {
                XmlNode bonusHouseholdNode = xmlDoc.CreateElement(bonusHouseName);
                foreach (string data in list.Keys)
                {
                    XmlNode meshNameNode = xmlDoc.CreateElement(meshName);
                    meshNameNode.InnerXml = data;
                    attribute             = xmlDoc.CreateAttribute("value");
                    DataStore.bonusHouseholdCache.TryGetValue(data, out int value);
                    attribute.Value = Convert.ToString(value);
                    meshNameNode.Attributes.Append(attribute);
                    bonusHouseholdNode.AppendChild(meshNameNode);
                }
                rootNode.AppendChild(bonusHouseholdNode); // Append the bonusHousehold to root
            }

            // Add mesh names to XML for workers
            comment = xmlDoc.CreateComment(" ******* Worker data ******* ");
            rootNode.AppendChild(comment);
            XmlNode overrideWorkNode = xmlDoc.CreateElement(overrideWorkName);

            attribute       = xmlDoc.CreateAttribute("printWorkNames");
            attribute.Value = DataStore.printEmploymentNames ? "true" : "false";
            overrideWorkNode.Attributes.Append(attribute);
            attribute       = xmlDoc.CreateAttribute("mergeWorkNames");
            attribute.Value = DataStore.mergeEmploymentNames ? "true" : "false";
            overrideWorkNode.Attributes.Append(attribute);

            SortedList <string, int> wList = new SortedList <string, int>(DataStore.workerCache);

            foreach (string name in wList.Keys)
            {
                XmlNode meshNameNode = xmlDoc.CreateElement(meshName);
                meshNameNode.InnerXml = SecurityElement.Escape(name);
                int value = 1;
                DataStore.workerCache.TryGetValue(name, out value);
                attribute       = xmlDoc.CreateAttribute("value");
                attribute.Value = Convert.ToString(value);
                meshNameNode.Attributes.Append(attribute);
                overrideWorkNode.AppendChild(meshNameNode);
            }
            rootNode.AppendChild(overrideWorkNode); // Append the overrideWorkers to root

            // Add mesh names to dictionary
            comment = xmlDoc.CreateComment(" ******* Printed out worker data. To activate the value, move the line into the override segment ******* ");
            rootNode.AppendChild(comment);
            XmlNode printWorkNode = xmlDoc.CreateElement(printWorkName);

            wList = new SortedList <string, int>(DataStore.workerPrintOutCache);
            foreach (string data in wList.Keys)
            {
                if (!DataStore.workerCache.ContainsKey(data))
                {
                    XmlNode meshNameNode = xmlDoc.CreateElement(meshName);
                    meshNameNode.InnerXml = data;
                    DataStore.workerPrintOutCache.TryGetValue(data, out int value);
                    attribute       = xmlDoc.CreateAttribute("value");
                    attribute.Value = Convert.ToString(value);
                    meshNameNode.Attributes.Append(attribute);
                    printWorkNode.AppendChild(meshNameNode);
                }
            }
            rootNode.AppendChild(printWorkNode); // Append the printWorkers to root

            // Add mesh names to dictionary
            wList = new SortedList <string, int>(DataStore.bonusWorkerCache);
            if (wList.Keys.Count != 0)
            {
                XmlNode bonusWorkNode = xmlDoc.CreateElement(bonusWorkName);
                foreach (string data in wList.Keys)
                {
                    XmlNode meshNameNode = xmlDoc.CreateElement(meshName);
                    meshNameNode.InnerXml = data;
                    DataStore.bonusWorkerCache.TryGetValue(data, out int value);
                    attribute       = xmlDoc.CreateAttribute("value");
                    attribute.Value = Convert.ToString(value);
                    meshNameNode.Attributes.Append(attribute);
                    bonusWorkNode.AppendChild(meshNameNode);
                }
                rootNode.AppendChild(bonusWorkNode); // Append the bonusWorkers to root
            }

            try
            {
                if (File.Exists(fullPathFileName))
                {
                    if (File.Exists(fullPathFileName + ".bak"))
                    {
                        File.Delete(fullPathFileName + ".bak");
                    }

                    File.Move(fullPathFileName, fullPathFileName + ".bak");
                }
            }
            catch (Exception e)
            {
                Debugging.Message("PathFileName exception:\r\n" + e.ToString());
            }

            try
            {
                xmlDoc.Save(fullPathFileName);
            }
            catch (Exception e)
            {
                Debugging.Message("XML save exception:\r\n" + e.ToString());
                return(false);  // Only time when we say there's an error
            }

            return(true);
        } // end writeXML