├── .gitignore
├── Fonts
├── attribution.txt
├── johnny fever.otf
└── typodermic-eula-03-2020.pdf
├── example.json
├── .gitattributes
├── Images
├── Logo.png
├── Logo_Wide.png
├── MCMRecorder.xcf
└── JContainers_SSE15.png
├── McmRecorder.esp
├── Scripts
├── Source
│ ├── McmRecorder_Compatibility.psc
│ ├── McmRecorder_PlayerAlias.psc
│ ├── McmRecorder_Logging.psc
│ ├── McmRecorder_RecordingInfo.psc
│ ├── McmRecorder_Config.psc
│ ├── McmRecorder_VRIK.psc
│ ├── McmRecorder_JDB.psc
│ ├── McmRecorder_UI.psc
│ ├── McmRecorder_KeyboardShortcuts.psc
│ ├── McmRecorder_RecordingFiles.psc
│ ├── McmRecorder.psc
│ ├── McmRecorder_McmFields.psc
│ ├── McmRecorder_Recorder.psc
│ ├── SKI_ConfigManager.psc
│ ├── McmRecorderMCM.psc
│ ├── McmRecorder_Player.psc
│ └── SKI_ConfigBase.psc
├── McmRecorder.pex
├── McmRecorderMCM.pex
├── McmRecorder_JDB.pex
├── McmRecorder_UI.pex
├── McmRecorder_VRIK.pex
├── SKI_ConfigBase.pex
├── McmRecorder_Config.pex
├── McmRecorder_Player.pex
├── SKI_ConfigManager.pex
├── McmRecorder_Logging.pex
├── McmRecorder_McmFields.pex
├── McmRecorder_Recorder.pex
├── McmRecorder_Shortcuts.pex
├── McmRecorder_PlayerAlias.pex
├── McmRecorder_Compatibility.pex
├── McmRecorder_RecordingFiles.pex
├── McmRecorder_RecordingInfo.pex
└── McmRecorder_KeyboardShortcuts.pex
├── McmRecorder.SE.esp
├── meta.ini
├── McmRecorder.json
├── McmRecorder.LE.json
├── README.md
├── .vscode
├── launch.json
└── tasks.json
├── McmRecorder.code-workspace
├── LICENSE
├── skyrimse.ppj
└── TODO.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.zip
2 | *.pas
--------------------------------------------------------------------------------
/Fonts/attribution.txt:
--------------------------------------------------------------------------------
1 | https://www.1001fonts.com/johnny-fever-font.html
--------------------------------------------------------------------------------
/example.json:
--------------------------------------------------------------------------------
1 | [
2 | { "ModName": "No Kids", "click": "Enable" }
3 | ]
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/Images/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Images/Logo.png
--------------------------------------------------------------------------------
/McmRecorder.esp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/McmRecorder.esp
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_Compatibility.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_Compatibility
2 |
--------------------------------------------------------------------------------
/McmRecorder.SE.esp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/McmRecorder.SE.esp
--------------------------------------------------------------------------------
/Images/Logo_Wide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Images/Logo_Wide.png
--------------------------------------------------------------------------------
/Fonts/johnny fever.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Fonts/johnny fever.otf
--------------------------------------------------------------------------------
/Images/MCMRecorder.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Images/MCMRecorder.xcf
--------------------------------------------------------------------------------
/Scripts/McmRecorder.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder.pex
--------------------------------------------------------------------------------
/Images/JContainers_SSE15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Images/JContainers_SSE15.png
--------------------------------------------------------------------------------
/Scripts/McmRecorderMCM.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorderMCM.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_JDB.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_JDB.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_UI.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_UI.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_VRIK.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_VRIK.pex
--------------------------------------------------------------------------------
/Scripts/SKI_ConfigBase.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/SKI_ConfigBase.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_Config.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_Config.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_Player.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_Player.pex
--------------------------------------------------------------------------------
/Scripts/SKI_ConfigManager.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/SKI_ConfigManager.pex
--------------------------------------------------------------------------------
/Fonts/typodermic-eula-03-2020.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Fonts/typodermic-eula-03-2020.pdf
--------------------------------------------------------------------------------
/Scripts/McmRecorder_Logging.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_Logging.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_McmFields.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_McmFields.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_Recorder.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_Recorder.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_Shortcuts.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_Shortcuts.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_PlayerAlias.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_PlayerAlias.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_Compatibility.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_Compatibility.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_RecordingFiles.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_RecordingFiles.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_RecordingInfo.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_RecordingInfo.pex
--------------------------------------------------------------------------------
/Scripts/McmRecorder_KeyboardShortcuts.pex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrowrpurr/McmRecorder/HEAD/Scripts/McmRecorder_KeyboardShortcuts.pex
--------------------------------------------------------------------------------
/meta.ini:
--------------------------------------------------------------------------------
1 | [General]
2 | modid=0
3 | version=
4 | newestVersion=
5 | category=0
6 | installationFile=
7 |
8 | [installedFiles]
9 | size=0
10 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_PlayerAlias.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_PlayerAlias extends ReferenceAlias
2 |
3 | event OnPlayerLoadGame()
4 | (GetOwningQuest() as McmRecorder).SaveGameLoaded()
5 | endEvent
6 |
--------------------------------------------------------------------------------
/McmRecorder.json:
--------------------------------------------------------------------------------
1 | {
2 | "notifications": {
3 | "console": "true",
4 | "upper-left": "true",
5 | "popup": "true"
6 | },
7 | "defaults": {
8 | "mcmLoad": 5.0
9 | }
10 | }
--------------------------------------------------------------------------------
/McmRecorder.LE.json:
--------------------------------------------------------------------------------
1 | {
2 | "notifications": {
3 | "console": "true",
4 | "upper-left": "true",
5 | "popup": "true"
6 | },
7 | "defaults": {
8 | "mcmLoad": 5.0
9 | }
10 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mcm Recorder
2 |
3 | Skyrim Mod Configuration Menu Recorder (for recording and playing back game configs)
4 |
5 | Note: the `SKI_ConfigBase` and `SKI_ConfigManager` scripts are NOT OWNED BY ME.
6 |
7 | They are owned by [schlangster](https://github.com/schlangster/skyui) and their inclusion in this project does NOT mean that they are MIT licensed.
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // created by vscode papyrus-lang papyrus.skyrimSpecialEdition.generateProject
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "Skyrim SE",
7 | "type": "papyrus",
8 | "request": "attach",
9 | "game": "skyrimSpecialEdition"
10 | }
11 | ]
12 | }
--------------------------------------------------------------------------------
/McmRecorder.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | // created by vscode papyrus-lang papyrus.skyrimSpecialEdition.generateProject
3 | "folders": [
4 | {
5 | "path": "."
6 | }
7 | ],
8 | "settings": {
9 | "papyrus.skyrimSpecialEdition.enabled": true,
10 | "papyrus.fallout4.enabled": false,
11 | "papyrus.skyrim.enabled": false
12 | }
13 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "pyro",
6 | "projectFile": "skyrimse.ppj",
7 | "gamePath": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Skyrim Special Edition\\",
8 | "problemMatcher": [
9 | "$PapyrusCompiler"
10 | ],
11 | "label": "pyro: Compile Project (skyrimse.ppj)",
12 | "group": {
13 | "kind": "build",
14 | "isDefault": true
15 | }
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_Logging.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_Logging hidden
2 |
3 | function Log(string text) global
4 | Debug.Trace("[MCM Recorder] " + text)
5 | endFunction
6 |
7 | function LogContainer(string text, int jcontainer) global
8 | Log(text + ":\n" + ToJson(jcontainer))
9 | endFunction
10 |
11 | string function ToJson(int jcontainer) global
12 | string filepath = McmRecorder_RecordingFiles.PathToRecordings() + "/" + ".temp" + "/temp.json"
13 | JValue.writeToFile(jcontainer, filepath)
14 | return MiscUtil.ReadFromFile(filepath)
15 | endFunction
16 |
17 | function ConsoleOut(string text) global
18 | MiscUtil.PrintConsole(text)
19 | endFunction
20 |
21 | function DumpAll(string filename = "Data/McmRecorder/.debug/McmRecorderDataDump.json") global
22 | JValue.writeToFile(JDB.solveObj(".mcmRecorder"), filename)
23 | ConsoleOut("[DEBUG] Written to " + filename)
24 | endFunction
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Mrowr Purr
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_RecordingInfo.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_RecordingInfo hidden
2 |
3 | int function Get(string recordingName) global
4 | return McmRecorder_RecordingFiles.GetRecordingInfo(recordingName)
5 | endFunction
6 |
7 | ; TODO remove the recordingName parameter
8 | function Save(string recordingName, int recordingInfo) global
9 | McmRecorder_RecordingFiles.SaveRecordingInfoFile(recordingName, recordingInfo)
10 | endFunction
11 |
12 | bool function IsAutorun(int recordingInfo) global
13 | return JMap.getStr(recordingInfo, "autorun") == "true"
14 | endFunction
15 |
16 | bool function IsVrGesture(int recordingInfo) global
17 | return JMap.getStr(recordingInfo, "gesture") == "true"
18 | endFunction
19 |
20 | bool function SetIsVrGesture(int recordingInfo, bool enabled = true) global
21 | if enabled
22 | JMap.setStr(recordingInfo, "gesture", "true")
23 | else
24 | JMap.removeKey(recordingInfo, "gesture")
25 | endIf
26 | Save(GetName(recordingInfo), recordingInfo)
27 | endFunction
28 |
29 | string function GetName(int recordingInfo) global
30 | return JMap.getStr(recordingInfo, "name")
31 | endFunction
32 |
33 | ; TODO support replacements like $STEP_COUNT$ or something.
34 | string function GetWelcomeMessage(int recordingInfo) global
35 | return JMap.getStr(recordingInfo, "welcome")
36 | endFunction
37 |
38 | string function GetCompleteMessage(int recordingInfo) global
39 | return JMap.getStr(recordingInfo, "complete")
40 | endFunction
41 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_Config.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_Config hidden
2 | {Responsible for checking MCM Recorder configuration settings
3 |
4 | Settings are defined in Data\McmRecorder.json}
5 |
6 | function ReloadConfig() global
7 | ; TODO
8 | endFunction
9 |
10 | bool function IsSkyrimVR() global
11 | return Game.GetModByName("SkyrimVR.esm") != 255
12 | endFunction
13 |
14 | bool function IsSkyrimLE() global
15 | return MiscUtil.FileExists("TESV.exe")
16 | endFunction
17 |
18 | bool function ShowNotifications() global
19 | return JDB.solveStr(McmRecorder_JDB.JdbPath_Config_ShowNotifications()) != "false"
20 | endFunction
21 |
22 | bool function SetShowNotifications(bool value) global
23 | if value
24 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_Config_ShowNotifications(), "true", createMissingKeys = true)
25 | else
26 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_Config_ShowNotifications(), "false", createMissingKeys = true)
27 | endIf
28 | endFunction
29 |
30 | bool function ShowMessageBoxes() global
31 | return JDB.solveStr(McmRecorder_JDB.JdbPath_Config_ShowMessageBoxes()) != "false"
32 | endFunction
33 |
34 | bool function SetShowMessageBoxes(bool value) global
35 | if value
36 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_Config_ShowMessageBoxes(), "true", createMissingKeys = true)
37 | else
38 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_Config_ShowMessageBoxes(), "false", createMissingKeys = true)
39 | endIf
40 | endFunction
41 |
--------------------------------------------------------------------------------
/skyrimse.ppj:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | @ImportsFolder\SKSE
20 | @ImportsFolder\SkyUI_SDK
21 | @ImportsFolder\PapyrusUtil
22 | @ImportsFolder\JContainers
23 | @ImportsFolder\UIExtensions
24 | @ImportsFolder\VRIK
25 | C:\Program Files (x86)\Steam\steamapps\common\Skyrim Special Edition\Data\Scripts\Source
26 |
27 |
28 | ./Scripts/Source
29 |
30 |
31 |
32 | @ModName.esp
33 | *.pex
34 | *.psc
35 |
36 |
37 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | - [ ] Show when dependencies are not installed
2 | - [ ] PW's not working mods
3 | - [ ] Pause while running
4 | - [ ] Add better VR support by customizing the MCM menu when you're in VR!
5 | - [ ] Set verbosity (whether messages show up )
6 | - [ ] Cancel while running
7 | - [ ] Choose whether to run a step or not!
8 | - [ ] Choose a BATCH of steps to run!
9 | - [ ] Look into supporting MCMs which were built using MCM Helper (reportedly these don't work)
10 |
11 | - [x] Trigger automatically via SKSE
12 | - [x] Autorun after RaceMenu close
13 | - [x] Welcome Message
14 | - [x] Complete Message
15 | - [x] Extract all global functions to a private API (keep them there for now)
16 | - [x] Track the Nth cuz that's cool
17 | - [x] Trigger automatically via autorun: true
18 | - [x] BUG When you record but there are no recordings it still says 'Choose a recording' - also DISABLE this text
19 | - [x] Show console messages for recording actions (and play actions!)
20 | - [x] Branch logic on VR and use PapyrusUtil for SSE <----
21 | - [x] Keyboard shortcuts - include in the Recording.json
22 | - [x] VR guestures - include in the Recording.json
23 |
24 |
25 | - Track the Nth index for selectors which have duplicates on the page
26 | - Can use SKSE mod events to run Recordings, Steps, or Actions
27 | - Can put recording name(s) into a config file which will AUTOMATICALLY run the recordings!
28 | - Can detect is a field is on the page easily (and get it)
29 |
30 | TODO: MCM translation files
31 |
32 | BUG: in VR when you click 'begin recording' if says 'Choose Recording To Play' even if there are none
33 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_VRIK.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_VRIK
2 |
3 | string function GetModEventNameForRecording(string recordingName) global
4 | return "McmRecorder_VrGesture_PlayRecording:" + recordingName
5 | endFunction
6 |
7 | string function GetRecordingNameFromModEvent(string modEventName) global
8 | return StringUtil.Substring(modEventName, StringUtil.GetLength("McmRecorder_VrGesture_PlayRecording:"))
9 | endFunction
10 |
11 | bool function IsVrikInstalled() global
12 | return Game.GetModByName("vrik.esp") != 255
13 | endFunction
14 |
15 | function RegisterVrikGesturesForRecordings() global
16 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
17 | int i = 0
18 | while i < recordingNames.Length
19 | string recordingName = recordingNames[i]
20 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
21 | bool isGesture = McmRecorder_RecordingInfo.IsVrGesture(recordingInfo)
22 | if isGesture
23 | RegisterVrikGestureForRecording(recordingName)
24 | endIf
25 | i += 1
26 | endWhile
27 | endFunction
28 |
29 | function RegisterVrikGestureForRecording(string recordingName) global
30 | VRIK.VrikAddGestureAction(GetModEventNameForRecording(recordingName), "MCM Recording: " + recordingName)
31 | ListenForVriKGestureForRecording(recordingName)
32 | endFunction
33 |
34 | function UnregisterVrikGestureForRecording(string recordingName) global
35 | ; TODO - Looks like there's no way to remove a VRIK gesture action?????
36 | StopListeningForVriKGestureForRecording(recordingName)
37 | endFunction
38 |
39 | function ListenForVriKGesturesForRecordings() global
40 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
41 | int i = 0
42 | while i < recordingNames.Length
43 | string recordingName = recordingNames[i]
44 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
45 | bool isGesture = McmRecorder_RecordingInfo.IsVrGesture(recordingInfo)
46 | if isGesture
47 | ListenForVriKGestureForRecording(recordingName)
48 | endIf
49 | i += 1
50 | endWhile
51 | endFunction
52 |
53 | function ListenForVriKGestureForRecording(string recordingName) global
54 | McmRecorder.GetMcmRecorderInstance().ListenForVriKGestureForRecording(recordingName)
55 | endFunction
56 |
57 | function StopListeningForVriKGestureForRecording(string recordingName) global
58 | McmRecorder.GetMcmRecorderInstance().StopListeningForVriKGestureForRecording(recordingName)
59 | endFunction
60 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_JDB.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_JDB hidden
2 | {Get JDB paths for JDB data stored by MCM Recorder}
3 |
4 | string function JdbPath_CurrentRecordingName() global
5 | return ".mcmRecorder.currentRecording.recordingName"
6 | endFunction
7 |
8 | string function JdbPath_CurrentRecordingModName() global
9 | return ".mcmRecorder.currentRecording.currentModName"
10 | endFunction
11 |
12 | string function JdbPath_CurrentRecordingRecordingStep() global
13 | return ".mcmRecorder.currentRecording.currentModStep"
14 | endFunction
15 |
16 | string function JdbPath_McmOptions() global
17 | return ".mcmRecorder.mcmOptions"
18 | endFunction
19 |
20 | string function JdbPath_McmOptions_MarkForReset() global
21 | return ".mcmRecorder.McmOptionsShouldBeReset"
22 | endFunction
23 |
24 | string function JdbPath_IsPlayingRecording() global
25 | return ".mcmRecorder.isPlayingRecording"
26 | endFunction
27 |
28 | string function JdbPath_PlayingRecordingName() global
29 | return ".mcmRecorder.playingRecording.name"
30 | endFunction
31 |
32 | string function JdbPath_PlayingRecordingSteps() global
33 | return ".mcmRecorder.playingRecording.steps"
34 | endFunction
35 |
36 | string function JdbPath_PlayingStepFilename() global
37 | return ".mcmRecorder.playingRecording.stepFilename"
38 | endFunction
39 |
40 | string function JdbPath_PlayingStepIndex() global
41 | return ".mcmRecorder.playingRecording.stepIndex"
42 | endFunction
43 |
44 | string function JdbPath_PlayingRecordingModName() global
45 | return ".mcmRecorder.playingRecording.modName"
46 | endFunction
47 |
48 | string function JdbPath_PlayingRecordingModPageName() global
49 | return ".mcmRecorder.playingRecording.pageName"
50 | endFunction
51 |
52 | string function JdbPath_PlayingRecordingModsPlayed() global
53 | return ".mcmRecorder.playingRecording.modsPlayed"
54 | endFunction
55 |
56 | string function JdbPath_CurrentlySkippingModName() global
57 | return ".mcmRecorder.playingRecording.modCurrentlySkipping"
58 | endFunction
59 |
60 | string function JdbPath_AutorunHistory() global
61 | return ".mcmRecorder.autorunHistory"
62 | endFunction
63 |
64 | string function JdbPath_MCM_KeyboardShortcuts_ShortcutInfos() global
65 | return ".mcmRecorder.mcm.keyboardShortcuts.shortcutInfos"
66 | endFunction
67 |
68 | string function JdbPath_MCM_KeyboardShortcuts_ShortcutOptions() global
69 | return ".mcmRecorder.mcm.keyboardShortcuts.shortcutOptions"
70 | endFunction
71 |
72 | string function JdbPath_Config_ShowNotifications() global
73 | return ".mcmRecorder.config.notifications"
74 | endFunction
75 |
76 | string function JdbPath_Config_ShowMessageBoxes() global
77 | return ".mcmRecorder.config.messageboxes"
78 | endFunction
79 |
80 | string function JdbPathPart(string part) global
81 | string[] parts = StringUtil.Split(part, ".")
82 | string sanitized = ""
83 | int i = 0
84 | while i < parts.Length
85 | if i == 0
86 | sanitized += parts[i]
87 | else
88 | sanitized += "_" + parts[i]
89 | endIf
90 | i += 1
91 | endWhile
92 | return sanitized
93 | endFunction
94 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_UI.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_UI
2 |
3 | function Notification(string text) global
4 | if McmRecorder_Config.ShowNotifications()
5 | Debug.Notification("[McmRecorder] " + text)
6 | endIf
7 | endFunction
8 |
9 | function MessageBox(string text) global
10 | if McmRecorder_Config.ShowMessageBoxes()
11 | Debug.MessageBox(text)
12 | endIf
13 | endFunction
14 |
15 | string function Options_Continue() global
16 | return "Continue"
17 | endFunction
18 |
19 | string function Options_TryAgain() global
20 | return "Try again"
21 | endFunction
22 |
23 | string function Options_SkipThisMod() global
24 | return "Skip this mod"
25 | endFunction
26 |
27 | function FinishedMessage(string recordingName) global
28 | int recording = McmRecorder_RecordingInfo.Get(recordingName)
29 | string finishedMessage = McmRecorder_RecordingInfo.GetCompleteMessage(recording)
30 | if ! finishedMessage
31 | finishedMessage = recordingName + " has finished playing."
32 | endIf
33 | MessageBox(finishedMessage)
34 | endFunction
35 |
36 | function WelcomeMessage(string recordingName) global
37 | int recording = McmRecorder_RecordingInfo.Get(recordingName)
38 | string welcomeMessage = McmRecorder_RecordingInfo.GetWelcomeMessage(recording)
39 | if welcomeMessage
40 | MessageBox(welcomeMessage)
41 | endIf
42 | endFunction
43 |
44 | function OpenSystemMenuDuringRecordingMessage(string recordingName) global
45 | int stepCount = JMap.count(McmRecorder_Player.GetCurrentlyPlayingSteps())
46 | int stepIndex = McmRecorder_Player.GetCurrentlyPlayingStepIndex()
47 | string stepName = McmRecorder_Player.GetCurrentlyPlayingStepFilename()
48 | string text = recordingName + " setup currently in progress."
49 | text += "\n\nCurrently playing step " + stepName + " ("+ (stepIndex + 1) + "/" + stepCount + ")"
50 | text += "\n\nPlease exit the menu to allow this recording to continue."
51 | MessageBox(text)
52 | endFunction
53 |
54 | string function GetUserResponseForNotFoundSelector(string modName, string pageName, string selector) global
55 | string description = "Could not find MCM option:\n\nMod name: " + modName
56 | if pageName
57 | description += "\nPage name: " + pageName
58 | endIf
59 | description += "\nField name: " + selector
60 | description += "\n\nWhich of the following would you like to do?"
61 | description += "\n- Continue this mod and move on to the next MCM field"
62 | description += "\n- Try finding this MCM field again"
63 | description += "\n- Skip this mod and move on to configuring the next one"
64 | McmRecorder recorder = McmRecorder.GetMcmRecorderInstance()
65 | recorder.McmRecorder_MessageText.SetName(description)
66 | int response = recorder.McmRecorder_Message_SelectorNotFound.Show()
67 | if response == 0
68 | return Options_Continue()
69 | elseIf response == 1
70 | return Options_TryAgain()
71 | elseIf response == 2
72 | return Options_SkipThisMod()
73 | endIf
74 | endFunction
75 |
76 | string function GetUserResponseForNotFoundMod(string modName) global
77 | string description = "Could not find MCM\n\nMod name: " + modName
78 | description += "\n\nWhich of the following would you like to do?"
79 | description += "\n- Try waiting longer for this mod to become available"
80 | description += "\n- Skip this mod and move on to configuring the next one"
81 | McmRecorder recorder = McmRecorder.GetMcmRecorderInstance()
82 | recorder.McmRecorder_MessageText.SetName(description)
83 | int response = recorder.McmRecorder_Message_ModNotFound.Show()
84 | if response == 0
85 | return Options_TryAgain()
86 | elseIf response == 1
87 | return Options_SkipThisMod()
88 | endIf
89 | endFunction
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_KeyboardShortcuts.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_KeyboardShortcuts
2 | {Responsible for MCM Recorder keyboard shortcuts and VR VRIK gestures}
3 |
4 | function AddRecording(string recordingName) global
5 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
6 | int shortcut = JMap.getObj(recordingInfo, "shortcut")
7 | if ! shortcut
8 | shortcut = JMap.object()
9 | JMap.setObj(recordingInfo, "shortcut", shortcut)
10 | endIf
11 | JMap.setInt(shortcut, "key", -1)
12 | McmRecorder_RecordingInfo.Save(recordingName, recordingInfo)
13 | endFunction
14 |
15 | int function GetShortcutsInfos() global
16 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
17 | int shortcutInfos = JArray.object()
18 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_MCM_KeyboardShortcuts_ShortcutInfos(), shortcutInfos, createMissingKeys = true)
19 | int i = 0
20 | while i < recordingNames.Length
21 | string recordingName = recordingNames[i]
22 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
23 | int shortcut = JMap.getObj(recordingInfo, "shortcut")
24 | if shortcut
25 | int shortcutInfo = JMap.object()
26 | JMap.setStr(shortcutInfo, "recordingName", recordingName)
27 | JMap.setObj(shortcutInfo, "shortcut", shortcut)
28 | JArray.addObj(shortcutInfos, shortcutInfo)
29 | endIf
30 | i += 1
31 | endWhile
32 | return shortcutInfos
33 | endFunction
34 |
35 | int[] function GetAllKeyboardShortcutKeys() global
36 | int[] keycodes
37 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
38 | int shortcutInfos = JArray.object()
39 | int i = 0
40 | while i < recordingNames.Length
41 | string recordingName = recordingNames[i]
42 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
43 | int shortcut = JMap.getObj(recordingInfo, "shortcut")
44 | if shortcut
45 | int keycode = JMap.getInt(shortcut, "key")
46 | if keycodes.Find(keycode) == -1
47 | keycodes = Utility.ResizeIntArray(keycodes, keycodes.Length + 1)
48 | keycodes[keycodes.Length - 1] = keycode
49 | endIf
50 | endIf
51 | i += 1
52 | endWhile
53 | return keycodes
54 | endFunction
55 |
56 | function RunKeyboardShortcutIfAny(int pressedKey) global
57 | bool ctrlPressed = Input.IsKeyPressed(29) || Input.IsKeyPressed(157)
58 | bool altPressed = Input.IsKeyPressed(56) || Input.IsKeyPressed(184)
59 | bool shiftPressed = Input.IsKeyPressed(42) || Input.IsKeyPressed(54)
60 | bool found
61 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
62 | int shortcutInfos = JArray.object()
63 | int i = 0
64 | while i < recordingNames.Length && (!found)
65 | string recordingName = recordingNames[i]
66 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
67 | int shortcut = JMap.getObj(recordingInfo, "shortcut")
68 | if shortcut
69 | int keycode = JMap.getInt(shortcut, "key")
70 | bool ctrl = JMap.getStr(shortcut, "ctrl") == "true"
71 | bool alt = JMap.getStr(shortcut, "alt") == "true"
72 | bool shift = JMap.getStr(shortcut, "shift") == "true"
73 | if pressedKey == keycode && \
74 | ctrlPressed == ctrl && \
75 | altPressed == alt && \
76 | shiftPressed == shift
77 | McmRecorder_Logging.ConsoleOut("[Keyboard Shortcut] " + recordingName + " Key:" + keycode + " Ctrl:" + ctrl + " Alt:" + alt + " Shift:" + shift)
78 | bool notifications = McmRecorder_Config.ShowNotifications()
79 | bool messageboxes = McmRecorder_Config.ShowMessageBoxes()
80 | McmRecorder_Config.SetShowNotifications(false)
81 | McmRecorder_Config.SetShowMessageBoxes(false)
82 | McmRecorder_Player.PlayRecording(recordingName)
83 | McmRecorder_Config.SetShowNotifications(notifications)
84 | McmRecorder_Config.SetShowMessageBoxes(messageboxes)
85 | found = true
86 | endIf
87 | endIf
88 | i += 1
89 | endWhile
90 | endFunction
91 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_RecordingFiles.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_RecordingFiles hidden
2 | {Responsible for managing the recording files found in Data\McmRecorder\}
3 |
4 | function SaveCurrentRecording(string recordingName, string modName) global
5 | JValue.writeToFile(McmRecorder_Recorder.GetCurrentRecordingSteps(), GetFileNameForRecordingAction(recordingName, modName))
6 | endFunction
7 |
8 | function SaveRecordingInfoFile(string recordingName, int metaInfo) global
9 | JValue.writeToFile(metaInfo, PathToRecordingFolder(recordingName) + ".json")
10 | endFunction
11 |
12 | int function GetAllStepsForRecording(string recordingName) global
13 | return JValue.readFromDirectory(PathToRecordingFolder(recordingName))
14 | endFunction
15 |
16 | string[] function GetRecordingNames() global
17 | if ! MiscUtil.FileExists(PathToRecordings())
18 | string[] ret
19 | return ret
20 | endIf
21 |
22 | string[] fileNames
23 |
24 | if McmRecorder_Config.IsSkyrimVR() || McmRecorder_Config.IsSkyrimLE()
25 | fileNames = JMap.allKeysPArray(JValue.readFromDirectory(PathToRecordings()))
26 | else
27 | fileNames = MiscUtil.FilesInFolder(PathToRecordings())
28 | endIf
29 |
30 | int i = 0
31 | while i < fileNames.Length
32 | fileNames[i] = StringUtil.Substring(fileNames[i], 0, StringUtil.Find(fileNames[i], ".json"))
33 | i += 1
34 | endWhile
35 | return fileNames
36 | endFunction
37 |
38 | string[] function GetRecordingStepFilenames(string recordingName) global
39 | if McmRecorder_Config.IsSkyrimVR() || McmRecorder_Config.IsSkyrimLE()
40 | return JMap.allKeysPArray(JValue.readFromDirectory(PathToRecordingFolder(recordingName)))
41 | else
42 | return MiscUtil.FilesInFolder(PathToRecordingFolder(recordingName))
43 | endIf
44 | endFunction
45 |
46 | int function GetRecordingInfo(string recordingName) global
47 | return JValue.ReadFromFile(PathToRecordingFolder(recordingName) + ".json")
48 | endFunction
49 |
50 | int function GetRecordingStep(string recordingName, string stepName) global
51 | return JValue.readFromFile(PathToStepFile(recordingName, stepName))
52 | endFunction
53 |
54 | string function GetRecordingDescription(string recordingName) global
55 | int info = GetRecordingInfo(recordingName)
56 | string[] stepNames = GetRecordingStepFilenames(recordingName)
57 |
58 | string recordingDescription = recordingName
59 | if JMap.getStr(info, "version")
60 | recordingDescription += " (" + JMap.getStr(info, "version") + ")"
61 | endIf
62 | if JMap.getStr(info, "author")
63 | recordingDescription += "\n~ by " + JMap.getStr(info, "author") + " ~"
64 | endIf
65 | recordingDescription += "\nSteps: " + stepNames.Length
66 |
67 | return recordingDescription
68 | endFunction
69 |
70 | string function PathToRecordings() global
71 | return "Data/McmRecorder"
72 | endFunction
73 |
74 | string function PathToRecordingFolder(string recordingName) global
75 | return PathToRecordings() + "/" + FileSystemPathPart(recordingName)
76 | endFunction
77 |
78 | string function PathToStepFile(string recordingName, string stepName) global
79 | if StringUtil.Find(stepName, ".json")
80 | return PathToRecordings() + "/" + FileSystemPathPart(recordingName) + "/" + stepName
81 | else
82 | return PathToRecordings() + "/" + FileSystemPathPart(recordingName) + "/" + stepName + ".json"
83 | endIf
84 | endFunction
85 |
86 | string function FileSystemPathPart(string part) global
87 | string[] parts = StringUtil.Split(part, "/")
88 | string sanitized = ""
89 | int i = 0
90 | while i < parts.Length
91 | if i == 0
92 | sanitized += parts[i]
93 | else
94 | sanitized += "_" + parts[i]
95 | endIf
96 | i += 1
97 | endWhile
98 | parts = StringUtil.Split(sanitized, "\\")
99 | sanitized = ""
100 | i = 0
101 | while i < parts.Length
102 | if i == 0
103 | sanitized += parts[i]
104 | else
105 | sanitized += "_" + parts[i]
106 | endIf
107 | i += 1
108 | endWhile
109 | return sanitized
110 | endFunction
111 |
112 | string function GetFileNameForRecordingAction(string recordingName, string modName) global
113 | string recordingFolder = PathToRecordingFolder(recordingName)
114 | int recordingStepNumber
115 | if McmRecorder_Config.IsSkyrimVR() || McmRecorder_Config.IsSkyrimLE()
116 | recordingStepNumber = JMap.allKeysPArray(JValue.readFromDirectory(recordingFolder)).Length
117 | else
118 | recordingStepNumber = MiscUtil.FilesInFolder(recordingFolder).Length
119 | endIf
120 | if modName != McmRecorder_Recorder.GetCurrentRecordingModName()
121 | recordingStepNumber += 1
122 | McmRecorder_Recorder.SetCurrentRecordingModName(modName)
123 | endIf
124 | string filenameNumericPrefix = recordingStepNumber
125 | while StringUtil.GetLength(filenameNumericPrefix) < 4
126 | filenameNumericPrefix = "0" + filenameNumericPrefix
127 | endWhile
128 | return PathToRecordingFolder(recordingName) + "/" + filenameNumericPrefix + "_" + FileSystemPathPart(modName) + ".json"
129 | endFunction
130 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder extends Quest hidden
2 |
3 | ; TODO separate out an McmRecorderPrivate so this can become just a public API intended for integration
4 |
5 | ; **PRIVATE**
6 | ;
7 | ; Primary instance of the SKI_ConfigManager from the SKI_ConfigManagerInstance quest
8 | SKI_ConfigManager property skiConfigManager auto
9 |
10 | ; **PRIVATE**
11 | ;
12 | ; Message used to ask the user if they want to run a full recording, view steps, or add to the recording.
13 | Message property McmRecorder_Message_RunRecordingOrViewSteps auto
14 |
15 | ; **PRIVATE**
16 | ;
17 | ; Message used to ask the user if they want to skip a field that wasn't found, retry it, or skip the entire mod.
18 | Message property McmRecorder_Message_SelectorNotFound auto
19 |
20 | ; **PRIVATE**
21 | ;
22 | ; Message used to ask the user if they want to skip a mod or wait for it to show up when a mod cannot be found
23 | Message property McmRecorder_Message_ModNotFound auto
24 |
25 | ; **PRIVATE**
26 | ;
27 | ; Form used to set dynamic text in all of the Message dialogs used by MCM Recorder.
28 | Form property McmRecorder_MessageText auto
29 |
30 | ; **PRIVATE**
31 | ;
32 | ; Stores the installed version of MCM Recorder. Used for performing version upgrades.
33 | string property CurrentlyInstalledVersion auto
34 |
35 | ; Returns the installed version of MCM Recorder
36 | string function GetVersion() global
37 | return "1.0.7"
38 | endFunction
39 |
40 | event OnInit()
41 | CurrentlyInstalledVersion = GetVersion()
42 | skiConfigManager = Quest.GetQuest("SKI_ConfigManagerInstance") as SKI_ConfigManager
43 | StartListenForKeyboardShortcuts()
44 | ListenForRaceMenuClose()
45 | McmRecorder_VRIK.RegisterVrikGesturesForRecordings()
46 | ListenForRecordingSkseModEvents()
47 | endEvent
48 |
49 | event SaveGameLoaded()
50 | RegisterForSingleUpdate(5)
51 | StartListenForKeyboardShortcuts()
52 | McmRecorder_VRIK.ListenForVriKGesturesForRecordings()
53 | ListenForRecordingSkseModEvents()
54 | endEvent
55 |
56 | function StartListenForKeyboardShortcuts()
57 | int[] keycodes = McmRecorder_KeyboardShortcuts.GetAllKeyboardShortcutKeys()
58 | int i = 0
59 | while i < keycodes.Length
60 | RegisterForKey(keycodes[i])
61 | i += 1
62 | endWhile
63 | endFunction
64 |
65 | function StopListeningForKeyboardShortcuts()
66 | int[] keycodes = McmRecorder_KeyboardShortcuts.GetAllKeyboardShortcutKeys()
67 | int i = 0
68 | while i < keycodes.Length
69 | UnregisterForKey(keycodes[i])
70 | i += 1
71 | endWhile
72 | endFunction
73 |
74 | event OnKeyDown(int keycode)
75 | if ! McmRecorder_Player.IsPlayingRecording()
76 | McmRecorder_KeyboardShortcuts.RunKeyboardShortcutIfAny(keycode)
77 | endIf
78 | endEvent
79 |
80 | ; **DO NOT USE THIS**
81 | ;
82 | ; Returns a **private** script containing the script fields and properties used by MCM Recorder
83 | McmRecorder function GetMcmRecorderInstance() global
84 | return Quest.GetQuest("McmRecorder") as McmRecorder
85 | endFunction
86 |
87 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
88 | ; Get SkyUI MCM Script Instance
89 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90 |
91 | SKI_ConfigBase function GetMcmInstance(string modName) global
92 | McmRecorder recorder = McmRecorder.GetMcmRecorderInstance()
93 | int index = recorder.skiConfigManager.ModNames.Find(modName)
94 | return recorder.skiConfigManager.ModConfigs[index]
95 | endFunction
96 |
97 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
98 | ; Autorun
99 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100 |
101 | function ListenForRaceMenuClose()
102 | RegisterForMenu("RaceSex Menu")
103 | endFunction
104 |
105 | event OnMenuClose(string menuName)
106 | if menuName == "RaceSex Menu"
107 | UnregisterForMenu("RaceSex Menu")
108 | AutorunRecordings()
109 | endIf
110 | endEvent
111 |
112 | function AutorunRecordings()
113 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
114 | int i = 0
115 | while i < recordingNames.Length
116 | string recordingName = recordingNames[i]
117 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
118 | if McmRecorder_RecordingInfo.IsAutorun(recordingInfo) && (! McmRecorder_Player.HasBeenAutorun(recordingName))
119 | McmRecorder_Player.MarkHasBeenAutorun(recordingName)
120 | McmRecorder_Logging.Log("Autorun Recording " + recordingName)
121 | McmRecorder_Player.PlayRecording(recordingName, mcmLoadWaitTime = 30.0)
122 | endIf
123 | i += 1
124 | endWhile
125 | endFunction
126 |
127 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
128 | ; Pause and Cancel Running Recording
129 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
130 |
131 | function ListenForSystemMenuOpen()
132 | UnregisterForMenu("Journal Menu")
133 | RegisterForMenu("Journal Menu") ; Track when the menu opens so we can show a mesasge if a recording is playing
134 | endFunction
135 |
136 | function StopListeningForSystemMenuOpen()
137 | UnregisterForMenu("Journal Menu")
138 | endFunction
139 |
140 | event OnMenuOpen(string menuName)
141 | if menuName == "Journal Menu"
142 | if McmRecorder_Player.IsPlayingRecording()
143 | McmRecorder_UI.OpenSystemMenuDuringRecordingMessage(McmRecorder_Player.GetCurrentlyPlayingRecordingName())
144 | endIf
145 | endIf
146 | endEvent
147 |
148 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
149 | ; VR Gestures
150 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
151 |
152 | function ListenForVriKGestureForRecording(string recordingName)
153 | string modEventName = McmRecorder_VRIK.GetModEventNameForRecording(recordingName)
154 | RegisterForModEvent(modEventName, "OnVrikGesture")
155 | endFunction
156 |
157 | function StopListeningForVriKGestureForRecording(string recordingName)
158 | string modEventName = McmRecorder_VRIK.GetModEventNameForRecording(recordingName)
159 | UnregisterForModEvent(modEventName)
160 | endFunction
161 |
162 | event OnVrikGesture(string eventName, string strArg, float fltArg, Form sender)
163 | string recordingName = McmRecorder_VRIK.GetRecordingNameFromModEvent(eventName)
164 | McmRecorder_Player.PlayRecording(recordingName, verbose = false)
165 | endEvent
166 |
167 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
168 | ; VR Gestures
169 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
170 |
171 | function ListenForRecordingSkseModEvents()
172 | RegisterForModEvent("McmRecorder_PlayRecording", "OnRecordingModEvent")
173 | endFunction
174 |
175 | event OnRecordingModEvent(string eventName, string recordingName, float fltArg, Form sender)
176 | McmRecorder_Player.PlayRecording(recordingName, verbose = false)
177 | endEvent
178 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_McmFields.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_McmFields hidden
2 | {Responsible for storage of and querying of individual fields on Mod Configuration Menu pages}
3 |
4 | ; TODO OptionsForModPage_ByState & GetConfigurationOptionByState ? O[tion IDs fine for stateful options?
5 |
6 | function TrackField(string modName, string pageName, string optionType, int optionId, string text, string strValue, float fltValue, string stateName, bool force = false) global
7 | if McmOptionsShouldBeReset()
8 | ResetMcmOptions()
9 | endIf
10 |
11 | if force || McmRecorder_Recorder.IsRecording() || McmRecorder_Player.IsPlayingRecording()
12 | int optionsOnModPageForType = OptionsForModPage_ByOptionType(modName, pageName, optionType)
13 | int option = JMap.object()
14 | JArray.addObj(optionsOnModPageForType, option)
15 | JIntMap.setObj(OptionsForModPage_ByOptionIds(modName, pageName), optionId, option)
16 | JMap.setInt(option, "id", optionId)
17 | JMap.setStr(option, "state", stateName)
18 | JMap.setStr(option, "type", optionType)
19 | JMap.setStr(option, "text", text)
20 | JMap.setStr(option, "strValue", strValue)
21 | JMap.setFlt(option, "fltValue", fltvalue)
22 | endIf
23 | endFunction
24 |
25 | function MarkMcmOptionsForReset() global
26 | JDB.solveIntSetter(McmRecorder_JDB.JdbPath_McmOptions_MarkForReset(), 1, createMissingKeys = true)
27 | endFunction
28 |
29 | function UnMarkMcmOptionsForReset() global
30 | JDB.solveIntSetter(McmRecorder_JDB.JdbPath_McmOptions_MarkForReset(), 0)
31 | endFunction
32 |
33 | bool function McmOptionsShouldBeReset() global
34 | return JDB.solveInt(McmRecorder_JDB.JdbPath_McmOptions_MarkForReset()) == 1
35 | endFunction
36 |
37 | function ResetMcmOptions() global
38 | UnMarkMcmOptionsForReset()
39 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_McmOptions(), JMap.object(), createMissingKeys = true)
40 | endFunction
41 |
42 | int function GetConfigurationOptionById(string modName, string pageName, int optionId) global
43 | return JIntMap.getObj(OptionsForModPage_ByOptionIds(modName, pageName), optionId)
44 | endFunction
45 |
46 | int function OptionsForModPage_ByOptionIds(string modName, string pageName) global
47 | return JMap.getObj(OptionsForModPage(modName, pageName), "byId")
48 | endFunction
49 |
50 | int function OptionsForModPage_ByOptionTypes(string modName, string pageName) global
51 | return JMap.getObj(OptionsForModPage(modName, pageName), "byType")
52 | endFunction
53 |
54 | int function OptionsForModPage_ByOptionType(string modName, string pageName, string optionType) global
55 | int byType = OptionsForModPage_ByOptionTypes(modName, pageName)
56 | int typeMap = JMap.getObj(byType, optionType)
57 | if ! typeMap
58 | typeMap = JArray.object()
59 | JMap.setObj(byType, optionType, typeMap)
60 | endIf
61 | return typeMap
62 | endFunction
63 |
64 | int function AllMcmOptions() global
65 | int options = JDB.solveObj(McmRecorder_JDB.JdbPath_McmOptions())
66 | if ! options
67 | options = JMap.object()
68 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_McmOptions(), options, createMissingKeys = true)
69 | endIf
70 | return options
71 | endFunction
72 |
73 | int function OptionsForMod(string modName) global
74 | int allOptions = AllMcmOptions()
75 | int options = JMap.getObj(allOptions, modName)
76 | if ! options
77 | options = JMap.object()
78 | JMap.setObj(allOptions, modName, options)
79 | endIf
80 | return options
81 | endFunction
82 |
83 | int function OptionsForModPage(string modName, string pageName) global
84 | int modOptions = OptionsForMod(modName)
85 | if ! pageName
86 | pageName = "SKYUI_DEFAULT_PAGE"
87 | endIf
88 | int options = JMap.getObj(modOptions, pageName)
89 | if ! options
90 | options = JMap.object()
91 | JMap.setObj(modOptions, pageName, options)
92 | JMap.setObj(options, "byId", JIntMap.object())
93 | JMap.setObj(options, "byType", JMap.object())
94 | endIf
95 | return options
96 | endFunction
97 |
98 | ; Given the internal numerical identifier for field types used by SkyUI in mod configuration menus,
99 | ; return a text representation of the field type, e.g. "input" rather than 8
100 | string function GetOptionTypeName(int skyUiMcmOptiontype) global
101 | if skyUiMcmOptiontype == 0
102 | return "empty"
103 | elseIf skyUiMcmOptiontype == 1
104 | return "header"
105 | elseIf skyUiMcmOptiontype == 2
106 | return "text"
107 | elseIf skyUiMcmOptiontype == 3
108 | return "toggle"
109 | elseIf skyUiMcmOptiontype == 4
110 | return "slider"
111 | elseIf skyUiMcmOptiontype == 5
112 | return "menu"
113 | elseIf skyUiMcmOptiontype == 6
114 | return "color"
115 | elseIf skyUiMcmOptiontype == 7
116 | return "keymap"
117 | elseIf skyUiMcmOptiontype == 8
118 | return "input"
119 | else
120 | return "unknown"
121 | endIf
122 | endFunction
123 |
124 | int function GetSelectorIndex(string modName, string pageName, int optionId) global
125 | int option = GetConfigurationOptionById(modName, pageName, optionId)
126 |
127 | if ! option
128 | McmRecorder_Logging.Log("Did not find option with ID " + optionId)
129 | return -2
130 | endIf
131 |
132 | string selector = GetOptionSelector(option)
133 | string stateName = JMap.getStr(option, "state")
134 |
135 | int optionsToSearch = OptionsForModPage_ByOptionType(modName, pageName, JMap.getStr(option, "type"))
136 | int optionsToSearchCount = JArray.count(optionsToSearch)
137 |
138 | int index = -1 ; The index of the item to return (-1 means it's the only one with the selector on the page)
139 | int count = 0
140 |
141 | int i = 0
142 | while i < optionsToSearchCount && index == -1
143 | int optionOnPage = JArray.getObj(optionsToSearch, i)
144 | string optionOnPageSelector = GetOptionSelector(optionOnPage)
145 |
146 | if optionOnPageSelector == selector
147 | count += 1
148 | endIf
149 |
150 | if stateName
151 | if stateName == JMap.getStr(optionOnPage, "state")
152 | index = count ; This is this specific item
153 | endIf
154 | elseIf optionId == JMap.getInt(optionOnPage, "id")
155 | index = count ; This is this specific item
156 | endIf
157 |
158 | i += 1
159 | endWhile
160 |
161 | if count > 1
162 | return index
163 | else
164 | return -1
165 | endIf
166 | endFunction
167 |
168 | string function GetOptionSelector(int option) global
169 | string selector = JMap.getStr(option, "text")
170 | if ! selector && JMap.getStr(option, "type") == "text" ; Use the 'right' side
171 | selector = JMap.getStr(option, "strValue")
172 | endIf
173 | return selector
174 | endFunction
175 |
176 | string function GetWildcardMatcher(string selector) global
177 | int strLength = StringUtil.GetLength(selector)
178 | if StringUtil.Substring(selector, 0, 1) == "*" && StringUtil.Substring(selector, strLength - 1, 1) == "*"
179 | return StringUtil.Substring(selector, 1, strLength - 2)
180 | else
181 | return ""
182 | endIf
183 | endFunction
184 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_Recorder.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_Recorder hidden
2 | {Responsible for recording actions in Mod Configuration Menus}
3 |
4 | bool function IsRecording() global
5 | return GetCurrentRecordingName()
6 | endFunction
7 |
8 | bool function AnyRecordings() global
9 | return RecordingsCount() > 0
10 | endFunction
11 |
12 | int function RecordingsCount() global
13 | return McmRecorder_RecordingFiles.GetRecordingNames().Length
14 | endFunction
15 |
16 | function RecordAction(SKI_ConfigBase mcm, string modName, string pageName, string optionType, int optionId, string stateName = "", bool recordFloatValue = false, bool recordStringValue = false, bool recordOptionType = false, float fltValue = -1.0, string strValue = "", string[] menuOptions = None) global
17 | if IsRecording() && modName != "MCM Recorder"
18 | if modName != GetCurrentRecordingModName()
19 | ResetCurrentRecordingSteps()
20 | endIf
21 |
22 | int option = McmRecorder_McmFields.GetConfigurationOptionById(modName, pageName, optionId)
23 |
24 | if ! option
25 | McmRecorder_Logging.ConsoleOut("Could not get configuration option for " + modName + " " + pageName + " optionId " + optionId)
26 | McmRecorder_Logging.DumpAll("Data/McmRecorder/.debug/ProblemMessageDump.json")
27 | Debug.MessageBox("[McmRecorder] Problem! You clicked on an MCM field which we were not able to detect.")
28 | Debug.Notification("[McmRecorder] Problem! You clicked on an MCM field which we were not able to detect.")
29 | return
30 | endIf
31 |
32 | if optionType == "menu" && fltValue == -1
33 | return ; The menu was opened but then closed without choosing an option. We don't reproduce this behavior.
34 | endIf
35 |
36 | int mcmAction = JMap.object()
37 | JArray.addObj(GetCurrentRecordingSteps(), mcmAction)
38 |
39 | JMap.setStr(mcmAction, "mod", modName)
40 |
41 | if pageName != "SKYUI_DEFAULT_PAGE"
42 | JMap.setStr(mcmAction, "page", pageName)
43 | endIf
44 |
45 | string selector = JMap.getStr(option, "text")
46 |
47 | ; How many items on this page have the same 'selector'?
48 | int selectorIndex = McmRecorder_McmFields.GetSelectorIndex(modName, pageName, optionId)
49 | if selectorIndex > -1
50 | JMap.setInt(mcmAction, "index", selectorIndex)
51 | endIf
52 |
53 | string debugPrefix = "[Record Action] " + modName
54 | if pageName
55 | debugPrefix += ": " + pageName
56 | endIf
57 | debugPrefix += " (" + selector + ")"
58 | if selectorIndex > -1
59 | debugPrefix += " [" + selectorIndex + "]"
60 | endIf
61 |
62 | if optionType == "clickable"
63 | if JMap.getStr(option, "type") == "toggle"
64 | JMap.setStr(mcmAction, "option", selector)
65 | if JMap.getFlt(option, "fltValue") == 0
66 | JMap.setStr(mcmAction, "toggle", "on")
67 | McmRecorder_Logging.ConsoleOut(debugPrefix + " on")
68 | else
69 | JMap.setStr(mcmAction, "toggle", "off")
70 | McmRecorder_Logging.ConsoleOut(debugPrefix + " off")
71 | endIf
72 | else
73 | if selector
74 | JMap.setStr(mcmAction, "click", selector)
75 | McmRecorder_Logging.ConsoleOut(debugPrefix + " click")
76 | else
77 | JMap.setStr(mcmAction, "click", JMap.getStr(option, "strValue"))
78 | JMap.setStr(mcmAction, "side", "right")
79 | McmRecorder_Logging.ConsoleOut(debugPrefix + " click (right)")
80 | endIf
81 | endIf
82 | elseIf optionType == "menu"
83 | JMap.setStr(mcmAction, "option", selector)
84 | if stateName
85 | string previousState = mcm.GetState()
86 | mcm.GotoState(stateName)
87 | mcm.OnMenuOpenST()
88 | string selectedOptionText = menuOptions[fltValue as int]
89 | JMap.setStr(mcmAction, "choose", selectedOptionText)
90 | mcm.GotoState(previousState)
91 | McmRecorder_Logging.ConsoleOut(debugPrefix + " choose '" + selectedOptionText + "'")
92 | else
93 | mcm.OnOptionMenuOpen(optionId)
94 | string selectedOptionText = menuOptions[fltValue as int]
95 | JMap.setStr(mcmAction, "choose", selectedOptionText)
96 | McmRecorder_Logging.ConsoleOut(debugPrefix + " choose '" + selectedOptionText + "'")
97 | endIf
98 | elseIf optionType == "slider"
99 | JMap.setStr(mcmAction, "option", selector)
100 | JMap.setFlt(mcmAction, "slider", fltValue)
101 | McmRecorder_Logging.ConsoleOut(debugPrefix + " slider " + fltValue)
102 | elseIf optionType == "keymap"
103 | JMap.setStr(mcmAction, "option", selector)
104 | JMap.setInt(mcmAction, "shortcut", fltValue as int)
105 | McmRecorder_Logging.ConsoleOut(debugPrefix + " shortcut " + fltValue as int)
106 | elseIf optionType == "color"
107 | JMap.setStr(mcmAction, "option", selector)
108 | JMap.setInt(mcmAction, "color", fltValue as int)
109 | McmRecorder_Logging.ConsoleOut(debugPrefix + " color " + fltValue as int)
110 | elseIf optionType == "input"
111 | JMap.setStr(mcmAction, "option", selector)
112 | JMap.setStr(mcmAction, "text", strValue)
113 | McmRecorder_Logging.ConsoleOut(debugPrefix + " input '" + strValue + "'")
114 | endIf
115 |
116 | McmRecorder_RecordingFiles.SaveCurrentRecording(GetCurrentRecordingName(), modName)
117 | endIf
118 | endFunction
119 |
120 | function BeginRecording(string recordingName) global
121 | SetCurrentRecordingName(recordingName)
122 | SetCurrentRecordingModName("")
123 | ResetCurrentRecordingSteps()
124 | int metaFile = JMap.object()
125 | string authorName = Game.GetPlayer().GetActorBase().GetName()
126 | JMap.setStr(metaFile, "name", recordingName)
127 | JMap.setStr(metaFile, "version", "1.0.0")
128 | JMap.setStr(metaFile, "author", authorName)
129 | JMap.setStr(metaFile, "autorun", "false")
130 | McmRecorder_RecordingFiles.SaveRecordingInfoFile(recordingName, metaFile)
131 | endFunction
132 |
133 | function ContinueRecording(string recordingName) global
134 | SetCurrentRecordingName(recordingName)
135 | SetCurrentRecordingModName("")
136 | ResetCurrentRecordingSteps()
137 | endFunction
138 |
139 | function StopRecording() global
140 | SetCurrentRecordingName("")
141 | endFunction
142 |
143 | string function GetCurrentRecordingName() global
144 | return JDB.solveStr(McmRecorder_JDB.JdbPath_CurrentRecordingName())
145 | endFunction
146 |
147 | function SetCurrentRecordingName(string recodingName) global
148 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_CurrentRecordingName(), recodingName, createMissingKeys = true)
149 | endFunction
150 |
151 | string function GetCurrentRecordingModName() global
152 | return JDB.solveStr(McmRecorder_JDB.JdbPath_CurrentRecordingMOdName())
153 | endFunction
154 |
155 | function SetCurrentRecordingModName(string modName) global
156 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_CurrentRecordingModName(), modName , createMissingKeys = true)
157 | endFunction
158 |
159 | int function GetCurrentRecordingSteps() global
160 | return JDB.solveObj(McmRecorder_JDB.JdbPath_CurrentRecordingRecordingStep())
161 | endFunction
162 |
163 | function SetCurrentRecordingSteps(int stepInfo) global
164 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_CurrentRecordingRecordingStep(), stepInfo, createMissingKeys = true)
165 | endFunction
166 |
167 | function ResetCurrentRecordingSteps() global
168 | SetCurrentRecordingSteps(JArray.object())
169 | endFunction
170 |
--------------------------------------------------------------------------------
/Scripts/Source/SKI_ConfigManager.psc:
--------------------------------------------------------------------------------
1 | scriptName SKI_ConfigManager extends SKI_QuestBase hidden
2 |
3 | ;-- Properties --------------------------------------
4 | String property JOURNAL_MENU
5 | String function get()
6 |
7 | return "Journal Menu"
8 | endFunction
9 | endproperty
10 | String property MENU_ROOT
11 | String function get()
12 |
13 | return "_root.ConfigPanelFader.configPanel"
14 | endFunction
15 | endproperty
16 |
17 | ;-- Variables ---------------------------------------
18 | String[] _modNames
19 | Bool _locked = false
20 | Bool _lockInit = false
21 | Int _updateCounter = 0
22 | Bool _cleanupFlag = false
23 | Int _configCount = 0
24 | SKI_ConfigBase[] _modConfigs
25 | SKI_ConfigBase _activeConfig
26 | Int _curConfigID = 0
27 | Int _addCounter = 0
28 |
29 | string[] property ModNames
30 | string[] function get()
31 | return _modNames
32 | endFunction
33 | endProperty
34 |
35 | SKI_ConfigBase[] property ModConfigs
36 | SKI_ConfigBase[] function get()
37 | return _modConfigs
38 | endFunction
39 | endProperty
40 |
41 | ;-- Functions ---------------------------------------
42 |
43 | function OnGameReload()
44 | self.RegisterForModEvent("SKICP_modSelected", "OnModSelect")
45 | self.RegisterForModEvent("SKICP_pageSelected", "OnPageSelect")
46 | self.RegisterForModEvent("SKICP_optionHighlighted", "OnOptionHighlight")
47 | self.RegisterForModEvent("SKICP_optionSelected", "OnOptionSelect")
48 | self.RegisterForModEvent("SKICP_optionDefaulted", "OnOptionDefault")
49 | self.RegisterForModEvent("SKICP_keymapChanged", "OnKeymapChange")
50 | self.RegisterForModEvent("SKICP_sliderSelected", "OnSliderSelect")
51 | self.RegisterForModEvent("SKICP_sliderAccepted", "OnSliderAccept")
52 | self.RegisterForModEvent("SKICP_menuSelected", "OnMenuSelect")
53 | self.RegisterForModEvent("SKICP_menuAccepted", "OnMenuAccept")
54 | self.RegisterForModEvent("SKICP_colorSelected", "OnColorSelect")
55 | self.RegisterForModEvent("SKICP_colorAccepted", "OnColorAccept")
56 | self.RegisterForModEvent("SKICP_inputSelected", "OnInputSelect")
57 | self.RegisterForModEvent("SKICP_inputAccepted", "OnInputAccept")
58 | self.RegisterForModEvent("SKICP_dialogCanceled", "OnDialogCancel")
59 | self.RegisterForMenu(self.JOURNAL_MENU)
60 | _lockInit = true
61 | _cleanupFlag = true
62 | self.CleanUp()
63 | self.SendModEvent("SKICP_configManagerReady", "", 0.000000)
64 | _updateCounter = 0
65 | self.RegisterForSingleUpdate(5 as Float)
66 | endFunction
67 |
68 | function OnSliderSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
69 |
70 | Int optionIndex = a_numArg as Int
71 | _activeConfig.RequestSliderDialogData(optionIndex)
72 | endFunction
73 |
74 | function CleanUp()
75 |
76 | self.GotoState("BUSY")
77 | _cleanupFlag = false
78 | _configCount = 0
79 | Int i = 0
80 | while i < _modConfigs.length
81 | if _modConfigs[i] == none || _modConfigs[i].GetFormID() == 0
82 | _modConfigs[i] = none
83 | _modNames[i] = ""
84 | else
85 | _configCount += 1
86 | endIf
87 | i += 1
88 | endWhile
89 | self.GotoState("")
90 | endFunction
91 |
92 | function OnMenuClose(String a_menuName)
93 |
94 | self.GotoState("")
95 | if _activeConfig
96 | _activeConfig.CloseConfig()
97 | endIf
98 | _activeConfig = none
99 | endFunction
100 |
101 | function OnInit()
102 |
103 | _modConfigs = new SKI_ConfigBase[128]
104 | _modNames = new String[128]
105 | self.OnGameReload()
106 | endFunction
107 |
108 | function OnKeymapChange(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
109 |
110 | Int optionIndex = a_numArg as Int
111 | Int keyCode = ui.GetInt(self.JOURNAL_MENU, self.MENU_ROOT + ".selectedKeyCode")
112 | String conflictControl = input.GetMappedControl(keyCode)
113 | String conflictName = ""
114 | Int i = 0
115 | while conflictControl == "" && i < _modConfigs.length
116 | if _modConfigs[i] != none
117 | conflictControl = _modConfigs[i].GetCustomControl(keyCode)
118 | if conflictControl != ""
119 | conflictName = _modNames[i]
120 | endIf
121 | endIf
122 | i += 1
123 | endWhile
124 | _activeConfig.RemapKey(optionIndex, keyCode, conflictControl, conflictName)
125 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
126 | endFunction
127 |
128 | function OnMenuSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
129 |
130 | Int optionIndex = a_numArg as Int
131 | _activeConfig.RequestMenuDialogData(optionIndex)
132 | endFunction
133 |
134 | function OnUpdate()
135 |
136 | if _cleanupFlag
137 | self.CleanUp()
138 | endIf
139 | if _addCounter > 0
140 | debug.Notification("MCM: Registered " + _addCounter as String + " new menu(s).")
141 | _addCounter = 0
142 | endIf
143 | self.SendModEvent("SKICP_configManagerReady", "", 0.000000)
144 | if _updateCounter < 6
145 | _updateCounter += 1
146 | self.RegisterForSingleUpdate(5 as Float)
147 | else
148 | self.RegisterForSingleUpdate(30 as Float)
149 | endIf
150 | endFunction
151 |
152 | Int function GetVersion()
153 |
154 | return 4
155 | endFunction
156 |
157 | function OnOptionDefault(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
158 |
159 | Int optionIndex = a_numArg as Int
160 | _activeConfig.ResetOption(optionIndex)
161 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
162 | endFunction
163 |
164 | function OnOptionSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
165 | Int optionIndex = a_numArg as Int
166 | _activeConfig.SelectOption(optionIndex)
167 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
168 | endFunction
169 |
170 | function OnInputSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
171 |
172 | Int optionIndex = a_numArg as Int
173 | _activeConfig.RequestInputDialogData(optionIndex)
174 | endFunction
175 |
176 | function Log(String a_msg)
177 |
178 | debug.Trace(self as String + ": " + a_msg, 0)
179 | endFunction
180 |
181 | function OnDialogCancel(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
182 |
183 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
184 | endFunction
185 |
186 | function OnSliderAccept(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
187 |
188 | Float value = a_numArg
189 | _activeConfig.SetSliderValue(value)
190 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
191 | endFunction
192 |
193 | Int function NextID()
194 |
195 | Int startIdx = _curConfigID
196 | while _modConfigs[_curConfigID] != none
197 | _curConfigID += 1
198 | if _curConfigID >= 128
199 | _curConfigID = 0
200 | endIf
201 | if _curConfigID == startIdx
202 | return -1
203 | endIf
204 | endWhile
205 | return _curConfigID
206 | endFunction
207 |
208 | ; Skipped compiler generated GetState
209 |
210 | Int function UnregisterMod(SKI_ConfigBase a_menu)
211 |
212 | self.GotoState("BUSY")
213 | Int i = 0
214 | while i < _modConfigs.length
215 | if _modConfigs[i] == a_menu
216 | _modConfigs[i] = none
217 | _modNames[i] = ""
218 | _configCount -= 1
219 | self.GotoState("")
220 | return i
221 | endIf
222 | i += 1
223 | endWhile
224 | self.GotoState("")
225 | return -1
226 | endFunction
227 |
228 | function OnMenuAccept(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
229 |
230 | Int value = a_numArg as Int
231 | _activeConfig.SetMenuIndex(value)
232 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
233 | endFunction
234 |
235 | Int function RegisterMod(SKI_ConfigBase a_menu, String a_modName)
236 |
237 | self.GotoState("BUSY")
238 | if _configCount >= 128
239 | self.GotoState("")
240 | return -1
241 | endIf
242 | Int i = 0
243 | while i < _modConfigs.length
244 | if _modConfigs[i] == a_menu
245 | self.GotoState("")
246 | return i
247 | endIf
248 | i += 1
249 | endWhile
250 | Int configID = self.NextID()
251 | if configID == -1
252 | self.GotoState("")
253 | return -1
254 | endIf
255 | _modConfigs[configID] = a_menu
256 | _modNames[configID] = a_modName
257 | _configCount += 1
258 | _addCounter += 1
259 | self.GotoState("")
260 | return configID
261 | endFunction
262 |
263 | function OnMenuOpen(String a_menuName)
264 | self.GotoState("BUSY")
265 | _activeConfig = none
266 | ui.InvokeStringA(self.JOURNAL_MENU, self.MENU_ROOT + ".setModNames", _modNames)
267 | endFunction
268 |
269 | function OnModSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
270 |
271 | Int configIndex = a_numArg as Int
272 | if configIndex > -1
273 | if _activeConfig
274 | _activeConfig.CloseConfig()
275 | endIf
276 | _activeConfig = _modConfigs[configIndex]
277 | _activeConfig.OpenConfig()
278 | endIf
279 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
280 | endFunction
281 |
282 | function OnColorAccept(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
283 |
284 | Int color = a_numArg as Int
285 | _activeConfig.SetColorValue(color)
286 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
287 | endFunction
288 |
289 | function OnInputAccept(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
290 |
291 | _activeConfig.SetInputText(a_strArg)
292 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
293 | endFunction
294 |
295 | function OnOptionHighlight(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
296 |
297 | Int optionIndex = a_numArg as Int
298 | _activeConfig.HighlightOption(optionIndex)
299 | endFunction
300 |
301 | ; Skipped compiler generated GotoState
302 |
303 | function ForceReset()
304 |
305 | self.Log("Forcing config manager reset...")
306 | self.SendModEvent("SKICP_configManagerReset", "", 0.000000)
307 | self.GotoState("BUSY")
308 | Int i = 0
309 | while i < _modConfigs.length
310 | _modConfigs[i] = none
311 | _modNames[i] = ""
312 | i += 1
313 | endWhile
314 | _curConfigID = 0
315 | _configCount = 0
316 | self.GotoState("")
317 | self.SendModEvent("SKICP_configManagerReady", "", 0.000000)
318 | endFunction
319 |
320 | function OnColorSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
321 |
322 | Int optionIndex = a_numArg as Int
323 | _activeConfig.RequestColorDialogData(optionIndex)
324 | endFunction
325 |
326 | function OnPageSelect(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
327 |
328 | String page = a_strArg
329 | Int index = a_numArg as Int
330 | _activeConfig.SetPage(page, index)
331 | ui.InvokeBool(self.JOURNAL_MENU, self.MENU_ROOT + ".unlock", true)
332 | endFunction
333 |
334 | ;-- State -------------------------------------------
335 | state BUSY
336 |
337 | function CleanUp()
338 |
339 | ; Empty function
340 | endFunction
341 |
342 | Int function RegisterMod(SKI_ConfigBase a_menu, String a_modName)
343 |
344 | return -2
345 | endFunction
346 |
347 | function ForceReset()
348 |
349 | ; Empty function
350 | endFunction
351 |
352 | Int function UnregisterMod(SKI_ConfigBase a_menu)
353 |
354 | return -2
355 | endFunction
356 | endState
357 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorderMCM.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorderMCM extends SKI_ConfigBase
2 | {**PRIVATE** Please do not edit.}
3 |
4 | McmRecorder Recorder
5 |
6 | int oid_Record
7 | int oid_Stop
8 | int[] oids_Recordings
9 | int oid_KeyboardShortcuts_RecordingSelectionMenu
10 |
11 | string[] menuOptions
12 | string[] recordings
13 | bool isPlayingRecording
14 | string currentlyPlayingRecordingName
15 | bool openRunOrPreviewStepsPrompt
16 |
17 | bool property IsSkyrimVR
18 | bool function get()
19 | return Game.GetModByName("SkyrimVR.esm") != 255
20 | endFunction
21 | endProperty
22 |
23 | bool property IsVrikInstalled
24 | bool function get()
25 | return McmRecorder_VRIK.IsVrikInstalled()
26 | endFunction
27 | endProperty
28 |
29 | bool property HasJcontainersInstalled
30 | bool function get()
31 | return JContainers.APIVersion()
32 | endFunction
33 | endProperty
34 |
35 | bool property HasPapyrusUtilInstalled
36 | bool function get()
37 | return PapyrusUtil.GetVersion()
38 | endFunction
39 | endProperty
40 |
41 | event OnConfigInit()
42 | ModName = "MCM Recorder"
43 | Recorder = (self as Quest) as McmRecorder
44 | endEvent
45 |
46 | event OnConfigOpen()
47 | if IsSkyrimVR && IsVrikInstalled
48 | Pages = new string[3]
49 | Pages[0] = "MCM Recordings"
50 | Pages[1] = "Keyboard Shortcuts"
51 | Pages[2] = "VR Gestures"
52 | else
53 | Pages = new string[2]
54 | Pages[0] = "MCM Recordings"
55 | Pages[1] = "Keyboard Shortcuts"
56 | endIf
57 | endEvent
58 |
59 | event OnPageReset(string page)
60 | bool papyrusUtilOK = HasPapyrusUtilInstalled
61 | bool jcontainersOK = HasJcontainersInstalled
62 |
63 | if papyrusUtilOK && jcontainersOK
64 | if page == "Keyboard Shortcuts"
65 | Render_KeyboardShortcuts()
66 | elseIf page == "VR Gestures"
67 | Render_VRGestures()
68 | else
69 | Render_Recordings()
70 | endIf
71 | else
72 | if ! papyrusUtilOK
73 | AddTextOption("PapyrusUtil not found", "FAILED", OPTION_FLAG_DISABLED)
74 | AddTextOption("(or incompatible version installed)", "", OPTION_FLAG_DISABLED)
75 | endIf
76 | if ! jcontainersOK
77 | AddTextOption("JContainers not found", "FAILED", OPTION_FLAG_DISABLED)
78 | AddTextOption("(or incompatible version installed)", "", OPTION_FLAG_DISABLED)
79 | endIf
80 | endIf
81 | endEvent
82 |
83 | function Render_Recordings()
84 | if McmRecorder_Recorder.IsRecording()
85 | oid_Stop = AddTextOption("Currently Recording!", "STOP RECORDING", OPTION_FLAG_NONE)
86 | AddTextOption(McmRecorder_Recorder.GetCurrentRecordingName(), "", OPTION_FLAG_DISABLED)
87 | else
88 | if IsSkyrimVR
89 | oid_Record = AddTextOption("Click to begin recording:", "BEGIN RECORDING", OPTION_FLAG_NONE)
90 | else
91 | oid_Record = AddInputOption("Click to begin recording:", "BEGIN RECORDING", OPTION_FLAG_NONE)
92 | endIf
93 | AddEmptyOption()
94 | endIf
95 | ListRecordings()
96 | endFunction
97 |
98 | function Render_KeyboardShortcuts()
99 | if McmRecorder_Recorder.AnyRecordings()
100 | ; Recording Choice Dropdown
101 | AddTextOption("Choose a recording to set keyboard shortcut", "", OPTION_FLAG_DISABLED)
102 | AddEmptyOption()
103 | oid_KeyboardShortcuts_RecordingSelectionMenu = AddMenuOption("", "[Choose Recording]", OPTION_FLAG_NONE)
104 | AddEmptyOption()
105 |
106 | ; Existing keyboard shortcuts
107 | Render_KeyboardShortcutInfos(McmRecorder_KeyboardShortcuts.GetShortcutsInfos())
108 | else
109 | AddTextOption("No recordings available", "", OPTION_FLAG_DISABLED)
110 | endIf
111 | endFunction
112 |
113 | function Render_KeyboardShortcutInfos(int shortcutInfos)
114 | int shortcutOptions = JIntMap.object()
115 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_MCM_KeyboardShortcuts_ShortcutOptions(), shortcutOptions, createMissingKeys = true)
116 | int shortcutInfosCount = JArray.count(shortcutInfos)
117 | if shortcutInfosCount > 0
118 | AddEmptyOption()
119 | AddEmptyOption()
120 | int i = 0
121 | while i < shortcutInfosCount
122 |
123 | int shortcutInfo = JArray.getObj(shortcutInfos, i)
124 | string recordingName = JMap.getStr(shortcutInfo, "recordingName")
125 | int shortcut = JMap.getObj(shortcutInfo, "shortcut")
126 | int keycode = JMap.getInt(shortcut, "key")
127 |
128 | int keymap = JMap.object()
129 | JMap.setStr(keymap, "action", "keymap")
130 | JMap.setObj(keymap, "shortcutInfo", shortcutInfo)
131 |
132 | int ctrl = JMap.object()
133 | JMap.setStr(ctrl, "action", "ctrl")
134 | JMap.setObj(ctrl, "shortcutInfo", shortcutInfo)
135 |
136 | int alt = JMap.object()
137 | JMap.setStr(alt, "action", "alt")
138 | JMap.setObj(alt, "shortcutInfo", shortcutInfo)
139 |
140 | int shift = JMap.object()
141 | JMap.setStr(shift, "action", "shift")
142 | JMap.setObj(shift, "shortcutInfo", shortcutInfo)
143 |
144 | int delete = JMap.object()
145 | JMap.setStr(delete, "action", "delete")
146 | JMap.setObj(delete, "shortcutInfo", shortcutInfo)
147 |
148 | JIntMap.setObj(shortcutOptions, AddKeyMapOption(recordingName, keycode, OPTION_FLAG_NONE), keymap)
149 | JIntMap.setObj(shortcutOptions, AddTextOption("Click to delete Recording", "DELETE", OPTION_FLAG_NONE), delete)
150 | JIntMap.setObj(shortcutOptions, AddToggleOption("Ctrl", JMap.getStr(shortcut, "ctrl") == "true", OPTION_FLAG_NONE), ctrl)
151 | AddEmptyOption()
152 | JIntMap.setObj(shortcutOptions, AddToggleOption("Alt", JMap.getStr(shortcut, "alt") == "true", OPTION_FLAG_NONE), alt)
153 | AddEmptyOption()
154 | JIntMap.setObj(shortcutOptions, AddToggleOption("Shift", JMap.getStr(shortcut, "shift") == "true", OPTION_FLAG_NONE), shift)
155 | AddEmptyOption()
156 | AddEmptyOption()
157 | AddEmptyOption()
158 | i += 1
159 | endWhile
160 | endIf
161 | endFunction
162 |
163 | int function GetShortcutInfoAndActionForOptionsID(int optionId)
164 | int shortcutOptions = JDB.solveObj(McmRecorder_JDB.JdbPath_MCM_KeyboardShortcuts_ShortcutOptions())
165 | if shortcutOptions
166 | return JIntMap.getObj(shortcutOptions, optionId)
167 | endIf
168 | endFunction
169 |
170 | function Render_VRGestures()
171 | recordings = McmRecorder_RecordingFiles.GetRecordingNames()
172 | if recordings.Length && ((! McmRecorder_Recorder.IsRecording()) || recordings.Length > 1)
173 | SetCursorFillMode(TOP_TO_BOTTOM)
174 | AddTextOption("Choose MCM Recordings", "", OPTION_FLAG_DISABLED)
175 | AddTextOption("These will become available as VRIK Gestures", "", OPTION_FLAG_DISABLED)
176 | AddTextOption("which can be configured via the VRIK MCM", "", OPTION_FLAG_DISABLED)
177 | AddEmptyOption()
178 | SetCursorFillMode(LEFT_TO_RIGHT)
179 | oids_Recordings = Utility.CreateIntArray(recordings.Length)
180 | int i = 0
181 | while i < recordings.Length
182 | string recordingName = recordings[i]
183 | if recordingName != McmRecorder_Recorder.GetCurrentRecordingName()
184 | string[] stepNames = McmRecorder_RecordingFiles.GetRecordingStepFilenames(recordingName)
185 | int recordingInfo = McmRecorder_RecordingFiles.GetRecordingInfo(recordingName)
186 | bool isGesture = McmRecorder_RecordingInfo.IsVrGesture(recordingInfo)
187 | oids_Recordings[i] = AddToggleOption(recordingName, isGesture, OPTION_FLAG_NONE)
188 | string authorText = ""
189 | if JMap.getStr(recordingInfo, "author")
190 | authorText = "by " + JMap.getStr(recordingInfo, "author")
191 | endIf
192 | AddTextOption(authorText, JMap.getStr(recordingInfo, "version"), OPTION_FLAG_DISABLED)
193 | endIf
194 | i += 1
195 | endWhile
196 | else
197 | AddTextOption("There are no recordings", "", OPTION_FLAG_DISABLED)
198 | endIf
199 | endFunction
200 |
201 | function ListRecordings()
202 | recordings = McmRecorder_RecordingFiles.GetRecordingNames()
203 | if recordings.Length && ((! McmRecorder_Recorder.IsRecording()) || recordings.Length > 1)
204 | AddEmptyOption()
205 | AddEmptyOption()
206 | AddTextOption("Choose a recording to play:", "", OPTION_FLAG_DISABLED)
207 | AddEmptyOption()
208 | oids_Recordings = Utility.CreateIntArray(recordings.Length)
209 | int i = 0
210 | while i < recordings.Length
211 | string recordingName = recordings[i]
212 | if recordingName != McmRecorder_Recorder.GetCurrentRecordingName()
213 | string[] stepNames = McmRecorder_RecordingFiles.GetRecordingStepFilenames(recordingName)
214 | oids_Recordings[i] = AddTextOption("", recordingName, OPTION_FLAG_NONE)
215 | int recordingInfo = McmRecorder_RecordingFiles.GetRecordingInfo(recordingName)
216 | string authorText = ""
217 | if JMap.getStr(recordingInfo, "author")
218 | authorText = "by " + JMap.getStr(recordingInfo, "author")
219 | endIf
220 | AddTextOption(authorText, JMap.getStr(recordingInfo, "version"), OPTION_FLAG_DISABLED)
221 | endIf
222 | i += 1
223 | endWhile
224 | endIf
225 | endFunction
226 |
227 | event OnOptionSelect(int optionId)
228 | if IsSkyrimVR && optionId == oid_Record ; SkyrimVR
229 | if ! McmRecorder_Recorder.IsRecording()
230 | McmRecorder_Recorder.BeginRecording(GetRandomRecordingName())
231 | ForcePageReset()
232 | else
233 | McmRecorder_Recorder.StopRecording() ; For SkyrimVR these OIDs are the same
234 | ForcePageReset()
235 | endIf
236 | elseIf optionId == oid_Stop
237 | McmRecorder_Recorder.StopRecording()
238 | ForcePageReset()
239 | elseIf oids_Recordings.Find(optionId) > -1
240 | int recordingIndex = oids_Recordings.Find(optionId)
241 | string recordingName = recordings[recordingIndex]
242 | if CurrentPage == "VR Gestures"
243 | int recording = McmRecorder_RecordingInfo.Get(recordingName)
244 | bool isGesture = McmRecorder_RecordingInfo.IsVrGesture(recording)
245 | if isGesture
246 | McmRecorder_RecordingInfo.SetIsVrGesture(recording, false)
247 | SetToggleOptionValue(optionId, false, false)
248 | McmRecorder_VRIK.UnregisterVrikGestureForRecording(recordingName)
249 | else
250 | McmRecorder_RecordingInfo.SetIsVrGesture(recording, true)
251 | SetToggleOptionValue(optionId, true, false)
252 | McmRecorder_VRIK.RegisterVrikGestureForRecording(recordingName)
253 | endIf
254 | else
255 | PromptToRunRecordingOrPreviewSteps(recordingName)
256 | endIf
257 | else
258 | int shortcutInfoAndAction = GetShortcutInfoAndActionForOptionsID(optionId)
259 | if shortcutInfoAndAction
260 | string clickAction = JMap.getStr(shortcutInfoAndAction, "action")
261 | int shortcutInfo = JMap.getObj(shortcutInfoAndAction, "shortcutInfo")
262 | string recordingName = JMap.getStr(shortcutInfo, "recordingName")
263 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
264 | int shortcut = JMap.getObj(recordingInfo, "shortcut")
265 | if clickAction == "ctrl"
266 | if JMap.getStr(shortcut, "ctrl") == "true"
267 | JMap.removeKey(shortcut, "ctrl")
268 | SetToggleOptionValue(optionId, false, false)
269 | else
270 | JMap.setStr(shortcut, "ctrl", "true")
271 | SetToggleOptionValue(optionId, true, false)
272 | endIf
273 | McmRecorder_RecordingInfo.Save(recordingName, recordingInfo)
274 | elseIf clickAction == "alt"
275 | if JMap.getStr(shortcut, "alt") == "true"
276 | JMap.removeKey(shortcut, "alt")
277 | SetToggleOptionValue(optionId, false, false)
278 | else
279 | JMap.setStr(shortcut, "alt", "true")
280 | SetToggleOptionValue(optionId, true, false)
281 | endIf
282 | McmRecorder_RecordingInfo.Save(recordingName, recordingInfo)
283 | elseIf clickAction == "shift"
284 | if JMap.getStr(shortcut, "shift") == "true"
285 | JMap.removeKey(shortcut, "shift")
286 | SetToggleOptionValue(optionId, false, false)
287 | else
288 | JMap.setStr(shortcut, "shift", "true")
289 | SetToggleOptionValue(optionId, true, false)
290 | endIf
291 | McmRecorder_RecordingInfo.Save(recordingName, recordingInfo)
292 | elseIf clickAction == "delete"
293 | if ShowMessage("Are you sure you would like to delete this shortcut?", true, "Yes", "Cancel")
294 | JMap.removeKey(recordingInfo, "shortcut")
295 | ForcePageReset()
296 | McmRecorder_RecordingInfo.Save(recordingName, recordingInfo)
297 | endIf
298 | endIf
299 | endIf
300 | endIf
301 | endEvent
302 |
303 | event OnOptionKeyMapChange(int optionId, int keyCode, string conflictControl, string conflictName)
304 | int shortcutInfoAndAction = GetShortcutInfoAndActionForOptionsID(optionId)
305 | if shortcutInfoAndAction
306 | int shortcutInfo = JMap.getObj(shortcutInfoAndAction, "shortcutInfo")
307 | string recordingName = JMap.getStr(shortcutInfo, "recordingName")
308 | int recordingInfo = McmRecorder_RecordingInfo.Get(recordingName)
309 | int shortcut = JMap.getObj(recordingInfo, "shortcut")
310 | JMap.setInt(shortcut, "key", keyCode)
311 | SetKeyMapOptionValue(optionId, keyCode, false)
312 | Recorder.StopListeningForKeyboardShortcuts()
313 | McmRecorder_RecordingInfo.Save(recordingName, recordingInfo)
314 | Recorder.StartListenForKeyboardShortcuts()
315 | endIf
316 | endEvent
317 |
318 | event OnOptionInputAccept(int optionId, string text)
319 | McmRecorder_Recorder.BeginRecording(text)
320 | ForcePageReset()
321 | Debug.MessageBox("Recording Started!\n\nYou can now interact with MCM menus and all interactions will be recorded.\n\nWhen you are finished, return to this page to stop the recording (or quit the game).\n\nRecordings are saved in simple text files inside of Data\\McmRecorder\\ which you can edit to tweak your recording without completely re-recording it :)")
322 | endEvent
323 |
324 | event OnOptionInputOpen(int optionId)
325 | if optionId == oid_Record
326 | SetInputDialogStartText(GetRandomRecordingName())
327 | endIf
328 | endEvent
329 |
330 | event OnOptionMenuOpen(int optionId)
331 | if optionId == oid_KeyboardShortcuts_RecordingSelectionMenu
332 | menuOptions = new string[1]
333 | string[] recordingNames = McmRecorder_RecordingFiles.GetRecordingNames()
334 | int recordingsWithoutShortcutsCount = 0
335 | int i = 0
336 | while i < recordingNames.Length
337 | string recordingName = recordingNames[i]
338 | if ! JMap.getObj(McmRecorder_RecordingInfo.Get(recordingName), "shortcut")
339 | recordingsWithoutShortcutsCount += 1
340 | menuOptions = Utility.ResizeStringArray(menuOptions, recordingsWithoutShortcutsCount)
341 | menuOptions[menuOptions.Length - 1] = recordingName
342 | endIf
343 | i += 1
344 | endWhile
345 | SetMenuDialogOptions(menuOptions)
346 | endIf
347 | endEvent
348 |
349 | event OnOptionMenuAccept(int optionId, int index)
350 | if index == -1
351 | return
352 | endIf
353 |
354 | if optionId == oid_KeyboardShortcuts_RecordingSelectionMenu
355 | string recordingName = menuOptions[index]
356 | McmRecorder_KeyboardShortcuts.AddRecording(recordingName)
357 | ForcePageReset()
358 | endIf
359 | endEvent
360 |
361 | string function GetRandomRecordingName()
362 | string[] currentTimeParts = StringUtil.Split(Utility.GetCurrentRealTime(), ".")
363 | return "Recording_" + currentTimeParts[0] + "_" + currentTimeParts[1]
364 | endFunction
365 |
366 | ; TODO move to the McmRecorder maybe a global script for prompts
367 | function PromptToRunRecordingOrPreviewSteps(string recordingName)
368 | string recordingDescription = McmRecorder_RecordingFiles.GetRecordingDescription(recordingName)
369 |
370 | bool confirmation = true
371 |
372 | ; The ShowMessage prompt can not be interacted with via SkyrimVR so we simply show a prompt - not a confirmation dialog
373 | if ! IsSkyrimVR
374 | confirmation = ShowMessage(recordingDescription + "\n\nClose the MCM to continue\n\nYou will be prompted to play this recording\n\nYou will also be able to preview all recording steps or play individual one\n\nYou will also be given the opportunity to continue the recording\n\nWould you like to continue?", "No", "Yes", "Cancel")
375 | if confirmation
376 | Debug.MessageBox("Close the MCM to continue")
377 | endIf
378 | endIf
379 |
380 | if confirmation
381 | string[] stepNames = McmRecorder_RecordingFiles.GetRecordingStepFilenames(recordingName)
382 | string text = recordingDescription + "\n"
383 | int i = 0
384 | while i < stepNames.Length && i < 11
385 | if i == 10
386 | text += "\n- ..."
387 | else
388 | text += "\n- " + StringUtil.Substring(stepNames[i], 0, StringUtil.Find(stepNames[i], ".json"))
389 | endIf
390 | i += 1
391 | endWhile
392 | text += "\n\nWould you like to play this recording?"
393 |
394 | ; Inlined to extract method later
395 | Recorder.McmRecorder_MessageText.SetName(text)
396 | int responseId = Recorder.McmRecorder_Message_RunRecordingOrViewSteps.Show()
397 | string response
398 | if responseId == 0
399 | response = "Play Recording"
400 | elseIf responseId == 1
401 | response = "View Steps"
402 | elseIf responseId == 2
403 | response = "Add to Recording"
404 | elseIf responseId == 3
405 | response = "Cancel"
406 | endIf
407 |
408 | if response == "Play Recording"
409 | currentlyPlayingRecordingName = recordingName
410 | isPlayingRecording = true
411 | McmRecorder_Player.PlayRecording(recordingName)
412 | currentlyPlayingRecordingName = ""
413 | isPlayingRecording = false
414 | elseIf response == "View Steps"
415 | ShowStepSelectionUI(recordingName, stepNames)
416 | elseIf response == "Add to Recording"
417 | McmRecorder_Recorder.ContinueRecording(recordingName)
418 | Debug.MessageBox("Recording has been restarted!\n\nYou can now interact with MCM menus and all interactions will be recorded.\n\nWhen you are finished, return to the MCM Recorder mod configuration menu to stop the recording (or quit the game).\n\nRecordings are saved in simple text files inside of Data\\McmRecorder\\ which you can edit to tweak your recording without completely re-recording it :)")
419 | endIf
420 | endIf
421 | endFunction
422 |
423 | function ShowStepSelectionUI(string recordingName, string[] stepNames)
424 | UIListMenu menu = UIExtensions.GetMenu("UIListMenu") as UIListMenu
425 | menu.AddEntryItem("[" + recordingName + "]")
426 | menu.AddEntryItem(" ")
427 |
428 | int i = 0
429 | while i < stepNames.Length
430 | string stepName = stepNames[i]
431 | menu.AddEntryItem(stepName)
432 | i += 1
433 | endWhile
434 |
435 | menu.OpenMenu()
436 |
437 | int selection = menu.GetResultInt()
438 |
439 | if selection < 2 ; Go Back
440 | ; TODO open the previous prompt! This isn't working...
441 | ; PromptToRunRecordingOrPreviewSteps(recordingName)
442 | else
443 | int stepIndex = selection - 2 ; Subtract the top 3 entry items
444 | string stepName = stepNames[stepIndex]
445 | McmRecorder_Player.PlayStep(recordingName, stepName)
446 | Debug.MessageBox("MCM recording " + recordingName + " step " + StringUtil.Substring(stepName, 0, StringUtil.Find(stepName, ".json")) + " has finished playing.")
447 | endIf
448 | endFunction
449 |
--------------------------------------------------------------------------------
/Scripts/Source/McmRecorder_Player.psc:
--------------------------------------------------------------------------------
1 | scriptName McmRecorder_Player hidden
2 | {Responsible for playback of recordings or can trigger individual actions}
3 |
4 | bool function IsPlayingRecording() global
5 | return JDB.solveInt(McmRecorder_JDB.JdbPath_IsPlayingRecording())
6 | endFunction
7 |
8 | function PlayRecording(string recordingName, float waitTimeBetweenActions = 0.0, float mcmLoadWaitTime = 0.0, bool verbose = true) global
9 | ClearModsPlayed()
10 | SetCurrentPlayingRecordingModName("")
11 | SetCurrentPlayingRecordingModPageName("")
12 |
13 | SetIsPlayingRecording(true)
14 | SetCurrentlyPlayingRecordingName(recordingName)
15 |
16 | McmRecorder recorder = McmRecorder.GetMcmRecorderInstance()
17 | recorder.ListenForSystemMenuOpen()
18 |
19 | int steps = McmRecorder_RecordingFiles.GetAllStepsForRecording(recordingName)
20 | SetCurrentlyPlayingSteps(steps)
21 |
22 | string[] stepFiles = JMap.allKeysPArray(steps)
23 |
24 | if verbose
25 | McmRecorder_UI.WelcomeMessage(recordingName)
26 | McmRecorder_UI.Notification("Play " + recordingName + " (" + stepFiles.Length + " steps)")
27 | endIf
28 |
29 | int fileIndex = 0
30 | while fileIndex < stepFiles.Length
31 | ; File for a given step
32 | string filename = stepFiles[fileIndex]
33 | int recordingActions = JMap.getObj(steps, filename)
34 | JValue.retain(recordingActions)
35 | int actionCount = JArray.count(recordingActions)
36 |
37 | ; Set the current step being run...
38 | SetCurrentlyPlayingStepFilename(filename)
39 | SetCurrentlyPlayingStepIndex(fileIndex)
40 |
41 | ; Show notification for the current step being run
42 | if verbose
43 | McmRecorder_UI.Notification(filename + " (" + (fileIndex + 1) + "/" + stepFiles.Length + ")")
44 | endIf
45 |
46 | int i = 0
47 | while i < actionCount
48 | int recordingAction = JArray.getObj(recordingActions, i)
49 | PlayAction(recordingAction, StringUtil.Substring(filename, 0, StringUtil.Find(filename, ".json")), mcmLoadWaitTime = mcmLoadWaitTime)
50 | if waitTimeBetweenActions
51 | Utility.WaitMenuMode(waitTimeBetweenActions)
52 | endIf
53 | i += 1
54 | endWhile
55 |
56 | JValue.release(recordingActions)
57 | fileIndex += 1
58 | endWhile
59 |
60 | recorder.StopListeningForSystemMenuOpen()
61 |
62 | if verbose
63 | McmRecorder_UI.FinishedMessage(recordingName)
64 | endIf
65 |
66 | SetIsPlayingRecording(false)
67 | endFunction
68 |
69 | function PlayStep(string recordingName, string stepName, float waitTimeBetweenActions = 0.0) global
70 | SetCurrentPlayingRecordingModName("")
71 | SetCurrentPlayingRecordingModPageName("")
72 | SetIsPlayingRecording(true) ; XXX is this used?
73 |
74 | int stepInfo = McmRecorder_RecordingFiles.GetRecordingStep(recordingName, stepName)
75 |
76 | JValue.retain(stepInfo)
77 |
78 | McmRecorder_UI.Notification("Playing step " + stepName + " of recording " + recordingName)
79 |
80 | int actionCount = JArray.count(stepInfo)
81 | int i = 0
82 | while i < actionCount
83 | int recordingAction = JArray.getObj(stepInfo, i)
84 | PlayAction(recordingAction, stepName)
85 | if waitTimeBetweenActions
86 | Utility.WaitMenuMode(waitTimeBetweenActions)
87 | endIf
88 | i += 1
89 | endWhile
90 |
91 | JValue.release(stepInfo)
92 |
93 | SetIsPlayingRecording(false)
94 | endFunction
95 |
96 | function PlayAction(int actionInfo, string stepName, bool promptOnFailures = true, float mcmLoadWaitTime = 10.0) global
97 | string modName = JMap.getStr(actionInfo, "mod")
98 | string pageName = JMap.getStr(actionInfo, "page")
99 |
100 | string skippingModName = GetCurrentlySkippingModName()
101 | if skippingModName
102 | if modName == skippingModName
103 | return ; Skip!
104 | else
105 | SetCurrentlySkippingModName("")
106 | endIf
107 | endIf
108 |
109 | SKI_ConfigBase mcm = McmRecorder.GetMcmInstance(modName)
110 |
111 | if (! mcm) && mcmLoadWaitTime
112 | McmRecorder_Logging.ConsoleOut("[Play Action] MCM not loaded: " + modName + " (waiting...)")
113 | float startTime = Utility.GetCurrentRealTime()
114 | float lastNotification = startTime
115 | while (! mcm) && (Utility.GetCurrentRealTime() - startTime) < mcmLoadWaitTime
116 | float now = Utility.GetCurrentRealTime()
117 | if (now - lastNotification) >= 5.0 ; Make configurable, 5 secs waiting for MCM to load
118 | lastNotification = now
119 | McmRecorder_UI.Notification("Waiting for " + modName + " MCM to load")
120 | McmRecorder_Logging.ConsoleOut("[Play Action] MCM not loaded: " + modName + " (waiting...)")
121 | endIf
122 | Utility.WaitMenuMode(1.0) ; hard coded for now
123 | mcm = McmRecorder.GetMcmInstance(modName)
124 | endWhile
125 | if ! mcm
126 | if promptOnFailures
127 | string result = McmRecorder_UI.GetUserResponseForNotFoundMod(modName)
128 | if result == "Try again"
129 | PlayAction(actionInfo, stepName, promptOnFailures, mcmLoadWaitTime)
130 | elseIf result == "Skip this mod"
131 | SetCurrentlySkippingModName(modName)
132 | return
133 | endIf
134 | else
135 | SetCurrentlySkippingModName(modName)
136 | return
137 | endIf
138 | return
139 | endIf
140 | endIf
141 |
142 | if ! mcm
143 | Debug.Trace("MCM recorder could not load MCM menu for " + modName)
144 | return
145 | endIf
146 |
147 | if modName != GetCurrentPlayingRecordingModName() || pageName != GetCurrentPlayingRecordingModPageName()
148 | RefreshMcmPage(mcm, modName, pageName)
149 | endIf
150 |
151 | SetCurrentPlayingRecordingModName(modName)
152 | SetCurrentPlayingRecordingModPageName(pageName)
153 |
154 | string optionType
155 | string selector = JMap.getStr(actionInfo, "option")
156 |
157 | if JMap.hasKey(actionInfo, "click")
158 | optionType = "text"
159 | selector = JMap.getStr(actionInfo, "click")
160 | elseIf JMap.hasKey(actionInfo, "toggle")
161 | optionType = "toggle"
162 | elseIf JMap.hasKey(actionInfo, "choose")
163 | optionType = "menu"
164 | elseIf JMap.hasKey(actionInfo, "text")
165 | optionType = "input"
166 | elseIf JMap.hasKey(actionInfo, "shortcut")
167 | optionType = "keymap"
168 | elseIf JMap.hasKey(actionInfo, "color")
169 | optionType = "color"
170 | elseIf JMap.hasKey(actionInfo, "slider")
171 | optionType = "slider"
172 | else
173 | McmRecorder_UI.MessageBox("MCM recording step " + stepName + " has action of unknown or unsupported type: '" + optionType + "'\n" + McmRecorder_Logging.ToJson(actionInfo))
174 | return
175 | endIf
176 |
177 | string wildcard = McmRecorder_McmFields.GetWildcardMatcher(selector)
178 | string side = JMap.getStr(actionInfo, "side", "left")
179 | string stateName = JMap.getStr(actionInfo, "state")
180 | int index = JMap.getInt(actionInfo, "index", -1)
181 |
182 | string debugPrefix = "[Play Action] " + modName
183 | if pageName
184 | debugPrefix += ": " + pageName
185 | endIf
186 | debugPrefix += " (" + selector + ")"
187 | if index > -1
188 | debugPrefix += " [" + index + "]"
189 | endIf
190 |
191 | float searchTimeout = JMap.getFlt(actionInfo, "timeout", 30.0) ; Default to wait for options to show up for a max of 30 seconds
192 | float searchInterval = JMap.getFlt(actionInfo, "interval", 0.5) ; Default to try twice per second
193 | float searchPageLoadTime = JMap.getFlt(actionInfo, "pageload", 5.0) ; Allow pages up to 5 seconds for an option to appear
194 |
195 | int option = FindOption(mcm, modName, pageName, optionType, selector, wildcard, index, side, searchTimeout, searchInterval, searchPageLoadTime)
196 |
197 | if option
198 | if ! stateName
199 | stateName = JMap.getStr(option, "state")
200 | endIf
201 | int optionId = JMap.getInt(option, "id")
202 | if stateName
203 | string previousState = mcm.GetState()
204 | mcm.GotoState(stateName)
205 | if optionType == "menu"
206 | string menuItem = JMap.getStr(actionInfo, "choose")
207 | McmRecorder_Logging.ConsoleOut(debugPrefix + " choose '" + menuItem + "'")
208 | mcm.OnMenuOpenST()
209 | string[] menuOptions = mcm.MostRecentlyConfiguredMenuDialogOptions
210 | int itemIndex = menuOptions.Find(menuItem)
211 | if itemIndex == -1
212 | McmRecorder_UI.MessageBox("Could not find " + menuItem + " menu item. Available options: " + menuOptions)
213 | else
214 | mcm.OnMenuAcceptST(itemIndex)
215 | endIf
216 | elseIf optionType == "keymap"
217 | int shortcut = JMap.getFlt(actionInfo, "shortcut") as int
218 | McmRecorder_Logging.ConsoleOut(debugPrefix + " shortcut " + shortcut)
219 | mcm.OnKeyMapChangeST(shortcut, "", "")
220 | elseIf optionType == "color"
221 | int colorCode = JMap.getInt(actionInfo, "color")
222 | McmRecorder_Logging.ConsoleOut(debugPrefix + " color " + colorCode)
223 | mcm.OnColorAcceptST(colorCode)
224 | elseIf optionType == "input"
225 | string inputValue = JMap.getStr(actionInfo, "text")
226 | McmRecorder_Logging.ConsoleOut(debugPrefix + " input '" + inputValue + "'")
227 | mcm.OnInputAcceptST(inputValue)
228 | elseIf optionType == "slider"
229 | float sliderValue = JMap.getFlt(actionInfo, "slider")
230 | McmRecorder_Logging.ConsoleOut(debugPrefix + " slider " + sliderValue)
231 | mcm.OnSliderAcceptST(sliderValue)
232 | elseIf optionType == "toggle"
233 | string turnOnOrOff = JMap.getStr(actionInfo, "toggle")
234 | bool currentlyEnabledOnPage = JMap.getFlt(option, "fltValue") == 1
235 | if currentlyEnabledOnPage && turnOnOrOff == "off"
236 | McmRecorder_Logging.ConsoleOut(debugPrefix + " toggle off")
237 | mcm.OnSelectST() ; Turn off
238 | elseIf (!currentlyEnabledOnPage) && turnOnOrOff == "on"
239 | McmRecorder_Logging.ConsoleOut(debugPrefix + " toggle on")
240 | mcm.OnSelectST() ; Turn on
241 | endIf
242 | elseIf optionType == "text"
243 | McmRecorder_Logging.ConsoleOut(debugPrefix + " click")
244 | mcm.OnSelectST()
245 | endIf
246 | mcm.GotoState(previousState)
247 | else
248 | if optionType == "menu"
249 | string menuItem = JMap.getStr(actionInfo, "choose")
250 | McmRecorder_Logging.ConsoleOut(debugPrefix + " choose '" + menuItem + "'")
251 | mcm.OnOptionMenuOpen(optionId)
252 | string[] menuOptions = mcm.MostRecentlyConfiguredMenuDialogOptions
253 | int itemIndex = menuOptions.Find(menuItem)
254 | if itemIndex == -1
255 | McmRecorder_UI.MessageBox("Could not find " + menuItem + " menu item. Available options: " + menuOptions)
256 | else
257 | mcm.OnOptionMenuAccept(optionId, itemIndex)
258 | endIf
259 | elseIf optionType == "slider"
260 | float sliderValue = JMap.getFlt(actionInfo, "slider")
261 | McmRecorder_Logging.ConsoleOut(debugPrefix + " slider " + sliderValue)
262 | mcm.OnOptionSliderAccept(optionId, sliderValue)
263 | elseIf optionType == "keymap"
264 | int shortcut = JMap.getInt(actionInfo, "shortcut")
265 | McmRecorder_Logging.ConsoleOut(debugPrefix + " shortcut " + shortcut)
266 | mcm.OnOptionKeyMapChange(optionId, shortcut, "", "")
267 | elseIf optionType == "color"
268 | int colorCode = JMap.getInt(actionInfo, "color")
269 | McmRecorder_Logging.ConsoleOut(debugPrefix + " color " + colorCode)
270 | mcm.OnOptionColorAccept(optionId, colorCode)
271 | elseIf optionType == "input"
272 | string inputValue = JMap.getStr(actionInfo, "text")
273 | McmRecorder_Logging.ConsoleOut(debugPrefix + " input '" + inputValue + "'")
274 | mcm.OnOptionInputAccept(optionId, inputValue)
275 | elseIf optionType == "toggle"
276 | string turnOnOrOff = JMap.getStr(actionInfo, "toggle")
277 | bool currentlyEnabledOnPage = JMap.getFlt(option, "fltValue") == 1
278 | if currentlyEnabledOnPage && turnOnOrOff == "off"
279 | McmRecorder_Logging.ConsoleOut(debugPrefix + " toggle off")
280 | mcm.OnOptionSelect(optionId) ; Turn off
281 | elseIf (!currentlyEnabledOnPage) && turnOnOrOff == "on"
282 | McmRecorder_Logging.ConsoleOut(debugPrefix + " toggle on")
283 | mcm.OnOptionSelect(optionId) ; Turn on
284 | endIf
285 | elseIf optionType == "text"
286 | McmRecorder_Logging.ConsoleOut(debugPrefix + " click")
287 | mcm.OnOptionSelect(optionId)
288 | endIf
289 | endIf
290 | elseIf promptOnFailures
291 | string response = McmRecorder_UI.GetUserResponseForNotFoundSelector(modName, pageName, selector)
292 | if response == "Try again"
293 | PlayAction(actionInfo, stepName, promptOnFailures)
294 | elseIf response == "Skip this mod"
295 | SetCurrentlySkippingModName(modName)
296 | endIf
297 | endIf
298 | endFunction
299 |
300 | function RefreshMcmPage(SKI_ConfigBase mcm, string modName, string pageName) global
301 | McmRecorder_McmFields.MarkMcmOptionsForReset()
302 | if HasModBeenPlayed(modName)
303 | mcm.CloseConfig()
304 | else
305 | AddModPlayed(modName)
306 | endIf
307 | mcm.OpenConfig()
308 | mcm.SetPage(pageName, mcm.Pages.Find(pageName))
309 | endFunction
310 |
311 | function SetIsPlayingRecording(bool running = true) global
312 | JDB.solveIntSetter(McmRecorder_JDB.JdbPath_IsPlayingRecording(), running as int, createMissingKeys = true)
313 | endFunction
314 |
315 | function SetCurrentlyPlayingRecordingName(string recordingName) global
316 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_PlayingRecordingName(), recordingName, createMissingKeys = true)
317 | endFunction
318 |
319 | string function GetCurrentlyPlayingRecordingName() global
320 | return JDB.solveStr(McmRecorder_JDB.JdbPath_PlayingRecordingName())
321 | endFunction
322 |
323 | function SetCurrentlyPlayingSteps(int steps) global
324 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_PlayingRecordingSteps(), steps, createMissingKeys = true)
325 | endFunction
326 |
327 | int function GetCurrentlyPlayingSteps() global
328 | return JDB.solveObj(McmRecorder_JDB.JdbPath_PlayingRecordingSteps())
329 | endFunction
330 |
331 | function SetCurrentlyPlayingStepFilename(string stepFilename) global
332 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_PlayingStepFilename(), stepFilename, createMissingKeys = true)
333 | endFunction
334 |
335 | string function GetCurrentlyPlayingStepFilename() global
336 | return JDB.solveStr(McmRecorder_JDB.JdbPath_PlayingStepFilename())
337 | endFunction
338 |
339 | function SetCurrentlyPlayingStepIndex(int stepIndex) global
340 | JDB.solveIntSetter(McmRecorder_JDB.JdbPath_PlayingStepIndex(), stepIndex, createMissingKeys = true)
341 | endFunction
342 |
343 | int function GetCurrentlyPlayingStepIndex() global
344 | return JDB.solveInt(McmRecorder_JDB.JdbPath_PlayingStepIndex())
345 | endFunction
346 |
347 | string function GetCurrentPlayingRecordingModName() global
348 | return JDB.solveStr(McmRecorder_JDB.JdbPath_PlayingRecordingModName())
349 | endFunction
350 |
351 | function SetCurrentPlayingRecordingModName(string modName) global
352 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_PlayingRecordingModName(), modName , createMissingKeys = true)
353 | endFunction
354 |
355 | string function GetCurrentPlayingRecordingModPageName() global
356 | return JDB.solveStr(McmRecorder_JDB.JdbPath_PlayingRecordingModPageName())
357 | endFunction
358 |
359 | function SetCurrentPlayingRecordingModPageName(string pageName) global
360 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_PlayingRecordingModPageName(), pageName , createMissingKeys = true)
361 | endFunction
362 |
363 | int function GetModsPlayed() global
364 | int modsPlayed = JDB.solveObj(McmRecorder_JDB.JdbPath_PlayingRecordingModsPlayed())
365 | if ! modsPlayed
366 | modsPlayed = JMap.object()
367 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_PlayingRecordingModsPlayed(), modsPlayed, createMissingKeys = true)
368 | endIf
369 | return modsPlayed
370 | endFunction
371 |
372 | function AddModPlayed(string modName) global
373 | JMap.setInt(GetModsPlayed(), modName, 1)
374 | endFunction
375 |
376 | bool function HasModBeenPlayed(string modName) global
377 | return JMap.getInt(GetModsPlayed(), modName)
378 | endFunction
379 |
380 | bool function ClearModsPlayed() global
381 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_PlayingRecordingModsPlayed(), 0)
382 | endFunction
383 |
384 | string function GetCurrentlySkippingModName() global
385 | return JDB.solveStr(McmRecorder_JDB.JdbPath_CurrentlySkippingModName())
386 | endFunction
387 |
388 | int function GetAutorunHistory() global
389 | int history = JDB.solveObj(McmRecorder_JDB.JdbPath_AutorunHistory())
390 | if ! history
391 | history = JMap.object()
392 | JDB.solveObjSetter(McmRecorder_JDB.JdbPath_AutorunHistory(), history, createMissingKeys = true)
393 | endIf
394 | return history
395 | endFunction
396 |
397 | bool function HasBeenAutorun(string recordingName) global
398 | return JMap.getInt(GetAutorunHistory(), recordingName)
399 | endFunction
400 |
401 | function MarkHasBeenAutorun(string recordingName) global
402 | JMap.setInt(GetAutorunHistory(), recordingName, 1)
403 | endFunction
404 |
405 | function SetCurrentlySkippingModName(string modName) global
406 | JDB.solveStrSetter(McmRecorder_JDB.JdbPath_CurrentlySkippingModName(), modName, createMissingKeys = true)
407 | endFunction
408 |
409 | int function FindOption(SKI_ConfigBase mcm, string modName, string pageName, string optionType, string selector, string wildcard, int index, string side, float searchTimeout, float searchInterval, float searchPageLoadTime) global
410 | int foundOption
411 | float startTime = Utility.GetCurrentRealTime()
412 | while (! foundOption) && (Utility.GetCurrentRealTime() - startTime) < searchTimeout
413 | foundOption = AttemptFindOption(mcm, modName, pageName, optionType, selector, wildcard, index, side, searchInterval, searchPageLoadTime)
414 | if ! foundOption ; Does this ever run?
415 | McmRecorder_UI.Notification(modName + ": " + pageName + " (search for " + selector + ")")
416 | Utility.WaitMenuMode(searchInterval)
417 | endIf
418 | endWhile
419 | return foundOption
420 | endFunction
421 |
422 | int function AttemptFindOption(SKI_ConfigBase mcm, string modName, string pageName, string optionType, string selector, string wildcard, int index, string side, float searchInterval, float searchPageLoadTime) global
423 | float startTime = Utility.GetCurrentRealTime()
424 | while (Utility.GetCurrentRealTime() - startTime) < searchPageLoadTime
425 | int options = McmRecorder_McmFields.OptionsForModPage_ByOptionType(modName, pageName, optionType)
426 | int optionsCount = JArray.count(options)
427 | int matchCount = 0
428 | int i = 0
429 | while i < optionsCount
430 | int option = JArray.getObj(options, i)
431 |
432 | string optionText = JMap.getStr(option, "text")
433 | if side == "right"
434 | optionText = JMap.getStr(option, "strValue")
435 | endIf
436 |
437 | bool matches
438 | if wildcard
439 | matches = StringUtil.Find(optionText, wildcard) > -1
440 | else
441 | matches = optionText == selector
442 | endIf
443 |
444 | if matches
445 | matchCount += 1
446 | if index > -1 ; This must be the Nth one on the page
447 | if index == matchCount
448 | return option
449 | endIf
450 | else
451 | return option
452 | endIf
453 | endIf
454 |
455 | i += 1
456 | endWhile
457 |
458 | Utility.WaitMenuMode(searchInterval)
459 |
460 | RefreshMcmPage(mcm, modName, pageName) ; Wasn't on the page! Let's refresh the page.
461 |
462 | string debugPrefix = "[Play Action] " + modName
463 | if pageName
464 | debugPrefix += ": " + pageName
465 | endIf
466 | debugPrefix += " (" + selector + ")"
467 | if index > -1
468 | debugPrefix += " [" + index + "]"
469 | endIf
470 |
471 | if (Utility.GetCurrentRealTime() - startTime) >= 4 ; Every 4 seconds print an update
472 | McmRecorder_Logging.ConsoleOut(debugPrefix + " Searching for MCM option...")
473 | McmRecorder_UI.Notification(modName + ": " + pageName + " (search for " + selector + ")")
474 | endIf
475 | endWhile
476 |
477 | return 0
478 | endFunction
479 |
--------------------------------------------------------------------------------
/Scripts/Source/SKI_ConfigBase.psc:
--------------------------------------------------------------------------------
1 | scriptName SKI_ConfigBase extends SKI_QuestBase
2 |
3 | ;-- Properties --------------------------------------
4 | string property PageNameOrDefault
5 | string function get()
6 | if _currentPage
7 | return _currentPage
8 | else
9 | return "SKYUI_DEFAULT_PAGE"
10 | endIf
11 | endFunction
12 | endProperty
13 | String property CurrentPage
14 | String function get()
15 |
16 | return _currentPage
17 | endFunction
18 | endproperty
19 | Int property OPTION_TYPE_INPUT
20 | Int function get()
21 |
22 | return 8
23 | endFunction
24 | endproperty
25 | Int property OPTION_TYPE_KEYMAP
26 | Int function get()
27 |
28 | return 7
29 | endFunction
30 | endproperty
31 | String property MENU_ROOT
32 | String function get()
33 |
34 | return "_root.ConfigPanelFader.configPanel"
35 | endFunction
36 | endproperty
37 | Int property LEFT_TO_RIGHT
38 | Int function get()
39 |
40 | return 1
41 | endFunction
42 | endproperty
43 | Int property OPTION_FLAG_WITH_UNMAP
44 | Int function get()
45 |
46 | return 4
47 | endFunction
48 | endproperty
49 | Int property OPTION_TYPE_HEADER
50 | Int function get()
51 |
52 | return 1
53 | endFunction
54 | endproperty
55 | Int property TOP_TO_BOTTOM
56 | Int function get()
57 |
58 | return 2
59 | endFunction
60 | endproperty
61 | Int property OPTION_TYPE_EMPTY
62 | Int function get()
63 |
64 | return 0
65 | endFunction
66 | endproperty
67 | Int property OPTION_TYPE_TOGGLE
68 | Int function get()
69 |
70 | return 3
71 | endFunction
72 | endproperty
73 | Int property STATE_RESET
74 | Int function get()
75 |
76 | return 1
77 | endFunction
78 | endproperty
79 | Int property OPTION_FLAG_DISABLED
80 | Int function get()
81 |
82 | return 1
83 | endFunction
84 | endproperty
85 | String[] property Pages auto
86 | Int property STATE_COLOR
87 | Int function get()
88 |
89 | return 4
90 | endFunction
91 | endproperty
92 | String property JOURNAL_MENU
93 | String function get()
94 |
95 | return "Journal Menu"
96 | endFunction
97 | endproperty
98 | Int property OPTION_TYPE_MENU
99 | Int function get()
100 |
101 | return 5
102 | endFunction
103 | endproperty
104 | Int property OPTION_FLAG_HIDDEN
105 | Int function get()
106 |
107 | return 2
108 | endFunction
109 | endproperty
110 | Int property OPTION_TYPE_TEXT
111 | Int function get()
112 |
113 | return 2
114 | endFunction
115 | endproperty
116 | Int property STATE_INPUT
117 | Int function get()
118 |
119 | return 5
120 | endFunction
121 | endproperty
122 | Int property STATE_MENU
123 | Int function get()
124 |
125 | return 3
126 | endFunction
127 | endproperty
128 | Int property OPTION_FLAG_NONE
129 | Int function get()
130 |
131 | return 0
132 | endFunction
133 | endproperty
134 | Int property OPTION_TYPE_SLIDER
135 | Int function get()
136 |
137 | return 4
138 | endFunction
139 | endproperty
140 | Int property OPTION_TYPE_COLOR
141 | Int function get()
142 |
143 | return 6
144 | endFunction
145 | endproperty
146 | String property ModName auto
147 | Int property STATE_SLIDER
148 | Int function get()
149 |
150 | return 2
151 | endFunction
152 | endproperty
153 | Int property STATE_DEFAULT
154 | Int function get()
155 |
156 | return 0
157 | endFunction
158 | endproperty
159 |
160 | ;-- Variables ---------------------------------------
161 | Bool _messageResult = false
162 | String _infoText
163 | Int _currentPageNum = 0
164 | String[] _textBuf
165 | Int _configID = -1
166 | SKI_ConfigManager _configManager
167 | Int[] _optionFlagsBuf
168 | String[] _strValueBuf
169 | String _inputStartText
170 | Int property _activeOption = -1 auto
171 | Int _state = 0
172 | String _currentPage = ""
173 | Bool _initialized = false
174 | Int[] _colorParams
175 | Float[] _sliderParams
176 | Int[] _menuParams
177 | Int _cursorFillMode = 1
178 | String[] _stateOptionMap
179 | Bool _waitForMessage = false
180 | Float[] _numValueBuf
181 | Int _cursorPosition = 0
182 |
183 | ;-- Functions ---------------------------------------
184 |
185 | function SetTitleText(String a_text)
186 | if ! McmRecorder_Player.IsPlayingRecording()
187 | ui.InvokeString(self.JOURNAL_MENU, self.MENU_ROOT + ".setTitleText", a_text)
188 | endIf
189 | endFunction
190 |
191 | function SetOptionFlagsST(Int a_flags, Bool a_noUpdate, String a_stateName)
192 |
193 | if _state == self.STATE_RESET
194 | self.Error("Cannot set option flags while in OnPageReset(). Pass flags to AddOption instead")
195 | return
196 | endIf
197 | Int index = self.GetStateOptionIndex(a_stateName)
198 | if index < 0
199 | self.Error("Cannot use SetOptionFlagsST outside a valid option state")
200 | return
201 | endIf
202 | self.SetOptionFlags(index, a_flags, a_noUpdate)
203 | endFunction
204 |
205 | function OnSelectST()
206 | {Called when a non-interactive state option has been selected}
207 |
208 | ; Empty function
209 | endFunction
210 |
211 | function OnHighlightST()
212 | {Called when highlighting a state option}
213 |
214 | ; Empty function
215 | endFunction
216 |
217 | function AddSliderOptionST(String a_stateName, String a_text, Float a_value, String a_formatString, Int a_flags)
218 |
219 | self.AddOptionST(a_stateName, self.OPTION_TYPE_SLIDER, a_text, a_formatString, a_value, a_flags)
220 | endFunction
221 |
222 | function OnConfigClose()
223 | {Called when this config menu is closed}
224 |
225 | ; Empty function
226 | endFunction
227 |
228 | function SetSliderDialogRange(Float a_minValue, Float a_maxValue)
229 |
230 | if _state != self.STATE_SLIDER
231 | self.Error("Cannot set slider dialog params while outside OnOptionSliderOpen()")
232 | return
233 | endIf
234 | _sliderParams[2] = a_minValue
235 | _sliderParams[3] = a_maxValue
236 | endFunction
237 |
238 | function SetKeyMapOptionValue(Int a_option, Int a_keyCode, Bool a_noUpdate)
239 |
240 | Int index = a_option % 256
241 | Int type = _optionFlagsBuf[index] % 256
242 | if type != self.OPTION_TYPE_KEYMAP
243 | Int pageIdx = a_option / 256 - 1
244 | if pageIdx != -1
245 | self.Error("Option type mismatch. Expected keymap option, page \"" + Pages[pageIdx] + "\", index " + index as String)
246 | else
247 | self.Error("Option type mismatch. Expected keymap option, page \"\", index " + index as String)
248 | endIf
249 | return
250 | endIf
251 | self.SetOptionNumValue(index, a_keyCode as Float, a_noUpdate)
252 | endFunction
253 |
254 | function SetKeyMapOptionValueST(Int a_keyCode, Bool a_noUpdate, String a_stateName)
255 |
256 | Int index = self.GetStateOptionIndex(a_stateName)
257 | if index < 0
258 | self.Error("Cannot use SetKeyMapOptionValueST outside a valid option state")
259 | return
260 | endIf
261 | self.SetKeyMapOptionValue(index, a_keyCode, a_noUpdate)
262 | endFunction
263 |
264 | function OnInit()
265 |
266 | self.OnGameReload()
267 | endFunction
268 |
269 | function OnOptionMenuAccept(Int a_option, Int a_index)
270 | {Called when a menu entry has been accepted}
271 |
272 | ; Empty function
273 | endFunction
274 |
275 | function OnOptionSliderOpen(Int a_option)
276 | {Called when a slider option has been selected}
277 |
278 | ; Empty function
279 | endFunction
280 |
281 | function OnPageReset(String a_page)
282 | {Called when a new page is selected, including the initial empty page}
283 |
284 | ; Empty function
285 | endFunction
286 |
287 | function SetTextOptionValueST(String a_value, Bool a_noUpdate, String a_stateName)
288 |
289 | Int index = self.GetStateOptionIndex(a_stateName)
290 | if index < 0
291 | self.Error("Cannot use SetTextOptionValueST outside a valid option state")
292 | return
293 | endIf
294 | self.SetTextOptionValue(index, a_value, a_noUpdate)
295 | endFunction
296 |
297 | function OnMenuOpenST()
298 | {Called when a menu state option has been selected}
299 |
300 | ; Empty function
301 | endFunction
302 |
303 | function OnConfigManagerReady(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
304 |
305 | SKI_ConfigManager newManager = a_sender as SKI_ConfigManager
306 | if _configManager == newManager || newManager == none
307 | return
308 | endIf
309 | _configID = newManager.RegisterMod(self, ModName)
310 | if _configID >= 0
311 | _configManager = newManager
312 | self.OnConfigRegister()
313 | debug.Trace(self as String + ": Registered " + ModName + " at MCM.", 0)
314 | endIf
315 | endFunction
316 |
317 | function SetInfoText(String a_text)
318 |
319 | _infoText = a_text
320 | endFunction
321 |
322 | function SetInputDialogStartText(String a_text)
323 |
324 | if _state != self.STATE_INPUT
325 | self.Error("Cannot set input dialog params while outside OnOptionInputOpen()")
326 | return
327 | endIf
328 | _inputStartText = a_text
329 | endFunction
330 |
331 | function Error(String a_msg)
332 |
333 | debug.Trace(self as String + " ERROR: " + a_msg, 0)
334 | endFunction
335 |
336 | function SetTextOptionValue(Int a_option, String a_value, Bool a_noUpdate)
337 |
338 | Int index = a_option % 256
339 | Int type = _optionFlagsBuf[index] % 256
340 | if type != self.OPTION_TYPE_TEXT
341 | Int pageIdx = a_option / 256 - 1
342 | if pageIdx != -1
343 | self.Error("Option type mismatch. Expected text option, page \"" + Pages[pageIdx] + "\", index " + index as String)
344 | else
345 | self.Error("Option type mismatch. Expected text option, page \"\", index " + index as String)
346 | endIf
347 | return
348 | endIf
349 | self.SetOptionStrValue(index, a_value, a_noUpdate)
350 | endFunction
351 |
352 | function SetInputText(String a_text)
353 |
354 | String optionState = _stateOptionMap[_activeOption % 256]
355 | if optionState != ""
356 | String oldState = self.GetState()
357 | self.GotoState(optionState)
358 | self.OnInputAcceptST(a_text)
359 | self.GotoState(oldState)
360 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "input", _activeOption, strValue = a_text, recordStringValue = true, recordOptionType = true)
361 | else
362 | self.OnOptionInputAccept(_activeOption, a_text)
363 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "input", _activeOption, strValue = a_text, recordStringValue = true, recordOptionType = true)
364 | endIf
365 | _activeOption = -1
366 | endFunction
367 |
368 | function AddInputOptionST(String a_stateName, String a_text, String a_value, Int a_flags)
369 |
370 | self.AddOptionST(a_stateName, self.OPTION_TYPE_INPUT, a_text, a_value, 0 as Float, a_flags)
371 | endFunction
372 |
373 | function AddKeyMapOptionST(String a_stateName, String a_text, Int a_keyCode, Int a_flags)
374 | self.AddOptionST(a_stateName, self.OPTION_TYPE_KEYMAP, a_text, none, a_keyCode as Float, a_flags)
375 | endFunction
376 |
377 | function OnKeyMapChangeST(Int a_keyCode, String a_conflictControl, String a_conflictName)
378 | {Called when a key has been remapped for this state option}
379 |
380 | ; Empty function
381 | endFunction
382 |
383 | function OnConfigManagerReset(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
384 |
385 | _configManager = none
386 | endFunction
387 |
388 | Int function AddInputOption(String a_text, String a_value, Int a_flags)
389 |
390 | return self.AddOption(self.OPTION_TYPE_INPUT, a_text, a_value, 0 as Float, a_flags)
391 | endFunction
392 |
393 | function SelectOption(Int a_index)
394 | String optionState = _stateOptionMap[a_index]
395 | if optionState != ""
396 | String oldState = self.GetState()
397 | self.GotoState(optionState)
398 | self.OnSelectST()
399 | self.GotoState(oldState)
400 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "clickable", (a_index + _currentPageNum * 256), stateName = optionState)
401 | else
402 | Int option = a_index + _currentPageNum * 256
403 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "clickable", option)
404 | self.OnOptionSelect(option)
405 | endIf
406 | endFunction
407 |
408 | function SetInputOptionValueST(String a_value, Bool a_noUpdate, String a_stateName)
409 |
410 | Int index = self.GetStateOptionIndex(a_stateName)
411 | if index < 0
412 | self.Error("Cannot use SetInputOptionValueST outside a valid option state")
413 | return
414 | endIf
415 | self.SetInputOptionValue(index, a_value, a_noUpdate)
416 | endFunction
417 |
418 | ; Skipped compiler generated GotoState
419 |
420 | function SetOptionFlags(Int a_option, Int a_flags, Bool a_noUpdate)
421 |
422 | if _state == self.STATE_RESET
423 | self.Error("Cannot set option flags while in OnPageReset(). Pass flags to AddOption instead")
424 | return
425 | endIf
426 | Int index = a_option % 256
427 | Int oldFlags = _optionFlagsBuf[index]
428 | oldFlags %= 256
429 | oldFlags += a_flags * 256
430 | Int[] params = new Int[2]
431 | params[0] = index
432 | params[1] = a_flags
433 | if ! McmRecorder_Player.IsPlayingRecording()
434 | ui.InvokeIntA(self.JOURNAL_MENU, self.MENU_ROOT + ".setOptionFlags", params)
435 | endIf
436 | if !a_noUpdate && ! McmRecorder_Player.IsPlayingRecording()
437 | ui.Invoke(self.JOURNAL_MENU, self.MENU_ROOT + ".invalidateOptionData")
438 | endIf
439 | endFunction
440 |
441 | function SetPage(String a_page, Int a_index)
442 | _currentPage = a_page
443 | _currentPageNum = 1 + a_index
444 | if ! McmRecorder_Player.IsPlayingRecording()
445 | if a_page != ""
446 | self.SetTitleText(a_page)
447 | else
448 | self.SetTitleText(ModName)
449 | endIf
450 | endIf
451 | self.ClearOptionBuffers()
452 | _state = self.STATE_RESET
453 | self.OnPageReset(a_page)
454 | _state = self.STATE_DEFAULT
455 | self.WriteOptionBuffers()
456 | endFunction
457 |
458 | function SetInputOptionValue(Int a_option, String a_value, Bool a_noUpdate)
459 |
460 | Int index = a_option % 256
461 | Int type = _optionFlagsBuf[index] % 256
462 | if type != self.OPTION_TYPE_INPUT
463 | Int pageIdx = a_option / 256 - 1
464 | if pageIdx != -1
465 | self.Error("Option type mismatch. Expected input option, page \"" + Pages[pageIdx] + "\", index " + index as String)
466 | else
467 | self.Error("Option type mismatch. Expected input option, page \"\", index " + index as String)
468 | endIf
469 | return
470 | endIf
471 | self.SetOptionStrValue(index, a_value, a_noUpdate)
472 | endFunction
473 |
474 | Int function AddHeaderOption(String a_text, Int a_flags)
475 |
476 | return self.AddOption(self.OPTION_TYPE_HEADER, a_text, none, 0 as Float, a_flags)
477 | endFunction
478 |
479 | function OnGameReload()
480 | if !_initialized
481 | _initialized = true
482 | _sliderParams = new Float[5]
483 | _menuParams = new Int[2]
484 | _colorParams = new Int[2]
485 | self.OnConfigInit()
486 | debug.Trace(self as String + " INITIALIZED", 0)
487 | endIf
488 | self.RegisterForModEvent("SKICP_configManagerReady", "OnConfigManagerReady")
489 | self.RegisterForModEvent("SKICP_configManagerReset", "OnConfigManagerReset")
490 | self.CheckVersion()
491 | endFunction
492 |
493 | function OnSliderOpenST()
494 | {Called when a slider state option has been selected}
495 |
496 | ; Empty function
497 | endFunction
498 |
499 | function SetColorDialogStartColor(Int a_color)
500 |
501 | if _state != self.STATE_COLOR
502 | self.Error("Cannot set color dialog params while outside OnOptionColorOpen()")
503 | return
504 | endIf
505 | _colorParams[0] = a_color
506 | endFunction
507 |
508 | String function GetCustomControl(Int a_keyCode)
509 | {Returns the name of a custom control mapped to given keyCode, or "" if the key is not in use by this config}
510 |
511 | return ""
512 | endFunction
513 |
514 | Int function GetVersion()
515 | {Returns version of this script}
516 |
517 | return 1
518 | endFunction
519 |
520 | function OnOptionSliderAccept(Int a_option, Float a_value)
521 | {Called when a new slider value has been accepted}
522 |
523 | ; Empty function
524 | endFunction
525 |
526 | Int function AddKeyMapOption(String a_text, Int a_keyCode, Int a_flags)
527 |
528 | return self.AddOption(self.OPTION_TYPE_KEYMAP, a_text, none, a_keyCode as Float, a_flags)
529 | endFunction
530 |
531 | function OnInputOpenST()
532 | {Called when a text input state option has been selected}
533 |
534 | ; Empty function
535 | endFunction
536 |
537 | function SetColorValue(Int a_color)
538 |
539 | String optionState = _stateOptionMap[_activeOption % 256]
540 | if optionState != ""
541 | String oldState = self.GetState()
542 | self.GotoState(optionState)
543 | self.OnColorAcceptST(a_color)
544 | self.GotoState(oldState)
545 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "color", _activeOption, stateName = optionState, recordOptionType = true, fltValue = a_color, recordFloatValue = true)
546 | else
547 | self.OnOptionColorAccept(_activeOption, a_color)
548 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "color", _activeOption, recordOptionType = true, fltValue = a_color, recordFloatValue = true)
549 | endIf
550 | _activeOption = -1
551 | endFunction
552 |
553 | function SetMenuDialogStartIndex(Int a_value)
554 |
555 | if _state != self.STATE_MENU
556 | self.Error("Cannot set menu dialog params while outside OnOptionMenuOpen()")
557 | return
558 | endIf
559 | _menuParams[0] = a_value
560 | endFunction
561 |
562 | function ForcePageReset()
563 | {Forces a full reset of the current page}
564 |
565 | if McmRecorder_Player.IsPlayingRecording()
566 | CloseConfig()
567 | OpenConfig()
568 | Debug.Trace("[McmRecorder] ForcePageReset() for page " + CurrentPage)
569 | SetPage(CurrentPage, Pages.Find(CurrentPage))
570 | else
571 | ui.Invoke(self.JOURNAL_MENU, self.MENU_ROOT + ".forcePageReset")
572 | endIf
573 | endFunction
574 |
575 | function HighlightOption(Int a_index)
576 |
577 | _infoText = ""
578 | if a_index != -1
579 | String optionState = _stateOptionMap[a_index]
580 | if optionState != ""
581 | String oldState = self.GetState()
582 | self.GotoState(optionState)
583 | self.OnHighlightST()
584 | self.GotoState(oldState)
585 | else
586 | Int option = a_index + _currentPageNum * 256
587 | self.OnOptionHighlight(option)
588 | endIf
589 | endIf
590 | if ! McmRecorder_Player.IsPlayingRecording()
591 | ui.InvokeString(self.JOURNAL_MENU, self.MENU_ROOT + ".setInfoText", _infoText)
592 | endIf
593 | endFunction
594 |
595 | function SetOptionStrValue(Int a_index, String a_strValue, Bool a_noUpdate)
596 |
597 | if _state == self.STATE_RESET
598 | self.Error("Cannot modify option data while in OnPageReset()")
599 | return
600 | endIf
601 | String menu = self.JOURNAL_MENU
602 | String root = self.MENU_ROOT
603 | if ! McmRecorder_Player.IsPlayingRecording()
604 | ui.SetInt(menu, root + ".optionCursorIndex", a_index)
605 | ui.SetString(menu, root + ".optionCursor.strValue", a_strValue)
606 | endIf
607 | if !a_noUpdate && !McmRecorder_Player.IsPlayingRecording()
608 | ui.Invoke(menu, root + ".invalidateOptionData")
609 | endIf
610 | endFunction
611 |
612 | Int function GetStateOptionIndex(String a_stateName)
613 |
614 | if a_stateName == ""
615 | a_stateName = self.GetState()
616 | endIf
617 | if a_stateName == ""
618 | return -1
619 | endIf
620 | return _stateOptionMap.find(a_stateName, 0)
621 | endFunction
622 |
623 | function SetSliderDialogDefaultValue(Float a_value)
624 |
625 | if _state != self.STATE_SLIDER
626 | self.Error("Cannot set slider dialog params while outside OnOptionSliderOpen()")
627 | return
628 | endIf
629 | _sliderParams[1] = a_value
630 | endFunction
631 |
632 | function ResetOption(Int a_index)
633 |
634 | String optionState = _stateOptionMap[a_index]
635 | if optionState != ""
636 | String oldState = self.GetState()
637 | self.GotoState(optionState)
638 | self.OnDefaultST()
639 | self.GotoState(oldState)
640 | else
641 | Int option = a_index + _currentPageNum * 256
642 | self.OnOptionDefault(option)
643 | endIf
644 | endFunction
645 |
646 | function OnColorOpenST()
647 | {Called when a color state option has been selected}
648 |
649 | ; Empty function
650 | endFunction
651 |
652 | function RequestInputDialogData(Int a_index)
653 |
654 | _activeOption = a_index + _currentPageNum * 256
655 | _inputStartText = ""
656 | _state = self.STATE_INPUT
657 | String optionState = _stateOptionMap[a_index]
658 | if optionState != ""
659 | String oldState = self.GetState()
660 | self.GotoState(optionState)
661 | self.OnInputOpenST()
662 | self.GotoState(oldState)
663 | else
664 | self.OnOptionInputOpen(_activeOption)
665 | endIf
666 | _state = self.STATE_DEFAULT
667 | if ! McmRecorder_Player.IsPlayingRecording()
668 | ui.InvokeString(self.JOURNAL_MENU, self.MENU_ROOT + ".setInputDialogParams", _inputStartText)
669 | endIf
670 | endFunction
671 |
672 | function OnOptionInputOpen(Int a_option)
673 | {Called when a text input option has been selected}
674 |
675 | ; Empty function
676 | endFunction
677 |
678 | function SetMenuIndex(Int a_index)
679 |
680 | String optionState = _stateOptionMap[_activeOption % 256]
681 | if optionState != ""
682 | String oldState = self.GetState()
683 | self.GotoState(optionState)
684 | self.OnMenuAcceptST(a_index)
685 | self.GotoState(oldState)
686 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "menu", _activeOption, stateName = optionState, fltValue = a_index, recordFloatValue = true, recordOptionType = true, menuOptions = MostRecentlyConfiguredMenuDialogOptions)
687 | else
688 | self.OnOptionMenuAccept(_activeOption, a_index)
689 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "menu", _activeOption, fltValue = a_index, recordFloatValue = true, recordOptionType = true, menuOptions = MostRecentlyConfiguredMenuDialogOptions)
690 | endIf
691 | _activeOption = -1
692 | endFunction
693 |
694 | function OnOptionColorOpen(Int a_option)
695 | {Called when a color option has been selected}
696 |
697 | ; Empty function
698 | endFunction
699 |
700 | function SetSliderValue(Float a_value)
701 |
702 | String optionState = _stateOptionMap[_activeOption % 256]
703 | if optionState != ""
704 | String oldState = self.GetState()
705 | self.GotoState(optionState)
706 | self.OnSliderAcceptST(a_value)
707 | self.GotoState(oldState)
708 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "slider", _activeOption, stateName = optionState, fltValue = a_value, recordFloatValue = true, recordOptionType = true)
709 | else
710 | self.OnOptionSliderAccept(_activeOption, a_value)
711 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "slider", _activeOption, fltValue = a_value, recordFloatValue = true, recordOptionType = true)
712 | endIf
713 | _activeOption = -1
714 | endFunction
715 |
716 | function OnConfigRegister()
717 | {Called when this config menu registered at the control panel}
718 |
719 | ; Empty function
720 | endFunction
721 |
722 | function SetSliderOptionValueST(Float a_value, String a_formatString, Bool a_noUpdate, String a_stateName)
723 |
724 | Int index = self.GetStateOptionIndex(a_stateName)
725 | if index < 0
726 | self.Error("Cannot use SetSliderOptionValueST outside a valid option state")
727 | return
728 | endIf
729 | self.SetSliderOptionValue(index, a_value, a_formatString, a_noUpdate)
730 | endFunction
731 |
732 | function RequestMenuDialogData(Int a_index)
733 |
734 | _activeOption = a_index + _currentPageNum * 256
735 | _menuParams[0] = -1
736 | _menuParams[1] = -1
737 | _state = self.STATE_MENU
738 | String optionState = _stateOptionMap[a_index]
739 | if optionState != ""
740 | String oldState = self.GetState()
741 | self.GotoState(optionState)
742 | self.OnMenuOpenST()
743 | self.GotoState(oldState)
744 | else
745 | self.OnOptionMenuOpen(_activeOption)
746 | endIf
747 | _state = self.STATE_DEFAULT
748 | if ! McmRecorder_Player.IsPlayingRecording()
749 | ui.InvokeIntA(self.JOURNAL_MENU, self.MENU_ROOT + ".setMenuDialogParams", _menuParams)
750 | endIf
751 | endFunction
752 |
753 | function OnOptionSelect(Int a_option)
754 | {Called when a non-interactive option has been selected}
755 |
756 | ; Empty function
757 | endFunction
758 |
759 | function RequestSliderDialogData(Int a_index)
760 |
761 | _activeOption = a_index + _currentPageNum * 256
762 | _sliderParams[0] = 0 as Float
763 | _sliderParams[1] = 0 as Float
764 | _sliderParams[2] = 0 as Float
765 | _sliderParams[3] = 1 as Float
766 | _sliderParams[4] = 1 as Float
767 | _state = self.STATE_SLIDER
768 | String optionState = _stateOptionMap[a_index]
769 | if optionState != ""
770 | String oldState = self.GetState()
771 | self.GotoState(optionState)
772 | self.OnSliderOpenST()
773 | self.GotoState(oldState)
774 | else
775 | self.OnOptionSliderOpen(_activeOption)
776 | endIf
777 | _state = self.STATE_DEFAULT
778 | if ! McmRecorder_Player.IsPlayingRecording()
779 | ui.InvokeFloatA(self.JOURNAL_MENU, self.MENU_ROOT + ".setSliderDialogParams", _sliderParams)
780 | endIf
781 | endFunction
782 |
783 | function OnMessageDialogClose(String a_eventName, String a_strArg, Float a_numArg, Form a_sender)
784 |
785 | _messageResult = a_numArg as Bool
786 | _waitForMessage = false
787 | endFunction
788 |
789 | function SetOptionValues(Int a_index, String a_strValue, Float a_numValue, Bool a_noUpdate)
790 |
791 | if _state == self.STATE_RESET
792 | self.Error("Cannot modify option data while in OnPageReset()")
793 | return
794 | endIf
795 | String menu = self.JOURNAL_MENU
796 | String root = self.MENU_ROOT
797 | if ! McmRecorder_Player.IsPlayingRecording()
798 | ui.SetInt(menu, root + ".optionCursorIndex", a_index)
799 | ui.SetString(menu, root + ".optionCursor.strValue", a_strValue)
800 | ui.SetFloat(menu, root + ".optionCursor.numValue", a_numValue)
801 | endIf
802 | if !a_noUpdate && !McmRecorder_Player.IsPlayingRecording()
803 | ui.Invoke(menu, root + ".invalidateOptionData")
804 | endIf
805 | endFunction
806 |
807 | function SetOptionNumValue(Int a_index, Float a_numValue, Bool a_noUpdate)
808 |
809 | if _state == self.STATE_RESET
810 | self.Error("Cannot modify option data while in OnPageReset()")
811 | return
812 | endIf
813 | String menu = self.JOURNAL_MENU
814 | String root = self.MENU_ROOT
815 | if ! McmRecorder_Player.IsPlayingRecording()
816 | ui.SetInt(menu, root + ".optionCursorIndex", a_index)
817 | ui.SetFloat(menu, root + ".optionCursor.numValue", a_numValue)
818 | endIf
819 | if !a_noUpdate && !McmRecorder_Player.IsPlayingRecording()
820 | ui.Invoke(menu, root + ".invalidateOptionData")
821 | endIf
822 | endFunction
823 |
824 | function ClearOptionBuffers()
825 | if McmRecorder_Player.IsPlayingRecording() || McmRecorder_Recorder.IsRecording()
826 | McmRecorder_McmFields.MarkMcmOptionsForReset()
827 | endIf
828 |
829 | Int t = self.OPTION_TYPE_EMPTY
830 | Int i = 0
831 | while i < 128
832 | _optionFlagsBuf[i] = t
833 | _textBuf[i] = ""
834 | _strValueBuf[i] = ""
835 | _numValueBuf[i] = 0 as Float
836 | _stateOptionMap[i] = ""
837 | i += 1
838 | endWhile
839 | _cursorPosition = 0
840 | _cursorFillMode = self.LEFT_TO_RIGHT
841 | endFunction
842 |
843 | function WriteOptionBuffers()
844 | if McmRecorder_Player.IsPlayingRecording()
845 | return
846 | endIf
847 |
848 | String menu = self.JOURNAL_MENU
849 | String root = self.MENU_ROOT
850 | Int t = self.OPTION_TYPE_EMPTY
851 | Int i = 0
852 | Int optionCount = 0
853 | i = 0
854 | while i < 128
855 | if _optionFlagsBuf[i] != t
856 | optionCount = i + 1
857 | endIf
858 | i += 1
859 | endWhile
860 | if ! McmRecorder_Player.IsPlayingRecording()
861 | ui.InvokeIntA(menu, root + ".setOptionFlagsBuffer", _optionFlagsBuf)
862 | ui.InvokeStringA(menu, root + ".setOptionTextBuffer", _textBuf)
863 | ui.InvokeStringA(menu, root + ".setOptionStrValueBuffer", _strValueBuf)
864 | ui.InvokeFloatA(menu, root + ".setOptionNumValueBuffer", _numValueBuf)
865 | ui.InvokeInt(menu, root + ".flushOptionBuffers", optionCount)
866 | endIf
867 | endFunction
868 |
869 | function SetSliderOptionValue(Int a_option, Float a_value, String a_formatString, Bool a_noUpdate)
870 |
871 | Int index = a_option % 256
872 | Int type = _optionFlagsBuf[index] % 256
873 | if type != self.OPTION_TYPE_SLIDER
874 | Int pageIdx = a_option / 256 - 1
875 | if pageIdx != -1
876 | self.Error("Option type mismatch. Expected slider option, page \"" + Pages[pageIdx] + "\", index " + index as String)
877 | else
878 | self.Error("Option type mismatch. Expected slider option, page \"\", index " + index as String)
879 | endIf
880 | return
881 | endIf
882 | self.SetOptionValues(index, a_formatString, a_value, a_noUpdate)
883 | endFunction
884 |
885 | function AddOptionST(String a_stateName, Int a_optionType, String a_text, String a_strValue, Float a_numValue, Int a_flags)
886 | if _stateOptionMap.find(a_stateName, 0) != -1
887 | self.Error("State option name " + a_stateName + " is already in use")
888 | return
889 | endIf
890 | Int index = self.AddOption(a_optionType, a_text, a_strValue, a_numValue, a_flags, a_stateName) % 256
891 | if index < 0
892 | return
893 | endIf
894 | if _stateOptionMap[index] != ""
895 | self.Error("State option index " + index as String + " already in use")
896 | return
897 | endIf
898 | _stateOptionMap[index] = a_stateName
899 | endFunction
900 |
901 | function AddToggleOptionST(String a_stateName, String a_text, Bool a_checked, Int a_flags)
902 |
903 | self.AddOptionST(a_stateName, self.OPTION_TYPE_TOGGLE, a_text, none, (a_checked as Int) as Float, a_flags)
904 | endFunction
905 |
906 | function UnloadCustomContent()
907 |
908 | if ! McmRecorder_Player.IsPlayingRecording()
909 | ui.Invoke(self.JOURNAL_MENU, self.MENU_ROOT + ".unloadCustomContent")
910 | endIf
911 | endFunction
912 |
913 | function OpenConfig()
914 |
915 | _optionFlagsBuf = new Int[128]
916 | _textBuf = new String[128]
917 | _strValueBuf = new String[128]
918 | _numValueBuf = new Float[128]
919 | _stateOptionMap = new String[128]
920 | self.SetPage("", -1)
921 | self.OnConfigOpen()
922 | if ! McmRecorder_Player.IsPlayingRecording()
923 | ui.InvokeStringA(self.JOURNAL_MENU, self.MENU_ROOT + ".setPageNames", Pages)
924 | endIf
925 | endFunction
926 |
927 | Bool function ShowMessage(String a_message, Bool a_withCancel, String a_acceptLabel, String a_cancelLabel)
928 | if McmRecorder_Player.IsPlayingRecording()
929 | return true ; Automatically accept every dialog without actually showing it :)
930 | endIf
931 |
932 | if _waitForMessage
933 | self.Error("Called ShowMessage() while another message was already open")
934 | return false
935 | endIf
936 | _waitForMessage = true
937 | _messageResult = false
938 | String[] params = new String[3]
939 | params[0] = a_message
940 | params[1] = a_acceptLabel
941 | if a_withCancel
942 | params[2] = a_cancelLabel
943 | else
944 | params[2] = ""
945 | endIf
946 | self.RegisterForModEvent("SKICP_messageDialogClosed", "OnMessageDialogClose")
947 | if ! McmRecorder_Player.IsPlayingRecording()
948 | ui.InvokeStringA(self.JOURNAL_MENU, self.MENU_ROOT + ".showMessageDialog", params)
949 | endIf
950 | while _waitForMessage
951 | utility.WaitMenuMode(0.100000)
952 | endWhile
953 | self.UnregisterForModEvent("SKICP_messageDialogClosed")
954 | return _messageResult
955 | endFunction
956 |
957 | string[] property MostRecentlyConfiguredMenuDialogOptions auto
958 |
959 | function SetMenuDialogOptions(String[] a_options)
960 | MostRecentlyConfiguredMenuDialogOptions = a_options
961 |
962 | if _state != self.STATE_MENU
963 | self.Error("Cannot set menu dialog params while outside OnOptionMenuOpen()")
964 | return
965 | endIf
966 | if ! McmRecorder_Player.IsPlayingRecording()
967 | ui.InvokeStringA(self.JOURNAL_MENU, self.MENU_ROOT + ".setMenuDialogOptions", a_options)
968 | endIf
969 | endFunction
970 |
971 | function OnVersionUpdate(Int a_version)
972 | {Called when a version update of this script has been detected}
973 |
974 | ; Empty function
975 | endFunction
976 |
977 | function SetColorDialogDefaultColor(Int a_color)
978 |
979 | if _state != self.STATE_COLOR
980 | self.Error("Cannot set color dialog params while outside OnOptionColorOpen()")
981 | return
982 | endIf
983 | _colorParams[1] = a_color
984 | endFunction
985 |
986 | function OnSliderAcceptST(Float a_value)
987 | {Called when a new slider state value has been accepted}
988 |
989 | ; Empty function
990 | endFunction
991 |
992 | function OnInputAcceptST(String a_input)
993 | {Called when a new text input has been accepted for this state option}
994 |
995 | ; Empty function
996 | endFunction
997 |
998 | function LoadCustomContent(String a_source, Float a_x, Float a_y)
999 |
1000 | Float[] params = new Float[2]
1001 | params[0] = a_x
1002 | params[1] = a_y
1003 | if ! McmRecorder_Player.IsPlayingRecording()
1004 | ui.InvokeFloatA(self.JOURNAL_MENU, self.MENU_ROOT + ".setCustomContentParams", params)
1005 | ui.InvokeString(self.JOURNAL_MENU, self.MENU_ROOT + ".loadCustomContent", a_source)
1006 | endIf
1007 | endFunction
1008 |
1009 | function RequestColorDialogData(Int a_index)
1010 |
1011 | _activeOption = a_index + _currentPageNum * 256
1012 | _colorParams[0] = -1
1013 | _colorParams[1] = -1
1014 | _state = self.STATE_COLOR
1015 | String optionState = _stateOptionMap[a_index]
1016 | if optionState != ""
1017 | String oldState = self.GetState()
1018 | self.GotoState(optionState)
1019 | self.OnColorOpenST()
1020 | self.GotoState(oldState)
1021 | else
1022 | self.OnOptionColorOpen(_activeOption)
1023 | endIf
1024 | _state = self.STATE_DEFAULT
1025 | if ! McmRecorder_Player.IsPlayingRecording()
1026 | ui.InvokeIntA(self.JOURNAL_MENU, self.MENU_ROOT + ".setColorDialogParams", _colorParams)
1027 | endIf
1028 | endFunction
1029 |
1030 | function SetSliderDialogInterval(Float a_value)
1031 |
1032 | if _state != self.STATE_SLIDER
1033 | self.Error("Cannot set slider dialog params while outside OnOptionSliderOpen()")
1034 | return
1035 | endIf
1036 | _sliderParams[4] = a_value
1037 | endFunction
1038 |
1039 | Int function AddColorOption(String a_text, Int a_color, Int a_flags)
1040 |
1041 | return self.AddOption(self.OPTION_TYPE_COLOR, a_text, none, a_color as Float, a_flags)
1042 | endFunction
1043 |
1044 | function SetColorOptionValueST(Int a_color, Bool a_noUpdate, String a_stateName)
1045 |
1046 | Int index = self.GetStateOptionIndex(a_stateName)
1047 | if index < 0
1048 | self.Error("Cannot use SetColorOptionValueST outside a valid option state")
1049 | return
1050 | endIf
1051 | self.SetColorOptionValue(index, a_color, a_noUpdate)
1052 | endFunction
1053 |
1054 | function SetMenuOptionValueST(String a_value, Bool a_noUpdate, String a_stateName)
1055 |
1056 | Int index = self.GetStateOptionIndex(a_stateName)
1057 | if index < 0
1058 | self.Error("Cannot use SetMenuOptionValueST outside a valid option state")
1059 | return
1060 | endIf
1061 | self.SetMenuOptionValue(index, a_value, a_noUpdate)
1062 | endFunction
1063 |
1064 | ; Skipped compiler generated GetState
1065 |
1066 | Int function AddEmptyOption()
1067 |
1068 | return self.AddOption(self.OPTION_TYPE_EMPTY, none, none, 0 as Float, 0)
1069 | endFunction
1070 |
1071 | function SetMenuOptionValue(Int a_option, String a_value, Bool a_noUpdate)
1072 |
1073 | Int index = a_option % 256
1074 | Int type = _optionFlagsBuf[index] % 256
1075 | if type != self.OPTION_TYPE_MENU
1076 | Int pageIdx = a_option / 256 - 1
1077 | if pageIdx != -1
1078 | self.Error("Option type mismatch. Expected menu option, page \"" + Pages[pageIdx] + "\", index " + index as String)
1079 | else
1080 | self.Error("Option type mismatch. Expected menu option, page \"\", index " + index as String)
1081 | endIf
1082 | return
1083 | endIf
1084 | self.SetOptionStrValue(index, a_value, a_noUpdate)
1085 | endFunction
1086 |
1087 | function SetMenuDialogDefaultIndex(Int a_value)
1088 |
1089 | if _state != self.STATE_MENU
1090 | self.Error("Cannot set menu dialog params while outside OnOptionMenuOpen()")
1091 | return
1092 | endIf
1093 | _menuParams[1] = a_value
1094 | endFunction
1095 |
1096 | function AddTextOptionST(String a_stateName, String a_text, String a_value, Int a_flags)
1097 |
1098 | self.AddOptionST(a_stateName, self.OPTION_TYPE_TEXT, a_text, a_value, 0 as Float, a_flags)
1099 | endFunction
1100 |
1101 | function AddMenuOptionST(String a_stateName, String a_text, String a_value, Int a_flags)
1102 |
1103 | self.AddOptionST(a_stateName, self.OPTION_TYPE_MENU, a_text, a_value, 0 as Float, a_flags)
1104 | endFunction
1105 |
1106 | function OnColorAcceptST(Int a_color)
1107 | {Called when a new color has been accepted for this state option}
1108 |
1109 | ; Empty function
1110 | endFunction
1111 |
1112 | function OnOptionHighlight(Int a_option)
1113 | {Called when highlighting an option}
1114 |
1115 | ; Empty function
1116 | endFunction
1117 |
1118 | function OnOptionKeyMapChange(Int a_option, Int a_keyCode, String a_conflictControl, String a_conflictName)
1119 | {Called when a key has been remapped}
1120 |
1121 | ; Empty function
1122 | endFunction
1123 |
1124 | Int function AddTextOption(String a_text, String a_value, Int a_flags)
1125 |
1126 | return self.AddOption(self.OPTION_TYPE_TEXT, a_text, a_value, 0 as Float, a_flags)
1127 | endFunction
1128 |
1129 | function OnConfigInit()
1130 | {Called when this config menu is initialized}
1131 |
1132 | ; Empty function
1133 | endFunction
1134 |
1135 | function OnDefaultST()
1136 | {Called when resetting a state option to its default value}
1137 |
1138 | ; Empty function
1139 | endFunction
1140 |
1141 | Int function AddToggleOption(String a_text, Bool a_checked, Int a_flags)
1142 |
1143 | return self.AddOption(self.OPTION_TYPE_TOGGLE, a_text, none, (a_checked as Int) as Float, a_flags)
1144 | endFunction
1145 |
1146 | function SetSliderDialogStartValue(Float a_value)
1147 |
1148 | if _state != self.STATE_SLIDER
1149 | self.Error("Cannot set slider dialog params while outside OnOptionSliderOpen()")
1150 | return
1151 | endIf
1152 | _sliderParams[0] = a_value
1153 | endFunction
1154 |
1155 | function SetCursorFillMode(Int a_fillMode)
1156 |
1157 | if a_fillMode == self.LEFT_TO_RIGHT || a_fillMode == self.TOP_TO_BOTTOM
1158 | _cursorFillMode = a_fillMode
1159 | endIf
1160 | endFunction
1161 |
1162 | function OnConfigOpen()
1163 | {Called when this config menu is opened}
1164 |
1165 | ; Empty function
1166 | endFunction
1167 |
1168 | function RemapKey(Int a_index, Int a_keyCode, String a_conflictControl, String a_conflictName)
1169 |
1170 | String optionState = _stateOptionMap[a_index]
1171 | if optionState != ""
1172 | String oldState = self.GetState()
1173 | self.GotoState(optionState)
1174 | self.OnKeyMapChangeST(a_keyCode, a_conflictControl, a_conflictName)
1175 | self.GotoState(oldState)
1176 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "keymap", (a_index + _currentPageNum * 256), stateName = optionState, recordOptionType = true, fltValue = a_keyCode, recordFloatValue = true)
1177 | else
1178 | Int option = a_index + _currentPageNum * 256
1179 | self.OnOptionKeyMapChange(option, a_keyCode, a_conflictControl, a_conflictName)
1180 | McmRecorder_Recorder.RecordAction(self, ModName, PageNameOrDefault, "keymap", option, recordOptionType = true, fltValue = a_keyCode, recordFloatValue = true)
1181 | endIf
1182 | endFunction
1183 |
1184 | function SetToggleOptionValue(Int a_option, Bool a_checked, Bool a_noUpdate)
1185 |
1186 | Int index = a_option % 256
1187 | Int type = _optionFlagsBuf[index] % 256
1188 | if type != self.OPTION_TYPE_TOGGLE
1189 | Int pageIdx = a_option / 256 - 1
1190 | if pageIdx != -1
1191 | self.Error("Option type mismatch. Expected toggle option, page \"" + Pages[pageIdx] + "\", index " + index as String)
1192 | else
1193 | self.Error("Option type mismatch. Expected toggle option, page \"\", index " + index as String)
1194 | endIf
1195 | return
1196 | endIf
1197 | self.SetOptionNumValue(index, (a_checked as Int) as Float, a_noUpdate)
1198 | endFunction
1199 |
1200 | Int function AddOption(Int a_optionType, String a_text, String a_strValue, Float a_numValue, Int a_flags, string stateName = "")
1201 | if _state != self.STATE_RESET
1202 | self.Error("Cannot add option " + a_text + " outside of OnPageReset()")
1203 | return -1
1204 | endIf
1205 | Int pos = _cursorPosition
1206 | if pos == -1
1207 | return -1
1208 | endIf
1209 |
1210 | _optionFlagsBuf[pos] = a_optionType + a_flags * 256
1211 | _textBuf[pos] = a_text
1212 | _strValueBuf[pos] = a_strValue
1213 | _numValueBuf[pos] = a_numValue
1214 | _cursorPosition += _cursorFillMode
1215 | if _cursorPosition >= 128
1216 | _cursorPosition = -1
1217 | endIf
1218 |
1219 | int optionId = pos + _currentPageNum * 256
1220 |
1221 | string optionTypeName = McmRecorder_McmFields.GetOptionTypeName(a_optionType)
1222 | McmRecorder_McmFields.TrackField( \
1223 | modName = ModName, \
1224 | pageName = PageNameOrDefault, \
1225 | optionType = optionTypeName, \
1226 | optionId = optionId, \
1227 | text = a_text, \
1228 | strValue = a_strValue, \
1229 | fltValue = a_numValue, \
1230 | stateName = stateName \
1231 | )
1232 | return optionId
1233 | endFunction
1234 |
1235 | function CloseConfig()
1236 |
1237 | self.OnConfigClose()
1238 | self.ClearOptionBuffers()
1239 | _waitForMessage = false
1240 | _optionFlagsBuf = new Int[1]
1241 | _textBuf = new String[1]
1242 | _strValueBuf = new String[1]
1243 | _numValueBuf = new Float[1]
1244 | _stateOptionMap = new String[1]
1245 | endFunction
1246 |
1247 | function OnOptionColorAccept(Int a_option, Int a_color)
1248 | {Called when a new color has been accepted}
1249 |
1250 | ; Empty function
1251 | endFunction
1252 |
1253 | function OnMenuAcceptST(Int a_index)
1254 | {Called when a menu entry has been accepted for this state option}
1255 |
1256 | ; Empty function
1257 | endFunction
1258 |
1259 | Int function AddSliderOption(String a_text, Float a_value, String a_formatString, Int a_flags)
1260 |
1261 | return self.AddOption(self.OPTION_TYPE_SLIDER, a_text, a_formatString, a_value, a_flags)
1262 | endFunction
1263 |
1264 | function OnOptionDefault(Int a_option)
1265 | {Called when resetting an option to its default value}
1266 |
1267 | ; Empty function
1268 | endFunction
1269 |
1270 | function AddColorOptionST(String a_stateName, String a_text, Int a_color, Int a_flags)
1271 |
1272 | self.AddOptionST(a_stateName, self.OPTION_TYPE_COLOR, a_text, none, a_color as Float, a_flags)
1273 | endFunction
1274 |
1275 | function SetCursorPosition(Int a_position)
1276 |
1277 | if a_position < 128
1278 | _cursorPosition = a_position
1279 | endIf
1280 | endFunction
1281 |
1282 | Int function AddMenuOption(String a_text, String a_value, Int a_flags)
1283 |
1284 | return self.AddOption(self.OPTION_TYPE_MENU, a_text, a_value, 0 as Float, a_flags)
1285 | endFunction
1286 |
1287 | function OnOptionInputAccept(Int a_option, String a_input)
1288 | {Called when a new text input has been accepted}
1289 |
1290 | ; Empty function
1291 | endFunction
1292 |
1293 | function SetToggleOptionValueST(Bool a_checked, Bool a_noUpdate, String a_stateName)
1294 |
1295 | Int index = self.GetStateOptionIndex(a_stateName)
1296 | if index < 0
1297 | self.Error("Cannot use SetToggleOptionValueST outside a valid option state")
1298 | return
1299 | endIf
1300 | self.SetToggleOptionValue(index, a_checked, a_noUpdate)
1301 | endFunction
1302 |
1303 | function OnOptionMenuOpen(Int a_option)
1304 | {Called when a menu option has been selected}
1305 |
1306 | ; Empty function
1307 | endFunction
1308 |
1309 | function SetColorOptionValue(Int a_option, Int a_color, Bool a_noUpdate)
1310 |
1311 | Int index = a_option % 256
1312 | Int type = _optionFlagsBuf[index] % 256
1313 | if type != self.OPTION_TYPE_COLOR
1314 | Int pageIdx = a_option / 256 - 1
1315 | if pageIdx != -1
1316 | self.Error("Option type mismatch. Expected color option, page \"" + Pages[pageIdx] + "\", index " + index as String)
1317 | else
1318 | self.Error("Option type mismatch. Expected color option, page \"\", index " + index as String)
1319 | endIf
1320 | return
1321 | endIf
1322 | self.SetOptionNumValue(index, a_color as Float, a_noUpdate)
1323 | endFunction
1324 |
--------------------------------------------------------------------------------