Build the Virtual Console patches with make red_vc and make blue_vc (#351)

This commit is contained in:
vulcandth 2022-03-26 15:59:36 -05:00 committed by GitHub
parent 07df4a5f88
commit fe8d3c51a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1752 additions and 34 deletions

3
.gitattributes vendored
View file

@ -15,3 +15,6 @@
*.wav binary *.wav binary
*.blk binary *.blk binary
*.pic binary *.pic binary
# Declare files that will always have CRLF line endings on checkout.
*.patch.template text eol=crlf linguist-language=INI

1
.gitignore vendored
View file

@ -9,6 +9,7 @@
# compiled roms # compiled roms
*.gbc *.gbc
*.gb *.gb
*.patch
# rgbds extras # rgbds extras
*.map *.map

View file

@ -1,19 +1,27 @@
roms := pokered.gbc pokeblue.gbc pokeblue_debug.gbc roms := \
pokered.gbc \
pokeblue.gbc \
pokeblue_debug.gbc
patches := \
pokered.patch \
pokeblue.patch
rom_obj := \ rom_obj := \
audio.o \ audio.o \
home.o \ home.o \
main.o \ main.o \
maps.o \ maps.o \
text.o \ text.o \
wram.o \ wram.o \
gfx/pics.o \ gfx/pics.o \
gfx/sprites.o \ gfx/sprites.o \
gfx/tilesets.o gfx/tilesets.o
pokered_obj := $(rom_obj:.o=_red.o) pokered_obj := $(rom_obj:.o=_red.o)
pokeblue_obj := $(rom_obj:.o=_blue.o) pokeblue_obj := $(rom_obj:.o=_blue.o)
pokeblue_debug_obj := $(rom_obj:.o=_blue_debug.o) pokeblue_debug_obj := $(rom_obj:.o=_blue_debug.o)
pokered_vc_obj := $(rom_obj:.o=_red_vc.o)
pokeblue_vc_obj := $(rom_obj:.o=_blue_vc.o)
### Build tools ### Build tools
@ -43,15 +51,34 @@ all: $(roms)
red: pokered.gbc red: pokered.gbc
blue: pokeblue.gbc blue: pokeblue.gbc
blue_debug: pokeblue_debug.gbc blue_debug: pokeblue_debug.gbc
red_vc: pokered.patch
blue_vc: pokeblue.patch
clean: tidy clean: tidy
find gfx \( -iname '*.1bpp' -o -iname '*.2bpp' -o -iname '*.pic' \) -delete find gfx \
\( -iname '*.1bpp' \
-o -iname '*.2bpp' \
-o -iname '*.pic' \) \
-delete
tidy: tidy:
$(RM) $(roms) $(pokered_obj) $(pokeblue_obj) $(pokeblue_debug_obj) $(roms:.gbc=.map) $(roms:.gbc=.sym) rgbdscheck.o $(RM) $(roms) \
$(roms:.gbc=.sym) \
$(roms:.gbc=.map) \
$(patches) \
$(patches:.patch=_vc.gbc) \
$(patches:.patch=_vc.sym) \
$(patches:.patch=_vc.map) \
$(patches:%.patch=vc/%.constants.sym) \
$(pokered_obj) \
$(pokeblue_obj) \
$(pokered_vc_obj) \
$(pokeblue_vc_obj) \
$(pokeblue_debug_obj) \
rgbdscheck.o
$(MAKE) clean -C tools/ $(MAKE) clean -C tools/
compare: $(roms) compare: $(roms) $(patches)
@$(SHA1) -c roms.sha1 @$(SHA1) -c roms.sha1
tools: tools:
@ -67,6 +94,11 @@ endif
$(pokered_obj): RGBASMFLAGS += -D _RED $(pokered_obj): RGBASMFLAGS += -D _RED
$(pokeblue_obj): RGBASMFLAGS += -D _BLUE $(pokeblue_obj): RGBASMFLAGS += -D _BLUE
$(pokeblue_debug_obj): RGBASMFLAGS += -D _BLUE -D _DEBUG $(pokeblue_debug_obj): RGBASMFLAGS += -D _BLUE -D _DEBUG
$(pokered_vc_obj): RGBASMFLAGS += -D _RED -D _RED_VC
$(pokeblue_vc_obj): RGBASMFLAGS += -D _BLUE -D _BLUE_VC
%.patch: vc/%.constants.sym %_vc.gbc %.gbc vc/%.patch.template
tools/make_patch $*_vc.sym $^ $@
rgbdscheck.o: rgbdscheck.asm rgbdscheck.o: rgbdscheck.asm
$(RGBASM) -o $@ $< $(RGBASM) -o $@ $<
@ -89,6 +121,12 @@ $(info $(shell $(MAKE) -C tools))
$(foreach obj, $(pokered_obj), $(eval $(call DEP,$(obj),$(obj:_red.o=.asm)))) $(foreach obj, $(pokered_obj), $(eval $(call DEP,$(obj),$(obj:_red.o=.asm))))
$(foreach obj, $(pokeblue_obj), $(eval $(call DEP,$(obj),$(obj:_blue.o=.asm)))) $(foreach obj, $(pokeblue_obj), $(eval $(call DEP,$(obj),$(obj:_blue.o=.asm))))
$(foreach obj, $(pokeblue_debug_obj), $(eval $(call DEP,$(obj),$(obj:_blue_debug.o=.asm)))) $(foreach obj, $(pokeblue_debug_obj), $(eval $(call DEP,$(obj),$(obj:_blue_debug.o=.asm))))
$(foreach obj, $(pokered_vc_obj), $(eval $(call DEP,$(obj),$(obj:_red_vc.o=.asm))))
$(foreach obj, $(pokeblue_vc_obj), $(eval $(call DEP,$(obj),$(obj:_blue_vc.o=.asm))))
# Dependencies for VC files that need to run scan_includes
%.constants.sym: %.constants.asm $(shell tools/scan_includes %.constants.asm) | rgbdscheck.o
$(RGBASM) $< > $@
endif endif
@ -98,11 +136,15 @@ endif
pokered_pad = 0x00 pokered_pad = 0x00
pokeblue_pad = 0x00 pokeblue_pad = 0x00
pokered_vc_pad = 0x00
pokeblue_vc_pad = 0x00
pokeblue_debug_pad = 0xff pokeblue_debug_pad = 0xff
pokered_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON RED" pokered_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON RED"
pokeblue_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON BLUE" pokeblue_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON BLUE"
pokeblue_debug_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON BLUE" pokeblue_debug_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON BLUE"
pokered_vc_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON RED"
pokeblue_vc_opt = -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t "POKEMON BLUE"
%.gbc: $$(%_obj) layout.link %.gbc: $$(%_obj) layout.link
$(RGBLINK) -p $($*_pad) -d -m $*.map -n $*.sym -l layout.link -o $@ $(filter %.o,$^) $(RGBLINK) -p $($*_pad) -d -m $*.map -n $*.sym -l layout.link -o $@ $(filter %.o,$^)

View file

@ -7,6 +7,8 @@ It builds the following ROMs:
- Pokemon Red (UE) [S][!].gb `sha1: ea9bcae617fdf159b045185467ae58b2e4a48b9a` - Pokemon Red (UE) [S][!].gb `sha1: ea9bcae617fdf159b045185467ae58b2e4a48b9a`
- Pokemon Blue (UE) [S][!].gb `sha1: d7037c83e1ae5b39bde3c30787637ba1d4c48ce2` - Pokemon Blue (UE) [S][!].gb `sha1: d7037c83e1ae5b39bde3c30787637ba1d4c48ce2`
- BLUEMONS.GB (debug build) `sha1: 5b1456177671b79b263c614ea0e7cc9ac542e9c4` - BLUEMONS.GB (debug build) `sha1: 5b1456177671b79b263c614ea0e7cc9ac542e9c4`
- dmgapae0.e69.patch `sha1: 0fb5f743696adfe1dbb2e062111f08f9bc5a293a`
- dmgapee0.e68.patch `sha1: ed4be94dc29c64271942c87f2157bca9ca1019c7`
To set up the repository, see [**INSTALL.md**](INSTALL.md). To set up the repository, see [**INSTALL.md**](INSTALL.md).

View file

@ -211,9 +211,19 @@ _CableClubNPCPleaseWaitText::
text_end text_end
_CableClubNPCLinkClosedBecauseOfInactivityText:: _CableClubNPCLinkClosedBecauseOfInactivityText::
vc_patch Change_MSG
IF DEF(_RED_VC) || DEF(_BLUE_VC)
text "Please come again!"
done
text_start
text "sed because of"
cont "inactivity."
ELSE
text "The link has been" text "The link has been"
line "closed because of" line "closed because of"
cont "inactivity." cont "inactivity."
ENDC
vc_patch_end
para "Please contact" para "Please contact"
line "your friend and" line "your friend and"

View file

@ -176,8 +176,12 @@ PlayAnimation:
ld h, [hl] ld h, [hl]
ld l, a ld l, a
.animationLoop .animationLoop
vc_hook FPA_Thunderbolt_End
ld a, [hli] ld a, [hli]
vc_hook_red FPA_007_End
vc_hook_blue FPA_009_End
cp -1 cp -1
vc_hook_blue FPA_008_End
jr z, .AnimationOver jr z, .AnimationOver
cp FIRST_SE_ID ; is this subanimation or a special effect? cp FIRST_SE_ID ; is this subanimation or a special effect?
jr c, .playSubanimation jr c, .playSubanimation
@ -246,37 +250,55 @@ PlayAnimation:
ld a, [wAnimPalette] ld a, [wAnimPalette]
ldh [rOBP0], a ldh [rOBP0], a
call LoadAnimationTileset call LoadAnimationTileset
vc_hook FPA_001_Begin
call LoadSubanimation call LoadSubanimation
call PlaySubanimation call PlaySubanimation
vc_hook FPA_001_End
pop af pop af
vc_hook_red FPA_008_End
ldh [rOBP0], a ldh [rOBP0], a
.nextAnimationCommand .nextAnimationCommand
vc_hook FPA_005_End
pop hl pop hl
vc_hook FPA_002_End
jr .animationLoop jr .animationLoop
.AnimationOver .AnimationOver
ret ret
LoadSubanimation: LoadSubanimation:
vc_hook FPA_002_Begin
ld a, [wSubAnimAddrPtr + 1] ld a, [wSubAnimAddrPtr + 1]
vc_hook FPA_003_Begin
ld h, a ld h, a
vc_hook_red FPA_131_Begin
ld a, [wSubAnimAddrPtr] ld a, [wSubAnimAddrPtr]
vc_hook_red FPA_56_Begin
ld l, a ld l, a
ld a, [hli] ld a, [hli]
ld e, a ld e, a
vc_hook FPA_76_Begin
ld a, [hl] ld a, [hl]
vc_hook FPA_Thunderbolt_Begin
ld d, a ; de = address of subanimation ld d, a ; de = address of subanimation
ld a, [de] ld a, [de]
vc_hook_blue FPA_012_Begin
ld b, a ld b, a
vc_hook FPA_Spore_Begin
and %00011111 and %00011111
vc_hook FPA_Bubblebeam_Begin
ld [wSubAnimCounter], a ; number of frame blocks ld [wSubAnimCounter], a ; number of frame blocks
vc_hook_red FPA_010_Begin
vc_hook_blue FPA_009_Begin
ld a, b ld a, b
and %11100000 and %11100000
cp SUBANIMTYPE_ENEMY << 5 cp SUBANIMTYPE_ENEMY << 5
vc_hook_blue FPA_004_Begin
jr nz, .isNotType5 jr nz, .isNotType5
.isType5 .isType5
call GetSubanimationTransform2 call GetSubanimationTransform2
jr .saveTransformation jr .saveTransformation
.isNotType5 .isNotType5
vc_hook FPA_Hyper_Beam_Begin
call GetSubanimationTransform1 call GetSubanimationTransform1
.saveTransformation .saveTransformation
; place the upper 3 bits of a into bits 0-2 of a before storing ; place the upper 3 bits of a into bits 0-2 of a before storing
@ -307,6 +329,7 @@ LoadSubanimation:
; sets the transform to SUBANIMTYPE_NORMAL if it's the player's turn ; sets the transform to SUBANIMTYPE_NORMAL if it's the player's turn
; sets the transform to the subanimation type if it's the enemy's turn ; sets the transform to the subanimation type if it's the enemy's turn
GetSubanimationTransform1: GetSubanimationTransform1:
vc_hook FPA_Reflect_Begin
ld b, a ld b, a
ldh a, [hWhoseTurn] ldh a, [hWhoseTurn]
and a and a
@ -399,11 +422,15 @@ MoveAnimation:
jr nz, .animationsDisabled jr nz, .animationsDisabled
call ShareMoveAnimations call ShareMoveAnimations
call PlayAnimation call PlayAnimation
vc_hook_red FPA_004_End
vc_hook_blue FPA_011_End
jr .next4 jr .next4
.animationsDisabled .animationsDisabled
ld c, 30 ld c, 30
call DelayFrames call DelayFrames
.next4 .next4
vc_hook_red FPA_010_End
vc_hook_blue FPA_012_End
call PlayApplyingAttackAnimation ; shake the screen or flash the pic in and out (to show damage) call PlayApplyingAttackAnimation ; shake the screen or flash the pic in and out (to show damage)
.animationFinished .animationFinished
call WaitForSoundToFinish call WaitForSoundToFinish
@ -541,6 +568,7 @@ SetAnimationPalette:
.notSGB .notSGB
ld a, $e4 ld a, $e4
ld [wAnimPalette], a ld [wAnimPalette], a
vc_hook FPA_Dream_Eater_Begin
ldh [rOBP0], a ldh [rOBP0], a
ld a, $6c ld a, $6c
ldh [rOBP1], a ldh [rOBP1], a
@ -956,6 +984,7 @@ AnimationFlashScreenLong:
ld [wFlashScreenLongCounter], a ld [wFlashScreenLongCounter], a
pop hl pop hl
jr nz, .loop jr nz, .loop
vc_hook_red FPA_phy_End
ret ret
; BG palettes ; BG palettes

View file

@ -3023,6 +3023,7 @@ LinkBattleExchangeData:
ld a, b ld a, b
.doExchange .doExchange
ld [wSerialExchangeNybbleSendData], a ld [wSerialExchangeNybbleSendData], a
vc_hook send_byt2
callfar PrintWaitingText callfar PrintWaitingText
.syncLoop1 .syncLoop1
call Serial_ExchangeNybble call Serial_ExchangeNybble
@ -3030,18 +3031,33 @@ LinkBattleExchangeData:
ld a, [wSerialExchangeNybbleReceiveData] ld a, [wSerialExchangeNybbleReceiveData]
inc a inc a
jr z, .syncLoop1 jr z, .syncLoop1
vc_hook send_byt2_ret
vc_patch FIGHT
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ld b, 26
ELSE
ld b, 10 ld b, 10
ENDC
vc_patch_end
.syncLoop2 .syncLoop2
call DelayFrame call DelayFrame
call Serial_ExchangeNybble call Serial_ExchangeNybble
dec b dec b
jr nz, .syncLoop2 jr nz, .syncLoop2
vc_hook send_dummy
vc_patch FIGHT2
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ld b, 26
ELSE
ld b, 10 ld b, 10
ENDC
vc_patch_end
.syncLoop3 .syncLoop3
call DelayFrame call DelayFrame
call Serial_SendZeroByte call Serial_SendZeroByte
dec b dec b
jr nz, .syncLoop3 jr nz, .syncLoop3
vc_hook send_dummy_end
ret ret
ExecutePlayerMove: ExecutePlayerMove:
@ -6661,7 +6677,14 @@ BattleRandom:
ld a, [hl] ld a, [hl]
pop bc pop bc
pop hl pop hl
vc_hook fight_ret_c
vc_patch fight_ret
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ret
ELSE
ret c ret c
ENDC
vc_patch_end
; if we picked the last seed, we need to recalculate the nine seeds ; if we picked the last seed, we need to recalculate the nine seeds
push hl push hl
@ -6726,7 +6749,9 @@ HandleExplodingAnimation:
PlayMoveAnimation: PlayMoveAnimation:
ld [wAnimationID], a ld [wAnimationID], a
vc_hook_red FPA_conf_Begin
call Delay3 call Delay3
vc_hook_red FPA_phy_Begin
predef_jump MoveAnimation predef_jump MoveAnimation
InitBattle:: InitBattle::

View file

@ -484,6 +484,7 @@ CheckSGB:
ldh a, [rJOYP] ldh a, [rJOYP]
ldh a, [rJOYP] ldh a, [rJOYP]
call Wait7000 call Wait7000
vc_hook Network_RESET
call Wait7000 call Wait7000
ld a, $30 ld a, $30
ldh [rJOYP], a ldh [rJOYP], a

View file

@ -124,18 +124,21 @@ CableClub_DoBattleOrTradeAgain:
ld hl, wSerialRandomNumberListBlock ld hl, wSerialRandomNumberListBlock
ld de, wSerialOtherGameboyRandomNumberListBlock ld de, wSerialOtherGameboyRandomNumberListBlock
ld bc, $11 ld bc, $11
vc_hook Network17
call Serial_ExchangeBytes call Serial_ExchangeBytes
ld a, SERIAL_NO_DATA_BYTE ld a, SERIAL_NO_DATA_BYTE
ld [de], a ld [de], a
ld hl, wSerialPlayerDataBlock ld hl, wSerialPlayerDataBlock
ld de, wSerialEnemyDataBlock ld de, wSerialEnemyDataBlock
ld bc, $1a8 ld bc, $1a8
vc_hook Network424
call Serial_ExchangeBytes call Serial_ExchangeBytes
ld a, SERIAL_NO_DATA_BYTE ld a, SERIAL_NO_DATA_BYTE
ld [de], a ld [de], a
ld hl, wSerialPartyMonsPatchList ld hl, wSerialPartyMonsPatchList
ld de, wSerialEnemyMonsPatchList ld de, wSerialEnemyMonsPatchList
ld bc, $c8 ld bc, $c8
vc_hook Network200
call Serial_ExchangeBytes call Serial_ExchangeBytes
ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK) ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
ldh [rIE], a ldh [rIE], a
@ -859,6 +862,7 @@ TradeCenter_Trade:
ld de, TradeCompleted ld de, TradeCompleted
call PlaceString call PlaceString
predef SaveSAVtoSRAM2 predef SaveSAVtoSRAM2
vc_hook save_game_end
ld c, 50 ld c, 50
call DelayFrames call DelayFrames
xor a xor a

