diff options
author | Rangi <remy.oukaour+rangi42@gmail.com> | 2020-07-07 18:50:58 -0400 |
---|---|---|
committer | Rangi <remy.oukaour+rangi42@gmail.com> | 2020-07-07 19:43:11 -0400 |
commit | bbf2f51a02b2544f1bef32a5868503b474ae2fef (patch) | |
tree | d73507228a57e4f3cece2fb93fe7df3a9439553f | |
parent | 51ac538c25f8c0a6d88101569a17f02d09855d31 (diff) |
Move all code out of home.asm into home/
This results in 64 home/*.asm files, comparable to pokecrystal's 57.
35 files changed, 1754 insertions, 1758 deletions
@@ -18,64 +18,16 @@ SECTION "Home", ROM0 INCLUDE "home/start.asm" INCLUDE "home/joypad.asm" -INCLUDE "data/maps/map_header_pointers.asm" -INCLUDE "home/overworld.asm" - -CheckForUserInterruption:: -; Return carry if Up+Select+B, Start or A are pressed in c frames. -; Used only in the intro and title screen. - call DelayFrame - - push bc - call JoypadLowSensitivity - pop bc - - ldh a, [hJoyHeld] - cp D_UP + SELECT + B_BUTTON - jr z, .input - - ldh a, [hJoy5] - and START | A_BUTTON - jr nz, .input - - dec c - jr nz, CheckForUserInterruption - - and a - ret - -.input - scf - ret -; function to load position data for destination warp when switching maps -; INPUT: -; a = ID of destination warp within destination map -LoadDestinationWarpPosition:: - ld b, a - ldh a, [hLoadedROMBank] - push af - ld a, [wPredefParentBank] - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ld a, b - add a - add a - ld c, a - ld b, 0 - add hl, bc - ld bc, 4 - ld de, wCurrentTileBlockMapViewPointer - call CopyData - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret +INCLUDE "data/maps/map_header_pointers.asm" +INCLUDE "home/overworld.asm" INCLUDE "home/pokemon.asm" INCLUDE "home/print_bcd.asm" INCLUDE "home/pics.asm" + INCLUDE "data/tilesets/collision_tile_ids.asm" + INCLUDE "home/copy2.asm" INCLUDE "home/text.asm" INCLUDE "home/vcopy.asm" @@ -85,1724 +37,51 @@ INCLUDE "home/fade.asm" INCLUDE "home/serial.asm" INCLUDE "home/timer.asm" INCLUDE "home/audio.asm" - -UpdateSprites:: - ld a, [wUpdateSpritesEnabled] - dec a - ret nz - ldh a, [hLoadedROMBank] - push af - ld a, BANK(_UpdateSprites) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call _UpdateSprites - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret +INCLUDE "home/update_sprites.asm" INCLUDE "data/items/marts.asm" + INCLUDE "home/overworld_text.asm" INCLUDE "home/uncompress.asm" - -ResetPlayerSpriteData:: - ld hl, wSpriteStateData1 - call ResetPlayerSpriteData_ClearSpriteData - ld hl, wSpriteStateData2 - call ResetPlayerSpriteData_ClearSpriteData - ld a, $1 - ld [wSpritePlayerStateData1PictureID], a - ld [wSpritePlayerStateData2ImageBaseOffset], a - ld hl, wSpritePlayerStateData1YPixels - ld [hl], $3c ; set Y screen pos - inc hl - inc hl - ld [hl], $40 ; set X screen pos - ret - -; overwrites sprite data with zeroes -ResetPlayerSpriteData_ClearSpriteData:: - ld bc, $10 - xor a - jp FillMemory - -FadeOutAudio:: - ld a, [wAudioFadeOutControl] - and a ; currently fading out audio? - jr nz, .fadingOut - ld a, [wd72c] - bit 1, a - ret nz - ld a, $77 - ldh [rNR50], a - ret -.fadingOut - ld a, [wAudioFadeOutCounter] - and a - jr z, .counterReachedZero - dec a - ld [wAudioFadeOutCounter], a - ret -.counterReachedZero - ld a, [wAudioFadeOutCounterReloadValue] - ld [wAudioFadeOutCounter], a - ldh a, [rNR50] - and a ; has the volume reached 0? - jr z, .fadeOutComplete - ld b, a - and $f - dec a - ld c, a - ld a, b - and $f0 - swap a - dec a - swap a - or c - ldh [rNR50], a - ret -.fadeOutComplete - ld a, [wAudioFadeOutControl] - ld b, a - xor a - ld [wAudioFadeOutControl], a - ld a, SFX_STOP_ALL_MUSIC - ld [wNewSoundID], a - call PlaySound - ld a, [wAudioSavedROMBank] - ld [wAudioROMBank], a - ld a, b - ld [wNewSoundID], a - jp PlaySound - +INCLUDE "home/reset_player_sprite.asm" +INCLUDE "home/fade_audio.asm" INCLUDE "home/text_script.asm" INCLUDE "home/start_menu.asm" - -; function to count how many bits are set in a string of bytes -; INPUT: -; hl = address of string of bytes -; b = length of string of bytes -; OUTPUT: -; [wNumSetBits] = number of set bits -CountSetBits:: - ld c, 0 -.loop - ld a, [hli] - ld e, a - ld d, 8 -.innerLoop ; count how many bits are set in the current byte - srl e - ld a, 0 - adc c - ld c, a - dec d - jr nz, .innerLoop - dec b - jr nz, .loop - ld a, c - ld [wNumSetBits], a - ret - -; subtracts the amount the player paid from their money -; OUTPUT: carry = 0(success) or 1(fail because there is not enough money) -SubtractAmountPaidFromMoney:: - farjp SubtractAmountPaidFromMoney_ - -; adds the amount the player sold to their money -AddAmountSoldToMoney:: - ld de, wPlayerMoney + 2 - ld hl, hMoney + 2 ; total price of items - ld c, 3 ; length of money in bytes - predef AddBCDPredef ; add total price to money - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID ; redraw money text box - ld a, SFX_PURCHASE - call PlaySoundWaitForCurrent - jp WaitForSoundToFinish - -; function to remove an item (in varying quantities) from the player's bag or PC box -; INPUT: -; HL = address of inventory (either wNumBagItems or wNumBoxItems) -; [wWhichPokemon] = index (within the inventory) of the item to remove -; [wItemQuantity] = quantity to remove -RemoveItemFromInventory:: - ldh a, [hLoadedROMBank] - push af - ld a, BANK(RemoveItemFromInventory_) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call RemoveItemFromInventory_ - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; function to add an item (in varying quantities) to the player's bag or PC box -; INPUT: -; HL = address of inventory (either wNumBagItems or wNumBoxItems) -; [wcf91] = item ID -; [wItemQuantity] = item quantity -; sets carry flag if successful, unsets carry flag if unsuccessful -AddItemToInventory:: - push bc - ldh a, [hLoadedROMBank] - push af - ld a, BANK(AddItemToInventory_) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call AddItemToInventory_ - pop bc - ld a, b - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - pop bc - ret - +INCLUDE "home/count_set_bits.asm" +INCLUDE "home/inventory.asm" INCLUDE "home/list_menu.asm" INCLUDE "home/names.asm" - -; reloads text box tile patterns, current map view, and tileset tile patterns -ReloadMapData:: - ldh a, [hLoadedROMBank] - push af - ld a, [wCurMap] - call SwitchToMapRomBank - call DisableLCD - call LoadTextBoxTilePatterns - call LoadCurrentMapView - call LoadTilesetTilePatternData - call EnableLCD - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; reloads tileset tile patterns -ReloadTilesetTilePatterns:: - ldh a, [hLoadedROMBank] - push af - ld a, [wCurMap] - call SwitchToMapRomBank - call DisableLCD - call LoadTilesetTilePatternData - call EnableLCD - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; shows the town map and lets the player choose a destination to fly to -ChooseFlyDestination:: - ld hl, wd72e - res 4, [hl] - farjp LoadTownMap_Fly - -; causes the text box to close without waiting for a button press after displaying text -DisableWaitingAfterTextDisplay:: - ld a, $01 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ret - -; uses an item -; UseItem is used with dummy items to perform certain other functions as well -; INPUT: -; [wcf91] = item ID -; OUTPUT: -; [wActionResultOrTookBattleTurn] = success -; 00: unsuccessful -; 01: successful -; 02: not able to be used right now, no extra menu displayed (only certain items use this) -UseItem:: - farjp UseItem_ - -; confirms the item toss and then tosses the item -; INPUT: -; hl = address of inventory (either wNumBagItems or wNumBoxItems) -; [wcf91] = item ID -; [wWhichPokemon] = index of item within inventory -; [wItemQuantity] = quantity to toss -; OUTPUT: -; clears carry flag if the item is tossed, sets carry flag if not -TossItem:: - ldh a, [hLoadedROMBank] - push af - ld a, BANK(TossItem_) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call TossItem_ - pop de - ld a, d - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; checks if an item is a key item -; INPUT: -; [wcf91] = item ID -; OUTPUT: -; [wIsKeyItem] = result -; 00: item is not key item -; 01: item is key item -IsKeyItem:: - push hl - push de - push bc - farcall IsKeyItem_ - pop bc - pop de - pop hl - ret - -; function to draw various text boxes -; INPUT: -; [wTextBoxID] = text box ID -; b, c = y, x cursor position (TWO_OPTION_MENU only) -DisplayTextBoxID:: - ldh a, [hLoadedROMBank] - push af - ld a, BANK(DisplayTextBoxID_) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call DisplayTextBoxID_ - pop bc - ld a, b - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; not zero if an NPC movement script is running, the player character is -; automatically stepping down from a door, or joypad states are being simulated -IsPlayerCharacterBeingControlledByGame:: - ld a, [wNPCMovementScriptPointerTableNum] - and a - ret nz - ld a, [wd736] - bit 1, a ; currently stepping down from door bit - ret nz - ld a, [wd730] - and $80 - ret - -RunNPCMovementScript:: - ld hl, wd736 - bit 0, [hl] - res 0, [hl] - jr nz, .playerStepOutFromDoor - ld a, [wNPCMovementScriptPointerTableNum] - and a - ret z - dec a - add a - ld d, 0 - ld e, a - ld hl, .NPCMovementScriptPointerTables - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ldh a, [hLoadedROMBank] - push af - ld a, [wNPCMovementScriptBank] - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ld a, [wNPCMovementScriptFunctionNum] - call CallFunctionInTable - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -.NPCMovementScriptPointerTables - dw PalletMovementScriptPointerTable - dw PewterMuseumGuyMovementScriptPointerTable - dw PewterGymGuyMovementScriptPointerTable -.playerStepOutFromDoor - farjp PlayerStepOutFromDoor - -EndNPCMovementScript:: - farjp _EndNPCMovementScript - -EmptyFunc2:: - ret - +INCLUDE "home/reload_tiles.asm" +INCLUDE "home/item.asm" +INCLUDE "home/textbox.asm" +INCLUDE "home/npc_movement.asm" INCLUDE "home/trainers.asm" - -; checks if the player's coordinates match an arrow movement tile's coordinates -; and if so, decodes the RLE movement data -; b = player Y -; c = player X -DecodeArrowMovementRLE:: - ld a, [hli] - cp $ff - ret z ; no match in the list - cp b - jr nz, .nextArrowMovementTileEntry1 - ld a, [hli] - cp c - jr nz, .nextArrowMovementTileEntry2 - ld a, [hli] - ld d, [hl] - ld e, a - ld hl, wSimulatedJoypadStatesEnd - call DecodeRLEList - dec a - ld [wSimulatedJoypadStatesIndex], a - ret -.nextArrowMovementTileEntry1 - inc hl -.nextArrowMovementTileEntry2 - inc hl - inc hl - jr DecodeArrowMovementRLE - -TextScript_ItemStoragePC:: - call SaveScreenTilesToBuffer2 - ld b, BANK(PlayerPC) - ld hl, PlayerPC - jr bankswitchAndContinue - -TextScript_BillsPC:: - call SaveScreenTilesToBuffer2 - ld b, BANK(BillsPC_) - ld hl, BillsPC_ - jr bankswitchAndContinue - -TextScript_GameCornerPrizeMenu:: -; XXX find a better name for this function -; special_F7 - ld b, BANK(CeladonPrizeMenu) - ld hl, CeladonPrizeMenu -bankswitchAndContinue:: - call Bankswitch - jp HoldTextDisplayOpen ; continue to main text-engine function - -TextScript_PokemonCenterPC:: - ld b, BANK(ActivatePC) - ld hl, ActivatePC - jr bankswitchAndContinue - -StartSimulatingJoypadStates:: - xor a - ld [wOverrideSimulatedJoypadStatesMask], a - ld [wSpritePlayerStateData2MovementByte1], a - ld hl, wd730 - set 7, [hl] - ret - -IsItemInBag:: -; given an item_id in b -; set zero flag if item isn't in player's bag -; else reset zero flag -; related to Pokémon Tower and ghosts - predef GetQuantityOfItemInBag - ld a, b - and a - ret - -DisplayPokedex:: - ld [wd11e], a - farjp _DisplayPokedex - -SetSpriteFacingDirectionAndDelay:: - call SetSpriteFacingDirection - ld c, 6 - jp DelayFrames - -SetSpriteFacingDirection:: - ld a, $9 - ldh [hSpriteDataOffset], a - call GetPointerWithinSpriteStateData1 - ldh a, [hSpriteFacingDirection] - ld [hl], a - ret - -SetSpriteImageIndexAfterSettingFacingDirection:: - ld de, -7 - add hl, de - ld [hl], a - ret - -; tests if the player's coordinates are in a specified array -; INPUT: -; hl = address of array -; OUTPUT: -; [wCoordIndex] = if there is match, the matching array index -; sets carry if the coordinates are in the array, clears carry if not -ArePlayerCoordsInArray:: - ld a, [wYCoord] - ld b, a - ld a, [wXCoord] - ld c, a - ; fallthrough - -CheckCoords:: - xor a - ld [wCoordIndex], a -.loop - ld a, [hli] - cp $ff ; reached terminator? - jr z, .notInArray - push hl - ld hl, wCoordIndex - inc [hl] - pop hl -.compareYCoord - cp b - jr z, .compareXCoord - inc hl - jr .loop -.compareXCoord - ld a, [hli] - cp c - jr nz, .loop -.inArray - scf - ret -.notInArray - and a - ret - -; tests if a boulder's coordinates are in a specified array -; INPUT: -; hl = address of array -; [hSpriteIndex] = index of boulder sprite -; OUTPUT: -; [wCoordIndex] = if there is match, the matching array index -; sets carry if the coordinates are in the array, clears carry if not -CheckBoulderCoords:: - push hl - ld hl, wSpritePlayerStateData2MapY - ldh a, [hSpriteIndex] - swap a - ld d, $0 - ld e, a - add hl, de - ld a, [hli] - sub $4 ; because sprite coordinates are offset by 4 - ld b, a - ld a, [hl] - sub $4 ; because sprite coordinates are offset by 4 - ld c, a - pop hl - jp CheckCoords - -GetPointerWithinSpriteStateData1:: - ld h, $c1 - jr _GetPointerWithinSpriteStateData - -GetPointerWithinSpriteStateData2:: - ld h, $c2 - -_GetPointerWithinSpriteStateData: - ldh a, [hSpriteDataOffset] - ld b, a - ldh a, [hSpriteIndex] - swap a - add b - ld l, a - ret - -; decodes a $ff-terminated RLEncoded list -; each entry is a pair of bytes <byte value> <repetitions> -; the final $ff will be replicated in the output list and a contains the number of bytes written -; de: input list -; hl: output list -DecodeRLEList:: - xor a - ld [wRLEByteCount], a ; count written bytes here -.listLoop - ld a, [de] - cp $ff - jr z, .endOfList - ldh [hRLEByteValue], a ; store byte value to be written - inc de - ld a, [de] - ld b, $0 - ld c, a ; number of bytes to be written - ld a, [wRLEByteCount] - add c - ld [wRLEByteCount], a ; update total number of written bytes - ldh a, [hRLEByteValue] - call FillMemory ; write a c-times to output - inc de - jr .listLoop -.endOfList - ld a, $ff - ld [hl], a ; write final $ff - ld a, [wRLEByteCount] - inc a ; include sentinel in counting - ret - -; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2] -SetSpriteMovementBytesToFE:: - push hl - call GetSpriteMovementByte1Pointer - ld [hl], $fe - call GetSpriteMovementByte2Pointer - ldh a, [hSpriteMovementByte2] - ld [hl], a - pop hl - ret - -; sets both movement bytes for sprite [hSpriteIndex] to $FF -SetSpriteMovementBytesToFF:: - push hl - call GetSpriteMovementByte1Pointer - ld [hl], $FF - call GetSpriteMovementByte2Pointer - ld [hl], $FF ; prevent person from walking? - pop hl - ret - -; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl -GetSpriteMovementByte1Pointer:: - ld h, $C2 - ldh a, [hSpriteIndex] - swap a - add 6 - ld l, a - ret - -; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl -GetSpriteMovementByte2Pointer:: - push de - ld hl, wMapSpriteData - ldh a, [hSpriteIndex] - dec a - add a - ld d, 0 - ld e, a - add hl, de - pop de - ret - -GetTrainerInformation:: - call GetTrainerName - ld a, [wLinkState] - and a - jr nz, .linkBattle - ld a, BANK(TrainerPicAndMoneyPointers) - call BankswitchHome - ld a, [wTrainerClass] - dec a - ld hl, TrainerPicAndMoneyPointers - ld bc, $5 - call AddNTimes - ld de, wTrainerPicPointer - ld a, [hli] - ld [de], a - inc de - ld a, [hli] - ld [de], a - ld de, wTrainerBaseMoney - ld a, [hli] - ld [de], a - inc de - ld a, [hli] - ld [de], a - jp BankswitchBack -.linkBattle - ld hl, wTrainerPicPointer - ld de, RedPicFront - ld [hl], e - inc hl - ld [hl], d - ret - -GetTrainerName:: - farjp GetTrainerName_ - -HasEnoughMoney:: -; Check if the player has at least as much -; money as the 3-byte BCD value at hMoney. - ld de, wPlayerMoney - ld hl, hMoney - ld c, 3 - jp StringCmp - -HasEnoughCoins:: -; Check if the player has at least as many -; coins as the 2-byte BCD value at hCoins. - ld de, wPlayerCoins - ld hl, hCoins - ld c, 2 - jp StringCmp - +INCLUDE "home/map_objects.asm" +INCLUDE "home/trainers2.asm" +INCLUDE "home/money.asm" INCLUDE "home/bankswitch.asm" INCLUDE "home/yes_no.asm" - -; calculates the difference |a-b|, setting carry flag if a<b -CalcDifference:: - sub b - ret nc - cpl - add $1 - scf - ret - -MoveSprite:: -; move the sprite [hSpriteIndex] with the movement pointed to by de -; actually only copies the movement data to wNPCMovementDirections for later - call SetSpriteMovementBytesToFF -MoveSprite_:: - push hl - push bc - call GetSpriteMovementByte1Pointer - xor a - ld [hl], a - ld hl, wNPCMovementDirections - ld c, 0 - -.loop - ld a, [de] - ld [hli], a - inc de - inc c - cp $FF ; have we reached the end of the movement data? - jr nz, .loop - - ld a, c - ld [wNPCNumScriptedSteps], a ; number of steps taken - - pop bc - ld hl, wd730 - set 0, [hl] - pop hl - xor a - ld [wOverrideSimulatedJoypadStatesMask], a - ld [wSimulatedJoypadStatesEnd], a - dec a - ld [wJoyIgnore], a - ld [wWastedByteCD3A], a - ret - -; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2] -DivideBytes:: - push hl - ld hl, hQuotient2 - xor a - ld [hld], a - ld a, [hld] - and a - jr z, .done - ld a, [hli] -.loop - sub [hl] - jr c, .done - inc hl - inc [hl] - dec hl - jr .loop -.done - pop hl - ret - -LoadFontTilePatterns:: - ldh a, [rLCDC] - bit 7, a ; is the LCD enabled? - jr nz, .on -.off - ld hl, FontGraphics - ld de, vFont - ld bc, FontGraphicsEnd - FontGraphics - ld a, BANK(FontGraphics) - jp FarCopyDataDouble ; if LCD is off, transfer all at once -.on - ld de, FontGraphics - ld hl, vFont - lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8 - jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank - -LoadTextBoxTilePatterns:: - ldh a, [rLCDC] - bit 7, a ; is the LCD enabled? - jr nz, .on -.off - ld hl, TextBoxGraphics - ld de, vChars2 tile $60 - ld bc, TextBoxGraphicsEnd - TextBoxGraphics - ld a, BANK(TextBoxGraphics) - jp FarCopyData2 ; if LCD is off, transfer all at once -.on - ld de, TextBoxGraphics - ld hl, vChars2 tile $60 - lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10 - jp CopyVideoData ; if LCD is on, transfer during V-blank - -LoadHpBarAndStatusTilePatterns:: - ldh a, [rLCDC] - bit 7, a ; is the LCD enabled? - jr nz, .on -.off - ld hl, HpBarAndStatusGraphics - ld de, vChars2 tile $62 - ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics - ld a, BANK(HpBarAndStatusGraphics) - jp FarCopyData2 ; if LCD is off, transfer all at once -.on - ld de, HpBarAndStatusGraphics - ld hl, vChars2 tile $62 - lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10 - jp CopyVideoData ; if LCD is on, transfer during V-blank - -FillMemory:: -; Fill bc bytes at hl with a. - push de - ld d, a -.loop - ld a, d - ld [hli], a - dec bc - ld a, b - or c - jr nz, .loop - pop de - ret - -UncompressSpriteFromDE:: -; Decompress pic at a:de. - ld hl, wSpriteInputPtr - ld [hl], e - inc hl - ld [hl], d - jp UncompressSpriteData - -SaveScreenTilesToBuffer2:: - hlcoord 0, 0 - ld de, wTileMapBackup2 - ld bc, SCREEN_WIDTH * SCREEN_HEIGHT - call CopyData - ret - -LoadScreenTilesFromBuffer2:: - call LoadScreenTilesFromBuffer2DisableBGTransfer - ld a, 1 - ldh [hAutoBGTransferEnabled], a - ret - -; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled -LoadScreenTilesFromBuffer2DisableBGTransfer:: - xor a - ldh [hAutoBGTransferEnabled], a - ld hl, wTileMapBackup2 - decoord 0, 0 - ld bc, SCREEN_WIDTH * SCREEN_HEIGHT - call CopyData - ret - -SaveScreenTilesToBuffer1:: - hlcoord 0, 0 - ld de, wTileMapBackup - ld bc, SCREEN_WIDTH * SCREEN_HEIGHT - jp CopyData - -LoadScreenTilesFromBuffer1:: - xor a - ldh [hAutoBGTransferEnabled], a - ld hl, wTileMapBackup - decoord 0, 0 - ld bc, SCREEN_WIDTH * SCREEN_HEIGHT - call CopyData - ld a, 1 - ldh [hAutoBGTransferEnabled], a - ret - -DelayFrames:: -; wait c frames - call DelayFrame - dec c - jr nz, DelayFrames - ret - -PlaySoundWaitForCurrent:: - push af - call WaitForSoundToFinish - pop af - jp PlaySound - -; Wait for sound to finish playing -WaitForSoundToFinish:: - ld a, [wLowHealthAlarm] - and $80 - ret nz - push hl -.waitLoop - ld hl, wChannelSoundIDs + Ch5 - xor a - or [hl] - inc hl - or [hl] - inc hl - inc hl - or [hl] - jr nz, .waitLoop - pop hl - ret - +INCLUDE "home/pathfinding.asm" +INCLUDE "home/load_font.asm" +INCLUDE "home/tilemap.asm" +INCLUDE "home/delay.asm" INCLUDE "home/names2.asm" - -GetItemPrice:: -; Stores item's price as BCD at hItemPrice (3 bytes) -; Input: [wcf91] = item id - ldh a, [hLoadedROMBank] - push af - ld a, [wListMenuID] - cp MOVESLISTMENU - ld a, BANK(ItemPrices) - jr nz, .ok - ld a, $f ; hardcoded Bank -.ok - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ld hl, wItemPrices - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wcf91] ; a contains item id - cp HM01 - jr nc, .getTMPrice - ld bc, $3 -.loop - add hl, bc - dec a - jr nz, .loop - dec hl - ld a, [hld] - ldh [hItemPrice + 2], a - ld a, [hld] - ldh [hItemPrice + 1], a - ld a, [hl] - ldh [hItemPrice], a - jr .done -.getTMPrice - ld a, BANK(GetMachinePrice) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call GetMachinePrice -.done - ld de, hItemPrice - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; copies a string from [de] to [wcf4b] -CopyStringToCF4B:: - ld hl, wcf4b - ; fall through - -; copies a string from [de] to [hl] -CopyString:: - ld a, [de] - inc de - ld [hli], a - cp "@" - jr nz, CopyString - ret - -; this function is used when lower button sensitivity is wanted (e.g. menus) -; OUTPUT: [hJoy5] = pressed buttons in usual format -; there are two flags that control its functionality, [hJoy6] and [hJoy7] -; there are essentially three modes of operation -; 1. Get newly pressed buttons only -; ([hJoy7] == 0, [hJoy6] == any) -; Just copies [hJoyPressed] to [hJoy5]. -; 2. Get currently pressed buttons at low sample rate with delay -; ([hJoy7] == 1, [hJoy6] != 0) -; If the user holds down buttons for more than half a second, -; report buttons as being pressed up to 12 times per second thereafter. -; If the user holds down buttons for less than half a second, -; report only one button press. -; 3. Same as 2, but report no buttons as pressed if A or B is held down. -; ([hJoy7] == 1, [hJoy6] == 0) -JoypadLowSensitivity:: - call Joypad - ldh a, [hJoy7] ; flag - and a ; get all currently pressed buttons or only newly pressed buttons? - ldh a, [hJoyPressed] ; newly pressed buttons - jr z, .storeButtonState - ldh a, [hJoyHeld] ; all currently pressed buttons -.storeButtonState - ldh [hJoy5], a - ldh a, [hJoyPressed] ; newly pressed buttons - and a ; have any buttons been newly pressed since last check? - jr z, .noNewlyPressedButtons -.newlyPressedButtons - ld a, 30 ; half a second delay - ldh [hFrameCounter], a - ret -.noNewlyPressedButtons - ldh a, [hFrameCounter] - and a ; is the delay over? - jr z, .delayOver -.delayNotOver - xor a - ldh [hJoy5], a ; report no buttons as pressed - ret -.delayOver -; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed - ldh a, [hJoyHeld] - and A_BUTTON | B_BUTTON - jr z, .setShortDelay - ldh a, [hJoy6] ; flag - and a - jr nz, .setShortDelay - xor a - ldh [hJoy5], a -.setShortDelay - ld a, 5 ; 1/12 of a second delay - ldh [hFrameCounter], a - ret - -WaitForTextScrollButtonPress:: - ldh a, [hDownArrowBlinkCount1] - push af - ldh a, [hDownArrowBlinkCount2] - push af - xor a - ldh [hDownArrowBlinkCount1], a - ld a, $6 - ldh [hDownArrowBlinkCount2], a -.loop - push hl - ld a, [wTownMapSpriteBlinkingEnabled] - and a - jr z, .skipAnimation - call TownMapSpriteBlinkingAnimation -.skipAnimation - hlcoord 18, 16 - call HandleDownArrowBlinkTiming - pop hl - call JoypadLowSensitivity - predef CableClub_Run - ldh a, [hJoy5] - and A_BUTTON | B_BUTTON - jr z, .loop - pop af - ldh [hDownArrowBlinkCount2], a - pop af - ldh [hDownArrowBlinkCount1], a - ret - -; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect -ManualTextScroll:: - ld a, [wLinkState] - cp LINK_STATE_BATTLING - jr z, .inLinkBattle - call WaitForTextScrollButtonPress - ld a, SFX_PRESS_AB - jp PlaySound -.inLinkBattle - ld c, 65 - jp DelayFrames - -; function to do multiplication -; all values are big endian -; INPUT -; FF96-FF98 = multiplicand -; FF99 = multiplier -; OUTPUT -; FF95-FF98 = product -Multiply:: - push hl - push bc - callfar _Multiply - pop bc - pop hl - ret - -; function to do division -; all values are big endian -; INPUT -; FF95-FF98 = dividend -; FF99 = divisor -; b = number of bytes in the dividend (starting from FF95) -; OUTPUT -; FF95-FF98 = quotient -; FF99 = remainder -Divide:: - push hl - push de - push bc - ldh a, [hLoadedROMBank] - push af - ld a, BANK(_Divide) - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - call _Divide - pop af - ldh [hLoadedROMBank], a - ld [MBC1RomBank], a - pop bc - pop de - pop hl - ret - -; This function is used to wait a short period after printing a letter to the -; screen unless the player presses the A/B button or the delay is turned off -; through the [wd730] or [wLetterPrintingDelayFlags] flags. -PrintLetterDelay:: - ld a, [wd730] - bit 6, a - ret nz - ld a, [wLetterPrintingDelayFlags] - bit 1, a - ret z - push hl - push de - push bc - ld a, [wLetterPrintingDelayFlags] - bit 0, a - jr z, .waitOneFrame - ld a, [wOptions] - and $f - ldh [hFrameCounter], a - jr .checkButtons -.waitOneFrame - ld a, 1 - ldh [hFrameCounter], a -.checkButtons - call Joypad - ldh a, [hJoyHeld] -.checkAButton - bit 0, a ; is the A button pressed? - jr z, .checkBButton - jr .endWait -.checkBButton - bit 1, a ; is the B button pressed? - jr z, .buttonsNotPressed -.endWait - call DelayFrame - jr .done -.buttonsNotPressed ; if neither A nor B is pressed - ldh a, [hFrameCounter] - and a - jr nz, .checkButtons -.done - pop bc - pop de - pop hl - ret - -; Copies [hl, bc) to [de, de + bc - hl). -; In other words, the source data is from hl up to but not including bc, -; and the destination is de. -CopyDataUntil:: - ld a, [hli] - ld [de], a - inc de - ld a, h - cp b - jr nz, CopyDataUntil - ld a, l - cp c - jr nz, CopyDataUntil - ret - +INCLUDE "home/item_price.asm" +INCLUDE "home/copy_string.asm" +INCLUDE "home/joypad2.asm" +INCLUDE "home/math.asm" +INCLUDE "home/print_text.asm" INCLUDE "home/move_mon.asm" - -; skips a text entries, each of size NAME_LENGTH (like trainer name, OT name, rival name, ...) -; hl: base pointer, will be incremented by NAME_LENGTH * a -SkipFixedLengthTextEntries:: - and a - ret z - ld bc, NAME_LENGTH -.skipLoop - add hl, bc - dec a - jr nz, .skipLoop - ret - -AddNTimes:: -; add bc to hl a times - and a - ret z -.loop - add hl, bc - dec a - jr nz, .loop - ret - -; Compare strings, c bytes in length, at de and hl. -; Often used to compare big endian numbers in battle calculations. -StringCmp:: - ld a, [de] - cp [hl] - ret nz - inc de - inc hl - dec c - jr nz, StringCmp - ret - -; INPUT: -; a = oam block index (each block is 4 oam entries) -; b = Y coordinate of upper left corner of sprite -; c = X coordinate of upper left corner of sprite -; de = base address of 4 tile number and attribute pairs -WriteOAMBlock:: - ld h, HIGH(wOAMBuffer) - swap a ; multiply by 16 - ld l, a - call .writeOneEntry ; upper left - push bc - ld a, 8 - add c - ld c, a - call .writeOneEntry ; upper right - pop bc - ld a, 8 - add b - ld b, a - call .writeOneEntry ; lower left - ld a, 8 - add c - ld c, a - ; lower right -.writeOneEntry - ld [hl], b ; Y coordinate - inc hl - ld [hl], c ; X coordinate - inc hl - ld a, [de] ; tile number - inc de - ld [hli], a - ld a, [de] ; attribute - inc de - ld [hli], a - ret - -HandleMenuInput:: - xor a - ld [wPartyMenuAnimMonEnabled], a - -HandleMenuInput_:: - ldh a, [hDownArrowBlinkCount1] - push af - ldh a, [hDownArrowBlinkCount2] - push af ; save existing values on stack - xor a - ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1 - ld a, 6 - ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2 -.loop1 - xor a - ld [wAnimCounter], a ; counter for pokemon shaking animation - call PlaceMenuCursor - call Delay3 -.loop2 - push hl - ld a, [wPartyMenuAnimMonEnabled] - and a ; is it a pokemon selection menu? - jr z, .getJoypadState - farcall AnimatePartyMon ; shake mini sprite of selected pokemon -.getJoypadState - pop hl - call JoypadLowSensitivity - ldh a, [hJoy5] - and a ; was a key pressed? - jr nz, .keyPressed - push hl - hlcoord 18, 11 ; coordinates of blinking down arrow in some menus - call HandleDownArrowBlinkTiming ; blink down arrow (if any) - pop hl - ld a, [wMenuJoypadPollCount] - dec a - jr z, .giveUpWaiting - jr .loop2 -.giveUpWaiting -; if a key wasn't pressed within the specified number of checks - pop af - ldh [hDownArrowBlinkCount2], a - pop af - ldh [hDownArrowBlinkCount1], a ; restore previous values - xor a - ld [wMenuWrappingEnabled], a ; disable menu wrapping - ret -.keyPressed - xor a - ld [wCheckFor180DegreeTurn], a - ldh a, [hJoy5] - ld b, a - bit 6, a ; pressed Up key? - jr z, .checkIfDownPressed -.upPressed - ld a, [wCurrentMenuItem] ; selected menu item - and a ; already at the top of the menu? - jr z, .alreadyAtTop -.notAtTop - dec a - ld [wCurrentMenuItem], a ; move selected menu item up one space - jr .checkOtherKeys -.alreadyAtTop - ld a, [wMenuWrappingEnabled] - and a ; is wrapping around enabled? - jr z, .noWrappingAround - ld a, [wMaxMenuItem] - ld [wCurrentMenuItem], a ; wrap to the bottom of the menu - jr .checkOtherKeys -.checkIfDownPressed - bit 7, a - jr z, .checkOtherKeys -.downPressed - ld a, [wCurrentMenuItem] - inc a - ld c, a - ld a, [wMaxMenuItem] - cp c - jr nc, .notAtBottom -.alreadyAtBottom - ld a, [wMenuWrappingEnabled] - and a ; is wrapping around enabled? - jr z, .noWrappingAround - ld c, $00 ; wrap from bottom to top -.notAtBottom - ld a, c - ld [wCurrentMenuItem], a -.checkOtherKeys - ld a, [wMenuWatchedKeys] - and b ; does the menu care about any of the pressed keys? - jp z, .loop1 -.checkIfAButtonOrBButtonPressed - ldh a, [hJoy5] - and A_BUTTON | B_BUTTON - jr z, .skipPlayingSound -.AButtonOrBButtonPressed - push hl - ld hl, wFlags_0xcd60 - bit 5, [hl] - pop hl - jr nz, .skipPlayingSound - ld a, SFX_PRESS_AB - call PlaySound -.skipPlayingSound - pop af - ldh [hDownArrowBlinkCount2], a - pop af - ldh [hDownArrowBlinkCount1], a ; restore previous values - xor a - ld [wMenuWrappingEnabled], a ; disable menu wrapping - ldh a, [hJoy5] - ret -.noWrappingAround - ld a, [wMenuWatchMovingOutOfBounds] - and a ; should we return if the user tried to go past the top or bottom? - jr z, .checkOtherKeys - jr .checkIfAButtonOrBButtonPressed - -PlaceMenuCursor:: - ld a, [wTopMenuItemY] - and a ; is the y coordinate 0? - jr z, .adjustForXCoord - hlcoord 0, 0 - ld bc, SCREEN_WIDTH -.topMenuItemLoop - add hl, bc - dec a - jr nz, .topMenuItemLoop -.adjustForXCoord - ld a, [wTopMenuItemX] - ld b, 0 - ld c, a - add hl, bc - push hl - ld a, [wLastMenuItem] - and a ; was the previous menu id 0? - jr z, .checkForArrow1 - push af - ldh a, [hFlagsFFF6] - bit 1, a ; is the menu double spaced? - jr z, .doubleSpaced1 - ld bc, 20 - jr .getOldMenuItemScreenPosition -.doubleSpaced1 - ld bc, 40 -.getOldMenuItemScreenPosition - pop af -.oldMenuItemLoop - add hl, bc - dec a - jr nz, .oldMenuItemLoop -.checkForArrow1 - ld a, [hl] - cp "▶" ; was an arrow next to the previously selected menu item? - jr nz, .skipClearingArrow -.clearArrow - ld a, [wTileBehindCursor] - ld [hl], a -.skipClearingArrow - pop hl - ld a, [wCurrentMenuItem] - and a - jr z, .checkForArrow2 - push af - ldh a, [hFlagsFFF6] - bit 1, a ; is the menu double spaced? - jr z, .doubleSpaced2 - ld bc, 20 - jr .getCurrentMenuItemScreenPosition -.doubleSpaced2 - ld bc, 40 -.getCurrentMenuItemScreenPosition - pop af -.currentMenuItemLoop - add hl, bc - dec a - jr nz, .currentMenuItemLoop -.checkForArrow2 - ld a, [hl] - cp "▶" ; has the right arrow already been placed? - jr z, .skipSavingTile ; if so, don't lose the saved tile - ld [wTileBehindCursor], a ; save tile before overwriting with right arrow -.skipSavingTile - ld a, "▶" ; place right arrow - ld [hl], a - ld a, l - ld [wMenuCursorLocation], a - ld a, h - ld [wMenuCursorLocation + 1], a - ld a, [wCurrentMenuItem] - ld [wLastMenuItem], a - ret - -; This is used to mark a menu cursor other than the one currently being -; manipulated. In the case of submenus, this is used to show the location of -; the menu cursor in the parent menu. In the case of swapping items in list, -; this is used to mark the item that was first chosen to be swapped. -PlaceUnfilledArrowMenuCursor:: - ld b, a - ld a, [wMenuCursorLocation] - ld l, a - ld a, [wMenuCursorLocation + 1] - ld h, a - ld [hl], $ec ; outline of right arrow - ld a, b - ret - -; Replaces the menu cursor with a blank space. -EraseMenuCursor:: - ld a, [wMenuCursorLocation] - ld l, a - ld a, [wMenuCursorLocation + 1] - ld h, a - ld [hl], " " - ret - -; This toggles a blinking down arrow at hl on and off after a delay has passed. -; This is often called even when no blinking is occurring. -; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0. -; The effect is that if the tile at hl is initialized with a down arrow, -; this function will toggle that down arrow on and off, but if the tile isn't -; initialized with a down arrow, this function does nothing. -; That allows this to be called without worrying about if a down arrow should -; be blinking. -HandleDownArrowBlinkTiming:: - ld a, [hl] - ld b, a - ld a, "▼" - cp b - jr nz, .downArrowOff -.downArrowOn - ldh a, [hDownArrowBlinkCount1] - dec a - ldh [hDownArrowBlinkCount1], a - ret nz - ldh a, [hDownArrowBlinkCount2] - dec a - ldh [hDownArrowBlinkCount2], a - ret nz - ld a, " " - ld [hl], a - ld a, $ff - ldh [hDownArrowBlinkCount1], a - ld a, $06 - ldh [hDownArrowBlinkCount2], a - ret -.downArrowOff - ldh a, [hDownArrowBlinkCount1] - and a - ret z - dec a - ldh [hDownArrowBlinkCount1], a - ret nz - dec a - ldh [hDownArrowBlinkCount1], a - ldh a, [hDownArrowBlinkCount2] - dec a - ldh [hDownArrowBlinkCount2], a - ret nz - ld a, $06 - ldh [hDownArrowBlinkCount2], a - ld a, "▼" - ld [hl], a - ret - -; The following code either enables or disables the automatic drawing of -; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait -; for a button press after displaying text (unless [wEnteringCableClub] is set). - -EnableAutoTextBoxDrawing:: - xor a - jr AutoTextBoxDrawingCommon - -DisableAutoTextBoxDrawing:: - ld a, $01 - -AutoTextBoxDrawingCommon:: - ld [wAutoTextBoxDrawingControl], a - xor a - ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press - ret - -PrintText:: -; Print text hl at (1, 14). - push hl - ld a, MESSAGE_BOX - ld [wTextBoxID], a - call DisplayTextBoxID - call UpdateSprites - call Delay3 - pop hl -PrintText_NoCreatingTextBox:: - bccoord 1, 14 - jp TextCommandProcessor - +INCLUDE "home/array.asm" +INCLUDE "home/compare.asm" +INCLUDE "home/oam.asm" +INCLUDE "home/window.asm" INCLUDE "home/print_num.asm" - -CallFunctionInTable:: -; Call function a in jumptable hl. -; de is not preserved. - push hl - push de - push bc - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ld de, .returnAddress - push de - jp hl -.returnAddress - pop bc - pop de - pop hl - ret - -IsInArray:: -; Search an array at hl for the value in a. -; Entry size is de bytes. -; Return count b and carry if found. - ld b, 0 - -IsInRestOfArray:: - ld c, a -.loop - ld a, [hl] - cp -1 - jr z, .notfound - cp c - jr z, .found - inc b - add hl, de - jr .loop - -.notfound - and a - ret - -.found - scf - ret - -RestoreScreenTilesAndReloadTilePatterns:: - call ClearSprites - ld a, $1 - ld [wUpdateSpritesEnabled], a - call ReloadMapSpriteTilePatterns - call LoadScreenTilesFromBuffer2 - call LoadTextBoxTilePatterns - call RunDefaultPaletteCommand - jr Delay3 - -GBPalWhiteOutWithDelay3:: - call GBPalWhiteOut - -Delay3:: -; The bg map is updated each frame in thirds. -; Wait three frames to let the bg map fully update. - ld c, 3 - jp DelayFrames - -GBPalNormal:: -; Reset BGP and OBP0. - ld a, %11100100 ; 3210 - ldh [rBGP], a - ld a, %11010000 ; 3100 - ldh [rOBP0], a - ret - -GBPalWhiteOut:: -; White out all palettes. - xor a - ldh [rBGP], a - ldh [rOBP0], a - ldh [rOBP1], a - ret - -RunDefaultPaletteCommand:: - ld b, SET_PAL_DEFAULT -RunPaletteCommand:: - ld a, [wOnSGB] - and a - ret z - predef_jump _RunPaletteCommand - -GetHealthBarColor:: -; Return at hl the palette of -; an HP bar e pixels long. - ld a, e - cp 27 - ld d, 0 ; green - jr nc, .gotColor - cp 10 - inc d ; yellow - jr nc, .gotColor - inc d ; red -.gotColor - ld [hl], d - ret - -; Copy the current map's sprites' tile patterns to VRAM again after they have -; been overwritten by other tile patterns. -ReloadMapSpriteTilePatterns:: - ld hl, wFontLoaded - ld a, [hl] - push af - res 0, [hl] - push hl - xor a - ld [wSpriteSetID], a - call DisableLCD - farcall InitMapSprites - call EnableLCD - pop hl - pop af - ld [hl], a - call LoadPlayerSpriteGraphics - call LoadFontTilePatterns - jp UpdateSprites - -GiveItem:: -; Give player quantity c of item b, -; and copy the item's name to wcf4b. -; Return carry on success. - ld a, b - ld [wd11e], a - ld [wcf91], a - ld a, c - ld [wItemQuantity], a - ld hl, wNumBagItems - call AddItemToInventory - ret nc - call GetItemName - call CopyStringToCF4B - scf - ret - -GivePokemon:: -; Give the player monster b at level c. - ld a, b - ld [wcf91], a - ld a, c - ld [wCurEnemyLVL], a - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - farjp _GivePokemon - -Random:: -; Return a random number in a. -; For battles, use BattleRandom. - push hl - push de - push bc - farcall Random_ - ldh a, [hRandomAdd] - pop bc - pop de - pop hl - ret - +INCLUDE "home/array2.asm" +INCLUDE "home/palettes.asm" +INCLUDE "home/reload_sprites.asm" +INCLUDE "home/give.asm" +INCLUDE "home/random.asm" INCLUDE "home/predef.asm" - -UpdateCinnabarGymGateTileBlocks:: - farjp UpdateCinnabarGymGateTileBlocks_ - -CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: - ldh a, [hLoadedROMBank] - push af - ldh a, [hJoyHeld] - bit 0, a ; A button - jr z, .nothingFound -; A button is pressed - ld a, BANK(CheckForHiddenObject) - ld [MBC1RomBank], a - ldh [hLoadedROMBank], a - call CheckForHiddenObject - ldh a, [hDidntFindAnyHiddenObject] - and a - jr nz, .hiddenObjectNotFound - ld a, [wHiddenObjectFunctionRomBank] - ld [MBC1RomBank], a - ldh [hLoadedROMBank], a - ld de, .returnAddress - push de - jp hl -.returnAddress - xor a - jr .done -.hiddenObjectNotFound - farcall PrintBookshelfText - ldh a, [hFFDB] - and a - jr z, .done -.nothingFound - ld a, $ff -.done - ldh [hItemAlreadyFound], a - pop af - ld [MBC1RomBank], a - ldh [hLoadedROMBank], a - ret - -PrintPredefTextID:: - ldh [hSpriteIndexOrTextID], a - ld hl, TextPredefs - call SetMapTextPointer - ld hl, wTextPredefFlag - set 0, [hl] - call DisplayTextID - -RestoreMapTextPointer:: - ld hl, wMapTextPtr - ldh a, [hSavedMapTextPtr] - ld [hli], a - ldh a, [hSavedMapTextPtr + 1] - ld [hl], a - ret - -SetMapTextPointer:: - ld a, [wMapTextPtr] - ldh [hSavedMapTextPtr], a - ld a, [wMapTextPtr + 1] - ldh [hSavedMapTextPtr + 1], a - ld a, l - ld [wMapTextPtr], a - ld a, h - ld [wMapTextPtr + 1], a - ret - -INCLUDE "data/text_predef_pointers.asm" +INCLUDE "home/hidden_objects.asm" +INCLUDE "home/predef_text.asm" diff --git a/home/array.asm b/home/array.asm new file mode 100644 index 00000000..256c58e1 --- /dev/null +++ b/home/array.asm @@ -0,0 +1,21 @@ +; skips a text entries, each of size NAME_LENGTH (like trainer name, OT name, rival name, ...) +; hl: base pointer, will be incremented by NAME_LENGTH * a +SkipFixedLengthTextEntries:: + and a + ret z + ld bc, NAME_LENGTH +.skipLoop + add hl, bc + dec a + jr nz, .skipLoop + ret + +AddNTimes:: +; add bc to hl a times + and a + ret z +.loop + add hl, bc + dec a + jr nz, .loop + ret diff --git a/home/array2.asm b/home/array2.asm new file mode 100644 index 00000000..f4ed8389 --- /dev/null +++ b/home/array2.asm @@ -0,0 +1,47 @@ +CallFunctionInTable:: +; Call function a in jumptable hl. +; de is not preserved. + push hl + push de + push bc + add a + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .returnAddress + push de + jp hl +.returnAddress + pop bc + pop de + pop hl + ret + +IsInArray:: +; Search an array at hl for the value in a. +; Entry size is de bytes. +; Return count b and carry if found. + ld b, 0 + +IsInRestOfArray:: + ld c, a +.loop + ld a, [hl] + cp -1 + jr z, .notfound + cp c + jr z, .found + inc b + add hl, de + jr .loop + +.notfound + and a + ret + +.found + scf + ret diff --git a/home/compare.asm b/home/compare.asm new file mode 100644 index 00000000..e2da7857 --- /dev/null +++ b/home/compare.asm @@ -0,0 +1,11 @@ +; Compare strings, c bytes in length, at de and hl. +; Often used to compare big endian numbers in battle calculations. +StringCmp:: + ld a, [de] + cp [hl] + ret nz + inc de + inc hl + dec c + jr nz, StringCmp + ret diff --git a/home/copy_string.asm b/home/copy_string.asm new file mode 100644 index 00000000..7f86e501 --- /dev/null +++ b/home/copy_string.asm @@ -0,0 +1,13 @@ +; copies a string from [de] to [wcf4b] +CopyStringToCF4B:: + ld hl, wcf4b + ; fall through + +; copies a string from [de] to [hl] +CopyString:: + ld a, [de] + inc de + ld [hli], a + cp "@" + jr nz, CopyString + ret diff --git a/home/count_set_bits.asm b/home/count_set_bits.asm new file mode 100644 index 00000000..73f7fa9c --- /dev/null +++ b/home/count_set_bits.asm @@ -0,0 +1,24 @@ +; function to count how many bits are set in a string of bytes +; INPUT: +; hl = address of string of bytes +; b = length of string of bytes +; OUTPUT: +; [wNumSetBits] = number of set bits +CountSetBits:: + ld c, 0 +.loop + ld a, [hli] + ld e, a + ld d, 8 +.innerLoop ; count how many bits are set in the current byte + srl e + ld a, 0 + adc c + ld c, a + dec d + jr nz, .innerLoop + dec b + jr nz, .loop + ld a, c + ld [wNumSetBits], a + ret diff --git a/home/delay.asm b/home/delay.asm new file mode 100644 index 00000000..850b23e9 --- /dev/null +++ b/home/delay.asm @@ -0,0 +1,31 @@ +DelayFrames:: +; wait c frames + call DelayFrame + dec c + jr nz, DelayFrames + ret + +PlaySoundWaitForCurrent:: + push af + call WaitForSoundToFinish + pop af + jp PlaySound + +; Wait for sound to finish playing +WaitForSoundToFinish:: + ld a, [wLowHealthAlarm] + and $80 + ret nz + push hl +.waitLoop + ld hl, wChannelSoundIDs + Ch5 + xor a + or [hl] + inc hl + or [hl] + inc hl + inc hl + or [hl] + jr nz, .waitLoop + pop hl + ret diff --git a/home/fade_audio.asm b/home/fade_audio.asm new file mode 100644 index 00000000..4ad2607d --- /dev/null +++ b/home/fade_audio.asm @@ -0,0 +1,48 @@ +FadeOutAudio:: + ld a, [wAudioFadeOutControl] + and a ; currently fading out audio? + jr nz, .fadingOut + ld a, [wd72c] + bit 1, a + ret nz + ld a, $77 + ldh [rNR50], a + ret +.fadingOut + ld a, [wAudioFadeOutCounter] + and a + jr z, .counterReachedZero + dec a + ld [wAudioFadeOutCounter], a + ret +.counterReachedZero + ld a, [wAudioFadeOutCounterReloadValue] + ld [wAudioFadeOutCounter], a + ldh a, [rNR50] + and a ; has the volume reached 0? + jr z, .fadeOutComplete + ld b, a + and $f + dec a + ld c, a + ld a, b + and $f0 + swap a + dec a + swap a + or c + ldh [rNR50], a + ret +.fadeOutComplete + ld a, [wAudioFadeOutControl] + ld b, a + xor a + ld [wAudioFadeOutControl], a + ld a, SFX_STOP_ALL_MUSIC + ld [wNewSoundID], a + call PlaySound + ld a, [wAudioSavedROMBank] + ld [wAudioROMBank], a + ld a, b + ld [wNewSoundID], a + jp PlaySound diff --git a/home/give.asm b/home/give.asm new file mode 100644 index 00000000..cbfd0310 --- /dev/null +++ b/home/give.asm @@ -0,0 +1,26 @@ +GiveItem:: +; Give player quantity c of item b, +; and copy the item's name to wcf4b. +; Return carry on success. + ld a, b + ld [wd11e], a + ld [wcf91], a + ld a, c + ld [wItemQuantity], a + ld hl, wNumBagItems + call AddItemToInventory + ret nc + call GetItemName + call CopyStringToCF4B + scf + ret + +GivePokemon:: +; Give the player monster b at level c. + ld a, b + ld [wcf91], a + ld a, c + ld [wCurEnemyLVL], a + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + farjp _GivePokemon diff --git a/home/hidden_objects.asm b/home/hidden_objects.asm new file mode 100644 index 00000000..eccf1c8f --- /dev/null +++ b/home/hidden_objects.asm @@ -0,0 +1,39 @@ +UpdateCinnabarGymGateTileBlocks:: + farjp UpdateCinnabarGymGateTileBlocks_ + +CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: + ldh a, [hLoadedROMBank] + push af + ldh a, [hJoyHeld] + bit 0, a ; A button + jr z, .nothingFound +; A button is pressed + ld a, BANK(CheckForHiddenObject) + ld [MBC1RomBank], a + ldh [hLoadedROMBank], a + call CheckForHiddenObject + ldh a, [hDidntFindAnyHiddenObject] + and a + jr nz, .hiddenObjectNotFound + ld a, [wHiddenObjectFunctionRomBank] + ld [MBC1RomBank], a + ldh [hLoadedROMBank], a + ld de, .returnAddress + push de + jp hl +.returnAddress + xor a + jr .done +.hiddenObjectNotFound + farcall PrintBookshelfText + ldh a, [hFFDB] + and a + jr z, .done +.nothingFound + ld a, $ff +.done + ldh [hItemAlreadyFound], a + pop af + ld [MBC1RomBank], a + ldh [hLoadedROMBank], a + ret diff --git a/home/inventory.asm b/home/inventory.asm new file mode 100644 index 00000000..ebaa4047 --- /dev/null +++ b/home/inventory.asm @@ -0,0 +1,55 @@ +; subtracts the amount the player paid from their money +; OUTPUT: carry = 0(success) or 1(fail because there is not enough money) +SubtractAmountPaidFromMoney:: + farjp SubtractAmountPaidFromMoney_ + +; adds the amount the player sold to their money +AddAmountSoldToMoney:: + ld de, wPlayerMoney + 2 + ld hl, hMoney + 2 ; total price of items + ld c, 3 ; length of money in bytes + predef AddBCDPredef ; add total price to money + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID ; redraw money text box + ld a, SFX_PURCHASE + call PlaySoundWaitForCurrent + jp WaitForSoundToFinish + +; function to remove an item (in varying quantities) from the player's bag or PC box +; INPUT: +; HL = address of inventory (either wNumBagItems or wNumBoxItems) +; [wWhichPokemon] = index (within the inventory) of the item to remove +; [wItemQuantity] = quantity to remove +RemoveItemFromInventory:: + ldh a, [hLoadedROMBank] + push af + ld a, BANK(RemoveItemFromInventory_) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call RemoveItemFromInventory_ + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +; function to add an item (in varying quantities) to the player's bag or PC box +; INPUT: +; HL = address of inventory (either wNumBagItems or wNumBoxItems) +; [wcf91] = item ID +; [wItemQuantity] = item quantity +; sets carry flag if successful, unsets carry flag if unsuccessful +AddItemToInventory:: + push bc + ldh a, [hLoadedROMBank] + push af + ld a, BANK(AddItemToInventory_) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call AddItemToInventory_ + pop bc + ld a, b + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + pop bc + ret diff --git a/home/item.asm b/home/item.asm new file mode 100644 index 00000000..f27d46f4 --- /dev/null +++ b/home/item.asm @@ -0,0 +1,49 @@ +; uses an item +; UseItem is used with dummy items to perform certain other functions as well +; INPUT: +; [wcf91] = item ID +; OUTPUT: +; [wActionResultOrTookBattleTurn] = success +; 00: unsuccessful +; 01: successful +; 02: not able to be used right now, no extra menu displayed (only certain items use this) +UseItem:: + farjp UseItem_ + +; confirms the item toss and then tosses the item +; INPUT: +; hl = address of inventory (either wNumBagItems or wNumBoxItems) +; [wcf91] = item ID +; [wWhichPokemon] = index of item within inventory +; [wItemQuantity] = quantity to toss +; OUTPUT: +; clears carry flag if the item is tossed, sets carry flag if not +TossItem:: + ldh a, [hLoadedROMBank] + push af + ld a, BANK(TossItem_) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call TossItem_ + pop de + ld a, d + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +; checks if an item is a key item +; INPUT: +; [wcf91] = item ID +; OUTPUT: +; [wIsKeyItem] = result +; 00: item is not key item +; 01: item is key item +IsKeyItem:: + push hl + push de + push bc + farcall IsKeyItem_ + pop bc + pop de + pop hl + ret diff --git a/home/item_price.asm b/home/item_price.asm new file mode 100644 index 00000000..98eb31b1 --- /dev/null +++ b/home/item_price.asm @@ -0,0 +1,44 @@ +GetItemPrice:: +; Stores item's price as BCD at hItemPrice (3 bytes) +; Input: [wcf91] = item id + ldh a, [hLoadedROMBank] + push af + ld a, [wListMenuID] + cp MOVESLISTMENU + ld a, BANK(ItemPrices) + jr nz, .ok + ld a, $f ; hardcoded Bank +.ok + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ld hl, wItemPrices + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wcf91] ; a contains item id + cp HM01 + jr nc, .getTMPrice + ld bc, $3 +.loop + add hl, bc + dec a + jr nz, .loop + dec hl + ld a, [hld] + ldh [hItemPrice + 2], a + ld a, [hld] + ldh [hItemPrice + 1], a + ld a, [hl] + ldh [hItemPrice], a + jr .done +.getTMPrice + ld a, BANK(GetMachinePrice) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call GetMachinePrice +.done + ld de, hItemPrice + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/joypad2.asm b/home/joypad2.asm new file mode 100644 index 00000000..139dd3f5 --- /dev/null +++ b/home/joypad2.asm @@ -0,0 +1,95 @@ +; this function is used when lower button sensitivity is wanted (e.g. menus) +; OUTPUT: [hJoy5] = pressed buttons in usual format +; there are two flags that control its functionality, [hJoy6] and [hJoy7] +; there are essentially three modes of operation +; 1. Get newly pressed buttons only +; ([hJoy7] == 0, [hJoy6] == any) +; Just copies [hJoyPressed] to [hJoy5]. +; 2. Get currently pressed buttons at low sample rate with delay +; ([hJoy7] == 1, [hJoy6] != 0) +; If the user holds down buttons for more than half a second, +; report buttons as being pressed up to 12 times per second thereafter. +; If the user holds down buttons for less than half a second, +; report only one button press. +; 3. Same as 2, but report no buttons as pressed if A or B is held down. +; ([hJoy7] == 1, [hJoy6] == 0) +JoypadLowSensitivity:: + call Joypad + ldh a, [hJoy7] ; flag + and a ; get all currently pressed buttons or only newly pressed buttons? + ldh a, [hJoyPressed] ; newly pressed buttons + jr z, .storeButtonState + ldh a, [hJoyHeld] ; all currently pressed buttons +.storeButtonState + ldh [hJoy5], a + ldh a, [hJoyPressed] ; newly pressed buttons + and a ; have any buttons been newly pressed since last check? + jr z, .noNewlyPressedButtons +.newlyPressedButtons + ld a, 30 ; half a second delay + ldh [hFrameCounter], a + ret +.noNewlyPressedButtons + ldh a, [hFrameCounter] + and a ; is the delay over? + jr z, .delayOver +.delayNotOver + xor a + ldh [hJoy5], a ; report no buttons as pressed + ret +.delayOver +; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed + ldh a, [hJoyHeld] + and A_BUTTON | B_BUTTON + jr z, .setShortDelay + ldh a, [hJoy6] ; flag + and a + jr nz, .setShortDelay + xor a + ldh [hJoy5], a +.setShortDelay + ld a, 5 ; 1/12 of a second delay + ldh [hFrameCounter], a + ret + +WaitForTextScrollButtonPress:: + ldh a, [hDownArrowBlinkCount1] + push af + ldh a, [hDownArrowBlinkCount2] + push af + xor a + ldh [hDownArrowBlinkCount1], a + ld a, $6 + ldh [hDownArrowBlinkCount2], a +.loop + push hl + ld a, [wTownMapSpriteBlinkingEnabled] + and a + jr z, .skipAnimation + call TownMapSpriteBlinkingAnimation +.skipAnimation + hlcoord 18, 16 + call HandleDownArrowBlinkTiming + pop hl + call JoypadLowSensitivity + predef CableClub_Run + ldh a, [hJoy5] + and A_BUTTON | B_BUTTON + jr z, .loop + pop af + ldh [hDownArrowBlinkCount2], a + pop af + ldh [hDownArrowBlinkCount1], a + ret + +; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect +ManualTextScroll:: + ld a, [wLinkState] + cp LINK_STATE_BATTLING + jr z, .inLinkBattle + call WaitForTextScrollButtonPress + ld a, SFX_PRESS_AB + jp PlaySound +.inLinkBattle + ld c, 65 + jp DelayFrames diff --git a/home/load_font.asm b/home/load_font.asm new file mode 100644 index 00000000..3b56d3a8 --- /dev/null +++ b/home/load_font.asm @@ -0,0 +1,47 @@ +LoadFontTilePatterns:: + ldh a, [rLCDC] + bit 7, a ; is the LCD enabled? + jr nz, .on +.off + ld hl, FontGraphics + ld de, vFont + ld bc, FontGraphicsEnd - FontGraphics + ld a, BANK(FontGraphics) + jp FarCopyDataDouble ; if LCD is off, transfer all at once +.on + ld de, FontGraphics + ld hl, vFont + lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8 + jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank + +LoadTextBoxTilePatterns:: + ldh a, [rLCDC] + bit 7, a ; is the LCD enabled? + jr nz, .on +.off + ld hl, TextBoxGraphics + ld de, vChars2 tile $60 + ld bc, TextBoxGraphicsEnd - TextBoxGraphics + ld a, BANK(TextBoxGraphics) + jp FarCopyData2 ; if LCD is off, transfer all at once +.on + ld de, TextBoxGraphics + ld hl, vChars2 tile $60 + lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10 + jp CopyVideoData ; if LCD is on, transfer during V-blank + +LoadHpBarAndStatusTilePatterns:: + ldh a, [rLCDC] + bit 7, a ; is the LCD enabled? + jr nz, .on +.off + ld hl, HpBarAndStatusGraphics + ld de, vChars2 tile $62 + ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics + ld a, BANK(HpBarAndStatusGraphics) + jp FarCopyData2 ; if LCD is off, transfer all at once +.on + ld de, HpBarAndStatusGraphics + ld hl, vChars2 tile $62 + lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10 + jp CopyVideoData ; if LCD is on, transfer during V-blank diff --git a/home/map_objects.asm b/home/map_objects.asm new file mode 100644 index 00000000..02555e35 --- /dev/null +++ b/home/map_objects.asm @@ -0,0 +1,248 @@ +; checks if the player's coordinates match an arrow movement tile's coordinates +; and if so, decodes the RLE movement data +; b = player Y +; c = player X +DecodeArrowMovementRLE:: + ld a, [hli] + cp $ff + ret z ; no match in the list + cp b + jr nz, .nextArrowMovementTileEntry1 + ld a, [hli] + cp c + jr nz, .nextArrowMovementTileEntry2 + ld a, [hli] + ld d, [hl] + ld e, a + ld hl, wSimulatedJoypadStatesEnd + call DecodeRLEList + dec a + ld [wSimulatedJoypadStatesIndex], a + ret +.nextArrowMovementTileEntry1 + inc hl +.nextArrowMovementTileEntry2 + inc hl + inc hl + jr DecodeArrowMovementRLE + +TextScript_ItemStoragePC:: + call SaveScreenTilesToBuffer2 + ld b, BANK(PlayerPC) + ld hl, PlayerPC + jr bankswitchAndContinue + +TextScript_BillsPC:: + call SaveScreenTilesToBuffer2 + ld b, BANK(BillsPC_) + ld hl, BillsPC_ + jr bankswitchAndContinue + +TextScript_GameCornerPrizeMenu:: +; XXX find a better name for this function +; special_F7 + ld b, BANK(CeladonPrizeMenu) + ld hl, CeladonPrizeMenu +bankswitchAndContinue:: + call Bankswitch + jp HoldTextDisplayOpen ; continue to main text-engine function + +TextScript_PokemonCenterPC:: + ld b, BANK(ActivatePC) + ld hl, ActivatePC + jr bankswitchAndContinue + +StartSimulatingJoypadStates:: + xor a + ld [wOverrideSimulatedJoypadStatesMask], a + ld [wSpritePlayerStateData2MovementByte1], a + ld hl, wd730 + set 7, [hl] + ret + +IsItemInBag:: +; given an item_id in b +; set zero flag if item isn't in player's bag +; else reset zero flag +; related to Pokémon Tower and ghosts + predef GetQuantityOfItemInBag + ld a, b + and a + ret + +DisplayPokedex:: + ld [wd11e], a + farjp _DisplayPokedex + +SetSpriteFacingDirectionAndDelay:: + call SetSpriteFacingDirection + ld c, 6 + jp DelayFrames + +SetSpriteFacingDirection:: + ld a, $9 + ldh [hSpriteDataOffset], a + call GetPointerWithinSpriteStateData1 + ldh a, [hSpriteFacingDirection] + ld [hl], a + ret + +SetSpriteImageIndexAfterSettingFacingDirection:: + ld de, -7 + add hl, de + ld [hl], a + ret + +; tests if the player's coordinates are in a specified array +; INPUT: +; hl = address of array +; OUTPUT: +; [wCoordIndex] = if there is match, the matching array index +; sets carry if the coordinates are in the array, clears carry if not +ArePlayerCoordsInArray:: + ld a, [wYCoord] + ld b, a + ld a, [wXCoord] + ld c, a + ; fallthrough + +CheckCoords:: + xor a + ld [wCoordIndex], a +.loop + ld a, [hli] + cp $ff ; reached terminator? + jr z, .notInArray + push hl + ld hl, wCoordIndex + inc [hl] + pop hl +.compareYCoord + cp b + jr z, .compareXCoord + inc hl + jr .loop +.compareXCoord + ld a, [hli] + cp c + jr nz, .loop +.inArray + scf + ret +.notInArray + and a + ret + +; tests if a boulder's coordinates are in a specified array +; INPUT: +; hl = address of array +; [hSpriteIndex] = index of boulder sprite +; OUTPUT: +; [wCoordIndex] = if there is match, the matching array index +; sets carry if the coordinates are in the array, clears carry if not +CheckBoulderCoords:: + push hl + ld hl, wSpritePlayerStateData2MapY + ldh a, [hSpriteIndex] + swap a + ld d, $0 + ld e, a + add hl, de + ld a, [hli] + sub $4 ; because sprite coordinates are offset by 4 + ld b, a + ld a, [hl] + sub $4 ; because sprite coordinates are offset by 4 + ld c, a + pop hl + jp CheckCoords + +GetPointerWithinSpriteStateData1:: + ld h, $c1 + jr _GetPointerWithinSpriteStateData + +GetPointerWithinSpriteStateData2:: + ld h, $c2 + +_GetPointerWithinSpriteStateData: + ldh a, [hSpriteDataOffset] + ld b, a + ldh a, [hSpriteIndex] + swap a + add b + ld l, a + ret + +; decodes a $ff-terminated RLEncoded list +; each entry is a pair of bytes <byte value> <repetitions> +; the final $ff will be replicated in the output list and a contains the number of bytes written +; de: input list +; hl: output list +DecodeRLEList:: + xor a + ld [wRLEByteCount], a ; count written bytes here +.listLoop + ld a, [de] + cp $ff + jr z, .endOfList + ldh [hRLEByteValue], a ; store byte value to be written + inc de + ld a, [de] + ld b, $0 + ld c, a ; number of bytes to be written + ld a, [wRLEByteCount] + add c + ld [wRLEByteCount], a ; update total number of written bytes + ldh a, [hRLEByteValue] + call FillMemory ; write a c-times to output + inc de + jr .listLoop +.endOfList + ld a, $ff + ld [hl], a ; write final $ff + ld a, [wRLEByteCount] + inc a ; include sentinel in counting + ret + +; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2] +SetSpriteMovementBytesToFE:: + push hl + call GetSpriteMovementByte1Pointer + ld [hl], $fe + call GetSpriteMovementByte2Pointer + ldh a, [hSpriteMovementByte2] + ld [hl], a + pop hl + ret + +; sets both movement bytes for sprite [hSpriteIndex] to $FF +SetSpriteMovementBytesToFF:: + push hl + call GetSpriteMovementByte1Pointer + ld [hl], $FF + call GetSpriteMovementByte2Pointer + ld [hl], $FF ; prevent person from walking? + pop hl + ret + +; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl +GetSpriteMovementByte1Pointer:: + ld h, $C2 + ldh a, [hSpriteIndex] + swap a + add 6 + ld l, a + ret + +; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl +GetSpriteMovementByte2Pointer:: + push de + ld hl, wMapSpriteData + ldh a, [hSpriteIndex] + dec a + add a + ld d, 0 + ld e, a + add hl, de + pop de + ret diff --git a/home/math.asm b/home/math.asm new file mode 100644 index 00000000..b081b540 --- /dev/null +++ b/home/math.asm @@ -0,0 +1,41 @@ +; function to do multiplication +; all values are big endian +; INPUT +; FF96-FF98 = multiplicand +; FF99 = multiplier +; OUTPUT +; FF95-FF98 = product +Multiply:: + push hl + push bc + callfar _Multiply + pop bc + pop hl + ret + +; function to do division +; all values are big endian +; INPUT +; FF95-FF98 = dividend +; FF99 = divisor +; b = number of bytes in the dividend (starting from FF95) +; OUTPUT +; FF95-FF98 = quotient +; FF99 = remainder +Divide:: + push hl + push de + push bc + ldh a, [hLoadedROMBank] + push af + ld a, BANK(_Divide) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call _Divide + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + pop bc + pop de + pop hl + ret diff --git a/home/money.asm b/home/money.asm new file mode 100644 index 00000000..a62835ea --- /dev/null +++ b/home/money.asm @@ -0,0 +1,15 @@ +HasEnoughMoney:: +; Check if the player has at least as much +; money as the 3-byte BCD value at hMoney. + ld de, wPlayerMoney + ld hl, hMoney + ld c, 3 + jp StringCmp + +HasEnoughCoins:: +; Check if the player has at least as many +; coins as the 2-byte BCD value at hCoins. + ld de, wPlayerCoins + ld hl, hCoins + ld c, 2 + jp StringCmp diff --git a/home/move_mon.asm b/home/move_mon.asm index cf7213b1..3e69e6d0 100644 --- a/home/move_mon.asm +++ b/home/move_mon.asm @@ -1,3 +1,18 @@ +; Copies [hl, bc) to [de, de + bc - hl). +; In other words, the source data is from hl up to but not including bc, +; and the destination is de. +CopyDataUntil:: + ld a, [hli] + ld [de], a + inc de + ld a, h + cp b + jr nz, CopyDataUntil + ld a, l + cp c + jr nz, CopyDataUntil + ret + ; Function to remove a pokemon from the party or the current box. ; wWhichPokemon determines the pokemon. ; [wRemoveMonFromBox] == 0 specifies the party. diff --git a/home/npc_movement.asm b/home/npc_movement.asm new file mode 100644 index 00000000..4914d3df --- /dev/null +++ b/home/npc_movement.asm @@ -0,0 +1,54 @@ +; not zero if an NPC movement script is running, the player character is +; automatically stepping down from a door, or joypad states are being simulated +IsPlayerCharacterBeingControlledByGame:: + ld a, [wNPCMovementScriptPointerTableNum] + and a + ret nz + ld a, [wd736] + bit 1, a ; currently stepping down from door bit + ret nz + ld a, [wd730] + and $80 + ret + +RunNPCMovementScript:: + ld hl, wd736 + bit 0, [hl] + res 0, [hl] + jr nz, .playerStepOutFromDoor + ld a, [wNPCMovementScriptPointerTableNum] + and a + ret z + dec a + add a + ld d, 0 + ld e, a + ld hl, .NPCMovementScriptPointerTables + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ldh a, [hLoadedROMBank] + push af + ld a, [wNPCMovementScriptBank] + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ld a, [wNPCMovementScriptFunctionNum] + call CallFunctionInTable + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +.NPCMovementScriptPointerTables + dw PalletMovementScriptPointerTable + dw PewterMuseumGuyMovementScriptPointerTable + dw PewterGymGuyMovementScriptPointerTable +.playerStepOutFromDoor + farjp PlayerStepOutFromDoor + +EndNPCMovementScript:: + farjp _EndNPCMovementScript + +EmptyFunc2:: + ret diff --git a/home/oam.asm b/home/oam.asm new file mode 100644 index 00000000..8a940d97 --- /dev/null +++ b/home/oam.asm @@ -0,0 +1,36 @@ +; INPUT: +; a = oam block index (each block is 4 oam entries) +; b = Y coordinate of upper left corner of sprite +; c = X coordinate of upper left corner of sprite +; de = base address of 4 tile number and attribute pairs +WriteOAMBlock:: + ld h, HIGH(wOAMBuffer) + swap a ; multiply by 16 + ld l, a + call .writeOneEntry ; upper left + push bc + ld a, 8 + add c + ld c, a + call .writeOneEntry ; upper right + pop bc + ld a, 8 + add b + ld b, a + call .writeOneEntry ; lower left + ld a, 8 + add c + ld c, a + ; lower right +.writeOneEntry + ld [hl], b ; Y coordinate + inc hl + ld [hl], c ; X coordinate + inc hl + ld a, [de] ; tile number + inc de + ld [hli], a + ld a, [de] ; attribute + inc de + ld [hli], a + ret diff --git a/home/overworld.asm b/home/overworld.asm index acc108c7..0408bf32 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -2421,3 +2421,54 @@ ForceBikeOrSurf:: ld hl, LoadPlayerSpriteGraphics call Bankswitch jp PlayDefaultMusic ; update map/player state? + +CheckForUserInterruption:: +; Return carry if Up+Select+B, Start or A are pressed in c frames. +; Used only in the intro and title screen. + call DelayFrame + + push bc + call JoypadLowSensitivity + pop bc + + ldh a, [hJoyHeld] + cp D_UP + SELECT + B_BUTTON + jr z, .input + + ldh a, [hJoy5] + and START | A_BUTTON + jr nz, .input + + dec c + jr nz, CheckForUserInterruption + + and a + ret + +.input + scf + ret + +; function to load position data for destination warp when switching maps +; INPUT: +; a = ID of destination warp within destination map +LoadDestinationWarpPosition:: + ld b, a + ldh a, [hLoadedROMBank] + push af + ld a, [wPredefParentBank] + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ld a, b + add a + add a + ld c, a + ld b, 0 + add hl, bc + ld bc, 4 + ld de, wCurrentTileBlockMapViewPointer + call CopyData + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/palettes.asm b/home/palettes.asm new file mode 100644 index 00000000..08dcdc85 --- /dev/null +++ b/home/palettes.asm @@ -0,0 +1,57 @@ +RestoreScreenTilesAndReloadTilePatterns:: + call ClearSprites + ld a, $1 + ld [wUpdateSpritesEnabled], a + call ReloadMapSpriteTilePatterns + call LoadScreenTilesFromBuffer2 + call LoadTextBoxTilePatterns + call RunDefaultPaletteCommand + jr Delay3 + +GBPalWhiteOutWithDelay3:: + call GBPalWhiteOut + +Delay3:: +; The bg map is updated each frame in thirds. +; Wait three frames to let the bg map fully update. + ld c, 3 + jp DelayFrames + +GBPalNormal:: +; Reset BGP and OBP0. + ld a, %11100100 ; 3210 + ldh [rBGP], a + ld a, %11010000 ; 3100 + ldh [rOBP0], a + ret + +GBPalWhiteOut:: +; White out all palettes. + xor a + ldh [rBGP], a + ldh [rOBP0], a + ldh [rOBP1], a + ret + +RunDefaultPaletteCommand:: + ld b, SET_PAL_DEFAULT +RunPaletteCommand:: + ld a, [wOnSGB] + and a + ret z + predef_jump _RunPaletteCommand + +GetHealthBarColor:: +; Return at hl the palette of +; an HP bar e pixels long. + ld a, e + cp 27 + ld d, 0 ; green + jr nc, .gotColor + cp 10 + inc d ; yellow + jr nc, .gotColor + inc d ; red +.gotColor + ld [hl], d + ret diff --git a/home/pathfinding.asm b/home/pathfinding.asm new file mode 100644 index 00000000..aca5a763 --- /dev/null +++ b/home/pathfinding.asm @@ -0,0 +1,65 @@ +; calculates the difference |a-b|, setting carry flag if a<b +CalcDifference:: + sub b + ret nc + cpl + add $1 + scf + ret + +MoveSprite:: +; move the sprite [hSpriteIndex] with the movement pointed to by de +; actually only copies the movement data to wNPCMovementDirections for later + call SetSpriteMovementBytesToFF +MoveSprite_:: + push hl + push bc + call GetSpriteMovementByte1Pointer + xor a + ld [hl], a + ld hl, wNPCMovementDirections + ld c, 0 + +.loop + ld a, [de] + ld [hli], a + inc de + inc c + cp $FF ; have we reached the end of the movement data? + jr nz, .loop + + ld a, c + ld [wNPCNumScriptedSteps], a ; number of steps taken + + pop bc + ld hl, wd730 + set 0, [hl] + pop hl + xor a + ld [wOverrideSimulatedJoypadStatesMask], a + ld [wSimulatedJoypadStatesEnd], a + dec a + ld [wJoyIgnore], a + ld [wWastedByteCD3A], a + ret + +; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2] +DivideBytes:: + push hl + ld hl, hQuotient2 + xor a + ld [hld], a + ld a, [hld] + and a + jr z, .done + ld a, [hli] +.loop + sub [hl] + jr c, .done + inc hl + inc [hl] + dec hl + jr .loop +.done + pop hl + ret diff --git a/home/predef_text.asm b/home/predef_text.asm new file mode 100644 index 00000000..b494a2c8 --- /dev/null +++ b/home/predef_text.asm @@ -0,0 +1,28 @@ +PrintPredefTextID:: + ldh [hSpriteIndexOrTextID], a + ld hl, TextPredefs + call SetMapTextPointer + ld hl, wTextPredefFlag + set 0, [hl] + call DisplayTextID + +RestoreMapTextPointer:: + ld hl, wMapTextPtr + ldh a, [hSavedMapTextPtr] + ld [hli], a + ldh a, [hSavedMapTextPtr + 1] + ld [hl], a + ret + +SetMapTextPointer:: + ld a, [wMapTextPtr] + ldh [hSavedMapTextPtr], a + ld a, [wMapTextPtr + 1] + ldh [hSavedMapTextPtr + 1], a + ld a, l + ld [wMapTextPtr], a + ld a, h + ld [wMapTextPtr + 1], a + ret + +INCLUDE "data/text_predef_pointers.asm" diff --git a/home/print_text.asm b/home/print_text.asm new file mode 100644 index 00000000..049ddfb4 --- /dev/null +++ b/home/print_text.asm @@ -0,0 +1,45 @@ +; This function is used to wait a short period after printing a letter to the +; screen unless the player presses the A/B button or the delay is turned off +; through the [wd730] or [wLetterPrintingDelayFlags] flags. +PrintLetterDelay:: + ld a, [wd730] + bit 6, a + ret nz + ld a, [wLetterPrintingDelayFlags] + bit 1, a + ret z + push hl + push de + push bc + ld a, [wLetterPrintingDelayFlags] + bit 0, a + jr z, .waitOneFrame + ld a, [wOptions] + and $f + ldh [hFrameCounter], a + jr .checkButtons +.waitOneFrame + ld a, 1 + ldh [hFrameCounter], a +.checkButtons + call Joypad + ldh a, [hJoyHeld] +.checkAButton + bit 0, a ; is the A button pressed? + jr z, .checkBButton + jr .endWait +.checkBButton + bit 1, a ; is the B button pressed? + jr z, .buttonsNotPressed +.endWait + call DelayFrame + jr .done +.buttonsNotPressed ; if neither A nor B is pressed + ldh a, [hFrameCounter] + and a + jr nz, .checkButtons +.done + pop bc + pop de + pop hl + ret diff --git a/home/random.asm b/home/random.asm new file mode 100644 index 00000000..33a24425 --- /dev/null +++ b/home/random.asm @@ -0,0 +1,12 @@ +Random:: +; Return a random number in a. +; For battles, use BattleRandom. + push hl + push de + push bc + farcall Random_ + ldh a, [hRandomAdd] + pop bc + pop de + pop hl + ret diff --git a/home/reload_sprites.asm b/home/reload_sprites.asm new file mode 100644 index 00000000..8a08d64d --- /dev/null +++ b/home/reload_sprites.asm @@ -0,0 +1,19 @@ +; Copy the current map's sprites' tile patterns to VRAM again after they have +; been overwritten by other tile patterns. +ReloadMapSpriteTilePatterns:: + ld hl, wFontLoaded + ld a, [hl] + push af + res 0, [hl] + push hl + xor a + ld [wSpriteSetID], a + call DisableLCD + farcall InitMapSprites + call EnableLCD + pop hl + pop af + ld [hl], a + call LoadPlayerSpriteGraphics + call LoadFontTilePatterns + jp UpdateSprites diff --git a/home/reload_tiles.asm b/home/reload_tiles.asm new file mode 100644 index 00000000..6228395c --- /dev/null +++ b/home/reload_tiles.asm @@ -0,0 +1,41 @@ +; reloads text box tile patterns, current map view, and tileset tile patterns +ReloadMapData:: + ldh a, [hLoadedROMBank] + push af + ld a, [wCurMap] + call SwitchToMapRomBank + call DisableLCD + call LoadTextBoxTilePatterns + call LoadCurrentMapView + call LoadTilesetTilePatternData + call EnableLCD + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +; reloads tileset tile patterns +ReloadTilesetTilePatterns:: + ldh a, [hLoadedROMBank] + push af + ld a, [wCurMap] + call SwitchToMapRomBank + call DisableLCD + call LoadTilesetTilePatternData + call EnableLCD + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +; shows the town map and lets the player choose a destination to fly to +ChooseFlyDestination:: + ld hl, wd72e + res 4, [hl] + farjp LoadTownMap_Fly + +; causes the text box to close without waiting for a button press after displaying text +DisableWaitingAfterTextDisplay:: + ld a, $01 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ret diff --git a/home/reset_player_sprite.asm b/home/reset_player_sprite.asm new file mode 100644 index 00000000..72df31a1 --- /dev/null +++ b/home/reset_player_sprite.asm @@ -0,0 +1,20 @@ +ResetPlayerSpriteData:: + ld hl, wSpriteStateData1 + call ResetPlayerSpriteData_ClearSpriteData + ld hl, wSpriteStateData2 + call ResetPlayerSpriteData_ClearSpriteData + ld a, $1 + ld [wSpritePlayerStateData1PictureID], a + ld [wSpritePlayerStateData2ImageBaseOffset], a + ld hl, wSpritePlayerStateData1YPixels + ld [hl], $3c ; set Y screen pos + inc hl + inc hl + ld [hl], $40 ; set X screen pos + ret + +; overwrites sprite data with zeroes +ResetPlayerSpriteData_ClearSpriteData:: + ld bc, $10 + xor a + jp FillMemory diff --git a/home/textbox.asm b/home/textbox.asm new file mode 100644 index 00000000..5067b044 --- /dev/null +++ b/home/textbox.asm @@ -0,0 +1,16 @@ +; function to draw various text boxes +; INPUT: +; [wTextBoxID] = text box ID +; b, c = y, x cursor position (TWO_OPTION_MENU only) +DisplayTextBoxID:: + ldh a, [hLoadedROMBank] + push af + ld a, BANK(DisplayTextBoxID_) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call DisplayTextBoxID_ + pop bc + ld a, b + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/tilemap.asm b/home/tilemap.asm new file mode 100644 index 00000000..afee7097 --- /dev/null +++ b/home/tilemap.asm @@ -0,0 +1,61 @@ +FillMemory:: +; Fill bc bytes at hl with a. + push de + ld d, a +.loop + ld a, d + ld [hli], a + dec bc + ld a, b + or c + jr nz, .loop + pop de + ret + +UncompressSpriteFromDE:: +; Decompress pic at a:de. + ld hl, wSpriteInputPtr + ld [hl], e + inc hl + ld [hl], d + jp UncompressSpriteData + +SaveScreenTilesToBuffer2:: + hlcoord 0, 0 + ld de, wTileMapBackup2 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call CopyData + ret + +LoadScreenTilesFromBuffer2:: + call LoadScreenTilesFromBuffer2DisableBGTransfer + ld a, 1 + ldh [hAutoBGTransferEnabled], a + ret + +; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled +LoadScreenTilesFromBuffer2DisableBGTransfer:: + xor a + ldh [hAutoBGTransferEnabled], a + ld hl, wTileMapBackup2 + decoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call CopyData + ret + +SaveScreenTilesToBuffer1:: + hlcoord 0, 0 + ld de, wTileMapBackup + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + jp CopyData + +LoadScreenTilesFromBuffer1:: + xor a + ldh [hAutoBGTransferEnabled], a + ld hl, wTileMapBackup + decoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call CopyData + ld a, 1 + ldh [hAutoBGTransferEnabled], a + ret diff --git a/home/trainers2.asm b/home/trainers2.asm new file mode 100644 index 00000000..950eabb2 --- /dev/null +++ b/home/trainers2.asm @@ -0,0 +1,35 @@ +GetTrainerInformation:: + call GetTrainerName + ld a, [wLinkState] + and a + jr nz, .linkBattle + ld a, BANK(TrainerPicAndMoneyPointers) + call BankswitchHome + ld a, [wTrainerClass] + dec a + ld hl, TrainerPicAndMoneyPointers + ld bc, $5 + call AddNTimes + ld de, wTrainerPicPointer + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld de, wTrainerBaseMoney + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + jp BankswitchBack +.linkBattle + ld hl, wTrainerPicPointer + ld de, RedPicFront + ld [hl], e + inc hl + ld [hl], d + ret + +GetTrainerName:: + farjp GetTrainerName_ diff --git a/home/update_sprites.asm b/home/update_sprites.asm new file mode 100644 index 00000000..80ea14d3 --- /dev/null +++ b/home/update_sprites.asm @@ -0,0 +1,14 @@ +UpdateSprites:: + ld a, [wUpdateSpritesEnabled] + dec a + ret nz + ldh a, [hLoadedROMBank] + push af + ld a, BANK(_UpdateSprites) + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + call _UpdateSprites + pop af + ldh [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/window.asm b/home/window.asm new file mode 100644 index 00000000..e83f9585 --- /dev/null +++ b/home/window.asm @@ -0,0 +1,294 @@ +HandleMenuInput:: + xor a + ld [wPartyMenuAnimMonEnabled], a + +HandleMenuInput_:: + ldh a, [hDownArrowBlinkCount1] + push af + ldh a, [hDownArrowBlinkCount2] + push af ; save existing values on stack + xor a + ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1 + ld a, 6 + ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2 +.loop1 + xor a + ld [wAnimCounter], a ; counter for pokemon shaking animation + call PlaceMenuCursor + call Delay3 +.loop2 + push hl + ld a, [wPartyMenuAnimMonEnabled] + and a ; is it a pokemon selection menu? + jr z, .getJoypadState + farcall AnimatePartyMon ; shake mini sprite of selected pokemon +.getJoypadState + pop hl + call JoypadLowSensitivity + ldh a, [hJoy5] + and a ; was a key pressed? + jr nz, .keyPressed + push hl + hlcoord 18, 11 ; coordinates of blinking down arrow in some menus + call HandleDownArrowBlinkTiming ; blink down arrow (if any) + pop hl + ld a, [wMenuJoypadPollCount] + dec a + jr z, .giveUpWaiting + jr .loop2 +.giveUpWaiting +; if a key wasn't pressed within the specified number of checks + pop af + ldh [hDownArrowBlinkCount2], a + pop af + ldh [hDownArrowBlinkCount1], a ; restore previous values + xor a + ld [wMenuWrappingEnabled], a ; disable menu wrapping + ret +.keyPressed + xor a + ld [wCheckFor180DegreeTurn], a + ldh a, [hJoy5] + ld b, a + bit 6, a ; pressed Up key? + jr z, .checkIfDownPressed +.upPressed + ld a, [wCurrentMenuItem] ; selected menu item + and a ; already at the top of the menu? + jr z, .alreadyAtTop +.notAtTop + dec a + ld [wCurrentMenuItem], a ; move selected menu item up one space + jr .checkOtherKeys +.alreadyAtTop + ld a, [wMenuWrappingEnabled] + and a ; is wrapping around enabled? + jr z, .noWrappingAround + ld a, [wMaxMenuItem] + ld [wCurrentMenuItem], a ; wrap to the bottom of the menu + jr .checkOtherKeys +.checkIfDownPressed + bit 7, a + jr z, .checkOtherKeys +.downPressed + ld a, [wCurrentMenuItem] + inc a + ld c, a + ld a, [wMaxMenuItem] + cp c + jr nc, .notAtBottom +.alreadyAtBottom + ld a, [wMenuWrappingEnabled] + and a ; is wrapping around enabled? + jr z, .noWrappingAround + ld c, $00 ; wrap from bottom to top +.notAtBottom + ld a, c + ld [wCurrentMenuItem], a +.checkOtherKeys + ld a, [wMenuWatchedKeys] + and b ; does the menu care about any of the pressed keys? + jp z, .loop1 +.checkIfAButtonOrBButtonPressed + ldh a, [hJoy5] + and A_BUTTON | B_BUTTON + jr z, .skipPlayingSound +.AButtonOrBButtonPressed + push hl + ld hl, wFlags_0xcd60 + bit 5, [hl] + pop hl + jr nz, .skipPlayingSound + ld a, SFX_PRESS_AB + call PlaySound +.skipPlayingSound + pop af + ldh [hDownArrowBlinkCount2], a + pop af + ldh [hDownArrowBlinkCount1], a ; restore previous values + xor a + ld [wMenuWrappingEnabled], a ; disable menu wrapping + ldh a, [hJoy5] + ret +.noWrappingAround + ld a, [wMenuWatchMovingOutOfBounds] + and a ; should we return if the user tried to go past the top or bottom? + jr z, .checkOtherKeys + jr .checkIfAButtonOrBButtonPressed + +PlaceMenuCursor:: + ld a, [wTopMenuItemY] + and a ; is the y coordinate 0? + jr z, .adjustForXCoord + hlcoord 0, 0 + ld bc, SCREEN_WIDTH +.topMenuItemLoop + add hl, bc + dec a + jr nz, .topMenuItemLoop +.adjustForXCoord + ld a, [wTopMenuItemX] + ld b, 0 + ld c, a + add hl, bc + push hl + ld a, [wLastMenuItem] + and a ; was the previous menu id 0? + jr z, .checkForArrow1 + push af + ldh a, [hFlagsFFF6] + bit 1, a ; is the menu double spaced? + jr z, .doubleSpaced1 + ld bc, 20 + jr .getOldMenuItemScreenPosition +.doubleSpaced1 + ld bc, 40 +.getOldMenuItemScreenPosition + pop af +.oldMenuItemLoop + add hl, bc + dec a + jr nz, .oldMenuItemLoop +.checkForArrow1 + ld a, [hl] + cp "▶" ; was an arrow next to the previously selected menu item? + jr nz, .skipClearingArrow +.clearArrow + ld a, [wTileBehindCursor] + ld [hl], a +.skipClearingArrow + pop hl + ld a, [wCurrentMenuItem] + and a + jr z, .checkForArrow2 + push af + ldh a, [hFlagsFFF6] + bit 1, a ; is the menu double spaced? + jr z, .doubleSpaced2 + ld bc, 20 + jr .getCurrentMenuItemScreenPosition +.doubleSpaced2 + ld bc, 40 +.getCurrentMenuItemScreenPosition + pop af +.currentMenuItemLoop + add hl, bc + dec a + jr nz, .currentMenuItemLoop +.checkForArrow2 + ld a, [hl] + cp "▶" ; has the right arrow already been placed? + jr z, .skipSavingTile ; if so, don't lose the saved tile + ld [wTileBehindCursor], a ; save tile before overwriting with right arrow +.skipSavingTile + ld a, "▶" ; place right arrow + ld [hl], a + ld a, l + ld [wMenuCursorLocation], a + ld a, h + ld [wMenuCursorLocation + 1], a + ld a, [wCurrentMenuItem] + ld [wLastMenuItem], a + ret + +; This is used to mark a menu cursor other than the one currently being +; manipulated. In the case of submenus, this is used to show the location of +; the menu cursor in the parent menu. In the case of swapping items in list, +; this is used to mark the item that was first chosen to be swapped. +PlaceUnfilledArrowMenuCursor:: + ld b, a + ld a, [wMenuCursorLocation] + ld l, a + ld a, [wMenuCursorLocation + 1] + ld h, a + ld [hl], $ec ; outline of right arrow + ld a, b + ret + +; Replaces the menu cursor with a blank space. +EraseMenuCursor:: + ld a, [wMenuCursorLocation] + ld l, a + ld a, [wMenuCursorLocation + 1] + ld h, a + ld [hl], " " + ret + +; This toggles a blinking down arrow at hl on and off after a delay has passed. +; This is often called even when no blinking is occurring. +; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0. +; The effect is that if the tile at hl is initialized with a down arrow, +; this function will toggle that down arrow on and off, but if the tile isn't +; initialized with a down arrow, this function does nothing. +; That allows this to be called without worrying about if a down arrow should +; be blinking. +HandleDownArrowBlinkTiming:: + ld a, [hl] + ld b, a + ld a, "▼" + cp b + jr nz, .downArrowOff +.downArrowOn + ldh a, [hDownArrowBlinkCount1] + dec a + ldh [hDownArrowBlinkCount1], a + ret nz + ldh a, [hDownArrowBlinkCount2] + dec a + ldh [hDownArrowBlinkCount2], a + ret nz + ld a, " " + ld [hl], a + ld a, $ff + ldh [hDownArrowBlinkCount1], a + ld a, $06 + ldh [hDownArrowBlinkCount2], a + ret +.downArrowOff + ldh a, [hDownArrowBlinkCount1] + and a + ret z + dec a + ldh [hDownArrowBlinkCount1], a + ret nz + dec a + ldh [hDownArrowBlinkCount1], a + ldh a, [hDownArrowBlinkCount2] + dec a + ldh [hDownArrowBlinkCount2], a + ret nz + ld a, $06 + ldh [hDownArrowBlinkCount2], a + ld a, "▼" + ld [hl], a + ret + +; The following code either enables or disables the automatic drawing of +; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait +; for a button press after displaying text (unless [wEnteringCableClub] is set). + +EnableAutoTextBoxDrawing:: + xor a + jr AutoTextBoxDrawingCommon + +DisableAutoTextBoxDrawing:: + ld a, $01 + +AutoTextBoxDrawingCommon:: + ld [wAutoTextBoxDrawingControl], a + xor a + ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press + ret + +PrintText:: +; Print text hl at (1, 14). + push hl + ld a, MESSAGE_BOX + ld [wTextBoxID], a + call DisplayTextBoxID + call UpdateSprites + call Delay3 + pop hl +PrintText_NoCreatingTextBox:: + bccoord 1, 14 + jp TextCommandProcessor |