besteon / Ironmon-Tracker

A Lua script for the Bizhawk/mGBA emulator compatible with Pokemon Fire Red, Leaf Green, Ruby, Sapphire, and Emerald that tracks relevant data for the IronMon challenge.
MIT License
129 stars 45 forks source link

Feature Request: Investigate if actual BST values can be read from the game #311

Closed UTDZac closed 1 year ago

UTDZac commented 1 year ago

While this is not IronMon related, but still a feature that some have requested. Seems simple enough.

In some randomizer programs (not Randomizer ZX), there is an option to randomize the total BST value of each Pokemon, meaning some end up significantly weaker or stronger than their originally defined values. Currently in the Tracker the BST values are just hard-coded. Ideally the PokemonData.lua read from memory function can detect changes to BST and read these in as well.

Along these lines, it may be worthwhile investigating if other hard-coded Data (Pokemon/Move/Ability) can be read from the game memory itself.

UTDZac commented 1 year ago

From BrentSpector's randomizer 1.10.3+

https://github.com/brentspector/universal-pokemon-randomizer

image

jtigues commented 1 year ago

Noting that there are some rounding errors even when the BSTs are not randomized. This was the Metang in my Snorlax Kaizo seed: 375|METANG |STEEL/PSYCHIC | 67| 67| 140| 74| 23| 50|BLAZE |------- |

Normally Metang has a BST of 420, but the rounding errors bring it to 421, so we would need some sort of margin of error when checking

UTDZac commented 1 year ago

Looks like this information is available here:

https://github.com/pret/pokefirered/blob/56f8b1a47cf6cf10b398536e43d9d48464c263d8/include/pokemon.h#L203-L208

/* 0x00 */ u8 baseHP; /* 0x01 */ u8 baseAttack; /* 0x02 */ u8 baseDefense; /* 0x03 */ u8 baseSpeed; /* 0x04 */ u8 baseSpAttack; /* 0x05 */ u8 baseSpDefense;

Even if there are rounding errors because of the way the randomizer chops off stuff, I still think thats fine. If BST's are randomized, could likely display them as BST~ 421. The trick to displaying this indicator is to determine if the BSTs of most Pokemon have been randomized, or if several just have that rounding error.

TheRealTaintedWolf commented 1 year ago

I think I could read that data very close to what I did for friendship and total it up and give it a few points of wiggle room to see "If it is random". I think i've somewhat done this in a local copy and got it to pull when BST is updated. Should I try to tackle this?

Example: Edited Bulbasaur and Chansey's BST: image

UTDZac commented 1 year ago

Sure absolutely, go for it. One thing to keep in mind is that if you are reading in game data from memory, you want to make sure it works for all games and all languages. For example, German FireRed has different address offsets than English. And Emerald has different offsets than FireRed. You can see these separated address definitions in GameSettings.lua.

TheRealTaintedWolf commented 1 year ago

I'm reading these off the GameSettings.gBaseStats like the standard ability/types do

local statCurrentData = Memory.readword(GameSettings.gBaseStats + (pokemonID * 0x1C) + 0x00)
local statTotal = Utils.getbits(statCurrentData, 0, 8)
<repeats for each base stat>

If understood what I read this should function correctly, since gBaseStats should point to the "start" of the memory where Pokémon data is stored.

This is the same way I did Friendship, and if it is wrong we need to fix that too.

UTDZac commented 1 year ago

Completed as of d303e438b2b62bcf70922a60020fc6f05d923730

The actual BST of the Pokémon in game is now represented in PokemonData.Pokemon as the bstCalculated property. For example, Shuckle's normal BST is 505, but if I check all of its base stats from the game and add them together I get 504.

image

I've reflected this total in the log too (note: its not calculated from the log, its the actually values in the game rom). Outside of the log, its just shown as 505 per normal, since a player doesnt know true values of each base stat until the log is opened.

The bstCalculated total is just a total. If there is a want in the future for this to be separated out to each individual stat (hp/atk/def/spa/spd/spe), that isn't a tough fix. Alternatively, you can just write an extension to handle this and use it as you see fit. Simply utilize the code example in PokemonData.buildPokemonData()