View file

@ -27,6 +27,7 @@ CableClubNPC::
xor a xor a
ldh [hSerialReceiveData], a ldh [hSerialReceiveData], a
ld a, START_TRANSFER_EXTERNAL_CLOCK ld a, START_TRANSFER_EXTERNAL_CLOCK
vc_hook linkCable_fake_begin
ldh [rSC], a ldh [rSC], a
ld a, [wLinkTimeoutCounter] ld a, [wLinkTimeoutCounter]
dec a dec a
@ -54,6 +55,7 @@ CableClubNPC::
ld a, [wCurrentMenuItem] ld a, [wCurrentMenuItem]
and a and a
jr nz, .choseNo jr nz, .choseNo
vc_hook linkCable_block_input
callfar SaveSAVtoSRAM callfar SaveSAVtoSRAM
call WaitForSoundToFinish call WaitForSoundToFinish
ld a, SFX_SAVE ld a, SFX_SAVE
@ -66,8 +68,10 @@ CableClubNPC::
xor a xor a
ld [hl], a ld [hl], a
ldh [hSerialReceivedNewData], a ldh [hSerialReceivedNewData], a
vc_hook linkCable_fake_end
ld [wSerialExchangeNybbleSendData], a ld [wSerialExchangeNybbleSendData], a
call Serial_SyncAndExchangeNybble call Serial_SyncAndExchangeNybble
vc_hook Network_RECHECK
ld hl, wUnknownSerialCounter ld hl, wUnknownSerialCounter
ld a, [hli] ld a, [hli]
inc a inc a

