Sync with pokecrystal up to 8873506b1

This commit is contained in:
xCrystal 2023-07-26 20:50:16 -04:00
parent 193882bc77
commit d6001be90c
30 changed files with 213 additions and 117 deletions

View File

@ -20,33 +20,35 @@ To set up the repository, see [INSTALL.md](INSTALL.md).
- [**Documentation**][docs] - [**Documentation**][docs]
- [**Wiki**][wiki] (includes [tutorials][tutorials]) - [**Wiki**][wiki] (includes [tutorials][tutorials])
- [**Symbols**][symbols] - [**Symbols**][symbols]
- **Discord:** [pret][discord]
- **IRC:** [libera#pret][irc]
Other disassembly projects: Other disassembly and/or decompilation projects:
* [**Pokémon Red and Blue**](https://github.com/pret/pokered)
* [**Pokémon Gold and Silver (Space World '97 demo)**](https://github.com/pret/pokegold-spaceworld)
* [**Pokémon Yellow**](https://github.com/pret/pokeyellow)
* [**Pokémon Trading Card Game**](https://github.com/pret/poketcg)
* [**Pokémon Pinball**](https://github.com/pret/pokepinball)
* [**Pokémon Stadium**](https://github.com/pret/pokestadium)
* [**Pokémon Gold and Silver**](https://github.com/pret/pokegold)
* [**Pokémon Ruby and Sapphire**](https://github.com/pret/pokeruby)
* [**Pokémon Pinball: Ruby & Sapphire**](https://github.com/pret/pokepinballrs)
* [**Pokémon FireRed and LeafGreen**](https://github.com/pret/pokefirered)
* [**Pokémon Emerald**](https://github.com/pret/pokeemerald)
* [**Pokémon Mystery Dungeon: Red Rescue Team**](https://github.com/pret/pmd-red)
* [**Pokémon Diamond and Pearl**](https://github.com/pret/pokediamond)
* [**Pokémon Platinum**](https://github.com/pret/pokeplatinum)
* [**Pokémon HeartGold and SoulSilver**](https://github.com/pret/pokeheartgold)
* [**Pokémon Mystery Dungeon: Explorers of Sky**](https://github.com/pret/pmd-sky)
- [**Pokémon Red/Blue**][pokered] ## Contacts
- [**Pokémon Yellow**][pokeyellow]
- [**Pokémon Gold/Silver**][pokegold] You can find us on:
- [**Pokémon Pinball**][pokepinball]
- [**Pokémon TCG**][poketcg] * [Discord (PRET, #pokecrystal)](https://discord.gg/d5dubZ3)
- [**Pokémon Ruby**][pokeruby] * [IRC](https://web.libera.chat/?#pret)
- [**Pokémon FireRed**][pokefirered]
- [**Pokémon Emerald**][pokeemerald]
[pokered]: https://github.com/pret/pokered
[pokeyellow]: https://github.com/pret/pokeyellow
[pokegold]: https://github.com/pret/pokegold
[pokepinball]: https://github.com/pret/pokepinball
[poketcg]: https://github.com/pret/poketcg
[pokeruby]: https://github.com/pret/pokeruby
[pokefirered]: https://github.com/pret/pokefirered
[pokeemerald]: https://github.com/pret/pokeemerald
[docs]: https://pret.github.io/pokecrystal/ [docs]: https://pret.github.io/pokecrystal/
[wiki]: https://github.com/pret/pokecrystal/wiki [wiki]: https://github.com/pret/pokecrystal/wiki
[tutorials]: https://github.com/pret/pokecrystal/wiki/Tutorials [tutorials]: https://github.com/pret/pokecrystal/wiki/Tutorials
[symbols]: https://github.com/pret/pokecrystal/tree/symbols [symbols]: https://github.com/pret/pokecrystal/tree/symbols
[discord]: https://discord.gg/d5dubZ3
[irc]: https://web.libera.chat/?#pret
[ci]: https://github.com/pret/pokecrystal/actions [ci]: https://github.com/pret/pokecrystal/actions
[ci-badge]: https://github.com/pret/pokecrystal/actions/workflows/main.yml/badge.svg [ci-badge]: https://github.com/pret/pokecrystal/actions/workflows/main.yml/badge.svg

View File

@ -713,6 +713,9 @@ DEF NUM_BATTLEANIMFRAMESETS EQU const_value
const BATTLEANIMOAMSET_D7 const BATTLEANIMOAMSET_D7
DEF NUM_BATTLEANIMOAMSETS EQU const_value DEF NUM_BATTLEANIMOAMSETS EQU const_value
assert NUM_BATTLEANIMOAMSETS <= FIRST_OAM_CMD, \
"BATTLEANIMOAMSET_* constants overlap oam*_command constants"
; BattleBGEffects indexes (see engine/battle_anims/bg_effects.asm) ; BattleBGEffects indexes (see engine/battle_anims/bg_effects.asm)
const_def 1 const_def 1
const ANIM_BG_FLASH_INVERTED const ANIM_BG_FLASH_INVERTED

View File

@ -90,7 +90,7 @@ DEF SPDSPCDV_SHINY EQU $AA
const BATTLETYPE_FISH const BATTLETYPE_FISH
const BATTLETYPE_ROAMING const BATTLETYPE_ROAMING
const BATTLETYPE_CONTEST const BATTLETYPE_CONTEST
const BATTLETYPE_SHINY const BATTLETYPE_FORCESHINY
const BATTLETYPE_TREE const BATTLETYPE_TREE
const BATTLETYPE_TRAP const BATTLETYPE_TRAP
const BATTLETYPE_FORCEITEM const BATTLETYPE_FORCEITEM

View File

@ -97,6 +97,7 @@ DEF RELATIVE_ATTRIBUTES EQU 1 << RELATIVE_ATTRIBUTES_F
DEF ABSOLUTE_TILE_ID EQU 1 << ABSOLUTE_TILE_ID_F DEF ABSOLUTE_TILE_ID EQU 1 << ABSOLUTE_TILE_ID_F
; map_object struct members (see macros/ram.asm) ; map_object struct members (see macros/ram.asm)
; struct initialized by object_event macro (see macros/scripts/maps.asm)
rsreset rsreset
DEF MAPOBJECT_OBJECT_STRUCT_ID rb ; 0 DEF MAPOBJECT_OBJECT_STRUCT_ID rb ; 0
DEF MAPOBJECT_SPRITE rb ; 1 DEF MAPOBJECT_SPRITE rb ; 1

View File

@ -109,7 +109,8 @@ DEF CALLBACK_SIZE EQU 3 ; callback
DEF WARP_EVENT_SIZE EQU 5 ; warp_event DEF WARP_EVENT_SIZE EQU 5 ; warp_event
DEF COORD_EVENT_SIZE EQU 8 ; coord_event DEF COORD_EVENT_SIZE EQU 8 ; coord_event
DEF BG_EVENT_SIZE EQU 5 ; bg_event DEF BG_EVENT_SIZE EQU 5 ; bg_event
DEF OBJECT_EVENT_SIZE EQU 13 ; object_event ; An object_event is a map_object without its initial MAPOBJECT_OBJECT_STRUCT_ID or final padding
DEF OBJECT_EVENT_SIZE EQU MAPOBJECT_LENGTH - 3 ; 13
; A coord_event for scene -1 will always activate, ; A coord_event for scene -1 will always activate,
; regardless of the map's scene variable value. ; regardless of the map's scene variable value.

View File

@ -370,3 +370,6 @@ DEF NUM_SPRITE_ANIM_FRAMESETS EQU const_value
const SPRITE_ANIM_OAMSET_LEVEL_SELECTION_MENU_FEMALE_RIGHT_1 ; 9a const SPRITE_ANIM_OAMSET_LEVEL_SELECTION_MENU_FEMALE_RIGHT_1 ; 9a
const SPRITE_ANIM_OAMSET_LEVEL_SELECTION_MENU_FEMALE_RIGHT_2 ; 9b const SPRITE_ANIM_OAMSET_LEVEL_SELECTION_MENU_FEMALE_RIGHT_2 ; 9b
DEF NUM_SPRITE_ANIM_OAMSETS EQU const_value DEF NUM_SPRITE_ANIM_OAMSETS EQU const_value
assert NUM_SPRITE_ANIM_OAMSETS <= FIRST_OAM_CMD, \
"SPRITE_ANIM_OAMSET_* constants overlap oam*_command constants"

View File

@ -31,52 +31,52 @@ MACRO connection
; Calculate tile offsets for source (current) and target maps ; Calculate tile offsets for source (current) and target maps
DEF _src = 0 DEF _src = 0
DEF _tgt = (\4) + 3 DEF _tgt = (\4) + MAP_CONNECTION_PADDING_WIDTH
if _tgt < 0 if _tgt < 0
DEF _src = -_tgt DEF _src = -_tgt
DEF _tgt = 0 DEF _tgt = 0
endc endc
if !STRCMP("\1", "north") if !STRCMP("\1", "north")
DEF _blk = \3_WIDTH * (\3_HEIGHT - 3) + _src DEF _blk = \3_WIDTH * (\3_HEIGHT - MAP_CONNECTION_PADDING_WIDTH) + _src
DEF _map = _tgt DEF _map = _tgt
DEF _win = (\3_WIDTH + 6) * \3_HEIGHT + 1 DEF _win = (\3_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2) * \3_HEIGHT + 1
DEF _y = \3_HEIGHT * 2 - 1 DEF _y = \3_HEIGHT * 2 - 1
DEF _x = (\4) * -2 DEF _x = (\4) * -2
DEF _len = CURRENT_MAP_WIDTH + 3 - (\4) DEF _len = CURRENT_MAP_WIDTH + MAP_CONNECTION_PADDING_WIDTH - (\4)
if _len > \3_WIDTH if _len > \3_WIDTH
DEF _len = \3_WIDTH DEF _len = \3_WIDTH
endc endc
elif !STRCMP("\1", "south") elif !STRCMP("\1", "south")
DEF _blk = _src DEF _blk = _src
DEF _map = (CURRENT_MAP_WIDTH + 6) * (CURRENT_MAP_HEIGHT + 3) + _tgt DEF _map = (CURRENT_MAP_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2) * (CURRENT_MAP_HEIGHT + MAP_CONNECTION_PADDING_WIDTH) + _tgt
DEF _win = \3_WIDTH + 7 DEF _win = \3_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2 + 1
DEF _y = 0 DEF _y = 0
DEF _x = (\4) * -2 DEF _x = (\4) * -2
DEF _len = CURRENT_MAP_WIDTH + 3 - (\4) DEF _len = CURRENT_MAP_WIDTH + MAP_CONNECTION_PADDING_WIDTH - (\4)
if _len > \3_WIDTH if _len > \3_WIDTH
DEF _len = \3_WIDTH DEF _len = \3_WIDTH
endc endc
elif !STRCMP("\1", "west") elif !STRCMP("\1", "west")
DEF _blk = (\3_WIDTH * _src) + \3_WIDTH - 3 DEF _blk = (\3_WIDTH * _src) + \3_WIDTH - MAP_CONNECTION_PADDING_WIDTH
DEF _map = (CURRENT_MAP_WIDTH + 6) * _tgt DEF _map = (CURRENT_MAP_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2) * _tgt
DEF _win = (\3_WIDTH + 6) * 2 - 6 DEF _win = (\3_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2) * 2 - MAP_CONNECTION_PADDING_WIDTH * 2
DEF _y = (\4) * -2 DEF _y = (\4) * -2
DEF _x = \3_WIDTH * 2 - 1 DEF _x = \3_WIDTH * 2 - 1
DEF _len = CURRENT_MAP_HEIGHT + 3 - (\4) DEF _len = CURRENT_MAP_HEIGHT + MAP_CONNECTION_PADDING_WIDTH - (\4)
if _len > \3_HEIGHT if _len > \3_HEIGHT
DEF _len = \3_HEIGHT DEF _len = \3_HEIGHT
endc endc
elif !STRCMP("\1", "east") elif !STRCMP("\1", "east")
DEF _blk = (\3_WIDTH * _src) DEF _blk = (\3_WIDTH * _src)
DEF _map = (CURRENT_MAP_WIDTH + 6) * _tgt + CURRENT_MAP_WIDTH + 3 DEF _map = (CURRENT_MAP_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2) * _tgt + CURRENT_MAP_WIDTH + MAP_CONNECTION_PADDING_WIDTH
DEF _win = \3_WIDTH + 7 DEF _win = \3_WIDTH + MAP_CONNECTION_PADDING_WIDTH * 2 + 1
DEF _y = (\4) * -2 DEF _y = (\4) * -2
DEF _x = 0 DEF _x = 0
DEF _len = CURRENT_MAP_HEIGHT + 3 - (\4) DEF _len = CURRENT_MAP_HEIGHT + MAP_CONNECTION_PADDING_WIDTH - (\4)
if _len > \3_HEIGHT if _len > \3_HEIGHT
DEF _len = \3_HEIGHT DEF _len = \3_HEIGHT
endc endc

View File

@ -1,6 +1,7 @@
TypeNames: TypeNames:
; entries correspond to types (see constants/type_constants.asm) ; entries correspond to types (see constants/type_constants.asm)
table_width 2, TypeNames table_width 2, TypeNames
dw Normal dw Normal
dw Fighting dw Fighting
dw Flying dw Flying
@ -12,17 +13,13 @@ TypeNames:
dw Ghost dw Ghost
dw Steel dw Steel
assert_table_length UNUSED_TYPES assert_table_length UNUSED_TYPES
rept UNUSED_TYPES_END - UNUSED_TYPES - 1 ; discount CURSE_TYPE
dw Normal dw Normal
dw Normal endr
dw Normal
dw Normal
dw Normal
dw Normal
dw Normal
dw Normal
dw Normal
dw CurseType dw CurseType
assert_table_length UNUSED_TYPES_END assert_table_length UNUSED_TYPES_END
dw Fire dw Fire
dw Water dw Water
dw Grass dw Grass

View File

@ -59,6 +59,7 @@ Fixes in the [multi-player battle engine](#multi-player-battle-engine) category
- [AI makes a false assumption about `CheckTypeMatchup`](#ai-makes-a-false-assumption-about-checktypematchup) - [AI makes a false assumption about `CheckTypeMatchup`](#ai-makes-a-false-assumption-about-checktypematchup)
- [AI use of Full Heal or Full Restore does not cure Nightmare status](#ai-use-of-full-heal-or-full-restore-does-not-cure-nightmare-status) - [AI use of Full Heal or Full Restore does not cure Nightmare status](#ai-use-of-full-heal-or-full-restore-does-not-cure-nightmare-status)
- [AI use of Full Heal does not cure confusion status](#ai-use-of-full-heal-does-not-cure-confusion-status) - [AI use of Full Heal does not cure confusion status](#ai-use-of-full-heal-does-not-cure-confusion-status)
- [AI might use its base reward value as an item](#ai-might-use-its-base-reward-value-as-an-item)
- [Wild Pokémon can always Teleport regardless of level difference](#wild-pok%C3%A9mon-can-always-teleport-regardless-of-level-difference) - [Wild Pokémon can always Teleport regardless of level difference](#wild-pok%C3%A9mon-can-always-teleport-regardless-of-level-difference)
- [`RIVAL2` has lower DVs than `RIVAL1`](#rival2-has-lower-dvs-than-rival1) - [`RIVAL2` has lower DVs than `RIVAL1`](#rival2-has-lower-dvs-than-rival1)
- [`HELD_CATCH_CHANCE` has no effect](#held_catch_chance-has-no-effect) - [`HELD_CATCH_CHANCE` has no effect](#held_catch_chance-has-no-effect)
@ -1455,6 +1456,33 @@ Pryce's dialog ("That BADGE will raise the SPECIAL stats of POKéMON.") implies
ret ret
``` ```
### AI might use its base reward value as an item
In the `AI_TryItem` routine, an item pointer is set to `wEnemyTrainerItem1` and then increments to `wEnemyTrainerItem2` to see if either of the AI's items are in the `AI_Items` list. However, if the AI has used its first item (or its first one is `ITEM_NONE`) and hasn't used its second item, the item pointer can increment from `wEnemyTrainerItem2` to `wEnemyTrainerBaseReward`. If the value at this address then matches an item in the `AI_Items` list, the AI could mistakenly use it.
**Fix:** Edit `AI_TryItem` in [engine/battle/ai/items.asm](https://github.com/pret/pokecrystal/blob/master/engine/battle/ai/items.asm):
```diff
AI_TryItem:
...
ld a, [wTrainerClass]
dec a
ld hl, TrainerClassAttributes + TRNATTR_AI_ITEM_SWITCH
ld bc, NUM_TRAINER_ATTRIBUTES
call AddNTimes
ld b, h
ld c, l
ld hl, AI_Items
-; BUG: AI might use its base reward value as an item (see docs/bugs_and_glitches.md)
- ld de, wEnemyTrainerItem1
.loop
+ ld de, wEnemyTrainerItem1
ld a, [hl]
and a
inc a
ret z
```
### Wild Pokémon can always Teleport regardless of level difference ### Wild Pokémon can always Teleport regardless of level difference

View File

@ -175,6 +175,7 @@ AI_TryItem:
ld b, h ld b, h
ld c, l ld c, l
ld hl, AI_Items ld hl, AI_Items
; BUG: AI might use its base reward value as an item (see docs/bugs_and_glitches.md)
ld de, wEnemyTrainerItem1 ld de, wEnemyTrainerItem1
.loop .loop
ld a, [hl] ld a, [hl]

View File

@ -3522,7 +3522,7 @@ TryToRunAwayFromBattle:
jp z, .cant_escape jp z, .cant_escape
cp BATTLETYPE_CELEBI cp BATTLETYPE_CELEBI
jp z, .cant_escape jp z, .cant_escape
cp BATTLETYPE_SHINY cp BATTLETYPE_FORCESHINY
jp z, .cant_escape jp z, .cant_escape
cp BATTLETYPE_SUICUNE cp BATTLETYPE_SUICUNE
jp z, .cant_escape jp z, .cant_escape
@ -5954,7 +5954,7 @@ LoadEnemyMon:
; Forced shiny battle type ; Forced shiny battle type
; Used by Red Gyarados at Lake of Rage ; Used by Red Gyarados at Lake of Rage
cp BATTLETYPE_SHINY cp BATTLETYPE_FORCESHINY
jr nz, .GenerateDVs jr nz, .GenerateDVs
ld b, ATKDEFDV_SHINY ; $ea ld b, ATKDEFDV_SHINY ; $ea

View File

@ -4161,14 +4161,14 @@ RaiseStat:
add hl, bc add hl, bc
ld b, [hl] ld b, [hl]
inc b inc b
ld a, $d ld a, MAX_STAT_LEVEL
cp b cp b
jp c, .cant_raise_stat jp c, .cant_raise_stat
ld a, [wLoweredStat] ld a, [wLoweredStat]
and $f0 and $f0
jr z, .got_num_stages jr z, .got_num_stages
inc b inc b
ld a, $d ld a, MAX_STAT_LEVEL
cp b cp b
jr nc, .got_num_stages jr nc, .got_num_stages
ld b, a ld b, a
@ -4176,7 +4176,7 @@ RaiseStat:
ld [hl], b ld [hl], b
push hl push hl
ld a, c ld a, c
cp $5 cp ACCURACY
jr nc, .done_calcing_stats jr nc, .done_calcing_stats
ld hl, wBattleMonStats + 1 ld hl, wBattleMonStats + 1
ld de, wPlayerStats ld de, wPlayerStats
@ -4684,7 +4684,7 @@ LowerStat:
.got_num_stages .got_num_stages
ld [hl], b ld [hl], b
ld a, c ld a, c
cp 5 cp ACCURACY
jr nc, .accuracy_evasion jr nc, .accuracy_evasion
push hl push hl
@ -4955,7 +4955,7 @@ SetBattleDraw:
BattleCommand_ForceSwitch: BattleCommand_ForceSwitch:
ld a, [wBattleType] ld a, [wBattleType]
cp BATTLETYPE_SHINY cp BATTLETYPE_FORCESHINY
jp z, .fail jp z, .fail
cp BATTLETYPE_TRAP cp BATTLETYPE_TRAP
jp z, .fail jp z, .fail

View File

@ -1,6 +1,6 @@
BattleCommand_Teleport: BattleCommand_Teleport:
ld a, [wBattleType] ld a, [wBattleType]
cp BATTLETYPE_SHINY cp BATTLETYPE_FORCESHINY
jr z, .failed jr z, .failed
cp BATTLETYPE_TRAP cp BATTLETYPE_TRAP
jr z, .failed jr z, .failed

View File

@ -20,11 +20,11 @@ ShowPlayerMonsRemaining:
ld de, wPartyCount ld de, wPartyCount
call StageBallTilesData call StageBallTilesData
; ldpixel wPlaceBallsX, 12, 12 ; ldpixel wPlaceBallsX, 12, 12
ld a, 12 * 8 ld a, 12 * TILE_WIDTH
ld hl, wPlaceBallsX ld hl, wPlaceBallsX
ld [hli], a ld [hli], a
ld [hl], a ld [hl], a
ld a, 8 ld a, TILE_WIDTH
ld [wPlaceBallsDirection], a ld [wPlaceBallsDirection], a
ld hl, wShadowOAMSprite00 ld hl, wShadowOAMSprite00
jp LoadTrainerHudOAM jp LoadTrainerHudOAM
@ -36,10 +36,10 @@ ShowOTTrainerMonsRemaining:
call StageBallTilesData call StageBallTilesData
; ldpixel wPlaceBallsX, 9, 4 ; ldpixel wPlaceBallsX, 9, 4
ld hl, wPlaceBallsX ld hl, wPlaceBallsX
ld a, 9 * 8 ld a, 9 * TILE_WIDTH
ld [hli], a ld [hli], a
ld [hl], 4 * 8 ld [hl], 4 * TILE_WIDTH
ld a, -8 ld a, -TILE_WIDTH
ld [wPlaceBallsDirection], a ld [wPlaceBallsDirection], a
ld hl, wShadowOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH ld hl, wShadowOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH
jp LoadTrainerHudOAM jp LoadTrainerHudOAM
@ -182,10 +182,10 @@ LinkBattle_TrainerHuds:
ld de, wPartyCount ld de, wPartyCount
call StageBallTilesData call StageBallTilesData
ld hl, wPlaceBallsX ld hl, wPlaceBallsX
ld a, 10 * 8 ld a, 10 * TILE_WIDTH
ld [hli], a ld [hli], a
ld [hl], 8 * 8 ld [hl], 8 * TILE_WIDTH
ld a, 8 ld a, TILE_WIDTH
ld [wPlaceBallsDirection], a ld [wPlaceBallsDirection], a
ld hl, wShadowOAMSprite00 ld hl, wShadowOAMSprite00
call LoadTrainerHudOAM call LoadTrainerHudOAM
@ -194,9 +194,9 @@ LinkBattle_TrainerHuds:
ld de, wOTPartyCount ld de, wOTPartyCount
call StageBallTilesData call StageBallTilesData
ld hl, wPlaceBallsX ld hl, wPlaceBallsX
ld a, 10 * 8 ld a, 10 * TILE_WIDTH
ld [hli], a ld [hli], a
ld [hl], 13 * 8 ld [hl], 13 * TILE_WIDTH
ld hl, wShadowOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH ld hl, wShadowOAMSprite00 + PARTY_LENGTH * SPRITEOAMSTRUCT_LENGTH
jp LoadTrainerHudOAM jp LoadTrainerHudOAM

View File

@ -243,7 +243,7 @@ InitBattleAnimBuffer:
add hl, bc add hl, bc
ld a, [hli] ld a, [hli]
ld d, a ld d, a
ld a, (-10 * 8) + 4 ld a, (-10 * TILE_WIDTH) + 4
sub d sub d
ld [wBattleAnimTempXCoord], a ld [wBattleAnimTempXCoord], a
ld a, [hli] ld a, [hli]
@ -251,7 +251,7 @@ InitBattleAnimBuffer:
ld a, [wBattleAnimTempFixY] ld a, [wBattleAnimTempFixY]
cp $ff cp $ff
jr nz, .check_kinesis_softboiled_milkdrink jr nz, .check_kinesis_softboiled_milkdrink
ld a, 5 * 8 ld a, 5 * TILE_WIDTH
add d add d
jr .done jr .done
@ -270,7 +270,7 @@ InitBattleAnimBuffer:
jr nz, .no_sub jr nz, .no_sub
.do_sub .do_sub
pop af pop af
sub 1 * 8 sub 1 * TILE_WIDTH
jr .done jr .done
.no_sub .no_sub

View File

@ -347,7 +347,7 @@ FlyToAnim:
ld [hl], SPRITE_ANIM_SEQ_FLY_TO ld [hl], SPRITE_ANIM_SEQ_FLY_TO
ld hl, SPRITEANIMSTRUCT_VAR4 ld hl, SPRITEANIMSTRUCT_VAR4
add hl, bc add hl, bc
ld [hl], 11 * 8 ld [hl], 11 * TILE_WIDTH
ld a, 64 ld a, 64
ld [wFrameCounter], a ld [wFrameCounter], a
.loop .loop

View File

@ -675,7 +675,7 @@ Slots_InitReelTiles:
ld [hl], d ld [hl], d
ld hl, REEL_X_COORD ld hl, REEL_X_COORD
add hl, bc add hl, bc
ld [hl], 6 * 8 ld [hl], 6 * TILE_WIDTH
call .OAM call .OAM
ld bc, wReel2 ld bc, wReel2
@ -693,7 +693,7 @@ Slots_InitReelTiles:
ld [hl], d ld [hl], d
ld hl, REEL_X_COORD ld hl, REEL_X_COORD
add hl, bc add hl, bc
ld [hl], 10 * 8 ld [hl], 10 * TILE_WIDTH
call .OAM call .OAM
ld bc, wReel3 ld bc, wReel3
@ -711,7 +711,7 @@ Slots_InitReelTiles:
ld [hl], d ld [hl], d
ld hl, REEL_X_COORD ld hl, REEL_X_COORD
add hl, bc add hl, bc
ld [hl], 14 * 8 ld [hl], 14 * TILE_WIDTH
call .OAM call .OAM
ret ret
@ -779,7 +779,7 @@ Slots_UpdateReelPositionAndOAM:
add hl, bc add hl, bc
ld a, [hl] ld a, [hl]
ld [wCurReelXCoord], a ld [wCurReelXCoord], a
ld a, 10 * 8 ld a, 10 * TILE_WIDTH
ld [wCurReelYCoord], a ld [wCurReelYCoord], a
ld hl, REEL_POSITION ld hl, REEL_POSITION
add hl, bc add hl, bc
@ -2010,7 +2010,7 @@ Slots_AnimateGolem:
jr c, .play_sound jr c, .play_sound
dec [hl] dec [hl]
ld e, a ld e, a
ld d, 14 * 8 ld d, 14 * TILE_WIDTH
farcall BattleAnim_Sine_e farcall BattleAnim_Sine_e
ld a, e ld a, e
ld hl, SPRITEANIMSTRUCT_YOFFSET ld hl, SPRITEANIMSTRUCT_YOFFSET
@ -2037,7 +2037,7 @@ Slots_AnimateGolem:
ld a, [hl] ld a, [hl]
inc [hl] inc [hl]
inc [hl] inc [hl]
cp 9 * 8 cp 9 * TILE_WIDTH
jr nc, .restart jr nc, .restart
and $3 and $3
ret nz ret nz
@ -2081,7 +2081,7 @@ Slots_AnimateChansey:
add hl, bc add hl, bc
ld a, [hl] ld a, [hl]
inc [hl] inc [hl]
cp 13 * 8 cp 13 * TILE_WIDTH
jr z, .limit jr z, .limit
and $f and $f
ret nz ret nz

View File

@ -576,7 +576,7 @@ InitCGBPals::
ldh [rVBK], a ldh [rVBK], a
ld a, 1 << rBGPI_AUTO_INCREMENT ld a, 1 << rBGPI_AUTO_INCREMENT
ldh [rBGPI], a ldh [rBGPI], a
ld c, 4 * 8 ld c, 4 * TILE_WIDTH
.bgpals_loop .bgpals_loop
ld a, LOW(PALRGB_WHITE) ld a, LOW(PALRGB_WHITE)
ldh [rBGPD], a ldh [rBGPD], a
@ -586,7 +586,7 @@ InitCGBPals::
jr nz, .bgpals_loop jr nz, .bgpals_loop
ld a, 1 << rOBPI_AUTO_INCREMENT ld a, 1 << rOBPI_AUTO_INCREMENT
ldh [rOBPI], a ldh [rOBPI], a
ld c, 4 * 8 ld c, 4 * TILE_WIDTH
.obpals_loop .obpals_loop
ld a, LOW(PALRGB_WHITE) ld a, LOW(PALRGB_WHITE)
ldh [rOBPD], a ldh [rOBPD], a

View File

@ -197,8 +197,8 @@ MoveList_InitAnimatedMonIcon:
ld [wCurIcon], a ld [wCurIcon], a
xor a xor a
call GetIconGFX call GetIconGFX
ld d, 3 * 8 + 2 ; depixel 3, 4, 2, 4 ld d, 3 * TILE_WIDTH + 2 ; depixel 3, 4, 2, 4
ld e, 4 * 8 + 4 ld e, 4 * TILE_WIDTH + 4
ld a, SPRITE_ANIM_INDEX_PARTY_MON ld a, SPRITE_ANIM_INDEX_PARTY_MON
call _InitSpriteAnimStruct call _InitSpriteAnimStruct
ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID ld hl, SPRITEANIMSTRUCT_ANIM_SEQ_ID

View File

@ -384,7 +384,7 @@ AnimSeq_SlotsChanseyEgg:
ld hl, SPRITEANIMSTRUCT_XCOORD ld hl, SPRITEANIMSTRUCT_XCOORD
add hl, bc add hl, bc
ld a, [hl] ld a, [hl]
cp 15 * 8 cp 15 * TILE_WIDTH
jr c, .move_right jr c, .move_right
call DeinitializeSprite call DeinitializeSprite
ld a, $4 ld a, $4
@ -686,7 +686,7 @@ AnimSeq_FlyLeaf:
ld hl, SPRITEANIMSTRUCT_XCOORD ld hl, SPRITEANIMSTRUCT_XCOORD
add hl, bc add hl, bc
ld a, [hl] ld a, [hl]
cp -9 * 8 cp -9 * TILE_WIDTH
jr nc, .delete_leaf jr nc, .delete_leaf
inc [hl] inc [hl]
inc [hl] inc [hl]
@ -715,7 +715,7 @@ AnimSeq_FlyTo:
ld hl, SPRITEANIMSTRUCT_YCOORD ld hl, SPRITEANIMSTRUCT_YCOORD
add hl, bc add hl, bc
ld a, [hl] ld a, [hl]
cp 10 * 8 + 4 cp 10 * TILE_WIDTH + 4
ret z ret z
ld hl, SPRITEANIMSTRUCT_YCOORD ld hl, SPRITEANIMSTRUCT_YCOORD

View File

@ -825,10 +825,10 @@ Intro_PlacePlayerSprite:
.sprites .sprites
db 4 db 4
; y pxl, x pxl, tile offset ; y pxl, x pxl, tile offset
db 9 * 8 + 4, 9 * 8, 0 db 9 * TILE_WIDTH + 4, 9 * TILE_WIDTH, 0
db 9 * 8 + 4, 10 * 8, 1 db 9 * TILE_WIDTH + 4, 10 * TILE_WIDTH, 1
db 10 * 8 + 4, 9 * 8, 2 db 10 * TILE_WIDTH + 4, 9 * TILE_WIDTH, 2
db 10 * 8 + 4, 10 * 8, 3 db 10 * TILE_WIDTH + 4, 10 * TILE_WIDTH, 3
const_def const_def

View File

@ -365,7 +365,7 @@ NamingScreenJoypadLoop:
depixel 10, 3 depixel 10, 3
call NamingScreen_IsTargetBox call NamingScreen_IsTargetBox
jr nz, .got_cursor_position jr nz, .got_cursor_position
ld d, 8 * 8 ld d, 8 * TILE_WIDTH
.got_cursor_position .got_cursor_position
ld a, SPRITE_ANIM_INDEX_NAMING_SCREEN_CURSOR ld a, SPRITE_ANIM_INDEX_NAMING_SCREEN_CURSOR
call InitSpriteAnimStruct call InitSpriteAnimStruct

View File

@ -880,12 +880,12 @@ MovementFunction_Shadow:
add hl, de add hl, de
ld a, [hl] ld a, [hl]
maskbits NUM_DIRECTIONS maskbits NUM_DIRECTIONS
ld d, 1 * 8 + 6 ld d, 1 * TILE_WIDTH + 6
cp DOWN cp DOWN
jr z, .ok jr z, .ok
cp UP cp UP
jr z, .ok jr z, .ok
ld d, 1 * 8 + 4 ld d, 1 * TILE_WIDTH + 4
.ok .ok
ld hl, OBJECT_SPRITE_Y_OFFSET ld hl, OBJECT_SPRITE_Y_OFFSET
add hl, bc add hl, bc
@ -909,7 +909,7 @@ MovementFunction_Emote:
ld [hl], 0 ld [hl], 0
ld hl, OBJECT_SPRITE_Y_OFFSET ld hl, OBJECT_SPRITE_Y_OFFSET
add hl, bc add hl, bc
ld [hl], -2 * 8 ld [hl], -2 * TILE_WIDTH
ld hl, OBJECT_SPRITE_X_OFFSET ld hl, OBJECT_SPRITE_X_OFFSET
add hl, bc add hl, bc
ld [hl], 0 ld [hl], 0

View File

@ -2302,10 +2302,10 @@ Pokedex_GetArea:
.PlayerOAM: .PlayerOAM:
; y pxl, x pxl, tile offset ; y pxl, x pxl, tile offset
db -1 * 8, -1 * 8, 0 ; top left db -1 * TILE_WIDTH, -1 * TILE_WIDTH, 0 ; top left
db -1 * 8, 0 * 8, 1 ; top right db -1 * TILE_WIDTH, 0 * TILE_WIDTH, 1 ; top right
db 0 * 8, -1 * 8, 2 ; bottom left db 0 * TILE_WIDTH, -1 * TILE_WIDTH, 2 ; bottom left
db 0 * 8, 0 * 8, 3 ; bottom right db 0 * TILE_WIDTH, 0 * TILE_WIDTH, 3 ; bottom right
db $80 ; terminator db $80 ; terminator
.CheckPlayerLocation: .CheckPlayerLocation:

View File

@ -769,9 +769,9 @@ EggHatch_CrackShell:
ret nc ret nc
swap a swap a
srl a srl a
add 9 * 8 + 4 add 9 * TILE_WIDTH + 4
ld d, a ld d, a
ld e, 11 * 8 ld e, 11 * TILE_WIDTH
ld a, SPRITE_ANIM_INDEX_EGG_CRACK ld a, SPRITE_ANIM_INDEX_EGG_CRACK
call InitSpriteAnimStruct call InitSpriteAnimStruct
ld hl, SPRITEANIMSTRUCT_TILE_ID ld hl, SPRITEANIMSTRUCT_TILE_ID
@ -828,7 +828,7 @@ Hatch_InitShellFragments:
MACRO shell_fragment MACRO shell_fragment
; y tile, y pxl, x tile, x pxl, frameset offset, ??? ; y tile, y pxl, x tile, x pxl, frameset offset, ???
db (\1 * 8) % $100 + \2, (\3 * 8) % $100 + \4, \5 - SPRITE_ANIM_FRAMESET_EGG_HATCH_1, \6 db (\1 * TILE_WIDTH) % $100 + \2, (\3 * TILE_WIDTH) % $100 + \4, \5 - SPRITE_ANIM_FRAMESET_EGG_HATCH_1, \6
ENDM ENDM
.SpriteData: .SpriteData:

View File

@ -53,7 +53,7 @@ HealPartyMon:
ret ret
ComputeHPBarPixels: ComputeHPBarPixels:
; e = bc * (6 * 8) / de ; e = bc * HP_BAR_LENGTH_PX / de
ld a, b ld a, b
or c or c
jr z, .zero jr z, .zero
@ -64,7 +64,7 @@ ComputeHPBarPixels:
ldh [hMultiplicand + 1], a ldh [hMultiplicand + 1], a
ld a, c ld a, c
ldh [hMultiplicand + 2], a ldh [hMultiplicand + 2], a
ld a, 6 * 8 ld a, HP_BAR_LENGTH_PX
ldh [hMultiplier], a ldh [hMultiplier], a
call Multiply call Multiply
; We need de to be under 256 because hDivisor is only 1 byte. ; We need de to be under 256 because hDivisor is only 1 byte.

View File

@ -18,8 +18,8 @@ MACRO anim_obj
else else
; LEGACY: Support the tile+offset format ; LEGACY: Support the tile+offset format
db \1 ; object db \1 ; object
db (\2) * 8 + (\3) ; x_tile, x db (\2) * TILE_WIDTH + (\3) ; x_tile, x
db (\4) * 8 + (\5) ; y_tile, y db (\4) * TILE_WIDTH + (\5) ; y_tile, y
db \6 ; param db \6 ; param
endc endc
ENDM ENDM

View File

@ -36,3 +36,5 @@ ENDM
MACRO oamdelete MACRO oamdelete
db oamdelete_command db oamdelete_command
ENDM ENDM
DEF FIRST_OAM_CMD EQU LOW(const_value + 1)

34
tools/dupeframes.py Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Usage: python dupeframes.py
Check for duplicate frames in Pokemon sprites (gfx/pokemon/*/front.png).
"""
import sys
import glob
import png
def check_duplicate_frames(filename):
with open(filename, 'rb') as file:
width, height, rows = png.Reader(file).asRGBA8()[:3]
rows = list(rows)
if height % width:
print(f'{filename} is not a vertical strip of square frames!', file=sys.stderr)
return
num_frames = height // width
frames = [rows[i*width:(i+1)*width] for i in range(num_frames)]
for i in range(num_frames):
for j in range(i + 1, num_frames):
if frames[i] == frames[j]:
print(f'{filename}: frame {j} is a duplicate of frame {i}', file=sys.stderr)
def main():
for filename in sorted(glob.glob('gfx/pokemon/*/front.png')):
check_duplicate_frames(filename)
if __name__ == '__main__':
main()

View File

@ -3,6 +3,8 @@
#include "common.h" #include "common.h"
#include <ctype.h>
void parse_args(int argc, char *argv[], bool *strict) { void parse_args(int argc, char *argv[], bool *strict) {
struct option long_options[] = { struct option long_options[] = {
{"strict", no_argument, 0, 's'}, {"strict", no_argument, 0, 's'},
@ -40,31 +42,47 @@ void scan_file(const char *filename, bool strict) {
fclose(f); fclose(f);
contents[size] = '\0'; contents[size] = '\0';
for (char *ptr = contents; ptr && ptr - contents < size; ptr++) { for (char *ptr = contents; ptr && ptr < contents + size; ptr++) {
bool is_incbin = false, is_include = false; ptr = strpbrk(ptr, ";\"Ii");
if (!ptr) {
break;
}
switch (*ptr) { switch (*ptr) {
case ';': case ';':
ptr = strchr(ptr, '\n'); // Skip comments until the end of the line
if (!ptr) { ptr += strcspn(ptr + 1, "\r\n");
fprintf(stderr, "%s: no newline at end of file\n", filename); if (*ptr) {
ptr++;
} }
break; break;
case '"': case '"':
// Skip string literal until the closing quote
ptr += strcspn(ptr + 1, "\"");
if (*ptr) {
ptr++; ptr++;
ptr = strchr(ptr, '"');
if (ptr) {
ptr++;
} else {
fprintf(stderr, "%s: unterminated string\n", filename);
} }
break; break;
case 'I': case 'I':
case 'i': case 'i':
is_incbin = !strncmp(ptr, "INCBIN", 6) || !strncmp(ptr, "incbin", 6); /* empty statement between the label and the variable declaration */;
is_include = !strncmp(ptr, "INCLUDE", 7) || !strncmp(ptr, "include", 7); // Check that an INCLUDE/INCBIN starts as its own token
char before = ptr > contents ? *(ptr - 1) : '\n';
if (!isspace((unsigned)before) && before != ':') {
break;
}
bool is_incbin = !strncmp(ptr, "INCBIN", 6) || !strncmp(ptr, "incbin", 6);
bool is_include = !strncmp(ptr, "INCLUDE", 7) || !strncmp(ptr, "include", 7);
if (is_incbin || is_include) { if (is_incbin || is_include) {
ptr = strchr(ptr, '"'); // Check that an INCLUDE/INCBIN ends as its own token
if (ptr) { ptr += is_include ? 7 : 6;
if (!isspace((unsigned)*ptr) && *ptr != '"') {
break;
}
ptr += strspn(ptr, " \t");
if (*ptr == '"') {
// Print the file path and recursively scan INCLUDEs
ptr++; ptr++;
char *include_path = ptr; char *include_path = ptr;
size_t length = strcspn(ptr, "\""); size_t length = strcspn(ptr, "\"");
@ -74,6 +92,12 @@ void scan_file(const char *filename, bool strict) {
if (is_include) { if (is_include) {
scan_file(include_path, strict); scan_file(include_path, strict);
} }
} else {
fprintf(stderr, "%s: no file path after INC%s\n", filename, is_include ? "LUDE" : "BIN");
// Continue to process a comment
if (*ptr == ';') {
ptr--;
}
} }
} }
break; break;