diff options
Diffstat (limited to 'main.asm')
-rw-r--r-- | main.asm | 1410 |
1 files changed, 1184 insertions, 226 deletions
@@ -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 |