View file

@ -284,9 +284,11 @@ LinkMenu:
.choseCancel .choseCancel
xor a xor a
ld [wMenuJoypadPollCount], a ld [wMenuJoypadPollCount], a
vc_hook Network_STOP
call Delay3 call Delay3
call CloseLinkConnection call CloseLinkConnection
ld hl, LinkCanceledText ld hl, LinkCanceledText
vc_hook Network_END
call PrintText call PrintText
ld hl, wd72e ld hl, wd72e
res 6, [hl] res 6, [hl]

View file

@ -37,20 +37,23 @@ LoadSAV0:
ld a, $1 ld a, $1
ld [MBC1SRamBankingMode], a ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM ; This vc_hook does not have to be in any particular location.
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV ; It is defined here because it refers to the same labels as the two lines below.
vc_hook SaveLimit
ld hl, sGameData
ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld c, a ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum ld a, [sMainDataCheckSum]
cp c cp c
jp z, .checkSumsMatched jp z, .checkSumsMatched
; If the computed checksum didn't match the saved on, try again. ; If the computed checksum didn't match the saved on, try again.
ld hl, sPlayerName ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld c, a ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum ld a, [sMainDataCheckSum]
cp c cp c
jp nz, SAVBadCheckSum jp nz, SAVBadCheckSum
@ -84,11 +87,11 @@ LoadSAV1:
ld a, $1 ld a, $1
ld [MBC1SRamBankingMode], a ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld c, a ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum ld a, [sMainDataCheckSum]
cp c cp c
jr nz, SAVBadCheckSum jr nz, SAVBadCheckSum
ld hl, sCurBoxData ld hl, sCurBoxData
@ -104,11 +107,11 @@ LoadSAV2:
ld a, $1 ld a, $1
ld [MBC1SRamBankingMode], a ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld c, a ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum ld a, [sMainDataCheckSum]
cp c cp c
jp nz, SAVBadCheckSum jp nz, SAVBadCheckSum
ld hl, sPartyData ld hl, sPartyData
@ -219,8 +222,8 @@ SaveSAVtoSRAM0:
call CopyData call CopyData
ldh a, [hTileAnimations] ldh a, [hTileAnimations]
ld [sTileAnimations], a ld [sTileAnimations], a
ld hl, sPlayerName ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld [sMainDataCheckSum], a ld [sMainDataCheckSum], a
xor a xor a
@ -239,8 +242,8 @@ SaveSAVtoSRAM1:
ld de, sCurBoxData ld de, sCurBoxData
ld bc, wBoxDataEnd - wBoxDataStart ld bc, wBoxDataEnd - wBoxDataStart
call CopyData call CopyData
ld hl, sPlayerName ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld [sMainDataCheckSum], a ld [sMainDataCheckSum], a
xor a xor a
@ -262,8 +265,8 @@ SaveSAVtoSRAM2:
ld de, sMainData ld de, sMainData
ld bc, wPokedexSeenEnd - wPokedexOwned ld bc, wPokedexSeenEnd - wPokedexOwned
call CopyData call CopyData
ld hl, sPlayerName ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld [sMainDataCheckSum], a ld [sMainDataCheckSum], a
xor a xor a
@ -612,8 +615,8 @@ SAVCheckRandomID:
ld a, [sPlayerName] ld a, [sPlayerName]
and a and a
jr z, .next jr z, .next
ld hl, sPlayerName ld hl, sGameData
ld bc, sMainDataCheckSum - sPlayerName ld bc, sGameDataEnd - sGameData
call SAVCheckSum call SAVCheckSum
ld c, a ld c, a
ld a, [sMainDataCheckSum] ld a, [sMainDataCheckSum]

View file

@ -230,6 +230,7 @@ Serial_PrintWaitingTextAndSyncAndExchangeNybble::
jp LoadScreenTilesFromBuffer1 jp LoadScreenTilesFromBuffer1
Serial_SyncAndExchangeNybble:: Serial_SyncAndExchangeNybble::
vc_hook send_send_buf2
ld a, $ff ld a, $ff
ld [wSerialExchangeNybbleReceiveData], a ld [wSerialExchangeNybbleReceiveData], a
.loop1 .loop1
@ -253,13 +254,25 @@ Serial_SyncAndExchangeNybble::
ld a, [wSerialExchangeNybbleReceiveData] ld a, [wSerialExchangeNybbleReceiveData]
inc a inc a
jr z, .loop1 jr z, .loop1
vc_patch Network10
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ld b, 26
ELSE
ld b, 10 ld b, 10
ENDC
vc_patch_end
.loop2 .loop2
call DelayFrame call DelayFrame
call Serial_ExchangeNybble call Serial_ExchangeNybble
dec b dec b
jr nz, .loop2 jr nz, .loop2
vc_patch Network11
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ld b, 26
ELSE
ld b, 10 ld b, 10
ENDC
vc_patch_end
.loop3 .loop3
call DelayFrame call DelayFrame
call Serial_SendZeroByte call Serial_SendZeroByte
@ -267,6 +280,7 @@ Serial_SyncAndExchangeNybble::
jr nz, .loop3 jr nz, .loop3
ld a, [wSerialExchangeNybbleReceiveData] ld a, [wSerialExchangeNybbleReceiveData]
ld [wSerialSyncAndExchangeNybbleReceiveData], a ld [wSerialSyncAndExchangeNybbleReceiveData], a
vc_hook send_send_buf2_ret
ret ret
Serial_ExchangeNybble:: Serial_ExchangeNybble::

