protected override void SetVariables(ShipComponent result, CWNode node)
        {
            result.Size = node.GetKeyValue("size");
            node.ActOnKeyValues("power", power => result.Properties["Power"] = power);
            node.ActOnKeyValues("sensor_range", power => result.Properties["Sensor Range"] = power);
            node.ActOnKeyValues("hyperlane_range", power => result.Properties["Hyperlane Detection Range"] = power);
            node.ActOnNodes("ship_modifier", modifierNode => AddModifiers(result, modifierNode));

            result.ComponentSet = node.GetKeyValue("component_set");

            if (result.ComponentSet != null)
            {
                result.ComponentSetName        = LocalisationApiHelper.GetName(result.ComponentSet);
                result.ComponentSetDescription = LocalisationApiHelper.GetDescription(result.ComponentSet);
            }

            if (result.Icon.StartsWith("GFX_"))
            {
                result.Icon = result.Icon.Replace("GFX_", "");
            }

            // because afterburners decide to pluralise, for shits and giggles.
            if (result.Icon.Contains("ship_part_afterburner"))
            {
                result.Icon = result.Icon.Replace("ship_part_afterburner", "ship_part_afterburners");
            }

            // because computer icons have "_role_" for shits and giggles
            if (result.Icon.Contains("ship_part_computer_"))
            {
                result.Icon = "computers/" + (!result.Icon.Contains("ship_part_computer_default") ? result.Icon.Replace("ship_part_computer_", "ship_part_computer_role_") : result.Icon);
            }

            CWNode classRestriction = node.GetNode("class_restriction");

            // most power cores restricted by ship class
            if (classRestriction != null)
            {
                var classesThatUsePowerCore = classRestriction.Values.Select(x => LocalisationApiHelper.GetName(x)).StringJoin(" & ");
                result.Name = classesThatUsePowerCore + " " + result.Name;
            }
            else
            {
                // ion cannon by size
                node.ActOnNodes("size_restriction", sizeNode => {
                    var sizesThatUsePowerCore = sizeNode.Values.Select(x => LocalisationApiHelper.GetName(x)).StringJoin(" & ");
                    result.Name = sizesThatUsePowerCore + " " + result.Name;
                });
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Example of using the helpers to parse tech files.
        /// </summary>
        /// <param name="stellarisRoot">The root directory to Stellaris</param>
        /// <param name="modRoots">The root directory of any mods you also wish to use.  The mod list will be processed in the same way Stellaris would, with earlier mods in the list overriding later ones.  (Conflict resolution: first-in wins), thus suggest you use an ordered collection!</param>
        public static void Example(string stellarisRoot, string stellarisUserDirectory, string modConfigFilePath)
        {
            // Setting up mods
            // if you don't want mods, you can skip all this to the "ending mods" comment
            // These Steps will show you the steps you need to take to work with mods that you have installed in stellaris with a minimum amount of boilerplate.
            // There are several steps, where you will do different ones on different runs of the code

            // First: Get all mods you are using in Stellaris and write out to a file that can be easily edited.

            // Open that file in your favourite text editor and review the mods it has found
            // Set the "include" property to true for all the mods you want to parse
            // For mods that are sensible to group together (E.g. the various mods in the At War series or Zenith of Fallen Empires) set a mod group so they will get processed together.

            // Last step: run the program again, loading that file from disk and making the mod definitions.


            // Locate your mods.
            // These are all the mods configured in the Stellaris Launcher
            IList <ModDefinitionFile> stellarisModDefinitions = ModDirectoryHelper.LoadModDefinitions(stellarisUserDirectory);

            // Write a config file that you can edit.
            ModDirectoryHelper.WriteModInfoFile(modConfigFilePath, stellarisModDefinitions);

            // FIRST RUN: STOP HERE!  GO EDIT THE FILE YOU JUST CREATED.  Then remember to not run the load mods and write mod file on your next run, or you are going to overwrite your edits.

            // TODO write a "merge" tool that will take an existing config and a stellaris directory and add any mods missing to the config but not overwrite changes.

            // Load the mod configs
            // This will be all the mods, including ones with include : false as they get filtered later.
            List <ModInfo> modInfos = ModDirectoryHelper.ReadModInfoFile(modConfigFilePath);

            // now create StellarisDirectoryHelpers for accessing your mods.
            // this will handling extracting zip files for you
            // and will only work over mods you ahve set the include parameter on.
            // The force override flag determines whether a mod will be extracted from steam workshop event if it already exists in the temp directory
            // For the first run of a "session" as you are parsing i alwayus recommend setting to true, to make sure you get the latest mod data
            // If you are running multiple times in succession (e.g. debugging your app), then set to false to speed things up.
            IList <StellarisDirectoryHelper> modDirectoryHelpers = ModDirectoryHelper.CreateDirectoryHelpers(modInfos, true);



            // Done with all the preprocessing for mods now.


            // First job is to get a Directory Helper for Stellaris Root.
            // While at the moment I could get away with changing the API to simply take an IEnumerable that includes the main stellaris directory
            // I want to keep the door open for the time when the utilities have differing behaviour for the game directory and any mods

            // For ease there are overloaded constructors on all utilities that just take the root stellaris directory when you are not loading mods,
            // but this example will always use the full ones.
            // the utilities will also cope happily with null or empty mod collections.

            var stellarisDirectoryHelper = new StellarisDirectoryHelper(stellarisRoot);

            // create a localisation helper, need to specify the Language for this
            // this gives easy way to look up localised strings from ids
            // 2 methods: GetName and GetDescription
            // GetName: gets the direct value for a key
            // GetDescription: gets the value for key + "_desc" as its such a common operation it gets a helper.
            // both of these methods will follow any $OtherLocalisationString$ variables in the localisation file (and strip out comments) to generate a complete
            // non-variabled string but will not process formatting codes
            var localisationApiHelper = new LocalisationApiHelper(stellarisDirectoryHelper, modDirectoryHelpers, STLLang.English);

            // Numerous values in the game files make use of variables in the scriptedVariables folder.  e.g. @tier1cost1 for level 1 tech costs
            // The scripted variables accessor handles the converting of these into their actual values
            // If it cannot look up a value for a given request it returns the requesting key
            var scriptedVariableAccessor = new ScriptedVariableAccessor(stellarisDirectoryHelper, modDirectoryHelpers);


            // Create the main parser helper
            // You do not need to assign a scripted variables helper if you don't want to resolve variables.
            var cwParserHelper = new CWParserHelper(scriptedVariableAccessor);

            // parse over all the tech files and convert each teach into a basic descriptive string
            // am storing each tech in a dictionary to allow the mods (which process after main) to override values in the core game.
            var allDirectoryHelpers = StellarisDirectoryHelper.CreateCombinedList(stellarisDirectoryHelper, modDirectoryHelpers);
            var result = new Dictionary <string, string>();

            foreach (var directoryHelper in allDirectoryHelpers)
            {
                // use DirectoryWalker to find all tech files to process.  Do not want to process the tier or category files.
                List <FileInfo> techFiles = DirectoryWalker.FindFilesInDirectoryTree(directoryHelper.Technology, StellarisDirectoryHelper.TextMask, new [] { "00_tier.txt", "00_category.txt" });

                // each node is the contents of an individual file, keyed by file name
                IDictionary <string, CWNode> parsedTechFiles = cwParserHelper.ParseParadoxFiles(techFiles.Select(x => x.FullName).ToList());
                foreach (var fileAndContents in parsedTechFiles)
                {
                    // top level nodes are files, so we process the immediate children of each file, which is the individual techs.
                    foreach (var techNode in fileAndContents.Value.Nodes)
                    {
                        // extract some info about the tech and put it in a string
                        string techString = "[" + techNode.GetKeyValue("area") + "]" +
                                            "(" + (techNode.GetKeyValue("tier") ?? "0") + ") " +
                                            localisationApiHelper.GetName(techNode.Key) + ": " +
                                            localisationApiHelper.GetDescription(techNode.Key) +
                                            " (from: " + fileAndContents.Key + ")";
                        result[techNode.Key] = techString;
                    }
                }
            }

            // loop over and output
            result.Values.ForEach(Console.WriteLine);
        }
        private void Initialise(Entity entity, string filePath, string modName, string modGroup, CWNode node)
        {
            // not always using the node key, so use the id that was specified for the entity and trust that I got that right
            entity.Name        = LocalisationApiHelper.GetName(entity.Id);
            entity.Description = LocalisationApiHelper.GetDescription(entity.Id);
            entity.FilePath    = filePath;
            entity.Mod         = modName;
            entity.ModGroup    = modGroup;

            // if icon has been defined
            if (node.GetKeyValue("icon") != null)
            {
                entity.Icon = node.GetKeyValue("icon");
            }

            // if its a DLC item
            node.ActOnNodes("potential", potentialNode => {
                entity.DLC = potentialNode.GetKeyValue("host_has_dlc");
            });

            node.ActOnNodes("prerequisites", cwNode => entity.PrerequisiteIds = cwNode.Values, () => entity.PrerequisiteIds = new string[] {});

            node.ActOnNodes("modifier", modifierNode => AddModifiers(entity, modifierNode));

            if (entity is IGestaltAvailability iga)
            {
                var    potentialNodes = node.GetNodes("potential").ToList();
                CWNode machineNode    = potentialNodes.SearchNodes(new NodeSearchCriteria()
                {
                    KeyValue = new KeyValuePair <string, string>("has_authority", "auth_machine_intelligence")
                });
                if (machineNode != null)
                {
                    iga.Machines = CWNodeHelpers.ResolveBoolean(true, machineNode);
                }
                CWNode gestaltNode = potentialNodes.SearchNodes(new NodeSearchCriteria()
                {
                    KeyValue = new KeyValuePair <string, string>("has_ethic", "ethic_gestalt_consciousness")
                });
                if (gestaltNode != null)
                {
                    iga.Gestalt = CWNodeHelpers.ResolveBoolean(true, gestaltNode);
                }
                else
                {
                    CWNode gestaltNode2 = potentialNodes.SearchNodes(new NodeSearchCriteria()
                    {
                        KeyValue = new KeyValuePair <string, string>("is_gestalt", null)
                    });
                    if (gestaltNode2 != null)
                    {
                        var keyValue  = gestaltNode2.GetKeyValue("is_gestalt");
                        var boolValue = CWNodeHelpers.ResolveBooleanValue(keyValue);
                        if (boolValue.HasValue)
                        {
                            iga.Gestalt = CWNodeHelpers.ResolveBoolean(boolValue.Value, gestaltNode2);
                        }
                    }
                }
            }

            if (entity is IHasCost ihc)
            {
                node.ActOnNodes("resources", cwNode => {
                    cwNode.ActOnNodes("cost", costNode => costNode.KeyValues.ForEach(value => ihc.Cost[value.Key]     = value.Value.ToDouble()));
                    cwNode.ActOnNodes("upkeep", costNode => costNode.KeyValues.ForEach(value => ihc.Upkeep[value.Key] = value.Value.ToDouble()));
                });
            }
        }
Exemplo n.º 4
0
        protected override void SetVariables(Tech result, CWNode node)
        {
            TechArea area;
            string   areaKeyValue = node.GetKeyValue("area");

            if ("physics".Equals(areaKeyValue, StringComparison.OrdinalIgnoreCase))
            {
                area = TechArea.Physics;
            }
            else if ("society".Equals(areaKeyValue, StringComparison.OrdinalIgnoreCase))
            {
                area = TechArea.Society;
            }
            else if ("engineering".Equals(areaKeyValue, StringComparison.OrdinalIgnoreCase))
            {
                area = TechArea.Engineering;
            }
            else
            {
                throw new Exception("Unable to determine tech area for " + node.Key + " found " + areaKeyValue);
            }

            result.Area     = area;
            result.Tier     = node.GetKeyValueOrDefault("tier", "0").ToInt();
            result.BaseCost = node.GetKeyValueOrDefault("cost", "0").ToInt();

            //categories, usually only one, but can be more
            if (node.GetNode("category") != null)
            {
                result.Categories = node.GetNode("category").Values;
            }

            // interesting flags about the tech
            var techFlags = new List <TechFlag>();

            // rare purple tech
            if ("yes".Equals(node.GetKeyValue("is_rare"), StringComparison.InvariantCultureIgnoreCase))
            {
                techFlags.Add(TechFlag.Rare);
            }

            // starter technology
            if ("yes".Equals(node.GetKeyValue("start_tech"), StringComparison.InvariantCultureIgnoreCase))
            {
                techFlags.Add(TechFlag.Starter);
            }

            // may cause endgame crisis or AI revolution
            if ("yes".Equals(node.GetKeyValue("is_dangerous"), StringComparison.InvariantCultureIgnoreCase))
            {
                techFlags.Add(TechFlag.Dangerous);
            }

            // tech that requires an acquisition - base weight is 0
            // this is not foolproof, look up some other things
            if ("0".Equals(node.GetKeyValue("weight"), StringComparison.InvariantCultureIgnoreCase))
            {
                techFlags.Add(TechFlag.NonTechDependency);
            }
            else
            {
                // for some reason some tech has a weighting of 1, then a weight modifier that just sets it to 0.
                var weightNode = node.GetNode("weight_modifier");
                if (weightNode != null)
                {
                    var weightFactor = weightNode.GetKeyValue("factor");
                    if (weightFactor == "0" && !weightNode.Nodes.Any())
                    {
                        techFlags.Add(TechFlag.NonTechDependency);
                    }
                }
            }

            // fallen empire tech has a weight of 1 then a node that sets to 0 if you are not a fallen empire.
            // imperfect method for finding fallen empire tech that needs acquisition.
            if (node.GetRawKeyValue("tier") == "@fallentechtier" && node.GetRawKeyValue("cost") == "@fallentechcost")
            {
                techFlags.Add(TechFlag.NonTechDependency);
            }

            // tech that is repeatable
            if (node.GetKeyValue("cost_per_level") != null)
            {
                techFlags.Add(TechFlag.Repeatable);
            }

            result.Flags = techFlags;

            node.ActOnNodes("prereqfor_desc", cwNode => {
                var description = cwNode.GetKeyValue("desc");
                if (description != null)
                {
                    result.ExtraDesc = description;
                    result.ExtraName = cwNode.GetKeyValue("title");
                }
                else
                {
                    var subNode = cwNode.Nodes.FirstOrDefault();
                    if (subNode != null)
                    {
                        result.ExtraDesc = subNode.GetKeyValue("desc");;
                        result.ExtraName = subNode.GetKeyValue("title");
                    }
                }

                result.ExtraDesc = result.ExtraDesc != null ? LocalisationApiHelper.GetName(result.ExtraDesc) : null;
                result.ExtraName = result.ExtraName != null ? LocalisationApiHelper.GetName(result.ExtraName) : null;
            });
        }