From 7d55a3909698d069f002c8f8297b7eb164361e59 Mon Sep 17 00:00:00 2001 From: yenatch Date: Fri, 11 Jan 2013 02:18:34 -0500 Subject: [PATCH] comment LoadEnemyMon and related fns; add RNG fns --- constants.asm | 23 +- main.asm | 857 +++++++++++++++++++++++++++++++++++++------------- wram.asm | 2 +- 3 files changed, 662 insertions(+), 220 deletions(-) diff --git a/constants.asm b/constants.asm index a3ad5e0d7..0df4de29e 100644 --- a/constants.asm +++ b/constants.asm @@ -1599,6 +1599,12 @@ THURSDAY EQU $04 FRIDAY EQU $05 SATURDAY EQU $06 +; times of day +MORN EQU 0 +DAY EQU 1 +NITE EQU 2 +DARKNESS EQU 3 + ; trainer groups FALKNER EQU $01 WHITNEY EQU $02 @@ -3247,17 +3253,15 @@ SPECIAL_DRATINI EQU $0094 SPECIAL_BEASTSCHECK EQU $0096 SPECIAL_MONCHECK EQU $0097 -; battle scripts -BATTLE_FILLPP EQU $05 -BATTLE_FILLSTATS EQU $0C - -BATTLE_FILLMOVES EQU $1B - -BATTLE_GETUNOWNLETTER EQU $2D +; predefs +PREDEF_FILLPP EQU $05 +PREDEF_FILLSTATS EQU $0C +PREDEF_FILLMOVES EQU $1B +PREDEF_GETUNOWNLETTER EQU $2D -; vars +; script vars NUM_VARS EQU $1b VAR_MOVEMENT EQU $08 @@ -3283,6 +3287,9 @@ MOVE_ACC EQU 4 MOVE_PP EQU 5 MOVE_CHANCE EQU 6 +; base stats +BASE_STATS_LENGTH EQU 32 + ; stat constants NUM_STATS EQU 6 STAT_HP EQU 1 diff --git a/main.asm b/main.asm index 5d3daf667..52e51f2bd 100644 --- a/main.asm +++ b/main.asm @@ -1364,7 +1364,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 @@ -1878,7 +1930,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, [CurBattleSpecies] + cp EGG + jr z, .egg + +; Get base stats + dec a + ld bc, BASE_STATS_LENGTH + ld hl, BaseStats + call AddNTimes + ld de, CurBaseStats + ld bc, BASE_STATS_LENGTH + 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, [CurBattleSpecies] + 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 +2101,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 @@ -12501,53 +12621,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 [CurBattleSpecies], 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 +12722,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 +12999,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 +13023,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 +13144,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 +13162,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 +13186,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,$3fc8b - $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", $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 @@ -18124,6 +18556,9 @@ Dark: INCBIN "baserom.gbc",$50A28, $51424 - $50A28 + +BaseStats: + BulbasaurBaseStats: ; 0x51424 db BULBASAUR ; 001 diff --git a/wram.asm b/wram.asm index 6f8364a23..ffa0b6b6f 100644 --- a/wram.asm +++ b/wram.asm @@ -539,7 +539,7 @@ BattleScriptBufferLocLo: ; c6b2 BattleScriptBufferLocHi: ; c6b3 ds 1 - ds 24 + ds 25 PlayerStatLevels: ; c6cc ; 07 neutral