View file

@ -6,6 +6,7 @@ INCLUDE "macros/data.asm"
INCLUDE "macros/code.asm" INCLUDE "macros/code.asm"
INCLUDE "macros/gfx.asm" INCLUDE "macros/gfx.asm"
INCLUDE "macros/coords.asm" INCLUDE "macros/coords.asm"
INCLUDE "macros/vc.asm"
INCLUDE "macros/scripts/audio.asm" INCLUDE "macros/scripts/audio.asm"
INCLUDE "macros/scripts/maps.asm" INCLUDE "macros/scripts/maps.asm"

39
macros/vc.asm Normal file
View file

@ -0,0 +1,39 @@
vc_hook: MACRO
IF DEF(_RED_VC) || DEF(_BLUE_VC)
.VC_\1::
ENDC
ENDM
vc_hook_red: MACRO
IF DEF(_RED_VC)
.VC_\1::
ENDC
ENDM
vc_hook_blue: MACRO
IF DEF(_BLUE_VC)
.VC_\1::
ENDC
ENDM
vc_patch: MACRO
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ASSERT !DEF(CURRENT_VC_PATCH), "Already started a vc_patch"
CURRENT_VC_PATCH EQUS "\1"
.VC_{CURRENT_VC_PATCH}::
ENDC
ENDM
vc_patch_end: MACRO
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ASSERT DEF(CURRENT_VC_PATCH), "No vc_patch started"
.VC_{CURRENT_VC_PATCH}_End::
PURGE CURRENT_VC_PATCH
ENDC
ENDM
vc_assert: MACRO
IF DEF(_RED_VC) || DEF(_BLUE_VC)
ASSERT \#
ENDC
ENDM

View file

@ -1,3 +1,5 @@
ea9bcae617fdf159b045185467ae58b2e4a48b9a *pokered.gbc ea9bcae617fdf159b045185467ae58b2e4a48b9a *pokered.gbc
d7037c83e1ae5b39bde3c30787637ba1d4c48ce2 *pokeblue.gbc d7037c83e1ae5b39bde3c30787637ba1d4c48ce2 *pokeblue.gbc
5b1456177671b79b263c614ea0e7cc9ac542e9c4 *pokeblue_debug.gbc 5b1456177671b79b263c614ea0e7cc9ac542e9c4 *pokeblue_debug.gbc
0fb5f743696adfe1dbb2e062111f08f9bc5a293a *pokered.patch
ed4be94dc29c64271942c87f2157bca9ca1019c7 *pokeblue.patch

View file

@ -13,12 +13,14 @@ SECTION "Save Data", SRAM
ds $598 ds $598
sGameData::
sPlayerName:: ds NAME_LENGTH sPlayerName:: ds NAME_LENGTH
sMainData:: ds wMainDataEnd - wMainDataStart sMainData:: ds wMainDataEnd - wMainDataStart
sSpriteData:: ds wSpriteDataEnd - wSpriteDataStart sSpriteData:: ds wSpriteDataEnd - wSpriteDataStart
sPartyData:: ds wPartyDataEnd - wPartyDataStart sPartyData:: ds wPartyDataEnd - wPartyDataStart
sCurBoxData:: ds wBoxDataEnd - wBoxDataStart sCurBoxData:: ds wBoxDataEnd - wBoxDataStart
sTileAnimations:: db sTileAnimations:: db
sGameDataEnd::
sMainDataCheckSum:: db sMainDataCheckSum:: db

3
tools/.gitignore vendored
View file

@ -1,3 +1,4 @@
scan_includes
gfx gfx
make_patch
pkmncompress pkmncompress
scan_includes

View file

@ -5,6 +5,7 @@ CFLAGS := -O3 -flto -std=c11 -Wall -Wextra -pedantic
tools := \ tools := \
gfx \ gfx \
make_patch \
pkmncompress \ pkmncompress \
scan_includes scan_includes

469
tools/make_patch.c Normal file
View file

