This commit is contained in:
Sanky 2013-03-02 21:40:02 +01:00
commit aec5a652c8
37 changed files with 6992 additions and 1405 deletions

View File

@ -16,27 +16,27 @@ SoundRestart: ; e8000
push bc
push af
call MusicOff
ld hl, $ff24 ; channel control registers
ld hl, rNR50 ; channel control registers
xor a
ld [hli], a ; ff24 ; volume/vin
ld [hli], a ; ff25 ; sfx channels
ld [hli], a ; rNR50 ; volume/vin
ld [hli], a ; rNR51 ; sfx channels
ld a, $80 ; all channels on
ld [hli], a ; ff26 ; music channels
ld hl, $ff10 ; sound channel registers
ld hl, rNR10 ; sound channel registers
ld e, $04 ; number of channels
.clearsound
; sound channel 1 2 3 4
xor a
ld [hli], a ; $ff10, $ff15, $ff1a, $ff1f ; sweep = 0
ld [hli], a ; rNR10, $ff15, rNR30, $ff1f ; sweep = 0
ld [hli], a ; $ff11, $ff16, $ff1b, $ff20 ; length/wavepattern = 0
ld [hli], a ; rNR11, rNR21, rNR31, rNR41 ; length/wavepattern = 0
ld a, $08
ld [hli], a ; $ff12, $ff17, $ff1c, $ff21 ; envelope = 0
ld [hli], a ; rNR12, rNR22, rNR32, rNR42 ; envelope = 0
xor a
ld [hli], a ; $ff13, $ff18, $ff1d, $ff22 ; frequency lo = 0
ld [hli], a ; rNR13, rNR23, rNR33, rNR43 ; frequency lo = 0
ld a, $80
ld [hli], a ; $ff14, $ff19, $ff1e, $ff23 ; restart sound (freq hi = 0)
ld [hli], a ; rNR14, rNR24, rNR34, rNR44 ; restart sound (freq hi = 0)
dec e
jr nz, .clearsound
@ -208,10 +208,10 @@ UpdateSound: ; e805c
call FadeMusic
; write volume to hardware register
ld a, [Volume]
ld [$ff24], a
ld [rNR50], a
; write SO on/off to hardware register
ld a, [SoundOutput]
ld [$ff25], a
ld [rNR51], a
ret
; e8125
@ -251,7 +251,7 @@ UpdateChannels: ; e8125
jr z, .asm_e8159
;
ld a, [SoundInput]
ld [$ff10], a
ld [rNR10], a
.asm_e8159
bit 5, [hl] ; rest
jr nz, .ch1rest
@ -264,48 +264,48 @@ UpdateChannels: ; e8125
jr .asm_e8175
.asm_e816b
ld a, [$c294]
ld [$ff13], a
ld [rNR13], a
ld a, [$c295]
ld [$ff14], a
ld [rNR14], a
.asm_e8175
bit 0, [hl]
ret z
ld a, [$c292]
ld d, a
ld a, [$ff11]
ld a, [rNR11]
and a, $3f ; sound length
or d
ld [$ff11], a
ld [rNR11], a
ret
.asm_e8184
ld a, [$c292]
ld d, a
ld a, [$ff11]
ld a, [rNR11]
and a, $3f ; sound length
or d
ld [$ff11], a
ld [rNR11], a
ld a, [$c294]
ld [$ff13], a
ld [rNR13], a
ret
.ch1rest
ld a, [$ff26]
ld a, [rNR52]
and a, %10001110 ; ch1 off
ld [$ff26], a
ld hl, $ff10
ld [rNR52], a
ld hl, rNR10
call ClearChannel
ret
.asm_e81a2
ld hl, $c292
ld a, $3f ; sound length
or [hl]
ld [$ff11], a
ld [rNR11], a
ld a, [$c293]
ld [$ff12], a
ld [rNR12], a
ld a, [$c294]
ld [$ff13], a
ld [rNR13], a
ld a, [$c295]
or a, $80
ld [$ff14], a
ld [rNR14], a
ret
.Channel2
@ -322,31 +322,31 @@ UpdateChannels: ; e8125
ret z
ld a, [$c292]
ld d, a
ld a, [$ff16]
ld a, [rNR21]
and a, $3f ; sound length
or d
ld [$ff16], a
ld [rNR21], a
ret
.asm_e81db ; unused
ld a, [$c294]
ld [$ff18], a
ld [rNR23], a
ld a, [$c295]
ld [$ff19], a
ld [rNR24], a
ret
.asm_e81e6
ld a, [$c292]
ld d, a
ld a, [$ff16]
ld a, [rNR21]
and a, $3f ; sound length
or d
ld [$ff16], a
ld [rNR21], a
ld a, [$c294]
ld [$ff18], a
ld [rNR23], a
ret
.ch2rest
ld a, [$ff26]
ld a, [rNR52]
and a, %10001101 ; ch2 off
ld [$ff26], a
ld [rNR52], a
ld hl, $ff15
call ClearChannel
ret
@ -354,14 +354,14 @@ UpdateChannels: ; e8125
ld hl, $c292
ld a, $3f ; sound length
or [hl]
ld [$ff16], a
ld [rNR21], a
ld a, [$c293]
ld [$ff17], a
ld [rNR22], a
ld a, [$c294]
ld [$ff18], a
ld [rNR23], a
ld a, [$c295]
or a, $80 ; initial (restart)
ld [$ff19], a
ld [rNR24], a
ret
.Channel3
@ -377,34 +377,34 @@ UpdateChannels: ; e8125
ret
.asm_e822f ; unused
ld a, [$c294]
ld [$ff1d], a
ld [rNR33], a
ld a, [$c295]
ld [$ff1e], a
ld [rNR34], a
ret
.asm_e823a
ld a, [$c294]
ld [$ff1d], a
ld [rNR33], a
ret
.ch3rest
ld a, [$ff26]
ld a, [rNR52]
and a, %10001011 ; ch3 off
ld [$ff26], a
ld hl, $ff1a
ld [rNR52], a
ld hl, rNR30
call ClearChannel
ret
.asm_e824d
ld a, $3f
ld [$ff1b], a
ld [rNR31], a
xor a
ld [$ff1a], a
ld [rNR30], a
call .asm_e8268
ld a, $80
ld [$ff1a], a
ld [rNR30], a
ld a, [$c294]
ld [$ff1d], a
ld [rNR33], a
ld a, [$c295]
or a, $80
ld [$ff1e], a
ld [rNR34], a
ret
.asm_e8268
push hl
@ -458,7 +458,7 @@ UpdateChannels: ; e8125
ld a, [$c293]
and a, $f0
sla a
ld [$ff1c], a
ld [rNR32], a
ret
.Channel4
@ -472,24 +472,24 @@ UpdateChannels: ; e8125
ret
.asm_e82c1 ; unused
ld a, [$c294]
ld [$ff22], a
ld [rNR43], a
ret
.ch4rest
ld a, [$ff26]
ld a, [rNR52]
and a, %10000111 ; ch4 off
ld [$ff26], a
ld [rNR52], a
ld hl, $ff1f
call ClearChannel
ret
.asm_e82d4
ld a, $3f ; sound length
ld [$ff20], a
ld [rNR41], a
ld a, [$c293]
ld [$ff21], a
ld [rNR42], a
ld a, [$c294]
ld [$ff22], a
ld [rNR43], a
ld a, $80
ld [$ff23], a
ld [rNR44], a
ret
; e82e7
@ -535,15 +535,15 @@ Functione8307: ; e8307
ld hl, Tablee8350
.updatehw
xor a
ld [$ff10], a ; sweep off
ld [rNR10], a ; sweep off
ld a, [hli]
ld [$ff11], a ; sound length / duty cycle
ld [rNR11], a ; sound length / duty cycle
ld a, [hli]
ld [$ff12], a ; ch1 volume envelope
ld [rNR12], a ; ch1 volume envelope
ld a, [hli]
ld [$ff13], a ; ch1 frequency lo
ld [rNR13], a ; ch1 frequency lo
ld a, [hli]
ld [$ff14], a ; ch1 frequency hi
ld [rNR14], a ; ch1 frequency hi
.asm_e8335
ld a, d
inc a
@ -1192,7 +1192,7 @@ ParseMusic: ; e85e1
jr nz, .ok
; ????
xor a
ld [$ff10], a ; sweep = 0
ld [rNR10], a ; sweep = 0
.ok
; stop playing
; turn channel off
@ -2352,72 +2352,87 @@ LoadMusic: ; e8b30
; e8b79
PlayCry: ; e8b79
; input: de = cry id
; Play cry de using parameters:
; CryPitch
; CryEcho
; CryLength
call MusicOff
; load cry id
; Overload the music id with the cry id
ld hl, MusicID
ld [hl], e
inc hl
ld [hl], d
; seek pointer table
; 3-byte pointers (bank, address)
ld hl, Cries
add hl, de
add hl, de
add hl, de
; get bank
ld a, [hli]
ld [MusicBank], a
; get address
ld e, [hl]
inc hl
ld d, [hl]
; read cry header
; get byte at bank:address
; Read the cry's sound header
call FarLoadMusicByte
; get top 2 bits (# chs)
; Top 2 bits contain the number of channels
rlca
rlca
and a, $03
inc a ; ch count -> loop count
and a, 3
; For each channel:
inc a
.loop
push af
call LoadChannel
ld hl, Channel1Flags - Channel1
add hl, bc
set 5, [hl]
ld hl, Channel1Flags2 - Channel1
add hl, bc
set 4, [hl]
ld hl, $0027
ld hl, Channel1CryPitch - Channel1
add hl, bc
ld a, [$c2b0]
ld a, [CryPitch]
ld [hli], a
ld a, [$c2b1]
ld a, [CryEcho]
ld [hl], a
; are we on the last channel? (music & sfx)
; No tempo for channel 4
ld a, [CurChannel]
and a, $03
cp a, $03
and a, 3
cp 3
jr nc, .start
; update tempo
; Tempo is effectively length
ld hl, Channel1Tempo - Channel1
add hl, bc
ld a, [$c2b2]
ld a, [CryLength]
ld [hli], a
ld a, [$c2b3]
ld a, [CryLength+1]
ld [hl], a
.start
call StartChannel
ld a, [$c2bc]
and a
jr z, .next
; play cry from the side of the monster it's coming from (stereo only)
; outside of battles cries play on both tracks
; is stereo on?
; Stereo only: Play cry from the monster's side.
; This only applies in-battle.
ld a, [Options]
bit 5, a ; stereo
jr z, .next
; and [Tracks], [CryTracks]
; [Tracks] &= [CryTracks]
ld hl, Channel1Tracks - Channel1
add hl, bc
ld a, [hl]
@ -2426,21 +2441,25 @@ PlayCry: ; e8b79
ld hl, Channel1Tracks - Channel1
add hl, bc
ld [hl], a
.next
pop af
dec a
jr nz, .loop
; save current volume
; Cries play at max volume, so we save the current volume for later.
ld a, [LastVolume]
and a
jr nz, .end
ld a, [Volume]
ld [LastVolume], a
; cries have max volume
ld a, $77
ld [Volume], a
.end
ld a, $01 ; stop playing music
ld a, 1 ; stop playing music
ld [SFXPriority], a
call MusicOn
ret
@ -2454,56 +2473,56 @@ LoadSFX: ; e8c04
jr z, .ch6
res 0, [hl] ; turn it off
xor a
ld [$ff11], a ; length/wavepattern = 0
ld [rNR11], a ; length/wavepattern = 0
ld a, $08
ld [$ff12], a ; envelope = 0
ld [rNR12], a ; envelope = 0
xor a
ld [$ff13], a ; frequency lo = 0
ld [rNR13], a ; frequency lo = 0
ld a, $80
ld [$ff14], a ; restart sound (freq hi = 0)
ld [rNR14], a ; restart sound (freq hi = 0)
xor a
ld [SoundInput], a ; global sound off
ld [$ff10], a ; sweep = 0
ld [rNR10], a ; sweep = 0
.ch6
ld hl, $c1fe ; ch6 on?
bit 0, [hl]
jr z, .ch7
res 0, [hl] ; turn it off
xor a
ld [$ff16], a ; length/wavepattern = 0
ld [rNR21], a ; length/wavepattern = 0
ld a, $08
ld [$ff17], a ; envelope = 0
ld [rNR22], a ; envelope = 0
xor a
ld [$ff18], a ; frequency lo = 0
ld [rNR23], a ; frequency lo = 0
ld a, $80
ld [$ff19], a ; restart sound (freq hi = 0)
ld [rNR24], a ; restart sound (freq hi = 0)
.ch7
ld hl, $c230 ; ch7 on?
bit 0, [hl]
jr z, .ch8
res 0, [hl] ; turn it off
xor a
ld [$ff1a], a ; sound mode #3 off
ld [$ff1b], a ; length/wavepattern = 0
ld [rNR30], a ; sound mode #3 off
ld [rNR31], a ; length/wavepattern = 0
ld a, $08
ld [$ff1c], a ; envelope = 0
ld [rNR32], a ; envelope = 0
xor a
ld [$ff1d], a ; frequency lo = 0
ld [rNR33], a ; frequency lo = 0
ld a, $80
ld [$ff1e], a ; restart sound (freq hi = 0)
ld [rNR34], a ; restart sound (freq hi = 0)
.ch8
ld hl, $c262 ; ch8 on?
bit 0, [hl]
jr z, .chscleared
res 0, [hl] ; turn it off
xor a
ld [$ff20], a ; length/wavepattern = 0
ld [rNR41], a ; length/wavepattern = 0
ld a, $08
ld [$ff21], a ; envelope = 0
ld [rNR42], a ; envelope = 0
xor a
ld [$ff22], a ; frequency lo = 0
ld [rNR43], a ; frequency lo = 0
ld a, $80
ld [$ff23], a ; restart sound (freq hi = 0)
ld [rNR44], a ; restart sound (freq hi = 0)
xor a
ld [NoiseSampleAddressLo], a
ld [NoiseSampleAddressHi], a
@ -3126,13 +3145,13 @@ ChannelPointers: ; e8fd9
ClearChannels: ; e8fe9
; runs ClearChannel for all 4 channels
; doesn't seem to be used, but functionally identical to SoundRestart
ld hl, $ff24
ld hl, rNR50
xor a
ld [hli], a
ld [hli], a
ld a, $80
ld [hli], a
ld hl, $ff10
ld hl, rNR10
ld e, $04
.loop
call ClearChannel
@ -3142,19 +3161,19 @@ ClearChannels: ; e8fe9
; e8ffe
ClearChannel: ; e8ffe
; input: hl = beginning hw sound register ($ff10, $ff15, $ff1a, $ff1f)
; input: hl = beginning hw sound register (rNR10, $ff15, rNR30, $ff1f)
; output: 00 00 80 00 80
; sound channel 1 2 3 4
xor a
ld [hli], a ; $ff10, $ff15, $ff1a, $ff1f ; sweep = 0
ld [hli], a ; rNR10, $ff15, rNR30, $ff1f ; sweep = 0
ld [hli], a ; $ff11, $ff16, $ff1b, $ff20 ; length/wavepattern = 0
ld [hli], a ; rNR11, rNR21, rNR31, rNR41 ; length/wavepattern = 0
ld a, $08
ld [hli], a ; $ff12, $ff17, $ff1c, $ff21 ; envelope = 0
ld [hli], a ; rNR12, rNR22, rNR32, rNR42 ; envelope = 0
xor a
ld [hli], a ; $ff13, $ff18, $ff1d, $ff22 ; frequency lo = 0
ld [hli], a ; rNR13, rNR23, rNR33, rNR43 ; frequency lo = 0
ld a, $80
ld [hli], a ; $ff14, $ff19, $ff1e, $ff23 ; restart sound (freq hi = 0)
ld [hli], a ; rNR14, rNR24, rNR34, rNR44 ; restart sound (freq hi = 0)
ret
; e900a

220
battle/magikarp_length.asm Normal file
View File

@ -0,0 +1,220 @@
CalcMagikarpLength: ; fbbfc
; Return Magikarp's length (in mm) in MagikarpLength (big endian)
;
; input:
; de: EnemyMonDVs
; bc: PlayerID
; This function is needlessly convoluted, and poorly commented.
; Reading is discouraged.
; In short, it generates a value between 190 and 1786 using
; a Magikarp's DVs and its trainer ID. This value is further
; scrutinized in GetEnemyMon to make longer Magikarp even rarer.
; This is done by calculating the value using operands from
; a conversion lookup table.
; Our index is calculated by xoring DVs with the trainer ID:
; bc = rrc(rrc(dvs)) xor rrc(id)
; if bc < $a: MagikarpLength = c + 190
; if bc >= $ff00: MagikarpLength = c + 1370
; else: MagikarpLength = z*100 + (bc-x)/y
; X, Y, and Z depend on the value of b as follows:
; if b = 0: x = 310, y = 2, z = 3
; if b = 1: x = 710, y = 4, z = 4
; if b = 2-9: x = 2710, y = 20, z = 5
; if b = 10-29: x = 7710, y = 50, z = 6
; if b = 30-68: x = 17710, y = 100, z = 7
; if b = 69-126: x = 32710, y = 150, z = 8
; if b = 127-185: x = 47710, y = 150, z = 9
; if b = 186-224: x = 57710, y = 100, z = 10
; if b = 225-243: x = 62710, y = 50, z = 11
; if b = 244-251: x = 64710, y = 20, z = 12
; if b = 252-253: x = 65210, y = 5, z = 13
; if b = 254: x = 65410, y = 2, z = 14
; These values represent arbitrary conversion points.
; b = rrcrrc(atkdefdv) xor rrc(id[0])
; id
ld h, b
ld l, c
ld a, [hli]
ld b, a
ld c, [hl]
rrc b
rrc c
; dvs
ld a, [de]
inc de
rrca
rrca
xor b
ld b, a
; c = rrcrrc(spdspcdv) xor rrc(id[1])
ld a, [de]
rrca
rrca
xor c
ld c, a
; if bc < $000a:
ld a, b
and a
jr nz, .loadtable
ld a, c
cp a, $a
jr nc, .loadtable
; de = hl = bc + $be
ld hl, $be
add hl, bc
ld d, h
ld e, l
jr .endtable
.loadtable
ld hl, .MagikarpLengthTable
ld a, $02
ld [$d265], a
.readtable
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
call .BLessThanD
jr nc, .advancetable
; c = bc / [hl]
call .BCMinusDE
ld a, b
ld [$ffb3], a
ld a, c
ld [$ffb4], a
ld a, [hl]
ld [$ffb7], a
ld b, $02
call Divide
ld a, [$ffb6]
ld c, a
; de = c + 100 * (2 + number of rows down the table)
xor a
ld [$ffb4], a
ld [$ffb5], a
ld a, $64
ld [$ffb6], a
ld a, [$d265]
ld [$ffb7], a
call Multiply
ld b, $00
ld a, [$ffb6]
add c
ld e, a
ld a, [$ffb5]
adc b
ld d, a
jr .endtable
.advancetable
inc hl ; align to next triplet
ld a, [$d265]
inc a
ld [$d265], a
cp a, $10
jr c, .readtable
call .BCMinusDE
ld hl, $0640
add hl, bc
ld d, h
ld e, l
.endtable
ld h, d
ld l, e
add hl, hl
add hl, hl
add hl, de
add hl, hl ; hl = de * 10
ld de, $ff02
ld a, $ff
.loop
inc a
add hl, de ; - 254
jr c, .loop
ld d, $00
; mod $0c
.modloop
cp a, $0c
jr c, .done
sub a, $0c
inc d
jr .modloop
.done
ld e, a
ld hl, MagikarpLength
ld [hl], d
inc hl
ld [hl], e
ret
; fbc9a
.BLessThanD ; fbc9a
; return carry if b < d
ld a, b
cp d
ret c
ret nc
; fbc9e
.CLessThanE ; fbc9e
; unused
ld a, c
cp e
ret
; fbca1
.BCMinusDE ; fbca1
; bc -= de
ld a, c
sub e
ld c, a
ld a, b
sbc d
ld b, a
ret
; fbca8
.MagikarpLengthTable ; fbca8
; ????, divisor
dwb $006e, $01
dwb $0136, $02
dwb $02c6, $04
dwb $0a96, $14
dwb $1e1e, $32
dwb $452e, $64
dwb $7fc6, $96
dwb $ba5e, $96
dwb $e16e, $64
dwb $f4f6, $32
dwb $fcc6, $14
dwb $feba, $05
dwb $ff82, $02
; fbccf

View File

@ -3417,15 +3417,20 @@ BATTLETYPE_SUICUNE EQU $0c
; joypad
NO_INPUT EQU %00000000
BUTTON_A EQU %00000001
BUTTON_B EQU %00000010
SELECT EQU %00000100
START EQU %00001000
D_RIGHT EQU %00010000
D_LEFT EQU %00100000
D_UP EQU %01000000
D_DOWN EQU %10000000
BUTTONS EQU %00010000
D_PAD EQU %00100000
AUTO_INPUT EQU $ff
NO_INPUT EQU %00000000
BUTTON_A EQU %00000001
BUTTON_B EQU %00000010
SELECT EQU %00000100
START EQU %00001000
D_RIGHT EQU %00010000
D_LEFT EQU %00100000
D_UP EQU %01000000
D_DOWN EQU %10000000
; mbc
NUM_SRAM_BANKS EQU 4

824
credits.asm Normal file
View File

@ -0,0 +1,824 @@
SATOSHI_TAJIRI EQU 00
JUNICHI_MASUDA EQU 01
TETSUYA_WATANABE EQU 02
SHIGEKI_MORIMOTO EQU 03
SOUSUKE_TAMADA EQU 04
TAKENORI_OOTA EQU 05
KEN_SUGIMORI EQU 06
MOTOFUMI_FUJIWARA EQU 07
ATSUKO_NISHIDA EQU 08
MUNEO_SAITO EQU 09
SATOSHI_OOTA EQU 10
RENA_YOSHIKAWA EQU 11
JUN_OKUTANI EQU 12
HIRONOBU_YOSHIDA EQU 13
ASUKA_IWASHITA EQU 14
GO_ICHINOSE EQU 15
MORIKAZU_AOKI EQU 16
KOHJI_NISHINO EQU 17
KENJI_MATSUSHIMA EQU 18
TOSHINOBU_MATSUMIYA EQU 19
SATORU_IWATA EQU 20
NOBUHIRO_SEYA EQU 21
KAZUHITO_SEKINE EQU 22
TETSUJI_OOTA EQU 23
NCL_SUPER_MARIO_CLUB EQU 24
SARUGAKUCHO EQU 25
AKITO_MORI EQU 26
TAKAHIRO_HARADA EQU 27
TOHRU_HASHIMOTO EQU 28
NOBORU_MATSUMOTO EQU 29
TAKEHIRO_IZUSHI EQU 30
TAKASHI_KAWAGUCHI EQU 31
TSUNEKAZU_ISHIHARA EQU 32
HIROSHI_YAMAUCHI EQU 33
KENJI_SAIKI EQU 34
ATSUSHI_TADA EQU 35
NAOKO_KAWAKAMI EQU 36
HIROYUKI_ZINNAI EQU 37
KUNIMI_KAWAMURA EQU 38
HISASHI_SOGABE EQU 39
KEITA_KAGAYA EQU 40
YOSHINORI_MATSUDA EQU 41
HITOMI_SATO EQU 42
TORU_OSAWA EQU 43
TAKAO_OHARA EQU 44
YUICHIRO_ITO EQU 45
TAKAO_SHIMIZU EQU 46
PLANNING EQU 47
KEITA_NAKAMURA EQU 48
HIROTAKA_UEMURA EQU 49
HIROAKI_TAMURA EQU 50
NORIAKI_SAKAGUCHI EQU 51
MIYUKI_SATO EQU 52
GAKUZI_NOMOTO EQU 53
AI_MASHIMA EQU 54
MIKIHIRO_ISHIKAWA EQU 55
HIDEYUKI_HASHIMOTO EQU 56
SATOSHI_YAMATO EQU 57
SHIGERU_MIYAMOTO EQU 58
GAIL_TILDEN EQU 59
NOB_OGASAWARA EQU 60
SETH_MCMAHILL EQU 61
HIROTO_ALEXANDER EQU 62
TERESA_LILLYGREN EQU 63
THOMAS_HERTZOG EQU 64
ERIK_JOHNSON EQU 65
HIRO_NAKAMURA EQU 66
TERUKI_MURAKAWA EQU 67
KAZUYOSHI_OSAWA EQU 68
KIMIKO_NAKAMICHI EQU 69
END EQU 70
CREDITS_UNKNOWN EQU 71
STAFF EQU 72
DIRECTOR EQU 73
CODIRECTOR EQU 74
PROGRAMMERS EQU 75
GRAPHICS_DIRECTOR EQU 76
MONSTER_DESIGN EQU 77
GRAPHICS_DESIGN EQU 78
MUSIC EQU 79
SOUND_EFFECTS EQU 80
GAME_DESIGN EQU 81
GAME_SCENARIO EQU 82
TOOL_PROGRAMMING EQU 83
PARAMETRIC_DESIGN EQU 84
SCRIPT_DESIGN EQU 85
MAP_DATA_DESIGN EQU 86
MAP_DESIGN EQU 87
PRODUCT_TESTING EQU 88
SPECIAL_THANKS EQU 89
PRODUCERS EQU 90
EXECUTIVE_PRODUCER EQU 91
POKEMON_ANIMATION EQU 92
POKEDEX_TEXT EQU 93
MOBILE_PRJ_LEADER EQU 94
MOBILE_SYSTEM_AD EQU 95
MOBILE_STADIUM_DIR EQU 96
COORDINATION EQU 97
COPYRIGHT EQU 98
US_VERSION_STAFF EQU 99
US_COORDINATION EQU 100
TEXT_TRANSLATION EQU 101
PAAD_TESTING EQU 102
CREDITS_THEEND EQU $f9
CREDITS_WAIT2 EQU $fa
CREDITS_MUSIC EQU $fb
CREDITS_CLEAR EQU $fc
CREDITS_SCENE EQU $fd
CREDITS_WAIT EQU $fe
ParseCredits: ; 1099aa
ld hl, $cf63
bit 7, [hl]
jp nz, .done
; Wait until the timer has run out to parse the next command.
ld hl, CreditsTimer
ld a, [hl]
and a
jr z, .parse
; One tick has passed.
dec [hl]
jp .done
.parse
; First, let's clear the current text display,
; starting from line 5.
xor a
ld [$ffd4], a
hlcoord 0, 5
ld bc, 20 * 12
ld a, " "
call ByteFill
; Then read the script.
.loop
call .get
; Commands:
cp $ff
jp z, .end
cp CREDITS_WAIT
jr z, .wait
cp CREDITS_SCENE
jr z, .scene
cp CREDITS_CLEAR
jr z, .clear
cp CREDITS_MUSIC
jr z, .music
cp CREDITS_WAIT2
jr z, .wait2
cp CREDITS_THEEND
jr z, .theend
; If it's not a command, it's a string identifier.
push af
ld e, a
ld d, 0
ld hl, CreditsStrings
add hl, de
add hl, de
ld a, [hli]
ld d, [hl]
ld e, a
pop af
; Strings spanning multiple lines have special cases.
cp COPYRIGHT
jr z, .copyright
cp STAFF
jr c, .staff
; The rest start from line 6.
hlcoord 0, 6
jr .print
.copyright
hlcoord 2, 6
jr .print
.staff
hlcoord 0, 6
.print
; Print strings spaced every two lines.
call .get
ld bc, 20 * 2
call AddNTimes
call PlaceString
jr .loop
.theend
; Display "The End" graphic.
call $5c11
jr .loop
.scene
; Update the scene number and corresponding palette.
call .get
ld [$cf65], a ; scene
xor a
ld [$cf64], a ; frame
call GetCreditsPalette
call $32f9 ; update hw pal registers
jr .loop
.clear
; Clear the banner.
ld a, $ff
ld [$cf64], a ; frame
jr .loop
.music
; Play the credits music.
ld de, MUSIC_CREDITS
push de
ld de, MUSIC_NONE
call StartMusic
call DelayFrame
pop de
call StartMusic
jp .loop
.wait2
; Wait for some amount of ticks.
call .get
ld [CreditsTimer], a
jr .done
.wait
; Wait for some amount of ticks, and do something else.
call .get
ld [CreditsTimer], a
xor a
ld [$ffd5], a
ld a, 1
ld [$ffd4], a
.done
jp $5951
.end
; Stop execution.
ld hl, $cf63
set 7, [hl]
ld a, $20
ld [$c2a7], a
ld a, $5c
ld [$c2a9], a
ld a, $00
ld [$c2aa], a
ret
.get
; Get byte CreditsPos from CreditsScript
push hl
push de
ld a, [CreditsPos]
ld e, a
ld a, [CreditsPos+1]
ld d, a
ld hl, CreditsScript
add hl, de
inc de
ld a, e
ld [CreditsPos], a
ld a, d
ld [CreditsPos+1], a
ld a, [hl]
pop de
pop hl
ret
; 109a95
INCBIN "baserom.gbc", $109a95, $109b2c - $109a95
GetCreditsPalette: ; 109b2c
call .GetPalAddress
push hl
ld a, 0
call .UpdatePals
pop hl
ret
.GetPalAddress
; Each set of palette data is 24 bytes long.
ld a, [$cf65] ; scene
and 3
add a
add a ; * 8
add a
ld e, a
ld d, 0
ld hl, .CreditsPalettes
add hl, de
add hl, de ; * 3
add hl, de
ret
.UpdatePals
; Update the first three colors in both palette buffers.
push af
push hl
add $00 ; lo($d000)
ld e, a
ld a, 0
adc $d0 ; hi($d000)
ld d, a
ld bc, 24
call CopyBytes
pop hl
pop af
add $80 ; lo($d080)
ld e, a
ld a, 0
adc $d0 ; hi($d080)
ld d, a
ld bc, 24
call CopyBytes
ret
.CreditsPalettes
INCBIN "baserom.gbc",$109b6a,$18 ; pichu.pal
INCBIN "baserom.gbc",$109b82,$18 ; smoochum.pal
INCBIN "baserom.gbc",$109b9a,$18 ; ditto.pal
INCBIN "baserom.gbc",$109bb2,$18 ; igglybuff.pal
; 109bca
INCBIN "baserom.gbc", $109bca, $109c24 - $109bca
CreditsGFX:
INCBIN "gfx/credits/border.2bpp"
INCBIN "gfx/credits/pichu.2bpp"
INCBIN "gfx/credits/smoochum.2bpp"
INCBIN "gfx/credits/ditto.2bpp"
INCBIN "gfx/credits/igglybuff.2bpp"
CreditsScript: ; 10acb4
; Clear the banner.
db CREDITS_CLEAR
; Pokemon Crystal Version Staff
db STAFF, 01
db CREDITS_WAIT, 08
; Play the credits music.
db CREDITS_MUSIC
db CREDITS_WAIT2, 10
db CREDITS_WAIT, 01
; Update the banner.
db CREDITS_SCENE, 00 ; Pichu
db DIRECTOR, 01
db SATOSHI_TAJIRI, 02
db CREDITS_WAIT, 12
db CODIRECTOR, 01
db JUNICHI_MASUDA, 02
db CREDITS_WAIT, 12
db PROGRAMMERS, 00
db SOUSUKE_TAMADA, 01
db HISASHI_SOGABE, 02
db KEITA_KAGAYA, 03
db YOSHINORI_MATSUDA, 04
db CREDITS_WAIT, 12
db PROGRAMMERS, 00
db SHIGEKI_MORIMOTO, 01
db TETSUYA_WATANABE, 02
db TAKENORI_OOTA, 03
db CREDITS_WAIT, 12
db GRAPHICS_DIRECTOR, 01
db KEN_SUGIMORI, 02
db CREDITS_WAIT, 12
db MONSTER_DESIGN, 00
db KEN_SUGIMORI, 01
db MOTOFUMI_FUJIWARA, 02
db SHIGEKI_MORIMOTO, 03
db HIRONOBU_YOSHIDA, 04
db SATOSHI_OOTA, 05
db CREDITS_WAIT, 12
db MONSTER_DESIGN, 00
db ATSUKO_NISHIDA, 01
db MUNEO_SAITO, 02
db RENA_YOSHIKAWA, 03
db CREDITS_WAIT, 12
db POKEMON_ANIMATION, 01
db HIRONOBU_YOSHIDA, 02
db JUN_OKUTANI, 03
db CREDITS_WAIT, 12
; Clear the banner.
db CREDITS_CLEAR
db CREDITS_WAIT, 01
; Update the banner.
db CREDITS_SCENE, 01 ; Smoochum
db GRAPHICS_DESIGN, 00
db HIRONOBU_YOSHIDA, 01
db JUN_OKUTANI, 02
db ASUKA_IWASHITA, 03
db TETSUYA_WATANABE, 04
db CREDITS_WAIT, 12
db MUSIC, 00
db JUNICHI_MASUDA, 01
db MORIKAZU_AOKI, 02
db GO_ICHINOSE, 03
db CREDITS_WAIT, 12
db SOUND_EFFECTS, 00
db MORIKAZU_AOKI, 01
db JUNICHI_MASUDA, 02
db TETSUYA_WATANABE, 03
db CREDITS_WAIT, 12
db GAME_DESIGN, 00
db JUNICHI_MASUDA, 01
db SHIGEKI_MORIMOTO, 02
db KOHJI_NISHINO, 03
db CREDITS_WAIT, 12
db GAME_DESIGN, 00
db TETSUJI_OOTA, 01
db HITOMI_SATO, 02
db KENJI_MATSUSHIMA, 03
db CREDITS_WAIT, 12
db GAME_SCENARIO, 00
db JUNICHI_MASUDA, 01
db KOHJI_NISHINO, 02
db TOSHINOBU_MATSUMIYA, 03
db KENJI_MATSUSHIMA, 04
db CREDITS_WAIT, 12
db POKEDEX_TEXT, 01
db TOSHINOBU_MATSUMIYA, 02
db CREDITS_WAIT, 12
db TOOL_PROGRAMMING, 01
db SOUSUKE_TAMADA, 02
db TAKENORI_OOTA, 03
db CREDITS_WAIT, 12
db PARAMETRIC_DESIGN, 01
db KOHJI_NISHINO, 02
db CREDITS_WAIT, 12
; Clear the banner.
db CREDITS_CLEAR
db CREDITS_WAIT, 01
; Update the banner.
db CREDITS_SCENE, 02 ; Ditto
db SCRIPT_DESIGN, 01
db TETSUJI_OOTA, 02
db NOBUHIRO_SEYA, 03
db CREDITS_WAIT, 12
db MAP_DATA_DESIGN, 01
db TETSUJI_OOTA, 02
db KAZUHITO_SEKINE, 03
db CREDITS_WAIT, 12
db MAP_DESIGN, 00
db TETSUJI_OOTA, 01
db KOHJI_NISHINO, 02
db NOBUHIRO_SEYA, 03
db CREDITS_WAIT, 12
db COORDINATION, 01
db HIROYUKI_ZINNAI, 02
db CREDITS_WAIT, 12
db PRODUCERS, 00
db SATORU_IWATA, 01
db SATOSHI_YAMATO, 02
db SHIGERU_MIYAMOTO, 03
db CREDITS_WAIT, 12
db PRODUCERS, 01
db TSUNEKAZU_ISHIHARA, 02
db CREDITS_WAIT, 12
; Clear the banner.
db CREDITS_CLEAR
db CREDITS_WAIT, 01
; Update the banner.
db CREDITS_SCENE, 03 ; Igglybuff
db US_VERSION_STAFF, 02
db CREDITS_WAIT, 09
db US_COORDINATION, 01
db GAIL_TILDEN, 02
db HIRO_NAKAMURA, 03
db CREDITS_WAIT, 12
db US_COORDINATION, 01
db JUNICHI_MASUDA, 02
db SETH_MCMAHILL, 03
db CREDITS_WAIT, 12
db US_COORDINATION, 01
db HIROTO_ALEXANDER, 02
db TERESA_LILLYGREN, 03
db CREDITS_WAIT, 12
db TEXT_TRANSLATION, 01
db NOB_OGASAWARA, 02
db CREDITS_WAIT, 12
db PROGRAMMERS, 01
db TERUKI_MURAKAWA, 02
db KAZUYOSHI_OSAWA, 03
db CREDITS_WAIT, 12
db PAAD_TESTING, 01
db THOMAS_HERTZOG, 02
db ERIK_JOHNSON, 03
db CREDITS_WAIT, 12
db PRODUCT_TESTING, 00
db PLANNING, 01
db CREDITS_WAIT, 12
db PRODUCT_TESTING, 00
db KEITA_NAKAMURA, 01
db HIROTAKA_UEMURA, 02
db HIROAKI_TAMURA, 03
db NORIAKI_SAKAGUCHI, 04
db CREDITS_WAIT, 12
db PRODUCT_TESTING, 00
db NCL_SUPER_MARIO_CLUB, 01
db KENJI_SAIKI, 02
db ATSUSHI_TADA, 03
db MIYUKI_SATO, 04
db CREDITS_WAIT, 12
db SPECIAL_THANKS, 00
db KIMIKO_NAKAMICHI, 01
db AKITO_MORI, 02
db CREDITS_WAIT, 12
db SPECIAL_THANKS, 00
db GAKUZI_NOMOTO, 01
db AI_MASHIMA, 02
db KUNIMI_KAWAMURA, 03
db CREDITS_WAIT, 12
db SPECIAL_THANKS, 00
db MIKIHIRO_ISHIKAWA, 01
db HIDEYUKI_HASHIMOTO, 02
db CREDITS_WAIT, 12
db EXECUTIVE_PRODUCER, 01
db HIROSHI_YAMAUCHI, 02
db CREDITS_WAIT, 12
db COPYRIGHT, 01
db CREDITS_WAIT, 09
; Display "The End" graphic.
db CREDITS_THEEND
db CREDITS_WAIT, 20
db $ff ; end
; 10ae13
CreditsStrings:
dw .SatoshiTajiri
dw .JunichiMasuda
dw .TetsuyaWatanabe
dw .ShigekiMorimoto
dw .SousukeTamada
dw .TakenoriOota
dw .KenSugimori
dw .MotofumiFujiwara
dw .AtsukoNishida
dw .MuneoSaito
dw .SatoshiOota
dw .RenaYoshikawa
dw .JunOkutani
dw .HironobuYoshida
dw .AsukaIwashita
dw .GoIchinose
dw .MorikazuAoki
dw .KohjiNishino
dw .KenjiMatsushima
dw .ToshinobuMatsumiya
dw .SatoruIwata
dw .NobuhiroSeya
dw .KazuhitoSekine
dw .TetsujiOota
dw .NclSuperMarioClub
dw .Sarugakucho
dw .AkitoMori
dw .TakahiroHarada
dw .TohruHashimoto
dw .NoboruMatsumoto
dw .TakehiroIzushi
dw .TakashiKawaguchi
dw .TsunekazuIshihara
dw .HiroshiYamauchi
dw .KenjiSaiki
dw .AtsushiTada
dw .NaokoKawakami
dw .HiroyukiZinnai
dw .KunimiKawamura
dw .HisashiSogabe
dw .KeitaKagaya
dw .YoshinoriMatsuda
dw .HitomiSato
dw .ToruOsawa
dw .TakaoOhara
dw .YuichiroIto
dw .TakaoShimizu
dw .Planning
dw .KeitaNakamura
dw .HirotakaUemura
dw .HiroakiTamura
dw .NoriakiSakaguchi
dw .MiyukiSato
dw .GakuziNomoto
dw .AiMashima
dw .MikihiroIshikawa
dw .HideyukiHashimoto
dw .SatoshiYamato
dw .ShigeruMiyamoto
dw .GailTilden
dw .NobOgasawara
dw .SethMcMahill
dw .HirotoAlexander
dw .TeresaLillygren
dw .ThomasHertzog
dw .ErikJohnson
dw .HiroNakamura
dw .TerukiMurakawa
dw .KazuyoshiOsawa
dw .KimikoNakamichi
dw .End
dw .Unknown
dw .Staff
dw .Director
dw .CoDirector
dw .Programmers
dw .GraphicsDirector
dw .MonsterDesign
dw .GraphicsDesign
dw .Music
dw .SoundEffects
dw .GameDesign
dw .GameScenario
dw .ToolProgramming
dw .ParametricDesign
dw .ScriptDesign
dw .MapDataDesign
dw .MapDesign
dw .ProductTesting
dw .SpecialThanks
dw .Producers
dw .ExecutiveProducer
dw .PokemonAnimation
dw .PokedexText
dw .MobilePrjLeader
dw .MobileSystemAd
dw .MobileStadiumDir
dw .Coordination
dw .Copyright
dw .UsVersionStaff
dw .UsCoordination
dw .TextTranslation
dw .PaadTesting
.SatoshiTajiri: db " SATOSHI TAJIRI@" ; "たじり さとし@"
.JunichiMasuda: db " JUNICHI MASUDA@" ; "ますだ じゅんいち@"
.TetsuyaWatanabe: db " TETSUYA WATANABE@" ; "わたなべ てつや@"
.ShigekiMorimoto: db " SHIGEKI MORIMOTO@" ; "もりもと しげき@"
.SousukeTamada: db " SOUSUKE TAMADA@" ; "たまだ そうすけ@"
.TakenoriOota: db " TAKENORI OOTA@" ; "おおた たけのり@"
.KenSugimori: db " KEN SUGIMORI@" ; "すぎもり けん@"
.MotofumiFujiwara: db " MOTOFUMI FUJIWARA@" ; "ふじわら もとふみ@"
.AtsukoNishida: db " ATSUKO NISHIDA@" ; "にしだ あつこ@"
.MuneoSaito: db " MUNEO SAITO@" ; "さいとう むねお@"
.SatoshiOota: db " SATOSHI OOTA@" ; "おおた さとし@"
.RenaYoshikawa: db " RENA YOSHIKAWA@" ; "よしかわ れな@"
.JunOkutani: db " JUN OKUTANI@" ; "おくたに じゅん@"
.HironobuYoshida: db " HIRONOBU YOSHIDA@" ; "よしだ ひろのぶ@"
.AsukaIwashita: db " ASUKA IWASHITA@" ; "いわした あすか@"
.GoIchinose: db " GO ICHINOSE@" ; "いちのせ ごう@"
.MorikazuAoki: db " MORIKAZU AOKI@" ; "あおき もりかず@"
.KohjiNishino: db " KOHJI NISHINO@" ; "にしの こうじ@"
.KenjiMatsushima: db " KENJI MATSUSHIMA@" ; "まつしま けんじ@"
.ToshinobuMatsumiya: db "TOSHINOBU MATSUMIYA@" ; "まつみや としのぶ@"
.SatoruIwata: db " SATORU IWATA@" ; "いわた さとる@"
.NobuhiroSeya: db " NOBUHIRO SEYA@" ; "せや のぶひろ@"
.KazuhitoSekine: db " KAZUHITO SEKINE@" ; "せきね かずひと@"
.TetsujiOota: db " TETSUJI OOTA@" ; "おおた てつじ@"
.NclSuperMarioClub: db "NCL SUPER MARIO CLUB@" ; "スーパーマりォクラブ@"
.Sarugakucho: db " SARUGAKUCHO@" ; "さるがくちょう@"
.AkitoMori: db " AKITO MORI@" ; "もり あきと@"
.TakahiroHarada: db " TAKAHIRO HARADA@" ; "はらだ たかひろ@"
.TohruHashimoto: db " TOHRU HASHIMOTO@" ; "はしもと とおる@"
.NoboruMatsumoto: db " NOBORU MATSUMOTO@" ; "まつもと のぼる@"
.TakehiroIzushi: db " TAKEHIRO IZUSHI@" ; "いずし たけひろ@"
.TakashiKawaguchi: db " TAKASHI KAWAGUCHI@" ; "かわぐち たかし@"
.TsunekazuIshihara: db " TSUNEKAZU ISHIHARA@" ; "いしはら つねかず@"
.HiroshiYamauchi: db " HIROSHI YAMAUCHI@" ; "やまうち ひろし@"
.KenjiSaiki: db " KENJI SAIKI@" ; "さいき けんじ@"
.AtsushiTada: db " ATSUSHI TADA@" ; "ただ あつし@"
.NaokoKawakami: db " NAOKO KAWAKAMI@" ; "かわかみ なおこ@"
.HiroyukiZinnai: db " HIROYUKI ZINNAI@" ; "じんない ひろゆき@"
.KunimiKawamura: db " KUNIMI KAWAMURA@" ; "かわむら くにみ@"
.HisashiSogabe: db " HISASHI SOGABE@" ; "そがべ ひさし@"
.KeitaKagaya: db " KEITA KAGAYA@" ; "かがや けいた@"
.YoshinoriMatsuda: db " YOSHINORI MATSUDA@" ; "まつだ よしのり@"
.HitomiSato: db " HITOMI SATO@" ; "さとう ひとみ@"
.ToruOsawa: db " TORU OSAWA@" ; "おおさわ とおる@"
.TakaoOhara: db " TAKAO OHARA@" ; "おおはら たかお@"
.YuichiroIto: db " YUICHIRO ITO@" ; "いとう ゆういちろう@"
.TakaoShimizu: db " TAKAO SHIMIZU@" ; "しみず たかお@"
.Planning: db " SPECIAL PRODUCTION", $4e
db " PLANNING", $4e ; "きかくかいはつぶ@"
db " & DEVELOPMENT DEPT.@"
.KeitaNakamura: db " KEITA NAKAMURA@" ; "なかむら けいた@"
.HirotakaUemura: db " HIROTAKA UEMURA@" ; "うえむら ひろたか@"
.HiroakiTamura: db " HIROAKI TAMURA@" ; "たむら ひろあき@"
.NoriakiSakaguchi: db " NORIAKI SAKAGUCHI@" ; "さかぐち のりあき@"
.MiyukiSato: db " MIYUKI SATO@" ; "さとう みゆき@"
.GakuziNomoto: db " GAKUZI NOMOTO@" ; "のもと がくじ@"
.AiMashima: db " AI MASHIMA@" ; "ましま あい@"
.MikihiroIshikawa: db " MIKIHIRO ISHIKAWA@" ; "いしかわ みきひろ@"
.HideyukiHashimoto: db " HIDEYUKI HASHIMOTO@" ; "はしもと ひでゆき@"
.SatoshiYamato: db " SATOSHI YAMATO@" ; "やまと さとし@"
.ShigeruMiyamoto: db " SHIGERU MIYAMOTO@" ; "みやもと しげる@"
.End: db " END@" ; "おしまい@"
.Unknown: db " ????????@" ; "????????@"
.GailTilden: db " GAIL TILDEN@"
.NobOgasawara: db " NOB OGASAWARA@"
.SethMcMahill: db " SETH McMAHILL@"
.HirotoAlexander: db " HIROTO ALEXANDER@"
.TeresaLillygren: db " TERESA LILLYGREN@"
.ThomasHertzog: db " THOMAS HERTZOG@"
.ErikJohnson: db " ERIK JOHNSON@"
.HiroNakamura: db " HIRO NAKAMURA@"
.TerukiMurakawa: db " TERUKI MURAKAWA@"
.KazuyoshiOsawa: db " KAZUYOSHI OSAWA@"
.KimikoNakamichi: db " KIMIKO NAKAMICHI@"
.Staff: db " #MON", $4e ; "ポケットモンスター", $4e
db " CRYSTAL VERSION", $4e ; " クりスタル バージョン", $4e
db " STAFF@" ; " スタッフ@"
.Director: db " DIRECTOR@" ; "エグゼクティブ ディレクター@"
.CoDirector: db " CO-DIRECTOR@" ; "ディレクター@"
.Programmers: db " PROGRAMMERS@" ; "プログラム@"
.GraphicsDirector: db " GRAPHICS DIRECTOR@" ; "グラフィック ディレクター@"
.MonsterDesign: db " MONSTER DESIGN@" ; "# デザイン@"
.GraphicsDesign: db " GRAPHICS DESIGN@" ; "グラフィック デザイン@"
.Music: db " MUSIC@" ; "おんがく@"
.SoundEffects: db " SOUND EFFECTS@" ; "サウンド エフ→クト@"
.GameDesign: db " GAME DESIGN@" ; "ゲームデザイン@"
.GameScenario: db " GAME SCENARIO@" ; "シナりォ@"
.ToolProgramming: db " TOOL PROGRAMMING@" ; "ツール プログラム@"
.ParametricDesign: db " PARAMETRIC DESIGN@" ; "パラメーター せってい@"
.ScriptDesign: db " SCRIPT DESIGN@" ; "スクりプト せってい@"
.MapDataDesign: db " MAP DATA DESIGN@" ; "マップデータ せってい@"
.MapDesign: db " MAP DESIGN@" ; "マップ デザイン@"
.ProductTesting: db " PRODUCT TESTING@" ; "デバッグプレイ@"
.SpecialThanks: db " SPECIAL THANKS@" ; "スぺシャルサンクス@"
.Producers: db " PRODUCERS@" ; "プロデューサー@"
.ExecutiveProducer: db " EXECUTIVE PRODUCER@" ; "エグゼクティブ プロデューサー@"
.PokemonAnimation: db " #MON ANIMATION@" ; "# アニメーション@"
.PokedexText: db " #DEX TEXT@" ; "ずかん テキスト@"
.MobilePrjLeader: db " MOBILE PRJ. LEADER@" ; "モバイルプロジ→クト りーダー@"
.MobileSystemAd: db " MOBILE SYSTEM AD.@" ; "モバイル システムアドバイザー@"
.MobileStadiumDir: db "MOBILE STADIUM DIR.@" ; "モバイルスタジアム ディレクター@"
.Coordination: db " COORDINATION@" ; "コーディネーター@"
.UsVersionStaff: db " US VERSION STAFF@"
.UsCoordination: db " US COORDINATION@"
.TextTranslation: db " TEXT TRANSLATION@"
.PaadTesting: db " PAAD TESTING@"
.Copyright:
; (C) 1 9 9 5 - 2 0 0 1 N i n t e n d o
db $60,$61,$62,$63,$64,$65,$66, $67, $68, $69, $6a, $6b, $6c, $4e
; (C) 1 9 9 5 - 2 0 0 1 C r e a t u r e s i n c .
db $60,$61,$62,$63,$64,$65,$66, $6d, $6e, $6f, $70, $71, $72, $7a, $7b, $7c, $4e
; (C) 1 9 9 5 - 2 0 0 1 G A M E F R E A K i n c .
db $60,$61,$62,$63,$64,$65,$66, $73, $74, $75, $76, $77, $78, $79, $7a, $7b, $7c, "@"

View File

@ -2816,16 +2816,18 @@ pksv_crystal_more = {
0x9C: ["specialphonecall", ["call_id", MultiByteParam]],
0x9D: ["checkphonecall"],
0x9E: ["verbosegiveitem", ["item", ItemLabelByte], ["quantity", DecimalParam]],
0x9F: ["verbosegiveitem2", ["item", ItemLabelByte]],
0x9F: ["verbosegiveitem2", ["item", ItemLabelByte], ["var", SingleByteParam]],
0xA0: ["loadwilddata", ["map_group", MapGroupParam], ["map_id", MapIdParam]],
0xA1: ["halloffame"],
0xA2: ["credits"],
0xA3: ["warpfacing", ["facing", SingleByteParam], ["map_group", MapGroupParam], ["map_id", MapIdParam], ["x", SingleByteParam], ["y", SingleByteParam]],
0xA4: ["storetext", ["pointer", PointerLabelBeforeBank], ["memory", SingleByteParam]],
0xA5: ["displaylocation", ["id", SingleByteParam]],
0xA6: ["unknown0xa6"],
0xA7: ["unknown0xa7"],
0xA8: ["unknown0xa8", ["unknown", SingleByteParam]],
0xB2: ["unknown0xb2", ["unknown", SingleByteParam]],
0xCC: ["unknown0xcc"],
0xA9: ["unknown0xa9"],
0xAA: ["unknown0xaa"],
}
def create_command_classes(debug=False):
"""creates some classes for each command byte"""
@ -6322,489 +6324,9 @@ class PokedexEntry:
{4}""".format(self.species, self.weight, self.height, self.page1.to_asm(), self.page2.to_asm())
return output
# map names with no labels will be generated at the end of the structure
map_names = {
1: {
0x1: {"name": "Olivine Pokémon Center 1F",
"label": "OlivinePokeCenter1F"},
0x2: {"name": "Olivine Gym"},
0x3: {"name": "Olivine Voltorb House"},
0x4: {"name": "Olivine House Beta"},
0x5: {"name": "Olivine Punishment Speech House"},
0x6: {"name": "Olivine Good Rod House"},
0x7: {"name": "Olivine Cafe"},
0x8: {"name": "Olivine Mart"},
0x9: {"name": "Route 38 Ecruteak Gate"},
0xA: {"name": "Route 39 Barn"},
0xB: {"name": "Route 39 Farmhouse"},
0xC: {"name": "Route 38"},
0xD: {"name": "Route 39"},
0xE: {"name": "Olivine City"},
},
2: {
0x1: {"name": "Mahogany Red Gyarados Speech House"},
0x2: {"name": "Mahogany Gym"},
0x3: {"name": "Mahogany Pokémon Center 1F",
"label": "MahoganyPokeCenter1F"},
0x4: {"name": "Route 42 Ecruteak Gate"},
0x5: {"name": "Route 42"},
0x6: {"name": "Route 44"},
0x7: {"name": "Mahogany Town"},
},
3: {
0x1: {"name": "Sprout Tower 1F"},
0x2: {"name": "Sprout Tower 2F"},
0x3: {"name": "Sprout Tower 3F"},
0x4: {"name": "Tin Tower 1F"},
0x5: {"name": "Tin Tower 2F"},
0x6: {"name": "Tin Tower 3F"},
0x7: {"name": "Tin Tower 4F"},
0x8: {"name": "Tin Tower 5F"},
0x9: {"name": "Tin Tower 6F"},
0xA: {"name": "Tin Tower 7F"},
0xB: {"name": "Tin Tower 8F"},
0xC: {"name": "Tin Tower 9F"},
0xD: {"name": "Burned Tower 1F"},
0xE: {"name": "Burned Tower B1F"},
0xF: {"name": "National Park"},
0x10: {"name": "National Park Bug Contest"},
0x11: {"name": "Radio Tower 1F"},
0x12: {"name": "Radio Tower 2F"},
0x13: {"name": "Radio Tower 3F"},
0x14: {"name": "Radio Tower 4F"},
0x15: {"name": "Radio Tower 5F"},
0x16: {"name": "Ruins of Alph Outside"},
0x17: {"name": "Ruins of Alph Ho-oh Chamber"},
0x18: {"name": "Ruins of Alph Kabuto Chamber"},
0x19: {"name": "Ruins of Alph Omanyte Chamber"},
0x1A: {"name": "Ruins of Alph Aerodactyl Chamber"},
0x1B: {"name": "Ruins of Alph Inner Chamber"},
0x1C: {"name": "Ruins of Alph Research Center"},
0x1D: {"name": "Ruins of Alph Ho-oh Item Room"},
0x1E: {"name": "Ruins of Alph Kabuto Item Room"},
0x1F: {"name": "Ruins of Alph Omanyte Item Room"},
0x20: {"name": "Ruins of Alph Aerodactyl Item Room"},
0x21: {"name": "Ruins of Alph Ho-Oh Word Room"},
0x22: {"name": "Ruins of Alph Kabuto Word Room"},
0x23: {"name": "Ruins of Alph Omanyte Word Room"},
0x24: {"name": "Ruins of Alph Aerodactyl Word Room"},
0x25: {"name": "Union Cave 1F"},
0x26: {"name": "Union Cave B1F"},
0x27: {"name": "Union Cave B2F"},
0x28: {"name": "Slowpoke Well B1F"},
0x29: {"name": "Slowpoke Well B2F"},
0x2A: {"name": "Olivine Lighthouse 1F"},
0x2B: {"name": "Olivine Lighthouse 2F"},
0x2C: {"name": "Olivine Lighthouse 3F"},
0x2D: {"name": "Olivine Lighthouse 4F"},
0x2E: {"name": "Olivine Lighthouse 5F"},
0x2F: {"name": "Olivine Lighthouse 6F"},
0x30: {"name": "Mahogany Mart 1F"},
0x31: {"name": "Team Rocket Base B1F"},
0x32: {"name": "Team Rocket Base B2F"},
0x33: {"name": "Team Rocket Base B3F"},
0x34: {"name": "Ilex Forest"},
0x35: {"name": "Warehouse Entrance"},
0x36: {"name": "Underground Path Switch Room Entrances"},
0x37: {"name": "Goldenrod Dept Store B1F"},
0x38: {"name": "Underground Warehouse"},
0x39: {"name": "Mount Mortar 1F Outside"},
0x3A: {"name": "Mount Mortar 1F Inside"},
0x3B: {"name": "Mount Mortar 2F Inside"},
0x3C: {"name": "Mount Mortar B1F"},
0x3D: {"name": "Ice Path 1F"},
0x3E: {"name": "Ice Path B1F"},
0x3F: {"name": "Ice Path B2F Mahogany Side"},
0x40: {"name": "Ice Path B2F Blackthorn Side"},
0x41: {"name": "Ice Path B3F"},
0x42: {"name": "Whirl Island NW"},
0x43: {"name": "Whirl Island NE"},
0x44: {"name": "Whirl Island SW"},
0x45: {"name": "Whirl Island Cave"},
0x46: {"name": "Whirl Island SE"},
0x47: {"name": "Whirl Island B1F"},
0x48: {"name": "Whirl Island B2F"},
0x49: {"name": "Whirl Island Lugia Chamber"},
0x4A: {"name": "Silver Cave Room 1"},
0x4B: {"name": "Silver Cave Room 2"},
0x4C: {"name": "Silver Cave Room 3"},
0x4D: {"name": "Silver Cave Item Rooms"},
0x4E: {"name": "Dark Cave Violet Entrance"},
0x4F: {"name": "Dark Cave Blackthorn Entrance"},
0x50: {"name": "Dragon's Den 1F"},
0x51: {"name": "Dragon's Den B1F"},
0x52: {"name": "Dragon Shrine"},
0x53: {"name": "Tohjo Falls"},
0x54: {"name": "Diglett's Cave"},
0x55: {"name": "Mount Moon"},
0x56: {"name": "Underground"},
0x57: {"name": "Rock Tunnel 1F"},
0x58: {"name": "Rock Tunnel B1F"},
0x59: {"name": "Safari Zone Fuchsia Gate Beta"},
0x5A: {"name": "Safari Zone Beta"},
0x5B: {"name": "Victory Road"},
},
4: {
0x1: {"name": "Ecruteak House"}, # passage to Tin Tower
0x2: {"name": "Wise Trio's Room"},
0x3: {"name": "Ecruteak Pokémon Center 1F",
"label": "EcruteakPokeCenter1F"},
0x4: {"name": "Ecruteak Lugia Speech House"},
0x5: {"name": "Dance Theatre"},
0x6: {"name": "Ecruteak Mart"},
0x7: {"name": "Ecruteak Gym"},
0x8: {"name": "Ecruteak Itemfinder House"},
0x9: {"name": "Ecruteak City"},
},
5: {
0x1: {"name": "Blackthorn Gym 1F"},
0x2: {"name": "Blackthorn Gym 2F"},
0x3: {"name": "Blackthorn Dragon Speech House"},
0x4: {"name": "Blackthorn Dodrio Trade House"},
0x5: {"name": "Blackthorn Mart"},
0x6: {"name": "Blackthorn Pokémon Center 1F",
"label": "BlackthornPokeCenter1F"},
0x7: {"name": "Move Deleter's House"},
0x8: {"name": "Route 45"},
0x9: {"name": "Route 46"},
0xA: {"name": "Blackthorn City"},
},
6: {
0x1: {"name": "Cinnabar Pokémon Center 1F",
"label": "CinnabarPokeCenter1F"},
0x2: {"name": "Cinnabar Pokémon Center 2F Beta",
"label": "CinnabarPokeCenter2FBeta"},
0x3: {"name": "Route 19 - Fuchsia Gate"},
0x4: {"name": "Seafoam Gym"},
0x5: {"name": "Route 19"},
0x6: {"name": "Route 20"},
0x7: {"name": "Route 21"},
0x8: {"name": "Cinnabar Island"},
},
7: {
0x1: {"name": "Cerulean Gym Badge Speech House"},
0x2: {"name": "Cerulean Police Station"},
0x3: {"name": "Cerulean Trade Speech House"},
0x4: {"name": "Cerulean Pokémon Center 1F",
"label": "CeruleanPokeCenter1F"},
0x5: {"name": "Cerulean Pokémon Center 2F Beta",
"label": "CeruleanPokeCenter2FBeta"},
0x6: {"name": "Cerulean Gym"},
0x7: {"name": "Cerulean Mart"},
0x8: {"name": "Route 10 Pokémon Center 1F",
"label": "Route10PokeCenter1F"},
0x9: {"name": "Route 10 Pokémon Center 2F Beta",
"label": "Route10PokeCenter2FBeta"},
0xA: {"name": "Power Plant"},
0xB: {"name": "Bill's House"},
0xC: {"name": "Route 4"},
0xD: {"name": "Route 9"},
0xE: {"name": "Route 10 North"},
0xF: {"name": "Route 24"},
0x10: {"name": "Route 25"},
0x11: {"name": "Cerulean City"},
},
8: {
0x1: {"name": "Azalea Pokémon Center 1F",
"label": "AzaleaPokeCenter1F"},
0x2: {"name": "Charcoal Kiln"},
0x3: {"name": "Azalea Mart"},
0x4: {"name": "Kurt's House"},
0x5: {"name": "Azalea Gym"},
0x6: {"name": "Route 33"},
0x7: {"name": "Azalea Town"},
},
9: {
0x1: {"name": "Lake of Rage Hidden Power House"},
0x2: {"name": "Lake of Rage Magikarp House"},
0x3: {"name": "Route 43 Mahogany Gate"},
0x4: {"name": "Route 43 Gate"},
0x5: {"name": "Route 43"},
0x6: {"name": "Lake of Rage"},
},
10: {
0x1: {"name": "Route 32"},
0x2: {"name": "Route 35"},
0x3: {"name": "Route 36"},
0x4: {"name": "Route 37"},
0x5: {"name": "Violet City"},
0x6: {"name": "Violet Mart"},
0x7: {"name": "Violet Gym"},
0x8: {"name": "Earl's Pokémon Academy",
"label": "EarlsPokemonAcademy"},
0x9: {"name": "Violet Nickname Speech House"},
0xA: {"name": "Violet Pokémon Center 1F",
"label": "VioletPokeCenter1F"},
0xB: {"name": "Violet Onix Trade House"},
0xC: {"name": "Route 32 Ruins of Alph Gate"},
0xD: {"name": "Route 32 Pokémon Center 1F",
"label": "Route32PokeCenter1F"},
0xE: {"name": "Route 35 Goldenrod gate"},
0xF: {"name": "Route 35 National Park gate"},
0x10: {"name": "Route 36 Ruins of Alph gate"},
0x11: {"name": "Route 36 National Park gate"},
},
11: {
0x1: {"name": "Route 34"},
0x2: {"name": "Goldenrod City"},
0x3: {"name": "Goldenrod Gym"},
0x4: {"name": "Goldenrod Bike Shop"},
0x5: {"name": "Goldenrod Happiness Rater"},
0x6: {"name": "Goldenrod Bill's House"},
0x7: {"name": "Goldenrod Magnet Train Station"},
0x8: {"name": "Goldenrod Flower Shop"},
0x9: {"name": "Goldenrod PP Speech House"},
0xA: {"name": "Goldenrod Name Rater's House"},
0xB: {"name": "Goldenrod Dept Store 1F"},
0xC: {"name": "Goldenrod Dept Store 2F"},
0xD: {"name": "Goldenrod Dept Store 3F"},
0xE: {"name": "Goldenrod Dept Store 4F"},
0xF: {"name": "Goldenrod Dept Store 5F"},
0x10: {"name": "Goldenrod Dept Store 6F"},
0x11: {"name": "Goldenrod Dept Store Elevator"},
0x12: {"name": "Goldenrod Dept Store Roof"},
0x13: {"name": "Goldenrod Game Corner"},
0x14: {"name": "Goldenrod Pokémon Center 1F",
"label": "GoldenrodPokeCenter1F"},
0x15: {"name": "Goldenrod PokéCom Center 2F Mobile",
"label": "GoldenrodPokeComCenter2FMobile"},
0x16: {"name": "Ilex Forest Azalea Gate"},
0x17: {"name": "Route 34 Ilex Forest Gate"},
0x18: {"name": "Day Care"},
},
12: {
0x1: {"name": "Route 6"},
0x2: {"name": "Route 11"},
0x3: {"name": "Vermilion City"},
0x4: {"name": "Vermilion House Fishing Speech House"},
0x5: {"name": "Vermilion Pokémon Center 1F",
"label": "VermilionPokeCenter1F"},
0x6: {"name": "Vermilion Pokémon Center 2F Beta",
"label": "VermilionPokeCenter2FBeta"},
0x7: {"name": "Pokémon Fan Club"},
0x8: {"name": "Vermilion Magnet Train Speech House"},
0x9: {"name": "Vermilion Mart"},
0xA: {"name": "Vermilion House Diglett's Cave Speech House"},
0xB: {"name": "Vermilion Gym"},
0xC: {"name": "Route 6 Saffron Gate"},
0xD: {"name": "Route 6 Underground Entrance"},
},
13: {
0x1: {"name": "Route 1"},
0x2: {"name": "Pallet Town"},
0x3: {"name": "Red's House 1F"},
0x4: {"name": "Red's House 2F"},
0x5: {"name": "Blue's House"},
0x6: {"name": "Oak's Lab"},
},
14: {
0x1: {"name": "Route 3"},
0x2: {"name": "Pewter City"},
0x3: {"name": "Pewter Nidoran Speech House"},
0x4: {"name": "Pewter Gym"},
0x5: {"name": "Pewter Mart"},
0x6: {"name": "Pewter Pokémon Center 1F",
"label": "PewterPokeCenter1F"},
0x7: {"name": "Pewter Pokémon Center 2F Beta",
"label": "PewterPokeCEnter2FBeta"},
0x8: {"name": "Pewter Snooze Speech House"},
},
15: {
0x1: {"name": "Olivine Port"},
0x2: {"name": "Vermilion Port"},
0x3: {"name": "Fast Ship 1F"},
0x4: {"name": "Fast Ship Cabins NNW, NNE, NE",
"label": "FastShipCabins_NNW_NNE_NE"},
0x5: {"name": "Fast Ship Cabins SW, SSW, NW",
"label": "FastShipCabins_SW_SSW_NW"},
0x6: {"name": "Fast Ship Cabins SE, SSE, Captain's Cabin",
"label": "FastShipCabins_SE_SSE_CaptainsCabin"},
0x7: {"name": "Fast Ship B1F"},
0x8: {"name": "Olivine Port Passage"},
0x9: {"name": "Vermilion Port Passage"},
0xA: {"name": "Mount Moon Square"},
0xB: {"name": "Mount Moon Gift Shop"},
0xC: {"name": "Tin Tower Roof"},
},
16: {
0x1: {"name": "Route 23"},
0x2: {"name": "Indigo Plateau Pokémon Center 1F",
"label": "IndigoPlateauPokeCenter1F"},
0x3: {"name": "Will's Room"},
0x4: {"name": "Koga's Room"},
0x5: {"name": "Bruno's Room"},
0x6: {"name": "Karen's Room"},
0x7: {"name": "Lance's Room"},
0x8: {"name": "Hall of Fame",
"label": "HallOfFame"},
},
17: {
0x1: {"name": "Route 13"},
0x2: {"name": "Route 14"},
0x3: {"name": "Route 15"},
0x4: {"name": "Route 18"},
0x5: {"name": "Fuchsia City"},
0x6: {"name": "Fuchsia Mart"},
0x7: {"name": "Safari Zone Main Office"},
0x8: {"name": "Fuchsia Gym"},
0x9: {"name": "Fuchsia Bill Speech House"},
0xA: {"name": "Fuchsia Pokémon Center 1F",
"label": "FuchsiaPokeCenter1F"},
0xB: {"name": "Fuchsia Pokémon Center 2F Beta",
"label": "FuchsiaPokeCenter2FBeta"},
0xC: {"name": "Safari Zone Warden's Home"},
0xD: {"name": "Route 15 Fuchsia Gate"},
},
18: {
0x1: {"name": "Route 8"},
0x2: {"name": "Route 12"},
0x3: {"name": "Route 10 South"},
0x4: {"name": "Lavender Town"},
0x5: {"name": "Lavender Pokémon Center 1F",
"label": "LavenderPokeCenter1F"},
0x6: {"name": "Lavender Pokémon Center 2F Beta",
"label": "LavenderPokeCenter2FBeta"},
0x7: {"name": "Mr. Fuji's House"},
0x8: {"name": "Lavender Town Speech House"},
0x9: {"name": "Lavender Name Rater"},
0xA: {"name": "Lavender Mart"},
0xB: {"name": "Soul House"},
0xC: {"name": "Lav Radio Tower 1F"},
0xD: {"name": "Route 8 Saffron Gate"},
0xE: {"name": "Route 12 Super Rod House"},
},
19: {
0x1: {"name": "Route 28"},
0x2: {"name": "Silver Cave Outside"},
0x3: {"name": "Silver Cave Pokémon Center 1F",
"label": "SilverCavePokeCenter1F"},
0x4: {"name": "Route 28 Famous Speech House"},
},
20: {
0x1: {"name": "Pokémon Center 2F",
"label": "PokeCenter2F"},
0x2: {"name": "Trade Center"},
0x3: {"name": "Colosseum"},
0x4: {"name": "Time Capsule"},
0x5: {"name": "Mobile Trade Room Mobile"},
0x6: {"name": "Mobile Battle Room"},
},
21: {
0x1: {"name": "Route 7"},
0x2: {"name": "Route 16"},
0x3: {"name": "Route 17"},
0x4: {"name": "Celadon City"},
0x5: {"name": "Celadon Dept Store 1F"},
0x6: {"name": "Celadon Dept Store 2F"},
0x7: {"name": "Celadon Dept Store 3F"},
0x8: {"name": "Celadon Dept Store 4F"},
0x9: {"name": "Celadon Dept Store 5F"},
0xA: {"name": "Celadon Dept Store 6F"},
0xB: {"name": "Celadon Dept Store Elevator"},
0xC: {"name": "Celadon Mansion 1F"},
0xD: {"name": "Celadon Mansion 2F"},
0xE: {"name": "Celadon Mansion 3F"},
0xF: {"name": "Celadon Mansion Roof"},
0x10: {"name": "Celadon Mansion Roof House"},
0x11: {"name": "Celadon Pokémon Center 1F",
"label": "CeladonPokeCenter1F"},
0x12: {"name": "Celadon Pokémon Center 2F Beta",
"label": "CeladonPokeCenter2FBeta"},
0x13: {"name": "Celadon Game Corner"},
0x14: {"name": "Celadon Game Corner Prize Room"},
0x15: {"name": "Celadon Gym"},
0x16: {"name": "Celadon Cafe"},
0x17: {"name": "Route 16 Fuchsia Speech House"},
0x18: {"name": "Route 16 Gate"},
0x19: {"name": "Route 7 Saffron Gate"},
0x1A: {"name": "Route 17 18 Gate"},
},
22: {
0x1: {"name": "Route 40"},
0x2: {"name": "Route 41"},
0x3: {"name": "Cianwood City"},
0x4: {"name": "Mania's House"},
0x5: {"name": "Cianwood Gym"},
0x6: {"name": "Cianwood Pokémon Center 1F",
"label": "CianwoodPokeCenter1F"},
0x7: {"name": "Cianwood Pharmacy"},
0x8: {"name": "Cianwood City Photo Studio"},
0x9: {"name": "Cianwood Lugia Speech House"},
0xA: {"name": "Poke Seer's House"},
0xB: {"name": "Battle Tower 1F"},
0xC: {"name": "Battle Tower Battle Room"},
0xD: {"name": "Battle Tower Elevator"},
0xE: {"name": "Battle Tower Hallway"},
0xF: {"name": "Route 40 Battle Tower Gate"},
0x10: {"name": "Battle Tower Outside"},
},
23: {
0x1: {"name": "Route 2"},
0x2: {"name": "Route 22"},
0x3: {"name": "Viridian City"},
0x4: {"name": "Viridian Gym"},
0x5: {"name": "Viridian Nickname Speech House"},
0x6: {"name": "Trainer House 1F"},
0x7: {"name": "Trainer House B1F"},
0x8: {"name": "Viridian Mart"},
0x9: {"name": "Viridian Pokémon Center 1F",
"label": "ViridianPokeCenter1F"},
0xA: {"name": "Viridian Pokémon Center 2F Beta",
"label": "ViridianPokeCenter2FBeta"},
0xB: {"name": "Route 2 Nugget Speech House"},
0xC: {"name": "Route 2 Gate"},
0xD: {"name": "Victory Road Gate"},
},
24: {
0x1: {"name": "Route 26"},
0x2: {"name": "Route 27"},
0x3: {"name": "Route 29"},
0x4: {"name": "New Bark Town"},
0x5: {"name": "Elm's Lab"},
0x6: {"name": "Kris's House 1F"},
0x7: {"name": "Kris's House 2F"},
0x8: {"name": "Kris's Neighbor's House"},
0x9: {"name": "Elm's House"},
0xA: {"name": "Route 26 Heal Speech House"},
0xB: {"name": "Route 26 Day of Week Siblings House"},
0xC: {"name": "Route 27 Sandstorm House"},
0xD: {"name": "Route 29 46 Gate"},
},
25: {
0x1: {"name": "Route 5"},
0x2: {"name": "Saffron City"},
0x3: {"name": "Fighting Dojo"},
0x4: {"name": "Saffron Gym"},
0x5: {"name": "Saffron Mart"},
0x6: {"name": "Saffron Pokémon Center 1F",
"label": "SaffronPokeCenter1F"},
0x7: {"name": "Saffron Pokémon Center 2F Beta",
"label": "SaffronPokeCenter2FBeta"},
0x8: {"name": "Mr. Psychic's House"},
0x9: {"name": "Saffron Train Station"},
0xA: {"name": "Silph Co. 1F"},
0xB: {"name": "Copycat's House 1F"},
0xC: {"name": "Copycat's House 2F"},
0xD: {"name": "Route 5 Underground Entrance"},
0xE: {"name": "Route 5 Saffron City Gate"},
0xF: {"name": "Route 5 Cleanse Tag Speech House"},
},
26: {
0x1: {"name": "Route 30"},
0x2: {"name": "Route 31"},
0x3: {"name": "Cherrygrove City"},
0x4: {"name": "Cherrygrove Mart"},
0x5: {"name": "Cherrygrove Pokémon Center 1F",
"label": "CherrygrovePokeCenter1F"},
0x6: {"name": "Cherrygrove Gym Speech House"},
0x7: {"name": "Guide Gent's House"},
0x8: {"name": "Cherrygrove Evolution Speech House"},
0x9: {"name": "Route 30 Berry Speech House"},
0xA: {"name": "Mr. Pokémon's House"},
0xB: {"name": "Route 31 Violet Gate"},
},
}
from map_names import map_names
# map names with no labels will be generated
# generate labels for each map name
for map_group_id in map_names.keys():
map_group = map_names[map_group_id]
@ -6834,7 +6356,7 @@ incbin_lines = []
# storage for processed incbin lines
processed_incbins = {}
def to_asm(some_object):
def to_asm(some_object, use_asm_rules=False):
"""shows an object's asm with a label and an ending comment
showing the next byte address"""
if isinstance(some_object, int):
@ -6850,6 +6372,9 @@ def to_asm(some_object):
asmr = asmr.replace("\n"+spacing+"\n", "\n\n"+spacing)
asmr = asmr.replace("\n\n"+spacing+spacing, "\n\n"+spacing)
asm += spacing + asmr
if use_asm_rules:
asm = asm.replace("\n" + spacing + "; ", "\n; ")
asm = asm.replace("\n" + spacing + ".asm_", "\n.asm_")
# show the address of the next byte below this
asm += "\n; " + hex(last_address)
return asm
@ -7223,7 +6748,7 @@ class Asm:
asm_list = AsmList(asm)
bank = 0
for line in asm_list:
if line[0:6] == "INCBIN" or line[1:6] == "INCBIN":
if (line[0:6] == "INCBIN" or line[1:6] == "INCBIN") and not any([contaminant+"\"" in line for contaminant in [".2bpp", ".1bpp", ".asm", ".lz"]]):
thing = Incbin(line, bank=bank)
elif line[0:7] == "SECTION":
thing = AsmSection(line)
@ -7288,11 +6813,13 @@ class Asm:
# check if the object is already inserted
if new_object in self.parts:
print "object was previously inserted ("+str(new_object)+")"
print "object was previously inserted ("+str(new_object)+"; " + hex(new_object.address) + ")"
return
# check by label
if self.is_label_name_in_file(new_object.label.name):
print "object was previously inserted ("+str(new_object)+") by label: "+new_object.label.name
other_obj = self.is_label_name_in_file(new_object.label.name)
if other_obj:
other_obj = other_obj.object
print "object was previously inserted ("+new_object.label.name+" at "+hex(new_object.address)+") by "+other_obj.label.name+" at "+hex(other_obj.address)
return
# check by address
#if self.does_address_have_label(new_object.address):

View File

@ -0,0 +1,151 @@
# -*- encoding: utf-8 -*-
"""
Dump out asm for scripting things in bank $25. This script will modify main.asm
and insert all scripting commands.
"""
import crystal
from gbz80disasm import output_bank_opcodes
rom = crystal.load_rom()
roml = [ord(x) for x in rom]
script_command_table_address = 0x96cb1
script_command_count = 170
# a list of addresses for each script command
command_pointers = [crystal.calculate_pointer_from_bytes_at(script_command_table_address + (id * 2), bank=0x25) for id in range(0, 170)]
# a list of hex addresses for each script command in bank $25
command_pointers_hex = ["$%.2x" % (x % 0x4000 + 0x4000) for x in command_pointers]
commands = {}
# force data into a more usable form
for command in crystal.command_classes:
name = "Script_" + command.macro_name
id = command.id
params = {}
for (id2, param_type) in command.param_types.items():
param = {
"name": param_type["name"],
"type": param_type["class"].__name__,
}
params[id2] = param
if id <= 0xa9:
commands[id] = {
"name": name,
"params": params,
"address": command_pointers[id],
}
avoid = [
0x974b0,
0x974be,
0x9754b,
0x97556,
0x97562,
0x9756e,
0x97540,
0x96f8e, # verbosegiveitem2
]
class DisassembledScriptCommand():
"""
Just a temporary object to store information about a script command's asm.
This is used by some of the infrastructure in crystal.py to automatically
insert asm into main.asm, rather than having someone do it manually.
"""
dependencies = None
def __init__(self, label=None, id=None, address=None, params=None):
self.id = id
self.label = crystal.Label(name=label, address=address, object=self)
self.address = address
self.params = params
max_byte_count = 0x4000
# Some of these scripts need to be truncated before insertion, because
# output_bank_opcodes doesn't know anything about stopping if some of
# the local labels are not resolved yet.
# Script_if_equal
if address == 0x97540:
max_byte_count = 86
# disassemble and laso get the last address
(asm, last_address, last_hl_address, last_a_address, used_3d97) = output_bank_opcodes(address, max_byte_count=max_byte_count, stop_at=command_pointers, include_last_address=False)
# remove indentation
asm = asm.replace("\n\t", "\n")
if asm[0] == "\t":
asm = asm[1:]
# remove the last two newlines
while asm[-1] == "\n":
asm = asm[:-1]
self.asm = asm
self.last_address = last_address
# make sure this gets dumped into main.asm
#if crystal.script_parse_table[self.address] == None and crystal.script_parse_table[self.last_address] == None:
crystal.script_parse_table[self.address : self.last_address] = self
#else:
# print ".. hm, something is already at " + hex(self.address) + " for " + self.label.name
def to_asm(self):
#output += self.label + ": ; " + hex(self.address) + "\n"
output = "; script command " + hex(self.id) + "\n"
if len(self.params) > 0:
output += "; parameters:\n"
for (id2, param) in self.params.items():
output += "; " + param["name"] + " (" + param["type"] + ")\n"
output += "\n"
output += self.asm
return output
def get_dependencies(*args, **kwargs):
return []
# make instances of DisassembledScriptCommand
for (id, command) in commands.items():
name = command["name"]
params = command["params"]
address = command["address"]
script_asm = DisassembledScriptCommand(label=name, id=id, address=address, params=params)
#print script_asm.to_asm()
#print crystal.to_asm(script_asm, use_asm_rules=True)
class ScriptCommandTable():
address = script_command_table_address
last_address = script_command_table_address + (2 * 170)
dependencies = None
def __init__(self):
self.label = crystal.Label(name="ScriptCommandTable", address=self.address, object=self)
# make sure this gets dumped into main.asm
crystal.script_parse_table[self.address : self.last_address] = self
def get_dependencies(*args, **kwargs):
return []
def to_asm(self):
output = ""
for (id, command) in commands.items():
output += "dw " + command["name"] + "; " + hex(command["address"]) + "\n"
if output[-1] == "\n":
output = output[:-1]
return output
script_command_table = ScriptCommandTable()
#print crystal.to_asm(script_command_table, use_asm_rules=True)
# automatic asm insertion
asm = crystal.Asm()
asm.insert_and_dump(limit=500)

View File

@ -592,7 +592,7 @@ def asm_label(address):
# why using a random value when you can use the address?
return ".ASM_" + hex(address)[2:]
def output_bank_opcodes(original_offset, max_byte_count=0x4000, debug = False):
def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_address=True, stop_at=[], debug = False):
#fs = current_address
#b = bank_byte
#in = input_data -- rom
@ -601,6 +601,10 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, debug = False):
#ad = end_address
#a, oa = current_byte_number
# stop_at can be used to supply a list of addresses to not disassemble
# over. This is useful if you know in advance that there are a lot of
# fall-throughs.
load_labels()
load_rom()
@ -622,6 +626,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, debug = False):
byte_labels = {}
first_loop = True
output = ""
keep_reading = True
while offset <= end_address and keep_reading:
@ -629,6 +634,11 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, debug = False):
is_data = False
maybe_byte = current_byte
# stop at any address
if not first_loop and offset in stop_at:
keep_reading = False
break
#first check if this byte already has a label
#if it does, use the label
#if not, generate a new label
@ -816,6 +826,8 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, debug = False):
#offset += 1
#current_byte_number += 1
first_loop = False
#clean up unused labels
for label_line in byte_labels.keys():
address = label_line
@ -824,7 +836,8 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, debug = False):
output = output.replace((label_line["name"] + "\n").lower(), "")
#add the offset of the final location
output += "; " + hex(offset)
if include_last_address:
output += "; " + hex(offset)
return (output, offset, last_hl_address, last_a_address, used_3d97)

486
extras/map_names.py Normal file
View File

@ -0,0 +1,486 @@
# -*- coding: utf-8 -*-
"""
"""
# this is modified in crystal.py during run-time
map_names = {
1: {
0x1: {"name": "Olivine Pokémon Center 1F",
"label": "OlivinePokeCenter1F"},
0x2: {"name": "Olivine Gym"},
0x3: {"name": "Olivine Voltorb House"},
0x4: {"name": "Olivine House Beta"},
0x5: {"name": "Olivine Punishment Speech House"},
0x6: {"name": "Olivine Good Rod House"},
0x7: {"name": "Olivine Cafe"},
0x8: {"name": "Olivine Mart"},
0x9: {"name": "Route 38 Ecruteak Gate"},
0xA: {"name": "Route 39 Barn"},
0xB: {"name": "Route 39 Farmhouse"},
0xC: {"name": "Route 38"},
0xD: {"name": "Route 39"},
0xE: {"name": "Olivine City"},
},
2: {
0x1: {"name": "Mahogany Red Gyarados Speech House"},
0x2: {"name": "Mahogany Gym"},
0x3: {"name": "Mahogany Pokémon Center 1F",
"label": "MahoganyPokeCenter1F"},
0x4: {"name": "Route 42 Ecruteak Gate"},
0x5: {"name": "Route 42"},
0x6: {"name": "Route 44"},
0x7: {"name": "Mahogany Town"},
},
3: {
0x1: {"name": "Sprout Tower 1F"},
0x2: {"name": "Sprout Tower 2F"},
0x3: {"name": "Sprout Tower 3F"},
0x4: {"name": "Tin Tower 1F"},
0x5: {"name": "Tin Tower 2F"},
0x6: {"name": "Tin Tower 3F"},
0x7: {"name": "Tin Tower 4F"},
0x8: {"name": "Tin Tower 5F"},
0x9: {"name": "Tin Tower 6F"},
0xA: {"name": "Tin Tower 7F"},
0xB: {"name": "Tin Tower 8F"},
0xC: {"name": "Tin Tower 9F"},
0xD: {"name": "Burned Tower 1F"},
0xE: {"name": "Burned Tower B1F"},
0xF: {"name": "National Park"},
0x10: {"name": "National Park Bug Contest"},
0x11: {"name": "Radio Tower 1F"},
0x12: {"name": "Radio Tower 2F"},
0x13: {"name": "Radio Tower 3F"},
0x14: {"name": "Radio Tower 4F"},
0x15: {"name": "Radio Tower 5F"},
0x16: {"name": "Ruins of Alph Outside"},
0x17: {"name": "Ruins of Alph Ho-oh Chamber"},
0x18: {"name": "Ruins of Alph Kabuto Chamber"},
0x19: {"name": "Ruins of Alph Omanyte Chamber"},
0x1A: {"name": "Ruins of Alph Aerodactyl Chamber"},
0x1B: {"name": "Ruins of Alph Inner Chamber"},
0x1C: {"name": "Ruins of Alph Research Center"},
0x1D: {"name": "Ruins of Alph Ho-oh Item Room"},
0x1E: {"name": "Ruins of Alph Kabuto Item Room"},
0x1F: {"name": "Ruins of Alph Omanyte Item Room"},
0x20: {"name": "Ruins of Alph Aerodactyl Item Room"},
0x21: {"name": "Ruins of Alph Ho-Oh Word Room"},
0x22: {"name": "Ruins of Alph Kabuto Word Room"},
0x23: {"name": "Ruins of Alph Omanyte Word Room"},
0x24: {"name": "Ruins of Alph Aerodactyl Word Room"},
0x25: {"name": "Union Cave 1F"},
0x26: {"name": "Union Cave B1F"},
0x27: {"name": "Union Cave B2F"},
0x28: {"name": "Slowpoke Well B1F"},
0x29: {"name": "Slowpoke Well B2F"},
0x2A: {"name": "Olivine Lighthouse 1F"},
0x2B: {"name": "Olivine Lighthouse 2F"},
0x2C: {"name": "Olivine Lighthouse 3F"},
0x2D: {"name": "Olivine Lighthouse 4F"},
0x2E: {"name": "Olivine Lighthouse 5F"},
0x2F: {"name": "Olivine Lighthouse 6F"},
0x30: {"name": "Mahogany Mart 1F"},
0x31: {"name": "Team Rocket Base B1F"},
0x32: {"name": "Team Rocket Base B2F"},
0x33: {"name": "Team Rocket Base B3F"},
0x34: {"name": "Ilex Forest"},
0x35: {"name": "Warehouse Entrance"},
0x36: {"name": "Underground Path Switch Room Entrances"},
0x37: {"name": "Goldenrod Dept Store B1F"},
0x38: {"name": "Underground Warehouse"},
0x39: {"name": "Mount Mortar 1F Outside"},
0x3A: {"name": "Mount Mortar 1F Inside"},
0x3B: {"name": "Mount Mortar 2F Inside"},
0x3C: {"name": "Mount Mortar B1F"},
0x3D: {"name": "Ice Path 1F"},
0x3E: {"name": "Ice Path B1F"},
0x3F: {"name": "Ice Path B2F Mahogany Side"},
0x40: {"name": "Ice Path B2F Blackthorn Side"},
0x41: {"name": "Ice Path B3F"},
0x42: {"name": "Whirl Island NW"},
0x43: {"name": "Whirl Island NE"},
0x44: {"name": "Whirl Island SW"},
0x45: {"name": "Whirl Island Cave"},
0x46: {"name": "Whirl Island SE"},
0x47: {"name": "Whirl Island B1F"},
0x48: {"name": "Whirl Island B2F"},
0x49: {"name": "Whirl Island Lugia Chamber"},
0x4A: {"name": "Silver Cave Room 1"},
0x4B: {"name": "Silver Cave Room 2"},
0x4C: {"name": "Silver Cave Room 3"},
0x4D: {"name": "Silver Cave Item Rooms"},
0x4E: {"name": "Dark Cave Violet Entrance"},
0x4F: {"name": "Dark Cave Blackthorn Entrance"},
0x50: {"name": "Dragon's Den 1F"},
0x51: {"name": "Dragon's Den B1F"},
0x52: {"name": "Dragon Shrine"},
0x53: {"name": "Tohjo Falls"},
0x54: {"name": "Diglett's Cave"},
0x55: {"name": "Mount Moon"},
0x56: {"name": "Underground"},
0x57: {"name": "Rock Tunnel 1F"},
0x58: {"name": "Rock Tunnel B1F"},
0x59: {"name": "Safari Zone Fuchsia Gate Beta"},
0x5A: {"name": "Safari Zone Beta"},
0x5B: {"name": "Victory Road"},
},
4: {
0x1: {"name": "Ecruteak House"}, # passage to Tin Tower
0x2: {"name": "Wise Trio's Room"},
0x3: {"name": "Ecruteak Pokémon Center 1F",
"label": "EcruteakPokeCenter1F"},
0x4: {"name": "Ecruteak Lugia Speech House"},
0x5: {"name": "Dance Theatre"},
0x6: {"name": "Ecruteak Mart"},
0x7: {"name": "Ecruteak Gym"},
0x8: {"name": "Ecruteak Itemfinder House"},
0x9: {"name": "Ecruteak City"},
},
5: {
0x1: {"name": "Blackthorn Gym 1F"},
0x2: {"name": "Blackthorn Gym 2F"},
0x3: {"name": "Blackthorn Dragon Speech House"},
0x4: {"name": "Blackthorn Dodrio Trade House"},
0x5: {"name": "Blackthorn Mart"},
0x6: {"name": "Blackthorn Pokémon Center 1F",
"label": "BlackthornPokeCenter1F"},
0x7: {"name": "Move Deleter's House"},
0x8: {"name": "Route 45"},
0x9: {"name": "Route 46"},
0xA: {"name": "Blackthorn City"},
},
6: {
0x1: {"name": "Cinnabar Pokémon Center 1F",
"label": "CinnabarPokeCenter1F"},
0x2: {"name": "Cinnabar Pokémon Center 2F Beta",
"label": "CinnabarPokeCenter2FBeta"},
0x3: {"name": "Route 19 - Fuchsia Gate"},
0x4: {"name": "Seafoam Gym"},
0x5: {"name": "Route 19"},
0x6: {"name": "Route 20"},
0x7: {"name": "Route 21"},
0x8: {"name": "Cinnabar Island"},
},
7: {
0x1: {"name": "Cerulean Gym Badge Speech House"},
0x2: {"name": "Cerulean Police Station"},
0x3: {"name": "Cerulean Trade Speech House"},
0x4: {"name": "Cerulean Pokémon Center 1F",
"label": "CeruleanPokeCenter1F"},
0x5: {"name": "Cerulean Pokémon Center 2F Beta",
"label": "CeruleanPokeCenter2FBeta"},
0x6: {"name": "Cerulean Gym"},
0x7: {"name": "Cerulean Mart"},
0x8: {"name": "Route 10 Pokémon Center 1F",
"label": "Route10PokeCenter1F"},
0x9: {"name": "Route 10 Pokémon Center 2F Beta",
"label": "Route10PokeCenter2FBeta"},
0xA: {"name": "Power Plant"},
0xB: {"name": "Bill's House"},
0xC: {"name": "Route 4"},
0xD: {"name": "Route 9"},
0xE: {"name": "Route 10 North"},
0xF: {"name": "Route 24"},
0x10: {"name": "Route 25"},
0x11: {"name": "Cerulean City"},
},
8: {
0x1: {"name": "Azalea Pokémon Center 1F",
"label": "AzaleaPokeCenter1F"},
0x2: {"name": "Charcoal Kiln"},
0x3: {"name": "Azalea Mart"},
0x4: {"name": "Kurt's House"},
0x5: {"name": "Azalea Gym"},
0x6: {"name": "Route 33"},
0x7: {"name": "Azalea Town"},
},
9: {
0x1: {"name": "Lake of Rage Hidden Power House"},
0x2: {"name": "Lake of Rage Magikarp House"},
0x3: {"name": "Route 43 Mahogany Gate"},
0x4: {"name": "Route 43 Gate"},
0x5: {"name": "Route 43"},
0x6: {"name": "Lake of Rage"},
},
10: {
0x1: {"name": "Route 32"},
0x2: {"name": "Route 35"},
0x3: {"name": "Route 36"},
0x4: {"name": "Route 37"},
0x5: {"name": "Violet City"},
0x6: {"name": "Violet Mart"},
0x7: {"name": "Violet Gym"},
0x8: {"name": "Earl's Pokémon Academy",
"label": "EarlsPokemonAcademy"},
0x9: {"name": "Violet Nickname Speech House"},
0xA: {"name": "Violet Pokémon Center 1F",
"label": "VioletPokeCenter1F"},
0xB: {"name": "Violet Onix Trade House"},
0xC: {"name": "Route 32 Ruins of Alph Gate"},
0xD: {"name": "Route 32 Pokémon Center 1F",
"label": "Route32PokeCenter1F"},
0xE: {"name": "Route 35 Goldenrod gate"},
0xF: {"name": "Route 35 National Park gate"},
0x10: {"name": "Route 36 Ruins of Alph gate"},
0x11: {"name": "Route 36 National Park gate"},
},
11: {
0x1: {"name": "Route 34"},
0x2: {"name": "Goldenrod City"},
0x3: {"name": "Goldenrod Gym"},
0x4: {"name": "Goldenrod Bike Shop"},
0x5: {"name": "Goldenrod Happiness Rater"},
0x6: {"name": "Goldenrod Bill's House"},
0x7: {"name": "Goldenrod Magnet Train Station"},
0x8: {"name": "Goldenrod Flower Shop"},
0x9: {"name": "Goldenrod PP Speech House"},
0xA: {"name": "Goldenrod Name Rater's House"},
0xB: {"name": "Goldenrod Dept Store 1F"},
0xC: {"name": "Goldenrod Dept Store 2F"},
0xD: {"name": "Goldenrod Dept Store 3F"},
0xE: {"name": "Goldenrod Dept Store 4F"},
0xF: {"name": "Goldenrod Dept Store 5F"},
0x10: {"name": "Goldenrod Dept Store 6F"},
0x11: {"name": "Goldenrod Dept Store Elevator"},
0x12: {"name": "Goldenrod Dept Store Roof"},
0x13: {"name": "Goldenrod Game Corner"},
0x14: {"name": "Goldenrod Pokémon Center 1F",
"label": "GoldenrodPokeCenter1F"},
0x15: {"name": "Goldenrod PokéCom Center 2F Mobile",
"label": "GoldenrodPokeComCenter2FMobile"},
0x16: {"name": "Ilex Forest Azalea Gate"},
0x17: {"name": "Route 34 Ilex Forest Gate"},
0x18: {"name": "Day Care"},
},
12: {
0x1: {"name": "Route 6"},
0x2: {"name": "Route 11"},
0x3: {"name": "Vermilion City"},
0x4: {"name": "Vermilion House Fishing Speech House"},
0x5: {"name": "Vermilion Pokémon Center 1F",
"label": "VermilionPokeCenter1F"},
0x6: {"name": "Vermilion Pokémon Center 2F Beta",
"label": "VermilionPokeCenter2FBeta"},
0x7: {"name": "Pokémon Fan Club"},
0x8: {"name": "Vermilion Magnet Train Speech House"},
0x9: {"name": "Vermilion Mart"},
0xA: {"name": "Vermilion House Diglett's Cave Speech House"},
0xB: {"name": "Vermilion Gym"},
0xC: {"name": "Route 6 Saffron Gate"},
0xD: {"name": "Route 6 Underground Entrance"},
},
13: {
0x1: {"name": "Route 1"},
0x2: {"name": "Pallet Town"},
0x3: {"name": "Red's House 1F"},
0x4: {"name": "Red's House 2F"},
0x5: {"name": "Blue's House"},
0x6: {"name": "Oak's Lab"},
},
14: {
0x1: {"name": "Route 3"},
0x2: {"name": "Pewter City"},
0x3: {"name": "Pewter Nidoran Speech House"},
0x4: {"name": "Pewter Gym"},
0x5: {"name": "Pewter Mart"},
0x6: {"name": "Pewter Pokémon Center 1F",
"label": "PewterPokeCenter1F"},
0x7: {"name": "Pewter Pokémon Center 2F Beta",
"label": "PewterPokeCEnter2FBeta"},
0x8: {"name": "Pewter Snooze Speech House"},
},
15: {
0x1: {"name": "Olivine Port"},
0x2: {"name": "Vermilion Port"},
0x3: {"name": "Fast Ship 1F"},
0x4: {"name": "Fast Ship Cabins NNW, NNE, NE",
"label": "FastShipCabins_NNW_NNE_NE"},
0x5: {"name": "Fast Ship Cabins SW, SSW, NW",
"label": "FastShipCabins_SW_SSW_NW"},
0x6: {"name": "Fast Ship Cabins SE, SSE, Captain's Cabin",
"label": "FastShipCabins_SE_SSE_CaptainsCabin"},
0x7: {"name": "Fast Ship B1F"},
0x8: {"name": "Olivine Port Passage"},
0x9: {"name": "Vermilion Port Passage"},
0xA: {"name": "Mount Moon Square"},
0xB: {"name": "Mount Moon Gift Shop"},
0xC: {"name": "Tin Tower Roof"},
},
16: {
0x1: {"name": "Route 23"},
0x2: {"name": "Indigo Plateau Pokémon Center 1F",
"label": "IndigoPlateauPokeCenter1F"},
0x3: {"name": "Will's Room"},
0x4: {"name": "Koga's Room"},
0x5: {"name": "Bruno's Room"},
0x6: {"name": "Karen's Room"},
0x7: {"name": "Lance's Room"},
0x8: {"name": "Hall of Fame",
"label": "HallOfFame"},
},
17: {
0x1: {"name": "Route 13"},
0x2: {"name": "Route 14"},
0x3: {"name": "Route 15"},
0x4: {"name": "Route 18"},
0x5: {"name": "Fuchsia City"},
0x6: {"name": "Fuchsia Mart"},
0x7: {"name": "Safari Zone Main Office"},
0x8: {"name": "Fuchsia Gym"},
0x9: {"name": "Fuchsia Bill Speech House"},
0xA: {"name": "Fuchsia Pokémon Center 1F",
"label": "FuchsiaPokeCenter1F"},
0xB: {"name": "Fuchsia Pokémon Center 2F Beta",
"label": "FuchsiaPokeCenter2FBeta"},
0xC: {"name": "Safari Zone Warden's Home"},
0xD: {"name": "Route 15 Fuchsia Gate"},
},
18: {
0x1: {"name": "Route 8"},
0x2: {"name": "Route 12"},
0x3: {"name": "Route 10 South"},
0x4: {"name": "Lavender Town"},
0x5: {"name": "Lavender Pokémon Center 1F",
"label": "LavenderPokeCenter1F"},
0x6: {"name": "Lavender Pokémon Center 2F Beta",
"label": "LavenderPokeCenter2FBeta"},
0x7: {"name": "Mr. Fuji's House"},
0x8: {"name": "Lavender Town Speech House"},
0x9: {"name": "Lavender Name Rater"},
0xA: {"name": "Lavender Mart"},
0xB: {"name": "Soul House"},
0xC: {"name": "Lav Radio Tower 1F"},
0xD: {"name": "Route 8 Saffron Gate"},
0xE: {"name": "Route 12 Super Rod House"},
},
19: {
0x1: {"name": "Route 28"},
0x2: {"name": "Silver Cave Outside"},
0x3: {"name": "Silver Cave Pokémon Center 1F",
"label": "SilverCavePokeCenter1F"},
0x4: {"name": "Route 28 Famous Speech House"},
},
20: {
0x1: {"name": "Pokémon Center 2F",
"label": "PokeCenter2F"},
0x2: {"name": "Trade Center"},
0x3: {"name": "Colosseum"},
0x4: {"name": "Time Capsule"},
0x5: {"name": "Mobile Trade Room Mobile"},
0x6: {"name": "Mobile Battle Room"},
},
21: {
0x1: {"name": "Route 7"},
0x2: {"name": "Route 16"},
0x3: {"name": "Route 17"},
0x4: {"name": "Celadon City"},
0x5: {"name": "Celadon Dept Store 1F"},
0x6: {"name": "Celadon Dept Store 2F"},
0x7: {"name": "Celadon Dept Store 3F"},
0x8: {"name": "Celadon Dept Store 4F"},
0x9: {"name": "Celadon Dept Store 5F"},
0xA: {"name": "Celadon Dept Store 6F"},
0xB: {"name": "Celadon Dept Store Elevator"},
0xC: {"name": "Celadon Mansion 1F"},
0xD: {"name": "Celadon Mansion 2F"},
0xE: {"name": "Celadon Mansion 3F"},
0xF: {"name": "Celadon Mansion Roof"},
0x10: {"name": "Celadon Mansion Roof House"},
0x11: {"name": "Celadon Pokémon Center 1F",
"label": "CeladonPokeCenter1F"},
0x12: {"name": "Celadon Pokémon Center 2F Beta",
"label": "CeladonPokeCenter2FBeta"},
0x13: {"name": "Celadon Game Corner"},
0x14: {"name": "Celadon Game Corner Prize Room"},
0x15: {"name": "Celadon Gym"},
0x16: {"name": "Celadon Cafe"},
0x17: {"name": "Route 16 Fuchsia Speech House"},
0x18: {"name": "Route 16 Gate"},
0x19: {"name": "Route 7 Saffron Gate"},
0x1A: {"name": "Route 17 18 Gate"},
},
22: {
0x1: {"name": "Route 40"},
0x2: {"name": "Route 41"},
0x3: {"name": "Cianwood City"},
0x4: {"name": "Mania's House"},
0x5: {"name": "Cianwood Gym"},
0x6: {"name": "Cianwood Pokémon Center 1F",
"label": "CianwoodPokeCenter1F"},
0x7: {"name": "Cianwood Pharmacy"},
0x8: {"name": "Cianwood City Photo Studio"},
0x9: {"name": "Cianwood Lugia Speech House"},
0xA: {"name": "Poke Seer's House"},
0xB: {"name": "Battle Tower 1F"},
0xC: {"name": "Battle Tower Battle Room"},
0xD: {"name": "Battle Tower Elevator"},
0xE: {"name": "Battle Tower Hallway"},
0xF: {"name": "Route 40 Battle Tower Gate"},
0x10: {"name": "Battle Tower Outside"},
},
23: {
0x1: {"name": "Route 2"},
0x2: {"name": "Route 22"},
0x3: {"name": "Viridian City"},
0x4: {"name": "Viridian Gym"},
0x5: {"name": "Viridian Nickname Speech House"},
0x6: {"name": "Trainer House 1F"},
0x7: {"name": "Trainer House B1F"},
0x8: {"name": "Viridian Mart"},
0x9: {"name": "Viridian Pokémon Center 1F",
"label": "ViridianPokeCenter1F"},
0xA: {"name": "Viridian Pokémon Center 2F Beta",
"label": "ViridianPokeCenter2FBeta"},
0xB: {"name": "Route 2 Nugget Speech House"},
0xC: {"name": "Route 2 Gate"},
0xD: {"name": "Victory Road Gate"},
},
24: {
0x1: {"name": "Route 26"},
0x2: {"name": "Route 27"},
0x3: {"name": "Route 29"},
0x4: {"name": "New Bark Town"},
0x5: {"name": "Elm's Lab"},
0x6: {"name": "Kris's House 1F"},
0x7: {"name": "Kris's House 2F"},
0x8: {"name": "Kris's Neighbor's House"},
0x9: {"name": "Elm's House"},
0xA: {"name": "Route 26 Heal Speech House"},
0xB: {"name": "Route 26 Day of Week Siblings House"},
0xC: {"name": "Route 27 Sandstorm House"},
0xD: {"name": "Route 29 46 Gate"},
},
25: {
0x1: {"name": "Route 5"},
0x2: {"name": "Saffron City"},
0x3: {"name": "Fighting Dojo"},
0x4: {"name": "Saffron Gym"},
0x5: {"name": "Saffron Mart"},
0x6: {"name": "Saffron Pokémon Center 1F",
"label": "SaffronPokeCenter1F"},
0x7: {"name": "Saffron Pokémon Center 2F Beta",
"label": "SaffronPokeCenter2FBeta"},
0x8: {"name": "Mr. Psychic's House"},
0x9: {"name": "Saffron Train Station"},
0xA: {"name": "Silph Co. 1F"},
0xB: {"name": "Copycat's House 1F"},
0xC: {"name": "Copycat's House 2F"},
0xD: {"name": "Route 5 Underground Entrance"},
0xE: {"name": "Route 5 Saffron City Gate"},
0xF: {"name": "Route 5 Cleanse Tag Speech House"},
},
26: {
0x1: {"name": "Route 30"},
0x2: {"name": "Route 31"},
0x3: {"name": "Cherrygrove City"},
0x4: {"name": "Cherrygrove Mart"},
0x5: {"name": "Cherrygrove Pokémon Center 1F",
"label": "CherrygrovePokeCenter1F"},
0x6: {"name": "Cherrygrove Gym Speech House"},
0x7: {"name": "Guide Gent's House"},
0x8: {"name": "Cherrygrove Evolution Speech House"},
0x9: {"name": "Route 30 Berry Speech House"},
0xA: {"name": "Mr. Pokémon's House"},
0xB: {"name": "Route 31 Violet Gate"},
},
}

View File

@ -298,6 +298,7 @@ pksv_crystal_more_enders = [0x03, 0x04, 0x05, 0x0C, 0x51, 0x52,
0x9B,
0xB2, #maybe?
0xCC, #maybe?
0x9A, # describedecoration
]
# these have no pksv names as of pksv 2.1.1

841
extras/vba.py Normal file
View File

@ -0,0 +1,841 @@
#!/usr/bin/jython
# -*- encoding: utf-8 -*-
"""
vba-clojure (but really it's jython/python/jvm)
This is jython, not python. Use jython to run this file. Before running this
file, some of the dependencies need to be constructed. These can be obtained
from the vba-clojure project.
sudo apt-get install g++ libtool openjdk-6-jre openjdk-6-jdk libsdl1.2-dev ant jython
export JAVA_INCLUDE_PATH=/usr/lib/jvm/java-6-openjdk-amd64/include/
export JAVA_INCLUDE_PATH2=/usr/lib/jvm/java-6-openjdk-amd64/include/
hg clone http://hg.bortreb.com/vba-clojure
cd vba-clojure/java/
ant all
cd ..
autoreconf -i
./configure
make
sudo make install
Make sure vba-clojure bindings are in $CLASSPATH:
export CLASSPATH=$CLASSPATH:java/dist/gb-bindings.jar
Make sure vba-clojure is available within "java.library.path":
sudo ln -s \
$HOME/local/vba-clojure/vba-clojure/src/clojure/.libs/libvba.so.0.0.0 \
/usr/lib/jni/libvba.so
Also make sure VisualBoyAdvance.cfg is somewhere in the $PATH for VBA to find.
A default configuration is provided in vba-clojure under src/.
Usage (in jython, not python):
import vba
# activate the laser beam
vba.load_rom("/path/to/baserom.gbc")
# make the emulator eat some instructions
vba.nstep(300)
# save the state because we're paranoid
copyrights = vba.get_state()
# or ...
vba.save_state("copyrights")
# >>> vba.load_state("copyrights") == copyrights
# True
# play for a while, then press F12
vba.run()
# let's save the game again
vba.save_state("unknown-delete-me")
# and let's go back to the other state
vba.set_state(copyrights)
# or why not the other way around?
vba.set_state(vba.load_state("unknown-delete-me"))
vba.get_memory_at(0xDCDA)
vba.set_memory_at(0xDCDB, 0xFF)
vba.get_memory_range(0xDCDA, 10)
TOOD:
[ ] set a specific register
[ ] get a specific register
[ ] breakpoints
[ ] vgm stuff
[ ] gbz80disasm integration
[ ] pokecrystal.extras integration
"""
import os
import sys
import re
from array import array
import string
from copy import copy
import unittest
# for converting bytes to readable text
from chars import chars
from map_names import map_names
# for _check_java_library_path
from java.lang import System
# for passing states to the emulator
from java.nio import ByteBuffer
# For getRegisters and other times we have to pass a java int array to a
# function.
import jarray
# load in the vba-clojure bindings
import com.aurellem.gb.Gb as Gb
# load the vba-clojure library
Gb.loadVBA()
from vba_config import *
if not os.path.exists(rom_path):
raise Exception("rom_path is not configured properly; edit vba_config.py?")
def _check_java_library_path():
"""
Returns the value of java.library.path. The vba-clojure library must be
compiled and linked from this location.
"""
return System.getProperty("java.library.path")
class RomList(list):
"""
Simple wrapper to prevent a giant rom from being shown on screen.
"""
def __init__(self, *args, **kwargs):
list.__init__(self, *args, **kwargs)
def __repr__(self):
"""
Simplifies this object so that the output doesn't overflow stdout.
"""
return "RomList(too long)"
button_masks = {
"a": 0x0001,
"b": 0x0002,
"r": 0x0010,
"l": 0x0020,
"u": 0x0040,
"d": 0x0080,
"select": 0x0004,
"start": 0x0008,
"restart": 0x0800,
"listen": -1, # what?
}
# useful for directly stating what to press
a, b, r, l, u, d, select, start, restart = "a", "b", "r", "l", "u", "d", "select", "start", "restart"
def button_combiner(buttons):
"""
Combines multiple button presses into an integer. This is used when sending
a keypress to the emulator.
"""
result = 0
# String inputs need to be cleaned up so that "start" doesn't get
# recognized as "s" and "t" etc..
if isinstance(buttons, str):
if "restart" in buttons:
buttons.replace("restart", "")
result |= button_masks["restart"]
if "start" in buttons:
buttons.replace("start", "")
result |= button_masks["start"]
if "select" in buttons:
buttons.replace("select", "")
result |= button_masks["select"]
for each in buttons:
result |= button_masks[each]
print "button: " + str(result)
return result
def load_rom(path=None):
"""
Starts the emulator with a certain ROM. Defaults to rom_path if no
parameters are given.
"""
if path == None:
path = rom_path
try:
root = load_state("root")
except:
# "root.sav" is required because if you create it in the future, you
# will have to shutdown the emulator and possibly lose your state. Some
# functions require there to be at least one root state available to do
# computations between two states.
sys.stderr.write("ERROR: unable to read \"root.sav\", please run"
" generate_root() or get_root() to make an initial save.\n")
Gb.startEmulator(path)
def shutdown():
"""
Stops the emulator. Closes the window. The "opposite" of this is the
load_rom function.
"""
Gb.shutdown()
def step():
"""
Advances the emulator forward by one step.
"""
Gb.step()
def nstep(steplimit):
"""
Step the game forward by a certain number of instructions.
"""
for counter in range(0, steplimit):
Gb.step()
def step_until_capture():
"""
Loop step() until SDLK_F12 is detected.
"""
Gb.stepUntilCapture()
# just some aliases for step_until_capture
run = go = step_until_capture
def translate_chars(charz):
result = ""
for each in charz:
result += chars[each]
return result
def _create_byte_buffer(data):
"""
Converts data into a ByteBuffer. This is useful for interfacing with the Gb
class.
"""
buf = ByteBuffer.allocateDirect(len(data))
if isinstance(data[0], int):
for byte in data:
buf.put(byte)
else:
for byte in data:
buf.put(ord(byte))
return buf
def set_state(state, do_step=False):
"""
Injects the given state into the emulator. Use do_step if you want to call
step(), which also allows SDL to render the latest frame. Note that the
default is to not step, and that the screen (if it is enabled) will appear
as if it still has the last state loaded. This is normal.
"""
Gb.loadState(_create_byte_buffer(state))
if do_step:
step()
def get_state():
"""
Retrieves the current state of the emulator.
"""
buf = Gb.saveState()
state = [buf.get(x) for x in range(0, buf.capacity())]
arr = array("b")
arr.extend(state)
return arr.tostring() # instead of state
def save_state(name, state=None, override=False):
"""
Saves the given state to save_state_path. The file format must be ".sav"
(and this will be appended to your string if necessary).
"""
if state == None:
state = get_state()
if len(name) < 4 or name[-4:] != ".sav":
name += ".sav"
save_path = os.path.join(save_state_path, name)
if not override and os.path.exists(save_path):
raise Exception("oops, save state path already exists: " + str(save_path))
else:
# convert the state into a reasonable output
data = array('b')
data.extend(state)
output = data.tostring()
file_handler = open(save_path, "wb")
file_handler.write(output)
file_handler.close()
def load_state(name):
"""
Reads a state from file based on name. Looks in save_state_path for a file
with this name (".sav" is optional).
"""
save_path = os.path.join(save_state_path, name)
if not os.path.exists(save_path):
if len(name) < 4 or name[-4:] != ".sav":
name += ".sav"
save_path = os.path.join(save_state_path, name)
file_handler = open(save_path, "rb")
state = file_handler.read()
file_handler.close()
return state
def generate_root():
"""
Restarts the emulator and saves the initial state to "root.sav".
"""
shutdown()
load_rom()
root = get_state()
save_state("root", state=root, override=True)
return root
def get_root():
"""
Loads the root state, or restarts the emulator and creates a new root
state.
"""
try:
root = load_state("root")
except:
root = generate_root()
def get_registers():
"""
Returns a list of current register values.
"""
register_array = jarray.zeros(Gb.NUM_REGISTERS, "i")
Gb.getRegisters(register_array)
return list(register_array)
def set_registers(registers):
"""
Applies the set of registers to the CPU.
"""
Gb.writeRegisters(registers)
write_registers = set_registers
def get_rom():
"""
Returns the ROM in bytes.
"""
rom_array = jarray.zeros(Gb.ROM_SIZE, "i")
Gb.getROM(rom_array)
return RomList(rom_array)
def get_ram():
"""
Returns the RAM in bytes.
"""
ram_array = jarray.zeros(Gb.RAM_SIZE, "i")
Gb.getRAM(ram_array)
return RomList(ram_array)
def say_hello():
"""
Test that the VBA/GB bindings are working.
"""
Gb.sayHello()
def get_memory():
"""
Returns memory in bytes.
"""
memory_size = 0x10000
memory = jarray.zeros(memory_size, "i")
Gb.getMemory(memory)
return RomList(memory)
def set_memory(memory):
"""
Sets memory in the emulator. Use get_memory() to retrieve the current
state.
"""
Gb.writeMemory(memory)
def get_pixels():
"""
Returns a list of pixels on the screen display. Broken, probably. Use
screenshot() instead.
"""
sys.stderr.write("ERROR: seems to be broken on VBA's end? Good luck. Use"
" screenshot() instead.\n")
size = Gb.DISPLAY_WIDTH * Gb.DISPLAY_HEIGHT
pixels = jarray.zeros(size, "i")
Gb.getPixels(pixels)
return RomList(pixels)
def screenshot(filename, literal=False):
"""
Saves a PNG screenshot to the file at filename. Use literal if you want to
store it in the current directory. Default is to save it to screenshots/
under the project.
"""
screenshots_path = os.path.join(project_path, "screenshots/")
filename = os.path.join(screenshots_path, filename)
if len(filename) < 4 or filename[-4:] != ".png":
filename += ".png"
Gb.nwritePNG(filename)
print "Screenshot saved to: " + str(filename)
save_png = screenshot
def read_memory(address):
"""
Read an integer at an address.
"""
return Gb.readMemory(address)
get_memory_at = read_memory
def get_memory_range(start_address, byte_count):
"""
Returns a list of bytes.
start_address - address to start reading at
byte_count - how many bytes (0 returns just 1 byte)
"""
bytez = []
for counter in range(0, byte_count):
byte = get_memory_at(start_address + counter)
bytez.append(byte)
return bytez
def set_memory_at(address, value):
"""
Sets a byte at a certain address in memory. This directly sets the memory
instead of copying the memory from the emulator.
"""
Gb.setMemoryAt(address, value)
def press(buttons, steplimit=1):
"""
Press a button. Use steplimit to say for how many steps you want to press
the button (try leaving it at the default, 1).
"""
if hasattr(buttons, "__len__"):
number = button_combiner(buttons)
elif isinstance(buttons, int):
number = buttons
else:
number = buttons
for step_counter in range(0, steplimit):
Gb.step(number)
class Registers:
order = [
"pc",
"sp",
"af",
"bc",
"de",
"hl",
"iff",
"div",
"tima",
"tma",
"tac",
"if",
"lcdc",
"stat",
"scy",
"scx",
"ly",
"lyc",
"dma",
"wy",
"wx",
"vbk",
"hdma1",
"hdma2",
"hdma3",
"hdma4",
"hdma5",
"svbk",
"ie",
]
def __setitem__(self, key, value):
current_registers = get_registers()
current_registers[Registers.order.index(key)] = value
set_registers(current_registers)
def __getitem__(self, key):
current_registers = get_registers()
return current_registers[Registers.order.index(key)]
def __list__(self):
return get_registers()
def _get_register(id):
def constructed_func(self, id=copy(id)):
return get_registers()[id]
return constructed_func
def _set_register(id):
def constructed_func(self, value, id=copy(id)):
current_registers = get_registers()
current_registers[id] = value
set_registers(current_registers)
return constructed_func
pc = property(fget=_get_register(0), fset=_set_register(0))
sp = property(fget=_get_register(1), fset=_set_register(1))
af = property(fget=_get_register(2), fset=_set_register(2))
bc = property(fget=_get_register(3), fset=_set_register(3))
de = property(fget=_get_register(4), fset=_set_register(4))
hl = property(fget=_get_register(5), fset=_set_register(5))
iff = property(fget=_get_register(6), fset=_set_register(6))
div = property(fget=_get_register(7), fset=_set_register(7))
tima = property(fget=_get_register(8), fset=_set_register(8))
tma = property(fget=_get_register(9), fset=_set_register(9))
tac = property(fget=_get_register(10), fset=_set_register(10))
_if = property(fget=_get_register(11), fset=_set_register(11))
lcdc = property(fget=_get_register(12), fset=_set_register(12))
stat = property(fget=_get_register(13), fset=_set_register(13))
scy = property(fget=_get_register(14), fset=_set_register(14))
scx = property(fget=_get_register(15), fset=_set_register(15))
ly = property(fget=_get_register(16), fset=_set_register(16))
lyc = property(fget=_get_register(17), fset=_set_register(17))
dma = property(fget=_get_register(18), fset=_set_register(18))
wy = property(fget=_get_register(19), fset=_set_register(19))
wx = property(fget=_get_register(20), fset=_set_register(20))
vbk = property(fget=_get_register(21), fset=_set_register(21))
hdma1 = property(fget=_get_register(22), fset=_set_register(22))
hdma2 = property(fget=_get_register(23), fset=_set_register(23))
hdma3 = property(fget=_get_register(24), fset=_set_register(24))
hdma4 = property(fget=_get_register(25), fset=_set_register(25))
hdma5 = property(fget=_get_register(26), fset=_set_register(26))
svbk = property(fget=_get_register(27), fset=_set_register(27))
ie = property(fget=_get_register(28), fset=_set_register(28))
def __repr__(self):
spacing = "\t"
output = "Registers:\n"
for (id, each) in enumerate(self.order):
output += spacing + each + " = " + hex(get_registers()[id])
#hex(self[each])
output += "\n"
return output
registers = Registers()
def call(bank, address):
"""
Jumps into a function at a certain address.
Go into the start menu, pause the game and try call(1, 0x1078) to see a
string printed to the screen.
"""
push = [
registers.pc,
registers.hl,
registers.de,
registers.bc,
registers.af,
0x3bb7,
]
for value in push:
registers.sp -= 2
set_memory_at(registers.sp + 1, value >> 8)
set_memory_at(registers.sp, value & 0xFF)
if get_memory_range(registers.sp, 2) != [value & 0xFF, value >> 8]:
print "desired memory values: " + str([value & 0xFF, value >> 8] )
print "actual memory values: " + str(get_memory_range(registers.sp , 2))
print "wrong value at " + hex(registers.sp) + " expected " + hex(value) + " but got " + hex(get_memory_at(registers.sp))
if bank != 0:
registers["af"] = (bank << 8) | (registers["af"] & 0xFF)
registers["hl"] = address
registers["pc"] = 0x2d63 # FarJump
else:
registers["pc"] = address
class crystal:
"""
Just a simple namespace to store a bunch of functions for Pokémon Crystal.
"""
@staticmethod
def walk_through_walls_slow():
memory = get_memory()
memory[0xC2FA] = 0
memory[0xC2FB] = 0
memory[0xC2FC] = 0
memory[0xC2FD] = 0
set_memory(memory)
@staticmethod
def walk_through_walls():
"""
Lets the player walk all over the map. These values are probably reset
by some of the map/collision functions when you move on to a new
location, so this needs to be executed each step/tick if continuous
walk-through-walls is desired.
"""
set_memory_at(0xC2FA, 0)
set_memory_at(0xC2FB, 0)
set_memory_at(0xC2FC, 0)
set_memory_at(0xC2FD, 0)
#@staticmethod
#def set_enemy_level(level):
# set_memory_at(0xd213, level)
@staticmethod
def nstep(steplimit=500):
"""
Steps the CPU forward and calls some functions in between each step,
like to manipulate memory. This is pretty slow.
"""
for step_counter in range(0, steplimit):
crystal.walk_through_walls()
#call(0x1, 0x1078)
step()
@staticmethod
def disable_triggers():
set_memory_at(0x23c4, 0xAF)
set_memory_at(0x23d0, 0xAF);
@staticmethod
def disable_callbacks():
set_memory_at(0x23f2, 0xAF)
set_memory_at(0x23fe, 0xAF)
@staticmethod
def get_map_group_id():
"""
Returns the current map group.
"""
return get_memory_at(0xdcb5)
@staticmethod
def get_map_id():
"""
Returns the map number of the current map.
"""
return get_memory_at(0xdcb6)
@staticmethod
def get_map_name():
"""
Figures out the current map name.
"""
map_group_id = crystal.get_map_group_id()
map_id = crystal.get_map_id()
return map_names[map_group_id][map_id]["name"]
@staticmethod
def get_xy():
"""
(x, y) coordinates of player on map.
Relative to top-left corner of map.
"""
x = get_memory_at(0xdcb8)
y = get_memory_at(0xdcb7)
return (x, y)
@staticmethod
def menu_select(id=1):
"""
Sets the cursor to the given pokemon in the player's party. This is
under Start -> PKMN. This is useful for selecting a certain pokemon
with fly or another skill.
This probably works on other menus.
"""
set_memory_at(0xcfa9, id)
@staticmethod
def is_in_battle():
"""
Checks whether or not we're in a battle.
"""
return (get_memory_at(0xd22d) != 0) or crystal.is_in_link_battle()
@staticmethod
def is_in_link_battle():
return get_memory_at(0xc2dc) != 0
@staticmethod
def unlock_flypoints():
"""
Unlocks different destinations for flying.
Note: this might start at 0xDCA4 (minus one on all addresses), but not
sure.
"""
set_memory_at(0xDCA5, 0xFF)
set_memory_at(0xDCA6, 0xFF)
set_memory_at(0xDCA7, 0xFF)
set_memory_at(0xDCA8, 0xFF)
@staticmethod
def get_gender():
"""
Returns 'male' or 'female'.
"""
gender = get_memory_at(0xD472)
if gender == 0:
return "male"
elif gender == 1:
return "female"
else:
return gender
@staticmethod
def get_player_name():
"""
Returns the 7 characters making up the player's name.
"""
bytez = get_memory_range(0xD47D, 7)
name = translate_chars(bytez)
return name
@staticmethod
def warp(map_group_id, map_id, x, y):
set_memory_at(0xdcb5, map_group_id)
set_memory_at(0xdcb6, map_id)
set_memory_at(0xdcb7, y)
set_memory_at(0xdcb8, x)
set_memory_at(0xd001, 0xFF)
set_memory_at(0xff9f, 0xF1)
set_memory_at(0xd432, 1)
set_memory_at(0xd434, 0 & 251)
@staticmethod
def warp_pokecenter():
crystal.warp(1, 1, 3, 3)
crystal.nstep(200)
@staticmethod
def masterballs():
# masterball
set_memory_at(0xd8d8, 1)
set_memory_at(0xd8d9, 99)
# ultraball
set_memory_at(0xd8da, 2)
set_memory_at(0xd8db, 99)
# pokeballs
set_memory_at(0xd8dc, 5)
set_memory_at(0xd8dd, 99)
@staticmethod
def get_text():
"""
Returns alphanumeric text on the screen. Other characters will not be
shown.
"""
output = ""
tiles = get_memory_range(0xc4a0, 1000)
for each in tiles:
if each in chars.keys():
thing = chars[each]
acceptable = False
if len(thing) == 2:
portion = thing[1:]
else:
portion = thing
if portion in string.printable:
acceptable = True
if acceptable:
output += thing
# remove extra whitespace
output = re.sub(" +", " ", output)
output = output.strip()
return output
@staticmethod
def set_partymon2():
"""
This causes corruption, so it's not working yet.
"""
memory = get_memory()
memory[0xdcd7] = 2
memory[0xdcd9] = 0x7
memory[0xdd0f] = 0x7
memory[0xdd10] = 0x1
# moves
memory[0xdd11] = 0x1
memory[0xdd12] = 0x2
memory[0xdd13] = 0x3
memory[0xdd14] = 0x4
# id
memory[0xdd15] = 0x1
memory[0xdd16] = 0x2
# experience
memory[0xdd17] = 0x2
memory[0xdd18] = 0x3
memory[0xdd19] = 0x4
# hp
memory[0xdd1a] = 0x5
memory[0xdd1b] = 0x6
# current hp
memory[0xdd31] = 0x10
memory[0xdd32] = 0x25
# max hp
memory[0xdd33] = 0x10
memory[0xdd34] = 0x40
set_memory(memory)
class TestEmulator(unittest.TestCase):
try:
state = load_state("cheating-12")
except:
if "__name__" == "__main__":
raise Exception("failed to setup unit tests because no save state found")
def setUp(self):
load_rom()
set_state(self.state)
def tearDown(self):
shutdown()
def test_PlaceString(self):
call(0, 0x1078)
# where to draw the text
registers["hl"] = 0xc4a0
# what text to read from
registers["de"] = 0x1276
nstep(10)
text = crystal.get_text()
self.assertTrue("TRAINER" in text)
if __name__ == "__main__":
unittest.main()

15
extras/vba_config.py Normal file
View File

@ -0,0 +1,15 @@
#!/usr/bin/jython
# -*- encoding: utf-8 -*-
import os
# by default we assume the user has things in their $HOME
home = os.path.expanduser("~") # or System.getProperty("user.home")
# and that the pokecrystal project folder is in there somewhere
project_path = os.path.join(home, os.path.join("code", "pokecrystal"))
# save states are in ~/code/pokecrystal/save-states/
save_state_path = os.path.join(project_path, "save-states")
# where is your rom?
rom_path = os.path.join(project_path, "baserom.gbc")

65
gbhw.asm Normal file
View File

@ -0,0 +1,65 @@
; Graciously aped from http://nocash.emubase.de/pandocs.htm .
rJOYP EQU $ff00 ; Joypad (R/W)
rSB EQU $ff01 ; Serial transfer data (R/W)
rSC EQU $ff02 ; Serial Transfer Control (R/W)
rDIV EQU $ff04 ; Divider Register (R/W)
rTIMA EQU $ff05 ; Timer counter (R/W)
rTMA EQU $ff06 ; Timer Modulo (R/W)
rTAC EQU $ff07 ; Timer Control (R/W)
rIF EQU $ff0f ; Interrupt Flag (R/W)
rNR10 EQU $ff10 ; Channel 1 Sweep register (R/W)
rNR11 EQU $ff11 ; Channel 1 Sound length/Wave pattern duty (R/W)
rNR12 EQU $ff12 ; Channel 1 Volume Envelope (R/W)
rNR13 EQU $ff13 ; Channel 1 Frequency lo (Write Only)
rNR14 EQU $ff14 ; Channel 1 Frequency hi (R/W)
rNR21 EQU $ff16 ; Channel 2 Sound Length/Wave Pattern Duty (R/W)
rNR22 EQU $ff17 ; Channel 2 Volume Envelope (R/W)
rNR23 EQU $ff18 ; Channel 2 Frequency lo data (W)
rNR24 EQU $ff19 ; Channel 2 Frequency hi data (R/W)
rNR30 EQU $ff1a ; Channel 3 Sound on/off (R/W)
rNR31 EQU $ff1b ; Channel 3 Sound Length
rNR32 EQU $ff1c ; Channel 3 Select output level (R/W)
rNR33 EQU $ff1d ; Channel 3 Frequency's lower data (W)
rNR34 EQU $ff1e ; Channel 3 Frequency's higher data (R/W)
rNR41 EQU $ff20 ; Channel 4 Sound Length (R/W)
rNR42 EQU $ff21 ; Channel 4 Volume Envelope (R/W)
rNR43 EQU $ff22 ; Channel 4 Polynomial Counter (R/W)
rNR44 EQU $ff23 ; Channel 4 Counter/consecutive; Inital (R/W)
rNR50 EQU $ff24 ; Channel control / ON-OFF / Volume (R/W)
rNR51 EQU $ff25 ; Selection of Sound output terminal (R/W)
rNR52 EQU $ff26 ; Sound on/off
rLCDC EQU $ff40 ; LCD Control (R/W)
rSTAT EQU $ff41 ; LCDC Status (R/W)
rSCY EQU $ff42 ; Scroll Y (R/W)
rSCX EQU $ff43 ; Scroll X (R/W)
rLY EQU $ff44 ; LCDC Y-Coordinate (R)
rLYC EQU $ff45 ; LY Compare (R/W)
rDMA EQU $ff46 ; DMA Transfer and Start Address (W)
rBGP EQU $ff47 ; BG Palette Data (R/W) - Non CGB Mode Only
rOBP0 EQU $ff48 ; Object Palette 0 Data (R/W) - Non CGB Mode Only
rOBP1 EQU $ff49 ; Object Palette 1 Data (R/W) - Non CGB Mode Only
rWY EQU $ff4a ; Window Y Position (R/W)
rWX EQU $ff4b ; Window X Position minus 7 (R/W)
rKEY1 EQU $ff4d ; CGB Mode Only - Prepare Speed Switch
rVBK EQU $ff4f ; CGB Mode Only - VRAM Bank
rHDMA1 EQU $ff51 ; CGB Mode Only - New DMA Source, High
rHDMA2 EQU $ff52 ; CGB Mode Only - New DMA Source, Low
rHDMA3 EQU $ff53 ; CGB Mode Only - New DMA Destination, High
rHDMA4 EQU $ff54 ; CGB Mode Only - New DMA Destination, Low
rHDMA5 EQU $ff55 ; CGB Mode Only - New DMA Length/Mode/Start
rRP EQU $ff56 ; CGB Mode Only - Infrared Communications Port
rBGPI EQU $ff68 ; CGB Mode Only - Background Palette Index
rBGPD EQU $ff69 ; CGB Mode Only - Background Palette Data
rOBPI EQU $ff6a ; CGB Mode Only - Sprite Palette Index
rOBPD EQU $ff6b ; CGB Mode Only - Sprite Palette Data
rUNKNOWN1 EQU $ff6c ; (FEh) Bit 0 (Read/Write) - CGB Mode Only
rSVBK EQU $ff70 ; CGB Mode Only - WRAM Bank
rUNKNOWN2 EQU $ff72 ; (00h) - Bit 0-7 (Read/Write)
rUNKNOWN3 EQU $ff73 ; (00h) - Bit 0-7 (Read/Write)
rUNKNOWN4 EQU $ff74 ; (00h) - Bit 0-7 (Read/Write) - CGB Mode Only
rUNKNOWN5 EQU $ff75 ; (8Fh) - Bit 4-6 (Read/Write)
rUNKNOWN6 EQU $ff76 ; (00h) - Always 00h (Read Only)
rUNKNOWN7 EQU $ff77 ; (00h) - Always 00h (Read Only)
rIE EQU $ffff ; Interrupt Enable (R/W)

BIN
gfx/debug/color_test.2bpp Normal file

Binary file not shown.

BIN
gfx/evo/bubble.2bpp Normal file

Binary file not shown.

BIN
gfx/evo/bubble_large.2bpp Normal file

Binary file not shown.

BIN
gfx/misc/pack_f.2bpp Normal file

Binary file not shown.

BIN
gfx/misc/unown_font.2bpp Normal file

Binary file not shown.

BIN
gfx/ow/misc.2bpp Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
00.>  ااd$6<12>فد<D981><D8AF>&<26><06><02><0E><>_g?83<}__{jn <0C><1C>ِِ<D990>@ـ ظ<>ب<EFBFBD>00

BIN
gfx/special/celebi/2.2bpp Normal file

Binary file not shown.

BIN
gfx/special/celebi/3.2bpp Normal file

Binary file not shown.

BIN
gfx/special/celebi/4.2bpp Normal file

Binary file not shown.

Binary file not shown.

275
joypad.asm Normal file
View File

@ -0,0 +1,275 @@
JoypadInt: ; 92e
; Replaced by Joypad, called from VBlank instead of the useless
; joypad interrupt.
; This is a placeholder in case the interrupt is somehow enabled.
reti
; 92f
ClearJoypadPublic: ; 92f
xor a
; Pressed this frame (delta)
ld [$ffa7], a
; Currently pressed
ld [$ffa8], a
ret
; 935
Joypad: ; 935
; Read the joypad register and translate it to something more
; workable for use in-game. There are 8 buttons, so we can use
; one byte to contain all player input.
; Updates:
; $ffa2: released this frame (delta)
; $ffa3: pressed this frame (delta)
; $ffa4: currently pressed
; $ffa5: pressed so far
; Any of these three bits can be used to disable input.
ld a, [$cfbe]
and %11010000
ret nz
; If we're saving, input is disabled.
ld a, [$c2cd]
and a
ret nz
; We can only get four inputs at a time.
; We take d-pad first for no particular reason.
ld a, D_PAD
ld [rJOYP], a
; Read twice to give the request time to take.
ld a, [rJOYP]
ld a, [rJOYP]
; The Joypad register output is in the lo nybble (inversed).
; We make the hi nybble of our new container d-pad input.
cpl
and $f
swap a
; We'll keep this in b for now.
ld b, a
; Buttons make 8 total inputs (A, B, Select, Start).
; We can fit this into one byte.
ld a, BUTTONS
ld [rJOYP], a
; Wait for input to stabilize.
ld a, [rJOYP]
ld a, [rJOYP]
ld a, [rJOYP]
ld a, [rJOYP]
ld a, [rJOYP]
ld a, [rJOYP]
; Buttons take the lo nybble.
cpl
and $f
or b
ld b, a
; Reset the joypad register since we're done with it.
ld a, $30
ld [rJOYP], a
; To get the delta we xor the last frame's input with the new one.
ld a, [$ffa4] ; last frame
ld e, a
xor b
ld d, a
; Released this frame:
and e
ld [$ffa2], a
; Pressed this frame:
ld a, d
and b
ld [$ffa3], a
; Add any new presses to the list of collective presses:
ld c, a
ld a, [$ffa5]
or c
ld [$ffa5], a
; Currently pressed:
ld a, b
ld [$ffa4], a
; Now that we have the input, we can do stuff with it.
; For example, soft reset:
and BUTTON_A | BUTTON_B | SELECT | START
cp BUTTON_A | BUTTON_B | SELECT | START
jp z, $0150 ; reset
ret
; 984
GetJoypadPublic: ; 984
; Update mirror joypad input from $ffa4 (real input)
; $ffa6: released this frame (delta)
; $ffa7: pressed this frame (delta)
; $ffa8: currently pressed
; bit 0 A
; 1 B
; 2 SELECT
; 3 START
; 4 RIGHT
; 5 LEFT
; 6 UP
; 7 DOWN
push af
push hl
push de
push bc
; The player input can be automated using an input stream.
; See more below.
ld a, [InputType]
cp a, AUTO_INPUT
jr z, .auto
; To get deltas, take this and last frame's input.
ld a, [$ffa4] ; real input
ld b, a
ld a, [$ffa8] ; last frame mirror
ld e, a
; Released this frame:
xor b
ld d, a
and e
ld [$ffa6], a
; Pressed this frame:
ld a, d
and b
ld [$ffa7], a
; It looks like the collective presses got commented out here.
ld c, a
; Currently pressed:
ld a, b
ld [$ffa8], a ; frame input
.quit
pop bc
pop de
pop hl
pop af
ret
.auto
; Use a predetermined input stream (used in the catching tutorial).
; Stream format: [input][duration]
; A value of $ff will immediately end the stream.
; Read from the input stream.
ld a, [$ff9d]
push af
ld a, [AutoInputBank]
rst Bankswitch
ld hl, AutoInputAddress
ld a, [hli]
ld h, [hl]
ld l, a
; We only update when the input duration has expired.
ld a, [AutoInputLength]
and a
jr z, .updateauto
; Until then, don't change anything.
dec a
ld [AutoInputLength], a
pop af
rst Bankswitch
jr .quit
.updateauto
; An input of $ff will end the stream.
ld a, [hli]
cp a, $ff
jr z, .stopauto
ld b, a
; A duration of $ff will end the stream indefinitely.
ld a, [hli]
ld [AutoInputLength], a
cp a, $ff
jr nz, .next
; The current input is overwritten.
dec hl
dec hl
ld b, NO_INPUT
jr .finishauto
.next
; On to the next input...
ld a, l
ld [AutoInputAddress], a
ld a, h
ld [AutoInputAddress+1], a
jr .finishauto
.stopauto
call StopAutoInput
ld b, NO_INPUT
.finishauto
pop af
rst Bankswitch
ld a, b
ld [$ffa7], a ; pressed
ld [$ffa8], a ; input
jr .quit
; 9ee
StartAutoInput: ; 9ee
; Start reading automated input stream at a:hl.
ld [AutoInputBank], a
ld a, l
ld [AutoInputAddress], a
ld a, h
ld [AutoInputAddress+1], a
; Start reading the stream immediately.
xor a
ld [AutoInputLength], a
; Reset input mirrors.
xor a
ld [$ffa7], a ; pressed this frame
ld [$ffa6], a ; released this frame
ld [$ffa8], a ; currently pressed
ld a, AUTO_INPUT
ld [InputType], a
ret
; a0a
StopAutoInput: ; a0a
; Clear variables related to automated input.
xor a
ld [AutoInputBank], a
ld [AutoInputAddress], a
ld [AutoInputAddress+1], a
ld [AutoInputLength], a
; Back to normal input.
ld [InputType], a
ret
; a1b

1368
main.asm

File diff suppressed because it is too large Load Diff

View File

@ -38,15 +38,64 @@ INCBIN "baserom.gbc",$7abc9,$7abcc - $7abc9
UnknownScript_0x7abcc: ; 0x7abcc
describedecoration $1
; 0x7abce
UnknownScript_0x7abce: ; 0x7abce
describedecoration $2
; 0x7abd0
UnknownScript_0x7abd0: ; 0x7abd0
describedecoration $3
; 0x7abd2
UnknownScript_0x7abd2: ; 0x7abd2
describedecoration $4
unknown0xcc
; 0x7abd5
; 0x7abd4
INCBIN "baserom.gbc",$7abd5,$3d
MapKrissHouse2FSignpost4: ; 0x7abd4
dw $02cc ; bit1
dw MapKrissHouse2FSignpost4Script
; 0x7abd8
MapKrissHouse2FSignpost2Script: ; 0x7ac12
MapKrissHouse2FSignpost4Script: ; 0x7abd8
describedecoration $0
; 0x7abda
MapKrissHouse2FSignpost2Script: ; 0x7abda
checkbit1 $001a
iftrue UnknownScript_0x7ac07
checkbit1 $0325
iftrue UnknownScript_0x7ac0a
playmusic $001d
loadfont
2writetext UnknownText_0x7ac24
pause 45
2writetext UnknownText_0x7ac55
pause 45
2writetext UnknownText_0x7ac64
pause 45
musicfadeout $003c, $10
2writetext UnknownText_0x7ac84
pause 45
loadmovesprites
setbit1 $0325
end
; 0x7ac07
UnknownScript_0x7ac07: ; 0x7ac07
jumpstd $000b
; 0x7ac0a
UnknownScript_0x7ac0a: ; 0x7ac0a
loadfont
2writetext UnknownText_0x7ac84
pause 45
loadmovesprites
end
; 0x7ac12
MapKrissHouse2FSignpost3Script: ; 0x7ac12
jumpstd $0002
; 0x7ac15
@ -97,15 +146,15 @@ KrissHouse2F_MapEventHeader: ; 0x7ac99
; signposts
db 4
signpost 1, 2, $1, MapKrissHouse2FSignpost0Script
signpost 1, 3, $0, $6bda
signpost 1, 5, $0, MapKrissHouse2FSignpost2Script
signpost 0, 6, $5, $6bd4
signpost 1, 3, $0, MapKrissHouse2FSignpost2Script
signpost 1, 5, $0, MapKrissHouse2FSignpost3Script
signpost 0, 6, $5, MapKrissHouse2FSignpost4 ; 6bd4
; people-events
db 4
person_event $f0, 6, 8, $1, $0, 255, 255, $0, 0, $6bd2, $0741
person_event $f0, 6, 8, $1, $0, 255, 255, $0, 0, UnknownScript_0x7abd2, $0741
person_event $f1, 8, 8, $1, $0, 255, 255, $0, 0, UnknownScript_0x7abcc, $0742
person_event $f2, 8, 9, $1, $0, 255, 255, $0, 0, $6bce, $0743
person_event $f3, 5, 4, $21, $0, 255, 255, $0, 0, $6bd0, $0744
person_event $f2, 8, 9, $1, $0, 255, 255, $0, 0, UnknownScript_0x7abce, $0743
person_event $f3, 5, 4, $21, $0, 255, 255, $0, 0, UnknownScript_0x7abd0, $0744
; 0x7acec

View File

@ -208,9 +208,8 @@ UnknownScript_0x18e2b4: ; 0x18e2b4
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 LEVEL_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 LEVEL_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e2c4: ; 0x18e2c4
clearbit1 $0258
2jump UnknownScript_0x18e2ab
@ -221,9 +220,8 @@ UnknownScript_0x18e2ca: ; 0x18e2ca
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 LURE_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 LURE_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e2da: ; 0x18e2da
clearbit1 $0259
2jump UnknownScript_0x18e2ab
@ -234,9 +232,8 @@ UnknownScript_0x18e2e0: ; 0x18e2e0
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 MOON_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 MOON_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e2f0: ; 0x18e2f0
clearbit1 $025a
2jump UnknownScript_0x18e2ab
@ -247,9 +244,8 @@ UnknownScript_0x18e2f6: ; 0x18e2f6
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 FRIEND_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 FRIEND_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e306: ; 0x18e306
clearbit1 $025b
2jump UnknownScript_0x18e2ab
@ -260,9 +256,8 @@ UnknownScript_0x18e30c: ; 0x18e30c
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 FAST_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 FAST_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e31c: ; 0x18e31c
clearbit1 $025c
2jump UnknownScript_0x18e2ab
@ -273,9 +268,8 @@ UnknownScript_0x18e322: ; 0x18e322
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 HEAVY_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 HEAVY_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e332: ; 0x18e332
clearbit1 $025d
2jump UnknownScript_0x18e2ab
@ -286,9 +280,8 @@ UnknownScript_0x18e338: ; 0x18e338
iftrue UnknownScript_0x18e3c5
2writetext UnknownText_0x18e7fb
keeptextopen
verbosegiveitem2 LOVE_BALL
addvar $8
unknown0xb2 $62
verbosegiveitem2 LOVE_BALL, $16
iffalse UnknownScript_0x18e2b2
UnknownScript_0x18e348: ; 0x18e348
clearbit1 $025e
2jump UnknownScript_0x18e2ab

View File

@ -1,3 +1,4 @@
INCLUDE "wram.asm"
INCLUDE "constants.asm"
INCLUDE "gbhw.asm"
INCLUDE "main.tx"

View File

@ -599,6 +599,11 @@ def read_line(l):
if "INCLUDE \"" in l:
include_file(asm)
# ascii string macro preserves the bytes as ascii (skip the translator)
elif len(asm) > 6 and "\tascii " in [asm[:7], "\t" + asm[:6]]:
asm = asm.replace("ascii", "db", 1)
sys.stdout.write(asm)
# convert text to bytes when a quote appears (not in a comment)
elif "\"" in asm:
quote_translator(asm)

3127
scripting.asm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -69,13 +69,13 @@ VBlank0: ; 2b1
inc [hl]
; advance rng
ld a, [$ff04] ; divider
ld a, [rDIV]
ld b, a
ld a, [$ffe1]
adc b
ld [$ffe1], a
ld a, [$ff04] ; divider
ld a, [rDIV]
ld b, a
ld a, [$ffe2]
sbc b
@ -87,16 +87,16 @@ VBlank0: ; 2b1
; scroll x
ld a, [$ffcf]
ld [$ff43], a ; scx
ld [rSCX], a
; scroll y
ld a, [$ffd0]
ld [$ff42], a ; scy
ld [rSCY], a
; window y
ld a, [$ffd2]
ld [$ff4a], a ; wy
ld [rWY], a
; window x + 7
ld a, [$ffd1]
ld [$ff4b], a ; wx
ld [rWX], a
; some time management is in order
; only have time for one of these during vblank
@ -131,7 +131,7 @@ VBlank0: ; 2b1
call $ff80
; 403f:
; ld a, $c4
; ld [$ff46], a ; oam dma
; ld [rDMA], a
; ld a, $28
; .loop
; dec a
@ -216,11 +216,11 @@ VBlank1: ; 337
; scroll x
ld a, [$ffcf]
ld [$ff43], a ; scx
ld [rSCX], a
; scroll y
ld a, [$ffd0]
ld [$ff42], a ; scy
ld [rSCY], a
; time-sensitive fns
call UpdatePals
@ -233,7 +233,7 @@ VBlank1: ; 337
call $ff80
; 403f:
; ld a, $c4
; ld [$ff46], a ; oam dma
; ld [rDMA], a
; ld a, $28
; .loop
; dec a
@ -246,20 +246,20 @@ VBlank1: ; 337
ld [VBlankOccurred], a
; get requested ints
ld a, [$ff0f] ; IF
ld a, [rIF]
ld b, a
; discard requested ints
xor a
ld [$ff0f], a ; IF
ld [rIF], a
; enable lcd stat
ld a, %10 ; lcd stat
ld [$ffff], a ; IE
ld [rIE], a
; rerequest serial int if applicable (still disabled)
; request lcd stat
ld a, b
and %1000 ; serial
or %10 ; lcd stat
ld [$ff0f], a ; IF
ld [rIF], a
ei
; update sound
@ -272,17 +272,17 @@ VBlank1: ; 337
di
; get requested ints
ld a, [$ff0f] ; IF
ld a, [rIF]
ld b, a
; discard requested ints
xor a
ld [$ff0f], a ; IF
ld [rIF], a
; enable ints besides joypad
ld a, %1111 ; serial timer lcdstat vblank
ld [$ffff], a ; IE
ld [rIE], a
; rerequest ints
ld a, b
ld [$ff0f], a ; IF
ld [rIF], a
ret
; 37f
@ -297,13 +297,13 @@ UpdatePals: ; 37f
; update gb pals
ld a, [$cfc7]
ld [$ff47], a ; BGP
ld [rBGP], a
ld a, [$cfc8]
ld [$ff48], a ; OBP0
ld [rOBP0], a
ld a, [$cfc9]
ld [$ff49], a ; 0BP1
ld [rOBP1], a
and a
ret
@ -324,10 +324,10 @@ VBlank3: ; 396
; scroll x
ld a, [$ffcf]
ld [$ff43], a ; scx
ld [rSCX], a
; scroll y
ld a, [$ffd0]
ld [$ff42], a ; scy
ld [rSCY], a
; any pals to update?
ld a, [$ffe5]
@ -342,7 +342,7 @@ VBlank3: ; 396
call $ff80
; 403f:
; ld a, $c4 ; Sprites / $100
; ld [$ff46], a ; oam dma
; ld [rDMA], a
; ld a, $28
; .loop
; dec a
@ -355,15 +355,15 @@ VBlank3: ; 396
ld [VBlankOccurred], a
; save int flag
ld a, [$ff0f] ; IF
ld a, [rIF]
push af
; reset ints
xor a
ld [$ff0f], a ; IF
ld [rIF], a
; force lcdstat int during sound update
ld a, %10 ; lcd stat
ld [$ffff], a ; IE
ld [$ff0f], a ; IF
ld [rIE], a
ld [rIF], a
ei
; update sound
@ -376,7 +376,7 @@ VBlank3: ; 396
di
; request lcdstat
ld a, [$ff0f] ; IF
ld a, [rIF]
ld b, a
; and any other ints
pop af
@ -384,13 +384,13 @@ VBlank3: ; 396
ld b, a
; reset ints
xor a
ld [$ff0f], a ; IF
ld [rIF], a
; enable ints besides joypad
ld a, %1111 ; serial timer lcdstat vblank
ld [$ffff], a ; IE
ld [rIE], a
; request ints
ld a, b
ld [$ff0f], a ; IF
ld [rIF], a
ret
; 3df
@ -414,7 +414,7 @@ VBlank4: ; 3df
call $ff80
; 403f:
; ld a, $c4
; ld [$ff46], a ; oam dma
; ld [rDMA], a
; ld a, $28
; .loop
; dec a
@ -456,7 +456,7 @@ VBlank5: ; 400
; scroll x
ld a, [$ffcf]
ld [$ff43], a ; scx
ld [rSCX], a
; if we can update pals, skip this part
call UpdatePalsIfCGB
@ -475,12 +475,12 @@ VBlank5: ; 400
; discard requested ints
xor a
ld [$ff0f], a ; IF
ld [rIF], a
; enable lcd stat
ld a, %10 ; lcd stat
ld [$ffff], a ; IE
ld [rIE], a
; request lcd stat
ld [$ff0f], a ; IF
ld [rIF], a
ei
; update sound
@ -494,10 +494,10 @@ VBlank5: ; 400
; discard requested ints
xor a
ld [$ff0f], a ; IF
ld [rIF], a
; enable ints besides joypad
ld a, %1111 ; serial timer lcdstat vblank
ld [$ffff], a ; IE
ld [rIE], a
ret
; 436

View File

@ -168,7 +168,13 @@ Channel1VibratoRate: ; c121
ds 1
; c126
ds 1
ds 7
; c127
ds 1
Channel1CryPitch: ; c128
ds 1
Channel1CryEcho: ; c129
ds 1
ds 4
Channel1NoteLength: ; c12e
; # frames per 16th note
ds 1
@ -278,9 +284,14 @@ MusicFadeIDLo: ; c2a9
ds 1
MusicFadeIDHi: ; c2aa
ds 1
ds 9
ds 5
CryPitch: ; c2b0
ds 1
CryEcho: ; c2b1
ds 1
CryLength: ; c2b2
ds 2
LastVolume: ; c2b4
; preserves volume of a song playing so cries can have their own volume
ds 1
ds 1
SFXPriority: ; c2b6
@ -643,8 +654,12 @@ OverworldMapEnd
ds 12
SECTION "gfx2",BSS[$cd20]
BGMapBuffer: ; cd20
ds 40
BGMapBuffer:
CreditsPos: ; cd20
ds 2
CreditsTimer: ; cd22
ds 1
ds 37
BGMapPalBuffer: ; cd48
ds 40
@ -837,11 +852,9 @@ TileSetPalettes: ; d1e6
ds 2
Buffer1:
MagikarpLength:
MagikarpLengthHi: ; d1ea
MagikarpLength: ; d1ea
ds 1
Buffer2:
MagikarpLengthLo: ; d1eb
Buffer2: ; d1eb
ds 1
SECTION "prng2",BSS[$d1fa]
@ -1102,6 +1115,12 @@ OTPartyMon5Nickname: ; d416
OTPartyMon6Nickname: ; d421
ds 11
SECTION "Scripting",BSS[$d439]
ScriptBank: ; d439
ds 1
ScriptPos: ; d43a
ds 2
SECTION "Player",BSS[$d472]
PlayerGender: ; d472