With the new version of Visual Studio bringing C# 12, we can revise our logic for better readability as well as use new methods/APIs introduced in the .NET 8.0 BCL.
Updates from net46->net7, dropping support for mono in favor of using the latest runtime (along with the performance/API improvements). Releases will be posted as 64bit only for now.
Refactors a good amount of internal API methods to be more performant and more customizable for future updates & fixes.
Adds functionality for Batch Editor commands to `>`, `<` and <=/>=
TID/SID properties renamed to TID16/SID16 for clarity; other properties exposed for Gen7 / display variants.
Main window has a new layout to account for DPI scaling (8 point grid)
Fixed: Tatsugiri and Paldean Tauros now output Showdown form names as Showdown expects
Changed: Gen9 species now interact based on the confirmed National Dex IDs (closes#3724)
Fixed: Pokedex set all no longer clears species with unavailable non-base forms (closes#3720)
Changed: Hyper Training suggestions now apply for level 50 in SV. (closes#3714)
Fixed: B2/W2 hatched egg met locations exclusive to specific versions are now explicitly checked (closes#3691)
Added: Properties for ribbon/mark count (closes#3659)
Fixed: Traded SV eggs are now checked correctly (closes#3692)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
More in line with modernizing the codebase with latest c# syntax
improve web-qr decode speed slightly (no linq skiptake)
get money/coin mask without a temporary string (lol performance)
* Initial bred moveset validation logic
Unpeel the inheritance via recursion and permitted moves
* Volt tackle considerations
* Optimize out empty slot skips
* Add tests, fix off-by-one's
* Require all base moves if empty slot in moveset
* Add test to prove failure per Anubis' provided test
* Tweak enum labels for easier debugging
When two enums share the same underlying value, the ToString/name of the value may be either of the two (or the last defined one, in my debugging). Just give it a separate magic value.
* Fix recursion oopsie
Also check for scenario where no-base-moves but not enough moves to push base moves out
* Add Crystal tutor checks
* Add specialized gen2 verification method
Game loops through father's moves and pushes in one iteration, rather than checking by type.
* Add another case with returning base move
* Add push-out requirement for re-added base moves
* Minor tweaks
Condense tests, fix another off-by-one noticed when creating tests
* Disallow inherited parent levelup moves
Disallow volt tackle on Gen2/R/S
* Split MoveBreed into generation specific classes
Gen2 behaves slightly different from Gen3/4, which behaves slightly different from Gen5... and Gen6 behaves differently too.
Add some xmldoc as the api is starting to solidify
* Add method overload that returns the parse
Verify that the parse order is as expected
* Add reordering suggestion logic
Try sorting first, then go nuclear with rebuilding.
* Return base moves if complete fail
* Set base moves when generating eggs, only.
* Use breed logic to check for egg ordering legality
Don't bother helping for split-breed species
See the EncounterSlotDumper with the memoization logic & json tree listing.
Simplifies things a lot, and improves checking speed. Unreachable trees are now treated the same as no-trees maps.
ez 1.5KB reduction in file size :P
Move form-info logic from FormConverter to AltFormInfo; now FormConverter is entirely form=>string[]
Add a bunch of xmldoc
Make pogo no-end-date cmp agaisnt UTCnow rather than local now.
Adds Nickname checks, thanks @ShadowMario3 for grabbing these into separate text files from Bulbapedia.
I reordered all the encounters to match Bulbapedia; each level is denoted if different if it can be sourced from RBY.
PKHeX.Core now accepts generated pkl binaries from PoGoEncounterTool (PGET).
Refer to pporg's repo. This will be treated like event data; occasionally updated.
* Rework gen1 slot loading
Slot templates are precomputed from ROM data and just loaded straight in, with tight coupling to the encounter area (grouped by slot types).
* Revise fuzzy met check for underleveled wild evos
Example: Level 23 poliwhirl in RBY as a level 50 poliwhirl, will assume the chain is 25-50 for poliwhirl (as poliwag evolves at 25). Instead of revising the origin chain, just ignore the evo min level in the comparison.
Previous commit fixed it for gen1.
* Rework gen2-4 slot loading
Gen4 not finished, Type Encounter data and some edge encounters not recognizing yet...
* Add feebas slots for old/good encounters
* Begin moving properties
Great news! Gen5-7 need to be de-dumbed like Gen1-4.
Then I can remove the bang (!) on the Area accessor and ensure that it's never null!
* Split off XD pokespot slot encounter table type
* Set area in constructor
* Deduplicate g3 roaming encounters
* Deduplicate xd encounter locations (rebattle)
Only difference is met location; no need to create 500 extra encounter objects. A simple contains check is ok (rarely in gen3 format).
* Make all slots have a readonly reference to their parent area
* Minor clean
* Remove "Safari" slot type flag
Can be determined via other means (generation-location), allows us to reduce the size of SlotType member to a byte
Output of slot binaries didn't preserve the Safari flag anyway.
* Update SlotType.cs
* Handle type encounters correctly
* Merge safari area into regular xy area
* Merge dexnav accessor logic
* fix some logic so that tests pass again
rearrange g5 dw init to be done outside of static constructor (initializer instead)
PIDGenerator: friend safari slots now generate with required flawless IV count
* Add cianwood tentacool gift encounter
* Remove unnecessary abstractions
Fake area just returned a slot; since Slots have a non-null reference to the area, we can just return the slot and use the API to grab a list of possible slots for the chain.
Increase restrictiveness of location/type get-set operations
* Minor tweaks, pass parameters
DexNav observed state isn't necessary to use, only need to see if it's possible to dexnav. Now that we have metadata for slots, we can.
* Remove unused legality tables
* Added PokeWalker Courses, Watts, and Steps editing
* Use util method for getting bitflags
* Keep old cheat method
Change signature so that the default value passed is to unlock all; can pass 0 instead to lock all
* Pass reference to derived sav4-type object
Wev'e already type-tested once, capture the reference and pass it into the appropriate load/save methods.
* Add control anchoring for window resizing
Also widen the labels for localization (longer strings possibly)
Certain Mark values (ribbon) are only obtainable if the encounter was
obtained in some weather (I really hope there's no crossover cases for
this), and non-symbol encounters can't wander to another zone.
I wonder if you can wander from one zone with one exclusive weather, to
another zone, and get an 'unobtainable' mark (with the new zone's
weather) on the crossover mon's weather. yikes lmao
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
Derived from WC7 with minor alterations (dynamic OT/Nickname which is
stored in the Full data). Since the 0x108 is not stored in the save
file, just keep the full data around.