@ -0,0 +1,469 @@
#define PROGRAM_NAME "make_patch"
#define USAGE_OPTS "labels.sym constants.sym patched.gbc original.gbc vc.patch.template vc.patch"
#include "common.h"
#include <ctype.h>
struct Buffer {
size_t item_size;
size_t size;
size_t capacity;
void *data;
};
struct Symbol {
struct Symbol *next;
unsigned int address;
unsigned int offset;
char name[]; // C99 FAM
};
struct Patch {
unsigned int offset;
unsigned int size;
};
struct Buffer *buffer_create(size_t item_size) {
struct Buffer *buffer = xmalloc(sizeof(*buffer));
buffer->item_size = item_size;
buffer->size = 0;
buffer->capacity = 0x10;
buffer->data = xmalloc(buffer->capacity * item_size);
return buffer;
}
void buffer_append(struct Buffer *buffer, const void *item) {
if (buffer->size >= buffer->capacity) {
buffer->capacity = (buffer->capacity + 1) * 2;
buffer->data = xrealloc(buffer->data, buffer->capacity * buffer->item_size);
}
memcpy((char *)buffer->data + (buffer->size++ * buffer->item_size), item, buffer->item_size);
}
void buffer_free(struct Buffer *buffer) {
free(buffer->data);
free(buffer);
}
void symbol_append(struct Symbol **symbols, const char *name, int bank, int address) {
size_t name_len = strlen(name) + 1;
struct Symbol *symbol = xmalloc(sizeof(*symbol) + name_len);
symbol->address = address;
symbol->offset = address < 0x8000
? (bank > 0 ? address + (bank - 1) * 0x4000 : address) // ROM addresses are relative to their bank
: address - 0x8000; // RAM addresses are relative to the start of all RAM
memcpy(symbol->name, name, name_len);
symbol->next = *symbols;
*symbols = symbol;
}
void symbol_free(struct Symbol *symbols) {
for (struct Symbol *next; symbols; symbols = next) {
next = symbols->next;
free(symbols);
}
}
const struct Symbol *symbol_find(const struct Symbol *symbols, const char *name) {
size_t name_len = strlen(name);
for (const struct Symbol *symbol = symbols; symbol; symbol = symbol->next) {
size_t sym_name_len = strlen(symbol->name);
if (name_len > sym_name_len) {
continue;
}
const char *sym_name = symbol->name;
if (name[0] == '.') {
// If `name` is a local label, compare it to the local part of `symbol->name`
sym_name += sym_name_len - name_len;
}
if (!strcmp(sym_name, name)) {
return symbol;
}
}
error_exit("Error: Unknown symbol: \"%s\"\n", name);
}
const struct Symbol *symbol_find_cat(const struct Symbol *symbols, const char *prefix, const char *suffix) {
char *sym_name = xmalloc(strlen(prefix) + strlen(suffix) + 1);
sprintf(sym_name, "%s%s", prefix, suffix);
const struct Symbol *symbol = symbol_find(symbols, sym_name);
free(sym_name);
return symbol;
}
int parse_number(const char *input, int base) {
char *endptr;
int n = (int)strtol(input, &endptr, base);
if (endptr == input || *endptr || n < 0) {
error_exit("Error: Cannot parse number: \"%s\"\n", input);
}
return n;
}
void parse_symbol_value(char *input, int *restrict bank, int *restrict address) {
char *colon = strchr(input, ':');
if (!colon) {
error_exit("Error: Cannot parse bank+address: \"%s\"\n", input);
}
*colon++ = '\0';
*bank = parse_number(input, 16);
*address = parse_number(colon, 16);
}
void parse_symbols(const char *filename, struct Symbol **symbols) {
FILE *file = xfopen(filename, 'r');
struct Buffer *buffer = buffer_create(1);
enum { SYM_PRE, SYM_VALUE, SYM_SPACE, SYM_NAME } state = SYM_PRE;
int bank = 0;
int address = 0;
for (;;) {
int c = getc(file);
if (c == EOF || c == '\n' || c == '\r' || c == ';' || (state == SYM_NAME && (c == ' ' || c == '\t'))) {
if (state == SYM_NAME) {
// The symbol name has ended; append the buffered symbol
buffer_append(buffer, &(char []){'\0'});
symbol_append(symbols, buffer->data, bank, address);
}
// Skip to the next line, ignoring anything after the symbol value and name
state = SYM_PRE;
while (c != EOF && c != '\n' && c != '\r') {
c = getc(file);
}
if (c == EOF) {
break;
}
} else if (c != ' ' && c != '\t') {
if (state == SYM_PRE || state == SYM_SPACE) {
// The symbol value or name has started; buffer its contents
if (++state == SYM_NAME) {
// The symbol name has started; parse the buffered value
buffer_append(buffer, &(char []){'\0'});
parse_symbol_value(buffer->data, &bank, &address);
}
buffer->size = 0;
}
buffer_append(buffer, &c);
} else if (state == SYM_VALUE) {
// The symbol value has ended; wait to see if a name comes after it
state = SYM_SPACE;
}
}
fclose(file);
buffer_free(buffer);
}
int strfind(const char *s, const char *list[], int count) {
for (int i = 0; i < count; i++) {
if (!strcmp(s, list[i])) {
return i;
}
}
return -1;
}
#define vstrfind(s, ...) strfind(s, (const char *[]){__VA_ARGS__}, sizeof (const char *[]){__VA_ARGS__} / sizeof(const char *))
int parse_arg_value(const char *arg, bool absolute, const struct Symbol *symbols, const char *patch_name) {
// Comparison operators for "ConditionValueB" evaluate to their particular values
int op = vstrfind(arg, "==", ">", "<", ">=", "<=", "!=", "||");
if (op >= 0) {
return op == 6 ? 0x11 : op; // "||" is 0x11
}
// Literal numbers evaluate to themselves
if (isdigit((unsigned)arg[0]) || arg[0] == '+') {
return parse_number(arg, 0);
}
// Symbols evaluate to their offset or address, plus an optional offset mod
int offset_mod = 0;
char *plus = strchr(arg, '+');
if (plus) {
offset_mod = parse_number(plus, 0);
*plus = '\0';
}
const char *sym_name = !strcmp(arg, "@") ? patch_name : arg; // "@" is the current patch label
const struct Symbol *symbol = symbol_find(symbols, sym_name);
return (absolute ? symbol->offset : symbol->address) + offset_mod;
}
void interpret_command(char *command, const struct Symbol *current_hook, const struct Symbol *symbols, struct Buffer *patches, FILE *restrict new_rom, FILE *restrict orig_rom, FILE *restrict output) {
// Strip all leading spaces and all but one trailing space
int x = 0;
for (int i = 0; command[i]; i++) {
if (!isspace((unsigned)command[i]) || (i > 0 && !isspace((unsigned)command[i - 1]))) {
command[x++] = command[i];
}
}
command[x - (x > 0 && isspace((unsigned)command[x - 1]))] = '\0';
// Count the arguments
int argc = 0;
for (const char *c = command; *c; c++) {
if (isspace((unsigned)*c)) {
argc++;
}
}
// Get the arguments
char *argv[argc]; // VLA
char *arg = command;
for (int i = 0; i < argc; i++) {
while (*arg && !isspace((unsigned)*arg)) {
arg++;
}
if (!*arg) {
break;
}
*arg++ = '\0';
argv[i] = arg;
}
// Use the arguments
if (vstrfind(command, "patch", "PATCH", "patch_", "PATCH_", "patch/", "PATCH/") >= 0) {
if (argc > 2) {
error_exit("Error: Invalid arguments for command: \"%s\"\n", command);
}
if (!current_hook) {
error_exit("Error: No current patch for command: \"%s\"\n", command);
}
int current_offset = current_hook->offset + (argc > 0 ? parse_number(argv[0], 0) : 0);
if (fseek(orig_rom, current_offset, SEEK_SET)) {
error_exit("Error: Cannot seek to \"vc_patch %s\" in the original ROM\n", current_hook->name);
}
if (fseek(new_rom, current_offset, SEEK_SET)) {
error_exit("Error: Cannot seek to \"vc_patch %s\" in the new ROM\n", current_hook->name);
}
int length;
if (argc == 2) {
length = parse_number(argv[1], 0);
} else {
const struct Symbol *current_hook_end = symbol_find_cat(symbols, current_hook->name, "_End");
length = current_hook_end->offset - current_offset;
}
buffer_append(patches, &(struct Patch){current_offset, length});
bool modified = false;
if (length == 1) {
int c = getc(new_rom);
modified = c != getc(orig_rom);
fprintf(output, isupper((unsigned)command[0]) ? "0x%02X" : "0x%02x", c);
} else {
if (command[strlen(command) - 1] != '/') {
fprintf(output, command[strlen(command) - 1] == '_' ? "a%d: " : "a%d:", length);
}
for (int i = 0; i < length; i++) {
if (i) {
putc(' ', output);
}
int c = getc(new_rom);
modified |= c != getc(orig_rom);
fprintf(output, isupper((unsigned)command[0]) ? "%02X" : "%02x", c);
}
}
if (!modified) {
fprintf(stderr, PROGRAM_NAME ": Warning: \"vc_patch %s\" doesn't alter the ROM\n", current_hook->name);
}
} else if (vstrfind(command, "dws", "DWS", "dws_", "DWS_", "dws/", "DWS/") >= 0) {
if (argc < 1) {
error_exit("Error: Invalid arguments for command: \"%s\"\n", command);
}
if (command[strlen(command) - 1] != '/') {
fprintf(output, command[strlen(command) - 1] == '_' ? "a%d: " : "a%d:", argc * 2);
}
for (int i = 0; i < argc; i++) {
int value = parse_arg_value(argv[i], false, symbols, current_hook->name);
if (value > 0xffff) {
error_exit("Error: Invalid value for \"%s\" argument: 0x%x\n", command, value);
}
if (i) {
putc(' ', output);
}
fprintf(output, isupper((unsigned)command[0]) ? "%02X %02X": "%02x %02x", value & 0xff, value >> 8);
}
} else if (vstrfind(command, "db", "DB", "db_", "DB_", "db/", "DB/") >= 0) {
if (argc != 1) {
error_exit("Error: Invalid arguments for command: \"%s\"\n", command);
}
int value = parse_arg_value(argv[0], false, symbols, current_hook->name);
if (value > 0xff) {
error_exit("Error: Invalid value for \"%s\" argument: 0x%x\n", command, value);
}
if (command[strlen(command) - 1] != '/') {
fputs(command[strlen(command) - 1] == '_' ? "a1: " : "a1:", output);
}
fprintf(output, isupper((unsigned)command[0]) ? "%02X" : "%02x", value);
} else if (vstrfind(command, "hex", "HEX", "HEx", "Hex", "heX", "hEX", "hex~", "HEX~", "HEx~", "Hex~", "heX~", "hEX~") >= 0) {
if (argc != 1 && argc != 2) {
error_exit("Error: Invalid arguments for command: \"%s\"\n", command);
}
int value = parse_arg_value(argv[0], command[strlen(command) - 1] != '~', symbols, current_hook->name);
int padding = argc > 1 ? parse_number(argv[1], 0) : 2;
if (vstrfind(command, "HEx", "HEx~") >= 0) {
fprintf(output, "0x%0*X%02x", padding - 2, value >> 8, value & 0xff);
} else if (vstrfind(command, "Hex", "Hex~") >= 0) {
fprintf(output, "0x%0*X%03x", padding - 3, value >> 12, value & 0xfff);
} else if (vstrfind(command, "heX", "heX~") >= 0) {
fprintf(output, "0x%0*x%02X", padding - 2, value >> 8, value & 0xff);
} else if (vstrfind(command, "hEX", "hEX~") >= 0) {
fprintf(output, "0x%0*x%03X", padding - 3, value >> 12, value & 0xfff);
} else {
fprintf(output, isupper((unsigned)command[0]) ? "0x%0*X" : "0x%0*x", padding, value);
}
} else {
error_exit("Error: Unknown command: \"%s\"\n", command);
}
}
void skip_to_next_line(FILE *restrict input, FILE *restrict output) {
for (int c = getc(input); c != EOF; c = getc(input)) {
putc(c, output);
if (c == '\n' || c == '\r') {
break;
}
}
}
struct Buffer *process_template(const char *template_filename, const char *patch_filename, FILE *restrict new_rom, FILE *restrict orig_rom, const struct Symbol *symbols) {
FILE *input = xfopen(template_filename, 'r');
FILE *output = xfopen(patch_filename, 'w');
struct Buffer *patches = buffer_create(sizeof(struct Patch));
struct Buffer *buffer = buffer_create(1);
// The ROM checksum will always differ
buffer_append(patches, &(struct Patch){0x14e, 2});
// The Stadium data (see stadium.c) will always differ
unsigned int rom_size = (unsigned int)xfsize("", orig_rom);
unsigned int stadium_size = 24 + 6 + 2 + (rom_size / 0x2000) * 2;
buffer_append(patches, &(struct Patch){rom_size - stadium_size, stadium_size});
// Fill in the template
const struct Symbol *current_hook = NULL;
for (int c = getc(input); c != EOF; c = getc(input)) {
switch (c) {
case ';':
// ";" comments until the end of the line
putc(c, output);
skip_to_next_line(input, output);
break;
case '{':
// "{...}" is a template command; buffer its contents
buffer->size = 0;
for (c = getc(input); c != EOF && c != '}'; c = getc(input)) {
buffer_append(buffer, &c);
}
buffer_append(buffer, &(char []){'\0'});
// Interpret the command in the context of the current patch
interpret_command(buffer->data, current_hook, symbols, patches, new_rom, orig_rom, output);
break;
case '[':
// "[...]" is a patch label; buffer its contents
putc(c, output);
bool alternate = false;
buffer->size = 0;
for (c = getc(input); c != EOF; c = getc(input)) {
if (!alternate && c == '@') {
// "@" designates an alternate name for the ".VC_" label
alternate = true;
buffer->size = 0;
} else if (c == ']') {
putc(c, output);
break;
} else {
if (!alternate) {
putc(c, output);
if (!isalnum(c) && c != '_') {
// Convert non-identifier characters to underscores
c = '_';
}
}
buffer_append(buffer, &c);
}
}
buffer_append(buffer, &(char []){'\0'});
// The current patch should have a corresponding ".VC_" label
current_hook = symbol_find_cat(symbols, ".VC_", buffer->data);
skip_to_next_line(input, output);
break;
default:
putc(c, output);
}
}
rewind(orig_rom);
rewind(new_rom);
fclose(input);
fclose(output);
buffer_free(buffer);
return patches;
}
int compare_patch(const void *patch1, const void *patch2) {
unsigned int offset1 = ((const struct Patch *)patch1)->offset;
unsigned int offset2 = ((const struct Patch *)patch2)->offset;
return offset1 > offset2 ? 1 : offset1 < offset2 ? -1 : 0;
}
bool verify_completeness(FILE *restrict orig_rom, FILE *restrict new_rom, struct Buffer *patches) {
qsort(patches->data, patches->size, patches->item_size, compare_patch);
for (unsigned int offset = 0, index = 0; ; offset++) {
int orig_byte = getc(orig_rom);
int new_byte = getc(new_rom);
if (orig_byte == EOF || new_byte == EOF) {
return orig_byte == new_byte;
}
struct Patch *patch = &((struct Patch *)patches->data)[index];
if (index < patches->size && patch->offset == offset) {
if (fseek(orig_rom, patch->size, SEEK_CUR)) {
return false;
}
if (fseek(new_rom, patch->size, SEEK_CUR)) {
return false;
}
offset += patch->size;
index++;
} else if (orig_byte != new_byte) {
fprintf(stderr, PROGRAM_NAME ": Warning: Unpatched difference at offset: 0x%x\n", offset);
fprintf(stderr, " Original ROM value: 0x%02x\n", orig_byte);
fprintf(stderr, " Patched ROM value: 0x%02x\n", new_byte);
fprintf(stderr, " Current patch offset: 0x%06x\n", patch->offset);
return false;
}
}
}
int main(int argc, char *argv[]) {
if (argc != 7) {
usage_exit(1);
}
struct Symbol *symbols = NULL;
parse_symbols(argv[1], &symbols);
parse_symbols(argv[2], &symbols);
FILE *new_rom = xfopen(argv[3], 'r');
FILE *orig_rom = xfopen(argv[4], 'r');
struct Buffer *patches = process_template(argv[5], argv[6], new_rom, orig_rom, symbols);
if (!verify_completeness(orig_rom, new_rom, patches)) {
fprintf(stderr, PROGRAM_NAME ": Warning: Not all ROM differences are defined by \"%s\"\n", argv[6]);
}
symbol_free(symbols);
fclose(new_rom);
fclose(orig_rom);
buffer_free(patches);
return 0;
}

