-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInstall-FancyScreenPatchForRecettear.bat
11970 lines (10001 loc) · 565 KB
/
Install-FancyScreenPatchForRecettear.bat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
@echo off
start "Fancy Screen Patch for Recettear" /D "%~dp0" powershell.exe -ExecutionPolicy Bypass -NoExit -Command "& {[Console]::WindowHeight = [Console]::LargestWindowHeight * 4 / 5;$Script = 'Install-FancyScreenPatchForRecettear.v1_0_3.FromBatchFile.ps1';$B = [IO.File]::ReadAllBytes(\"%~nx0\");$O = $B[0x030E .. ($B.Length - 1)];try{$S = [IO.File]::ReadAllBytes($Script);if ($O.Length -ne $S.Length -or -not [Linq.Enumerable]::SequenceEqual($O, $S)) {if ($Host.UI.PromptForChoice($Null, \"The contents of the file at `\"$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Script))`\" will be overwritten. Would you like to proceed?\", ('&Yes', '&No'), 0) -ne 0){return}}}catch {}[IO.File]::WriteAllBytes($Script, $O);& (Join-Path . $Script)}"
exit /b
<#
If you meant to run this script file, please right-click the file, and then select "Run with PowerShell".
#>
<# SPDX-LICENSE-IDENTIFIER: BSL-1.0 #>
<#
Copyright Harry Gillanders 2023-2023.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
#>
<#
.Synopsis
Used to apply the Fancy Screen Patch for Recettear to an installation of Recettear.
.Description
Fancy Screen Patch for Recettear is a patch for the video-game Recettear.
The patch adds supports to Recettear for:
* Arbitrary resolutions of aspect-ratios at-least as wide as 4:3.
* Raising the frame-rate limit above 60-FPS, whilst retaining the game's original frame-rate of 60-FPS for game-logic.
* Configurability for the texture-filtering algorithm used to up-scale a given category of textures.
* Restricting the up-scaling of 2D art to integral scaling multipliers.
* Restricting the width of the HUD to a subset of the game's width.
* Hiding some persistent control reminders from the HUD.
This script is used to apply the patch to an installation of Recettear.
This script has two main modes of operation: interactive, and non-interactive. Interactive is the default mode, and non-interactive mode can be enabled via the `NonInteractive` switch.
The interactive and non-interactive modes generally behave in the same way when given the same arguments, with two exceptions: when a value is not provided for the `SaveSettingsToConfiguration` parameter or the `DoNotInstallThirdPartyToolsByDefaultNextTime` parameter, they default to `$True` in interactive mode, and `$False` in non-interactive mode.
When no value is provided for the `Configuration` parameter, it will be initialised from an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder, if present.
This is true in both interactive and non-interactive mode.
If you want to ignore the configuration file, you can supply an empty hash-table for the `Configuration` parameter.
See the help entry for the `Configuration` parameter for more detail.
The `ReturnInformation` switch is useful for interacting with the more complex parameters programmatically.
For consistency between the parameters of this script and the values set via the configuration file, every parameter that can be set via the configuration file is optional, and untyped.
Additionally, for such parameters, explicitly supplying a value of `$Null` is treated in the same way as not specifying the parameter at all.
The general philosophy for those parameters is that if a parameter is `$Null` or unspecified then a reasonable default is used for its value.
.Example
PS> Install-FancyScreenPatchForRecettear.ps1
# Applies the patch interactively with the default settings, including the settings saved in an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder, if present.
.Example
PS> Install-FancyScreenPatchForRecettear.ps1 -NonInteractive
# Applies the patch non-interactively with the default settings, including the settings saved in an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder, if present.
.Example
PS> Install-FancyScreenPatchForRecettear.ps1 -NonInteractive -Configuration @{}
# Applies the patch non-interactively with the default settings, ignoring the settings saved in an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder.
.Example
PS> Install-FancyScreenPatchForRecettear.ps1 -NonInteractive -Configuration @{} -ResolutionWidth 3840 -ResolutionHeight 2160 -FramerateLimit 160
# Applies the patch non-interactively such that the game will use a resolution of 3840x2160, at 160 FPS, with otherwise default settings, ignoring the settings saved in an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder.
.Outputs
System.Management.Automation.PSCustomObject.
When the `ReturnInformation` parameter is `$False`, this script's returned value will contain the following entries:
TimeTaken: [System.TimeSpan]; How long it took the script to patch the game (excluding time spent waiting for user-input in interactive mode, and time spent downloading files from the Internet).
When the game is patched, this script's returned value will contain the following entries:
BackupOfPatchedExecutable: [System.IO.FileInfo]; The backup made of the game's executable before it was patched.
PatchedExecutable: [System.IO.FileInfo]; The game's patched executable.
When post-patch operations are performed, this script's returned value will contain the following entries:
ConfigurationChanges: [System.Management.Automation.PSCustomObject]; Details about the changes made to the game's configuration.
The ConfigurationChanges member is structured as follows:
ByFile: [System.Collections.Specialized.OrderedDictionary]; A hash-table keyed by the name of a configuration file that was changed, with the values being a `PSCustomObject` with two entries:
Reset: [System.Management.Automation.PSCustomObject]; If the configuration file was not reset, this will be `$Null`, otherwise it will have two entries:
Before: [System.Management.Automation.PSCustomObject]; The state of the configuration file before it was reset:
Lines: [String[]]; An array of the lines of the configuration file.
After: [System.Management.Automation.PSCustomObject]; The state of the configuration file after it was reset:
Lines: [String[]]; An array of the lines of the configuration file.
Changes: [System.Collections.Specialized.OrderedDictionary]; A hash-table keyed by the name of a section of the configuration file that was changed, with the values being an `OrderedDictionary` wherein each entry is keyed by the name of a setting in the configuration and the value is what that setting was changed to.
DgVoodoo2EnabledStatusChange: [System.Boolean]; To switch between DirectX 12/11 and DirectX 9/8.1, dgVoodoo2 may be enabled or disabled, when this happens, this will be a boolean representing whether or not dgVoodoo2 is enabled or disabled. If dgVoodoo2 does not need to be enabled or disabled this will be `$Null`.
FileNameChanges: [System.Collections.Generic.List[System.ValueTuple[System.String, System.String]]]; This is a list of two-item tuples detailing any files that were renamed. The first item of each tuple is the full path of a file before it was renamed, and the second item is the new name of the renamed file.
When the `CheckDxWrapperConfiguration`, `CheckDgVoodoo2Configuration`, or `CheckSpecialKConfiguration` parameters are `$True`, this script's returned value will contain `DxWrapperConfiguration`, `DgVoodoo2Configuration`, or `SpecialKConfiguration` entries respectively, the values of these entries are:
[System.Collections.Specialized.OrderedDictionary]; A hash-table keyed by the name of a section of the configuration file that was changed, with the values being an `OrderedDictionary` wherein each entry is keyed by the name of a setting in the configuration and the value is a `PSCustomObject` with two entries:
ActualValue: [System.String]; The actual value of the configuration setting.
ExpectedValue: [System.String]; The value of the configuration setting expected by the patch.
When the `GetGameWindowMode` parameter is `$True`, this script's returned value will have a `GameWindowMode` member, wherein the value is a string representing the mode that the game's window is configured to use.
When the `GetDirectXVersionToUse` parameter is `$True`, this script's returned value will have a `DirectXVersionToUse` member, wherein the value is an integer representing the version of DirectX that the game is configured to use.
When the `GetVerticalSyncEnabled` parameter is `$True`, this script's returned value will have a `VerticalSyncEnabled` member, wherein the value is a boolean representing whether the game is configured to use vertical-sync or not.
When the `ReturnInformation` parameter is `$True`, this script's returned value will contain the following entries:
DetectedInstallations: An array of `PSCustomObject`s wherein each object represents an automatically detected installation of Recettear, with each object having these three entries:
Source: A string representing the source of the installation, using the same values recognised by the `DetectedInstallationPreference` parameter.
UIChoice: A string containing the label used for the installation source in interactive mode.
Path: The full-path to the installation's `recettear.exe` file.
UsingIntegral2DScaling: A boolean representing whether integral 2D scaling is being used or not.
DrawDistanceMultiplier: A double representing the value by which the game's vanilla draw-distance for mobs and whatnot is being multiplied by.
PartiallyResolvedEffectiveConfiguration: An `OrderedDictionary` containing the configuration that would be saved to the `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder when the `SaveSettingsToConfiguration` parameter is `$True`.
FullyResolvedEffectiveConfiguration: An `OrderedDictionary` containing the configuration that would be used for patching the game if the `ReturnInformation` parameter were `$False`.
RecettearExecutablePath: The full path of the `recettear.exe` file that would be patched if the `ReturnInformation` parameter were `$False`.
BackupPath: If the `BackupPath` parameter has been supplied, its values will be mirrored here.
ClobberedByRestoredBackupBackupPath: If the `ClobberedByRestoredBackupBackupPath` parameter has been supplied, its values will be mirrored here.
Configuration: The configuration object that the script loaded. Either from the `Configuration` parameter or the `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder.
ReturnInformation: `$True`.
ConfigurableInterpolatedFloats: A collection of `PSCustomObject`s representing the interpolated floats that can be configured, each object having the following entries:
Names: An array of strings representing the names that the interpolated float is recognised by. The first name in this array is always the canonical name for the interpolated float.
Recommendation: The value recommended by this patch for the interpolated float.
Synopsis: A string describing the interpolated float.
ConfigurableTextureFilterings: A collection of `PSCustomObject`s representing the classes of textures for which the texture-filtering can be configured, each object having the following entries:
Names: An array of strings representing the names that the class of textures is recognised by. The first name in this array is always the canonical name for the class of textures.
Recommendation: The value recommended by this patch for the class of textures.
Synopsis: A string describing the class of textures.
.Parameter NonInteractive
Controls whether the script is operating in non-interactive or interactive mode.
.Parameter RecettearExecutablePath
Specifies which installation of Recettear is patched, via the path of a `recettear.exe` file.
If this is not provided, an automatically detected installation of Recettear is patched; see the help entry for the `DetectedInstallationPreference` parameter for more detail on how that operates.
.Parameter DetectedInstallationPreference
Specifies the precedence of automatically detected installations of Recettear over one another.
This script can automatically detect installations of Recettear from four locations:
`ScriptRoot`: The same folder as the script is in.
`CurrentDirectory`: The current working directory.
`Steam`: An installation of the game in a Steam library folder.
`GOG.com`: An installation of the game from GOG.com.
The precedence of those locations can be specified as an array ordered from most preferred to least preferred.
The order those locations were documented in above is the default order.
When the `RecettearExecutablePath` parameter is not supplied:
In interactive mode, this is used for the order of the locations when prompting the user to select one of them.
In non-interactive mode, the first of these installations that can be found is the installation that gets patched.
.Parameter BackupPath
Specifies the path to save a backup of the `recettear.exe` file to be patched to. Existing files at this path will be overwritten.
This patch saves a backup of the `recettear.exe` file before it makes any changes to it.
If this parameter is not provided the backup path defaults to `<game installation folder>/recettear.<game language code>.SansFancyScreenPatch.<current time in UTC as the number of hecto-nanoseconds elapsed since 0001-01-01 00:00>.exe`.
.Parameter ClobberedByRestoredBackupBackupPath
Specifies the path to save a backup of the `recettear.exe` file being overwritten, when restoring a backup, to. Existing files at this path will be overwritten.
This patch can automatically restore a previously-made backup of the `recettear.exe` file, before it does this it creates a backup for the `recettear.exe` file.
If this parameter is not provided the backup path defaults to `<game installation folder>/recettear.<game language code>.ClobberedByRestoredBackupBackupPath.<current time in UTC as the number of hecto-nanoseconds elapsed since 0001-01-01 00:00>.exe`.
.Parameter FramerateLimit
The controls the frame-rate that the game should run at.
If you intend to use vertical-sync, this ideally should be one less than your screen's refresh-rate (e.g 119-FPS for a 120-Hz screen), if possible, to avoid excess latency. Otherwise, this should be the frame-rate you intend to run the game at.
The frame-rate limit must be at-least sixty. Values greater-than one-thousand for the frame-rate limit can be used, but any adverse effects resulting from values greater-than one-thousand are unsupported.
Whilst this patch does allow the use of frame-rates greater-than the game's native frame-rate of sixty FPS, it does not completely decouple the frame-rate from the rendering logic. The frame-rate limit set here influences how the game is interpolated to higher frame-rates, so setting this value higher than your screen's refresh-rate may have an adverse effect on the appearance of the game's motion.
If this parameter is not provided the frame-rate limit defaults to 60 FPS.
.Parameter ResolutionWidth
This controls the width, in pixels, of the game's window.
If no value is provided for the width, it defaults to 640.
.Parameter ResolutionHeight
This controls the height, in pixels, of the game's window.
If no value is provided for the height, it defaults to 480.
.Parameter HUDWidth
This controls the width, in pixels, that the game's HUD is bounded to.
If no value is provided for the HUD's width, it defaults to being no wider-than a 16:9 resolution of the same height as the game window's height.
.Parameter UseIntegral2DScaling
This controls whether or not integral scaling is used for 2D graphics.
When integral scaling is enabled 2D graphics will be upscaled by the largest integer multiplier that will fit the height of the screen. As an example, given a 1080p resolution: upscaling 480 to 1080 requires a scaling-factor of 2.25, which is not an integer, so when integral scaling is enabled 480 would be upscaled by a scaling-factor of 2, resulting in a height of 960.
Most full-screen 2D graphics will be letter-boxed if the graphic cannot fill the height of the screen due to the integral scaling. An exception to this is when Recet is manning the till, wherein the interface is rearranged slightly to make use of the additional space.
.Parameter MobDrawDistancePatchVariant
This controls how the draw-distance for mobs in dungeons is patched when the aspect-ratio is wider than 4:3.
When a mob in a dungeon goes off-screen (roughly speaking), the vanilla game stops simulating that mob entirely: it will not move, nor attack—it won't even animate.
There are three options for how the patch handles the draw-distance of mobs:
`OnlyVisual`: Will cause mobs to always be displayed after they have been first revealed, but the mobs will not be simulated outside of the game's vanilla draw-distance, as described earlier.
`Real`: Will cause mobs to always be displayed and simulated after they have been first revealed—this will make the game more difficult as mobs will chase the player-character from further away–this option is not intended to provide balanced gameplay.
`None`: Will cause mobs to simply disappear when they are out of the game's vanilla draw-distance.
.Parameter CameraSmoothingVariant
This controls how the game's camera smoothing is adapted to support frame-rates higher than 60 FPS.
There are two options for the camera smoothing variant:
`Interpolatedv2`: Aims to replicate the game's vanilla camera smoothing, but at a higher frame-rate.
`None`: Makes no changes to the game's camera smoothing, which generally results in choppy-looking motion.
.Parameter FloatInterpolation
This can be used to individually specify which floats should be interpolated for display at a frame-rate higher than 60 FPS.
Recettear's game logic is fixed at 60 FPS, so merely raising the frame-rate limit is not enough to achieve high frame-rate motion. To give the appearance of high frame-rate motion, this patch can interpolate specific floating-point values during the frames that get presented between each frame of game logic. (This is done in a way that has only a visual effect, the game logic is exactly the same as it is in the vanilla game.)
This parameter is used by supplying a HashTable-like object which is keyed by the name of an interpolated float, wherein the values are: `$True` to interpolate the float; `$False` to not interpolate the float; `'Recommended'` to use the patch's recommendation for the interpolated float.
If this parameter is not provided, the patch defaults to using the recommended value for each interpolated float.
The interpolated floats which can be configured can be found in the `ConfigurableInterpolatedFloats` member of this script's output when the `ReturnInformation` switch is present.
.Parameter TextureFiltering
This can be used to individually specify which texture-filtering algorithm is used to upscale a class of textures.
Much of Recettear's 2D art was designed for a resolution of 640x480, which is then, usually, upscaled using bilinear interpolation: causing the art to looking extremely blurry at high resolutions. To remedy this this patch allows the texture-filtering algorithms used for upscaling different classes of textures to be configured separately.
This parameter is used by supplying a HashTable-like object which is keyed by the name of a class of textures, wherein the values are: `$False` to make no change to the texture-filtering algorithm used for a class of textures; `'Recommended'` to use the patch's recommendation for the texture-filtering algorithm used for a class of textures; one of the following texture-filtering algorithm identifiers:
`NearestNeighbour`
`Bilinear`
`Anisotropic`
`FlatCubic`
`GaussianCubic`.
If this parameter is not provided, the patch defaults to using the recommended value for each texture-filtering algorithm used for a class of textures.
The classes of textures which can be configured can be found in the `ConfigurableTextureFilterings` member of this script's output when the `ReturnInformation` switch is present.
As it is not known which textures some of the classes of textures affect, they are named "Unknown" with a hexadecimal suffix.
In the future, these may be renamed to reflect the textures that they affect – if this happens, the original UnknownFF-style names will still be recognised for backwards-compatibility.
.Parameter HideChangeCameraControlReminder
This controls whether or not the "Change camera" button reminder is displayed in the bottom-right corner of the screen when in the shop.
.Parameter HideSkipEventControlReminder
This controls whether or not the "Skip event" button reminder is displayed in the bottom-right corner of the screen during an event or a cutscene.
.Parameter HideItemDetailsControlReminderWhenHaggling
This controls whether or not the "Item details" button reminder is displayed in the bottom-right corner of the screen when haggling with a customer.
.Parameter HideItemDetailsControlReminderInItemMenus
This controls whether or not the "Item details" button reminder is displayed in the bottom-right corner of the screen when browsing through an item menu.
.Parameter GameLanguageOverride
This is used to override the language that this script considers the version of Recettear being patched to be.
The Japanese version and English version of Recettear differ enough that this patch needs to handle them differently.
This patch will automatically detect the language of a Recettear installation via the hash of certain files, or through the game executable's version-info, or through the contents of the game's manual.
Usually this should determine the language of the game correctly, but if it does not, this parameter can be used to override it.
Use a value of `eng` for English, and `jpn` for Japanese.
.Parameter RestoreBackupAutomatically
This controls whether or not a previously-made backup of Recettear is automatically restored if the patching of the game fails, in non-interactive mode.
.Parameter ApplySupportedPatchAutomatically
This controls whether or not the game's official patch is downloaded and applied when the Steam version of the game is to be patched, or when the patching of the game fails, in non-interactive mode.
.Parameter Configuration
This is used to supply a base configuration for the parameters that control how the game is patched.
If no value is provided for this parameter it will be initialised from an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder, if present.
The values in the configuration object are used as-is for the parameters of this script.
Any parameters supplied when invoking this script will take precedence over the values in the configuration object.
The parameters that get used from the configuration object are: FramerateLimit; ResolutionWidth; ResolutionHeight; HUDWidth; UseIntegral2DScaling; MobDrawDistancePatchVariant; CameraSmoothingVariant; FloatInterpolation; TextureFiltering; HideChangeCameraControlReminder; HideSkipEventControlReminder; HideItemDetailsControlReminderWhenHaggling; HideItemDetailsControlReminderInItemMenus; SkipPatching; SkipPostPatchOperations; GetGameWindowMode; SetGameWindowMode; InstallDxWrapper; ConfigureDxWrapper; ResetDxWrapperConfiguration; CheckDxWrapperConfiguration; InstallDgVoodoo2; ConfigureDgVoodoo2; ResetDgVoodoo2Configuration; CheckDgVoodoo2Configuration; InstallSpecialK; ResetSpecialKConfiguration; ConfigureSpecialK; SetDirectXVersionToUse; GetDirectXVersionToUse; SetVerticalSyncEnabled; GetVerticalSyncEnabled; CheckSpecialKConfiguration; SaveSettingsToConfiguration; DoNotInstallThirdPartyToolsByDefaultNextTime.
.Parameter ReturnInformation
When this switch is present, this script will return an object with some information, and the game will not be patched, nor will any post-patch operations be carried out (the `SkipPatching` and `SkipPostPatchOperations` parameters will be treated as though they are `$True`).
Refer to the Outputs section of this documentation for information about how this parameter affects this script's output.
.Parameter SkipConfigurator
When this switch is present, the configurator that usually runs, in interactive mode, will be skipped.
.Parameter ConfiguratorPort
Specifies a port number that the configurator, in interactive mode, should listen on.
If this parameter is not provided, the configurator will listen on the first port that it can successfully listen on starting from port 49600.
If this parameter is provided, and the configuration cannot listen on it, the script will throw an exception.
.Parameter SkipPatching
This controls whether or not this script actually patches the game.
This can be used to perform only post-patch operations, for configuring the game/patch without patching it again.
.Parameter SkipPostPatchOperations
This controls whether or not this script performs post-patch operations.
This can be used to only patch the game, without affecting the game's configuration, or the state of any third-party tools.
The post-patch operations are controlled via the parameters documented after this parameter, until the `SaveSettingsToConfiguration` parameter.
.Parameter GetGameWindowMode
When this is `$True`, this script's output will detail the mode that the game's window is configured to use.
This is a post-patch operation.
.Parameter SetGameWindowMode
Specifies which mode the game's window should be configured to use.
There are four options for this:
`NoChange`: The game's window mode is not changed.
`FullScreen`: The game's window mode is changed to full-screen.
`Windowed`: The game's window mode is changed to windowed.
`BorderlessWindowed`: The game's window mode is changed to borderless-windowed.
This is a post-patch operation.
.Parameter InstallDxWrapper
Controls whether or not DxWrapper is installed. (https://github.com/elishacloud/dxwrapper).
If DxWrapper cannot be found in the game's installation folder, as `dxwrapper.zip`, it will be downloaded from the Internet (the file's SHA256 hash will be verified to ensure the file is safe to install). If DxWrapper is already installed it will be reinstalled, overwriting any existing files (a backup of the existing files will be made, however).
This is a post-patch operation.
.Parameter ConfigureDxWrapper
Controls whether or not DxWrapper will be configured to use the settings recommended by this patch.
If the `InstallDxWrapper` parameter or the `ResetDxWrapperConfiguration` parameter is `$True`, DxWrapper will be configured regardless of whether this parameter is `$True` or not.
This is a post-patch operation.
.Parameter ResetDxWrapperConfiguration
Controls whether or not DxWrapper's configuration is entirely reset – this is achieved by clearing the configuration file entirely.
This is a post-patch operation.
.Parameter CheckDxWrapperConfiguration
When this is `$True`, this script's output will detail the difference between the recommended settings and the configured settings for DxWrapper's configuration.
This is a post-patch operation.
.Parameter InstallDgVoodoo2
Controls whether or not dgVoodoo2 is installed. (http://dege.freeweb.hu/dgVoodoo2/).
If dgVoodoo2 cannot be found in the game's installation folder, as `dgVoodoo2.zip`, it will be downloaded from the Internet (the file's SHA256 hash will be verified to ensure the file is safe to install). If dgVoodoo2 is already installed it will be reinstalled, overwriting any existing files (a backup of the existing files will be made, however).
This is a post-patch operation.
.Parameter ConfigureDgVoodoo2
Controls whether or not dgVoodoo2 will be configured to use the settings recommended by this patch.
If the `InstallDgVoodoo2` parameter or the `ResetDgVoodoo2Configuration` parameter is `$True`, dgVoodoo2 will be configured regardless of whether this parameter is `$True` or not.
This is a post-patch operation.
.Parameter ResetDgVoodoo2Configuration
Controls whether or not dgVoodoo2's configuration is entirely reset – this is achieved by clearing the configuration file entirely.
This is a post-patch operation.
.Parameter CheckDgVoodoo2Configuration
When this is `$True`, this script's output will detail the difference between the recommended settings and the configured settings for dgVoodoo2's configuration.
This is a post-patch operation.
.Parameter InstallSpecialK
Controls whether or not Special K is installed. (https://special-k.info/).
If Special K cannot be found in the game's installation folder, as `SpecialK.zip`, it will be downloaded from the Internet (the file's SHA256 hash will be verified to ensure the file is safe to install). If Special K is already installed it will be reinstalled, overwriting any existing files (a backup of the existing files will be made, however).
This is a post-patch operation.
.Parameter ConfigureSpecialK
Controls whether or not Special K will be configured to use the settings recommended by this patch.
If the `InstallSpecialK` parameter or the `ResetSpecialKConfiguration` parameter is `$True`, Special K will be configured regardless of whether this parameter is `$True` or not.
This is a post-patch operation.
.Parameter ResetSpecialKConfiguration
Controls whether or not Special K's configuration is entirely reset – this is achieved by clearing the configuration file entirely.
This is a post-patch operation.
.Parameter CheckSpecialKConfiguration
When this is `$True`, this script's output will detail the difference between the recommended settings and the configured settings for Special K's configuration.
This is a post-patch operation.
.Parameter SetDirectXVersionToUse
This is used to change which version of DirectX is used by the game. Each DirectX version performs differently with regards to frame-pacing (especially when vertical-sync is enabled) and in their support for windowed/fullscreen mode.
DirectX 12 generally has the best results for frame-pacing, however it does not support fullscreen mode so borderless-windowed mode must be used instead.
If the game's resolution is configured to be the same as the monitor's resolution then DirectX 12 should be the first choice on machines that support DirectX 12, as it works well regardless of the vertical-sync setting, and has low-latency in borderless-windowed mode meaning the fast alt-tabbing of borderless-windowed mode can be availed of without the traditional drawbacks of borderless-windowed mode.
To be able to use DirectX 12, DxWrapper and dgVoodoo2 must be installed.
DirectX 9 has the next best results for frame-pacing, and it supports fullscreen mode, however it incurs additional latency when borderless-windowed mode is used.
If the game's resolution is configured to be smaller than the monitor's resolution and fullscreen is desired then DirectX 9 should be the first choice.
To be able to use DirectX 9, DxWrapper must be installed.
DirectX 11 is very sensitive when it comes to frame-pacing, especially when vertical-sync is enabled, but it does support fullscreen mode, and does not incur additional latency when borderless-windowed mode is used.
If vertical-sync is disabled, DirectX 11 may be worth a try if DirectX 9 does not satisfy, or for usage of borderless-windowed mode on machines that do not support DirectX 12.
To be able to use DirectX 11, DxWrapper and dgVoodoo2 must be installed.
DirectX 8.1 is the version of DirectX used by the vanilla game. It has little advantage over the other versions of DirectX 8.1 except for compatibility with very old hardware. Though, its usage does not require any third-party tools, so it can be useful for trouble-shooting.
When DirectX 9 or later is used, DxWrapper is used to convert the game's usage of DirextX 8.1 to DirectX 9 (DxWrapper in turn uses "d3d8to9" for the conversion).
When DirectX 11 or later is used, DxWrapper is still used, and dgVoodoo2 is used to convert the game's usage of DirectX 9 to DirectX 11 or 12.
When DirectX 8.1 is used, neither DxWrapper nor dgVoodoo2 are used.
There are five options for this:
`'NoChange'`: The DirectX version to use is not changed.
`12`: The DirectX version to use is changed to DirectX 12.
`9`: The DirectX version to use is changed to DirectX 9.
`11`: The DirectX version to use is changed to DirectX 11.
`8`: The DirectX version to use is changed to DirectX 8.1.
This is a post-patch operation.
.Parameter GetDirectXVersionToUse
When this is `$True`, this script's output will detail the version of DirectX that the game is configured to use.
This is a post-patch operation.
.Parameter SetVerticalSyncEnabled
This is used to change whether vertical-sync ("v-sync") is enabled or disabled.
There are three options for this:
`'NoChange'`: The vertical-sync setting is not changed.
`$False`: Vertical-sync is configured to be disabled.
`$True`: Vertical-sync is configured to be enabled.
This is a post-patch operation.
.Parameter GetVerticalSyncEnabled
When this is `$True`, this script's output will detail whether vertical-sync is configured to be enabled or disabled.
This is a post-patch operation.
.Parameter SaveSettingsToConfiguration
When this is `$True`, the configuration that the game is to be patched with is saved to an `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder.
In interactive mode, this defaults to `$True`. In non-interactive mode, this defaults to `$False`.
.Parameter DoNotInstallThirdPartyToolsByDefaultNextTime
When this is `$True`, the `InstallDxWrapper`, `InstallDgVoodoo2`, and `InstallSpecialK` parameters are treated as though they are `$False` when the configuration that the game is to be patched with is saved to the `Install-FancyScreenPatchForRecettear.config.json` file in the game's installation folder.
In interactive mode, this defaults to `$True`. In non-interactive mode, this defaults to `$False`.
.Parameter CheatEngineTablePath
Specifies a path to save a cheat-table for Cheat Engine to. Any existing files at this path will be overwritten.
The generated cheat-table is used mainly for debugging, but it does include one cheat (forcing Nagi to spawn regardless of the RNG roll for her spawning).
.Parameter InterpolatedFloatsToIncludeInCheatTable
Specifies a HashSet of strings of interpolated float names, the interpolated floats specified by this set are the interpolated floats that will be present in the cheat-table that is generated when the `CheatEngineTablePath` parameter is used.
#>
[CmdletBinding()]
Param (
[Parameter()]
[Switch] $NonInteractive,
[Parameter()]
$RecettearExecutablePath,
[Parameter()]
$DetectedInstallationPreference = ('ScriptRoot', 'CurrentDirectory', 'Steam', 'GOG'),
[Parameter()]
$BackupPath,
[Parameter()]
$ClobberedByRestoredBackupBackupPath,
[Parameter()]
$FramerateLimit,
[Parameter()]
$ResolutionWidth,
[Parameter()]
$ResolutionHeight,
[Parameter()]
$HUDWidth,
[Parameter()]
$UseIntegral2DScaling,
[Parameter()]
[ArgumentCompleter({'OnlyVisual', 'None', 'Real' | ForEach-Object {$_}})]
$MobDrawDistancePatchVariant,
[Parameter()]
[ArgumentCompleter({'InterpolatedV2', 'None' | ForEach-Object {$_}})]
$CameraSmoothingVariant,
[Parameter()]
$FloatInterpolation,
[Parameter()]
$TextureFiltering,
[Parameter()]
$HideChangeCameraControlReminder,
[Parameter()]
$HideSkipEventControlReminder,
[Parameter()]
$HideItemDetailsControlReminderWhenHaggling,
[Parameter()]
$HideItemDetailsControlReminderInItemMenus,
[Parameter()]
[ValidateSet('eng', 'jpn')]
[ArgumentCompleter({'eng', 'jpn' | ForEach-Object {$_}})]
$GameLanguageOverride,
[Parameter()]
[Switch] $RestoreBackupAutomatically = $True,
[Parameter()]
[Switch] $ApplySupportedPatchAutomatically = $True,
[Parameter()]
$Configuration,
[Parameter()]
[Switch] $ReturnInformation,
[Parameter()]
[Switch] $SkipConfigurator,
[Parameter()]
[UInt16] $ConfiguratorPort,
[Parameter()]
$SkipPatching,
[Parameter()]
$SkipPostPatchOperations,
[Parameter()]
$GetGameWindowMode,
[Parameter()]
[ArgumentCompleter({'NoChange', 'FullScreen', 'Windowed', 'BorderlessWindowed' | ForEach-Object {$_}})]
$SetGameWindowMode,
[Parameter()]
$InstallDxWrapper,
[Parameter()]
$ConfigureDxWrapper,
[Parameter()]
$ResetDxWrapperConfiguration,
[Parameter()]
$CheckDxWrapperConfiguration,
[Parameter()]
$InstallDgVoodoo2,
[Parameter()]
$ResetDgVoodoo2Configuration,
[Parameter()]
$ConfigureDgVoodoo2,
[Parameter()]
$CheckDgVoodoo2Configuration,
[Parameter()]
$InstallSpecialK,
[Parameter()]
$ResetSpecialKConfiguration,
[Parameter()]
$ConfigureSpecialK,
[Parameter()]
$CheckSpecialKConfiguration,
[Parameter()]
[ArgumentCompleter({12, 9, 11, 8, 'NoChange' | ForEach-Object {$_}})]
$SetDirectXVersionToUse,
[Parameter()]
$GetDirectXVersionToUse,
[Parameter()]
[ArgumentCompleter({'NoChange', $False, $True | ForEach-Object {$_}})]
$SetVerticalSyncEnabled,
[Parameter()]
$GetVerticalSyncEnabled,
[Parameter()]
$SaveSettingsToConfiguration,
[Parameter()]
$DoNotInstallThirdPartyToolsByDefaultNextTime,
[Parameter()]
$CheatEngineTablePath,
[Parameter()]
[ValidateNotNull()]
[AllowEmptyCollection()]
[Collections.Generic.HashSet[String]] $InterpolatedFloatsToIncludeInCheatTable = (
'PlayerCharacterPosition',
'RecetWhenInDungeonPosition',
'TearPosition',
'ShopperPosition',
'WindowShopperPosition',
'MobPosition',
'HUDSlideIn'
)
)
$StopWatch = [Diagnostics.Stopwatch]::StartNew()
if ($Null -eq $PSVersionTable -or ($PSVersionTable.PSVersion.Major -lt 5 -or ($PSVersionTable.PSVersion.Major -eq 5 -and $PSVersionTable.PSVersion.Minor -lt 1)))
{
Write-Error 'This script requires at-least version 5.1, or later, of PowerShell.'
exit 2
}
if ($Null -eq ([Management.Automation.PSTypeName] 'System.ValueTuple').Type)
{
Write-Error 'This script requires at-least version 4.7, or later, of .NET to be installed.'
exit 3
}
$ExtendedDebug = $False
$Verbose = $Null -ne (Write-Verbose ([String]::Empty) 4>&1)
$Debug = $Null -ne (Write-Debug ([String]::Empty) 5>&1)
if ($PSVersionTable.PSVersion.Major -le 5)
{
$IsWindows = $True
$ANSIEncoding = 'Default'
$Script:MaximumVariableCount = 32767
}
elseif ($PSVersionTable.PSVersion.Major -gt 7 -or ($PSVersionTable.PSVersion.Major -eq 7 -and $PSVersionTable.PSVersion.Minor -ge 4))
{
$ANSIEncoding = 'ANSI'
}
else
{
$ANSIEncoding = 'OEM'
}
$ScriptArgumentDepth = 3
$Variables = $ExecutionContext.SessionState.PSVariable
class FancyScreenPatchForRecettearException : Exception
{
[PSCustomObject] $Data
FancyScreenPatchForRecettearException ([String] $Message, [PSCustomObject] $Data) : base($Message)
{
$This.Data = $Data
}
}
class FancyScreenPatchForRecettearConfigurationException : FancyScreenPatchForRecettearException {FancyScreenPatchForRecettearConfigurationException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearOptionAlreadyConfiguredAsException : FancyScreenPatchForRecettearConfigurationException {FancyScreenPatchForRecettearOptionAlreadyConfiguredAsException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearNoInstallationFoundException : FancyScreenPatchForRecettearConfigurationException {FancyScreenPatchForRecettearNoInstallationFoundException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearConfiguratorException : FancyScreenPatchForRecettearException {FancyScreenPatchForRecettearConfiguratorException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearUnableToUseConfiguratorPortException : FancyScreenPatchForRecettearConfiguratorException {FancyScreenPatchForRecettearUnableToUseConfiguratorPortException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearPatchingException : FancyScreenPatchForRecettearException {FancyScreenPatchForRecettearPatchingException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearNoRecettearExecutableException : FancyScreenPatchForRecettearPatchingException {FancyScreenPatchForRecettearNoRecettearExecutableException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearTooFewUnusedExecutableSectionSlotsException : FancyScreenPatchForRecettearPatchingException {FancyScreenPatchForRecettearTooFewUnusedExecutableSectionSlotsException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearFailedToFindSectionException : FancyScreenPatchForRecettearPatchingException {FancyScreenPatchForRecettearFailedToFindSectionException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearFailedToFindCodeException : FancyScreenPatchForRecettearPatchingException {FancyScreenPatchForRecettearFailedToFindCodeException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearFailedToDetectLanguageException : FancyScreenPatchForRecettearPatchingException {FancyScreenPatchForRecettearFailedToDetectLanguageException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearBugException : FancyScreenPatchForRecettearException {FancyScreenPatchForRecettearBugException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
class FancyScreenPatchForRecettearFailedToDownloadFileException : FancyScreenPatchForRecettearException {FancyScreenPatchForRecettearFailedToDownloadFileException ([String] $Message, [PSCustomObject] $Data) : base($Message, $Data) {}}
function Coerce-Parameter ($Identifier, $Type, $TypeDescription)
{
$Value = $Variables.GetValue("Script:$Identifier")
if ($Null -ne $Value)
{
if (-not ($Value -as $Type -is $Type))
{
Write-Warning "The value for the `"$Identifier`" parameter is expected to be $TypeDescription. And thus, it is being ignored.",
$Variables.Set("Script:$Identifier", $Null)
}
else
{
$Variables.Set("Script:$Identifier", $Value -as $Type)
}
}
}
function Assert-MinimumValue ($Identifier, $Minimum)
{
$Value = $Variables.GetValue("Script:$Identifier")
if ($Null -ne $Value -and $Value -lt $Minimum)
{
Write-Warning "The value for the `"$Identifier`" parameter is expected to be at-least $Minimum. And thus, it is being ignored."
$Variables.Set("Script:$Identifier", $Null)
}
}
$RecognisedInstallationPreferences = ('ScriptRoot', 'CurrentDirectory', 'Steam', 'GOG')
$RecognisedMobDrawDistancePatchVariants = ('OnlyVisual', 'None', 'Real')
$RecognisedCameraSmoothingVariants = ('InterpolatedV2', 'None')
$RecognisedDirectXVersions = ('NoChange', 8, 9, 11, 12)
$RecognisedGameWindowModes = ('NoChange', 'BorderlessWindowed', 'FullScreen', 'Windowed')
$RecognisedVerticalSyncSettings = ('NoChange', $False, $True)
$GameFramerate = [UInt32] 60
$DefaultResolutionWidth = 640
$DefaultResolutionHeight = 480
$GameBaseWidth = 640.0
$GameBaseHeight = 480.0
$ConfigurableInterpolatedFloats = @(
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('PlayerCharacterPosition'); Recommendation = $Null; Synopsis = 'The position of the current player-character.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('RecetWhenInDungeonPosition'); Recommendation = $Null; Synopsis = 'The position of Recet, when dungeon crawling.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('TearPosition'); Recommendation = $Null; Synopsis = 'The position of Tear.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('ShopperPosition'); Recommendation = $Null; Synopsis = 'The positions of the NPCs that walk past the shop''s window.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('WindowShopperPosition'); Recommendation = $Null; Synopsis = 'The positions of NPCs that are walking around in the shop.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('MobPosition'); Recommendation = $Null; Synopsis = 'The positions of mobs when dungeon crawling.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('MirrorImageReflectionPosition'); Recommendation = $Null; Synopsis = 'The positions of the reflections that follow the player-character when the Mirror Image skill is used.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('AttackProjectilePosition'); Recommendation = $Null; Synopsis = 'The positions of projectiles originating from attacks.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('XPGemPosition'); Recommendation = $Null; Synopsis = 'The positions of XP-gems acquired from felling mobs.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('MovementParticlePosition'); Recommendation = $Null; Synopsis = 'The positions of particles that originate from the movement of characters.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('HUDSlideIn'); Recommendation = $Null; Synopsis = 'The sliding-around of various HUD elements during transitions.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('ShopTillEntryTransitionFloatMirror'); Recommendation = $Null; Synopsis = 'The sliding-around of various HUD elements when a customer comes to or leaves the till.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('ShopTillCustomerPositionFloatMirror'); Recommendation = $Null; Synopsis = 'The position of a customer as they enter or exit the screen when talking to Recet, in the shop.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('TearMenuTransitionCounterFloatMirror'); Recommendation = $Null; Synopsis = 'The sliding-around of the menus displayed when interacting with Tear, in the shop.'}}
[PSCustomObject] @{Metadata = [PSCustomObject] @{Names = [String[]] @('TearLectureButtonTransitionCounterFloatMirror'); Recommendation = $Null; Synopsis = 'The sliding-around of the menu buttons used for replaying Tear''s lectures, in the shop.'}}
)
$D3DTEXF_POINT = 1
$D3DTEXF_LINEAR = 2
$D3DTEXF_ANISOTROPIC = 3
$D3DTEXF_FLATCUBIC = 4
$D3DTEXF_GAUSSIANCUBIC = 5
$TextureFilteringAlgorithmLookup = @{
NearestNeighbour = $D3DTEXF_POINT
Bilinear = $D3DTEXF_LINEAR
Anisotropic = $D3DTEXF_ANISOTROPIC
FlatCubic = $D3DTEXF_FLATCUBIC
GaussianCubic = $D3DTEXF_GAUSSIANCUBIC
}
$TextureFilteringAlgorithmFriendlyNameMapping = [Ordered] @{
'Nearest Neighbour' = 'NearestNeighbour'
'Bilinear' = 'Bilinear'
'Anisotropic' = 'Anisotropic'
'Flat Cubic' = 'FlatCubic'
'Gaussian Cubic' = 'GaussianCubic'
}
$CameraSmoothingVariantFriendlyNameMapping = [Ordered] @{
'Interpolated v2' = 'InterpolatedV2'
'None' = 'None'
}
$ConfigurableTextureFilterings = @(
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[0]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('ShopItems'); Recommendation = $Null; Synopsis = 'Items in the shop.'}}
[PSCustomObject] @{PatchVariant = 'ShopShadows'; Metadata = [PSCustomObject] @{Names = [String[]] @('ShopShadows'); Recommendation = $Null; Synopsis = 'Shadows in the shop.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[1]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('HUDClock'); Recommendation = $Null; Synopsis = 'HUD clock.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[2]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('FPSOSD'); Recommendation = $Null; Synopsis = 'FPS OSD.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[3]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('SaveAndItemSlots'); Recommendation = $Null; Synopsis = 'Save slots and item icons.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[4]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Flora'); Recommendation = $Null; Synopsis = 'Flora?'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[5]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('MeshTextures'); Recommendation = $Null; Synopsis = 'Mesh textures.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[6]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('ChestTextures'); Recommendation = $Null; Synopsis = 'Chest textures?'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[7]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Other2DArt'); Recommendation = $Null; Synopsis = 'All other 2D art not covered by other options.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[8]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown00'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[9]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown01'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[10]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown02'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[11]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown03'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[12]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown04'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[13]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown05'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[14]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown06'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[15]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown07'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[16]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown08'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[17]'; PatchVariant = 'PushedImmediate'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown09'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[18]'; PatchVariant = 'WrapperCall'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown0A'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[19]'; PatchVariant = 'WrapperCall'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown0B'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[20]'; PatchVariant = 'WrapperCall'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown0C'); Recommendation = $Null; Synopsis = 'Unknown.'}}
[PSCustomObject] @{VirtualAddress = $Null; VirtualAddressSource = 'TextureFiltering[21]'; PatchVariant = 'WrapperCall'; Metadata = [PSCustomObject] @{Names = [String[]] @('Unknown0D'); Recommendation = $Null; Synopsis = 'Unknown.'}}
)
function Resolve-KeyedOptionConfiguration ($Parameter, $Object, $ConfigurableOptions, $ConfigurableOptionKey, $ValueKey, $RecognisedValues, [Switch] $IgnoreFalseValues, [Switch] $Final)
{
$ResolvedConfiguration = [Collections.Generic.Dictionary[String, HashTable]]::new()
if ($Null -ne $Object)
{
for ($Index = $ConfigurableOptions.Length; ($Index--) -gt 0;)
{
$ConfigurableOption = $ConfigurableOptions[$Index]
$AlreadyConfiguredAs = $Null
foreach ($Name in $ConfigurableOption.Metadata.Names)
{
$ConfigurationValue = $Object.$Name
if ($Null -eq $ConfigurationValue)
{
continue
}
if ($Null -ne $AlreadyConfiguredAs)
{
throw [FancyScreenPatchForRecettearOptionAlreadyConfiguredAsException]::new("The `"$Name`" option of `"$Parameter`" was already configured as `"$AlreadyConfiguredAs`".", [PSCustomObject] @{ProvidedName = $Name; AlreadyConfiguredAs = $AlreadyConfiguredAs})
}
$AlreadyConfiguredAs = $Name
if ($IgnoreFalseValues -and $ConfigurationValue -eq $False)
{
continue
}
if ('Recommended' -eq $ConfigurationValue)
{
if ($Final)
{
$ConfigurationValue = $ConfigurableOption.Metadata.Recommendation
}
}
elseif (-not $RecognisedValues.Contains($ConfigurationValue))
{
Write-Warning "An unrecognised value of `"$ConfigurationValue`" was supplied for `"$Name`" for `"$Parameter`". The recognised values are: $(($RecognisedValues | Sort-Object) -join '; ')."
continue
}
$ResolvedConfiguration[$ConfigurableOption.Metadata.Names[0]] = @{
$ValueKey = $ConfigurationValue
$ConfigurableOptionKey = $ConfigurableOption
}
}
}
}
else
{
for ($Index = $ConfigurableOptions.Length; ($Index--) -gt 0;)
{
$Filtering = $ConfigurableOptions[$Index]
$ResolvedConfiguration[$Filtering.Metadata.Names[0]] = @{
$ValueKey = $(if ($Final) {$Filtering.Metadata.Recommendation})
$ConfigurableOptionKey = $Filtering
}
}
}
$ResolvedConfiguration
}
function Resolve-InterpolatedFloatConfiguration ([Switch] $Final)
{
Resolve-KeyedOptionConfiguration FloatInterpolation $Script:FloatInterpolation $ConfigurableInterpolatedFloats ConfigurableInterpolatedFloat Enabled ([Collections.Generic.HashSet[Bool]] ($True, $False)) -Final:$Final
}
function Resolve-TextureFilteringConfiguration ([Switch] $Final)
{
Resolve-KeyedOptionConfiguration TextureFiltering $Script:TextureFiltering $ConfigurableTextureFilterings ConfigurableTextureFiltering Algorithm ([Collections.Generic.HashSet[String]] ($TextureFilteringAlgorithmLookup.Keys | % {$_})) -IgnoreFalseValues -Final:$Final
}
function Resolve-Configuration
{
[CmdletBinding()]
Param (
[Parameter()]
[Switch] $Final
)
$DefaultDirectXVersionToUse = 12
if ($Null -eq $Script:SetDirectXVersionToUse)
{
$Script:SetDirectXVersionToUse = $DefaultDirectXVersionToUse
}
elseif ($Null -eq $RecognisedDirectXVersions.Where({$_ -eq $Script:SetDirectXVersionToUse}, 'First')[0])
{
Write-Warning "DirectX version $Script:SetDirectXVersionToUse, specified by `"SetDirectXVersionToUse`", is unrecognised, and thus the default version of $DefaultDirectXVersionToUse is being used. The recognised DirectX versions are: $(($RecognisedDirectXVersions | Sort-Object) -join '; ')."
$Script:SetDirectXVersionToUse = $DefaultDirectXVersionToUse
}
$DefaultSetGameWindowMode = 'NoChange'
if ($Null -eq $Script:SetGameWindowMode)
{
$Script:SetGameWindowMode = $DefaultSetGameWindowMode
}
elseif ($Null -eq $RecognisedGameWindowModes.Where({$_ -eq $Script:SetGameWindowMode}, 'First')[0])
{
Write-Warning "The window-mode of `"$Script:SetGameWindowMode`" specified by `"SetGameWindowMode`" is unrecognised. Thus, the game's window-mode will not be changed. The recognised window-modes are: $(($RecognisedGameWindowModes | Sort-Object) -join '; ')."
$Script:SetGameWindowMode = $DefaultSetGameWindowMode
}
$DefaultSetVerticalSyncEnabled = 'NoChange'
if ($Null -eq $Script:SetVerticalSyncEnabled)
{
$Script:SetVerticalSyncEnabled = $DefaultSetVerticalSyncEnabled
}
if ($Null -eq $RecognisedVerticalSyncSettings.Where({$_ -eq $Script:SetVerticalSyncEnabled}, 'First')[0])
{
Write-Warning "The setting of `"$Script:SetVerticalSyncEnabled`" specified by `"SetVerticalSyncEnabled`" is unrecognised. Thus, the game's vertical-sync setting will not be changed. The recognised vertical-sync settings are: $(($RecognisedVerticalSyncSettings | Sort-Object) -join '; ')."
$Script:SetVerticalSyncEnabled = $DefaultSetVerticalSyncEnabled
}
if ($Final)
{
Coerce-Parameter RecettearExecutablePath ([String]) 'a string of text'
Coerce-Parameter BackupPath ([String]) 'a string of text'
Coerce-Parameter ClobberedByRestoredBackupBackupPath ([String]) 'a string of text'
Coerce-Parameter FramerateLimit ([UInt32]) 'a 32-bit unsigned integer'
Coerce-Parameter ResolutionWidth ([UInt32]) 'a 32-bit unsigned integer'
Coerce-Parameter ResolutionHeight ([UInt32]) 'a 32-bit unsigned integer'
Coerce-Parameter HUDWidth ([UInt32]) 'a 32-bit unsigned integer'
Coerce-Parameter UseIntegral2DScaling ([Bool]) 'true or false'
Coerce-Parameter MobDrawDistancePatchVariant ([String]) 'a string of text'
Coerce-Parameter CheatEngineTablePath ([String]) 'a string of text'
Coerce-Parameter HideChangeCameraControlReminder ([Bool]) 'true or false'
Coerce-Parameter HideSkipEventControlReminder ([Bool]) 'true or false'
Coerce-Parameter HideItemDetailsControlReminderWhenHaggling ([Bool]) 'true or false'
Coerce-Parameter HideItemDetailsControlReminderInItemMenus ([Bool]) 'true or false'
Coerce-Parameter SkipPatching ([Bool]) 'true or false'
Coerce-Parameter SkipPostPatchOperations ([Bool]) 'true or false'
Coerce-Parameter GetGameWindowMode ([Bool]) 'true or false'
Coerce-Parameter SetGameWindowMode ([String]) 'a string of text'
Coerce-Parameter InstallDxWrapper ([Bool]) 'true or false'
Coerce-Parameter ConfigureDxWrapper ([Bool]) 'true or false'
Coerce-Parameter ResetDxWrapperConfiguration ([Bool]) 'true or false'
Coerce-Parameter CheckDxWrapperConfiguration ([Bool]) 'true or false'
Coerce-Parameter InstallDgVoodoo2 ([Bool]) 'true or false'
Coerce-Parameter ResetDgVoodoo2Configuration ([Bool]) 'true or false'
Coerce-Parameter ConfigureDgVoodoo2 ([Bool]) 'true or false'
Coerce-Parameter CheckDgVoodoo2Configuration ([Bool]) 'true or false'
Coerce-Parameter InstallSpecialK ([Bool]) 'true or false'
Coerce-Parameter ResetSpecialKConfiguration ([Bool]) 'true or false'
Coerce-Parameter ConfigureSpecialK ([Bool]) 'true or false'
Coerce-Parameter CheckSpecialKConfiguration ([Bool]) 'true or false'
Coerce-Parameter GetDirectXVersionToUse ([Bool]) 'true or false'
Coerce-Parameter GetVerticalSyncEnabled ([Bool]) 'true or false'
Coerce-Parameter SaveSettingsToConfiguration ([Bool]) 'true or false'
Coerce-Parameter DoNotInstallThirdPartyToolsByDefaultNextTime ([Bool]) 'true or false'
Assert-MinimumValue FramerateLimit ([UInt32] 60)
Assert-MinimumValue ResolutionWidth ([UInt32] 1)
Assert-MinimumValue ResolutionHeight ([UInt32] 1)