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 wJoyIgnore: u16 = 0xcd6b; // 52587
pub const wNumMovesMinusOne: u16 = 0xcd6c; // 52588 pub const wNumMovesMinusOne: u16 = 0xcd6c; // 52588
pub const wBattleResult: u16 = 0xcf0b; // 53003 pub const wBattleResult: u16 = 0xcf0b; // 53003
pub const wSpriteIndex: u16 = 0xcf13; // 53011
pub const wItemList: u16 = 0xcf7b; // 53115 pub const wItemList: u16 = 0xcf7b; // 53115
pub const wListMenuID: u16 = 0xcf94; // 53140 pub const wListMenuID: u16 = 0xcf94; // 53140
pub const wFontLoaded: u16 = 0xcfc4; // 53188 pub const wFontLoaded: u16 = 0xcfc4; // 53188
pub const wWalkCounter: u16 = 0xcfc5; // 53189
pub const wEnemyMonSpecies: u16 = 0xcfe5; // 53221 pub const wEnemyMonSpecies: u16 = 0xcfe5; // 53221
pub const wEnemyMonHP: u16 = 0xcfe6; // 53222 pub const wEnemyMonHP: u16 = 0xcfe6; // 53222
pub const wEnemyMonLevel: u16 = 0xcff3; // 53235 pub const wEnemyMonLevel: u16 = 0xcff3; // 53235
@ -71,11 +73,15 @@ pub mod ram {
pub const wSignCoords: u16 = 0xd4b1; // 54449 pub const wSignCoords: u16 = 0xd4b1; // 54449
pub const wSignTextIDs: u16 = 0xd4d1; // 54481 pub const wSignTextIDs: u16 = 0xd4d1; // 54481
pub const wNumSprites: u16 = 0xd4e1; // 54497 pub const wNumSprites: u16 = 0xd4e1; // 54497
pub const wMapSpriteExtraData: u16 = 0xd504; // 54532
pub const wTilesetBank: u16 = 0xd52b; // 54571 pub const wTilesetBank: u16 = 0xd52b; // 54571
pub const wTilesetBlocksPtr: u16 = 0xd52c; // 54572 pub const wTilesetBlocksPtr: u16 = 0xd52c; // 54572
pub const wTilesetCollisionPtr: u16 = 0xd530; // 54576 pub const wTilesetCollisionPtr: u16 = 0xd530; // 54576
pub const wTilesetTalkingOverTiles: u16 = 0xd532; // 54578 pub const wTilesetTalkingOverTiles: u16 = 0xd532; // 54578
pub const wNumHoFTeams: u16 = 0xd5a2; // 54690 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 wStatusFlags5: u16 = 0xd730; // 55088
pub const wStatusFlags6: u16 = 0xd732; // 55090 pub const wStatusFlags6: u16 = 0xd732; // 55090
pub const wStatusFlags7: u16 = 0xd733; // 55091 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 # services/flysim/tools/resolve_wram.py is the second reading of it, from ram/wram.asm at
# this commit, bracketed by wFontLoaded and wForcePlayerToChooseMon. # this commit, bracketed by wFontLoaded and wForcePlayerToChooseMon.
'wCapturedMonSpecies', '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 # 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. # catch apart from a gift, a trade or an evolution.
'wCapturedMonSpecies': 'the species a ball just caught, 0 for none', '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 = { COUNTED = {
'NUM_HMS': ('constants/item_constants.asm', r'^\s*add_hm\s+\w+'), 'NUM_HMS': ('constants/item_constants.asm', r'^\s*add_hm\s+\w+'),
'NUM_TMS': ('constants/item_constants.asm', r'^\s*add_tm\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]: def pinned(text: str) -> dict[str, int]:
"""Every address `symbols.rs` carries today, by symbol name.""" """Every address `symbols.rs` carries today, by symbol name."""
return { return {
@ -95,10 +135,7 @@ def constants(root: Path) -> dict[str, int]:
BLOCK_WIDTH`). A name whose expression never becomes evaluable is simply left BLOCK_WIDTH`). A name whose expression never becomes evaluable is simply left
out, which kills the cursor at any declaration that uses it. out, which kills the cursor at any declaration that uses it.
""" """
counted = { counted = {name: count_in(root, *spec) for name, spec in COUNTED.items()}
name: len(re.findall(pattern, (root / path).read_text(), re.M))
for name, (path, pattern) in COUNTED.items()
}
pending: dict[str, str] = {} pending: dict[str, str] = {}
sources = sorted((root / 'constants').glob('*.asm')) + sorted( sources = sorted((root / 'constants').glob('*.asm')) + sorted(
(root / 'constants').glob('*.inc') (root / 'constants').glob('*.inc')