71
vc/pokeblue.constants.asm Normal file
View file

@ -0,0 +1,71 @@
INCLUDE "constants.asm"
; These are all the asm constants needed to make the blue_vc patch.
vc_const: MACRO
x = \1
PRINTLN "00:{04x:x} \1" ; same format as rgblink's .sym file
ENDM
; [FPA 001 Begin]
vc_const "M"
vc_const "E"
vc_const "G"
vc_const "A"
vc_const "P"
vc_const "S"
vc_const "L"
vc_const "F"
vc_const "X"
vc_const MEGA_PUNCH
; [FPA 001 End]
vc_const EXPLOSION
; [FPA 002 Begin]
vc_const "U"
vc_const "I"
vc_const GUILLOTINE
; [FPA 002 End]
vc_const "K"
vc_const MEGA_KICK
; [FPA 004 Begin]
vc_const "B"
vc_const "Z"
vc_const BLIZZARD
; [FPA 005 Begin]
vc_const BUBBLEBEAM
; [FPA 005 End]
vc_const HYPER_BEAM
; [FPA 006 Begin]
vc_const "H"
vc_const "Y"
; [FPA 007 Begin]
vc_const "T"
vc_const "N"
vc_const THUNDERBOLT
; [FPA 008 Begin]
vc_const "R"
vc_const REFLECT
; [FPA 009 Begin]
vc_const SELFDESTRUCT
; [FPA 010 Begin]
vc_const "D"
vc_const DREAM_EATER
; [FPA 011 Begin]
vc_const "O"
vc_const SPORE
; [FPA 012 Begin]
vc_const "C"
vc_const ROCK_SLIDE

436
vc/pokeblue.patch.template Normal file
View file

