summaryrefslogtreecommitdiff
path: root/main.asm
diff options
context:
space:
mode:
Diffstat (limited to 'main.asm')
-rw-r--r--main.asm1410
1 files changed, 1184 insertions, 226 deletions
diff --git a/main.asm b/main.asm
index 038d0564b..d29d86ccc 100644
--- a/main.asm
+++ b/main.asm
@@ -140,6 +140,9 @@ IncGradGBPalTable_01: ; 52f
INCBIN "baserom.gbc",$547,$568 - $547
DisableLCD: ; 568
+; Turn the LCD off
+; Most of this is just going through the motions
+
; don't need to do anything if lcd is already off
ld a, [$ff40] ; LCDC
bit 7, a ; lcd enable
@@ -782,7 +785,23 @@ FarCopyBytesDouble: ; e9b
; 0xeba
-INCBIN "baserom.gbc",$eba,$ff1 - $eba
+INCBIN "baserom.gbc",$eba,$fc8 - $eba
+
+ClearTileMap: ; fc8
+; Fill the tile map with blank tiles
+ ld hl, TileMap
+ ld a, $7f ; blank tile
+ ld bc, 360 ; length of TileMap
+ call ByteFill
+
+; We aren't done if the LCD is on
+ ld a, [$ff40] ; LCDC
+ bit 7, a
+ ret z
+ jp WaitBGMap
+; fdb
+
+INCBIN "baserom.gbc",$fdb,$ff1 - $fdb
TextBoxBorder: ; ff1
; draw a text box
@@ -1364,7 +1383,59 @@ BitTableFunc: ; 0x2e76
ret
; 0x2ead
-INCBIN "baserom.gbc",$2ead,$2fb1-$2ead
+INCBIN "baserom.gbc", $2ead, $2f8c - $2ead
+
+RNG: ; 2f8c
+; Two random numbers are generated by adding and subtracting
+; the divider to the respective values every time it's called.
+
+; The divider is a value that increments at a rate of 16384Hz.
+; For comparison, the Game Boy operates at a clock speed of 4.2MHz.
+
+; Additionally, an equivalent function is called every frame.
+
+; output:
+; a: rand2
+; ffe1: rand1
+; ffe2: rand2
+
+ push bc
+; Added value
+ ld a, [$ff04] ; divider
+ ld b, a
+ ld a, [$ffe1]
+ adc b
+ ld [$ffe1], a
+; Subtracted value
+ ld a, [$ff04] ; divider
+ ld b, a
+ ld a, [$ffe2]
+ sbc b
+ ld [$ffe2], a
+ pop bc
+ ret
+; 2f9f
+
+FarBattleRNG: ; 2f9f
+; BattleRNG lives in another bank.
+; It handles all RNG calls in the battle engine,
+; allowing link battles to remain in sync using a shared PRNG.
+
+; Save bank
+ ld a, [$ff9d] ; bank
+ push af
+; Bankswitch
+ ld a, BANK(BattleRNG)
+ rst $10
+ call BattleRNG
+; Restore bank
+ ld [$cfb6], a
+ pop af
+ rst $10
+ ld a, [$cfb6]
+ ret
+; 2fb1
+
Function2fb1: ; 2fb1
push bc
@@ -1423,9 +1494,34 @@ CloseSRAM: ; 2fe1
ld [$0000], a
pop af
ret
-; 2fef
+; 2fec
-INCBIN "baserom.gbc",$2fec,$3026-$2fec
+INCBIN "baserom.gbc",$2fec,$300b-$2fec
+
+ClearSprites: ; 300b
+ ld hl, Sprites
+ ld b, TileMap - Sprites
+ xor a
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+; 3016
+
+HideSprites: ; 3016
+; Set all OBJ y-positions to 160 to hide them offscreen
+ ld hl, Sprites
+ ld de, $0004 ; length of an OBJ struct
+ ld b, $28 ; number of OBJ structs
+ ld a, 160 ; y-position
+.loop
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ ret
+; 3026
CopyBytes: ; 0x3026
; copy bc bytes from hl to de
@@ -1727,10 +1823,62 @@ StringCmp: ; 31db
ret
; 0x31e4
-INCBIN "baserom.gbc",$31e4,$3340 - $31e4
+INCBIN "baserom.gbc",$31e4,$31f3 - $31e4
+WhiteBGMap: ; 31f3
+ call ClearPalettes
+WaitBGMap: ; 31f6
+; Tell VBlank to update BG Map
+ ld a, 1 ; BG Map 0 tiles
+ ld [$ffd4], a
+; Wait for it to do its magic
+ ld c, 4
+ call DelayFrames
+ ret
+; 3200
+
+INCBIN "baserom.gbc",$3200,$3317 - $3200
+
+ClearPalettes: ; 3317
+; Make all palettes white
+
+; For CGB we make all the palette colors white
+ ld a, [$ffe6]
+ and a
+ jr nz, .cgb
+
+; In DMG mode, we can just change palettes to 0 (white)
+ xor a
+ ld [$ff47], a ; BGP
+ ld [$ff48], a ; OBP0
+ ld [$ff49], a ; OBP1
+ ret
+
+.cgb
+; Save WRAM bank
+ ld a, [$ff70]
+ push af
+; WRAM bank 5
+ ld a, 5
+ ld [$ff70], a
+; Fill BGPals and OBPals with $ffff (white)
+ ld hl, BGPals
+ ld bc, $0080
+ ld a, $ff
+ call ByteFill
+; Restore WRAM bank
+ pop af
+ ld [$ff70], a
+; Request palette update
+ ld a, 1
+ ld [$ffe5], a
+ ret
+; 333e
+
+ClearSGB: ; 333e
+ ld b, $ff
GetSGBLayout: ; 3340
-; load sgb packets unless gb
+; load sgb packets unless dmg
; check cgb
ld a, [$ffe6]
@@ -1823,7 +1971,7 @@ GetName: ; 33c3
call GetNthString
ld de, $d073
ld bc, $000d
- call $3026
+ call CopyBytes
.asm_3403
ld a, e
ld [$d102], a
@@ -1878,7 +2026,71 @@ GetItemName: ; 3468
ret
; 0x3487
-INCBIN "baserom.gbc",$3487,$38a2 - $3487
+INCBIN "baserom.gbc",$3487,$3856 - $3487
+
+GetBaseStats: ; 3856
+ push bc
+ push de
+ push hl
+
+; Save bank
+ ld a, [$ff9d]
+ push af
+; Bankswitch
+ ld a, BANK(BaseStats)
+ rst $10
+
+; Egg doesn't have base stats
+ ld a, [CurSpecies]
+ cp EGG
+ jr z, .egg
+
+; Get base stats
+ dec a
+ ld bc, BaseStatsStructEnd - BaseStats
+ ld hl, BaseStats
+ call AddNTimes
+ ld de, CurBaseStats
+ ld bc, BaseStatsStructEnd - BaseStats
+ call CopyBytes
+ jr .end
+
+.egg
+; ????
+ ld de, $7d9c
+
+; Sprite dimensions
+ ld b, $55
+ ld hl, $d247
+ ld [hl], b
+
+; ????
+ ld hl, $d248
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ inc hl
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ jr .end
+
+.end
+; Replace Pokedex # with species
+ ld a, [CurSpecies]
+ ld [CurBaseStats], a
+
+; Restore bank
+ pop af
+ rst $10
+
+ pop hl
+ pop de
+ pop bc
+ ret
+; 389c
+
+INCBIN "baserom.gbc",$389c,$38a2 - $389c
GetNick: ; 38a2
; get the nickname of a partymon
@@ -1985,21 +2197,25 @@ PrintBCDDigit: ; 38f2
ret
; 0x3917
-Function3917: ; 3917
+GetPartyParamLocation: ; 3917
+; Get the location of parameter a from CurPartyMon in hl
push bc
- ld hl, $dcdf
+ ld hl, PartyMons
ld c, a
ld b, $00
add hl, bc
- ld a, [$d109]
- call Function3927
+ ld a, [CurPartyMon]
+ call GetPartyLocation
pop bc
ret
; 3927
-Function3927: ; 3927
-; a is typically [$d109]
- ld bc, $0030
+GetPartyLocation: ; 3927
+; Add the length of a PartyMon struct to hl a times
+; input:
+; a: partymon #
+; hl: partymon struct
+ ld bc, $0030 ; PARTYMON_LENGTH
jp AddNTimes
; 392d
@@ -2159,7 +2375,31 @@ CheckSFX: ; 3dde
ret
; 3dfe
-INCBIN "baserom.gbc",$3dfe,$4000 - $3dfe
+INCBIN "baserom.gbc",$3dfe,$3e10 - $3dfe
+
+ChannelsOff: ; 3e10
+; Quickly turn off music channels
+ xor a
+ ld [$c104], a
+ ld [$c136], a
+ ld [$c168], a
+ ld [$c19a], a
+ ld [$c29c], a
+ ret
+; 3e21
+
+SFXChannelsOff: ; 3e21
+; Quickly turn off sound effect channels
+ xor a
+ ld [$c1cc], a
+ ld [$c1fe], a
+ ld [$c230], a
+ ld [$c262], a
+ ld [$c29c], a
+ ret
+; 3e32
+
+INCBIN "baserom.gbc",$3e32,$4000 - $3e32
SECTION "bank1",DATA,BANK[$1]
@@ -2254,7 +2494,35 @@ CheckNickErrors: ; 669f
db $ff ; end
; 66de
-INCBIN "baserom.gbc",$66de,$8000 - $66de
+INCBIN "baserom.gbc",$66de,$6eef - $66de
+
+DrawGraphic: ; 6eef
+; input:
+; hl: draw location
+; b: height
+; c: width
+; d: tile to start drawing from
+; e: number of tiles to advance for each row
+ call $7009
+ pop bc
+ pop hl
+ ret c
+ bit 5, [hl]
+ jr nz, .asm_6f05
+ push hl
+ call $70a4
+ pop hl
+ ret c
+ push hl
+ call $70ed
+ pop hl
+ ret c
+.asm_6f05
+ and a
+ ret
+; 6f07
+
+INCBIN "baserom.gbc",$6f07,$8000 - $6f07
SECTION "bank2",DATA,BANK[$2]
@@ -2503,7 +2771,7 @@ SpecialsPointers: ; 0xc029
dbw $01,$7305
dbw $01,$737e
dbw $01,$73f7
- dbw $03,$4419
+ dbw BANK(SpecialCheckPokerus),SpecialCheckPokerus
dbw $09,$4b25
dbw $09,$4b4e
dbw $09,$4ae8
@@ -2595,7 +2863,28 @@ SpecialsPointers: ; 0xc029
dbw $24,$4a88
dbw $03,$4224
-INCBIN "baserom.gbc",$c224,$c43d - $c224
+INCBIN "baserom.gbc",$c224,$c3e2 - $c224
+
+ScriptReturnCarry: ; c3e2
+ jr c, .carry
+ xor a
+ ld [ScriptVar], a
+ ret
+.carry
+ ld a, 1
+ ld [ScriptVar], a
+ ret
+; c3ef
+
+INCBIN "baserom.gbc",$c3ef,$c419 - $c3ef
+
+SpecialCheckPokerus: ; c419
+; Check if a monster in your party has Pokerus
+ callba CheckPokerus
+ jp ScriptReturnCarry
+; c422
+
+INCBIN "baserom.gbc",$c422,$c43d - $c422
SpecialSnorlaxAwake: ; 0xc43d
; Check if the Poké Flute channel is playing, and if the player is standing
@@ -12501,53 +12790,100 @@ INCBIN "baserom.gbc",$3d14e,$3ddc2 - $3d14e
INCBIN "baserom.gbc",$3ddc8,$3e8eb - $3ddc8
-Function3e8eb: ; 3e8eb
-;part of battle init
+LoadEnemyMon: ; 3e8eb
+; Initialize enemy monster parameters
+; To do this we pull the species from TempEnemyMonSpecies
+
+; Notes:
+; FarBattleRNG is used to ensure sync between Game Boys
+
+; Clear the whole EnemyMon struct
xor a
ld hl, EnemyMonSpecies
ld bc, $0027
call ByteFill
+
+; We don't need to be here if we're in a link battle
ld a, [InLinkBattle]
and a
jp nz, $5abd
- ld a, [$cfc0]
+
+ ld a, [$cfc0] ; ????
bit 0, a
jp nz, $5abd
+
+; Make sure everything knows what species we're working with
ld a, [TempEnemyMonSpecies]
ld [EnemyMonSpecies], a
- ld [$cf60], a
- ld [$d108], a
- call $3856
- ld a, [$d22d]
+ ld [CurSpecies], a
+ ld [CurPartySpecies], a
+
+; Grab the base stats for this species
+ call GetBaseStats
+
+
+; Let's get the item:
+
+; Is the item predetermined?
+ ld a, [IsInBattle]
dec a
- jr z, .asm_3e925
- ld a, [$d109]
- ld hl, $d289
- call Function3927
+ jr z, .WildItem
+
+; If we're in a trainer battle, the item is in the party struct
+ ld a, [CurPartyMon]
+ ld hl, OTPartyMon1Item
+ call GetPartyLocation ; bc = PartyMon[CurPartyMon] - PartyMons
ld a, [hl]
- jr .asm_3e945
-.asm_3e925
+ jr .UpdateItem
+
+
+.WildItem
+; In a wild battle, we pull from the item slots in base stats
+
+; Force Item1
+; Used for Ho-Oh, Lugia and Snorlax encounters
ld a, [BattleType]
- cp a, $0a
- ld a, [$d241]
- jr z, .asm_3e945
- call $2f9f
- cp a, $c0
- ld a, $00
- jr c, .asm_3e945
- call $2f9f
- cp a, $14
- ld a, [$d241]
- jr nc, .asm_3e945
- ld a, [$d242]
-.asm_3e945
+ cp BATTLETYPE_FORCEITEM
+ ld a, [$d241] ; BufferMonItem1
+ jr z, .UpdateItem
+
+; Failing that, it's all up to chance
+; Effective chances:
+; 75% None
+; 23% Item1
+; 2% Item2
+
+; 25% chance of getting an item
+ call FarBattleRNG
+ cp a, $c0 ; $c0/$100 = 75%
+ ld a, NO_ITEM
+ jr c, .UpdateItem
+
+; From there, an 8% chance for Item2
+ call FarBattleRNG
+ cp a, $14 ; 8% of 25% = 2% Item2
+ ld a, [$d241] ; BaseStatsItem1
+ jr nc, .UpdateItem
+ ld a, [$d242] ; BaseStatsItem2
+
+
+.UpdateItem
ld [EnemyMonItem], a
- ld a, [$d22d]
+
+
+; Initialize DVs
+
+; If we're in a trainer battle, DVs are predetermined
+ ld a, [IsInBattle]
and a
- jr z, .asm_3e963
+ jr z, .InitDVs
+
+; ????
ld a, [$c671]
bit 3, a
- jr z, .asm_3e963
+ jr z, .InitDVs
+
+; Unknown
ld hl, $c6f2
ld de, EnemyMonDVs
ld a, [hli]
@@ -12555,161 +12891,276 @@ Function3e8eb: ; 3e8eb
inc de
ld a, [hl]
ld [de], a
- jp .asm_3ea1a
-.asm_3e963
- ld a, $09
- ld hl, $70c4
- rst $08
- ld a, [$d22d]
+ jp .Happiness
+
+
+.InitDVs
+
+; Trainer DVs
+
+; All trainers have preset DVs, determined by class
+; See GetTrainerDVs for more on that
+ callba GetTrainerDVs
+; These are the DVs we'll use if we're actually in a trainer battle
+ ld a, [IsInBattle]
dec a
- jr nz, .asm_3e9a8
+ jr nz, .UpdateDVs
+
+
+; Wild DVs
+; Here's where the fun starts
+
+; Roaming monsters (Entei, Raikou) work differently
+; They have their own structs, which are shorter than normal
ld a, [BattleType]
- cp a, $05
- jr nz, .asm_3e996
- call $7a01
+ cp a, BATTLETYPE_ROAMING
+ jr nz, .NotRoaming
+
+; Grab HP
+ call GetRoamMonHP
ld a, [hl]
+; Check if the HP has been initialized
and a
+; We'll do something with the result in a minute
push af
- call $7a19
+
+; Grab DVs
+ call GetRoamMonDVs
inc hl
ld a, [hld]
ld c, a
ld b, [hl]
+
+; Get back the result of our check
pop af
- jr nz, .asm_3e9a8
- call $7a19
+; If the RoamMon struct has already been initialized, we're done
+ jr nz, .UpdateDVs
+
+; If it hasn't, we need to initialize the DVs
+; (HP is initialized at the end of the battle)
+ call GetRoamMonDVs
inc hl
- call $2f9f
+ call FarBattleRNG
ld [hld], a
ld c, a
- call $2f9f
+ call FarBattleRNG
ld [hl], a
ld b, a
- jr .asm_3e9a8
-.asm_3e996
- cp a, $07
- jr nz, .asm_3e9a0
- ld b, $ea
- ld c, $aa
- jr .asm_3e9a8
-.asm_3e9a0
- call $2f9f
+; We're done with DVs
+ jr .UpdateDVs
+
+
+.NotRoaming
+; Register a contains BattleType
+
+; Forced shiny battle type
+; Used by Red Gyarados at Lake of Rage
+ cp a, BATTLETYPE_SHINY
+ jr nz, .GenerateDVs
+
+ ld b, ATKDEFDV_SHINY ; $ea
+ ld c, SPDSPCDV_SHINY ; $aa
+ jr .UpdateDVs
+
+.GenerateDVs
+; Generate new random DVs
+ call FarBattleRNG
ld b, a
- call $2f9f
+ call FarBattleRNG
ld c, a
-.asm_3e9a8
+
+.UpdateDVs
+; Input DVs in register bc
ld hl, EnemyMonDVs
ld a, b
ld [hli], a
ld [hl], c
- ld a, [$d22d]
+
+
+; We've still got more to do if we're dealing with a wild monster
+ ld a, [IsInBattle]
dec a
- jr nz, .asm_3ea1a
+ jr nz, .Happiness
+
+
+; Species-specfic:
+
+
+; Unown
ld a, [TempEnemyMonSpecies]
cp a, UNOWN
- jr nz, .notunown
+ jr nz, .Magikarp
+
+; Get letter based on DVs
ld hl, EnemyMonDVs
- ld a, $2d
- call $2d83
+ ld a, PREDEF_GETUNOWNLETTER
+ call Predef
+; Can't use any letters that haven't been unlocked
+; If combined with forced shiny battletype, causes an infinite loop
call CheckUnownLetter
- jr c, .asm_3e9a0
-.notunown
+ jr c, .GenerateDVs ; try again
+
+
+.Magikarp
+; Skimming this part recommended
+
ld a, [TempEnemyMonSpecies]
cp a, MAGIKARP
- jr nz, .asm_3ea1a
+ jr nz, .Happiness
+
+; Get Magikarp's length
ld de, EnemyMonDVs
ld bc, PlayerID
- ld hl, CalcMagikarpLength
- ld a, BANK(CalcMagikarpLength)
- rst $08
- ld a, [$d1ea] ; Magikarp's length
- cp a, $06
- jr nz, .asm_3e9fe
- call $2f8c
- cp a, $0c
- jr c, .asm_3e9fe
- ld a, [$d1eb]
+ callab CalcMagikarpLength
+
+; We're clear if the length is < 1536
+ ld a, [MagikarpLengthHi]
+ cp a, $06 ; $600 = 1536
+ jr nz, .CheckMagikarpArea
+
+; 5% chance of skipping size checks
+ call RNG
+ cp a, $0c ; / $100
+ jr c, .CheckMagikarpArea
+; Try again if > 1614
+ ld a, [MagikarpLengthLo]
cp a, $50
- jr nc, .asm_3e9a0
- call $2f8c
- cp a, $32
- jr c, .asm_3e9fe
- ld a, [$d1eb]
+ jr nc, .GenerateDVs
+
+; 20% chance of skipping this check
+ call RNG
+ cp a, $32 ; / $100
+ jr c, .CheckMagikarpArea
+; Try again if > 1598
+ ld a, [MagikarpLengthLo]
cp a, $40
- jr nc, .asm_3e9a0
-.asm_3e9fe
- ld a, [$dcb5]
- cp a, $09
- jr z, .asm_3ea1a
- ld a, [$dcb6]
- cp a, $06
- jr z, .asm_3ea1a
- call $2f8c
- cp a, $64
- jr c, .asm_3ea1a
- ld a, [$d1ea]
- cp a, $04
- jr c, .asm_3e9a0
-.asm_3ea1a
- ld a, $46
+ jr nc, .GenerateDVs
+
+.CheckMagikarpArea
+; The z checks are supposed to be nz
+; Instead, all maps in GROUP_LAKE_OF_RAGE (mahogany area)
+; and routes 20 and 44 are treated as Lake of Rage
+
+; This also means Lake of Rage Magikarp can be smaller than ones
+; caught elsewhere rather than the other way around
+
+; Intended behavior enforces a minimum size at Lake of Rage
+; The real behavior prevents size flooring in the Lake of Rage area
+ ld a, [MapGroup]
+ cp a, GROUP_LAKE_OF_RAGE
+ jr z, .Happiness
+ ld a, [MapNumber]
+ cp a, MAP_LAKE_OF_RAGE
+ jr z, .Happiness
+; 40% chance of not flooring
+ call RNG
+ cp a, $64 ; / $100
+ jr c, .Happiness
+; Floor at length 1024
+ ld a, [MagikarpLengthHi]
+ cp a, $04 ; $400 = 1024
+ jr c, .GenerateDVs ; try again
+
+
+; Finally done with DVs
+
+.Happiness
+; Set happiness
+ ld a, 70 ; BASE_HAPPINESS
ld [EnemyMonHappiness], a
- ld a, [$d143]
+; Set level
+ ld a, [CurPartyLevel]
ld [EnemyMonLevel], a
+; Fill stats
ld de, EnemyMonMaxHP
ld b, $00
- ld hl, $d201
- ld a, $0c
- call $2d83
- ld a, [$d22d]
- cp a, $02
- jr z, .asm_3ea74
+ ld hl, $d201 ; ?
+ ld a, PREDEF_FILLSTATS
+ call Predef
+
+; If we're in a trainer battle,
+; get the rest of the parameters from the party struct
+ ld a, [IsInBattle]
+ cp a, TRAINER_BATTLE
+ jr z, .OpponentParty
+
+; If we're in a wild battle, check wild-specific stuff
and a
- jr z, .asm_3ea44
+ jr z, .TreeMon
+
+; ????
ld a, [$c671]
bit 3, a
- jp nz, .asm_3ea90
-.asm_3ea44
+ jp nz, .Moves
+
+.TreeMon
+; If we're headbutting trees, some monsters enter battle asleep
call CheckSleepingTreeMon
- ld a, $07
- jr c, .asm_3ea4c
+ ld a, 7 ; Asleep for 7 turns
+ jr c, .UpdateStatus
+; Otherwise, no status
xor a
-.asm_3ea4c
+
+.UpdateStatus
ld hl, EnemyMonStatus
ld [hli], a
+
+; Unused byte
xor a
ld [hli], a
+
+; Full HP...
ld a, [EnemyMonMaxHPHi]
ld [hli], a
ld a, [EnemyMonMaxHPLo]
ld [hl], a
+
+; ...unless it's a RoamMon
ld a, [BattleType]
- cp a, $05
- jr nz, .asm_3ea90
- call $7a01
+ cp a, BATTLETYPE_ROAMING
+ jr nz, .Moves
+
+; Grab HP
+ call GetRoamMonHP
ld a, [hl]
+; Check if it's been initialized again
and a
- jr z, .asm_3ea6e
+ jr z, .InitRoamHP
+; Update from the struct if it has
ld a, [hl]
ld [EnemyMonHPLo], a
- jr .asm_3ea90
-.asm_3ea6e
+ jr .Moves
+
+.InitRoamHP
+; HP only uses the lo byte in the RoamMon struct since
+; Raikou/Entei/Suicune will have < 256 hp at level 40
ld a, [EnemyMonHPLo]
ld [hl], a
- jr .asm_3ea90
-.asm_3ea74
- ld hl, $d2ab
- ld a, [$d109]
- call Function3927
+ jr .Moves
+
+
+.OpponentParty
+; Get HP from the party struct
+ ld hl, (PartyMon1CurHP + 1) - PartyMon1 + OTPartyMon1
+ ld a, [CurPartyMon]
+ call GetPartyLocation
ld a, [hld]
ld [EnemyMonHPLo], a
ld a, [hld]
ld [EnemyMonHPHi], a
- ld a, [$d109]
- ld [$c663], a
+
+; Make sure everything knows which monster the opponent is using
+ ld a, [CurPartyMon]
+ ld [CurOTMon], a
+
+; Get status from the party struct
dec hl
- ld a, [hl]
+ ld a, [hl] ; OTPartyMonStatus
ld [EnemyMonStatus], a
-.asm_3ea90
+
+
+.Moves
+; ????
ld hl, $d23d
ld de, $d224
ld a, [hli]
@@ -12717,17 +13168,23 @@ Function3e8eb: ; 3e8eb
inc de
ld a, [hl]
ld [de], a
+
+; Get moves
ld de, EnemyMonMoves
- ld a, [$d22d]
- cp a, $02
- jr nz, .asm_3eab6
+; Are we in a trainer battle?
+ ld a, [IsInBattle]
+ cp a, TRAINER_BATTLE
+ jr nz, .WildMoves
+; Then copy moves from the party struct
ld hl, OTPartyMon1Moves
- ld a, [$d109]
- call Function3927
- ld bc, $0004
+ ld a, [CurPartyMon]
+ call GetPartyLocation
+ ld bc, NUM_MOVES
call CopyBytes
- jr .asm_3eac5
-.asm_3eab6
+ jr .PP
+
+.WildMoves
+; Clear EnemyMonMoves
xor a
ld h, d
ld l, e
@@ -12735,86 +13192,115 @@ Function3e8eb: ; 3e8eb
ld [hli], a
ld [hli], a
ld [hl], a
+; Make sure the predef knows this isn't a partymon
ld [$d1ea], a
- ld a, $1b
- call $2d83
-.asm_3eac5
- ld a, [$d22d]
- cp a, $02
- jr z, .asm_3ead9
+; Fill moves based on level
+ ld a, PREDEF_FILLMOVES
+ call Predef
+
+.PP
+; Trainer battle?
+ ld a, [IsInBattle]
+ cp a, TRAINER_BATTLE
+ jr z, .TrainerPP
+
+; Fill wild PP
ld hl, EnemyMonMoves
ld de, EnemyMonPP
- ld a, $05
- call $2d83
- jr .asm_3eaeb
-.asm_3ead9
- ld hl, $d29f
- ld a, [$d109]
- call Function3927
+ ld a, PREDEF_FILLPP
+ call Predef
+ jr .Finish
+
+.TrainerPP
+; Copy PP from the party struct
+ ld hl, OTPartyMon1PP
+ ld a, [CurPartyMon]
+ call GetPartyLocation
ld de, EnemyMonPP
- ld bc, $0004
+ ld bc, NUM_MOVES
call CopyBytes
-.asm_3eaeb
+
+.Finish
+; ????
ld hl, $d237
ld de, $d226
- ld b, $05
-.asm_3eaf3
+ ld b, 5 ; # bytes to copy
+; Copy $d237-a to $d226-9
+.loop
ld a, [hli]
ld [de], a
inc de
dec b
- jr nz, .asm_3eaf3
+ jr nz, .loop
+; Copy $d23f to $d22a
ld a, [$d23f]
ld [de], a
inc de
+; Copy $d240 to $d22b
ld a, [$d240]
ld [de], a
+; copy TempEnemyMonSpecies to $d265
ld a, [TempEnemyMonSpecies]
ld [$d265], a
+; ????
call $343b
- ld a, [$d22d]
+; If wild, we're done
+ ld a, [IsInBattle]
and a
ret z
- ld hl, $d073
- ld de, $c616
- ld bc, $000b
+; Update enemy nick
+ ld hl, StringBuffer1
+ ld de, EnemyMonNick
+ ld bc, PKMN_NAME_LENGTH
call CopyBytes
+; ????
ld a, [TempEnemyMonSpecies]
dec a
ld c, a
ld b, $01
ld hl, $deb9
- ld a, $03
- call $2d83
+ ld a, $03 ; PREDEF_
+ call Predef
+; Fill EnemyMon stats
ld hl, EnemyMonAtk
ld de, $c6c1
- ld bc, $000a
+ ld bc, 2*(NUM_STATS-1) ; 2 bytes for each non-HP stat
call CopyBytes
+; We're done
ret
; 3eb38
+
CheckSleepingTreeMon: ; 3eb38
+; Return carry if species is in the list
+; for the current time of day
+
+; Don't do anything if this isn't a tree encounter
ld a, [BattleType]
- cp a, $08 ; headbutt
- jr nz, .notsleeping
- ld hl, SleepingTreeMonMornTable
+ cp a, BATTLETYPE_TREE
+ jr nz, .NotSleeping
+
+; Get list for the time of day
+ ld hl, .Morn
ld a, [TimeOfDay]
- cp a, $01 ; day
- jr c, .check
- ld hl, SleepingTreeMonDayTable
- jr z, .check
- ld hl, SleepingTreeMonNiteTable
-.check
+ cp a, DAY
+ jr c, .Check
+ ld hl, .Day
+ jr z, .Check
+ ld hl, .Nite
+
+.Check
ld a, [TempEnemyMonSpecies]
- ld de, $0001
+ ld de, 1 ; length of species id
call IsInArray
+; If it's a match, the opponent is asleep
ret c
-.notsleeping
+
+.NotSleeping
and a
ret
-; 3eb5d
-SleepingTreeMonNiteTable: ; 3eb5d
+.Nite
db CATERPIE
db METAPOD
db BUTTERFREE
@@ -12827,18 +13313,16 @@ SleepingTreeMonNiteTable: ; 3eb5d
db LEDYBA
db AIPOM
db $ff ; end
-; 3eb69
-SleepingTreeMonDayTable: ; 3eb69
+.Day
db VENONAT
db HOOTHOOT
db NOCTOWL
db SPINARAK
db HERACROSS
db $ff ; end
-; 3eb6f
-SleepingTreeMonMornTable ; 3eb6f
+.Morn
db VENONAT
db HOOTHOOT
db NOCTOWL
@@ -12847,19 +13331,23 @@ SleepingTreeMonMornTable ; 3eb6f
db $ff ; end
; 3eb75
+
CheckUnownLetter: ; 3eb75
-; returns carry if not a valid letter
- ld a, [$def3]
+; Return carry if the Unown letter hasn't been unlocked yet
+ ld a, [$def3] ; UnownLetter
ld c, a
ld de, $0000
-.asm_3eb7c
- srl c ; bit 0 off?
- jr nc, .asm_3eb96
- ld hl, UnownLetterPointerTable
+.loop
+; Has this set been unlocked?
+ srl c
+ jr nc, .next
+; Check out the set
+ ld hl, .LetterSets
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
+; Is our letter in the set?
push de
ld a, [$d234]
ld de, $0001
@@ -12867,51 +13355,164 @@ CheckUnownLetter: ; 3eb75
call IsInArray
pop bc
pop de
- jr c, .end
-.asm_3eb96
+ jr c, .Match
+.next
+; Next set
inc e
inc e
ld a, e
- cp a, $08 ; has the end of the table been reached?
- jr c, .asm_3eb7c
+; Gone past the end of the table?
+ cp a, 4*2 ; 4 sets with 2-byte pointers
+ jr c, .loop
+
+; Didn't find the letter (not unlocked)
scf
ret
-.end
+
+.Match
+; Valid letter
and a
ret
-UnownLetterPointerTable: ; 3eba1
- dw UnownLetterTable
- dw UnownLetterTable2
- dw UnownLetterTable3
- dw UnownLetterTable4
-; 3eba9
+.LetterSets
+ dw .Set1
+ dw .Set2
+ dw .Set3
+ dw .Set4
-UnownLetterTable: ; 3eba9
+.Set1
; A B C D E F G H I J K
db $01, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $0b
- db $ff
-; 3ebb5
+ db $ff ; end
-UnownLetterTable2: ; 3ebb5
+.Set2
; L M N O P Q R
db $0c, $0d, $0e, $0f, $10, $11, $12
- db $ff
-; 3ebbd
+ db $ff ; end
-UnownLetterTable3: ; 3ebbd
+.Set3
; S T U V W
db $13, $14, $15, $16, $17
- db $ff
-; 3ebc3
+ db $ff ; end
-UnownLetterTable4: ; 3ebc3
+.Set4
; X Y Z
db $18, $19, $1a
- db $ff
-;3ebc7
+ db $ff ; end
+; 3ebc7
+
+INCBIN "baserom.gbc", $3ebc7, $3edd8 - $3ebc7
+
+BattleRNG: ; 3edd8
+; If the normal RNG is used in a link battle it'll desync.
+; To circumvent this a shared PRNG is used instead.
+
+; But if we're in a non-link battle we're safe to use it
+ ld a, [InLinkBattle]
+ and a
+ jp z, RNG
+
+; The PRNG operates in streams of 8 values
+; The reasons for this are unknown
+
+; Which value are we trying to pull?
+ push hl
+ push bc
+ ld a, [LinkBattleRNCount]
+ ld c, a
+ ld b, $0
+ ld hl, LinkBattleRNs
+ add hl, bc
+ inc a
+ ld [LinkBattleRNCount], a
+
+; If we haven't hit the end yet, we're good
+ cp 9 ; Exclude last value. See the closing comment
+ ld a, [hl]
+ pop bc
+ pop hl
+ ret c
+
+
+; If we have, we have to generate new pseudorandom data
+; Instead of having multiple PRNGs, ten seeds are used
+ push hl
+ push bc
+ push af
+
+; Reset count to 0
+ xor a
+ ld [LinkBattleRNCount], a
+ ld hl, LinkBattleRNs
+ ld b, 10 ; number of seeds
+
+; Generate next number in the sequence for each seed
+; The algorithm takes the form *5 + 1 % 256
+.loop
+ ; get last #
+ ld a, [hl]
+
+ ; a * 5 + 1
+ ld c, a
+ add a
+ add a
+ add c
+ inc a
+
+ ; update #
+ ld [hli], a
+ dec b
+ jr nz, .loop
+
+; This has the side effect of pulling the last value first,
+; then wrapping around. As a result, when we check to see if
+; we've reached the end, we have to take this into account.
+ pop af
+ pop bc
+ pop hl
+ ret
+; 3ee0f
-INCBIN "baserom.gbc",$3ebc7,$3fc8b - $3ebc7
+INCBIN "baserom.gbc", $3ee0f, $3fa01 - $3ee0f
+
+GetRoamMonHP: ; 3fa01
+; output: hl = RoamMonCurHP
+ ld a, [TempEnemyMonSpecies]
+ ld b, a
+ ld a, [RoamMon1Species]
+ cp b
+ ld hl, RoamMon1CurHP
+ ret z
+ ld a, [RoamMon2Species]
+ cp b
+ ld hl, RoamMon2CurHP
+ ret z
+; remnant of the GS function
+; we know this will be $00 because it's never initialized
+ ld hl, RoamMon3CurHP
+ ret
+; 3fa19
+
+GetRoamMonDVs: ; 3fa19
+; output: hl = RoamMonDVs
+ ld a, [TempEnemyMonSpecies]
+ ld b, a
+ ld a, [RoamMon1Species]
+ cp b
+ ld hl, RoamMon1DVs
+ ret z
+ ld a, [RoamMon2Species]
+ cp b
+ ld hl, RoamMon2DVs
+ ret z
+; remnant of the GS function
+; we know this will be $0000 because it's never initialized
+ ld hl, RoamMon3DVs
+ ret
+; 3fa31
+
+
+INCBIN "baserom.gbc", $3fa31, $3fc8b - $3fa31
; I have no clue what most of this does
@@ -18073,7 +18674,36 @@ TileTypeTable: ; 4ce1f
db $00, $00, $00, $00, $00, $00, $00, $0f
; 4cf1f
-INCBIN "baserom.gbc",$4cf1f,$50000 - $4cf1f
+INCBIN "baserom.gbc",$4cf1f,$4d860 - $4cf1f
+
+CheckPokerus: ; 4d860
+; Return carry if a monster in your party has Pokerus
+
+; Get number of monsters to iterate over
+ ld a, [PartyCount]
+ and a
+ jr z, .NoPokerus
+ ld b, a
+; Check each monster in the party for Pokerus
+ ld hl, PartyMon1PokerusStatus
+ ld de, PartyMon2 - PartyMon1
+.Check
+ ld a, [hl]
+ and $0f ; only the bottom nybble is used
+ jr nz, .HasPokerus
+; Next PartyMon
+ add hl, de
+ dec b
+ jr nz, .Check
+.NoPokerus
+ and a
+ ret
+.HasPokerus
+ scf
+ ret
+; 4d87a
+
+INCBIN "baserom.gbc",$4d87a,$50000 - $4d87a
SECTION "bank14",DATA,BANK[$14]
@@ -18124,6 +18754,9 @@ Dark:
INCBIN "baserom.gbc",$50A28, $51424 - $50A28
+
+BaseStats:
+
BulbasaurBaseStats: ; 0x51424
db BULBASAUR ; 001
@@ -18154,6 +18787,7 @@ BulbasaurBaseStats: ; 0x51424
db %01000101
db %00000000
; end
+BaseStatsStructEnd:
IvysaurBaseStats: ; 0x51444
db IVYSAUR ; 002
@@ -88337,7 +88971,7 @@ SFX: ; e927c
dbw $3c, $4a22 ; tap
dbw $3c, $4a25 ; tap
dbw $3c, $4a28 ; burn ; that is not a burn
- dbw $3c, $4a2b ;
+ dbw $3c, $4a2b ; title screen sound
dbw $3c, $4a2e ; similar to $60
dbw $3c, $4a31 ; get coin from slots
dbw $3c, $4a34 ; pay day
@@ -89093,7 +89727,245 @@ INCBIN "baserom.gbc", $10983f, $10c000 - $10983f
SECTION "bank43",DATA,BANK[$43]
-INCBIN "baserom.gbc", $10c000, $10ef46 - $10c000
+INCBIN "baserom.gbc", $10c000, $10ed67 - $10c000
+
+TitleScreen: ; 10ed67
+
+ call WhiteBGMap
+ call ClearSprites
+ call ClearTileMap
+
+; Turn BG Map update off
+ xor a
+ ld [$ffd4], a
+
+; Reset timing variables
+ ld hl, $cf63
+ ld [hli], a ; cf63 ; Scene?
+ ld [hli], a ; cf64
+ ld [hli], a ; cf65 ; Timer lo
+ ld [hl], a ; cf66 ; Timer hi
+
+; Turn LCD off
+ call DisableLCD
+
+
+; VRAM bank 1
+ ld a, 1
+ ld [$ff4f], a
+
+
+; Decompress running Suicune gfx
+ ld hl, TitleSuicuneGFX
+ ld de, $8800
+ call $0b50
+
+
+; Clear screen palettes
+ ld hl, $9800
+ ld bc, $0280
+ xor a
+ call ByteFill
+
+
+; Fill tile palettes:
+
+; BG Map 1:
+
+; line 0 (copyright)
+ ld hl, $9c00
+ ld bc, $0020 ; one row
+ ld a, 7 ; palette
+ call ByteFill
+
+
+; BG Map 0:
+
+; Apply logo gradient:
+
+; lines 3-4
+ ld hl, $9860 ; (0,3)
+ ld bc, $0040 ; 2 rows
+ ld a, 2
+ call ByteFill
+; line 5
+ ld hl, $98a0 ; (0,5)
+ ld bc, $0020 ; 1 row
+ ld a, 3
+ call ByteFill
+; line 6
+ ld hl, $98c0 ; (0,6)
+ ld bc, $0020 ; 1 row
+ ld a, 4
+ call ByteFill
+; line 7
+ ld hl, $98e0 ; (0,7)
+ ld bc, $0020 ; 1 row
+ ld a, 5
+ call ByteFill
+; lines 8-9
+ ld hl, $9900 ; (0,8)
+ ld bc, $0040 ; 2 rows
+ ld a, 6
+ call ByteFill
+
+
+; 'CRYSTAL VERSION'
+ ld hl, $9925 ; (5,9)
+ ld bc, $000b ; length of version text
+ ld a, 1
+ call ByteFill
+
+; Suicune gfx
+ ld hl, $9980 ; (0,12)
+ ld bc, $00c0 ; the rest of the screen
+ ld a, 8
+ call ByteFill
+
+
+; Back to VRAM bank 0
+ ld a, $0
+ ld [$ff4f], a
+
+
+; Decompress logo
+ ld hl, TitleLogoGFX
+ ld de, $8800
+ call $0b50
+
+; Decompress background crystal
+ ld hl, TitleCrystalGFX
+ ld de, $8000
+ call $0b50
+
+
+; Clear screen tiles
+ ld hl, $9800
+ ld bc, $0800
+ ld a, $7f
+ call ByteFill
+
+; Draw Pokemon logo
+ ld hl, $c4dc ; TileMap(0,3)
+ ld bc, $0714 ; 20x7
+ ld d, $80
+ ld e, $14
+ call DrawGraphic
+
+; Draw copyright text
+ ld hl, $9c03 ; BG Map 1 (3,0)
+ ld bc, $010d ; 13x1
+ ld d, $c
+ ld e, $10
+ call DrawGraphic
+
+; Initialize running Suicune?
+ ld d, $0
+ call $6ed2
+
+; Initialize background crystal
+ call $6f06
+
+; Save WRAM bank
+ ld a, [$ff70]
+ push af
+; WRAM bank 5
+ ld a, 5
+ ld [$ff70], a
+
+; Update palette colors
+ ld hl, TitleScreenPalettes
+ ld de, $d000
+ ld bc, $0080
+ call CopyBytes
+
+ ld hl, TitleScreenPalettes
+ ld de, $d080
+ ld bc, $0080
+ call CopyBytes
+
+; Restore WRAM bank
+ pop af
+ ld [$ff70], a
+
+
+; LY/SCX trickery starts here
+
+; Save WRAM bank
+ ld a, [$ff70]
+ push af
+; WRAM bank 5
+ ld a, 5
+ ld [$ff70], a
+
+; Make alternating lines come in from opposite sides
+
+; ( This part is actually totally pointless, you can't
+; see anything until these values are overwritten! )
+
+ ld b, 40 ; alternate for 80 lines
+ ld hl, $d100 ; LY buffer
+.loop
+; $00 is the middle position
+ ld [hl], $70 ; coming from the left
+ inc hl
+ ld [hl], $90 ; coming from the right
+ inc hl
+ dec b
+ jr nz, .loop
+
+; Make sure the rest of the buffer is empty
+ ld hl, $d150
+ xor a
+ ld bc, $0040
+ call ByteFill
+
+; Let LCD Stat know we're messing around with SCX
+ ld a, $43 ; ff43 ; SCX
+ ld [$ffc6], a
+
+; Restore WRAM bank
+ pop af
+ ld [$ff70], a
+
+
+; Reset audio
+ call ChannelsOff
+ call $058a
+
+; Set sprite size to 8x16
+ ld a, [$ff40] ; LCDC
+ set 2, a
+ ld [$ff40], a ; LCDC
+
+;
+ ld a, $70
+ ld [$ffcf], a
+ ld a, $8
+ ld [$ffd0], a
+ ld a, $7
+ ld [$ffd1], a
+ ld a, $90
+ ld [$ffd2], a
+
+ ld a, $1
+ ld [$ffe5], a
+
+; Update BG Map 0 (bank 0)
+ ld [$ffd4], a
+
+ xor a
+ ld [$d002], a
+
+; Play starting sound effect
+ call SFXChannelsOff
+ ld de, $0065
+ call StartSFX
+
+ ret
+; 10eea7
+
+INCBIN "baserom.gbc", $10eea7, $10ef46 - $10eea7
TitleSuicuneGFX: ; 10ef46
INCBIN "gfx/title/lz/suicune.lz"
@@ -89111,7 +89983,93 @@ TitleCrystalGFX: ; 10fcee
INCBIN "gfx/title/lz/crystal.lz"
; 10fed7
-INCBIN "baserom.gbc", $10fed7, $110000 - $10fed7
+INCBIN "baserom.gbc", $10fed7, $10fede - $10fed7
+
+TitleScreenPalettes:
+; BG
+ RGB 00, 00, 00
+ RGB 19, 00, 00
+ RGB 15, 08, 31
+ RGB 15, 08, 31
+
+ RGB 00, 00, 00
+ RGB 31, 31, 31
+ RGB 15, 16, 31
+ RGB 31, 01, 13
+
+ RGB 00, 00, 00
+ RGB 07, 07, 07
+ RGB 31, 31, 31
+ RGB 02, 03, 30
+
+ RGB 00, 00, 00
+ RGB 13, 13, 13
+ RGB 31, 31, 18
+ RGB 02, 03, 30
+
+ RGB 00, 00, 00
+ RGB 19, 19, 19
+ RGB 29, 28, 12
+ RGB 02, 03, 30
+
+ RGB 00, 00, 00
+ RGB 25, 25, 25
+ RGB 28, 25, 06
+ RGB 02, 03, 30
+
+ RGB 00, 00, 00
+ RGB 31, 31, 31
+ RGB 26, 21, 00
+ RGB 02, 03, 30
+
+ RGB 00, 00, 00
+ RGB 11, 11, 19
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+
+; OBJ
+ RGB 00, 00, 00
+ RGB 10, 00, 15
+ RGB 17, 05, 22
+ RGB 19, 09, 31
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+ RGB 31, 31, 31
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+ RGB 00, 00, 00
+
+
+INCBIN "baserom.gbc", $10ff5e, $110000 - $10ff5e
SECTION "bank44",DATA,BANK[$44]
@@ -89376,7 +90334,7 @@ Function117bb6:
ld hl, $d002
ld de, $b000
ld bc, $1000
- call $3026
+ call CopyBytes
call CloseSRAM
pop af
ld [$ff70], a