mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 02:44:17 +00:00
Initial Web Menu Implementation (#170)
* initial commit with some nice css * add beginnings of templating. revert to qa model * add most options visually * add parser and full input checks * separate menu code, use ControlModule * add tests for menu rendering locally * wip sliders * add AttackAngle * remove tesla overlay * begin with into_string * add slider.js * don't use in html yet Co-authored-by: jugeeya <jugeeya@llive.com>
This commit is contained in:
parent
049232c420
commit
1a273f7cbf
33 changed files with 867 additions and 2537 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,4 +1 @@
|
||||||
|
|
||||||
[submodule "TrainingModpackOverlay/libs/libtesla"]
|
|
||||||
path = TrainingModpackOverlay/libs/libtesla
|
|
||||||
url = https://github.com/WerWolv/libtesla
|
|
||||||
|
|
|
@ -10,10 +10,17 @@ crate-type = ["cdylib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" }
|
skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" }
|
||||||
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git" }
|
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git" }
|
||||||
|
skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" }
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
parking_lot = { version = "0.11.0", features = ["nightly"] }
|
parking_lot = { version = "0.11.0", features = ["nightly"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
owo-colors = "1.1.3"
|
owo-colors = "1.1.3"
|
||||||
|
ramhorns = "0.10.1"
|
||||||
|
paste = "1.0"
|
||||||
|
num = "0.3.0"
|
||||||
|
num-derive = "0.3"
|
||||||
|
num-traits = "0.2"
|
||||||
|
wsl = "0.1.0"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
---
|
|
||||||
AccessModifierOffset: '-4'
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignConsecutiveAssignments: 'true'
|
|
||||||
AlignConsecutiveDeclarations: 'true'
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AlignOperands: 'true'
|
|
||||||
AlignTrailingComments: 'true'
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
|
||||||
AllowShortBlocksOnASingleLine: 'false'
|
|
||||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
|
||||||
AllowShortIfStatementsOnASingleLine: 'true'
|
|
||||||
AllowShortLoopsOnASingleLine: 'true'
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: 'true'
|
|
||||||
AlwaysBreakTemplateDeclarations: 'false'
|
|
||||||
BinPackArguments: 'false'
|
|
||||||
BinPackParameters: 'false'
|
|
||||||
BreakBeforeBinaryOperators: NonAssignment
|
|
||||||
BreakBeforeBraces: Custom
|
|
||||||
BraceWrapping:
|
|
||||||
AfterClass: 'true'
|
|
||||||
AfterControlStatement: 'true'
|
|
||||||
AfterEnum: 'true'
|
|
||||||
AfterFunction: 'true'
|
|
||||||
AfterNamespace: 'true'
|
|
||||||
AfterStruct: 'true'
|
|
||||||
AfterUnion: 'true'
|
|
||||||
AfterExternBlock: 'true'
|
|
||||||
BeforeCatch: 'true'
|
|
||||||
BeforeElse: 'true'
|
|
||||||
SplitEmptyFunction: 'false'
|
|
||||||
SplitEmptyRecord: 'false'
|
|
||||||
SplitEmptyNamespace: 'false'
|
|
||||||
BreakBeforeTernaryOperators: 'true'
|
|
||||||
BreakConstructorInitializers: BeforeComma
|
|
||||||
BreakStringLiterals: 'false'
|
|
||||||
ColumnLimit: '128'
|
|
||||||
CompactNamespaces: 'false'
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
|
||||||
Cpp11BracedListStyle: 'true'
|
|
||||||
FixNamespaceComments: 'true'
|
|
||||||
IncludeBlocks: Regroup
|
|
||||||
IndentCaseLabels: 'false'
|
|
||||||
IndentPPDirectives: AfterHash
|
|
||||||
IndentWidth: '4'
|
|
||||||
IndentWrappedFunctionNames: 'true'
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
|
||||||
Language: Cpp
|
|
||||||
MaxEmptyLinesToKeep: '1'
|
|
||||||
PointerAlignment: Left
|
|
||||||
ReflowComments: 'true'
|
|
||||||
SortIncludes: 'false'
|
|
||||||
SortUsingDeclarations: 'false'
|
|
||||||
SpaceAfterCStyleCast: 'false'
|
|
||||||
SpaceAfterTemplateKeyword: 'false'
|
|
||||||
SpaceBeforeAssignmentOperators: 'true'
|
|
||||||
SpaceBeforeParens: Never
|
|
||||||
SpaceInEmptyParentheses: 'false'
|
|
||||||
SpacesInAngles: 'false'
|
|
||||||
SpacesInCStyleCastParentheses: 'false'
|
|
||||||
SpacesInContainerLiterals: 'false'
|
|
||||||
SpacesInParentheses: 'false'
|
|
||||||
SpacesInSquareBrackets: 'false'
|
|
||||||
Standard: Cpp11
|
|
||||||
TabWidth: '4'
|
|
||||||
UseTab: ForIndentation
|
|
||||||
|
|
||||||
...
|
|
5
TrainingModpackOverlay/.github/FUNDING.yml
vendored
5
TrainingModpackOverlay/.github/FUNDING.yml
vendored
|
@ -1,5 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
patreon: werwolv
|
|
||||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KP7XRJAND9KWU&source=url
|
|
||||||
github: WerWolv
|
|
|
@ -1,50 +0,0 @@
|
||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "DKP Aarch64 Windows",
|
|
||||||
"includePath": [
|
|
||||||
"C:/devkitPro/devkitA64/aarch64-none-elf/include/**",
|
|
||||||
"C:/devkitPro/devkitA64/lib/gcc/aarch64-none-elf/10.1.0/include/**",
|
|
||||||
"C:/devkitPro/libnx/include/**",
|
|
||||||
"C:/devkitPro/portlibs/switch/include/**",
|
|
||||||
"C:/devkitPro/portlibs/switch/include/freetype2/**",
|
|
||||||
"${workspaceFolder}/include/**",
|
|
||||||
"${workspaceFolder}/libs/libtesla/include/**"
|
|
||||||
],
|
|
||||||
"defines": [
|
|
||||||
"SWITCH",
|
|
||||||
"__SWITCH__",
|
|
||||||
"__aarch64__",
|
|
||||||
"VERSION=\"\""
|
|
||||||
],
|
|
||||||
"compilerPath": "C:/devkitPro/devkitA64/bin/aarch64-none-elf-g++",
|
|
||||||
"cStandard": "c11",
|
|
||||||
"cppStandard": "c++17",
|
|
||||||
"intelliSenseMode": "gcc-x64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DKP Aarch64 Linux",
|
|
||||||
"includePath": [
|
|
||||||
"/opt/devkitpro/devkitA64/aarch64-none-elf/include/**",
|
|
||||||
"/opt/devkitpro/devkitA64/lib/gcc/aarch64-none-elf/8.3.0/include/**",
|
|
||||||
"/opt/devkitpro/libnx/include/**",
|
|
||||||
"/opt/devkitpro/portlibs/switch/include/**",
|
|
||||||
"/opt/devkitpro/portlibs/switch/include/**",
|
|
||||||
"/opt/devkitpro/portlibs/switch/include/freetype2/**",
|
|
||||||
"${workspaceFolder}/include/**",
|
|
||||||
"${workspaceFolder}/libs/libtesla/include/**"
|
|
||||||
],
|
|
||||||
"defines": [
|
|
||||||
"SWITCH",
|
|
||||||
"__SWITCH__",
|
|
||||||
"__aarch64__",
|
|
||||||
"VERSION=\"\""
|
|
||||||
],
|
|
||||||
"compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-g++",
|
|
||||||
"cStandard": "c11",
|
|
||||||
"cppStandard": "c++17",
|
|
||||||
"intelliSenseMode": "gcc-x64"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": 4
|
|
||||||
}
|
|
61
TrainingModpackOverlay/.vscode/settings.json
vendored
61
TrainingModpackOverlay/.vscode/settings.json
vendored
|
@ -1,61 +0,0 @@
|
||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"chrono": "cpp",
|
|
||||||
"string_view": "cpp",
|
|
||||||
"array": "cpp",
|
|
||||||
"atomic": "cpp",
|
|
||||||
"bit": "cpp",
|
|
||||||
"*.tcc": "cpp",
|
|
||||||
"cctype": "cpp",
|
|
||||||
"clocale": "cpp",
|
|
||||||
"cmath": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
|
||||||
"cstddef": "cpp",
|
|
||||||
"cstdint": "cpp",
|
|
||||||
"cstdio": "cpp",
|
|
||||||
"cstdlib": "cpp",
|
|
||||||
"cstring": "cpp",
|
|
||||||
"ctime": "cpp",
|
|
||||||
"cwchar": "cpp",
|
|
||||||
"cwctype": "cpp",
|
|
||||||
"deque": "cpp",
|
|
||||||
"unordered_map": "cpp",
|
|
||||||
"vector": "cpp",
|
|
||||||
"exception": "cpp",
|
|
||||||
"algorithm": "cpp",
|
|
||||||
"functional": "cpp",
|
|
||||||
"iterator": "cpp",
|
|
||||||
"memory": "cpp",
|
|
||||||
"memory_resource": "cpp",
|
|
||||||
"numeric": "cpp",
|
|
||||||
"optional": "cpp",
|
|
||||||
"random": "cpp",
|
|
||||||
"ratio": "cpp",
|
|
||||||
"string": "cpp",
|
|
||||||
"system_error": "cpp",
|
|
||||||
"tuple": "cpp",
|
|
||||||
"type_traits": "cpp",
|
|
||||||
"utility": "cpp",
|
|
||||||
"fstream": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
|
||||||
"iosfwd": "cpp",
|
|
||||||
"istream": "cpp",
|
|
||||||
"limits": "cpp",
|
|
||||||
"new": "cpp",
|
|
||||||
"ostream": "cpp",
|
|
||||||
"sstream": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
|
||||||
"streambuf": "cpp",
|
|
||||||
"thread": "cpp",
|
|
||||||
"cinttypes": "cpp",
|
|
||||||
"typeinfo": "cpp",
|
|
||||||
"codecvt": "cpp",
|
|
||||||
"condition_variable": "cpp",
|
|
||||||
"iomanip": "cpp",
|
|
||||||
"mutex": "cpp",
|
|
||||||
"forward_list": "cpp",
|
|
||||||
"list": "cpp",
|
|
||||||
"map": "cpp",
|
|
||||||
"valarray": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,339 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
|
@ -1,212 +0,0 @@
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITPRO)),)
|
|
||||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
|
||||||
endif
|
|
||||||
|
|
||||||
TOPDIR ?= $(CURDIR)
|
|
||||||
include $(DEVKITPRO)/libnx/switch_rules
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# TARGET is the name of the output
|
|
||||||
# BUILD is the directory where object files & intermediate files will be placed
|
|
||||||
# SOURCES is a list of directories containing source code
|
|
||||||
# DATA is a list of directories containing data files
|
|
||||||
# INCLUDES is a list of directories containing header files
|
|
||||||
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
|
||||||
#
|
|
||||||
# NO_ICON: if set to anything, do not use icon.
|
|
||||||
# NO_NACP: if set to anything, no .nacp file is generated.
|
|
||||||
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
|
||||||
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
|
||||||
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
|
||||||
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
|
||||||
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
|
||||||
# If not set, it attempts to use one of the following (in this order):
|
|
||||||
# - <Project name>.jpg
|
|
||||||
# - icon.jpg
|
|
||||||
# - <libnx folder>/default_icon.jpg
|
|
||||||
#
|
|
||||||
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
|
||||||
# If not set, it attempts to use one of the following (in this order):
|
|
||||||
# - <Project name>.json
|
|
||||||
# - config.json
|
|
||||||
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
|
||||||
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
|
||||||
# NACP building is skipped as well.
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
APP_TITLE := Training Modpack
|
|
||||||
APP_VERSION := 2.6
|
|
||||||
|
|
||||||
TARGET := ovlTrainingModpack
|
|
||||||
BUILD := build
|
|
||||||
SOURCES := source
|
|
||||||
DATA := data
|
|
||||||
INCLUDES := include libs/libtesla/include
|
|
||||||
|
|
||||||
ifeq ($(RELEASE),)
|
|
||||||
APP_VERSION := $(APP_VERSION)
|
|
||||||
endif
|
|
||||||
|
|
||||||
NO_ICON := 1
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# options for code generation
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
|
||||||
|
|
||||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
|
||||||
$(ARCH) $(DEFINES)
|
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -DVERSION=\"v$(APP_VERSION)\"
|
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=c++17
|
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
|
||||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
|
||||||
|
|
||||||
LIBS := -lnx
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# list of directories containing libraries, this must be the top level containing
|
|
||||||
# include and lib
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# no real need to edit anything past this point unless you need to add additional
|
|
||||||
# rules for different file extensions
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
|
||||||
export TOPDIR := $(CURDIR)
|
|
||||||
|
|
||||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
|
||||||
|
|
||||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(CPPFILES)),)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CC)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CXX)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
|
||||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
|
||||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
|
||||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
|
||||||
|
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
|
||||||
-I$(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
|
||||||
|
|
||||||
ifeq ($(strip $(CONFIG_JSON)),)
|
|
||||||
jsons := $(wildcard *.json)
|
|
||||||
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
|
||||||
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
|
||||||
else
|
|
||||||
ifneq (,$(findstring config.json,$(jsons)))
|
|
||||||
export APP_JSON := $(TOPDIR)/config.json
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(strip $(ICON)),)
|
|
||||||
icons := $(wildcard *.jpg)
|
|
||||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
|
||||||
else
|
|
||||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(strip $(NO_ICON)),)
|
|
||||||
export NROFLAGS += --icon=$(APP_ICON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(strip $(NO_NACP)),)
|
|
||||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(APP_TITLEID),)
|
|
||||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(ROMFS),)
|
|
||||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all: $(BUILD)
|
|
||||||
|
|
||||||
|
|
||||||
$(BUILD):
|
|
||||||
@[ -d $@ ] || mkdir -p $@
|
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
clean:
|
|
||||||
@rm -fr $(BUILD) $(TARGET).ovl $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
.PHONY: all
|
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# main targets
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all : $(OUTPUT).ovl
|
|
||||||
|
|
||||||
$(OUTPUT).ovl : $(OUTPUT).elf $(OUTPUT).nacp
|
|
||||||
@elf2nro $< $@ $(NROFLAGS)
|
|
||||||
@echo "built ... $(notdir $(OUTPUT).ovl)"
|
|
||||||
|
|
||||||
$(OUTPUT).elf : $(OFILES)
|
|
||||||
|
|
||||||
$(OFILES_SRC) : $(HFILES_BIN)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# you need a rule like this for each extension you use as binary data
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
%.bin.o %_bin.h : %.bin
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
@echo $(notdir $<)
|
|
||||||
@$(bin2o)
|
|
||||||
|
|
||||||
-include $(DEPENDS)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
|
@ -1,7 +0,0 @@
|
||||||
# ovlSysmodule
|
|
||||||
|
|
||||||
A Tesla overlay that allows you to toggle sysmodules on the fly
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Download the latest ovlSysmodules.ovl from the release page and drop it into the /switch/.overlays folder on your Switch's SD card
|
|
|
@ -1,81 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <tesla.hpp>
|
|
||||||
|
|
||||||
class ClickableListItem : public tsl::elm::ListItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClickableListItem(std::string text,
|
|
||||||
const std::vector<std::string> values,
|
|
||||||
int* defaultPos,
|
|
||||||
const std::string data,
|
|
||||||
int index,
|
|
||||||
std::string title,
|
|
||||||
std::string help)
|
|
||||||
: tsl::elm::ListItem(text), m_values(values), m_curValue(defaultPos), extdata(data), title(title), help(help)
|
|
||||||
{
|
|
||||||
this->index = index;
|
|
||||||
this->setValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
~ClickableListItem() {}
|
|
||||||
|
|
||||||
tsl::elm::Element* requestFocus(Element* oldFocus, tsl::FocusDirection direction)
|
|
||||||
{
|
|
||||||
return ListItem::requestFocus(oldFocus, direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
void layout(u16 parentX, u16 parentY, u16 parentWidth, u16 parentHeight)
|
|
||||||
{
|
|
||||||
ListItem::layout(parentX, parentY, parentWidth, parentHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onClick(u64 keys)
|
|
||||||
{
|
|
||||||
if(keys & KEY_Y)
|
|
||||||
{
|
|
||||||
if(this->m_helpListener != nullptr)
|
|
||||||
{
|
|
||||||
this->m_helpListener(this->title, this->help);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(keys & KEY_A)
|
|
||||||
{
|
|
||||||
if(this->m_clickListener != nullptr)
|
|
||||||
{
|
|
||||||
this->m_clickListener(this->m_values, this->m_curValue, this->extdata, this->index, this->title, this->help);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getCurValue() { return *(this->m_curValue); }
|
|
||||||
void setCurValue(int value) { *(this->m_curValue) = value; }
|
|
||||||
|
|
||||||
const std::string getExtData() { return this->extdata; }
|
|
||||||
|
|
||||||
const std::vector<std::string> getValues() { return this->m_values; }
|
|
||||||
|
|
||||||
void setClickListener(
|
|
||||||
std::function<void(const std::vector<std::string>, int*, std::string, int index, std::string title, std::string help)>
|
|
||||||
clickListener)
|
|
||||||
{
|
|
||||||
this->m_clickListener = clickListener;
|
|
||||||
}
|
|
||||||
void setHelpListener(std::function<void(std::string, std::string)> helpListener) { this->m_helpListener = helpListener; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::vector<std::string> m_values;
|
|
||||||
int* m_curValue;
|
|
||||||
std::function<void(const std::vector<std::string>, int*, std::string, int, std::string, std::string)> m_clickListener =
|
|
||||||
nullptr;
|
|
||||||
std::function<void(std::string, std::string)> m_helpListener = nullptr;
|
|
||||||
const std::string extdata;
|
|
||||||
const std::string title;
|
|
||||||
const std::string help;
|
|
||||||
int index;
|
|
||||||
};
|
|
|
@ -1,159 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template<class T, typename U = uint32_t> struct BitFlags
|
|
||||||
{
|
|
||||||
using UnderlyingType = U;
|
|
||||||
using Type = T;
|
|
||||||
|
|
||||||
constexpr static const UnderlyingType s_validMask = (UnderlyingType{1u << *Type::Count} - UnderlyingType{1});
|
|
||||||
|
|
||||||
struct NoneType
|
|
||||||
{};
|
|
||||||
struct AllType
|
|
||||||
{};
|
|
||||||
|
|
||||||
UnderlyingType m_bits;
|
|
||||||
|
|
||||||
constexpr static const AllType All{};
|
|
||||||
constexpr static const NoneType None{};
|
|
||||||
|
|
||||||
BitFlags() = default;
|
|
||||||
BitFlags(const BitFlags&) = default;
|
|
||||||
|
|
||||||
constexpr BitFlags(NoneType) : m_bits(0) {}
|
|
||||||
constexpr BitFlags(AllType) : m_bits(s_validMask) {}
|
|
||||||
constexpr explicit BitFlags(UnderlyingType t) : m_bits(s_validMask & t) {}
|
|
||||||
|
|
||||||
BitFlags& operator=(const BitFlags&) = default;
|
|
||||||
~BitFlags() = default;
|
|
||||||
|
|
||||||
constexpr BitFlags(Type t) : m_bits{UnderlyingType{1} << static_cast<std::underlying_type_t<Type>>(t)} {}
|
|
||||||
|
|
||||||
constexpr BitFlags& operator|=(BitFlags rhs)
|
|
||||||
{
|
|
||||||
m_bits |= rhs.m_bits;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
constexpr BitFlags& operator&=(BitFlags rhs)
|
|
||||||
{
|
|
||||||
m_bits &= rhs.m_bits;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
constexpr BitFlags& operator-=(BitFlags rhs)
|
|
||||||
{
|
|
||||||
m_bits &= ~rhs.m_bits;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const { return m_bits != 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator|(BitFlags<T, U> lhs, BitFlags<T, U> rhs)
|
|
||||||
{
|
|
||||||
lhs |= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator&(BitFlags<T, U> lhs, BitFlags<T, U> rhs)
|
|
||||||
{
|
|
||||||
lhs &= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator-(BitFlags<T, U> lhs, BitFlags<T, U> rhs)
|
|
||||||
{
|
|
||||||
lhs -= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator-(BitFlags<T, U> lhs, T rhs)
|
|
||||||
{
|
|
||||||
lhs -= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator-(T lhs, BitFlags<T, U> rhs)
|
|
||||||
{
|
|
||||||
rhs -= lhs;
|
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator|(BitFlags<T, U> lhs, T rhs)
|
|
||||||
{
|
|
||||||
lhs |= rhs;
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr BitFlags<T, U> operator|(T lhs, BitFlags<T, U> rhs)
|
|
||||||
{
|
|
||||||
rhs |= lhs;
|
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr bool operator&(BitFlags<T, U> lhs, T rhs)
|
|
||||||
{
|
|
||||||
lhs &= rhs;
|
|
||||||
return lhs.m_bits != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U> constexpr bool operator&(T lhs, BitFlags<T, U> rhs)
|
|
||||||
{
|
|
||||||
rhs &= lhs;
|
|
||||||
return rhs.m_bits != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> struct FlagType;
|
|
||||||
|
|
||||||
template<typename T> using FlagTypeT = typename FlagType<T>::Type;
|
|
||||||
|
|
||||||
template<class T> struct EnumArray;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
#define DEFINE_FLAGS_UT(TypeName, UnderlyingType) \
|
|
||||||
using TypeName##s = detail::BitFlags<TypeName, UnderlyingType>; \
|
|
||||||
constexpr TypeName##s operator|(TypeName lhs, TypeName rhs) { return TypeName##s{lhs} | TypeName##s{rhs}; } \
|
|
||||||
namespace detail \
|
|
||||||
{ \
|
|
||||||
template<> struct FlagType<TypeName> \
|
|
||||||
{ \
|
|
||||||
using Type = TypeName##s; \
|
|
||||||
}; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEFINE_FLAGS(TypeName) DEFINE_FLAGS_UT(TypeName, uint32_t)
|
|
||||||
#define ENUM_X(type, e, y) e,
|
|
||||||
#define ENUM_QUAL_X(type, e, y) type::e,
|
|
||||||
#define ENUM_NAME_PAIR(type, e, y) {type::e, y},
|
|
||||||
#define CASE_X(type, e, y) \
|
|
||||||
case type::e: \
|
|
||||||
return y;
|
|
||||||
#define DEFINE_ENUM_CLASS_TYPE(Name, Type) \
|
|
||||||
enum class Name : Type \
|
|
||||||
{ \
|
|
||||||
ENUM_CLASS_##Name(Name, ENUM_X) Count \
|
|
||||||
}; \
|
|
||||||
constexpr auto operator*(Name t) { return static_cast<std::underlying_type_t<Name>>(t); } \
|
|
||||||
namespace detail \
|
|
||||||
{ \
|
|
||||||
template<> struct EnumArray<Name> \
|
|
||||||
{ \
|
|
||||||
constexpr static const std::array<std::pair<Name, const char*>, *Name::Count> values{ \
|
|
||||||
{ENUM_CLASS_##Name(Name, ENUM_NAME_PAIR)}}; \
|
|
||||||
}; \
|
|
||||||
} \
|
|
||||||
constexpr const char* toString(Name t) \
|
|
||||||
{ \
|
|
||||||
if(t < Name::Count) \
|
|
||||||
{ \
|
|
||||||
return detail::EnumArray<Name>::values[*t].second; \
|
|
||||||
} \
|
|
||||||
return "UNKNWON"; \
|
|
||||||
} \
|
|
||||||
DEFINE_FLAGS_UT(Name, Type)
|
|
||||||
#define DEFINE_ENUM_CLASS(Name) DEFINE_ENUM_CLASS_TYPE(Name, uint32_t)
|
|
|
@ -1,38 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <tesla.hpp>
|
|
||||||
|
|
||||||
static char help_text_global[1024];
|
|
||||||
|
|
||||||
class GuiHelp : public tsl::Gui
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GuiHelp(std::string title, std::string help) : m_title(std::move(title)), m_help(std::move(help)) {}
|
|
||||||
|
|
||||||
virtual tsl::elm::Element* createUI() override
|
|
||||||
{
|
|
||||||
auto rootFrame = new tsl::elm::OverlayFrame(m_title, "Help");
|
|
||||||
|
|
||||||
snprintf(help_text_global, sizeof help_text_global, "%s", m_help.c_str());
|
|
||||||
|
|
||||||
auto help_text = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
||||||
renderer->drawString(help_text_global, false, 45, 125, 20, renderer->a(0xFFFF));
|
|
||||||
});
|
|
||||||
|
|
||||||
rootFrame->setContent(help_text);
|
|
||||||
|
|
||||||
return rootFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update() override {}
|
|
||||||
virtual bool handleInput(u64 keysDown,
|
|
||||||
u64 keysHeld,
|
|
||||||
touchPosition touchInput,
|
|
||||||
JoystickPosition leftJoyStick,
|
|
||||||
JoystickPosition rightJoyStick) override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string m_title;
|
|
||||||
std::string m_help;
|
|
||||||
};
|
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <tesla.hpp>
|
|
||||||
#include "value_list_item.hpp"
|
|
||||||
|
|
||||||
class GuiMain : public tsl::Gui
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
FsFileSystem m_fs;
|
|
||||||
tsl::elm::ToggleListItem* toggleItem = nullptr;
|
|
||||||
std::vector<ValueListItem*> valueListItems;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GuiMain();
|
|
||||||
~GuiMain();
|
|
||||||
|
|
||||||
virtual tsl::elm::Element* createUI();
|
|
||||||
virtual void update() override;
|
|
||||||
void applyChanges();
|
|
||||||
};
|
|
|
@ -1,43 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <tesla.hpp>
|
|
||||||
#include "clickable_list_item.hpp"
|
|
||||||
|
|
||||||
class GuiSublist : public tsl::Gui
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::vector<tsl::elm::ListItem*> listItems;
|
|
||||||
std::vector<std::string> menuItems;
|
|
||||||
int* index;
|
|
||||||
std::string extData;
|
|
||||||
std::string title;
|
|
||||||
std::string help;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GuiSublist(std::vector<std::string> menuItems, int* index, std::string extData, std::string title, std::string help);
|
|
||||||
~GuiSublist();
|
|
||||||
|
|
||||||
virtual tsl::elm::Element* createUI();
|
|
||||||
virtual void update() override;
|
|
||||||
void applyChanges();
|
|
||||||
virtual void setClickListener(ClickableListItem* item);
|
|
||||||
};
|
|
||||||
|
|
||||||
class GuiLambda : public tsl::Gui
|
|
||||||
{
|
|
||||||
std::function<tsl::elm::Element*()> m_createUI;
|
|
||||||
tsl::Gui* m_guiMain;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual tsl::elm::Element* createUI() override
|
|
||||||
{
|
|
||||||
if(m_createUI) return m_createUI();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
virtual void update() override
|
|
||||||
{
|
|
||||||
m_guiMain->update();
|
|
||||||
}
|
|
||||||
GuiLambda(std::function<tsl::elm::Element*()> createUIFunc, tsl::Gui* guiMain) : m_createUI(std::move(createUIFunc)), m_guiMain(guiMain) {}
|
|
||||||
};
|
|
|
@ -1,61 +0,0 @@
|
||||||
#include <tesla.hpp>
|
|
||||||
|
|
||||||
static const char* SYSTEM_SETTINGS_FILE = "/atmosphere/config/system_settings.ini";
|
|
||||||
|
|
||||||
static tsl::hlp::ini::IniData readSettings()
|
|
||||||
{
|
|
||||||
/* Open Sd card filesystem. */
|
|
||||||
FsFileSystem fsSdmc;
|
|
||||||
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return {};
|
|
||||||
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
|
|
||||||
|
|
||||||
/* Open config file. */
|
|
||||||
FsFile fileConfig;
|
|
||||||
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Read, &fileConfig))) return {};
|
|
||||||
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
|
|
||||||
|
|
||||||
/* Get config file size. */
|
|
||||||
s64 configFileSize;
|
|
||||||
if(R_FAILED(fsFileGetSize(&fileConfig, &configFileSize))) return {};
|
|
||||||
|
|
||||||
/* Read and parse config file. */
|
|
||||||
std::string configFileData(configFileSize, '\0');
|
|
||||||
u64 readSize;
|
|
||||||
Result rc = fsFileRead(&fileConfig, 0, configFileData.data(), configFileSize, FsReadOption_None, &readSize);
|
|
||||||
if(R_FAILED(rc) || readSize != static_cast<u64>(configFileSize)) return {};
|
|
||||||
|
|
||||||
return tsl::hlp::ini::parseIni(configFileData);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void writeSettings(tsl::hlp::ini::IniData const& iniData)
|
|
||||||
{
|
|
||||||
/* Open Sd card filesystem. */
|
|
||||||
FsFileSystem fsSdmc;
|
|
||||||
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return;
|
|
||||||
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
|
|
||||||
|
|
||||||
std::string iniString = tsl::hlp::ini::unparseIni(iniData);
|
|
||||||
|
|
||||||
fsFsDeleteFile(&fsSdmc, SYSTEM_SETTINGS_FILE);
|
|
||||||
fsFsCreateFile(&fsSdmc, SYSTEM_SETTINGS_FILE, iniString.length(), 0);
|
|
||||||
|
|
||||||
/* Open config file. */
|
|
||||||
FsFile fileConfig;
|
|
||||||
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Write, &fileConfig))) return;
|
|
||||||
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
|
|
||||||
|
|
||||||
fsFileWrite(&fileConfig, 0, iniString.c_str(), iniString.length(), FsWriteOption_Flush);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateSettings(tsl::hlp::ini::IniData const& changes)
|
|
||||||
{
|
|
||||||
tsl::hlp::ini::IniData iniData = readSettings();
|
|
||||||
for(auto& section : changes)
|
|
||||||
{
|
|
||||||
for(auto& keyValue : section.second)
|
|
||||||
{
|
|
||||||
iniData[section.first][keyValue.first] = keyValue.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeSettings(iniData);
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
#include <tesla.hpp>
|
|
||||||
|
|
||||||
class OverflowList : public tsl::elm::List {
|
|
||||||
public:
|
|
||||||
OverflowList() : tsl::elm::List() {}
|
|
||||||
|
|
||||||
virtual tsl::elm::Element* requestFocus(tsl::elm::Element *oldFocus, tsl::FocusDirection direction) override {
|
|
||||||
tsl::elm::Element *newFocus = nullptr;
|
|
||||||
|
|
||||||
if (this->m_clearList || this->m_itemsToAdd.size() > 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (direction == tsl::FocusDirection::None) {
|
|
||||||
u16 i = 0;
|
|
||||||
|
|
||||||
if (oldFocus == nullptr) {
|
|
||||||
s32 elementHeight = 0;
|
|
||||||
while (elementHeight < this->m_offset && i < this->m_items.size() - 1) {
|
|
||||||
i++;
|
|
||||||
elementHeight += this->m_items[i]->getHeight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < this->m_items.size(); i++) {
|
|
||||||
newFocus = this->m_items[i]->requestFocus(oldFocus, direction);
|
|
||||||
|
|
||||||
if (newFocus != nullptr) {
|
|
||||||
this->m_focusedIndex = i;
|
|
||||||
|
|
||||||
this->updateScrollOffset();
|
|
||||||
return newFocus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (direction == tsl::FocusDirection::Down) {
|
|
||||||
|
|
||||||
for (u16 i = this->m_focusedIndex + 1; i < this->m_items.size(); i++) {
|
|
||||||
newFocus = this->m_items[i]->requestFocus(oldFocus, direction);
|
|
||||||
|
|
||||||
if (newFocus != nullptr && newFocus != oldFocus) {
|
|
||||||
this->m_focusedIndex = i;
|
|
||||||
|
|
||||||
this->updateScrollOffset();
|
|
||||||
return newFocus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->m_focusedIndex == this->m_items.size() - 1) {
|
|
||||||
for (u16 i = 0; i < this->m_items.size(); i++) {
|
|
||||||
newFocus = this->m_items[i]->requestFocus(oldFocus, direction);
|
|
||||||
|
|
||||||
if (newFocus != nullptr && newFocus != oldFocus) {
|
|
||||||
this->m_focusedIndex = i;
|
|
||||||
|
|
||||||
this->updateScrollOffset();
|
|
||||||
return newFocus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldFocus;
|
|
||||||
} else if (direction == tsl::FocusDirection::Up) {
|
|
||||||
if (this->m_focusedIndex > 0) {
|
|
||||||
|
|
||||||
for (u16 i = this->m_focusedIndex - 1; i >= 0; i--) {
|
|
||||||
if (i > this->m_items.size() || this->m_items[i] == nullptr)
|
|
||||||
return oldFocus;
|
|
||||||
else
|
|
||||||
newFocus = this->m_items[i]->requestFocus(oldFocus, direction);
|
|
||||||
|
|
||||||
if (newFocus != nullptr && newFocus != oldFocus) {
|
|
||||||
this->m_focusedIndex = i;
|
|
||||||
|
|
||||||
this->updateScrollOffset();
|
|
||||||
return newFocus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u16 i = this->m_items.size() - 1; i >= 0; i--) {
|
|
||||||
if (i <= this->m_items.size() && this->m_items[i] != nullptr)
|
|
||||||
newFocus = this->m_items[i]->requestFocus(oldFocus, direction);
|
|
||||||
|
|
||||||
if (newFocus != nullptr && newFocus != oldFocus) {
|
|
||||||
this->m_focusedIndex = i;
|
|
||||||
|
|
||||||
this->updateScrollOffset();
|
|
||||||
return newFocus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldFocus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual void updateScrollOffset() {
|
|
||||||
if (this->getInputMode() != tsl::InputMode::Controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this->m_listHeight <= this->getHeight()) {
|
|
||||||
this->m_nextOffset = 0;
|
|
||||||
this->m_offset = 0;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_nextOffset = 0;
|
|
||||||
for (u16 i = 0; i < this->m_focusedIndex; i++)
|
|
||||||
this->m_nextOffset += this->m_items[i]->getHeight();
|
|
||||||
|
|
||||||
this->m_nextOffset -= this->getHeight() / 3;
|
|
||||||
|
|
||||||
if (this->m_nextOffset < 0)
|
|
||||||
this->m_nextOffset = 0;
|
|
||||||
|
|
||||||
if (this->m_nextOffset > (this->m_listHeight - this->getHeight()) + 50)
|
|
||||||
this->m_nextOffset = (this->m_listHeight - this->getHeight() + 50);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,24 +0,0 @@
|
||||||
#include <tesla.hpp>
|
|
||||||
|
|
||||||
class OverlayFrameWithHelp : public tsl::elm::OverlayFrame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OverlayFrameWithHelp(const std::string& title, const std::string& subtitle) : tsl::elm::OverlayFrame(title, subtitle)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual void draw(tsl::gfx::Renderer* renderer) override
|
|
||||||
{
|
|
||||||
renderer->fillScreen(a(tsl::style::color::ColorFrameBackground));
|
|
||||||
renderer->drawRect(tsl::cfg::FramebufferWidth - 1, 0, 1, tsl::cfg::FramebufferHeight, a(0xF222));
|
|
||||||
|
|
||||||
renderer->drawString(this->m_title.c_str(), false, 20, 50, 30, a(tsl::style::color::ColorText));
|
|
||||||
renderer->drawString(this->m_subtitle.c_str(), false, 20, 70, 15, a(tsl::style::color::ColorDescription));
|
|
||||||
|
|
||||||
renderer->drawRect(15, tsl::cfg::FramebufferHeight - 73, tsl::cfg::FramebufferWidth - 30, 1, a(tsl::style::color::ColorText));
|
|
||||||
|
|
||||||
renderer->drawString("\uE0E1 Back \uE0E0 OK \uE0E3 Help", false, 30, 693, 23, a(tsl::style::color::ColorText));
|
|
||||||
|
|
||||||
if (this->m_contentElement != nullptr)
|
|
||||||
this->m_contentElement->frame(renderer);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,368 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define NONE 0
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "cpp_utils.hpp"
|
|
||||||
|
|
||||||
const std::vector<std::string> on_off{"Off", "On"};
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_OnOffFlag(type,x) \
|
|
||||||
x(type,On,"On")
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
DEFINE_ENUM_CLASS(OnOffFlag);
|
|
||||||
|
|
||||||
// Frame Advantage
|
|
||||||
const std::vector<std::string> frame_advantage_items{""};
|
|
||||||
const std::string frame_advantage_help = R""""(
|
|
||||||
Show frame advantage when
|
|
||||||
hitting a CPU's shield.
|
|
||||||
|
|
||||||
This is comparing true frames
|
|
||||||
of actionability between the
|
|
||||||
CPU and player.
|
|
||||||
|
|
||||||
Use this to practice optimal
|
|
||||||
aerial heights and specific
|
|
||||||
safe hitboxes.)"""";
|
|
||||||
|
|
||||||
// Input delay
|
|
||||||
const std::vector<std::string> input_delay_items{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
|
|
||||||
const std::string input_delay_help = R""""(
|
|
||||||
In frames.
|
|
||||||
|
|
||||||
Emulate input delay
|
|
||||||
to practice in a online
|
|
||||||
environment.)"""";
|
|
||||||
|
|
||||||
// Side Taunt
|
|
||||||
|
|
||||||
// DI / Left Stick
|
|
||||||
/*
|
|
||||||
0, 0.785398, 1.570796, 2.356194, -3.14159, -2.356194, -1.570796, -0.785398
|
|
||||||
0, pi/4, pi/2, 3pi/4, pi, 5pi/4, 3pi/2, 7pi/4
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* DI */
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_Direction(type,x) \
|
|
||||||
x(type,Out,"Out") \
|
|
||||||
x(type,UpOut,"Up Out") \
|
|
||||||
x(type,Up,"Up") \
|
|
||||||
x(type,UpIn,"Up In") \
|
|
||||||
x(type,In,"In") \
|
|
||||||
x(type,DownIn,"Down In") \
|
|
||||||
x(type,Down,"Down") \
|
|
||||||
x(type,DownOut,"Down Out")\
|
|
||||||
x(type,Nothing,"Neutral")
|
|
||||||
|
|
||||||
DEFINE_ENUM_CLASS(Direction);
|
|
||||||
const std::string di_help = R""""(
|
|
||||||
Specified Direction
|
|
||||||
CPUs DI in the direction specified
|
|
||||||
(relative to the player's facing
|
|
||||||
position).
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
const std::string sdi_help = R""""(
|
|
||||||
Specified Direction
|
|
||||||
CPUs SDI in the direction specified
|
|
||||||
(relative to the player's facing
|
|
||||||
position) every four frames
|
|
||||||
during hitlag.
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Left Stick
|
|
||||||
const std::string air_dodge_direction_help = R""""(
|
|
||||||
Air Dodge Direction
|
|
||||||
(relative to the player's facing
|
|
||||||
position).
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Ledge Option
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_LedgeFlag(type,x) \
|
|
||||||
x(type,Neutral,"Neutral") \
|
|
||||||
x(type,Roll,"Roll") \
|
|
||||||
x(type,Jump,"Jump") \
|
|
||||||
x(type,Attack,"Attack") \
|
|
||||||
x(type,Wait,"Wait")
|
|
||||||
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
DEFINE_ENUM_CLASS(LedgeFlag);
|
|
||||||
const std::string ledge_help = R""""(
|
|
||||||
CPUs will perform a ledge option
|
|
||||||
among the selected options.
|
|
||||||
|
|
||||||
CPUs will also perform a defensive
|
|
||||||
option after getting up.
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
const std::string ledge_delay_help = R""""(
|
|
||||||
Frames to delay ledge option.)"""";
|
|
||||||
|
|
||||||
// Tech Option
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_TechFlag(type,x) \
|
|
||||||
x(type,Miss,"Miss Tech") \
|
|
||||||
x(type,RollF,"RollF") \
|
|
||||||
x(type,RollB,"RollB") \
|
|
||||||
x(type,InPlace,"In Place")
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
DEFINE_ENUM_CLASS(TechFlag);
|
|
||||||
|
|
||||||
constexpr const char* const tech_help = R""""(
|
|
||||||
CPUs will perform a random
|
|
||||||
tech option among the selected
|
|
||||||
options.
|
|
||||||
|
|
||||||
CPUs will also perform a defensive
|
|
||||||
option after getting up.
|
|
||||||
|
|
||||||
For wall tech jumps set it to RollF
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Missed Tech Option
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_MissTechFlag(type,x) \
|
|
||||||
x(type,Getup,"Normal Getup") \
|
|
||||||
x(type,Attack,"Getup Attack") \
|
|
||||||
x(type,RollF,"RollF") \
|
|
||||||
x(type,RollB,"RollB")
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
DEFINE_ENUM_CLASS(MissTechFlag);
|
|
||||||
|
|
||||||
constexpr const char* const miss_tech_help = R""""(
|
|
||||||
CPUs will perform a random
|
|
||||||
option after missing a tech
|
|
||||||
among the selected options.
|
|
||||||
|
|
||||||
CPUs will also perform a defensive
|
|
||||||
option after getting up.)"""";
|
|
||||||
|
|
||||||
// Defensive States
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_DefensiveFlag(type,x) \
|
|
||||||
x(type,SpotDodge,"Spotdodge") \
|
|
||||||
x(type,RollF,"RollF") \
|
|
||||||
x(type,RollB,"RollB") \
|
|
||||||
x(type,Jab,"Jab")\
|
|
||||||
x(type,Shield,"Shield")
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
DEFINE_ENUM_CLASS(DefensiveFlag);
|
|
||||||
|
|
||||||
const std::string defensive_help = R""""(
|
|
||||||
Choose the defensive option a CPU
|
|
||||||
will perform after teching or
|
|
||||||
getting up from the ledge.
|
|
||||||
|
|
||||||
The option will be random
|
|
||||||
among the selected options.
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Mash States
|
|
||||||
const std::string mash_help = R""""(
|
|
||||||
Use this toggle along with the Shield
|
|
||||||
Options toggle to practice moves on
|
|
||||||
shield.
|
|
||||||
|
|
||||||
The option will be random
|
|
||||||
among the selected options.
|
|
||||||
|
|
||||||
CPUs will mash on the first frame out
|
|
||||||
of hitstun or out of specific states.
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Action items (Follow Up only atm)
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_ActionFlag(type,x) \
|
|
||||||
x(type,Airdodge,"Airdodge") x(type,Jump,"Jump") x(type,Shield,"Shield") x(type,Spotdodge,"Spotdodge") x(type,RollF,"Roll F") x(type,RollB,"Roll B") \
|
|
||||||
x(type,Nair,"Neutral Air") x(type,Fair,"Forward Air") x(type,Bair,"Back Air") x(type,Uair,"Up Air") x(type,Dair,"Down Air") \
|
|
||||||
x(type,NeutralB,"Neutral B") x(type,SideB,"Side B") x(type,UpB,"Up B") x(type,DownB,"Down B") \
|
|
||||||
x(type,FSmash,"Forward Smash") x(type,USmash,"Up Smash") x(type,DSmash,"Down Smash") \
|
|
||||||
x(type,Jab,"Jab") x(type,FTilt,"Ftilt") x(type,UTilt,"Utilt") x(type,Dtilt,"Dtilt") \
|
|
||||||
x(type,Grab,"Grab") x(type,Dash,"Dash") x(type,DashAttack,"Dash Attack")
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
DEFINE_ENUM_CLASS(ActionFlag);
|
|
||||||
|
|
||||||
const std::string follow_up_help = R""""(
|
|
||||||
The selected action will be
|
|
||||||
buffered after the specified
|
|
||||||
mash option.
|
|
||||||
|
|
||||||
The option will be random
|
|
||||||
among the selected options.
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Hitbox visualization
|
|
||||||
const std::string hitbox_help = R""""(
|
|
||||||
Currently, hitboxes and
|
|
||||||
grabboxes are supported.
|
|
||||||
|
|
||||||
Original move effects are
|
|
||||||
paused during normal attacks
|
|
||||||
and specials when hitbox
|
|
||||||
visualization is active.)"""";
|
|
||||||
|
|
||||||
// Stage Hazards
|
|
||||||
const std::string hazards_help = R""""(
|
|
||||||
Toggle state hazards on/off for
|
|
||||||
Training Mode.
|
|
||||||
|
|
||||||
Only works outside of a match.
|
|
||||||
Make sure to turn them on/off
|
|
||||||
before leaving the Character
|
|
||||||
Select Screen.
|
|
||||||
|
|
||||||
If you change this while in training,
|
|
||||||
make sure to restart training mode.
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Save states
|
|
||||||
const std::vector<std::string> empty_items{""};
|
|
||||||
const std::string save_states_help = R""""(
|
|
||||||
Press Grab + Down Taunt at any
|
|
||||||
time to save the state of the
|
|
||||||
training mode for you and the
|
|
||||||
CPU.
|
|
||||||
|
|
||||||
Press Grab + Up Taunt at any
|
|
||||||
time to revert to a
|
|
||||||
previously saved state.
|
|
||||||
|
|
||||||
The following attributes
|
|
||||||
are saved:
|
|
||||||
- Percent
|
|
||||||
- Position
|
|
||||||
- Facing direction)"""";
|
|
||||||
|
|
||||||
const std::string reset_menu_help = R""""(
|
|
||||||
Reset menu to default
|
|
||||||
configuration. Please also
|
|
||||||
use on the first boot after
|
|
||||||
upgrading Training Modpack
|
|
||||||
versions.)"""";
|
|
||||||
|
|
||||||
// Shield States
|
|
||||||
#define SHIELD_INFINITE 1
|
|
||||||
#define SHIELD_HOLD 2
|
|
||||||
const std::vector<std::string> shield_items{"None", "Infinite", "Hold", "Constant"};
|
|
||||||
const std::string shield_help = R""""(
|
|
||||||
Use these toggles in conjunction
|
|
||||||
with Mash toggles to practice
|
|
||||||
moves on shield.
|
|
||||||
|
|
||||||
Infinite
|
|
||||||
CPUs will hold a shield that does
|
|
||||||
not deteriorate over time or
|
|
||||||
by damage.
|
|
||||||
|
|
||||||
Hold
|
|
||||||
CPUs will hold a normal shield.
|
|
||||||
This shield will not deteriorate
|
|
||||||
until hit once.)
|
|
||||||
|
|
||||||
Constant
|
|
||||||
Shield will take damage but not deteriorate
|
|
||||||
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// OOS
|
|
||||||
const std::string oos_help = R""""(
|
|
||||||
Option to delay oos options
|
|
||||||
until a certain number of hits
|
|
||||||
have connected.
|
|
||||||
|
|
||||||
Consecutive hits that keep the
|
|
||||||
CPU locked in shield stun
|
|
||||||
between hits will count
|
|
||||||
as a single hit.)"""";
|
|
||||||
|
|
||||||
const std::string reaction_time_help = R""""(
|
|
||||||
Additional reaction time
|
|
||||||
in frames.
|
|
||||||
|
|
||||||
Used to delay OOS Options.)"""";
|
|
||||||
|
|
||||||
const std::string shield_tilt_help = R""""(
|
|
||||||
Shield Tilt Direction
|
|
||||||
)"""";
|
|
||||||
|
|
||||||
// Mash in neutral
|
|
||||||
const std::string mash_neutral_help = R""""(
|
|
||||||
Force mash options to
|
|
||||||
always occur, not just
|
|
||||||
out of specific states.)"""";
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define ENUM_CLASS_DelayFlag(type,x) \
|
|
||||||
x(type,D0,"0") \
|
|
||||||
x(type,D1,"1") x(type,D2,"2") x(type,D3,"3") x(type,D4,"4") x(type,D5,"5") \
|
|
||||||
x(type,D6,"6") x(type,D7,"7") x(type,D8,"8") x(type,D9,"9") x(type,D10,"10") \
|
|
||||||
x(type,D11,"11") x(type,D12,"12") x(type,D13,"13") x(type,D14,"14") x(type,D15,"15") \
|
|
||||||
x(type,D16,"16") x(type,D17,"17") x(type,D18,"18") x(type,D19,"19") x(type,D20,"20") \
|
|
||||||
x(type,D21,"21") x(type,D22,"22") x(type,D23,"23") x(type,D24,"24") x(type,D25,"25") \
|
|
||||||
x(type,D26,"26") x(type,D27,"27") x(type,D28,"28") x(type,D29,"29") x(type,D30,"30") \
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
DEFINE_ENUM_CLASS(DelayFlag);
|
|
||||||
|
|
||||||
#define ENUM_CLASS_BoolFlag(type,x) \
|
|
||||||
x(type,True,"True") x(type,False,"False")
|
|
||||||
|
|
||||||
DEFINE_ENUM_CLASS(BoolFlag);
|
|
||||||
|
|
||||||
const std::string fast_fall_help = R""""(
|
|
||||||
CPUs will fast fall
|
|
||||||
out of jumps and aerial
|
|
||||||
attacks as soon as possible.)"""";
|
|
||||||
|
|
||||||
const std::string fast_fall_delay_help = R""""(
|
|
||||||
Frames to delay CPU
|
|
||||||
fast fall.)"""";
|
|
||||||
|
|
||||||
const std::string falling_aerials_help = R""""(
|
|
||||||
CPUs will only begin
|
|
||||||
aerials at the apex of
|
|
||||||
their jump.)"""";
|
|
||||||
|
|
||||||
const std::string aerial_delay_help = R""""(
|
|
||||||
Frames to delay CPU Aerial.)"""";
|
|
||||||
|
|
||||||
const std::string full_hop_help = R""""(
|
|
||||||
CPUs will full hop
|
|
||||||
rather than short hop
|
|
||||||
aerials.)"""";
|
|
||||||
|
|
||||||
#define ENUM_CLASS_AttackAngleFlag(type,x) \
|
|
||||||
x(type,Neutral,"Neutral") x(type,Up,"Up") x(type,Down,"Down")
|
|
||||||
DEFINE_ENUM_CLASS(AttackAngleFlag);
|
|
||||||
|
|
||||||
const std::string attack_angle_help = R""""(
|
|
||||||
Set angleable tilt and smash attacks.)"""";
|
|
||||||
|
|
||||||
const std::string save_damage_help = R""""(
|
|
||||||
Set if save states should apply to damage.)"""";
|
|
||||||
|
|
||||||
#define NORMAL 0
|
|
||||||
const std::vector<std::string> strength_items{ "Normal", "Medium", "High"};
|
|
||||||
const std::string sdi_strength_help = R""""(
|
|
||||||
How many frames between each SDI input
|
|
||||||
|
|
||||||
Normal 8
|
|
||||||
Medium 6
|
|
||||||
High 4
|
|
||||||
|
|
||||||
)"""";
|
|
|
@ -1,185 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <tesla.hpp>
|
|
||||||
#include "gui_help.hpp"
|
|
||||||
#include "gui_sublist.hpp"
|
|
||||||
#include "cpp_utils.hpp"
|
|
||||||
|
|
||||||
class ValueListItem : public tsl::elm::ListItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ValueListItem(std::string text,
|
|
||||||
const std::vector<std::string> values,
|
|
||||||
int* defaultPos,
|
|
||||||
const std::string data,
|
|
||||||
const std::string help)
|
|
||||||
: tsl::elm::ListItem(text), m_values(values), m_curValue(defaultPos), extdata(data), help(help)
|
|
||||||
{
|
|
||||||
this->setValue(m_values[*m_curValue]);
|
|
||||||
|
|
||||||
this->initEventListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
~ValueListItem() {}
|
|
||||||
|
|
||||||
void applyChanges()
|
|
||||||
{
|
|
||||||
int value = this->getCurValue();
|
|
||||||
this->setValue(this->getValues()[value]);
|
|
||||||
this->setCurValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
tsl::elm::Element* requestFocus(Element* oldFocus, tsl::FocusDirection direction)
|
|
||||||
{
|
|
||||||
return ListItem::requestFocus(oldFocus, direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
void layout(u16 parentX, u16 parentY, u16 parentWidth, u16 parentHeight)
|
|
||||||
{
|
|
||||||
ListItem::layout(parentX, parentY, parentWidth, parentHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onClick(u64 keys)
|
|
||||||
{
|
|
||||||
if(keys & KEY_A)
|
|
||||||
{
|
|
||||||
if(this->m_valueChangeListener != nullptr)
|
|
||||||
{
|
|
||||||
this->m_valueChangeListener(this->m_values, this->m_curValue, this->extdata, this->getText(), this->help);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getCurValue() { return *(this->m_curValue); }
|
|
||||||
void setCurValue(int value) { *(this->m_curValue) = value; }
|
|
||||||
|
|
||||||
const std::string getExtData() { return this->extdata; }
|
|
||||||
|
|
||||||
const std::vector<std::string> getValues() { return this->m_values; }
|
|
||||||
|
|
||||||
void setStateChangedListener(
|
|
||||||
std::function<void(const std::vector<std::string>, int*, std::string, std::string, std::string)> valueChangeListener)
|
|
||||||
{
|
|
||||||
this->m_valueChangeListener = valueChangeListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void initEventListener()
|
|
||||||
{
|
|
||||||
this->setStateChangedListener(
|
|
||||||
[](std::vector<std::string> menuItems, int* val, std::string data, std::string title, std::string helpTxt) {
|
|
||||||
tsl::changeTo<GuiSublist>(menuItems, val, data, title, helpTxt);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::vector<std::string> m_values;
|
|
||||||
int* m_curValue;
|
|
||||||
std::function<void(const std::vector<std::string>, int*, std::string, std::string, std::string)> m_valueChangeListener =
|
|
||||||
nullptr;
|
|
||||||
const std::string extdata;
|
|
||||||
const std::string help;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> class BitFlagToggleListItem : public tsl::elm::ToggleListItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using FlagType = detail::FlagTypeT<T>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
T m_mask;
|
|
||||||
FlagType* m_value;
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_help;
|
|
||||||
|
|
||||||
public:
|
|
||||||
BitFlagToggleListItem(const std::string& text, T mask, FlagType* value, std::string name = "", std::string help = "")
|
|
||||||
: tsl::elm::ToggleListItem(text, (mask & *value) != 0, "\uE14B", "\uE14C"), m_mask(mask), m_value(value), m_name(name), m_help(help)
|
|
||||||
{
|
|
||||||
setStateChangedListener([this](bool v) {
|
|
||||||
if(v)
|
|
||||||
{
|
|
||||||
*m_value = *m_value | m_mask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*m_value = *m_value - m_mask;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
virtual bool onClick(u64 keys) override
|
|
||||||
{
|
|
||||||
// temp band-aid for issues with ToggleListItem
|
|
||||||
if(keys & KEY_A)
|
|
||||||
{
|
|
||||||
setState(!m_state);
|
|
||||||
return ListItem::onClick(keys);
|
|
||||||
}
|
|
||||||
else if(keys & KEY_Y)
|
|
||||||
{
|
|
||||||
if (m_help != "") {
|
|
||||||
tsl::changeTo<GuiHelp>(m_name, m_help);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual void setState(bool state) override
|
|
||||||
{
|
|
||||||
// temp band-aid for issues with ToggleListItem
|
|
||||||
bool stateChanged = state != this->m_state;
|
|
||||||
ToggleListItem::setState(state);
|
|
||||||
if(stateChanged && m_stateChangedListener)
|
|
||||||
{
|
|
||||||
m_stateChangedListener(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual ~BitFlagToggleListItem() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SetToggleListItem : public tsl::elm::ListItem
|
|
||||||
{
|
|
||||||
std::vector<tsl::elm::ToggleListItem*> m_itemsOn;
|
|
||||||
std::vector<tsl::elm::ToggleListItem*> m_itemsOff;
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_help;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SetToggleListItem(std::vector<tsl::elm::ToggleListItem*> itemsOn,
|
|
||||||
std::vector<tsl::elm::ToggleListItem*> itemsOff,
|
|
||||||
const std::string& text,
|
|
||||||
const std::string name = "",
|
|
||||||
const std::string help = "",
|
|
||||||
const std::string& value = "")
|
|
||||||
: tsl::elm::ListItem(text, value), m_itemsOn(std::move(itemsOn)), m_itemsOff(std::move(itemsOff)), m_name(name), m_help(help)
|
|
||||||
{
|
|
||||||
setClickListener([this](u64 keys) -> bool {
|
|
||||||
if(keys & KEY_A)
|
|
||||||
{
|
|
||||||
for(auto it : m_itemsOn)
|
|
||||||
{
|
|
||||||
it->setState(true);
|
|
||||||
}
|
|
||||||
for(auto it : m_itemsOff)
|
|
||||||
{
|
|
||||||
it->setState(false);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(keys & KEY_Y)
|
|
||||||
{
|
|
||||||
if (m_help != "") {
|
|
||||||
tsl::changeTo<GuiHelp>(m_name, m_help);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
virtual ~SetToggleListItem() = default;
|
|
||||||
};
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit a68af19eda8e2b1d51008a2e1a1b71649460f901
|
|
|
@ -1,539 +0,0 @@
|
||||||
#include <tesla.hpp>
|
|
||||||
#include "gui_main.hpp"
|
|
||||||
#include "gui_help.hpp"
|
|
||||||
#include "overflow_list.hpp"
|
|
||||||
#include "overlay_frame_with_help.hpp"
|
|
||||||
#include "value_list_item.hpp"
|
|
||||||
#include "clickable_list_item.hpp"
|
|
||||||
#include "ini_settings.hpp"
|
|
||||||
#include "taunt_toggles.hpp"
|
|
||||||
|
|
||||||
static struct TrainingModpackMenu
|
|
||||||
{
|
|
||||||
OnOffFlags HITBOX_VIS = OnOffFlag::On;
|
|
||||||
OnOffFlags STAGE_HAZARDS = OnOffFlags::None;
|
|
||||||
Directions DI_STATE = Directions::None;
|
|
||||||
Directions SDI_STATE = Directions::None;
|
|
||||||
int SDI_STRENGTH = NORMAL;
|
|
||||||
Directions AIR_DODGE_DIR = Directions::None;
|
|
||||||
ActionFlags MASH_STATE = ActionFlags::None;
|
|
||||||
ActionFlags FOLLOW_UP = ActionFlags::None;
|
|
||||||
AttackAngleFlags ATTACK_ANGLE = AttackAngleFlags::None;
|
|
||||||
LedgeFlags LEDGE_STATE = LedgeFlags::All;
|
|
||||||
DelayFlags LEDGE_DELAY = DelayFlags::All;
|
|
||||||
TechFlags TECH_STATE = TechFlags::All;
|
|
||||||
MissTechFlags MISS_TECH_STATE = MissTechFlags::All;
|
|
||||||
int SHIELD_STATE = NONE;
|
|
||||||
DefensiveFlags DEFENSIVE_STATE = DefensiveFlags::All;
|
|
||||||
DelayFlags OOS_OFFSET = DelayFlags::None;
|
|
||||||
DelayFlags REACTION_TIME = DelayFlags::None;
|
|
||||||
Directions SHIELD_TILT = Directions::None;
|
|
||||||
OnOffFlags MASH_IN_NEUTRAL = OnOffFlags::None;
|
|
||||||
BoolFlags FAST_FALL = BoolFlags::None;
|
|
||||||
DelayFlags FAST_FALL_DELAY = DelayFlags::None;
|
|
||||||
BoolFlags FALLING_AERIALS = BoolFlags::None;
|
|
||||||
DelayFlags AERIAL_DELAY = DelayFlags::None;
|
|
||||||
BoolFlags FULL_HOP = BoolFlags::None;
|
|
||||||
int INPUT_DELAY = 0;
|
|
||||||
OnOffFlags SAVE_DAMAGE = OnOffFlag::On;
|
|
||||||
} menu;
|
|
||||||
|
|
||||||
static struct TrainingModpackMenu defaultMenu = menu;
|
|
||||||
|
|
||||||
static int FRAME_ADVANTAGE = 0;
|
|
||||||
|
|
||||||
u64 pidSmash = 0;
|
|
||||||
static const char* TRAINING_MOD_LOG = "/TrainingModpack/training_modpack.log";
|
|
||||||
static const char* TRAINING_MOD_FRAME_ADV_LOG = "/TrainingModpack/training_modpack_frame_adv.log";
|
|
||||||
static const char* TRAINING_MOD_CONF = "/TrainingModpack/training_modpack_menu.conf";
|
|
||||||
|
|
||||||
GuiMain::GuiMain()
|
|
||||||
{
|
|
||||||
smInitialize();
|
|
||||||
pminfoInitialize();
|
|
||||||
pmbmInitialize();
|
|
||||||
smExit();
|
|
||||||
|
|
||||||
pmdmntGetProcessId(&pidSmash, 0x01006A800016E000);
|
|
||||||
|
|
||||||
Result rc = fsOpenSdCardFileSystem(&this->m_fs);
|
|
||||||
if(R_FAILED(rc)) return;
|
|
||||||
|
|
||||||
FsFile menuFile;
|
|
||||||
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_CONF, FsOpenMode_Read, &menuFile);
|
|
||||||
if(R_FAILED(rc)) return;
|
|
||||||
|
|
||||||
u64 bytesRead;
|
|
||||||
rc = fsFileRead(&menuFile, 0, static_cast<void*>(&menu), sizeof(menu), FsReadOption_None, &bytesRead);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
fsFileWrite(&menuFile, 0, static_cast<void*>(&menu), sizeof(menu), FsOpenMode_Write);
|
|
||||||
}
|
|
||||||
|
|
||||||
fsFileClose(&menuFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
GuiMain::~GuiMain()
|
|
||||||
{
|
|
||||||
// apply changes on exit
|
|
||||||
applyChanges();
|
|
||||||
|
|
||||||
smInitialize();
|
|
||||||
pminfoExit();
|
|
||||||
pmbmExit();
|
|
||||||
smExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static char FrameAdvantage[672];
|
|
||||||
|
|
||||||
class FrameAdvantageOverlayFrame : public tsl::elm::OverlayFrame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FrameAdvantageOverlayFrame(const std::string& title, const std::string& subtitle) : tsl::elm::OverlayFrame(title, subtitle)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual void draw(tsl::gfx::Renderer* renderer) override
|
|
||||||
{
|
|
||||||
renderer->clearScreen();
|
|
||||||
|
|
||||||
renderer->drawRect(0, 0, tsl::cfg::FramebufferWidth, 85, a(tsl::style::color::ColorFrameBackground));
|
|
||||||
|
|
||||||
renderer->drawString(this->m_title.c_str(), false, 20, 50, 30, a(tsl::style::color::ColorText));
|
|
||||||
renderer->drawString(this->m_subtitle.c_str(), false, 20, 70, 15, a(tsl::style::color::ColorDescription));
|
|
||||||
|
|
||||||
if(this->m_contentElement != nullptr) this->m_contentElement->frame(renderer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class GuiFrameAdvantage : public tsl::Gui
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GuiFrameAdvantage()
|
|
||||||
{
|
|
||||||
tsl::hlp::requestForeground(false);
|
|
||||||
smInitialize();
|
|
||||||
pminfoInitialize();
|
|
||||||
pmbmInitialize();
|
|
||||||
smExit();
|
|
||||||
|
|
||||||
pmdmntGetProcessId(&pidSmash, 0x01006A800016E000);
|
|
||||||
|
|
||||||
Result rc = fsOpenSdCardFileSystem(&this->m_fs);
|
|
||||||
if(R_FAILED(rc)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
~GuiFrameAdvantage()
|
|
||||||
{
|
|
||||||
smInitialize();
|
|
||||||
pminfoExit();
|
|
||||||
pmbmExit();
|
|
||||||
smExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual tsl::elm::Element* createUI() override
|
|
||||||
{
|
|
||||||
snprintf(FrameAdvantage, 256, "Frame Advantage: %d", FRAME_ADVANTAGE);
|
|
||||||
auto rootFrame = new FrameAdvantageOverlayFrame(FrameAdvantage, "\uE0A2 + \uE07B Back");
|
|
||||||
|
|
||||||
this->rootFrame = rootFrame;
|
|
||||||
|
|
||||||
return rootFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update() override
|
|
||||||
{
|
|
||||||
static u32 counter = 0;
|
|
||||||
|
|
||||||
if(counter++ % 10 != 0) return;
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
Handle debug;
|
|
||||||
|
|
||||||
if(pidSmash != 0)
|
|
||||||
{
|
|
||||||
rc = svcDebugActiveProcess(&debug, pidSmash);
|
|
||||||
if(R_SUCCEEDED(rc))
|
|
||||||
{
|
|
||||||
u64 frame_adv_addr = 0;
|
|
||||||
FsFile menuAddrFile;
|
|
||||||
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_FRAME_ADV_LOG, FsOpenMode_Read, &menuAddrFile);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Failed to open file with error %d", rc);
|
|
||||||
rootFrame->setTitle(FrameAdvantage);
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[100];
|
|
||||||
u64 bytesRead;
|
|
||||||
rc = fsFileRead(&menuAddrFile, 0, buffer, 100, FsReadOption_None, &bytesRead);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Failed to read file with error %d", rc);
|
|
||||||
rootFrame->setTitle(FrameAdvantage);
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsFileClose(&menuAddrFile);
|
|
||||||
buffer[bytesRead] = '\0';
|
|
||||||
frame_adv_addr = strtoul(buffer, NULL, 16);
|
|
||||||
|
|
||||||
if(frame_adv_addr != 0)
|
|
||||||
{
|
|
||||||
rc = svcReadDebugProcessMemory(&FRAME_ADVANTAGE, debug, frame_adv_addr, sizeof(int));
|
|
||||||
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Frame Advantage: %d", FRAME_ADVANTAGE);
|
|
||||||
rootFrame->setTitle(FrameAdvantage);
|
|
||||||
}
|
|
||||||
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Smash is not running.");
|
|
||||||
rootFrame->setTitle(FrameAdvantage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual bool handleInput(u64 keysDown,
|
|
||||||
u64 keysHeld,
|
|
||||||
touchPosition touchInput,
|
|
||||||
JoystickPosition leftJoyStick,
|
|
||||||
JoystickPosition rightJoyStick) override
|
|
||||||
{
|
|
||||||
if(keysHeld & KEY_DLEFT)
|
|
||||||
{
|
|
||||||
if(keysHeld & KEY_X)
|
|
||||||
{
|
|
||||||
tsl::goBack();
|
|
||||||
tsl::hlp::requestForeground(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// intercept B inputs
|
|
||||||
if(keysDown & KEY_B)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameAdvantageOverlayFrame* rootFrame;
|
|
||||||
FsFileSystem m_fs;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
template<typename T>
|
|
||||||
tsl::elm::ListItem* createBitFlagOption(T* option, const std::string& name, const std::string& help, GuiMain* guiMain)
|
|
||||||
{
|
|
||||||
using FlagType = typename T::Type;
|
|
||||||
|
|
||||||
auto item = new tsl::elm::ListItem(name);
|
|
||||||
item->setClickListener([name, help, option, guiMain](u64 keys) -> bool {
|
|
||||||
if(keys & KEY_A)
|
|
||||||
{
|
|
||||||
tsl::changeTo<GuiLambda>(
|
|
||||||
[option, name, help]() -> tsl::elm::Element* {
|
|
||||||
auto toggleList = new OverflowList();
|
|
||||||
std::vector<tsl::elm::ToggleListItem*> items;
|
|
||||||
for(auto& [flag, str] : detail::EnumArray<FlagType>::values)
|
|
||||||
{
|
|
||||||
items.emplace_back(new BitFlagToggleListItem<FlagType>(str, flag, option, name, help));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto allOff = new SetToggleListItem({}, items, "None", name, help);
|
|
||||||
auto allOn = new SetToggleListItem(items, {}, "All", name, help);
|
|
||||||
|
|
||||||
toggleList->addItem(allOn);
|
|
||||||
toggleList->addItem(allOff);
|
|
||||||
|
|
||||||
for(auto it : items)
|
|
||||||
{
|
|
||||||
toggleList->addItem(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto frame = new OverlayFrameWithHelp(name, "Press \uE0E3 for help with these options.");
|
|
||||||
frame->setContent(toggleList);
|
|
||||||
return frame;
|
|
||||||
},
|
|
||||||
guiMain);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(keys & KEY_Y)
|
|
||||||
{
|
|
||||||
tsl::changeTo<GuiHelp>(name, help);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
tsl::elm::Element* GuiMain::createUI()
|
|
||||||
{
|
|
||||||
char buffer[256];
|
|
||||||
snprintf(buffer, 256, "Version %s", VERSION);
|
|
||||||
OverlayFrameWithHelp* rootFrame = new OverlayFrameWithHelp("Training Modpack", buffer);
|
|
||||||
|
|
||||||
auto list = new OverflowList();
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
Handle debug;
|
|
||||||
|
|
||||||
tsl::hlp::ini::IniData iniData = readSettings();
|
|
||||||
bool ease_nro_restriction = false;
|
|
||||||
for(auto& section : iniData)
|
|
||||||
{
|
|
||||||
for(auto& keyValue : section.second)
|
|
||||||
{
|
|
||||||
if(section.first == "ro")
|
|
||||||
{
|
|
||||||
if(keyValue.first == "ease_nro_restriction")
|
|
||||||
{
|
|
||||||
ease_nro_restriction = (readSettings()["ro"]["ease_nro_restriction"] == "u8!0x1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ease_nro_restriction)
|
|
||||||
{
|
|
||||||
tsl::elm::Element* iniShow = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
||||||
renderer->drawString(
|
|
||||||
"Your config file did not have the \nproper configuration to run the \nTraining Modpack.\n\n\nIt has been automatically \nupdated.\n- atmosphere\n---- config\n-------- system_settings.ini\n\n(enable ease_nro_restriction)\n\n\nPlease reboot your Switch.",
|
|
||||||
false,
|
|
||||||
50,
|
|
||||||
225,
|
|
||||||
20,
|
|
||||||
tsl::Color(255, 255, 255, 255));
|
|
||||||
});
|
|
||||||
|
|
||||||
updateSettings({{"ro", {{"ease_nro_restriction", "u8!0x1"}}}});
|
|
||||||
|
|
||||||
rootFrame->setContent(iniShow);
|
|
||||||
return rootFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pidSmash != 0)
|
|
||||||
{
|
|
||||||
rc = svcDebugActiveProcess(&debug, pidSmash);
|
|
||||||
if(R_SUCCEEDED(rc))
|
|
||||||
{
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
|
|
||||||
// Remove because it breaks scrolling up to the bottom of the
|
|
||||||
// menu, because CategoryHeaders can't requestFocus?
|
|
||||||
// list->addItem(new tsl::elm::CategoryHeader("Mash", true));
|
|
||||||
|
|
||||||
list->addItem(createBitFlagOption(&menu.MASH_STATE, "Mash Toggles", mash_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.FOLLOW_UP, "Followup Toggles", follow_up_help, this));
|
|
||||||
list->addItem(new BitFlagToggleListItem<OnOffFlags::Type>(
|
|
||||||
"Mash In Neutral", OnOffFlag::On, &menu.MASH_IN_NEUTRAL, "Mash In Neutral", mash_neutral_help));
|
|
||||||
list->addItem(createBitFlagOption(&menu.ATTACK_ANGLE, "Attack Angle", attack_angle_help, this));
|
|
||||||
|
|
||||||
list->addItem(new tsl::elm::CategoryHeader("Left Stick", true));
|
|
||||||
|
|
||||||
list->addItem(createBitFlagOption(&menu.DI_STATE, "Set DI", di_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.SDI_STATE, "Set SDI", sdi_help, this));
|
|
||||||
|
|
||||||
ValueListItem* sdiItem =
|
|
||||||
new ValueListItem("SDI Strength", strength_items, &menu.SDI_STRENGTH, "SDI Strength", sdi_strength_help);
|
|
||||||
list->addItem(sdiItem);
|
|
||||||
valueListItems.push_back(sdiItem);
|
|
||||||
|
|
||||||
list->addItem(createBitFlagOption(&menu.AIR_DODGE_DIR, "Airdodge Direction", air_dodge_direction_help, this));
|
|
||||||
|
|
||||||
list->addItem(new tsl::elm::CategoryHeader("Shield", true));
|
|
||||||
|
|
||||||
ValueListItem* shieldItem =
|
|
||||||
new ValueListItem("Shield Options", shield_items, &menu.SHIELD_STATE, "shield", shield_help);
|
|
||||||
list->addItem(shieldItem);
|
|
||||||
valueListItems.push_back(shieldItem);
|
|
||||||
|
|
||||||
ClickableListItem* frameAdvantageItem = new ClickableListItem("Frame Advantage",
|
|
||||||
frame_advantage_items,
|
|
||||||
nullptr,
|
|
||||||
"frameAdvantage",
|
|
||||||
0,
|
|
||||||
"Frame Advantage",
|
|
||||||
frame_advantage_help);
|
|
||||||
frameAdvantageItem->setClickListener([](std::vector<std::string> values,
|
|
||||||
int* curValue,
|
|
||||||
std::string extdata,
|
|
||||||
int index,
|
|
||||||
std::string title,
|
|
||||||
std::string help) { tsl::changeTo<GuiFrameAdvantage>(); });
|
|
||||||
frameAdvantageItem->setHelpListener(
|
|
||||||
[](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
||||||
list->addItem(frameAdvantageItem);
|
|
||||||
|
|
||||||
list->addItem(createBitFlagOption(&menu.OOS_OFFSET, "OOS Offset", oos_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.REACTION_TIME, "Reaction Time", reaction_time_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.SHIELD_TILT, "Shield Tilt", shield_tilt_help, this));
|
|
||||||
|
|
||||||
list->addItem(new tsl::elm::CategoryHeader("Chase", true));
|
|
||||||
|
|
||||||
list->addItem(createBitFlagOption(&menu.LEDGE_STATE, "Ledge Options", ledge_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.LEDGE_DELAY, "Ledge Delay", ledge_delay_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.TECH_STATE, "Tech Options", tech_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.MISS_TECH_STATE, "Missed Tech Options", miss_tech_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.DEFENSIVE_STATE, "Defensive Options", defensive_help, this));
|
|
||||||
|
|
||||||
list->addItem(new tsl::elm::CategoryHeader("Aerials", true));
|
|
||||||
|
|
||||||
list->addItem(createBitFlagOption(&menu.FAST_FALL, "Fast Fall", fast_fall_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.FAST_FALL_DELAY, "Fast Fall Delay", fast_fall_delay_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.FALLING_AERIALS, "Falling Aerials", falling_aerials_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.AERIAL_DELAY, "Aerial Delay", aerial_delay_help, this));
|
|
||||||
list->addItem(createBitFlagOption(&menu.FULL_HOP, "Full Hop", full_hop_help, this));
|
|
||||||
|
|
||||||
list->addItem(new tsl::elm::CategoryHeader("Miscellaneous", true));
|
|
||||||
|
|
||||||
list->addItem(new BitFlagToggleListItem<OnOffFlags::Type>(
|
|
||||||
"Hitbox Visualization", OnOffFlag::On, &menu.HITBOX_VIS, "Hitbox Visualization", hitbox_help));
|
|
||||||
|
|
||||||
list->addItem(new BitFlagToggleListItem<OnOffFlags::Type>(
|
|
||||||
"Stage Hazards", OnOffFlag::On, &menu.STAGE_HAZARDS, "Stage Hazards", hazards_help));
|
|
||||||
|
|
||||||
ClickableListItem* saveStateItem =
|
|
||||||
new ClickableListItem("Save States", empty_items, nullptr, "saveStates", 0, "Save States", save_states_help);
|
|
||||||
saveStateItem->setClickListener([](std::vector<std::string> values,
|
|
||||||
int* curValue,
|
|
||||||
std::string extdata,
|
|
||||||
int index,
|
|
||||||
std::string title,
|
|
||||||
std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
||||||
saveStateItem->setHelpListener([](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
||||||
list->addItem(saveStateItem);
|
|
||||||
|
|
||||||
list->addItem(new BitFlagToggleListItem<OnOffFlags::Type>(
|
|
||||||
"Save Damage", OnOffFlag::On, &menu.SAVE_DAMAGE, "Save Damage", save_damage_help));
|
|
||||||
|
|
||||||
ValueListItem* inputDelayItem =
|
|
||||||
new ValueListItem("Input Delay", input_delay_items, &menu.INPUT_DELAY, "inputDelay", input_delay_help);
|
|
||||||
list->addItem(inputDelayItem);
|
|
||||||
valueListItems.push_back(inputDelayItem);
|
|
||||||
|
|
||||||
ClickableListItem* resetMenuItem =
|
|
||||||
new ClickableListItem("Reset Menu", empty_items, nullptr, "resetMenu", 0, "Reset Menu", reset_menu_help);
|
|
||||||
resetMenuItem->setClickListener([](std::vector<std::string> values,
|
|
||||||
int* curValue,
|
|
||||||
std::string extdata,
|
|
||||||
int index,
|
|
||||||
std::string title,
|
|
||||||
std::string help) {
|
|
||||||
menu = defaultMenu;
|
|
||||||
|
|
||||||
/* Open Sd card filesystem. */
|
|
||||||
FsFileSystem fsSdmc;
|
|
||||||
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return;
|
|
||||||
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
|
|
||||||
|
|
||||||
fsFsDeleteFile(&fsSdmc, TRAINING_MOD_CONF);
|
|
||||||
|
|
||||||
tsl::goBack();
|
|
||||||
});
|
|
||||||
resetMenuItem->setHelpListener([](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
||||||
list->addItem(resetMenuItem);
|
|
||||||
|
|
||||||
rootFrame->setContent(list);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tsl::elm::Element* warning =
|
|
||||||
new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
||||||
renderer->drawString("\uE150", false, 180, 250, 90, tsl::Color(255, 255, 255, 255));
|
|
||||||
renderer->drawString("Could not debug process memory", false, 110, 340, 25, tsl::Color(255, 255, 255, 255));
|
|
||||||
});
|
|
||||||
|
|
||||||
rootFrame->setContent(warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tsl::elm::Element* warning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
||||||
renderer->drawString("\uE150", false, 180, 250, 90, tsl::Color(255, 255, 255, 255));
|
|
||||||
renderer->drawString("Smash not running.", false, 110, 340, 25, tsl::Color(255, 255, 255, 255));
|
|
||||||
});
|
|
||||||
|
|
||||||
rootFrame->setContent(warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rootFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiMain::update()
|
|
||||||
{
|
|
||||||
static u32 counter = 0;
|
|
||||||
|
|
||||||
if(counter++ % 15 != 0) return;
|
|
||||||
|
|
||||||
applyChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiMain::applyChanges()
|
|
||||||
{
|
|
||||||
for(ValueListItem* item : valueListItems)
|
|
||||||
{
|
|
||||||
item->applyChanges();
|
|
||||||
}
|
|
||||||
Result rc;
|
|
||||||
Handle debug;
|
|
||||||
|
|
||||||
if(pidSmash != 0)
|
|
||||||
{
|
|
||||||
rc = svcDebugActiveProcess(&debug, pidSmash);
|
|
||||||
if(R_SUCCEEDED(rc))
|
|
||||||
{
|
|
||||||
u64 menu_addr = 0;
|
|
||||||
FsFile menuAddrFile;
|
|
||||||
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_LOG, FsOpenMode_Read, &menuAddrFile);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[100];
|
|
||||||
u64 bytesRead;
|
|
||||||
rc = fsFileRead(&menuAddrFile, 0, buffer, 100, FsReadOption_None, &bytesRead);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsFileClose(&menuAddrFile);
|
|
||||||
buffer[bytesRead] = '\0';
|
|
||||||
menu_addr = strtoul(buffer, NULL, 16);
|
|
||||||
|
|
||||||
if(menu_addr != 0)
|
|
||||||
{
|
|
||||||
rc = svcWriteDebugProcessMemory(debug, &menu, (u64)menu_addr, sizeof(menu));
|
|
||||||
}
|
|
||||||
svcCloseHandle(debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FsFile menuFile;
|
|
||||||
fsFsCreateFile(&this->m_fs, TRAINING_MOD_CONF, sizeof(menu), 0);
|
|
||||||
|
|
||||||
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_CONF, FsOpenMode_Write, &menuFile);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
fsFileClose(&menuFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = fsFileWrite(&menuFile, 0, static_cast<void*>(&menu), sizeof(menu), FsOpenMode_Write);
|
|
||||||
if(R_FAILED(rc))
|
|
||||||
{
|
|
||||||
fsFileClose(&menuFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsFileClose(&menuFile);
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
#include "gui_sublist.hpp"
|
|
||||||
#include "overflow_list.hpp"
|
|
||||||
#include "overlay_frame_with_help.hpp"
|
|
||||||
#include "gui_help.hpp"
|
|
||||||
#include "clickable_list_item.hpp"
|
|
||||||
#include "taunt_toggles.hpp"
|
|
||||||
|
|
||||||
GuiSublist::GuiSublist(std::vector<std::string> menuItems, int* index, std::string extData, std::string title, std::string help)
|
|
||||||
{
|
|
||||||
this->menuItems = menuItems;
|
|
||||||
this->index = index;
|
|
||||||
this->extData = extData;
|
|
||||||
this->title = title;
|
|
||||||
this->help = help;
|
|
||||||
}
|
|
||||||
|
|
||||||
GuiSublist::~GuiSublist() {}
|
|
||||||
|
|
||||||
tsl::elm::Element* GuiSublist::createUI()
|
|
||||||
{
|
|
||||||
tsl::elm::OverlayFrame* rootFrame = new OverlayFrameWithHelp(title, "Press \uE0E3 for help with these options.");
|
|
||||||
|
|
||||||
auto list = new OverflowList();
|
|
||||||
|
|
||||||
for(size_t i = 0; i < menuItems.size(); i++)
|
|
||||||
{
|
|
||||||
auto item = new ClickableListItem(menuItems[i], menuItems, this->index, "", i, title, help);
|
|
||||||
setClickListener(item);
|
|
||||||
item->setHelpListener([](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
||||||
list->addItem(item);
|
|
||||||
listItems.push_back(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
list->setFocusedIndex(*index);
|
|
||||||
|
|
||||||
rootFrame->setContent(list);
|
|
||||||
|
|
||||||
return rootFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiSublist::setClickListener(ClickableListItem* item)
|
|
||||||
{
|
|
||||||
item->setClickListener([](std::vector<std::string> values,
|
|
||||||
int* curValue,
|
|
||||||
std::string extdata,
|
|
||||||
int index,
|
|
||||||
std::string title,
|
|
||||||
std::string help) {
|
|
||||||
*curValue = index;
|
|
||||||
tsl::goBack();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiSublist::update()
|
|
||||||
{
|
|
||||||
static u32 counter = 0;
|
|
||||||
|
|
||||||
if(counter++ % 15 != 0) return;
|
|
||||||
|
|
||||||
applyChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiSublist::applyChanges() {}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#define TESLA_INIT_IMPL
|
|
||||||
#include "gui_main.hpp"
|
|
||||||
|
|
||||||
class TrainingModpackOverlay : public tsl::Overlay
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TrainingModpackOverlay() {}
|
|
||||||
~TrainingModpackOverlay() {}
|
|
||||||
|
|
||||||
void initServices() override { pmshellInitialize(); }
|
|
||||||
|
|
||||||
void exitServices() override { pmshellExit(); }
|
|
||||||
|
|
||||||
std::unique_ptr<tsl::Gui> loadInitialGui() override { return std::make_unique<GuiMain>(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
return tsl::loop<TrainingModpackOverlay>(argc, argv);
|
|
||||||
}
|
|
|
@ -3,56 +3,66 @@ use core::f64::consts::PI;
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
// bitflag helper function macro
|
// bitflag helper function macro
|
||||||
macro_rules! to_vec_impl {
|
macro_rules! extra_bitflag_impls {
|
||||||
($e:ty) => {
|
($e:ty) => {
|
||||||
pub fn to_vec(&self) -> Vec::<$e> {
|
impl core::fmt::Display for $e {
|
||||||
let mut vec = Vec::<$e>::new();
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
let mut field = <$e>::from_bits_truncate(self.bits);
|
core::fmt::Debug::fmt(self, f)
|
||||||
while !field.is_empty() {
|
}
|
||||||
let flag = <$e>::from_bits(1u32 << field.bits.trailing_zeros()).unwrap();
|
}
|
||||||
field -= flag;
|
|
||||||
vec.push(flag);
|
impl $e {
|
||||||
|
pub fn to_vec(&self) -> Vec::<$e> {
|
||||||
|
let mut vec = Vec::<$e>::new();
|
||||||
|
let mut field = <$e>::from_bits_truncate(self.bits);
|
||||||
|
while !field.is_empty() {
|
||||||
|
let flag = <$e>::from_bits(1u32 << field.bits.trailing_zeros()).unwrap();
|
||||||
|
field -= flag;
|
||||||
|
vec.push(flag);
|
||||||
|
}
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_index(&self) -> u32 {
|
||||||
|
if self.bits == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.bits.trailing_zeros();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_random(&self) -> $e {
|
||||||
|
let options = self.to_vec();
|
||||||
|
match options.len() {
|
||||||
|
0 => {
|
||||||
|
return <$e>::empty();
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
return options[0];
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return *random_option(&options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_toggle_strs() -> Vec<String> {
|
||||||
|
let all_options = <$e>::all().to_vec();
|
||||||
|
all_options.iter().map(|i| i.into_string()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_toggle_vals() -> Vec<usize> {
|
||||||
|
let all_options = <$e>::all().to_vec();
|
||||||
|
all_options.iter().map(|i| i.bits() as usize).collect()
|
||||||
}
|
}
|
||||||
return vec;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! to_index_impl {
|
|
||||||
($e:ty) => {
|
|
||||||
pub fn to_index(&self) -> u32 {
|
|
||||||
if self.bits == 0 {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.bits.trailing_zeros();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn random_option<T>(arg: &[T]) -> &T {
|
pub fn random_option<T>(arg: &[T]) -> &T {
|
||||||
&arg[get_random_int(arg.len() as i32) as usize]
|
&arg[get_random_int(arg.len() as i32) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! get_random_impl {
|
|
||||||
($e:ty) => {
|
|
||||||
pub fn get_random(&self) -> $e {
|
|
||||||
let options = self.to_vec();
|
|
||||||
match options.len() {
|
|
||||||
0 => {
|
|
||||||
return <$e>::empty();
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
return options[0];
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return *random_option(&options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// DI
|
// DI
|
||||||
/*
|
/*
|
||||||
0, 0.785398, 1.570796, 2.356194, -3.14159, -2.356194, -1.570796, -0.785398
|
0, 0.785398, 1.570796, 2.356194, -3.14159, -2.356194, -1.570796, -0.785398
|
||||||
|
@ -98,10 +108,24 @@ impl Direction {
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
to_vec_impl! {Direction}
|
|
||||||
get_random_impl! {Direction}
|
fn into_string(self) -> String {
|
||||||
|
match self {
|
||||||
|
Direction::OUT => "Away",
|
||||||
|
Direction::UP_OUT => "Up and Away",
|
||||||
|
Direction::UP => "Up",
|
||||||
|
Direction::UP_IN => "Up and In",
|
||||||
|
Direction::IN => "In",
|
||||||
|
Direction::DOWN_IN => "Down and In",
|
||||||
|
Direction::DOWN => "Down",
|
||||||
|
Direction::DOWN_OUT => "Down and Away",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {Direction}
|
||||||
|
|
||||||
// Ledge Option
|
// Ledge Option
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct LedgeOption : u32
|
pub struct LedgeOption : u32
|
||||||
|
@ -125,10 +149,21 @@ impl LedgeOption {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
to_vec_impl! {LedgeOption}
|
|
||||||
get_random_impl! {LedgeOption}
|
fn into_string(self) -> String {
|
||||||
|
match self {
|
||||||
|
LedgeOption::NEUTRAL => "Neutral Getup",
|
||||||
|
LedgeOption::ROLL => "Roll",
|
||||||
|
LedgeOption::JUMP => "Jump",
|
||||||
|
LedgeOption::ATTACK => "Getup Attack",
|
||||||
|
LedgeOption::WAIT => "Wait",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {LedgeOption}
|
||||||
|
|
||||||
// Tech options
|
// Tech options
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct TechFlags : u32 {
|
pub struct TechFlags : u32 {
|
||||||
|
@ -140,10 +175,19 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TechFlags {
|
impl TechFlags {
|
||||||
to_vec_impl! {TechFlags}
|
fn into_string(self) -> String {
|
||||||
get_random_impl! {TechFlags}
|
match self {
|
||||||
|
TechFlags::NO_TECH => "No Tech",
|
||||||
|
TechFlags::ROLL_F => "Roll Forwards",
|
||||||
|
TechFlags::ROLL_B => "Roll Backwards",
|
||||||
|
TechFlags::IN_PLACE => "Tech In Place",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {TechFlags}
|
||||||
|
|
||||||
// Missed Tech Options
|
// Missed Tech Options
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct MissTechFlags : u32 {
|
pub struct MissTechFlags : u32 {
|
||||||
|
@ -155,13 +199,22 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MissTechFlags {
|
impl MissTechFlags {
|
||||||
to_vec_impl! {MissTechFlags}
|
fn into_string(self) -> String {
|
||||||
get_random_impl! {MissTechFlags}
|
match self {
|
||||||
|
MissTechFlags::GETUP => "Neutral Getup",
|
||||||
|
MissTechFlags::ATTACK => "Getup Attack",
|
||||||
|
MissTechFlags::ROLL_F => "Roll Forwards",
|
||||||
|
MissTechFlags::ROLL_B => "Roll Backwards",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {MissTechFlags}
|
||||||
|
|
||||||
/// Shield States
|
/// Shield States
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
|
||||||
pub enum Shield {
|
pub enum Shield {
|
||||||
None = 0,
|
None = 0,
|
||||||
Infinite = 1,
|
Infinite = 1,
|
||||||
|
@ -169,6 +222,18 @@ pub enum Shield {
|
||||||
Constant = 3,
|
Constant = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Shield {
|
||||||
|
fn into_string(self) -> String {
|
||||||
|
match self {
|
||||||
|
Shield::None => "None",
|
||||||
|
Shield::Infinite => "Infinite",
|
||||||
|
Shield::Hold => "Hold",
|
||||||
|
Shield::Constant => "Constant",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Defensive States
|
// Defensive States
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct Defensive : u32 {
|
pub struct Defensive : u32 {
|
||||||
|
@ -181,10 +246,20 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Defensive {
|
impl Defensive {
|
||||||
to_vec_impl! {Defensive}
|
fn into_string(self) -> String {
|
||||||
get_random_impl! {Defensive}
|
match self {
|
||||||
|
Defensive::SPOT_DODGE => "Spotdodge",
|
||||||
|
Defensive::ROLL_F => "Roll Forwards",
|
||||||
|
Defensive::ROLL_B => "Roll Backwards",
|
||||||
|
Defensive::JAB => "Jab",
|
||||||
|
Defensive::SHIELD => "Shield",
|
||||||
|
_ => "",
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {Defensive}
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum OnOff {
|
pub enum OnOff {
|
||||||
|
@ -192,6 +267,24 @@ pub enum OnOff {
|
||||||
On = 1,
|
On = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OnOff {
|
||||||
|
pub fn from_val(val: u32) -> Option<Self> {
|
||||||
|
match val {
|
||||||
|
1 => Some(OnOff::On),
|
||||||
|
0 => Some(OnOff::Off),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_string(self) -> String {
|
||||||
|
match self {
|
||||||
|
OnOff::Off => "Off",
|
||||||
|
OnOff::On => "On",
|
||||||
|
_ => ""
|
||||||
|
}.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct Action : u32 {
|
pub struct Action : u32 {
|
||||||
const AIR_DODGE = 0x1;
|
const AIR_DODGE = 0x1;
|
||||||
|
@ -234,10 +327,15 @@ impl Action {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
to_vec_impl! {Action}
|
|
||||||
get_random_impl! {Action}
|
pub fn into_string(self) -> String {
|
||||||
|
// TODO: add
|
||||||
|
return self.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {Action}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct AttackAngle : u32 {
|
pub struct AttackAngle : u32 {
|
||||||
const NEUTRAL = 0x1;
|
const NEUTRAL = 0x1;
|
||||||
|
@ -247,10 +345,14 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttackAngle {
|
impl AttackAngle {
|
||||||
to_vec_impl! {AttackAngle}
|
pub fn into_string(self) -> String {
|
||||||
get_random_impl! {AttackAngle}
|
// TODO: add
|
||||||
|
return self.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {AttackAngle}
|
||||||
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct Delay : u32 {
|
pub struct Delay : u32 {
|
||||||
|
@ -289,11 +391,14 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Delay {
|
impl Delay {
|
||||||
to_vec_impl! {Delay}
|
pub fn into_string(self) -> String {
|
||||||
get_random_impl! {Delay}
|
// TODO: add
|
||||||
to_index_impl! {Delay}
|
return self.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra_bitflag_impls! {Delay}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct BoolFlag : u32 {
|
pub struct BoolFlag : u32 {
|
||||||
const TRUE = 0x1;
|
const TRUE = 0x1;
|
||||||
|
@ -301,16 +406,20 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoolFlag {
|
extra_bitflag_impls! {BoolFlag}
|
||||||
to_vec_impl! {BoolFlag}
|
|
||||||
get_random_impl! {BoolFlag}
|
|
||||||
|
|
||||||
|
impl BoolFlag {
|
||||||
pub fn into_bool(self) -> bool {
|
pub fn into_bool(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
BoolFlag::TRUE => true,
|
BoolFlag::TRUE => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_string(self) -> String {
|
||||||
|
// TODO: add
|
||||||
|
return self.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -343,6 +452,50 @@ pub struct TrainingModpackMenu {
|
||||||
pub save_damage: OnOff,
|
pub save_damage: OnOff,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! set_by_str {
|
||||||
|
($obj:ident, $s:ident, $(($field:ident = $rhs:expr))*) => {
|
||||||
|
$(
|
||||||
|
if $s == stringify!($field) {
|
||||||
|
$obj.$field = $rhs.unwrap();
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrainingModpackMenu {
|
||||||
|
pub fn set(&mut self, s: &str, val: u32) {
|
||||||
|
set_by_str!(self, s,
|
||||||
|
(di_state = Direction::from_bits(val))
|
||||||
|
(sdi_state = Direction::from_bits(val))
|
||||||
|
(air_dodge_dir = Direction::from_bits(val))
|
||||||
|
|
||||||
|
(mash_state = Action::from_bits(val))
|
||||||
|
(follow_up = Action::from_bits(val))
|
||||||
|
|
||||||
|
(ledge_state = LedgeOption::from_bits(val))
|
||||||
|
(ledge_delay = Delay::from_bits(val))
|
||||||
|
(tech_state = TechFlags::from_bits(val))
|
||||||
|
(miss_tech_state = MissTechFlags::from_bits(val))
|
||||||
|
|
||||||
|
(shield_state = num::FromPrimitive::from_u32(val))
|
||||||
|
(defensive_state = Defensive::from_bits(val))
|
||||||
|
(oos_offset = Delay::from_bits(val))
|
||||||
|
(reaction_time = Delay::from_bits(val))
|
||||||
|
|
||||||
|
(fast_fall = BoolFlag::from_bits(val))
|
||||||
|
(fast_fall_delay = Delay::from_bits(val))
|
||||||
|
(falling_aerials = BoolFlag::from_bits(val))
|
||||||
|
(aerial_delay = Delay::from_bits(val))
|
||||||
|
(full_hop = BoolFlag::from_bits(val))
|
||||||
|
|
||||||
|
(hitbox_vis = OnOff::from_val(val))
|
||||||
|
(stage_hazards = OnOff::from_val(val))
|
||||||
|
|
||||||
|
(input_delay = Some(val as i32))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fighter Ids
|
// Fighter Ids
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -368,4 +521,9 @@ impl SdiStrength {
|
||||||
SdiStrength::High => 4,
|
SdiStrength::High => 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_string(self) -> String {
|
||||||
|
// TODO: add
|
||||||
|
return "".to_string()
|
||||||
|
}
|
||||||
}
|
}
|
291
src/common/menu.rs
Normal file
291
src/common/menu.rs
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
|
||||||
|
|
||||||
|
use crate::common::*;
|
||||||
|
use skyline::nn::hid::NpadHandheldState;
|
||||||
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
|
use skyline_web::{Background, BootDisplay, Webpage};
|
||||||
|
use ramhorns::{Template, Content};
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct Slider {
|
||||||
|
min: usize,
|
||||||
|
max: usize,
|
||||||
|
index: usize,
|
||||||
|
value: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct Toggle<'a> {
|
||||||
|
title: &'a str,
|
||||||
|
checked: &'a str,
|
||||||
|
index: usize,
|
||||||
|
value: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Toggle<'a> {
|
||||||
|
pub fn new(title: &'a str, checked: bool, value: usize) -> Toggle<'a> {
|
||||||
|
Toggle{
|
||||||
|
title: title,
|
||||||
|
checked: if checked { "is-appear "} else { "is-hidden" },
|
||||||
|
index: 0,
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct SubMenu<'a> {
|
||||||
|
title: &'a str,
|
||||||
|
id: &'a str,
|
||||||
|
toggles: Vec<Toggle<'a>>,
|
||||||
|
sliders: Vec<Slider>,
|
||||||
|
index: usize,
|
||||||
|
check_against: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SubMenu<'a> {
|
||||||
|
pub fn max_idx(&self) -> usize {
|
||||||
|
self.toggles
|
||||||
|
.iter()
|
||||||
|
.max_by(|t1,t2| t1.index.cmp(&t2.index))
|
||||||
|
.map(|t| t.index)
|
||||||
|
.unwrap_or(self.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_toggle(&mut self, title: &'a str, checked: bool, value: usize) {
|
||||||
|
self.toggles.push(Toggle{
|
||||||
|
title: title,
|
||||||
|
checked: if checked { "is-appear "} else { "is-hidden" },
|
||||||
|
index: self.max_idx() + 1,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_slider(&mut self, min: usize, max: usize, value: usize) {
|
||||||
|
self.sliders.push(Slider{
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
index: self.max_idx() + 1,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct Menu<'a> {
|
||||||
|
sub_menus: Vec<SubMenu<'a>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Menu<'a> {
|
||||||
|
pub fn max_idx(&self) -> usize {
|
||||||
|
self.sub_menus
|
||||||
|
.iter()
|
||||||
|
.max_by(|x, y| x.max_idx().cmp(&y.max_idx()))
|
||||||
|
.map(|sub_menu| sub_menu.max_idx())
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_sub_menu(&mut self, title: &'a str, id: &'a str, check_against: usize, toggles: Vec<(&'a str, usize)>, sliders: Vec<(usize,usize,usize)>) {
|
||||||
|
let mut sub_menu = SubMenu {
|
||||||
|
title: title,
|
||||||
|
id: id,
|
||||||
|
toggles: Vec::new(),
|
||||||
|
sliders: Vec::new(),
|
||||||
|
index: self.max_idx() + 1,
|
||||||
|
check_against: check_against
|
||||||
|
};
|
||||||
|
|
||||||
|
for toggle in toggles {
|
||||||
|
sub_menu.add_toggle(toggle.0, (check_against & toggle.1) != 0, toggle.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for slider in sliders {
|
||||||
|
sub_menu.add_slider(slider.0, slider.1, slider.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sub_menus.push(sub_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_sub_menu_sep(&mut self, title: &'a str, id: &'a str, check_against: usize, strs: Vec<&'a str>, vals: Vec<usize>) {
|
||||||
|
let mut sub_menu = SubMenu {
|
||||||
|
title: title,
|
||||||
|
id: id,
|
||||||
|
toggles: Vec::new(),
|
||||||
|
sliders: Vec::new(),
|
||||||
|
index: self.max_idx() + 1,
|
||||||
|
check_against: check_against
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in 0..strs.len() {
|
||||||
|
sub_menu.add_toggle(strs[i], (check_against & vals[i]) != 0, vals[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add sliders?
|
||||||
|
|
||||||
|
self.sub_menus.push(sub_menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! add_bitflag_submenu {
|
||||||
|
($menu:ident, $title:literal, $id:ident, $e:ty) => {
|
||||||
|
paste::paste!{
|
||||||
|
let [<$id _strs>] = <$e>::to_toggle_strs();
|
||||||
|
let [<$id _vals>] = <$e>::to_toggle_vals();
|
||||||
|
|
||||||
|
$menu.add_sub_menu_sep(
|
||||||
|
$title,
|
||||||
|
stringify!($id),
|
||||||
|
MENU_STRUCT.$id.bits() as usize,
|
||||||
|
[<$id _strs>].iter().map(|i| i.as_str()).collect(),
|
||||||
|
[<$id _vals>]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_menu_from_url(s: &str) {
|
||||||
|
let base_url_len = "http://localhost/".len();
|
||||||
|
let total_len = s.len();
|
||||||
|
|
||||||
|
let ss: String = s.chars().skip(base_url_len).take(total_len - base_url_len).collect();
|
||||||
|
|
||||||
|
for toggle_values in ss.split("&") {
|
||||||
|
let toggle_value_split = toggle_values.split("?").collect::<Vec<&str>>();
|
||||||
|
let toggle = toggle_value_split[0];
|
||||||
|
if toggle == "" { continue; }
|
||||||
|
|
||||||
|
let toggle_vals = toggle_value_split[1];
|
||||||
|
|
||||||
|
let mut bits = 0;
|
||||||
|
for toggle_val in toggle_vals.split(",") {
|
||||||
|
if toggle_val == "" { continue; }
|
||||||
|
|
||||||
|
let mut val = toggle_val.parse::<u32>().unwrap();
|
||||||
|
bits = bits | val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
MENU_STRUCT.set(toggle, bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn menu_condition(module_accessor: &mut smash::app::BattleObjectModuleAccessor) -> bool {
|
||||||
|
ControlModule::check_button_on(module_accessor, *CONTROL_PAD_BUTTON_SPECIAL) &&
|
||||||
|
ControlModule::check_button_on_trriger(module_accessor, *CONTROL_PAD_BUTTON_APPEAL_HI)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn render_menu() -> String {
|
||||||
|
let tpl = Template::new(include_str!("../templates/menu.html")).unwrap();
|
||||||
|
|
||||||
|
let mut overall_menu = Menu {
|
||||||
|
sub_menus: Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle/bitflag menus
|
||||||
|
add_bitflag_submenu!(overall_menu, "Mash Toggles", mash_state, Action);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Followup Toggles", follow_up, Action);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Attack Angle", attack_angle, AttackAngle);
|
||||||
|
|
||||||
|
add_bitflag_submenu!(overall_menu, "Ledge Options", ledge_state, LedgeOption);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Ledge Delay", ledge_delay, Delay);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Tech Options", tech_state, TechFlags);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Miss Tech Options", miss_tech_state, MissTechFlags);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Defensive Options", defensive_state, Defensive);
|
||||||
|
|
||||||
|
add_bitflag_submenu!(overall_menu, "OoS Offset", oos_offset, Delay);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Reaction Time", reaction_time, Delay);
|
||||||
|
|
||||||
|
add_bitflag_submenu!(overall_menu, "Fast Fall", fast_fall, BoolFlag);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Fast Fall Delay", fast_fall_delay, Delay);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Falling Aerials", falling_aerials, BoolFlag);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Full Hop", full_hop, BoolFlag);
|
||||||
|
|
||||||
|
add_bitflag_submenu!(overall_menu, "Shield Tilt", shield_tilt, Direction);
|
||||||
|
|
||||||
|
add_bitflag_submenu!(overall_menu, "DI", di_state, Direction);
|
||||||
|
add_bitflag_submenu!(overall_menu, "SDI", sdi_state, Direction);
|
||||||
|
add_bitflag_submenu!(overall_menu, "Airdodge Direction", air_dodge_dir, Direction);
|
||||||
|
|
||||||
|
overall_menu.add_sub_menu(
|
||||||
|
"Shield Toggles",
|
||||||
|
"shield_state",
|
||||||
|
MENU_STRUCT.shield_state as usize,
|
||||||
|
[
|
||||||
|
("None", Shield::None as usize),
|
||||||
|
("Hold", Shield::Hold as usize),
|
||||||
|
("Infinite", Shield::Infinite as usize),
|
||||||
|
].to_vec(),
|
||||||
|
[].to_vec()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Slider menus
|
||||||
|
overall_menu.add_sub_menu(
|
||||||
|
"Input Delay",
|
||||||
|
"input_delay",
|
||||||
|
// unnecessary for slider?
|
||||||
|
MENU_STRUCT.input_delay as usize,
|
||||||
|
[].to_vec(),
|
||||||
|
[
|
||||||
|
(0, 10, MENU_STRUCT.input_delay as usize)
|
||||||
|
].to_vec()
|
||||||
|
);
|
||||||
|
|
||||||
|
// SDI strength
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: OnOff flags... need a different sort of submenu.
|
||||||
|
overall_menu.add_sub_menu(
|
||||||
|
"Hitbox Visualization",
|
||||||
|
"hitbox_vis",
|
||||||
|
MENU_STRUCT.hitbox_vis as usize,
|
||||||
|
[
|
||||||
|
("Off", OnOff::Off as usize),
|
||||||
|
("On", OnOff::On as usize),
|
||||||
|
].to_vec(),
|
||||||
|
[].to_vec()
|
||||||
|
);
|
||||||
|
overall_menu.add_sub_menu(
|
||||||
|
"Stage Hazards",
|
||||||
|
"stage_hazards",
|
||||||
|
MENU_STRUCT.stage_hazards as usize,
|
||||||
|
[
|
||||||
|
("Off", OnOff::Off as usize),
|
||||||
|
("On", OnOff::On as usize),
|
||||||
|
].to_vec(),
|
||||||
|
[].to_vec()
|
||||||
|
);
|
||||||
|
overall_menu.add_sub_menu(
|
||||||
|
"Mash In Neutral",
|
||||||
|
"mash_in_neutral",
|
||||||
|
MENU_STRUCT.mash_in_neutral as usize,
|
||||||
|
[
|
||||||
|
("Off", OnOff::Off as usize),
|
||||||
|
("On", OnOff::On as usize),
|
||||||
|
].to_vec(),
|
||||||
|
[].to_vec()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
tpl.render(&overall_menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn spawn_menu() {
|
||||||
|
let data = render_menu();
|
||||||
|
|
||||||
|
let response = Webpage::new()
|
||||||
|
.background(Background::BlurredScreenshot)
|
||||||
|
.file("index.html", &data)
|
||||||
|
.htdocs_dir("contents")
|
||||||
|
.boot_display(BootDisplay::BlurredScreenshot)
|
||||||
|
.boot_icon(true)
|
||||||
|
.open()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let last_url = response.get_last_url().unwrap();
|
||||||
|
|
||||||
|
set_menu_from_url(last_url);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
|
pub mod menu;
|
||||||
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
use smash::app::{self, lua_bind::*};
|
use smash::app::{self, lua_bind::*};
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -2,14 +2,20 @@
|
||||||
#![feature(with_options)]
|
#![feature(with_options)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
|
|
||||||
mod common;
|
pub mod common;
|
||||||
mod hazard_manager;
|
mod hazard_manager;
|
||||||
mod hitbox_visualizer;
|
mod hitbox_visualizer;
|
||||||
mod training;
|
mod training;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate num_derive;
|
||||||
|
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
use training::combo::FRAME_ADVANTAGE;
|
use training::combo::FRAME_ADVANTAGE;
|
||||||
|
|
||||||
|
@ -39,6 +45,7 @@ macro_rules! c_str {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
#[skyline::main(name = "training_modpack")]
|
#[skyline::main(name = "training_modpack")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
macro_rules! log {
|
macro_rules! log {
|
||||||
|
@ -92,4 +99,4 @@ pub fn main() {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
8
src/templates/check.svg
Normal file
8
src/templates/check.svg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="レイヤー_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||||
|
y="0px" viewBox="-15 -10 80 80" enable-background="new 0 0 80 80" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M 6,36 18,48 48,6" style="stroke:#FFFFFF; stroke-width:6; fill:none" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 447 B |
BIN
src/templates/frame_adv.webp
Normal file
BIN
src/templates/frame_adv.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 126 KiB |
221
src/templates/menu.html
Normal file
221
src/templates/menu.html
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="./help/css/common.css" />
|
||||||
|
<link rel="stylesheet" href="./help/css/qa.css" />
|
||||||
|
<link id="font-stylesheet" rel="stylesheet" href="./help/css/font.css">
|
||||||
|
<link rel="stylesheet" href="./help/css/keyword.css">
|
||||||
|
<link href="./nouislider.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
@-moz-document url-prefix() {
|
||||||
|
@font-face {
|
||||||
|
font-family: '-webkit-standard';
|
||||||
|
src: url('nintendo_udsg-r_std_003.ttf');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overwrite padding from keyword stuff. */
|
||||||
|
.l-main-content {
|
||||||
|
padding: 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Somehow isn't getting passed through from default css. */
|
||||||
|
.ret-icon-shadow {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
top: 3px;
|
||||||
|
left: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 58px;
|
||||||
|
height: 58px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script src="./help/js/jquery-3.3.1.min.js"></script>
|
||||||
|
<script src="./help/common/js/wsnd.min.js"></script>
|
||||||
|
<script src="./help/common/js/keyhelp.js"></script>
|
||||||
|
<script src="./help/js/common.js"></script>
|
||||||
|
<script src="./help/js/qa.js"></script>
|
||||||
|
<script src="./nouislider.min.js"></script>
|
||||||
|
|
||||||
|
<div class="l-header">
|
||||||
|
<div class="l-header-title">
|
||||||
|
<div class="header-title f-u-bold"><span data-msgcom="true" data-msgid="textbox_id-10020">Ultimate Training
|
||||||
|
Modpack Menu</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="header">
|
||||||
|
<a id="ret-button" tabindex="-1" class="header-decoration" href="javascript:goBackHook();"
|
||||||
|
nx-se-disabled="">
|
||||||
|
<div class="ret-icon-wrapper">
|
||||||
|
<img class="ret-icon-shadow is-appear" ref="./help/img/icon/m_retnormal.svg"
|
||||||
|
src="./help/img/icon/m_retnormal.svg">
|
||||||
|
<img class="ret-icon is-appear" ref="./help/img/icon/m_retnormal.svg"
|
||||||
|
src="./help/img/icon/m_retnormal.svg">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Script the part below via templating. Overall structure is perhaps
|
||||||
|
[
|
||||||
|
l-qa qa [id=qa-{{menuName}} tabindex="{{index}}"] {
|
||||||
|
// make question for {{menuName}}
|
||||||
|
// make answer with l-grid : l-item list for options
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Remember to set make max keyword size greater than 23!
|
||||||
|
-->
|
||||||
|
{{#sub_menus}}
|
||||||
|
<div class="l-qa">
|
||||||
|
<a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this)"
|
||||||
|
onblur="defocusQA(this)" onclick="openAnswer(this)" nx-se-disabled="">
|
||||||
|
<div class="question-outer">
|
||||||
|
<div class="question-border">
|
||||||
|
<div id="question-{{id}}" class="question scuffle-thema">
|
||||||
|
<img class="question-icon" ref="./{{id}}.svg" />
|
||||||
|
<p class="question-message f-u-bold"><span data-msgid="textbox_id-7">{{title}}</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="answer-border-{{id}}" class="answer-border-outer is-hidden">
|
||||||
|
<div class="l-main">
|
||||||
|
<ul class="l-grid" id="{{id}}">
|
||||||
|
{{#toggles}}
|
||||||
|
<li class="l-item" val="{{value}}">
|
||||||
|
<div class="keyword-button-outer"> <a tabindex="{{index}}"
|
||||||
|
class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);" nx-se-disabled="">
|
||||||
|
<div class="button-icon-wrapper"> <img class="button-icon {{checked}}"
|
||||||
|
ref="./check.svg" src="./check.svg">
|
||||||
|
</div>
|
||||||
|
<div class="button-msg-wrapper">
|
||||||
|
<div class="keyword-message f-u-bold">{{title}}</div>
|
||||||
|
</div>
|
||||||
|
</a> </div>
|
||||||
|
</li>
|
||||||
|
{{/toggles}}
|
||||||
|
{{#sliders}}
|
||||||
|
<li class="l-item" val="{{value}}">
|
||||||
|
<div class="keyword-button-outer"> <a tabindex="{{index}}"
|
||||||
|
class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);" nx-se-disabled="">
|
||||||
|
<div class="button-icon-wrapper"> <img class="button-icon {{checked}}"
|
||||||
|
ref="./check.svg" src="./check.svg">
|
||||||
|
</div>
|
||||||
|
<div class="button-msg-wrapper">
|
||||||
|
<div class="keyword-message f-u-bold">
|
||||||
|
<div name='range_slider' oninput="this.nextElementSibling.value = this.value">
|
||||||
|
</div>
|
||||||
|
<output>{{value}}</output>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a> </div>
|
||||||
|
</li>
|
||||||
|
{{/sliders}}
|
||||||
|
{{#range_sliders}}
|
||||||
|
<li class="l-item" val="{{value}}">
|
||||||
|
<div class="keyword-button-outer"> <a tabindex="{{index}}"
|
||||||
|
class="flex-button keyword-button scuffle-thema" href="javascript:void(0)" onclick="clickToggle(this);" nx-se-disabled="">
|
||||||
|
<div class="button-icon-wrapper"> <img class="button-icon {{checked}}"
|
||||||
|
ref="./check.svg" src="./check.svg">
|
||||||
|
</div>
|
||||||
|
<div class="button-msg-wrapper">
|
||||||
|
<div class="keyword-message f-u-bold">
|
||||||
|
<div name="{{id}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a> </div>
|
||||||
|
</li>
|
||||||
|
{{/range_sliders}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{/sub_menus}}
|
||||||
|
{{#sub_menus}}
|
||||||
|
{{#sliders}}
|
||||||
|
<script>
|
||||||
|
// todo: loop through
|
||||||
|
noUiSlider.create(document.getElementsByName('range_slider')[0], {
|
||||||
|
start: {{value}},
|
||||||
|
range: {
|
||||||
|
'min': {{min}},
|
||||||
|
'max': {{max}}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{/sliders}}
|
||||||
|
{{/sub_menus}}
|
||||||
|
<script>
|
||||||
|
if (isNx) {
|
||||||
|
window.nx.footer.setAssign('B', '', goBackHook, {
|
||||||
|
se: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function goBackHook() {
|
||||||
|
// Use this function to check menu settings on exit, return through localhost
|
||||||
|
|
||||||
|
$('.is-focused').addClass('is-pause-anim')
|
||||||
|
$('#ret-button').addClass('is-focus')
|
||||||
|
|
||||||
|
disabledOtherLink()
|
||||||
|
|
||||||
|
playSound('cancel')
|
||||||
|
|
||||||
|
fadeOutPage(function () {
|
||||||
|
window.history.back()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
var url = "http://localhost/"
|
||||||
|
|
||||||
|
$(".l-grid").each(function() {
|
||||||
|
var section = this.id;
|
||||||
|
|
||||||
|
url += section + "?"
|
||||||
|
|
||||||
|
var children = this.children;
|
||||||
|
for (var i = 0; i < children.length; i++) {
|
||||||
|
var child = children[i];
|
||||||
|
if (child.innerHTML.includes("is-appear")) {
|
||||||
|
url += child.getAttribute("val") + ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url += "&"
|
||||||
|
});
|
||||||
|
|
||||||
|
location.href = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickToggle(e) {
|
||||||
|
var toggleImage = e.children[0];
|
||||||
|
if (toggleImage.innerHTML.includes("is-appear")) {
|
||||||
|
toggleImage.innerHTML = toggleImage.innerHTML.replace("is-appear", "is-hidden");
|
||||||
|
} else {
|
||||||
|
toggleImage.innerHTML = toggleImage.innerHTML.replace("is-hidden", "is-appear");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
77
src/templates/slider.js
Normal file
77
src/templates/slider.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
var slider = document.getElementById('slider');
|
||||||
|
const STEP = 5
|
||||||
|
|
||||||
|
function checkGamepad(index, gamepad) {
|
||||||
|
// Gets the current value of the sliders
|
||||||
|
var current_value = slider.noUiSlider.get();
|
||||||
|
|
||||||
|
// Displays it on the HTML page
|
||||||
|
document.getElementById("input").innerHTML = current_value;
|
||||||
|
|
||||||
|
|
||||||
|
// Checks to see if the L-button is pressed
|
||||||
|
if(gamepad.buttons[4].pressed){
|
||||||
|
// If the right-side of the slider is focused on, subtract STEP from the current value
|
||||||
|
if(document.activeElement.classList.contains("noUi-handle-upper")){
|
||||||
|
slider.noUiSlider.set(
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
parseInt(current_value[1]) - STEP
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// If the left-side of the slider is focused on, subtract STEP from the current value
|
||||||
|
else if(document.activeElement.classList.contains("noUi-handle-lower")){
|
||||||
|
slider.noUiSlider.set(
|
||||||
|
[
|
||||||
|
parseInt(current_value[0]) - STEP,
|
||||||
|
null
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Checks to see if the R-button is pressed
|
||||||
|
else if(gamepad.buttons[5].pressed){
|
||||||
|
// If the right-side of the slider is focused on, add STEP to the current value
|
||||||
|
if(document.activeElement.classList.contains("noUi-handle-upper")){
|
||||||
|
slider.noUiSlider.set(
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
parseInt(current_value[1]) + STEP
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// If the left-side of the slider is focused on, add STEP to the current value
|
||||||
|
else if(document.activeElement.classList.contains("noUi-handle-lower")){
|
||||||
|
slider.noUiSlider.set(
|
||||||
|
[
|
||||||
|
parseInt(current_value[0]) + STEP,
|
||||||
|
null
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = function(){
|
||||||
|
// Creates the slider
|
||||||
|
noUiSlider.create(slider, {
|
||||||
|
start: [20, 80],
|
||||||
|
connect: true,
|
||||||
|
range: {
|
||||||
|
'min': 0,
|
||||||
|
'max': 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listens to see if the gamepad is connected
|
||||||
|
window.addEventListener("gamepadconnected", function (e) {
|
||||||
|
document.getElementById("input").innerHTML = "Gamepad Connected!";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sets an interval and runs a function every 100 seconds to check the gamepads
|
||||||
|
setInterval(function () {
|
||||||
|
var gpl = navigator.getGamepads();
|
||||||
|
if (gpl.length > 0) {
|
||||||
|
for (var i = 0; i < gpl.length; i++) {
|
||||||
|
checkGamepad(i, gpl[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
30
src/test.rs
Normal file
30
src/test.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/// Recommended to run with the following command:
|
||||||
|
/// `RUSTFLAGS=-Awarnings cargo test --target=x86_64-unknown-linux-gnu`
|
||||||
|
/// But you can replace the target with your PC's target.
|
||||||
|
|
||||||
|
/// This will run and render the default menu in your default HTML opening program, ideally Chrome.
|
||||||
|
#[test]
|
||||||
|
fn render_menu() {
|
||||||
|
unsafe {
|
||||||
|
use std::process::Command;
|
||||||
|
use crate::common::menu::render_menu;
|
||||||
|
|
||||||
|
let folder_path = "../contents.htdocs";
|
||||||
|
let path = "../contents.htdocs/index.html";
|
||||||
|
|
||||||
|
assert!(std::path::Path::new(folder_path).exists(), "Needs required folder: ../contents.htdocs!");
|
||||||
|
|
||||||
|
std::fs::write(path, render_menu()).unwrap();
|
||||||
|
|
||||||
|
let (cmd, args) = if wsl::is_wsl() || cfg!(target_os = "windows") {
|
||||||
|
("cmd.exe", ["/C", "start", path])
|
||||||
|
} else {
|
||||||
|
("sh", ["-c", "open", path])
|
||||||
|
};
|
||||||
|
|
||||||
|
Command::new(cmd)
|
||||||
|
.args(&args)
|
||||||
|
.output()
|
||||||
|
.expect("failed to open rendered HTML file");
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,6 +98,10 @@ fn once_per_frame_per_fighter(
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
if crate::common::menu::menu_condition(module_accessor) {
|
||||||
|
crate::common::menu::spawn_menu();
|
||||||
|
}
|
||||||
|
|
||||||
input_record::get_command_flag_cat(module_accessor);
|
input_record::get_command_flag_cat(module_accessor);
|
||||||
combo::get_command_flag_cat(module_accessor);
|
combo::get_command_flag_cat(module_accessor);
|
||||||
hitbox_visualizer::get_command_flag_cat(module_accessor);
|
hitbox_visualizer::get_command_flag_cat(module_accessor);
|
||||||
|
|
Loading…
Reference in a new issue