@ -0,0 +1,436 @@
;Format Sample
;[xxxx] ;User-defined Name (Max:31 chars)
;Mode = 1 ;1:Fixcode; 2:Fixvalue; 3:Mask; 4:Palette; 5:Double Frame Buffer
;Type = 0 ;0:Begin 1:End
;Index = 0 ;Index
;Address = x1F8000 ;ROM Address
;MemAddress = x2000 ;RAM Address
;Fixcode = 0 ;Mode1: Fixed Rom Code; Mode2: Fixed Value
;DelayFrame = 0 ;Delay Frame
;FadeFrame = 0 ;Fade Frame 0:Off
;DarkEnable0 = 0 ;0:Off, 1:On (for Normal Mode)
;ReduceEnable0 = 0 ;0:Off, 1:On (for Normal Mode)
;MotionBEnable0 = 0 ;0:Off, 1:Black Fade, 2:, 3:Frame Blend (for Normal Mode)
;Dark0 = 10 ;0~10 (for Normal Mode)
;ReduceColorR0 = 0 ;0~31 (for Normal Mode)
;ReduceColorG0 = 0 ;0~31 (for Normal Mode)
;ReduceColorB0 = 0 ;0~31 (for Normal Mode)
;MotionBlur0 = 31 ;0~31 (for Normal Mode)
;DarkEnable1 = 0 ;0:Off, 1:On (for Green Mode)
;ReduceEnable1 = 0 ;0:Off, 1:On (for Green Mode)
;MotionBEnable1 = 0 ;0:Off, 1:Black Fade, 2:, 3:Frame Blend (for Green Mode)
;Dark1 = 10 ;0~10 (for Green Mode)
;ReduceColorR1 = 0 ;0~31 (for Green Mode)
;ReduceColorG1 = 0 ;0~31 (for Green Mode)
;ReduceColorB1 = 0 ;0~31 (for Green Mode)
;MotionBlur1 = 31 ;0~31 (for Green Mode)
;PaletteX = c31,31,31 ;X:0~15, cR,G,B (0~31)
[SaveLimit]
Mode = 12
Type = 1
Index = {hex sGameData}
Address = {hex sGameDataEnd}
[send_send_buf2]
Mode = 2
Address = {HEX @}
Type = 29
[send_send_buf2_ret]
Mode = 2
Address = {HEX @}
Type = 30
[send_byt2]
Mode = 2
Address = {HEX @+5}
Type = 31
[send_byt2_ret]
Mode = 2
Address = {HEX @}
Type = 32
[send_dummy]
Mode = 2
Address = {HEX @}
Type = 33
[send_dummy_end]
Mode = 2
Address = {HEX @}
Type = 34
[FIGHT]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[FIGHT2]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[Network10]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[Network11]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[Network17]
Mode = 2
Address = {HEX @}
Type = 5
[Network424]
Mode = 2
Address = {HEX @}
Type = 4
[Network200]
Mode = 2
Address = {HEX @}
Type = 4
[Network_RECHECK]
Mode = 2
Address = {HEX @}
Type = 7
[Network_STOP]
Mode = 2
Address = {HEX @}
Type = 8
[Network_END]
Mode = 2
Address = {HEX @}
Type = 9
[Network_RESET]
Mode = 2
Address = {HEX @}
Type = 10
[linkCable fake begin]
Mode = 2
Address = {HEX @}
Type = 16
[linkCable fake end]
Mode = 2
Address = {HEX @}
Type = 17
[linkCable block input]
Mode = 2
Address = {HEX @+5}
Type = 18
;[save game start]
;Mode = 2
;Address = 0x59E6
;Type = 19
[save game end]
Mode = 2
Address = {HEX @}
Type = 20
[Change_MSG]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH_ +1 20}
[fight_ret]
Mode = 1
Address = {HEX @}
Fixcode = {PATCH}
[fight_ret_c]
Mode = 2
Address = {HEX @}
Type = 98
;rsm003758
;No151
[FPA 001 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 27
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == == || == == == == == || == == == == == }
ConditionValueC = {dws_ "M" "E" "G" "A" "P" MEGA_PUNCH 00 "S" "E" "L" "F" MEGA_PUNCH 00 "E" "X" "P" "L" MEGA_PUNCH }
[FPA 001 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == == || == == == == == || == == == == == }
ConditionValueC = {dws_ "M" "E" "G" "A" "P" MEGA_PUNCH 00 "E" "X" "P" "L" EXPLOSION 00 "E" "X" "P" "L" MEGA_PUNCH }
;rsm141151
;No117
[FPA 002 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 9
MotionBEnable1 = 3
MotionBlur1 = 8
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "G" "U" "I" "L" GUILLOTINE }
[FPA 002 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == || == == == == == == }
ConditionValueC = {dws_ "G" "U" "I" "L" GUILLOTINE 00 "M" "E" "G" "A" "K" MEGA_KICK }
;rsm143918
;No150
[FPA 003 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 25
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "M" "E" "G" "A" "K" MEGA_KICK }
;rsm152422
;No131
[FPA 004 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 25
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "B" "L" "I" "Z" BLIZZARD }
;rsm160334
;No123
[FPA 005 Begin@FPA_Bubblebeam_Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable0 = 3
MotionBlur0 = 27
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "B" "U" "B" "B" BUBBLEBEAM }
[FPA 005 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == || == == == == == || == == == == == }
ConditionValueC = {dws_ "B" "U" "B" "B" BUBBLEBEAM 00 "H" "Y" "P" "E" HYPER_BEAM 00 "B" "L" "I" "Z" BLIZZARD }
;rsm163356
;No116
[FPA 006 Begin@FPA_Hyper_Beam_Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 1
MotionBlur0 = 5
MotionBEnable1 = 1
MotionBlur1 = 5
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "H" "Y" "P" "E" HYPER_BEAM }
;rsm174631
;No57
[FPA 007 Begin@FPA_Thunderbolt_Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 30
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "T" "H" "U" "N" THUNDERBOLT }
[FPA 007 End@FPA_Thunderbolt_End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "T" "H" "U" "N" THUNDERBOLT }
;rsm134518
;No159
[FPA 008 Begin@FPA_Reflect_Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable0 = 1
MotionBlur0 = 5
MotionBEnable1 = 1
MotionBlur1 = 5
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "R" "E" "F" "L" REFLECT }
[FPA 008 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "R" "E" "F" "L" REFLECT }
;rsm140510
;No56
[FPA 009 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 27
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "S" "E" "L" "F" SELFDESTRUCT}
[FPA 009 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == || == == == == == }
ConditionValueC = {dws_ "S" "E" "L" "F" MEGA_PUNCH 00 "S" "E" "L" "F" SELFDESTRUCT}
;rsm150211
;No156
[FPA 010 Begin@FPA_Dream_Eater_Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable0 = 3
MotionBlur0 = 10
MotionBEnable1 = 3
MotionBlur1 = 7
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "D" "R" "E" "A" DREAM_EATER }
;[FPA 010 End]
;Mode = 3
;Type = 1
;Address = 0x78176
;ConditionType = 0
;ConditionValueA = a10: 4b cf 4c cf 4d cf 4e cf 7c d0
;ConditionValueB = a10: 00 00 00 00 00 00 00 00 00 00
;ConditionValueC = a10: 83 00 91 00 84 00 80 00 8a 00
;rsm163334
;No36
[FPA 011 Begin@FPA_Spore_Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 8
MotionBEnable1 = 3
MotionBlur1 = 8
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "S" "P" "O" "R" SPORE }
[FPA 011 End]
Mode = 3
Type = 1
Address = {hex @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "S" "P" "O" "R" SPORE }
;rsm012224
;No12
[FPA 012 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 27
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "R" "O" "C" "K" ROCK_SLIDE }
[FPA 012 End]
Mode = 3
Type = 1
Address = {hex @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == || == == == == == }
ConditionValueC = {dws_ "R" "O" "C" "K" ROCK_SLIDE 00 "D" "R" "E" "A" DREAM_EATER }
;explosion
;No76
[FPA 76 Begin]
Mode = 3
Type = 0
Address = 0x78186
MotionBEnable0 = 3
MotionBlur0 = 28
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "E" "X" "P" "L" EXPLOSION }

74
vc/pokered.constants.asm Normal file
View file

@ -0,0 +1,74 @@
INCLUDE "constants.asm"
; These are all the asm constants needed to make the red_vc patch.
vc_const: MACRO
x = \1
PRINTLN "00:{04x:x} \1" ; same format as rgblink's .sym file
ENDM
; [FPA 001 Begin]
vc_const "M"
vc_const "E"
vc_const "G"
vc_const "A"
vc_const "P"
vc_const "S"
vc_const "L"
vc_const "F"
vc_const "D"
vc_const "X"
vc_const MEGA_PUNCH
; [FPA 002 Begin]
vc_const "U"
vc_const "I"
vc_const GUILLOTINE
; [FPA 003 Begin]
vc_const "K"
vc_const MEGA_KICK
; [FPA 004 Begin]
vc_const "B"
vc_const BUBBLEBEAM
; [FPA 005 Begin]
vc_const "H"
vc_const "Y"
vc_const HYPER_BEAM
; [FPA 006 Begin]
vc_const "T"
vc_const "N"
vc_const THUNDERBOLT
; [FPA 007 Begin]
vc_const "R"
vc_const "F"
vc_const REFLECT
; [FPA 008 Begin]
vc_const DREAM_EATER
; [FPA 008 End]
vc_const "Z"
vc_const BLIZZARD
; [FPA 009 Begin]
vc_const "O"
vc_const SPORE
; [FPA 010 Begin]
vc_const "C"
vc_const ROCK_SLIDE
; [FPA 010 End]
vc_const SELFDESTRUCT
vc_const EXPLOSION
; [FPA conf Begin]
vc_const CONFUSION
; [FPA phy Begin]
vc_const PSYCHIC_M

482
vc/pokered.patch.template Normal file
View file

