symbols: the six WRAM names the engagement rewards read

wSpriteIndex, wWalkCounter, wMapSpriteExtraData, wToggleableObjectFlags,
wToggleableObjectList and wObtainedHiddenItemsFlags, resolved by
tools/resolve_wram.py from ram/wram.asm at the pinned commit and bracketed by
addresses symbols.rs already carries. Two of the brackets needed the tool to
count NUM_STATS and NUM_CITY_MAPS, which the decomp defines as const_value over
an enumeration; both are now counted up to the line that defines them.
This commit is contained in:
acamilo 2026-09-23 11:06:07 +00:00
parent 7784a9d172
commit ed0080ab2c
3 changed files with 63 additions and 4 deletions

View file

@ -28,9 +28,11 @@ pub mod ram {
pub const wJoyIgnore: u16 = 0xcd6b; // 52587
pub const wNumMovesMinusOne: u16 = 0xcd6c; // 52588
pub const wBattleResult: u16 = 0xcf0b; // 53003
pub const wSpriteIndex: u16 = 0xcf13; // 53011
pub const wItemList: u16 = 0xcf7b; // 53115
pub const wListMenuID: u16 = 0xcf94; // 53140
pub const wFontLoaded: u16 = 0xcfc4; // 53188
pub const wWalkCounter: u16 = 0xcfc5; // 53189
pub const wEnemyMonSpecies: u16 = 0xcfe5; // 53221
pub const wEnemyMonHP: u16 = 0xcfe6; // 53222
pub const wEnemyMonLevel: u16 = 0xcff3; // 53235
@ -71,11 +73,15 @@ pub mod ram {
pub const wSignCoords: u16 = 0xd4b1; // 54449
pub const wSignTextIDs: u16 = 0xd4d1; // 54481
pub const wNumSprites: u16 = 0xd4e1; // 54497
pub const wMapSpriteExtraData: u16 = 0xd504; // 54532
pub const wTilesetBank: u16 = 0xd52b; // 54571
pub const wTilesetBlocksPtr: u16 = 0xd52c; // 54572
pub const wTilesetCollisionPtr: u16 = 0xd530; // 54576
pub const wTilesetTalkingOverTiles: u16 = 0xd532; // 54578
pub const wNumHoFTeams: u16 = 0xd5a2; // 54690
pub const wToggleableObjectFlags: u16 = 0xd5a6; // 54694
pub const wToggleableObjectList: u16 = 0xd5ce; // 54734
pub const wObtainedHiddenItemsFlags: u16 = 0xd6f0; // 55024
pub const wStatusFlags5: u16 = 0xd730; // 55088
pub const wStatusFlags6: u16 = 0xd732; // 55090
pub const wStatusFlags7: u16 = 0xd733; // 55091

View file

@ -209,6 +209,22 @@ EXTRA_RAM = (
# services/flysim/tools/resolve_wram.py is the second reading of it, from ram/wram.asm at
# this commit, bracketed by wFontLoaded and wForcePlayerToChooseMon.
'wCapturedMonSpecies',
# The engagement rewards (`docs/rewards-learning.md`, the operator 2026-09-23).
# `talk`: DisplayTextID copies its argument -- the sprite slot, or a sign's text id --
# into wSpriteIndex before it looks the text up, and the overworld's A press only
# reaches it while wWalkCounter is zero. `item`: an item ball is a sprite whose
# wMapSpriteExtraData entry is (item id, 0) -- LoadMapHeader writes that shape for
# an ITEM-flagged object_event and no other -- found in the map's
# wToggleableObjectList; PickUpItem hides it by setting its global bit in
# wToggleableObjectFlags, and FoundHiddenItemText sets the hidden item's bit in
# wObtainedHiddenItemsFlags, each only after GiveItem succeeded.
# services/flysim/tools/resolve_wram.py is the second reading of all six.
'wSpriteIndex',
'wWalkCounter',
'wMapSpriteExtraData',
'wToggleableObjectFlags',
'wToggleableObjectList',
'wObtainedHiddenItemsFlags',
)

View file

@ -57,6 +57,22 @@ WANTED = {
# this one caught", and the only signal that needs no second rule to tell a
# catch apart from a gift, a trade or an evolution.
'wCapturedMonSpecies': 'the species a ball just caught, 0 for none',
# The engagement rewards (`docs/rewards-learning.md`, the operator 2026-09-23).
# DisplayTextID stores its argument here -- a sprite slot, or a sign's text id --
# before it looks the text up, so it names what a conversation is with.
'wSpriteIndex': "DisplayTextID's argument, a sprite slot or a text id",
# Non-zero for the frames of a step; the overworld only reads an A press at zero.
'wWalkCounter': 'frames left in the step the player is taking',
# Two bytes per sprite slot: (item id, 0) for an ITEM-flagged object_event,
# (trainer class, trainer number) for a TRAINER one, zeroes otherwise.
'wMapSpriteExtraData': 'per sprite slot: item id, or trainer class and number',
# One bit per global toggleable object; PickUpItem's HideObject sets an item
# ball's bit once GiveItem has succeeded.
'wToggleableObjectFlags': 'global hidden bits of every toggleable object',
# The current map's (sprite slot, global toggleable index) pairs, $ff-terminated.
'wToggleableObjectList': "this map's toggleable sprites and their global indices",
# One bit per hidden item, set by FoundHiddenItemText once GiveItem succeeded.
'wObtainedHiddenItemsFlags': 'hidden items already found',
}
@ -76,9 +92,33 @@ WANTED = {
COUNTED = {
'NUM_HMS': ('constants/item_constants.asm', r'^\s*add_hm\s+\w+'),
'NUM_TMS': ('constants/item_constants.asm', r'^\s*add_tm\s+\w+'),
# The engagement rewards need two more, for the same reason: each is an
# `EQU const_value` over an enumeration, and each is the size of a declaration
# the cursor has to cross. `ds NUM_STATS` sits between wFontLoaded and
# wTrainerClass, the bracket of wWalkCounter; `flag_array NUM_CITY_MAPS` sits
# between wNumHoFTeams and wStatusFlags5, the bracket of the toggleable-object
# and hidden-item flags. Both are counted only up to the line that defines
# them, which is where `const_value` is read.
'NUM_STATS': (
'constants/battle_constants.asm', r'^\s*const\s+STAT_\w+', r'^DEF NUM_STATS\b'
),
'NUM_CITY_MAPS': (
'constants/map_constants.asm', r'^\s*map_const\s+\w+', r'^DEF NUM_CITY_MAPS\b'
),
}
def count_in(root: Path, path: str, pattern: str, stop: str | None = None) -> int:
"""Lines of `path` matching `pattern`, up to the first line matching `stop`."""
text = (root / path).read_text()
if stop is not None:
match = re.search(stop, text, re.M)
if match is None:
raise SystemExit(f'{path}: no line matches {stop}')
text = text[: match.start()]
return len(re.findall(pattern, text, re.M))
def pinned(text: str) -> dict[str, int]:
"""Every address `symbols.rs` carries today, by symbol name."""
return {
@ -95,10 +135,7 @@ def constants(root: Path) -> dict[str, int]:
BLOCK_WIDTH`). A name whose expression never becomes evaluable is simply left
out, which kills the cursor at any declaration that uses it.
"""
counted = {
name: len(re.findall(pattern, (root / path).read_text(), re.M))
for name, (path, pattern) in COUNTED.items()
}
counted = {name: count_in(root, *spec) for name, spec in COUNTED.items()}
pending: dict[str, str] = {}
sources = sorted((root / 'constants').glob('*.asm')) + sorted(
(root / 'constants').glob('*.inc')