diff --git a/.github/workflows/update-doc-and-samples.yml b/.github/workflows/update-doc-and-samples.yml index dabeb2c..df638fe 100644 --- a/.github/workflows/update-doc-and-samples.yml +++ b/.github/workflows/update-doc-and-samples.yml @@ -26,34 +26,21 @@ jobs: - name: Parse doc example run: > cargo run --release -- - -f="../doc/mod-menu.xml" + "../doc/mod-menu.xml" -o="../doc/mod-menu.ws" - -p="MOD" -p="mod_" - -m="MyModSettings" - -v="1.23" - --option-parsing-mode=enums working-directory: settings-parser - name: Parse DifficultyMod sample run: > cargo run --release -- - -f="../samples/DifficultyMod/bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml" + "../samples/DifficultyMod/bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml" -o="../samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws" - -m="ModDifficultySettingsBase" - -p="DM" - --default-preset-keyword="DEFAULT" - -v="1.1" --no-getter working-directory: settings-parser - name: Parse MonsterOfTheWeek sample run: > cargo run --release -- - -f="../samples/MonsterOfTheWeek/bin/config/r4game/user_config_matrix/pc/SampleMonsterOfTheWeek.xml" + "../samples/MonsterOfTheWeek/bin/config/r4game/user_config_matrix/pc/SampleMonsterOfTheWeek.xml" -o="../samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week_settings.ws" - -m="MonsterOfTheWeekSettings" - -p="MOTW" - -p="motw" - -v="1.0" - --option-parsing-mode=enums working-directory: settings-parser - name: CLI specification run: | diff --git a/README.md b/README.md index 6cec13a..f7d6bf0 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,14 @@ Framework for modding Witcher 3 that simplifies the pipeline of using mod settin ## Overview Witcher 3 allows for creating custom mod menus which provide an interface between the mod developer and the end user to further customize their experience. The way settings are accessed in game's scripts is not complicated, but can often result in very boilerplaty code and situations when settings can be fetched improperly simply due to some typo. This framework is trying to midigate that. -First part of this framwork is the menu xml parser. It turns the mod menu xml into WitcherScript code which mirrors the structure of customisable variables in the xml and assures on compile time that the developer uses their variables properly - no way for typos or bad type cast. +Framework provides xml parser program. It generates WitcherScript code which mirrors the structure of customisable variables in the xml and assures on compile time that the developer uses their variables properly - no way for typos, bad type cast or other headaches. -Second part of this framework is WitcherScript code that updates generated by parser settings class and even notifies you about it. ## Instructions for mod users 1. Check for [framework version](#framework-version-support) you need 2. Go to the [releases page](https://github.com/SpontanCombust/tw3-settings-framework/releases) -3. Download `TW3_Mod_Settings_Framework_modSettingsFramework.zip` from the newest version or version specified by the developer +3. Download `TW3_Mod_Settings_Framework_modSettingsFramework.zip` dependency from the newest version or version specified by the developer 4. Install it like any other Witcher 3 mod by dropping what's inside into your `Mods` folder 5. Use Script Merger to solve any conflicts @@ -44,12 +43,13 @@ Second part of this framework is WitcherScript code that updates generated by pa 3. Download `TW3_Mod_Settings_Framework_Parser.zip` and unpack it anywhere. Use the `settings_parser.exe` program with the menu xml of your mod ```shell -./settings_parser -f ../../doc/mod-menu.xml -m MyModSettings -v 1.23 --omit-prefix=MOD +./settings_parser "../../doc/mod-menu.xml" Group MODtab2 at line 40, column 6 has no vars and will be ignored. Successfully parsed ../../doc/mod-menu.xml into ../../doc/mod-menu.ws ``` -Parser at minimum takes a path to the menu xml file (`-f` flag) and a name you wish your settings class to have (`-m` flag). -To see all the possible options that can be used with the parser use the `--help` (shorhand `-h`) option or check the latest [parser CLI specification](doc/cli_specification.md). +Parser can generate WitcherScript by the means of simply drag-and-dropping the XML file onto exe. It is however recommended to use it with some kind of command line prompt to see any warnings or errors it might return. To see all the possible options that can be used with the parser use the `--help` (shorhand `-h`) option or check the latest [parser CLI specification](doc/cli_specification.md). + +Since version v0.6 most of the data parser needs is retrieved directly from the XML based on custom attributes. List of these attributes can be found in [xml specification](doc/xml_specification.md). [Example mod xml](doc/mod-menu.xml) @@ -100,14 +100,20 @@ The most common usage of this would be overriding `ReadSettings()` method to run ## Remarks ### Framework version support: -- 0.4+ for game version 4.04 +- 0.4.0 - 0.6.0 for game version 4.04 - 0.3.0 - 0.3.1 for game version 4.03 - 0.1.0 - 0.2.0 for game version 1.32 (requires [Community Patch - Base](https://www.nexusmods.com/witcher3/mods/3652)) +### Migrating from version v0.5 to v0.6 and beyond (for developers) +Script files generated by pre-v0.6 version parsers and therefore mods using them are not compatible with the current version of `modSettingsFramework` and can't be mixed. +If you're a mod creator, please reparse you XMLs for this version. +Also, most of the data that previously had to be passed into the CLI now has to be put directly in the XML. Therefore the process of parsing said file has been changed to some degree. Check [details](doc/details.md) and [xml specification](doc/xml_specification.md) for more information about that. ## Documentation [Further reading](doc/details.md) +[XML specification](doc/xml_specification.md) + [WitcherScript class specification](doc/class_specification.md) [Parser CLI specification](doc/cli_specification.md) diff --git a/doc/class_specification.md b/doc/class_specification.md index 86f4d70..ce43290 100644 --- a/doc/class_specification.md +++ b/doc/class_specification.md @@ -1,17 +1,16 @@ # Class specification - -## [ISettingsGroup](../modSettingsFramework/content/scripts/local/settings_group.ws) -Abstract base class which is an analogue to settings groups in XML. Child classes generated by the parser store settings variables. +## [`CSettingsMasterRegistry`](../modSettingsFramework/content/scripts/local/settings_master_registry.ws) +Class that contains all settings master objects and updates them when necessary. ### Public member constants -- `id: name` - value of the id attribute for the group in the XML. -- `defaultPresetIndex: int` - value of the default preset used by the given group. By default it's 0. To see how to instruct the CLI to deduce default presets refer to [CLI specification](cli_specification.md). +- `FRAMEWORK_VERSION: name` - version of the framework ### Public member functions -- `Init(parent_: ISettingsMaster) : void` - used internally. -- `Reset(presetIndex: int) : void` - applies a preset with given id. Automatically updates settings class to reflect this. -- `ResetToDefault() : void` - calls Reset() with defaultPresetIndex. +- `AddSettings(settingsMaster : ISettingsMaster, id : name): void` - adds a settings master object to the registry and initialises it. The 'id' parameter is used to identify said object later. +- `GetSettings(id : name) : ISettingsMaster` - returns stored settings master object or NULL if it can't find any with this id. +- `RemoveSettings(id : name) : void` - removes settings master object from the registry. +- `ReadAllSettings() : void` - reads settings values from user config into stored settings master objects. ## [`ISettingsMaster`](../modSettingsFramework/content/scripts/local/settings_master.ws) @@ -19,14 +18,34 @@ Abstract base class for the settings class generated by the parser. The child cl ### Public member constants - `modVersion: string` - arbitrary version string that can be passed during parsing. +- `id: name` - arbitrary identifier of the settings master object. Used by the registry to differentiate between them. ### Public member functions - `Init() : void` - initializes settings groups, reads data from config and optionally resets this data to default if your mod has just been installed. -- `ReadSettings() : void` - reads the data from game's configuration into your settings object. -- `WriteSettings() : void` - writes the data from your settings object into game's configuration. -- `ValidateSettings(): void` - checks all fields in the settings object and corrects their values so they adhere to the limits set in the XML, e.g. if the value of a variable corresponding to a slider config is within the correct range. -- `ResetSettingsToDefault() : void` - applies default presets to all groups. +- `ReadSettings() : void` - calls Read() on all group objects. +- `WriteSettings() : void` - calls Write() on all group objects and saves data to disk. +- `ValidateSettings(): void` - calls Validate() on all group objects. +- `ResetSettingsToDefault() : void` - applies default presets to all groups and saves data to disk. - `ShouldResetSettingsToDefaultOnInit() : bool` - a condition telling the class whether it should use ResetSettingsToDefault on Init. By default it checks whether GetVarValue() for a random (in reality the first one) var from the xml returns "". - `ReadSettingValue(config: CInGameConfigWrapper, groupId: name, varId: name) : string` - method used by ReadSettings to retrieve values from game config. By default it used CInGameConfigWrapper directly. - `WriteSettingValue(config: CInGameConfigWrapper, groupId: name, varId: name, value: string) : void` - method used by WriteSettings to write values into game config. By default it used CInGameConfigWrapper directly. - `ResetSettingValues(config: CInGameConfigWrapper, groupId: name, presetIndex: int) : void` - method used by ISettingsGroup's Reset method to apply a preset. By default it used CInGameConfigWrapper directly. + + +## [ISettingsGroup](../modSettingsFramework/content/scripts/local/settings_group.ws) +Abstract base class which is an analogue to settings groups in XML. Child classes generated by the parser store settings variables. + +### Public member constants +- `id: name` - value of the id attribute for the group in the XML. +- `defaultPresetIndex: int` - value of the default preset used by the given group. By default it's 0. To see how to instruct the parser deduce default presets refer to [XML specification](./xml_specification.md). + +### Public member functions +- `Init(parent_: ISettingsMaster) : void` - used internally. +- `ValidateSettings() : void` - checks all fields and corrects their values so they adhere to the limits set in the XML, e.g. if the value of a variable corresponding to a slider config is within the correct range. +- `ReadSettings(optional config: CInGameConfigWrapper) : void` - reads the data from game's configuration. +- `WriteSettings(shouldSave: bool, optional config: CInGameConfigWrapper) : void` - writes the data into game's configuration. If 'shouldSave' is true saved the data to disk. +- `ResetSettings(presetIndex: int, shouldSave: bool, optional config: CInGameConfigWrapper) : void` - applies a preset with given id. Automatically updates settings class to reflect this. If 'shouldSave' is true saved the data to disk. +- `ResetSettingsToDefault() : void` - calls Reset() with defaultPresetIndex. +- `EnumValueMappingConfigToUnified(vId: name, val: int) : int` - returns integer value of the unified enum type for options var index in user config. If the config value is not valid for given option, should return -1. More about unified enums in [details](./details.md). +- `EnumValueMappingUnifiedToConfig(vId: name, val: int) : int` - returns the options var index in user config for integer value of unified enum. If the unified value is not valid for given option, should return -1. More about unified enums in [details](./details.md). +- `EnumValueMappingValidateUnified(vId: name, val: int) : int` - If integer value for given enum variable is correct returns said value. Otherwise returns the smallest valid value. More about unified enums in [details](./details.md). diff --git a/doc/cli_specification.md b/doc/cli_specification.md index 9e290cc..59f5d51 100644 --- a/doc/cli_specification.md +++ b/doc/cli_specification.md @@ -1,58 +1,21 @@ ``` -TW3 Settings Framework Parser 0.5.0 +TW3 Settings Framework Parser 0.6.0 Parses a mod menu XML file and outputs witcher script code representing settings of this menu USAGE: - settings_parser [OPTIONS] --file --master + settings_parser [OPTIONS] -OPTIONS: - -f, --file - Path to the menu xml file. (REQUIRED) - - -m, --master - Name to use for the settings master class. (REQUIRED) - - -v, --mod-version - Version of the mod in format. Format is arbitrary, but preferably a real number - [default: 1.0] +ARGS: + Path to the menu xml file. (REQUIRED) +OPTIONS: -o, --output Path of the WitcherScipt output file, by default it's made from the menu xml file name in the same directory - -p, --omit-prefix - Prefix to omit from groups and vars when generating code. Case sensitive. Possible - multiple cases - - --default-preset-keyword - Keyword used in default presets' display_name. Used to deduce IDs of default presets for - config groups so they can be used in ResetToDefault() methods. If won't find default - preset or any preset at that will use 0 as the preset ID. Case insensitive [default: - default] - - --option-parsing-mode - Controls how OPTION type vars are parsed into WitcherScript - - ints: - Treats options vars as regular ints instead of creating custom enum types for them. - This essentially means the behaviour from before v0.5. - - enums: - Parses options vars into enums. Then tries to find vars that have the same set of - displayName attributes in option node - and assigns them one common type. - Requires that displayNames of all option nodes contain some prefix that determines their - relation. - If two option arrays contain the same set of possible values they are considered to have - the same enum type. - - enums-strict: - Parses options vars into enums with an exception that having mutliple option arrays - designated by the same prefix - but having different sets of values is disallowed. This prevents possible user mistakes - from happening. [default: enums] [possible values: ints, enums, enums-strict] - - --no-var-validation - Disables the generation of code for value correction. After reading from or before - writing to user config values will no longer be checked if they adhere to the XML, e.g. - if slider value is in a specified range + --strict-enums + Causes the parser to throw an error if it will find occurances options that would + generate unified enum type. More about unified enums in `doc/details.md` --no-getter Prevents the settings object getter convenience function from being generated diff --git a/doc/details.md b/doc/details.md index 750c0e7..12a5d48 100644 --- a/doc/details.md +++ b/doc/details.md @@ -4,25 +4,46 @@ Var's displayType and some other factors determine what type does the corresponding variable in WitcherScript take: - **TOGGLE** -> `bool`, - **SLIDER** -> `int` or `float` depending on whether said slider can yield fractional numbers, for example "SLIDER;0;100;100" will be assigned int type, because value step is equal to 1 and slider can yield only integer values, but "SLIDER;0;100;200" will be assigned float type, because it can yield non-integer values like 0.5, -- **OPTIONS** -> `int` or custom `enum` type depending on `--option-parsing-mode` option in CLI. More about it [here](#a-word-or-two-about-options), +- **OPTIONS** -> `int` or custom `enum` type depending on `msfIsEnum` value. More about it in [enums](#enums) section, - **SUBTLE_SEPARATOR** -> vars with this type are ignored in the process of parsing to WitcherScript. -## A word or two about parsing options +## Custom XML data +The game reads XML config files and takes only the data that it needs without applying strict schema rules onto them. What this means is that alongside the well known data that the game expects we can put extra data that only the framework's parser needs without risking the game to throw any errors. + +Most of the data that has previously been passed into the parser through CLI now is done by using custom XML attributes. +The full specification describing it together with which attributes are necessary can be found in [xml specification](./xml_specification.md). + + +## Default values on first use +When initialising the settings for your mod for the very first time in game the framework applies a default preset for each settings Group. Therefore if you want a specific set of values to be set you should create PresetsArrays for your Groups. By default the preset with index 0 is picked. If you want other one to be the default, use `msfDefault` attribute in PresetsArray node. + +## Var validation +After reading from and before writing to user configuration during the game values of the parsed class are corrected to adhere to their XML constraints, for example a variable corresponding to the slider var in XML will have its value clamped between minimal and maximal possible values. +It is possible to disable this validation for the entire class or singular groups and vars. To do it use the `msfValidate` attribute. + + +## Enums ### Basics Since version v0.5 of the framework the parser can generate enum types based on "OPTIONS" type vars in config xml. General rules on how the parser does this: -1. `displayName` attributes in each Option node are checked and a common prefix is obtained if possible -2. Name of the enum type is constructed as such: `{SettingsMasterName}_{CommonDisplayNamePrefix}` if the common prefix exists. If it does not the `id` attribute of var is used: `{SettingsMasterName}_{VarId}` -3. Enum values' names are obtained as such: `{EnumTypeName}{Suffix}` where `Suffix` is the remaining part of `displayName` without the common prefix. +- The old way: + 1. `displayName` attributes in each Option node are checked and a common prefix is obtained if possible. + 2. Name of the enum type is constructed as such: `{SettingsMasterName}_{CommonDisplayNamePrefix}` if the common prefix exists. Not having such prefix leads to an error. + 3. Enum values' names are obtained as such: `{EnumTypeName}{Suffix}` where `Suffix` is the remaining part of `displayName` without the common prefix. + +When `id`s and `displayName`s are parsed, their beginnings are stripped with values from `msfPrefix` attribute (if any is specified). + +- The new way using custom attributes: + 1. Name enum type in OptionsArray node using `msfEnum="EDifficulty"` + 2. Name enum value suffixes in subsequent Option nodes using `msfEnumValue=Easy`, `msfEnumValue=Hard` etc. -When `id`s and `displayName`s are parsed values from the `--omit-prefix` CLI option are also applied. Considering the fact that multiple options can have the same or similar set of possible values a few features have been put in place: 1. For options with the same deduced enum type only one enum definition is generated -2. When `--option-parsing-mode` CLI option takes `enums-strict` value all xml options that have the same common prefix need to have the exact same set of possible values in the same order. -3. When `--option-parsing-mode` CLI option takes `enums` value (which is the default) and multiple options have the same deduced type, but different sets of values, a [unified](#unified-enums) enum is constructed. +2. If `--strict-enums` CLI flag is enabled all xml options that have the same common prefix need to have the exact same set of possible values in the same order. +3. If `--strict-enums` CLI flag is not enabled (which is the default) and multiple options have the same deduced type, but different sets of values, a [unified](#unified-enums) enum is constructed. ### Unified enums Unified enums are what this framework calls enum types that are assigned to options that share the same common prefix in their possible values. Example: let's say we have bunch of options that dictate the "quality" of graphics. Possible values in total are "Low", "Medium", "High" and "Ultra". Not all settings might need to use all of them. Some of them may only go up to "High" and others might start from "Medium". All of them however would be attributed the same enum type in the WitcherScript. So this feature allows all of these settings to be handled using the same enum type. @@ -30,4 +51,30 @@ Example of unified enums can be found in [Monster of the Week](../samples/Monste If a variable of a unified enum type in WitcherScript gets assigned a value it is not supposed to take (e.g. a setting that cannot have "Low" quality gets assigned such) before this value will be saved into user config it will be corrected in the `ValidateSettings` function. The current behaviour is to assign it the first valid value (in this case "Medium" quality). -If a unified enum type exists for the settings class, an extra set of functions are generated, which names start with `EnumValueMapping`. They essentially make all of this just work and allow the conversion from user config integer value to enum value in WitcherScript and vice versa. \ No newline at end of file +If a unified enum type exists for the settings class, an extra set of functions are generated, which names start with `EnumValueMapping`. They essentially make all of this just work and allow the conversion from user config integer value to enum value in WitcherScript and vice versa. + + +## Breaking changes + +### v0.6 +- XML + - some custom attributes are required to successfully parse the document (see [Custom XML data](#custom-xml-data)) +- CLI + - removed `--file` argument, replaced it with a positional (you only need to input the XML path itself) + - removed `--master` argument + - removed `--mod-version` argument + - removed `--omit-prefix` argument + - removed `--default-preset-keyword` argument + - removed `--option-parsing-mode` argument, added `--strict-enums` flag in its place + - removed ` --no-var-validation` argument +- WitcherScript + - renamed `Reset` function in `ISettingsGroup` to `ResetSettings` + - renamed `ResetToDefault` function in `ISettingsGroup` to `ResetSettingsToDefault` + - moved `StringToBool` and `BoolToString` from `ISettingsMaster` to `ISettingsGroup` + - removed `SSettingsMasterRegistryEntry` struct type + - heavily modified how parsed classes look + +### v0.2 +- WitcherScript + - removed `ISettingsReadListener` class + - removed `AddReadListener` function from `CSettingsMasterRegistry` \ No newline at end of file diff --git a/doc/mod-menu.ws b/doc/mod-menu.ws index ee30257..f333bc2 100644 --- a/doc/mod-menu.ws +++ b/doc/mod-menu.ws @@ -1,86 +1,31 @@ -// Code generated using Mod Settings Framework v0.5.0 by SpontanCombust & Aeltoth +// Code generated using Mod Settings Framework v0.6.0 by SpontanCombust & Aeltoth class MyModSettings extends ISettingsMaster { default modVersion = "1.23"; public var tab1 : MyModSettings_tab1; - public var tab2subtab1 : MyModSettings_tab2subtab1; - public var tab2subtab2 : MyModSettings_tab2subtab2; + public var tab2 : MyModSettings_tab2; + public var tab3 : MyModSettings_tab3; - public /* override */ function Init() : void + protected /* override */ function Parser_Init() : void { - tab1 = new MyModSettings_tab1 in this; tab1.Init(this); - tab2subtab1 = new MyModSettings_tab2subtab1 in this; tab2subtab1.Init(this); - tab2subtab2 = new MyModSettings_tab2subtab2 in this; tab2subtab2.Init(this); + tab1 = new MyModSettings_tab1 in this; + tab1.Init(this); + m_groups.PushBack(tab1); - super.Init(); - } - - public /* override */ function ValidateSettings() : void - { - tab1.option = (MyModSettings_opt)Clamp((int)tab1.option, 0, 2); - tab1.sliderFloat = ClampF(tab1.sliderFloat, 0, 1); - tab1.sliderInt = Clamp(tab1.sliderInt, 0, 100); - tab1.version = ClampF(tab1.version, 0, 100); - - tab2subtab1.anotherSlider = ClampF(tab2subtab1.anotherSlider, -100, 100); + tab2 = new MyModSettings_tab2 in this; + tab2.Init(this); + m_groups.PushBack(tab2); - super.ValidateSettings(); + tab3 = new MyModSettings_tab3 in this; + tab3.Init(this); + m_groups.PushBack(tab3); } - public /* override */ function ReadSettings() : void + protected /* override */ function Parser_ShouldResetSettingsToDefaultOnInit(config : CInGameConfigWrapper) : bool { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - tab1.option = (MyModSettings_opt)StringToInt(ReadSettingValue(config, 'MODtab1', 'MODoption'), 0); - tab1.sliderFloat = StringToFloat(ReadSettingValue(config, 'MODtab1', 'MODsliderFloat'), 0.0); - tab1.sliderInt = StringToInt(ReadSettingValue(config, 'MODtab1', 'MODsliderInt'), 0); - tab1.toggle = StringToBool(ReadSettingValue(config, 'MODtab1', 'MODtoggle')); - tab1.version = StringToFloat(ReadSettingValue(config, 'MODtab1', 'MODversion'), 0.0); - - tab2subtab1.anotherSlider = StringToFloat(ReadSettingValue(config, 'MODtab2subtab1', 'anotherSlider'), 0.0); - - tab2subtab2.anotherToggle = StringToBool(ReadSettingValue(config, 'MODtab2subtab2', 'anotherToggle')); - - this.ValidateSettings(); - super.ReadSettings(); - } - - public /* override */ function WriteSettings() : void - { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - this.ValidateSettings(); - - WriteSettingValue(config, 'MODtab1', 'MODoption', IntToString((int)tab1.option)); - WriteSettingValue(config, 'MODtab1', 'MODsliderFloat', FloatToString(tab1.sliderFloat)); - WriteSettingValue(config, 'MODtab1', 'MODsliderInt', IntToString(tab1.sliderInt)); - WriteSettingValue(config, 'MODtab1', 'MODtoggle', BoolToString(tab1.toggle)); - WriteSettingValue(config, 'MODtab1', 'MODversion', FloatToString(tab1.version)); - - WriteSettingValue(config, 'MODtab2subtab1', 'anotherSlider', FloatToString(tab2subtab1.anotherSlider)); - - WriteSettingValue(config, 'MODtab2subtab2', 'anotherToggle', BoolToString(tab2subtab2.anotherToggle)); - - super.WriteSettings(); - } - - public /* override */ function ResetSettingsToDefault() : void - { - tab1.ResetToDefault(); - tab2subtab1.ResetToDefault(); - tab2subtab2.ResetToDefault(); - } - - public /* override */ function ShouldResetSettingsToDefaultOnInit() : bool - { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - return config.GetVarValue('MODtab1','MODoption') == ""; + return ReadSettingValue(config, 'MODtab1','MODoption') == "-1"; } } @@ -94,22 +39,77 @@ class MyModSettings_tab1 extends ISettingsGroup default id = 'MODtab1'; default defaultPresetIndex = 1; + + protected /* override */ function Parser_ValidateSettings() : void + { + option = (MyModSettings_opt)Clamp((int)option, 0, 2); + sliderFloat = ClampF(sliderFloat, 0, 1); + sliderInt = Clamp(sliderInt, 0, 100); + version = ClampF(version, 0, 100); + } + + protected /* override */ function Parser_ReadSettings(config: CInGameConfigWrapper) : void + { + option = (MyModSettings_opt)ReadIntSettingValue(config, 'MODoption'); + sliderFloat = ReadFloatSettingValue(config, 'MODslider1'); + sliderInt = ReadIntSettingValue(config, 'MODslider2'); + toggle = ReadBoolSettingValue(config, 'MODtoggle'); + version = ReadFloatSettingValue(config, 'MODversion'); + } + + protected /* override */ function Parser_WriteSettings(config: CInGameConfigWrapper) : void + { + WriteIntSettingValue(config, 'MODoption', (int)option); + WriteFloatSettingValue(config, 'MODslider1', sliderFloat); + WriteIntSettingValue(config, 'MODslider2', sliderInt); + WriteBoolSettingValue(config, 'MODtoggle', toggle); + WriteFloatSettingValue(config, 'MODversion', version); + } } -class MyModSettings_tab2subtab1 extends ISettingsGroup +class MyModSettings_tab2 extends ISettingsGroup { public var anotherSlider : float; default id = 'MODtab2subtab1'; default defaultPresetIndex = 0; + + protected /* override */ function Parser_ValidateSettings() : void + { + anotherSlider = ClampF(anotherSlider, -100, 100); + } + + protected /* override */ function Parser_ReadSettings(config: CInGameConfigWrapper) : void + { + anotherSlider = ReadFloatSettingValue(config, 'anotherSlider'); + } + + protected /* override */ function Parser_WriteSettings(config: CInGameConfigWrapper) : void + { + WriteFloatSettingValue(config, 'anotherSlider', anotherSlider); + } } -class MyModSettings_tab2subtab2 extends ISettingsGroup +class MyModSettings_tab3 extends ISettingsGroup { public var anotherToggle : bool; default id = 'MODtab2subtab2'; default defaultPresetIndex = 0; + + protected /* override */ function Parser_ValidateSettings() : void + { + } + + protected /* override */ function Parser_ReadSettings(config: CInGameConfigWrapper) : void + { + anotherToggle = ReadBoolSettingValue(config, 'anotherToggle'); + } + + protected /* override */ function Parser_WriteSettings(config: CInGameConfigWrapper) : void + { + WriteBoolSettingValue(config, 'anotherToggle', anotherToggle); + } } enum MyModSettings_opt diff --git a/doc/mod-menu.xml b/doc/mod-menu.xml index a0ce421..bb7dd16 100644 --- a/doc/mod-menu.xml +++ b/doc/mod-menu.xml @@ -1,14 +1,14 @@ - + - + - + @@ -29,8 +29,8 @@ - - + + @@ -40,12 +40,12 @@ - + - + diff --git a/doc/xml_specification.md b/doc/xml_specification.md new file mode 100644 index 0000000..3f4a51d --- /dev/null +++ b/doc/xml_specification.md @@ -0,0 +1,26 @@ +# XML specification +This document lists all the custom attribute data that the parser expects to find inside configuration menu XML file. + +- **UserConfig**: + - `msfClass` (string) * - name of the settings master class, + - `msfVersion` (string) - version of the mod; format is arbitrary, but preferably a real number [default: 1.0], + - `msfPrefix` (string) - determines the mod prefix to be omitted from id and displayName attributes when parsing them into names used by generated class (e.g. if Var's 'id' is "MODslider" and the prefix is "MOD", variable in WitcherScript will be called "slider"); case sensitive, multiple values can be given by using semicolon (;) as delimiter; does not apply to any other custom framework attributes, such as `msfVariable`, + - `msfValidate` (bool) - determines whether validation code of underlying groups should be generated [default: "true"] +- **Group**: + - `msfVariable` (string) - custom name of the instance of settings group in WS, by default this name is obtained from 'id' attribute, + - `msfIgnore` (bool) - determines whether the group should be ignored or not [default: "false"] + - `msfValidate` (bool) - determines whether validation code of underlying vars should be generated [default: value inherited from parent UserConfig] +- **Var** + - `msfVariable` (string) - custom name of the instance of settings variable in WS, by default this name is obtained from 'id' attribute, + - `msfIgnore` (bool) - determines whether the var should be ignored or not [default: "false"] + - `msfValidate` (bool) - determines whether validation code for this var should be generated [default: value inherited from parent Group] +- **OptionsArray** + - `msfIsEnum` (bool) - determines whether this OptionsArray should be parsed as enum or int type [default: "true"] + - `msfEnum` (string) ** - custom name of the enum type, by default it is made as {SettingsMasterClass}_{CommonDisplayNamePrefix}, where 'CommonDisplayNamePrefix' is the common beginning part of displayName attributes in subject Option nodes; if there is no common prefix between displayNames in Options this attribute is required; ignored if `msfIsEnum` is "false"; more about parsing enums in [details](./details.md), +- **Option** + - `msfEnumValue` (string) ** - custom suffix for the enum value if `msfEnum` is specified; by default these values are made as {SettingsMasterClass}_{displayName}, +- **PresetsArray** + - `msfDefault` (int) - index of the default preset [default: 0]. + +\* - required
+\*\* - required conditionally \ No newline at end of file diff --git a/modSettingsFramework/content/scripts/local/settings_group.ws b/modSettingsFramework/content/scripts/local/settings_group.ws index 83eed34..006c09d 100644 --- a/modSettingsFramework/content/scripts/local/settings_group.ws +++ b/modSettingsFramework/content/scripts/local/settings_group.ws @@ -7,25 +7,160 @@ abstract class ISettingsGroup public const var defaultPresetIndex: int; + // ===================================== Main functions ======================================= + + // Prepares the object public function Init(parent_: ISettingsMaster) : void { m_parentMaster = parent_; } - public function Reset(presetIndex: int) : void + // Corrects values to ranges specified in the xml + public function ValidateSettings(): void + { + LogChannel('ModSettingsFramework', "Validating settings for group '" + id + "'"); + Parser_ValidateSettings(); + } + + // Reads all settings from CInGameConfigWrapper using ReadSettingValue and sets class variables + public function ReadSettings(optional config: CInGameConfigWrapper) : void + { + if (!config) + config = theGame.GetInGameConfigWrapper(); + + LogChannel('ModSettingsFramework', "Reading settings for group '" + id + "'"); + Parser_ReadSettings(config); + ValidateSettings(); + } + + // Using class variables and WriteSettingValue sets all settings in CInGameConfigWrapper and saves user configuration + public function WriteSettings(shouldSave: bool, optional config: CInGameConfigWrapper) : void { - var config: CInGameConfigWrapper; + if (!config) + config = theGame.GetInGameConfigWrapper(); - config = theGame.GetInGameConfigWrapper(); + LogChannel('ModSettingsFramework', "Writing settings for group '" + id + "'"); + ValidateSettings(); + Parser_WriteSettings(config); + + if (shouldSave) + theGame.SaveUserSettings(); + } + + // Applies a preset + public function ResetSettings(presetIndex: int, shouldSave: bool, optional config: CInGameConfigWrapper) : void + { + if (!config) + config = theGame.GetInGameConfigWrapper(); + LogChannel('ModSettingsFramework', "Resetting settings for group '" + id + "'" + " to preset " + presetIndex); m_parentMaster.ResetSettingValues(config, id, presetIndex); - //TODO add parameter that says whether this should be done (if all groups are reset it is needlessly done multiple times) - theGame.SaveUserSettings(); - m_parentMaster.ReadSettings(); // get preset values back from config + ReadSettings(config); // get preset values back from config + + if (shouldSave) + theGame.SaveUserSettings(); + } + + // Applies a default preset + public function ResetSettingsToDefault(shouldSave: bool, optional config: CInGameConfigWrapper) : void + { + ResetSettings(defaultPresetIndex, shouldSave, config); + } + + // Returns integer value of the unified enum type for options var index in user config + // If the config value is not valid for given option, should return -1 + public function EnumValueMappingConfigToUnified(vId: name, val: int) : int + { + return Parser_EnumValueMappingConfigToUnified(vId, val); + } + + // Returns the options var index in user config for integer value of unified enum + // If the unified value is not valid for given option, should return -1 + public function EnumValueMappingUnifiedToConfig(vId: name, val: int) : int + { + return Parser_EnumValueMappingUnifiedToConfig(vId, val); + } + + // If integer value for given enum variable is correct returns said value + // Otherwise returns the smallest valid value + public function EnumValueMappingValidateUnified(vId: name, val: int) : int + { + return Parser_EnumValueMappingValidateUnified(vId, val); + } + + + + // ====================== Functions to be defined in class generated by parser ====================== + + protected function Parser_ValidateSettings(): void {} + protected function Parser_ReadSettings(config: CInGameConfigWrapper) : void {} + protected function Parser_WriteSettings(config: CInGameConfigWrapper) : void {} + protected function Parser_EnumValueMappingConfigToUnified(vId: name, val: int) : int { return -1; } + protected function Parser_EnumValueMappingUnifiedToConfig(vId: name, val: int) : int { return -1; } + protected function Parser_EnumValueMappingValidateUnified(vId: name, val: int) : int { return 0; } + + + + // ====================== Utility functions ====================== + + // these bool conversion functions are here for sanity sake, + // because an implicit conversion from string to bool doesn't sit right with me + protected function StringToBool(s: string) : bool + { + if(s == "false" || s == "" || !s) { + return false; + } else { + return true; + } + } + + protected function BoolToString(b: bool) : string + { + if(b) { + return "true"; + } else { + return "false"; + } + } + + protected function ReadIntSettingValue(config: CInGameConfigWrapper, vId: name) : int + { + return StringToInt(m_parentMaster.ReadSettingValue(config, this.id, vId), 0); + } + + protected function ReadFloatSettingValue(config: CInGameConfigWrapper, vId: name) : float + { + return StringToFloat(m_parentMaster.ReadSettingValue(config, this.id, vId), 0.0); + } + + protected function ReadBoolSettingValue(config: CInGameConfigWrapper, vId: name) : bool + { + return StringToBool(m_parentMaster.ReadSettingValue(config, this.id, vId)); + } + + protected function ReadUnifiedEnumSettingValue(config: CInGameConfigWrapper, vId: name) : int + { + return EnumValueMappingConfigToUnified(vId, ReadIntSettingValue(config, vId)); + } + + + protected function WriteIntSettingValue(config: CInGameConfigWrapper, vId: name, value: int) : void + { + m_parentMaster.WriteSettingValue(config, this.id, vId, IntToString(value)); + } + + protected function WriteFloatSettingValue(config: CInGameConfigWrapper, vId: name, value: float) : void + { + m_parentMaster.WriteSettingValue(config, this.id, vId, FloatToString(value)); + } + + protected function WriteBoolSettingValue(config: CInGameConfigWrapper, vId: name, value: bool) : void + { + m_parentMaster.WriteSettingValue(config, this.id, vId, BoolToString(value)); } - public function ResetToDefault() : void + protected function WriteUnifiedEnumSettingValue(config: CInGameConfigWrapper, vId: name, value: int) : void { - Reset(defaultPresetIndex); + WriteIntSettingValue(config, vId, EnumValueMappingUnifiedToConfig(vId, value)); } } \ No newline at end of file diff --git a/modSettingsFramework/content/scripts/local/settings_master.ws b/modSettingsFramework/content/scripts/local/settings_master.ws index 7b81a6a..d6d9aa9 100644 --- a/modSettingsFramework/content/scripts/local/settings_master.ws +++ b/modSettingsFramework/content/scripts/local/settings_master.ws @@ -1,73 +1,121 @@ abstract class ISettingsMaster { public const var modVersion: string; + public var id: name; + protected var m_groups: array; - // ====================== Functions to be defined in class generated by parser ====================== + // ============================ Main functions, can be overriden ============================== // Initializes the settings class members and more public function Init() : void { - if(ShouldResetSettingsToDefaultOnInit()) + var resetToDefault : bool; + + LogChannel('ModSettingsFramework', "Initialising settings master '" + id + "'"); + Parser_Init(); + + resetToDefault = ShouldResetSettingsToDefaultOnInit(); + if (resetToDefault) { - ResetSettingsToDefault(); + ResetSettingsToDefault(); } - // child class will initialize variables and modVersion beforehand ReadSettings(); + + if (resetToDefault) + { + // Resetting settings implies that there are presets to begin with + // If for some reason there are none, nothing new will be written to user.config + // If a mod was initialised for the first time then it will still not exist in user.config after closing the game + // This can be midigated by forcing settings to be written for this mod + // After calling ReadSettings() everything should have valid values, so writing to config should be more than safe + // This is also done only once per session, so it shouldn't be an issue performance wise + WriteSettings(); + } } // Corrects values to ranges specified in the xml public function ValidateSettings() : void { - // generated child class will correct these values in this function + var i, size: int; + var group: ISettingsGroup; + + LogChannel('ModSettingsFramework', "Validating settings for master '" + id + "'"); + size = m_groups.Size(); + for(i = 0; i < size; i += 1) + { + group = m_groups[i]; + group.ValidateSettings(); + } } // Reads all settings from CInGameConfigWrapper using ReadSettingValue and sets class variables public function ReadSettings() : void { - // child class will fetch config var values here + var i, size: int; + var group: ISettingsGroup; + var config: CInGameConfigWrapper; + + config = theGame.GetInGameConfigWrapper(); + + LogChannel('ModSettingsFramework', "Reading settings for master '" + id + "'"); + size = m_groups.Size(); + for(i = 0; i < size; i += 1) + { + group = m_groups[i]; + group.ReadSettings(config); + } } // Using class variables and WriteSettingValue sets all settings in CInGameConfigWrapper and saves user configuration public function WriteSettings() : void { - // child class will send var values to config beforehand + var i, size: int; + var group: ISettingsGroup; + var config: CInGameConfigWrapper; + + config = theGame.GetInGameConfigWrapper(); + + LogChannel('ModSettingsFramework', "Writing settings for master '" + id + "'"); + size = m_groups.Size(); + for(i = 0; i < size; i += 1) + { + group = m_groups[i]; + group.WriteSettings(false, config); + } + theGame.SaveUserSettings(); } // Apply a default preset to all groups if possible public function ResetSettingsToDefault() : void { - // child class will call reset code on every group here - } + var i, size: int; + var group: ISettingsGroup; + var config: CInGameConfigWrapper; - public function ShouldResetSettingsToDefaultOnInit() : bool - { - // child class will evaluate mod version var here - return false; - } + config = theGame.GetInGameConfigWrapper(); - // Returns integer value of the unified enum type for options var index in user config - // If the config value is not valid for given option, should return -1 - public function EnumValueMappingConfigToUnified(groupId: name, varId: name, val: int) : int - { - return -1; - } + LogChannel('ModSettingsFramework', "Resetting settings to default for master '" + id + "'"); + size = m_groups.Size(); + for(i = 0; i < size; i += 1) + { + group = m_groups[i]; + group.ResetSettingsToDefault(false, config); + } - // Returns the options var index in user config for integer value of unified enum - // If the unified value is not valid for given option, should return -1 - public function EnumValueMappingUnifiedToConfig(groupId: name, varId: name, val: int) : int - { - return -1; + theGame.SaveUserSettings(); } - // If integer value for given enum variable is correct returns said value - // Otherwise returns the smallest valid value - public function EnumValueMappingValidateUnified(groupId: name, varId: name, val: int) : int + // Checks whether this mod's settings have been saved onto disk before + public function ShouldResetSettingsToDefaultOnInit() : bool { - return 0; + var config: CInGameConfigWrapper; + config = theGame.GetInGameConfigWrapper(); + + return Parser_ShouldResetSettingsToDefaultOnInit(config); } @@ -76,18 +124,21 @@ abstract class ISettingsMaster // ==== Get/Set functions - to be potentially overriden by the developer if default is not enough ==== // Fetches setting value from CInGameConfigWrapper + // Master provides this function for group classes public function ReadSettingValue(config: CInGameConfigWrapper, gId: name, vId: name) : string { return config.GetVarValue(gId, vId); } // Writes setting value into CInGameConfigWrapper + // Master provides this function for group classes public function WriteSettingValue(config: CInGameConfigWrapper, gId: name, vId: name, value: string) : void { config.SetVarValue(gId, vId, value); } // Applies a preset to a group in CInGameConfigWrapper + // Master provides this function for group classes public function ResetSettingValues(config: CInGameConfigWrapper, gId: name, presetIndex: int) : void { config.ApplyGroupPreset(gId, presetIndex); @@ -95,24 +146,8 @@ abstract class ISettingsMaster + // ====================== Functions to be defined in class generated by parser ====================== - // ====================== Utility functions ====================== - - protected function StringToBool(s: string) : bool - { - if(s == "false" || s == "" || !s) { - return false; - } else { - return true; - } - } - - protected function BoolToString(b: bool) : string - { - if(b) { - return "true"; - } else { - return "false"; - } - } + protected function Parser_Init() : void {} + protected function Parser_ShouldResetSettingsToDefaultOnInit(config: CInGameConfigWrapper) : bool { return false; } } \ No newline at end of file diff --git a/modSettingsFramework/content/scripts/local/settings_master_registry.ws b/modSettingsFramework/content/scripts/local/settings_master_registry.ws index f364098..a2623c7 100644 --- a/modSettingsFramework/content/scripts/local/settings_master_registry.ws +++ b/modSettingsFramework/content/scripts/local/settings_master_registry.ws @@ -1,36 +1,29 @@ -struct SSettingsMasterRegistryEntry -{ - var settingsMaster : ISettingsMaster; - var id : name; -} - class CSettingsMasterRegistry { public const var FRAMEWORK_VERSION : name; - default FRAMEWORK_VERSION = '0.5'; + default FRAMEWORK_VERSION = '0.6.0'; - private var m_settingsEntries : array; + private var m_settingsEntries : array; public function AddSettings(settingsMaster : ISettingsMaster, id : name) : void { var i, size : int; - var settingsEntry : SSettingsMasterRegistryEntry; size = m_settingsEntries.Size(); for (i = 0; i < size; i += 1) { if (m_settingsEntries[i].id == id) { + LogChannel('ModSettingsFramework', "Attempt was made to add settings master '" + id + "' which already exists in the registry"); return; } } + settingsMaster.id = id; settingsMaster.Init(); - settingsEntry.settingsMaster = settingsMaster; - settingsEntry.id = id; - //TODO log these actions - m_settingsEntries.PushBack(settingsEntry); + m_settingsEntries.PushBack(settingsMaster); + LogChannel('ModSettingsFramework', "Added settings master '" + id + "' to the registry"); } // Returns NULL if no setting master is found with that ID @@ -43,7 +36,7 @@ class CSettingsMasterRegistry { if(m_settingsEntries[i].id == id) { - return m_settingsEntries[i].settingsMaster; + return m_settingsEntries[i]; } } @@ -60,6 +53,7 @@ class CSettingsMasterRegistry if(m_settingsEntries[i].id == id) { m_settingsEntries.Erase(i); + LogChannel('ModSettingsFramework', "Removed settings master '" + id + "' from the registry"); return; } } @@ -69,10 +63,12 @@ class CSettingsMasterRegistry { var i, size : int; + LogChannel('ModSettingsFramework', "Reading all settings"); + size = m_settingsEntries.Size(); for (i = 0; i < size; i += 1) { - m_settingsEntries[i].settingsMaster.ReadSettings(); + m_settingsEntries[i].ReadSettings(); } } } @@ -86,6 +82,7 @@ function GetSettingsMasterRegistry() : CSettingsMasterRegistry if(!game.m_settingsMasterRegistry) { + LogChannel('ModSettingsFramework', "Initialising the registry"); game.m_settingsMasterRegistry = new CSettingsMasterRegistry in theGame; } diff --git a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings index 806dcb7..61fe762 100644 Binary files a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings and b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings differ diff --git a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings.csv b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings.csv index 4860135..3490e77 100644 --- a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings.csv +++ b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/en.w3strings.csv @@ -4,7 +4,7 @@ 2119000001||panel_difficulty_mod|Difficulty mod 2119000002||preset_Mods_difficulty_mod|Presets 2119000003||preset_value_dm_preset_easy|Easy -2119000004||preset_value_dm_default_preset_normal|Normal +2119000004||preset_value_dm_preset_normal|Normal 2119000005||preset_value_dm_preset_hard|Hard 2119000006||option_dm_enabled|Mod enabled 2119000007||option_dm_health_multip|Health multiplier diff --git a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/pl.w3strings b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/pl.w3strings index 806dcb7..61fe762 100644 Binary files a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/pl.w3strings and b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/pl.w3strings differ diff --git a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws index e980d16..3cb4f08 100644 --- a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws +++ b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws @@ -1,4 +1,4 @@ -// Code generated using Mod Settings Framework v0.5.0 by SpontanCombust & Aeltoth +// Code generated using Mod Settings Framework v0.6.0 by SpontanCombust & Aeltoth class ModDifficultySettingsBase extends ISettingsMaster { @@ -6,69 +6,46 @@ class ModDifficultySettingsBase extends ISettingsMaster public var general : ModDifficultySettingsBase_general; - public /* override */ function Init() : void + protected /* override */ function Parser_Init() : void { - general = new ModDifficultySettingsBase_general in this; general.Init(this); - - super.Init(); + general = new ModDifficultySettingsBase_general in this; + general.Init(this); + m_groups.PushBack(general); } - public /* override */ function ValidateSettings() : void + protected /* override */ function Parser_ShouldResetSettingsToDefaultOnInit(config : CInGameConfigWrapper) : bool { - general.healthMultip = ClampF(general.healthMultip, 0, 2); - general.dmgMultip = ClampF(general.dmgMultip, 0, 2); - - super.ValidateSettings(); + return ReadSettingValue(config, 'DMgeneral','DMenabled') == ""; } +} - public /* override */ function ReadSettings() : void - { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - general.enabled = StringToBool(ReadSettingValue(config, 'DMgeneral', 'DMenabled')); - general.healthMultip = StringToFloat(ReadSettingValue(config, 'DMgeneral', 'DMhealthMultip'), 0.0); - general.dmgMultip = StringToFloat(ReadSettingValue(config, 'DMgeneral', 'DMdmgMultip'), 0.0); +class ModDifficultySettingsBase_general extends ISettingsGroup +{ + public var enabled : bool; + public var healthMultip : float; + public var dmgMultip : float; - this.ValidateSettings(); - super.ReadSettings(); - } + default id = 'DMgeneral'; + default defaultPresetIndex = 1; - public /* override */ function WriteSettings() : void + protected /* override */ function Parser_ValidateSettings() : void { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - this.ValidateSettings(); - - WriteSettingValue(config, 'DMgeneral', 'DMenabled', BoolToString(general.enabled)); - WriteSettingValue(config, 'DMgeneral', 'DMhealthMultip', FloatToString(general.healthMultip)); - WriteSettingValue(config, 'DMgeneral', 'DMdmgMultip', FloatToString(general.dmgMultip)); - - super.WriteSettings(); + healthMultip = ClampF(healthMultip, 0, 2); + dmgMultip = ClampF(dmgMultip, 0, 2); } - public /* override */ function ResetSettingsToDefault() : void + protected /* override */ function Parser_ReadSettings(config: CInGameConfigWrapper) : void { - general.ResetToDefault(); + enabled = ReadBoolSettingValue(config, 'DMenabled'); + healthMultip = ReadFloatSettingValue(config, 'DMhealthMultip'); + dmgMultip = ReadFloatSettingValue(config, 'DMdmgMultip'); } - public /* override */ function ShouldResetSettingsToDefaultOnInit() : bool + protected /* override */ function Parser_WriteSettings(config: CInGameConfigWrapper) : void { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - return config.GetVarValue('DMgeneral','DMenabled') == ""; + WriteBoolSettingValue(config, 'DMenabled', enabled); + WriteFloatSettingValue(config, 'DMhealthMultip', healthMultip); + WriteFloatSettingValue(config, 'DMdmgMultip', dmgMultip); } } -class ModDifficultySettingsBase_general extends ISettingsGroup -{ - public var enabled : bool; - public var healthMultip : float; - public var dmgMultip : float; - - default id = 'DMgeneral'; - default defaultPresetIndex = 1; -} - diff --git a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_execs.ws b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_execs.ws index 3151514..42cc90b 100644 --- a/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_execs.ws +++ b/samples/DifficultyMod/Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_execs.ws @@ -1,11 +1,11 @@ exec function settings_difficulty_easy() { - GetModDifficultySettings().general.Reset(0); + GetModDifficultySettings().general.ResetSettings(0, true); } exec function settings_difficulty_default() { - GetModDifficultySettings().general.ResetToDefault(); + GetModDifficultySettings().general.ResetSettingsToDefault(true); } exec function settings_difficulty_hard() diff --git a/samples/DifficultyMod/bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml b/samples/DifficultyMod/bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml index cb446da..91b8f0c 100644 --- a/samples/DifficultyMod/bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml +++ b/samples/DifficultyMod/bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml @@ -1,13 +1,13 @@ - + - + - + diff --git a/samples/DifficultyMod/command.bat b/samples/DifficultyMod/command.bat index 73a7735..eccd755 100644 --- a/samples/DifficultyMod/command.bat +++ b/samples/DifficultyMod/command.bat @@ -1 +1 @@ -settings_parser.exe -f="bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml" -m="ModDifficultySettingsBase" -v="1.1" --omit-prefix="DM" --default-preset-keyword="DEFAULT" -o="Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws" --no-getter \ No newline at end of file +settings_parser.exe "bin/config/r4game/user_config_matrix/pc/SampleDifficultyMod.xml" -o="Mods/modSampleDifficultyMod/content/scripts/local/difficulty_mod_base.ws" --no-getter \ No newline at end of file diff --git a/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week.ws b/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week.ws index 303c970..6b23acd 100644 --- a/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week.ws +++ b/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week.ws @@ -45,24 +45,24 @@ exec function monster_of_the_week_next_monster() LogChannel('MOTW', "Kaer Morhen: " + settings.monsters.kaerMorhen); LogChannel('MOTW', "Toussaint: " + settings.monsters.toussaint); - i = settings.EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWnoMansLand', (int)settings.monsters.noMansLand); - settings.monsters.noMansLand = (MonsterOfTheWeekSettings_monster)settings.EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWnoMansLand', i + 1); + i = settings.monsters.EnumValueMappingUnifiedToConfig('MOTWnoMansLand', (int)settings.monsters.noMansLand); + settings.monsters.noMansLand = (MonsterOfTheWeekSettings_monster)settings.monsters.EnumValueMappingConfigToUnified('MOTWnoMansLand', i + 1); LogChannel('MOTW', "NML: " + i + " -> " + (i + 1)); - i = settings.EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWskellige', (int)settings.monsters.skellige); - settings.monsters.skellige = (MonsterOfTheWeekSettings_monster)settings.EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWskellige', i + 1); + i = settings.monsters.EnumValueMappingUnifiedToConfig('MOTWskellige', (int)settings.monsters.skellige); + settings.monsters.skellige = (MonsterOfTheWeekSettings_monster)settings.monsters.EnumValueMappingConfigToUnified('MOTWskellige', i + 1); LogChannel('MOTW', "Skellige: " + i + " -> " + (i + 1)); - i = settings.EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWkaerMorhen', (int)settings.monsters.kaerMorhen); - settings.monsters.kaerMorhen = (MonsterOfTheWeekSettings_monster)settings.EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWkaerMorhen', i + 1); + i = settings.monsters.EnumValueMappingUnifiedToConfig('MOTWkaerMorhen', (int)settings.monsters.kaerMorhen); + settings.monsters.kaerMorhen = (MonsterOfTheWeekSettings_monster)settings.monsters.EnumValueMappingConfigToUnified('MOTWkaerMorhen', i + 1); LogChannel('MOTW', "Kaer Morhen: " + i + " -> " + (i + 1)); - i = settings.EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWtoussaint', (int)settings.monsters.toussaint); - settings.monsters.toussaint = (MonsterOfTheWeekSettings_monster)settings.EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWtoussaint', i + 1); + i = settings.monsters.EnumValueMappingUnifiedToConfig('MOTWtoussaint', (int)settings.monsters.toussaint); + settings.monsters.toussaint = (MonsterOfTheWeekSettings_monster)settings.monsters.EnumValueMappingConfigToUnified('MOTWtoussaint', i + 1); LogChannel('MOTW', "Toussaint: " + i + " -> " + (i + 1)); // validation happens before writing - settings.WriteSettings(); + settings.monsters.WriteSettings(true); LogChannel('MOTW', "After"); LogChannel('MOTW', "NML: " + settings.monsters.noMansLand); diff --git a/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week_settings.ws b/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week_settings.ws index 823e355..a8e7600 100644 --- a/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week_settings.ws +++ b/samples/MonsterOfTheWeek/Mods/modSampleMonsterOfTheWeek/content/scripts/local/monster_of_the_week_settings.ws @@ -1,4 +1,4 @@ -// Code generated using Mod Settings Framework v0.5.0 by SpontanCombust & Aeltoth +// Code generated using Mod Settings Framework v0.6.0 by SpontanCombust & Aeltoth class MonsterOfTheWeekSettings extends ISettingsMaster { @@ -7,290 +7,266 @@ class MonsterOfTheWeekSettings extends ISettingsMaster public var difficulties : MonsterOfTheWeekSettings_difficulties; public var monsters : MonsterOfTheWeekSettings_monsters; - public /* override */ function Init() : void + protected /* override */ function Parser_Init() : void { - difficulties = new MonsterOfTheWeekSettings_difficulties in this; difficulties.Init(this); - monsters = new MonsterOfTheWeekSettings_monsters in this; monsters.Init(this); + difficulties = new MonsterOfTheWeekSettings_difficulties in this; + difficulties.Init(this); + m_groups.PushBack(difficulties); - super.Init(); + monsters = new MonsterOfTheWeekSettings_monsters in this; + monsters.Init(this); + m_groups.PushBack(monsters); } - public /* override */ function ValidateSettings() : void + protected /* override */ function Parser_ShouldResetSettingsToDefaultOnInit(config : CInGameConfigWrapper) : bool { - difficulties.noMansLand = (MonsterOfTheWeekSettings_difficulty)Clamp((int)difficulties.noMansLand, 0, 2); - difficulties.skellige = (MonsterOfTheWeekSettings_difficulty)Clamp((int)difficulties.skellige, 0, 2); - difficulties.kaerMorhen = (MonsterOfTheWeekSettings_difficulty)Clamp((int)difficulties.kaerMorhen, 0, 2); - difficulties.toussaint = (MonsterOfTheWeekSettings_difficulty)Clamp((int)difficulties.toussaint, 0, 2); - - monsters.noMansLand = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWmonsters', 'MOTWnoMansLand', (int)monsters.noMansLand); - monsters.skellige = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWmonsters', 'MOTWskellige', (int)monsters.skellige); - monsters.kaerMorhen = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWmonsters', 'MOTWkaerMorhen', (int)monsters.kaerMorhen); - monsters.toussaint = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWmonsters', 'MOTWtoussaint', (int)monsters.toussaint); - - super.ValidateSettings(); + return ReadSettingValue(config, 'MOTWdifficulties','MOTWnoMansLand') == "-1"; } +} - public /* override */ function ReadSettings() : void - { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - difficulties.noMansLand = (MonsterOfTheWeekSettings_difficulty)StringToInt(ReadSettingValue(config, 'MOTWdifficulties', 'MOTWnoMansLand'), 0); - difficulties.skellige = (MonsterOfTheWeekSettings_difficulty)StringToInt(ReadSettingValue(config, 'MOTWdifficulties', 'MOTWskellige'), 0); - difficulties.kaerMorhen = (MonsterOfTheWeekSettings_difficulty)StringToInt(ReadSettingValue(config, 'MOTWdifficulties', 'MOTWkaerMorhen'), 0); - difficulties.toussaint = (MonsterOfTheWeekSettings_difficulty)StringToInt(ReadSettingValue(config, 'MOTWdifficulties', 'MOTWtoussaint'), 0); +class MonsterOfTheWeekSettings_difficulties extends ISettingsGroup +{ + public var noMansLand : MOTWDifficulty; + public var skellige : MOTWDifficulty; + public var kaerMorhen : MOTWDifficulty; + public var toussaint : MOTWDifficulty; - monsters.noMansLand = (MonsterOfTheWeekSettings_monster)EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWnoMansLand', StringToInt(ReadSettingValue(config, 'MOTWmonsters', 'MOTWnoMansLand'), 0)); - monsters.skellige = (MonsterOfTheWeekSettings_monster)EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWskellige', StringToInt(ReadSettingValue(config, 'MOTWmonsters', 'MOTWskellige'), 0)); - monsters.kaerMorhen = (MonsterOfTheWeekSettings_monster)EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWkaerMorhen', StringToInt(ReadSettingValue(config, 'MOTWmonsters', 'MOTWkaerMorhen'), 0)); - monsters.toussaint = (MonsterOfTheWeekSettings_monster)EnumValueMappingConfigToUnified('MOTWmonsters', 'MOTWtoussaint', StringToInt(ReadSettingValue(config, 'MOTWmonsters', 'MOTWtoussaint'), 0)); + default id = 'MOTWdifficulties'; + default defaultPresetIndex = 0; - this.ValidateSettings(); - super.ReadSettings(); + protected /* override */ function Parser_ValidateSettings() : void + { + noMansLand = (MOTWDifficulty)Clamp((int)noMansLand, 0, 2); + skellige = (MOTWDifficulty)Clamp((int)skellige, 0, 2); + kaerMorhen = (MOTWDifficulty)Clamp((int)kaerMorhen, 0, 2); + toussaint = (MOTWDifficulty)Clamp((int)toussaint, 0, 2); } - public /* override */ function WriteSettings() : void + protected /* override */ function Parser_ReadSettings(config: CInGameConfigWrapper) : void { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); + noMansLand = (MOTWDifficulty)ReadIntSettingValue(config, 'MOTWnoMansLand'); + skellige = (MOTWDifficulty)ReadIntSettingValue(config, 'MOTWskellige'); + kaerMorhen = (MOTWDifficulty)ReadIntSettingValue(config, 'MOTWkaerMorhen'); + toussaint = (MOTWDifficulty)ReadIntSettingValue(config, 'MOTWtoussaint'); + } - this.ValidateSettings(); + protected /* override */ function Parser_WriteSettings(config: CInGameConfigWrapper) : void + { + WriteIntSettingValue(config, 'MOTWnoMansLand', (int)noMansLand); + WriteIntSettingValue(config, 'MOTWskellige', (int)skellige); + WriteIntSettingValue(config, 'MOTWkaerMorhen', (int)kaerMorhen); + WriteIntSettingValue(config, 'MOTWtoussaint', (int)toussaint); + } +} - WriteSettingValue(config, 'MOTWdifficulties', 'MOTWnoMansLand', IntToString((int)difficulties.noMansLand)); - WriteSettingValue(config, 'MOTWdifficulties', 'MOTWskellige', IntToString((int)difficulties.skellige)); - WriteSettingValue(config, 'MOTWdifficulties', 'MOTWkaerMorhen', IntToString((int)difficulties.kaerMorhen)); - WriteSettingValue(config, 'MOTWdifficulties', 'MOTWtoussaint', IntToString((int)difficulties.toussaint)); +class MonsterOfTheWeekSettings_monsters extends ISettingsGroup +{ + public var noMansLand : MonsterOfTheWeekSettings_monster; + public var skellige : MonsterOfTheWeekSettings_monster; + public var kaerMorhen : MonsterOfTheWeekSettings_monster; + public var toussaint : MonsterOfTheWeekSettings_monster; - WriteSettingValue(config, 'MOTWmonsters', 'MOTWnoMansLand', IntToString(EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWnoMansLand', (int)monsters.noMansLand))); - WriteSettingValue(config, 'MOTWmonsters', 'MOTWskellige', IntToString(EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWskellige', (int)monsters.skellige))); - WriteSettingValue(config, 'MOTWmonsters', 'MOTWkaerMorhen', IntToString(EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWkaerMorhen', (int)monsters.kaerMorhen))); - WriteSettingValue(config, 'MOTWmonsters', 'MOTWtoussaint', IntToString(EnumValueMappingUnifiedToConfig('MOTWmonsters', 'MOTWtoussaint', (int)monsters.toussaint))); + default id = 'MOTWmonsters'; + default defaultPresetIndex = 0; - super.WriteSettings(); + protected /* override */ function Parser_ValidateSettings() : void + { + noMansLand = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWnoMansLand', (int)noMansLand); + skellige = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWskellige', (int)skellige); + kaerMorhen = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWkaerMorhen', (int)kaerMorhen); + toussaint = (MonsterOfTheWeekSettings_monster)EnumValueMappingValidateUnified('MOTWtoussaint', (int)toussaint); } - public /* override */ function ResetSettingsToDefault() : void + protected /* override */ function Parser_ReadSettings(config: CInGameConfigWrapper) : void { - difficulties.ResetToDefault(); - monsters.ResetToDefault(); + noMansLand = (MonsterOfTheWeekSettings_monster)ReadUnifiedEnumSettingValue(config, 'MOTWnoMansLand'); + skellige = (MonsterOfTheWeekSettings_monster)ReadUnifiedEnumSettingValue(config, 'MOTWskellige'); + kaerMorhen = (MonsterOfTheWeekSettings_monster)ReadUnifiedEnumSettingValue(config, 'MOTWkaerMorhen'); + toussaint = (MonsterOfTheWeekSettings_monster)ReadUnifiedEnumSettingValue(config, 'MOTWtoussaint'); } - public /* override */ function ShouldResetSettingsToDefaultOnInit() : bool + protected /* override */ function Parser_WriteSettings(config: CInGameConfigWrapper) : void { - var config : CInGameConfigWrapper; - config = theGame.GetInGameConfigWrapper(); - - return config.GetVarValue('MOTWdifficulties','MOTWnoMansLand') == ""; + WriteUnifiedEnumSettingValue(config, 'MOTWnoMansLand', (int)noMansLand); + WriteUnifiedEnumSettingValue(config, 'MOTWskellige', (int)skellige); + WriteUnifiedEnumSettingValue(config, 'MOTWkaerMorhen', (int)kaerMorhen); + WriteUnifiedEnumSettingValue(config, 'MOTWtoussaint', (int)toussaint); } - public /* override */ function EnumValueMappingConfigToUnified(gId: name, vId: name, val: int) : int + protected /* override */ function Parser_EnumValueMappingValidateUnified(vId: name, val: int) : int { - switch(gId) + switch(vId) { - case 'MOTWmonsters': - switch(vId) + case 'MOTWnoMansLand': + switch(val) { - case 'MOTWnoMansLand': - switch(val) - { - case 0: return 0; - case 1: return 1; - case 2: return 2; - case 3: return 3; - case 4: return 4; - case 5: return 5; - case 6: return 6; - } - case 'MOTWskellige': - switch(val) - { - case 0: return 7; - case 1: return 8; - case 2: return 1; - case 3: return 2; - case 4: return 3; - case 5: return 4; - case 6: return 9; - case 7: return 10; - case 8: return 11; - } - case 'MOTWkaerMorhen': - switch(val) - { - case 0: return 8; - case 1: return 2; - case 2: return 1; - case 3: return 3; - } - case 'MOTWtoussaint': - switch(val) - { - case 0: return 12; - case 1: return 13; - case 2: return 14; - case 3: return 15; - case 4: return 16; - case 5: return 17; - case 6: return 18; - } + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + return val; + default: + return 0; + } + case 'MOTWskellige': + switch(val) + { + case 7: + case 8: + case 1: + case 2: + case 3: + case 4: + case 9: + case 10: + case 11: + return val; + default: + return 7; + } + case 'MOTWkaerMorhen': + switch(val) + { + case 8: + case 2: + case 1: + case 3: + return val; + default: + return 8; + } + case 'MOTWtoussaint': + switch(val) + { + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + return val; + default: + return 12; } } - return -1; + return 0; } - public /* override */ function EnumValueMappingUnifiedToConfig(gId: name, vId: name, val: int) : int + protected /* override */ function Parser_EnumValueMappingConfigToUnified(vId: name, val: int) : int { - switch(gId) + switch(vId) { - case 'MOTWmonsters': - switch(vId) + case 'MOTWnoMansLand': + switch(val) { - case 'MOTWnoMansLand': - switch(val) - { - case 0: return 0; - case 1: return 1; - case 2: return 2; - case 3: return 3; - case 4: return 4; - case 5: return 5; - case 6: return 6; - } - case 'MOTWskellige': - switch(val) - { - case 7: return 0; - case 8: return 1; - case 1: return 2; - case 2: return 3; - case 3: return 4; - case 4: return 5; - case 9: return 6; - case 10: return 7; - case 11: return 8; - } - case 'MOTWkaerMorhen': - switch(val) - { - case 8: return 0; - case 2: return 1; - case 1: return 2; - case 3: return 3; - } - case 'MOTWtoussaint': - switch(val) - { - case 12: return 0; - case 13: return 1; - case 14: return 2; - case 15: return 3; - case 16: return 4; - case 17: return 5; - case 18: return 6; - } + case 0: return 0; + case 1: return 1; + case 2: return 2; + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + } + case 'MOTWskellige': + switch(val) + { + case 0: return 7; + case 1: return 8; + case 2: return 1; + case 3: return 2; + case 4: return 3; + case 5: return 4; + case 6: return 9; + case 7: return 10; + case 8: return 11; + } + case 'MOTWkaerMorhen': + switch(val) + { + case 0: return 8; + case 1: return 2; + case 2: return 1; + case 3: return 3; + } + case 'MOTWtoussaint': + switch(val) + { + case 0: return 12; + case 1: return 13; + case 2: return 14; + case 3: return 15; + case 4: return 16; + case 5: return 17; + case 6: return 18; } } return -1; } - public /* override */ function EnumValueMappingValidateUnified(gId: name, vId: name, val: int) : int + protected /* override */ function Parser_EnumValueMappingUnifiedToConfig(vId: name, val: int) : int { - switch(gId) + switch(vId) { - case 'MOTWmonsters': - switch(vId) + case 'MOTWnoMansLand': + switch(val) + { + case 0: return 0; + case 1: return 1; + case 2: return 2; + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + } + case 'MOTWskellige': + switch(val) { - case 'MOTWnoMansLand': - switch(val) - { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - return val; - default: - return 0; - } - case 'MOTWskellige': - switch(val) - { - case 7: - case 8: - case 1: - case 2: - case 3: - case 4: - case 9: - case 10: - case 11: - return val; - default: - return 7; - } - case 'MOTWkaerMorhen': - switch(val) - { - case 8: - case 2: - case 1: - case 3: - return val; - default: - return 8; - } - case 'MOTWtoussaint': - switch(val) - { - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - return val; - default: - return 12; - } + case 7: return 0; + case 8: return 1; + case 1: return 2; + case 2: return 3; + case 3: return 4; + case 4: return 5; + case 9: return 6; + case 10: return 7; + case 11: return 8; + } + case 'MOTWkaerMorhen': + switch(val) + { + case 8: return 0; + case 2: return 1; + case 1: return 2; + case 3: return 3; + } + case 'MOTWtoussaint': + switch(val) + { + case 12: return 0; + case 13: return 1; + case 14: return 2; + case 15: return 3; + case 16: return 4; + case 17: return 5; + case 18: return 6; } } - return 0; + return -1; } } -class MonsterOfTheWeekSettings_difficulties extends ISettingsGroup -{ - public var noMansLand : MonsterOfTheWeekSettings_difficulty; - public var skellige : MonsterOfTheWeekSettings_difficulty; - public var kaerMorhen : MonsterOfTheWeekSettings_difficulty; - public var toussaint : MonsterOfTheWeekSettings_difficulty; - - default id = 'MOTWdifficulties'; - default defaultPresetIndex = 0; -} - -class MonsterOfTheWeekSettings_monsters extends ISettingsGroup -{ - public var noMansLand : MonsterOfTheWeekSettings_monster; - public var skellige : MonsterOfTheWeekSettings_monster; - public var kaerMorhen : MonsterOfTheWeekSettings_monster; - public var toussaint : MonsterOfTheWeekSettings_monster; - - default id = 'MOTWmonsters'; - default defaultPresetIndex = 0; -} - -enum MonsterOfTheWeekSettings_difficulty +enum MOTWDifficulty { - MonsterOfTheWeekSettings_difficulty_easy = 0, - MonsterOfTheWeekSettings_difficulty_medium = 1, - MonsterOfTheWeekSettings_difficulty_hard = 2, + MOTWDifficultyEasy = 0, + MOTWDifficultyMedium = 1, + MOTWDifficultyHard = 2, } enum MonsterOfTheWeekSettings_monster diff --git a/samples/MonsterOfTheWeek/bin/config/r4game/user_config_matrix/pc/SampleMonsterOfTheWeek.xml b/samples/MonsterOfTheWeek/bin/config/r4game/user_config_matrix/pc/SampleMonsterOfTheWeek.xml index aa3467e..7e8eb1c 100644 --- a/samples/MonsterOfTheWeek/bin/config/r4game/user_config_matrix/pc/SampleMonsterOfTheWeek.xml +++ b/samples/MonsterOfTheWeek/bin/config/r4game/user_config_matrix/pc/SampleMonsterOfTheWeek.xml @@ -1,56 +1,56 @@ - + - - - - - - - -