@ -0,0 +1,482 @@
;Format Sample
;[xxxx] ;User-defined Name (Max:31 chars)
;Mode = 1 ;1:Fixcode; 2:Fixvalue; 3:Mask; 4:Palette; 5:Double Frame Buffer
;Type = 0 ;0:Begin 1:End
;Index = 0 ;Index
;Address = x1F8000 ;ROM Address
;MemAddress = x2000 ;RAM Address
;Fixcode = 0 ;Mode1: Fixed Rom Code; Mode2: Fixed Value
;DelayFrame = 0 ;Delay Frame
;FadeFrame = 0 ;Fade Frame 0:Off
;DarkEnable0 = 0 ;0:Off, 1:On (for Normal Mode)
;ReduceEnable0 = 0 ;0:Off, 1:On (for Normal Mode)
;MotionBEnable0 = 0 ;0:Off, 1:Black Fade, 2:, 3:Frame Blend (for Normal Mode)
;Dark0 = 10 ;0~10 (for Normal Mode)
;ReduceColorR0 = 0 ;0~31 (for Normal Mode)
;ReduceColorG0 = 0 ;0~31 (for Normal Mode)
;ReduceColorB0 = 0 ;0~31 (for Normal Mode)
;MotionBlur0 = 31 ;0~31 (for Normal Mode)
;DarkEnable1 = 0 ;0:Off, 1:On (for Green Mode)
;ReduceEnable1 = 0 ;0:Off, 1:On (for Green Mode)
;MotionBEnable1 = 0 ;0:Off, 1:Black Fade, 2:, 3:Frame Blend (for Green Mode)
;Dark1 = 10 ;0~10 (for Green Mode)
;ReduceColorR1 = 0 ;0~31 (for Green Mode)
;ReduceColorG1 = 0 ;0~31 (for Green Mode)
;ReduceColorB1 = 0 ;0~31 (for Green Mode)
;MotionBlur1 = 31 ;0~31 (for Green Mode)
;PaletteX = c31,31,31 ;X:0~15, cR,G,B (0~31)
[SaveLimit]
Mode = 12
Type = 1
Index = {hex sGameData}
Address = {hex sGameDataEnd}
;[Fix pokemon]
;Mode = 2
;Address = 0x1551
;Type = 3
[send_send_buf2]
Mode = 2
Address = {HEX @}
Type = 29
[send_send_buf2_ret]
Mode = 2
Address = {HEX @}
Type = 30
[send_byt2]
Mode = 2
Address = {HEX @+5}
Type = 31
[send_byt2_ret]
Mode = 2
Address = {HEX @}
Type = 32
[send_dummy]
Mode = 2
Address = {HEX @}
Type = 33
[send_dummy_end]
Mode = 2
Address = {HEX @}
Type = 34
[FIGHT]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[FIGHT2]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[Network10]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[Network11]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH +1}
[Network17]
Mode = 2
Address = {HEX @}
Type = 5
[Network424]
Mode = 2
Address = {HEX @}
Type = 4
[Network200]
Mode = 2
Address = {HEX @}
Type = 4
[Network_RECHECK]
Mode = 2
Address = {HEX @}
Type = 7
[Network_STOP]
Mode = 2
Address = {HEX @}
Type = 8
[Network_END]
Mode = 2
Address = {HEX @}
Type = 9
[Network_RESET]
Mode = 2
Address = {HEX @}
Type = 10
[linkCable fake begin]
Mode = 2
Address = {HEX @}
Type = 16
[linkCable fake end]
Mode = 2
Address = {HEX @}
Type = 17
[linkCable block input]
Mode = 2
Address = {HEX @+5}
Type = 18
;[save game start]
;Mode = 2
;Address = 0x59E6
;Type = 19
[save game end]
Mode = 2
Address = {HEX @}
Type = 20
;93 A7 A4 7F AB A8 AD AA 7F A7
;at 93
[Change_MSG]
Mode = 1
Address = {HEX @+1}
Fixcode = {PATCH_ +1 20}
[fight_ret]
Mode = 1
Address = {HEX @}
Fixcode = {PATCH}
[fight_ret_c]
Mode = 2
Address = {HEX @}
Type = 98
; The effect_no decide which animation will be played.
; So we use it as a condition value. The address of effect_no is 0xd07c
; a7 c0 3e 05 ea
; and a A7
; ret nz C0
;
; ld a,5 3E 05
; ld (anime_buf),a EA
;
;
;effect_select_rdy:
; ld (effect_no),a
;
; call put_wait
;
; ld a,B_EFFECT_SELECT
;rsm033659
;no151 mega punch
[FPA 001 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 21
MotionBEnable1 = 3
MotionBlur1 = 21
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+4 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == == || == == == == == == || == == == == == }
ConditionValueC = {dws_ "M" "E" "G" "A" "P" MEGA_PUNCH 00 "S" "E" "L" "F" "D" MEGA_PUNCH 00 "E" "X" "P" "L" MEGA_PUNCH }
[FPA 001 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "M" "E" "G" "A" "P" MEGA_PUNCH }
;rsm032916
;no117 guillotine
[FPA 002 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 9
MotionBEnable1 = 3
MotionBlur1 = 8
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "G" "U" "I" "L" GUILLOTINE }
[FPA 002 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "G" "U" "I" "L" GUILLOTINE }
;rsm041307
;no150 mega kick
[FPA 003 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 25
MotionBEnable1 = 3
MotionBlur1 = 21
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "M" "E" "G" "A" "K" MEGA_KICK }
;rsm001929
;no123 bubble beam
[FPA 004 Begin@FPA_Bubblebeam_Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable0 = 3
MotionBlur0 = 30
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "B" "U" "B" "B" BUBBLEBEAM }
[FPA 004 End]
Mode = 3
Type = 1
Address = {hex @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == || == == == == == == }
ConditionValueC = {dws_ "B" "U" "B" "B" BUBBLEBEAM 00 "M" "E" "G" "A" "K" MEGA_KICK }
;rsm103658
;no116 hyper beam
[FPA 005 Begin@FPA_Hyper_Beam_Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 1
MotionBlur0 = 5
MotionBEnable1 = 1
MotionBlur1 = 5
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "H" "Y" "P" "E" HYPER_BEAM }
[FPA 005 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "H" "Y" "P" "E" HYPER_BEAM }
;rsm133358
;no57 thunderbolt
[FPA 006 Begin@FPA_Thunderbolt_Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 30
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "T" "H" "U" "N" THUNDERBOLT }
[FPA 006 End@FPA_Thunderbolt_End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "T" "H" "U" "N" THUNDERBOLT }
;rsm152340
;no159 reflect
[FPA 007 Begin@FPA_Reflect_Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable0 = 1
MotionBlur0 = 6
MotionBEnable1 = 1
MotionBlur1 = 5
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "R" "E" "F" "L" REFLECT }
[FPA 007 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "R" "E" "F" "L" REFLECT }
;rsm171812
;no156 dream eater
[FPA 008 Begin@FPA_Dream_Eater_Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable0 = 3
MotionBlur0 = 10
MotionBEnable1 = 3
MotionBlur1 = 7
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "D" "R" "E" "A" DREAM_EATER }
[FPA 008 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+4} {dws/ wAnimationID}
ConditionValueB = {dws_ == == == == == } {dws/ == }
ConditionValueC = {dws_ "B" "L" "I" "Z" "Z" } {dws/ BLIZZARD }
;rsm174650
;no36 spore
[FPA 009 Begin@FPA_Spore_Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 8
MotionBEnable1 = 3
MotionBlur1 = 8
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "S" "P" "O" "R" SPORE }
;rsm152115
;no12 rock slide
[FPA 010 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 27
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "R" "O" "C" "K" ROCK_SLIDE }
[FPA 010 End]
Mode = 3
Type = 1
Address = {HEX @}
ConditionType = 11
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+4 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+4 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID 00 wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == || == == == == == || == == == == == || == == == == == == || == == == == == == || == == == == == == || == == == == == || == == == == == }
ConditionValueC = {dws_ "D" "R" "E" "A" DREAM_EATER 00 "R" "O" "C" "K" ROCK_SLIDE 00 "S" "P" "O" "R" SPORE 00 "S" "E" "L" "F" "D" MEGA_PUNCH 00 "S" "E" "L" "F" "D" SELFDESTRUCT 00 "C" "O" "N" "F" "S" CONFUSION 00 "E" "X" "P" "L" EXPLOSION 00 "E" "X" "P" "L" MEGA_PUNCH }
;explosion
;No76 explosion
[FPA 76 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 28
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wAnimationID}
ConditionValueB = {dws_ == == == == == }
ConditionValueC = {dws_ "E" "X" "P" "L" EXPLOSION }
;No56 self-destruct
[FPA 56 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 23
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+4 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "S" "E" "L" "F" "D" SELFDESTRUCT}
;No131 blizzard
[FPA 131 Begin]
Mode = 3
Type = 0
Address = {HEX @}
MotionBEnable0 = 3
MotionBlur0 = 26
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+4 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "B" "L" "I" "Z" "Z" BLIZZARD }
;confusion
[FPA conf Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable1 = 3
MotionBlur1 = 21
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "C" "O" "N" "F" "S" CONFUSION }
;phychic
[FPA phy Begin]
Mode = 3
Type = 0
Address = {hex @}
MotionBEnable1 = 3
MotionBlur1 = 21
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "P" "S" "Y" "C" "I" PSYCHIC_M }
[FPA phy End]
Mode = 3
Type = 1
Address = {hex @}
ConditionType = 0
ConditionValueA = {dws_ wStringBuffer wStringBuffer+1 wStringBuffer+2 wStringBuffer+3 wStringBuffer+5 wAnimationID}
ConditionValueB = {dws_ == == == == == == }
ConditionValueC = {dws_ "P" "S" "Y" "C" "I" PSYCHIC_M }