;*************************************************************************** ;* Gfx.asm - graphics support routines ;* 12.17.99 by Abe Pralle ;* ;*************************************************************************** INCLUDE "Source/Defs.inc" INCLUDE "Source/Levels.inc" INCLUDE "Source/Start.inc" MAX_PER_TURN EQU 32 FAST_SCROLL_THRESHOLD EQU 2 SECTION "Graphics",ROM0 ;--------------------------------------------------------------------- ; Routine: InitGfx ; Description: Sets up some basic graphics stuff - One time ;--------------------------------------------------------------------- InitGfx:: push bc push de push hl ;set up game state ld a,$ff ld [amLinkMaster],a xor a ld [lastLinkAction],a ld [amChangingMap],a ld [heroesPresent],a ld a,(hero0_data & $ff) ld [curHeroAddressL],a ld a,(HERO_BA_FLAG | HERO_BS_FLAG | HERO_HAIKU_FLAG) ld [heroesAvailable],a xor a ld [heroesUsed],a ld [randomLoc],a ldio [musicEnabled],a ld [musicBank],a ld [musicAddress],a ld [musicAddress+1],a ld [heroesLocked],a ld [hero0_puffCount],a ld [hero1_puffCount],a ld [inLoadMethod],a ld c,16 ld hl,inventory .clearInventory ld [hl+],a dec c jr nz,.clearInventory ;ld a,%10100001 ;ld [inventory],a ;ld a,%00000011 ;ld [inventory+1],a xor a ld [musicOverride1],a ld [musicOverride4],a ld a,64 ld [fadeRange],a ld a,APPOMATTOXMAPINDEX ld [appomattoxMapIndex],a ld a,BANK(init_flightCodes) call SetActiveROM ld a,FLIGHTCODEBANK ld bc,256 ld de,flightCode ld hl,init_flightCodes call MemCopy xor a ldio [dmaLoad],a ld [displayType],a ld a,1 ldio [curROMBank],a call DisplayOff call SetupSpriteHandler ;sound off xor a ldio [$ff26],a ;envelopes to zero xor a ldio [$ff12],a ;zero envelope all instruments ldio [$ff17],a ldio [$ff1c],a ldio [$ff21],a ;turn on sound master control ld a,$80 ldio [$ff26],a ld a,$ff ldio [$ff24],a ;full volume both channels ldio [$ff25],a ;all sounds to both channels ;setup vector to hblank ld a,$c3 ld [hblankVector],a ;opcode of jp ld hl,OnHBlank ld a,l ld [hblankVector+1],a ld a,h ld [hblankVector+2],a ;enable VBlank interrupts ld a,[$ffff] or 1 ld [$ffff],a ;turn LCD on ld a,%11000011 ld [$ff40], a ;lcdc control ;clear all level states to zero ld a,LEVELSTATEBANK ld [$ff70],a ld c,0 ;loop 256 times ld hl,levelState xor a .clearStateLoop ld [hl+],a dec c jr nz,.clearStateLoop ld a,1 ;fade from white the first time ld [standardFadeColor],a ;enable interrupts ei .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: VMemCopy ; Arguments: a - VRAM bank of destination ; c - number of 16-byte blocks (tiles) to copy ; de - dest ; hl - source ; Alters: af ; [$ff4f] VRAM bank ; Description: Copies bytes from source to destination in VRAM. ; If screen is active it utilizes DMA loading, otherwise ; a normal copy is performed. DMA copies exceeding ; 2048 bytes may produce weird results. ;--------------------------------------------------------------------- VMemCopy:: push bc push de push hl push af ;test if screen is on ldio a,[$ff40] and %10000000 jr nz,.screenIsOn .screenIsOff pop af ldio [$ff4f],a ;switch VRAM bank .setLoop ld b,16 .bytesLoop ld a,[hl+] ld [de],a inc de dec b jr nz,.bytesLoop dec c jr nz,.setLoop jr .done .screenIsOn ;copy using DMA pop af call InitDMALoad call WaitDMALoad .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: MemSet ; Arguments: a - RAM bank of destination ; bc - length in bytes ; d - byte to set to ; hl - dest ; Alters: af ; [$ff70] RAM bank ; Description: Sets each byte in the range to be the specified value. ;--------------------------------------------------------------------- MemSet:: push bc push de push hl ldio [$ff70],a .loop ld a,d ld [hl+],a dec bc xor a cp b jr nz,.loop cp c jr nz,.loop pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: MemCopy ; Arguments: a - RAM bank ; bc - non-zero length in bytes ; de - destination starting address ; hl - source start address ; Alters: af ; [$ff70] RAM bank ; Description: Copies each of "bc" # of bytes from source to dest. ; Alters the RAM bank to specified but does not revert ; to original during or after copying. ;--------------------------------------------------------------------- MemCopy:: push bc push de push hl ldio [$ff70],a ;set RAM .copy ld a,[hl+] ld [de],a inc de xor a dec bc cp b jr nz,.copy cp c jr nz,.copy pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: InitDMALoad ; Arguments: a - VRAM bank of destination ; c - length in multiples of 16 bytes ; de - dest ; hl - source ; Alters: af ; Description: Preps appropriate variables for DMA transfer to take ; place on VBlank. Note may be called multiple times ; (er, twice) to set up values for bank 0 and bank 1 ; transfer. Note that transfers for bank 0 and bank 1 ; combined should not exceed 2048 bytes (and perhaps ; a bit less) ;--------------------------------------------------------------------- InitDMALoad:: or a jr nz,.prepBank1 .prepBank0 ld a,l ld [dmaLoadSrc0],a ld a,h ld [dmaLoadSrc0+1],a ld a,e ld [dmaLoadDest0],a ld a,d ld [dmaLoadDest0+1],a ld a,c dec a ld [dmaLoadLen0],a ldio a,[dmaLoad] or 1 ldio [dmaLoad],a ret .prepBank1 ld a,l ld [dmaLoadSrc1],a ld a,h ld [dmaLoadSrc1+1],a ld a,e ld [dmaLoadDest1],a ld a,d ld [dmaLoadDest1+1],a ld a,c dec a ld [dmaLoadLen1],a ldio a,[dmaLoad] or 2 ldio [dmaLoad],a ret ;--------------------------------------------------------------------- ; Routine: WaitDMALoad ; Alters: af ;--------------------------------------------------------------------- WaitDMALoad:: push bc push de push hl .wait ldio a,[dmaLoad] and %11 jr nz,.wait call GetInput pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: DMALoad ; Arguments: a - VRAM bank of destination ; c - byte length / 16 ; hl - source ; de - dest ; Alters: af ; Description: Combines InitDMALoad and WaitDMALoad. ;--------------------------------------------------------------------- DMALoad:: call InitDMALoad call WaitDMALoad ret ;--------------------------------------------------------------------- ; Routine: DisplayOff ; Arguments: ; Alters: af ; Description: Waits for VBlank then turns of the display ;--------------------------------------------------------------------- DisplayOff:: ;skip if the display is off already ld a,[$ff40] and %10000000 ret z ;turn display off ld a,[$ffff] ;get interrupts enabled push af ;save original value and %11111110 ;turn off vblank interrupt ld [$ffff],a ;"interrupt THIS!" .wait ld a,[$ff44] ;get line being drawn cp 144 ;wait until line is >= 144 jr c,.wait ld a,[$ff40] ;LCDC register and %01111111 ;turn off screen ld [$ff40],a pop af ;retrieve original interrupt settings ld [$ffff],a .waitVRAM ld a,[$ff41] ;STAT register and %00000010 ;bit 1 needs to be zero to access VRAM jr nz,.waitVRAM ret ;--------------------------------------------------------------------- ; Subroutine: LoadNextLevel ; Arguments: ; Alters: af ; Description: Does all the prep work of setting up the next level ; based on arguments stored in memory ;--------------------------------------------------------------------- LoadNextLevel:: push bc push de push hl .reload ld a,1 ld [amChangingMap],a ;xor a ;ld [timeToChangeLevel],a ;save old level's level state ld a,LEVELSTATEBANK ld [$ff70],a ld a,[curLevelStateIndex] ld l,a ld h,((levelState>>8) & $ff) ldio a,[mapState] or a jr nz,.stateNotZero ld a,1 .stateNotZero ld [hl],a ;clear joystick input xor a ld [curJoy0],a ld [curJoy1],a ldio [jiggleDuration],a ld [jiggleType],a ;normal jiggle call PrepLevel ld a,[timeToChangeLevel] or a jr nz,.reload ;set interrupt controller flag so the interrupt will happen ld a,[$ffff] ;interrupt enable control register or %00000011 ;enable vblank and hblank interrupts ld [$ffff],a ;store that back in the IEC call DrawMapToBackBuffer ;ld b,METHOD_CHECK ;call IterateAllLists ;initialize some values xor a ldio [backBufferReady],a xor a ld [amChangingMap],a ei ;enable interrupts pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: PrepLevel ; Description: Sets up some basic graphics stuff ;--------------------------------------------------------------------- PrepLevel:: push bc push de push hl ;reset some stuff xor a ld [levelCheckSkip],a ld [levelCheckSkip+1],a ld [levelCheckSkip+2],a ld [levelCheckSkip+3],a ld a,MAX_PER_TURN ld [iterateNumObjects],a ld hl,timeToChangeLevel ld a,[hl] ld [hl],0 cp 2 ;2=skip init & load in next jp z,.loadMap ;restore default vector to hblank ld hl,OnHBlank call InstallHBlankHandler xor a ldh [$ff43], a ;set screen offsets to 0 ldh [$ff42], a xor a ldh [$ff4a], a ;set window offsets to 7,0 ld a,7 ldh [$ff4b], a xor a ld [specialFX],a ld [paletteBufferReady],a ld [mapColor],a ld [mapColor+1],a ld [bgAttributes],a ld [bgTileMap],a ld [checkInputInMainLoop],a ld [dialogJoyIndex],a ld [heroJoyIndex],a ld [hero0_index],a ld [hero1_index],a ld [heroesIdle],a ld [allIdle],a ld [mapDialogClassIndex],a ld [dialogSettings],a ;no border, no press B ld [amShowingDialog],a ld [objTimerBase],a ld [objTimer60ths],a ld [heroTimerBase],a ld [heroTimerBase],a ld [lineZeroHorizontalOffset],a ld [samplePlaying],a ld [guardAlarm],a ld [dialogNPC_speakerIndex],a ld [dialogNPC_heroIndex],a ld [dialogBalloonClassIndex],a ld [envEffectType],a ;clear the horizontal offsets ld bc,144 ld d,0 ld hl,horizontalOffset ld a,TILEINDEXBANK call MemSet ld a,1 ld [canJoinMap],a ld de,0 call SetDialogSkip call SetDialogForward ;--------------------------- xor a ;turn all sounds off ldio [$ff12],a ;sound 1 envelope ldio [$ff17],a ;sound 2 envelope ldio [$ff1a],a ;sound 3 output ldio [$ff21],a ;sound 4 envelope ld a,$ff ld [$ff24],a ;full volume both channels ;--------------------------- ld a,$ff ld [dialogSpeakerIndex],a ;ld a,$21 ;fast=2, slow=1 ;ld a,$22 ;fast=2, slow=2 ld a,$42 ldio [scrollSpeed],a ;set up each entry of bgTileMap to be its own index for a ;speed trick in the map redraw ld c,0 ld hl,bgTileMap xor a .initBGTileMap ld [hl+],a inc a dec c jr nz,.initBGTileMap ld a,%00100111 ;background palette colors ld [$ff47],a ld a,1 ld [scrollSprites],a call LoadGraphics ;go back to VRAM bank zero xor a ;Switch to tile map ld [$ff00+$4f],a ;(VRAM bank 0) call SetupGamePalettes ;load in inventory items tiles 246-254 ld a,BANK(BGTiles1024) call SetActiveROM ld a,1 ;xor a ld c,9 ;#characters ld de,$8f60 ld hl,BGTiles1024+$3f70 call VMemCopy call LoadFont ld a,1 ld c,1 ;1 character ld de,$8ff0 ld hl,blankTileData call VMemCopy ;set up hblank interrupt ld a,143 ld [$ff45],a ;set lyc xor a ld [hblankFlag],a ;don't show dialog window ld a,[$ff0f] ;clear LCDC interrupt flag and %11111101 ld [$ff0f],a ld a,119 ldio [hblankWinOn],a ld a,143 ldio [hblankWinOff],a ld a,%00001100 ;setup stat for lyc = ly ld [$ff41],a ld a,[$ffff] ;enable hblank interrupt or %00000010 ld [$ffff],a ld a,$98 ld [backBufferDestHighByte],a call ResetSprites .loadMap ; load in a map ld a,BANK(ResetList) call SetActiveROM call ResetList call ClearFGBGFlags ld hl,curLevelIndex ld a,[hl+] ld h,[hl] ld l,a call LoadMap .done pop hl pop de pop bc ret LoadFont:: ;load in font into $8c80 (tiles 200-253) ld a,BANK(fontData) call SetActiveROM xor a ld c,62 ;# characters ld de,$8c00 ld hl,fontData jp VMemCopy ;--------------------------------------------------------------------- ; Routine: SetupSpriteHandler ; Description: Copies the routine required for sprite DMA to high ; RAM and initializes the sprites to off ;--------------------------------------------------------------------- SetupSpriteHandler:: ld hl,oamHandlerStart ;src addr ld de,SpriteDMAHandler ;dest addr ld c,(oamHandlerFinish - oamHandlerStart) ;# of bytes .loop ld a,[hl+] ld [de],a inc de dec c jr nz,.loop call ResetSprites ret oamHandlerStart: ld a,((spriteOAMBuffer>>8) & $ff) ;addr of start (in $100's) ld [$ff00+$46],a ;start sprite dma ld a,$28 ;start a delay loop .wait dec a jr nz,.wait ret oamHandlerFinish: ;--------------------------------------------------------------------- ; Routine: SetupCommonColor ; Arguments: b - Color Spec for entry to set up ; de - color for entry ; Description: Sets all 8 palettes (bg AND sprite) to have the same ; colors for the specified entry. ; Note: The format specification should have bit 7 set so it ; auto-selects the next palette ;--------------------------------------------------------------------- SetupCommonColor:: push af push bc push hl ld a,FADEBANK ld [$ff70],a ld a,b ld h,((gamePalette>>8) & $ff) and %00000110 ;color # * 2 add (gamePalette & $ff) ld l,a ld a,b ld c,16 .loop ld a,e ;Get low byte of color ld [hl+],a ;store it in game palette ld a,d ;Get high byte of color ld [hl+],a ;store in game palette ld a,l ;skip next 3 colors in game palette add 6 ld l,a dec c jr nz,.loop pop hl pop bc pop af ret ;--------------------------------------------------------------------- ; Routine: SetupGamePalettes ; Description: Sets up [gamePalette] the in-game colors but sets ; the actual hardware to be all standard ;--------------------------------------------------------------------- SetupGamePalettes: push bc push de push hl ld a,FADEBANK ld [$ff70],a ld a,%10000000 ;color specs ld [$ff68],a ld [$ff6a],a ld bc,$0000 ;standard fade color ld hl,standardFadeColor ld a,[hl] ld [hl],0 or a jr z,.fadeColorSet ld bc,$7fff ;color 1 = white .fadeColorSet ld hl,.stdPaletteData ld de,gamePalette ld a,32 ;set up 64 bytes (32 colors) .loop push af ld a,[hl+] ld [de],a ;copy of palette inc de ld a,[hl+] ld [de],a inc de ld a,c ld [$ff69],a ;bg palette ld [$ff6b],a ;fg palette ld a,b ld [$ff69],a ;bg palette ld [$ff6b],a ;fg palette pop af dec a jr nz,.loop ;repeat for FG colors ld hl,.stdPaletteData ld c,32 ;set up 64 bytes (32 colors) .loopFG ld a,[hl+] ld [de],a ;copy of palette inc de ld a,[hl+] ld [de],a inc de dec c jr nz,.loopFG pop hl pop de pop bc ret .stdPaletteData DW $0000, $2108, $4210, $7fff ;Palette 0 (Grey) DW $0000, $000A, $001f, $7fff ;Palette 1 (Red) DW $0000, $5000, $7e00, $7fff ;Palette 2 (Blue) DW $0000, $0140, $03e0, $7fff ;Palette 3 (Green) DW $0000, $4008, $5192, $7fff ;Palette 4 (Purple) DW $0000, $01cd, $03fe, $7fff ;Palette 5 (Yellow) DW $0000, $00d1, $09ff, $7fff ;Palette 6 (Brown) DW $0000, $4412, $799c, $7fff ;Palette 7 (Fuscia) ;--------------------------------------------------------------------- ; Routines: IndexToPointerDE ; IndexToPointerHL ; Arguments: a - index 1-255 of object ; Returns: de/hl - pointer $d010-$dff0 to object ;--------------------------------------------------------------------- IndexToPointerDE:: swap a jr z,.null ld e,a and %00001111 add $d0 ld d,a ld a,e and %11110000 ld e,a ret .null ld de,0 ret IndexToPointerHL:: swap a jr z,.null ld l,a and %00001111 add $d0 ld h,a ld a,l and %11110000 ld l,a ret .null ld hl,0 ret SECTION "TileCopyRoutines",ROM0 ;--------------------------------------------------------------------- ; Routines: AddHL16 ; AddDE16 ; Alters: af, (hl or de) ;--------------------------------------------------------------------- AddHL16:: ld a,l add 16 ld l,a ret nc inc h ret AddDE16:: ld a,e add 16 ld e,a ret nc inc d ret ;--------------------------------------------------------------------- ; Routines: TileIndexLToAddressHL ; TileIndexEToAddressDE ; Arguments: l/e - tile index (0-255) ; Returns: hl/de - address of tile index ($9000 +/- index*16) ;--------------------------------------------------------------------- TileIndexLToAddressHL: push af ;shift "l" 4 left and into a xor a ;clear a to zero (new high byte) sla l ;shift into carry rla ;carry into a sla l ;repeat total of 4 times rla ;carry into a sla l rla sla l rla or $90 ;add base addr of $9000 cp $98 ;>=$9800? jr c,.allSet sub $10 ;signed #'s means >$9800 should be $8800+ .allSet ld h,a ;a into h; hl is now $9000+/-offset pop af ret TileIndexEToAddressDE: push af ;shift "e" 4 left and into a xor a ;clear a to zero (new high byte) sla e ;shift into carry rla ;carry into a sla e ;repeat total of 4 times rla ;carry into a sla e rla sla e rla or $90 ;add base addr of $9000 cp $98 jr c,.allSet sub $10 .allSet ld d,a ;a into d; de is now $9000+/-offset pop af ret ;--------------------------------------------------------------------- ; Routine: TileCopyRotateCCW ; Arguments: l - Source tile index (0-255) ; e - Dest tile index ; Description: Copies pixels from source tile to dest tile, rotating ; 90 degrees counter clock-wise in the process ; Note: Assumes VRAM to be already accessible ;--------------------------------------------------------------------- TileCopyRotateCCW: push af push bc push de push hl call TileCopyIndicesToAddresses ;Set up outer loop ld a,8 ;outer loop 8 times ;Beginning of outer loop / Set up inner loop .outer1 push de ;save source start push af ;save outer loop counter ld a,8 ;inner loop 8 times .inner1 push af ;save loop counter on stack ld a,[de] ;get next even byte rrca rl b ld [de],a inc de ld a,[de] ;get next odd byte rrca rl c ld [de],a inc de pop af ;retrieve loop counter dec a jr nz,.inner1 ld a,b ;save next two bytes of result ld [hl+],a ld a,c ld [hl+],a pop af ;retrieve outer loop counter pop de ;reset srcptr to start of tile dec a jr nz,.outer1 pop hl pop de pop bc pop af ret ;--------------------------------------------------------------------- ; Routines: TileCopy ; TileCopyShiftLeft ; TileCopyShiftRight ; TileCopyShiftLeftOverlay ; TileCopyShiftRightOverlay ; TileCopyShiftUp ; TileCopyShiftDown ; Arguments: e - Source tile index (0-15) ; l - Dest tile index (0-15) ; Description: Copies tiles while shifting 4 pixels in the specified ; direction (except for plain TileCopy). Tile patterns ; should be stored in $c000-$c0ff. "Overlay" routines ; OR the source with the destination. ;--------------------------------------------------------------------- TileCopy: push af push bc push de push hl call TileCopyIndicesToAddresses ld c,16 ;loop 16 times .loop ld a,[de] ;get a byte inc de ld [hl+],a ;put it in dest dec c jr nz,.loop pop hl pop de pop bc pop af ret TileCopyShiftLeft: push af push bc push de push hl call TileCopyIndicesToAddresses ld c,16 ;loop 16 times .loop ld a,[de] ;get a byte inc de swap a ;flip nibbles and $f0 ;clear out lower four bits ld [hl+],a ;put it in dest dec c jr nz,.loop pop hl pop de pop bc pop af ret TileCopyShiftRight: push af push bc push de push hl call TileCopyIndicesToAddresses ld c,16 ;loop 16 times .loop ld a,[de] ;get a byte inc de swap a ;flip nibbles and $0f ;clear out upper four bits ld [hl+],a ;put it in dest dec c jr nz,.loop pop hl pop de pop bc pop af ret TileCopyShiftLeftOverlay: push af push bc push de push hl call TileCopyIndicesToAddresses ld c,16 ;loop 16 times .loop ld a,[de] ;get a byte inc de swap a ;flip nibbles and $f0 ;clear out lower four bits or [hl] ;combine with dest ld [hl+],a dec c jr nz,.loop pop hl pop de pop bc pop af ret TileCopyShiftRightOverlay: push af push bc push de push hl ;Get tile addresses call TileCopyIndicesToAddresses ld c,16 ;loop 16 times .loop ld a,[de] ;get a byte inc de swap a ;flip nibbles and $0f ;clear out upper four bits or [hl] ;combine with dest ld [hl+],a dec c jr nz,.loop pop hl pop de pop bc pop af ret TileCopyIndicesToAddresses: push bc ld c,4 ld h,0 ld d,0 .loop sla l rl h sla e rl d dec c jr nz,.loop pop bc ld a,((backBuffer>>8) & $ff) add a,h ld h,a ld a,((backBuffer>>8) & $ff) add a,d ld d,a ret TileCopyShiftUp: push bc push de push hl call TileCopyIndicesToAddresses ld a,e ;source += 8 add 8 ld e,a ld c,8 ;loop 8 times .loop ld a,[de] ;get a byte inc de ld [hl+],a ;put it in dest dec c jr nz,.loop ;clear 4 rows (8 bytes) ld c,8 xor a .clear ld [hl+],a dec c jr nz,.clear pop hl pop de pop bc ret TileCopyShiftDown: push bc push de push hl call TileCopyIndicesToAddresses ;clear 4 rows (8 bytes) ld c,8 xor a .clear ld [hl+],a dec c jr nz,.clear ld c,8 ;loop 8 times .loop ld a,[de] ;get a byte inc de ld [hl+],a ;put it in dest dec c jr nz,.loop pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: DuplicateTilesToSpriteMem ; Arguments: a - number of tiles to duplicate (1+) ; c - index of first tile in tile mem ; Alters: af ; Description: Copies {a} number of tiles (a*16 bytes) from $c000 ; (backBuffer) to $8000 + c*16. ; Note: Uses current VRAM bank ;--------------------------------------------------------------------- DuplicateTilesToSpriteMem: push bc push de push hl ld b,a ;tiles remaining ;de = $8000 + c*16 ld a,c swap a and %00001111 add $80 ld d,a ld a,c swap a and %11110000 ld e,a ;hl = $c000 ld hl,backBuffer .next_tile ;tiles 128-255 are in VRAM shared between sprites and tiles ;and do not need to be copied. ld a,c cp 128 jr nc,.after_copy push bc ld c,1 ;1*16 bytes ld a,1 ;VRAM bank 1 call VMemCopy pop bc .after_copy ;de+=16, hl+=16 call AddHL16 call AddDE16 ;tileNum++, tilesRemaining-- inc c dec b jr nz,.next_tile pop hl pop de pop bc ret IF 0 push bc push de push hl ld b,a ld l,c call TileIndexLToAddressHL .next_tile ld a,h cp $90 jr c,.no_copy_necessary ;dest addr = source addr - $1000 ld a,h sub $10 ld d,a ld e,l ;source addr ld hl,$c000 ld c,16 .copy ld a,[hl+] ld [de],a inc de dec c jr nz,.copy jr .after_copy .no_copy_necessary ld de,16 add hl,de .after_copy dec b jr nz,.next_tile pop hl pop de pop bc ret ENDC ;--------------------------------------------------------------------- ; Routine: GenerateFacings ; Arguments: a - index (0-255) of the first of two consecutive ; tiles (frame1 and frame2) which should be facing ; east. Tiles should be located at $c000 ; (backBuffer). ; [curObjWidthHeight] - copy of FG attribute flags ; Description: Creates the following tiles at $9000-$97ff (indices ; 0-127) and $8800-$8fff (128-255): ; a - North facing, frame 1 ; a+1 - Top half of North facing, frame 2 ; a+2 - Bottom half of North facing, frame 2 ; a+3...a+5 - East facing (frame1, left frame2, right ; frame2) ; ; Duplicates any tiles in area $9000-$9800 into ; $8000-$8800 for tile<->sprite purposes ;--------------------------------------------------------------------- GenerateFacings:: push af push bc push de push hl ld c,a ;starting index ldio a,[curObjWidthHeight] ;retrieve flags bit BIT_2X2,a jr z,.generate1x1 jp .generate2x2 .generate1x1 ld a,[curObjWidthHeight] ;attribute flags bit BIT_NOROTATE,a jr nz,.createNonRotatedSprites .createRotatedSprites ;create non-split frames for sprites ld e,0 ;source index ld l,2 ;dest index call TileCopyRotateCCW inc e inc l call TileCopyRotateCCW jr .copyTilesToSpriteMem .createNonRotatedSprites ;create non-split frames for sprites ld e,0 ;source index ld l,2 ;dest index call TileCopy inc e inc l call TileCopy .copyTilesToSpriteMem ld a,4 call DuplicateTilesToSpriteMem ;East-facing frames ld e,0 ;source index in e ld l,3 ;dest index in l call TileCopy inc e ;source to next frame inc l ;set dest index to next frame call TileCopyShiftRight inc l call TileCopyShiftLeft ld a,[curObjWidthHeight] ;attribute flags bit BIT_NOROTATE,a jr nz,.copyNorthNoRotate ;North facings ld l,0 ;dest is +0 (North) ld e,3 ;Set source ptr to +3 (East) call TileCopyRotateCCW inc e inc l inc l call TileCopyRotateCCW inc e dec l call TileCopyRotateCCW jr .copyBufferToVMem .copyNorthNoRotate ld e,1 ld l,6 call TileCopy ld e,6 ld l,1 call TileCopyShiftDown inc l call TileCopyShiftUp .copyBufferToVMem ;Copy 6 tiles beginning at $c000+ to $9000+(c*16). ;Next location after $97f0 is $8800. ld a,c cp 122 ;122+6 < 128 jr c,.copySet ;to $9000+ cp 128 jr nc,.copySet ;to $8800+ .copyOneByOne ;split across different banks ld e,c call TileIndexEToAddressDE ;destination ld hl,$c000 ;source ld b,6 ;tiles to copy ld c,1 ;copy 16 bytes at a time .nextTile ld a,1 ;VRAM Bank 1 call VMemCopy call AddDE16 call AddHL16 ld a,d cp $98 jr nz,.destPtrOkay ld d,$88 .destPtrOkay dec b jr nz,.nextTile jp .done .copySet ld e,a call TileIndexEToAddressDE ld hl,$c000 ld c,6 ;6*16 ld a,1 call VMemCopy jp .done .generate2x2 ;East-facing 2x2 ld e,0 ;source index in e ld l,10 ;dest index in l call TileCopy inc e inc l call TileCopy inc e inc l call TileCopy inc e inc l call TileCopy inc e inc l call TileCopyShiftRight inc l call TileCopyShiftLeft inc e call TileCopyShiftRightOverlay inc l call TileCopyShiftLeft inc e inc l call TileCopyShiftRight inc l call TileCopyShiftLeft inc e call TileCopyShiftRightOverlay inc l call TileCopyShiftLeft ld e,10 ld l,2 call TileCopyRotateCCW inc e ld l,0 call TileCopyRotateCCW inc e ld l,3 call TileCopyRotateCCW inc e ld l,1 call TileCopyRotateCCW inc e ld l,8 call TileCopyRotateCCW inc e ld l,6 call TileCopyRotateCCW inc e ld l,4 call TileCopyRotateCCW inc e ld l,9 call TileCopyRotateCCW inc e ld l,7 call TileCopyRotateCCW inc e ld l,5 call TileCopyRotateCCW ;Copy 20 tiles beginning at $c000+ to $9000+(c*16). ;Next location after $97f0 is $8800. ld a,c cp 108 ;108+20 < 128 jr c,.copySet20 ;to $9000+ cp 128 jr nc,.copySet20 ;to $8800+ .copyOneByOne20 ;split across different banks ld e,c call TileIndexEToAddressDE ;destination ld hl,$c000 ;source ld b,20 ;tiles to copy ld c,1 ;copy 16 bytes at a time .nextTile20 ld a,1 ;VRAM Bank 1 call VMemCopy call AddDE16 call AddHL16 ld a,d cp $98 jr nz,.destPtrOkay20 ld d,$88 .destPtrOkay20 dec b jr nz,.nextTile20 jr .done .copySet20 ld e,a call TileIndexEToAddressDE ld hl,$c000 ld c,20 ;20*16 ld a,1 call VMemCopy jp .done .done pop hl pop de pop bc pop af ret SECTION "Graphics",ROM0 ;--------------------------------------------------------------------- ; Routine: LoadGraphics ; Arguments: ;--------------------------------------------------------------------- LoadGraphics: ld a,BANK(BGTiles) call SetActiveROM ;switch to vram bank 1 ld a,1 ;ld [$ff4f],a call .loadBlank ;switch to vram bank 0 xor a ;ld [$ff4f],a call .loadBlank ;load 86 explosion sprites ld a,MAP0ROM call SetActiveROM xor a ld c,86 ;#sprites ld de,$8000 ld hl,explosionSprites call VMemCopy IF 0 ;load 80 explosion sprites ld a,MAP0ROM call SetActiveROM ld hl,explosionSprites ld de,$8000 ld b,80 ;# sprites .outer ld c,16 ;16 bytes each .inner ld a,[hl+] ld [de],a inc de dec c jr nz,.inner dec b jr nz,.outer ENDC ret .loadBlank ;load a blank tile to tile 0 of VRAM bank "a" ;xor a ld c,1 ;1 tile ld de,$9000 ld hl,BGTiles ;1st tile is blank call VMemCopy ret IF 0 ld hl,blankTile ;address to get graphics from ld de, $9000 ;destination address (Tile VRAM) ld c, 1 * 16 ;copy 1 tile of 16 bytes .loop ld a,[hl+] ld [de],a inc de dec c jr nz,.loop ret ENDC ;--------------------------------------------------------------------- ; Routine: LoadSprites ; Arguments: a - ROM bank containing sprites ; c - number of sprites to load ; hl - starting addr of sprites to load ; de - dest addr of sprites to load ; Alters: af ; Description: Loads specified number of sprites to VRAM bank 0 ; specified location. Switches back to CLASSROM when ; done. Must be done on VBLANK or when display is off ;--------------------------------------------------------------------- LoadSprites:: push bc push de push hl call SetActiveROM xor a ;VRAM bank 0 ld [$ff4f],a .outer ld b,16 ;copy 16 bytes .inner ld a,[hl+] ld [de],a inc de dec b jr nz,.inner dec c jr nz,.outer ld a,CLASSROM call SetActiveROM pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: PrepareForInitialMapDraw ; Description: Sets relevant variables so the map can be drawn ;--------------------------------------------------------------------- PrepareForInitialMapDraw:: call AdjustCameraToHero call RestrictCameraToBounds ld hl,mapLeft ld a,[desiredMapLeft] ld [hl+],a ;mapLeft add 20 ld [hl+],a ;mapRight inc a ld [hl+],a ;mapRightPlusOne ld a,[desiredMapTop] ld [hl+],a ;mapTop add 18 ld [hl+],a ;mapBottom inc a ld [hl+],a ;mapBottomPlusOne xor a ld [curPixelOffset_x],a ld [curPixelOffset_y],a ld [desiredPixelOffset_x],a ld [desiredPixelOffset_y],a ld [scrollAccelState_x],a ld [scrollAccelState_y],a ;set up a table for speedy AI ;east offset is +1 ld a,1 ld [mapOffsetEast],a ;low byte xor a ld [mapOffsetEast+1],a ;high byte ;west offset is -1 ld a,$ff ld [mapOffsetWest],a ld [mapOffsetWest+1],a ;south offset is +pitch xor a ld [mapOffsetSouth+1],a ld a,[mapPitch] ld [mapOffsetSouth],a ;north offset is -pitch cpl inc a ld [mapOffsetNorth],a ld a,$ff ld [mapOffsetNorth+1],a ret ;--------------------------------------------------------------------- ; Routine: AdjustCameraToHero ; Arguments: None. ; Description: Centers camera on hero, then adjusts so that maximum ; amount of space on in all 4 directions is visible ; ;--------------------------------------------------------------------- AdjustCameraToHero:: ld a,[displayType] or a jr z,.mapType ;cinema type xor a ld [camera_i],a ld [camera_j],a ret .mapType push bc push de push hl ld a,OBJBANK ;Get Location of hero ld [$ff70],a ;hl = &heroX_object LDHL_CURHERODATA HERODATA_OBJ ld a,[hl+] ld e,a ld a,[hl] ld d,a ld a,[de] ld l,a ld [tempL],a inc de ld a,[de] ld h,a ld [tempH],a call ConvertLocHLToXY ;convert to x,y indices ld a,h ld [camera_i],a ld a,l ld [camera_j],a ld a,MAPBANK ld [$ff70],a ldio a,[firstMonster] ld c,a ;c class of first monster ;find nearest wall to the north of location ld a,[tempL] ;hl will track location ld l,a ld a,[tempH] ld h,a ld b,0 ;b will track north offset ld d,$ff ;de = -pitch ld a,[mapPitch] cpl add 1 ld e,a push hl .nloop add hl,de inc b ld a,[hl] or a jr z,.nloop ;nothing at all here cp c ;found something, check if monster jr nc,.nloop ;don't count monsters call GetBGAttributes and (BG_FLAG_WALKOVER|BG_FLAG_SHOOTOVER) ld a,MAPBANK ldio [$ff70],a jr nz,.nloop ;b is tile distance of closest wall to the north pop hl ;retrieve original location push bc ;save north count b ld b,0 ;b counts clear tiles to south ld d,0 ;de is offset to go south ld a,[mapPitch] ld e,a push hl ;push original location again .sloop add hl,de inc b ld a,[hl] or a jr z,.sloop cp c jr nc,.sloop call GetBGAttributes and (BG_FLAG_WALKOVER|BG_FLAG_SHOOTOVER) ld a,MAPBANK ldio [$ff70],a jr nz,.sloop ;now b is distance of closest wall to south pop hl ;retrieve original location ld a,b pop bc ;retrieve north distance ld c,a ;b=north, c=south dist ;---------------Scroll Camera South--------------------------- ;while(s_dist >= 10 && n_dist<8){ ; move camera to south; ; south dist--; ; north dist++; ;} .cam_south_loop ld a,c ;s_dist >= 10? cp 10 jr c,.cam_south_loopDone ld a,b cp 7 jr nc,.cam_south_loopDone ;n_dist < 8? call .moveCameraSouth jr .cam_south_loop .cam_south_loopDone ;---------------Scroll Camera North--------------------------- ;while(n_dist >= 9 && s_dist<9){ ; move camera to north; ; south dist++; ; north dist--; ;} .cam_north_loop ld a,b ;n_dist >= 9? cp 9 jr c,.cam_north_loopDone ld a,c cp 9 jr nc,.cam_north_loopDone ;s_dist < 9? call .moveCameraNorth jr .cam_north_loop .cam_north_loopDone ld a,c ;save distances for later use ld [distToWall_S],a ld a,b ld [distToWall_N],a ;---------------------------- ; Handle east/west scrolling ;---------------------------- ld b,0 ;b counts clear tiles to west ld d,h ;save hl in de ld e,l ldio a,[firstMonster] ld c,a dec hl .wloop inc b ld a,[hl-] ;get location or a jr z,.wloop ;loop if empty cp c jr nc,.wloop ;loop if monster call GetBGAttributes and (BG_FLAG_WALKOVER|BG_FLAG_SHOOTOVER) ld a,MAPBANK ldio [$ff70],a jr nz,.wloop ;now b is distance of closest wall to west ld h,d ;set hl back to original location ld l,e ld d,b ;store west distance in d ld b,0 inc hl .eloop inc b ld a,[hl+] ;get location or a jr z,.eloop ;loop if empty cp c jr nc,.eloop ;loop if monster call GetBGAttributes and (BG_FLAG_WALKOVER|BG_FLAG_SHOOTOVER) ld a,MAPBANK ldio [$ff70],a jr nz,.eloop ;now b is distance of closest wall to east ld c,b ;b=west, c=east dist ld b,d ;---------------Scroll Camera East---------------------------- ;while(e_dist >= 11 && w_dist<9){ ; move camera to east; ; east dist--; ; west dist++; ;} .cam_east_loop ld a,c ;e_dist >= 11? cp 11 jr c,.cam_east_loopDone ld a,b cp 9 jr nc,.cam_east_loopDone ;w_dist < 10? ld a,[camera_i] inc a ld [camera_i],a dec c inc b jr .cam_east_loop .cam_east_loopDone ;---------------Scroll Camera West---------------------------- ;while(w_dist >= 10 && e_dist<10){ ; move camera to west; ; east dist++; ; west dist--; ;} .cam_west_loop ld a,b ;w_dist >= 10? cp 10 jr c,.cam_west_loopDone ld a,c cp 9 jr nc,.cam_west_loopDone ;e_dist < 10? ld a,[camera_i] dec a ld [camera_i],a inc c dec b jr .cam_west_loop .cam_west_loopDone ld a,c ;save distances for later use ld [distToWall_E],a ld a,b ld [distToWall_W],a .done pop hl pop de pop bc ret .moveCameraSouth ld a,[camera_j] inc a ld [camera_j],a dec c inc b ret .moveCameraNorth ld a,[camera_j] dec a ld [camera_j],a inc c dec b ret ;--------------------------------------------------------------------- ; Routine: GentleCameraAdjust ; Arguments: None. ; Description: Adjusts the camera to the hero but then goes with the ; old camera position if it doesn't make much difference ;--------------------------------------------------------------------- GentleCameraAdjust:: ld a,[displayType] or a ret nz ;done if cinema display type push bc push de push hl ;save previous camera i,j ld a,[camera_i] ld b,a ld a,[camera_j] ld c,a push bc call AdjustCameraToHero pop bc ;retrieve old camera coords ld a,[camera_i] cp b jr z,.checkCamera_j ;new_i==old_i, don't bother jr c,.new_i_lt_old_i ;new i > old i sub b ;d = new_i - old_i ld d,a ld a,[distToWall_E] ;a = dist_E + offset add d cp 11 jr c,.useOldCamera_i ;only good if east dist < 11 jr .checkCamera_j .new_i_lt_old_i ;new i < old i sub b ;d = old_i - new_i cpl inc a ld d,a ld a,[distToWall_W] add d cp 9 jr c,.useOldCamera_i ;only good if west dist < 10 jr .checkCamera_j .useOldCamera_i ;we can use the old camera pos and be less jerky ld a,b ld [camera_i],a .checkCamera_j ld a,[camera_j] cp c jr z,.done ;new_j==old_j, don't bother jr c,.new_j_lt_old_j ;new j > old j sub c ;d = new_j - old_j ld d,a ld a,[distToWall_S] ;a = dist_S + offset add d cp 10 jr c,.useOldCamera_j ;only good if south dist < 10 jr .done .new_j_lt_old_j ;new j < old j sub c ;d = old_j - new_j cpl inc a ld d,a ld a,[distToWall_N] add d cp 9 jr c,.useOldCamera_j ;only good if north dist < 9 jr .done .useOldCamera_j ;we can use the old camera pos and be less jerky ld a,c ld [camera_j],a .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: RestrictCameraToBounds ; Arguments: None. ;--------------------------------------------------------------------- RestrictCameraToBounds:: ld a,[displayType] or a jr nz,.cinemaType push hl ;set map left/right based on camera_i ld a,[camera_i] sub 9 jr z,.left_le_0 jr nc,.left_gt_0 .left_le_0 ld a,1 ;set to 1 if < 1 .left_gt_0 ld hl,mapMaxLeft cp [hl] jr z,.left_le_max jr c,.left_le_max ld a,[hl] ;left = maxLeft .left_le_max ld [desiredMapLeft],a ;now see about top/bottom boundaries using camera_j ld a,[camera_j] sub 8 jr z,.top_le_0 jr nc,.top_gt_0 .top_le_0 ld a,1 ;set to one if less than one .top_gt_0 ld hl,mapMaxTop cp [hl] jr z,.top_le_max jr c,.top_le_max ld a,[hl] ;top = maxTop .top_le_max ld [desiredMapTop],a pop hl ret .cinemaType push hl ;set map left/right based on camera_i ld a,[camera_i] sub 9 jr z,.left_ge_0 jr nc,.left_ge_0 .left_lt_0 xor a ;set to 0 if < 0 .left_ge_0 ld hl,mapMaxLeft cp [hl] jr z,.left_le_max2 jr c,.left_le_max2 ld a,[hl] ;left = maxLeft .left_le_max2 ld [desiredMapLeft],a ;now see about top/bottom boundaries using camera_j ld a,[camera_j] sub 8 jr z,.top_ge_0 jr nc,.top_ge_0 .top_lt_0 xor a ;set to zero if less than zero .top_ge_0 ld hl,mapMaxTop cp [hl] jr z,.top_le_max2 jr c,.top_le_max2 ld a,[hl] ;top = maxTop .top_le_max2 ld [desiredMapTop],a pop hl ret ;--------------------------------------------------------------------- ; Routine: ScrollToCamera ; Description: Scrolls from old camera view to new camera position. ; Increments of 2 pixels if difference < 4 tiles, ; increments of 4 pixels if >= 4 tiles ; Update: Uses [scrollSpeed][7:4] for fast, [3:0] slow ; instead of 4 and 2. ;--------------------------------------------------------------------- ScrollToCamera:: push bc push de push hl ;calculate tiles different in x & store in d ld a,[mapLeft] ld b,a ld a,[desiredMapLeft] sub b jr nc,.gotPositiveXDiff cpl inc a .gotPositiveXDiff ld d,a ;calculate tiles different in y & store in e ld a,[mapTop] ld b,a ld a,[desiredMapTop] sub b jr nc,.gotPositiveYDiff cpl inc a .gotPositiveYDiff ld e,a ;setup d,e with x-pixel step-size and max value push de ld a,d cp FAST_SCROLL_THRESHOLD jr c,.setupXForSlow ld a,[scrollAccelState_x] or a jr z,.setupXForSlow ;get fast scroll speed in 9 ldio a,[scrollSpeed] swap a and $0f ld d,a ;ld a,8 ;sub d ;ld e,a ;ld d,4 ;ld e,4 ;ld a,[desiredPixelOffset_x] ;make sure its a multiple of 4 ;and %00000100 ;ld [desiredPixelOffset_x],a jr .checkLeft .setupXForSlow ;get slow scroll speed in d ldio a,[scrollSpeed] and $0f ld d,a .checkLeft ;make sure current pixel offset is an even multiple of the speed ;offset &= ~(speed - 1) ;off mask off dec cpl ;1 - and %111 0001 0000 1111 ;2 - and %110 0010 0001 1110 ;4 - and %100 0100 0011 1100 ;8 - and %000 1000 0111 1000 ld a,d dec a ;first scroll sprites right by value to be masked off ld e,a ld hl,desiredPixelOffset_x ld a,[hl] and e push de ld d,a call ScrollSpritesRight pop de ld a,e cpl and %00000111 ld e,a ld a,[hl] and e ld [hl],a ld a,8 sub d ld e,a ;ld a,[desiredPixelOffset_x] ;make sure its a multiple of 4 ;and %00000100 ;ld [desiredPixelOffset_x],a ld a,[mapLeft] ld b,a ld a,[desiredMapLeft] cp b jr z,.checkPixelOffset jr c,.desired_lt_current jr .desired_gt_current .checkPixelOffset ld a,[desiredPixelOffset_x] or a jr z,.x_offsetOkay push af ld a,[scrollSprites] or a jr z,.afterScrollRight1 call ScrollSpritesRight .afterScrollRight1 pop af jr .scrollPixelsLeft .x_offsetOkay ;reset accelleration if no scroll xor a ld [scrollAccelState_x],a jr .leftRightAdjustDone .desired_gt_current ;desired is > current ld a,[scrollSprites] or a jr z,.afterScrollSpritesLeft1 call ScrollSpritesLeft .afterScrollSpritesLeft1 ld a,[desiredPixelOffset_x] cp e jr nc,.atMaxLeftPixelOffset add d ld [desiredPixelOffset_x],a jr .leftRightAdjustDone .atMaxLeftPixelOffset ld hl,scrollAccelState_x inc [hl] xor a ld [desiredPixelOffset_x],a ld a,b inc a jr .recalcMapLeftRight .desired_lt_current ld a,[scrollSprites] or a jr z,.afterScrollSpritesRight2 call ScrollSpritesRight .afterScrollSpritesRight2 ld a,[desiredPixelOffset_x] or a jr z,.atMinLeftPixelOffset .scrollPixelsLeft sub d ld [desiredPixelOffset_x],a or a jr nz,.leftRightAdjustDone ld hl,scrollAccelState_x inc [hl] jr .leftRightAdjustDone .atMinLeftPixelOffset ld a,e ld [desiredPixelOffset_x],a ld a,b dec a .recalcMapLeftRight ld hl,mapLeft ld [hl+],a ;mapLeft, mapRight, mapRight+1 add 20 ld [hl+],a inc a ld [hl+],a .leftRightAdjustDone ;setup d,e with y-pixel step-size and max value pop de ld a,e cp FAST_SCROLL_THRESHOLD jr c,.setupYForSlow or a jr z,.setupYForSlow ldio a,[scrollSpeed] swap a and $0f ld d,a ld a,8 sub d ld e,a ;ld d,4 ;ld e,4 ;ld a,[desiredPixelOffset_y] ;make sure its a multiple of 4 ;and %00000100 ;ld [desiredPixelOffset_y],a jr .checkTop .setupYForSlow ldio a,[scrollSpeed] and $0f ld d,a ld a,8 sub d ld e,a ;ld d,2 ;ld e,6 .checkTop ;make sure current pixel offset is an even multiple of the speed ;offset &= ~(speed - 1) ;1 - and %111 0001 0000 1111 ;2 - and %110 0010 0001 1110 ;4 - and %100 0100 0011 1100 ;8 - and %000 1000 0111 1000 ld a,d dec a ;first scroll sprites down by value to be masked off to snap ;them to the new grid ld e,a ld hl,desiredPixelOffset_y ld a,[hl] and e push de ld d,a call ScrollSpritesDown pop de ld a,e cpl and %00000111 ld e,a ld a,[hl] and e ld [hl],a ld a,8 sub d ld e,a ld a,[mapTop] ld b,a ld a,[desiredMapTop] cp b jr z,.checkPixelOffsetTB jr c,.desired_tb_lt_current jr .desired_tb_gt_current .checkPixelOffsetTB ld a,[desiredPixelOffset_y] or a jr z,.y_offsetOkay push af ld a,[scrollSprites] or a jr z,.afterScrollSpritesDown1 call ScrollSpritesDown .afterScrollSpritesDown1 pop af jr .scrollPixelsUp .y_offsetOkay ;reset accelleration if no scroll xor a ld [scrollAccelState_y],a jr .topBottomAdjustDone .desired_tb_gt_current ;desired is > current ld a,[scrollSprites] or a jr z,.afterScrollSpritesUp1 call ScrollSpritesUp .afterScrollSpritesUp1 ld a,[desiredPixelOffset_y] cp e jr nc,.atMaxTopPixelOffset add d ld [desiredPixelOffset_y],a jr .topBottomAdjustDone .atMaxTopPixelOffset ld hl,scrollAccelState_y inc [hl] xor a ld [desiredPixelOffset_y],a ld a,b inc a jr .recalcMapTopBottom .desired_tb_lt_current ld a,[scrollSprites] or a jr z,.afterScrollSpritesDown2 call ScrollSpritesDown .afterScrollSpritesDown2 ld a,[desiredPixelOffset_y] or a jr z,.atMinTopPixelOffset .scrollPixelsUp sub d ld [desiredPixelOffset_y],a or a jr nz,.topBottomAdjustDone ld hl,scrollAccelState_y inc [hl] jr .topBottomAdjustDone .atMinTopPixelOffset ld a,e ld [desiredPixelOffset_y],a ld a,b dec a .recalcMapTopBottom ld hl,mapTop ld [hl+],a ;mapTop, mapBottom, mapBottom+1 add 18 ld [hl+],a inc a ld [hl+],a .topBottomAdjustDone pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routines: ScrollSpritesLeft ; ScrollSpritesRight ; ScrollSpritesUp ; ScrollSpritesDown ; Arguments: d - pixels to scroll ; Alters: af ; Description: Scrolls each of the 40 sprites (if their y-pos!=0) ; "d" # of pixels in the desired direction. ;--------------------------------------------------------------------- ScrollSpritesLeft:: push af push bc push de push hl xor a sub d ld d,a jr ScrollSpritesLRCommon ScrollSpritesRight:: push af push bc push de push hl ScrollSpritesLRCommon: ld hl,spriteOAMBuffer ld bc,3 ld e,40 .loop ld a,[hl+] or a jr z,.afterChange ;sprite inactive ld a,[hl] add d ld [hl],a .afterChange add hl,bc dec e jr nz,.loop .done pop hl pop de pop bc pop af ret ScrollSpritesUp:: push af push bc push de push hl xor a sub d ld d,a jr ScrollSpritesUDCommon ScrollSpritesDown:: push af push bc push de push hl ScrollSpritesUDCommon: ld hl,spriteOAMBuffer ld bc,4 ld e,40 .loop ld a,[hl] or a jr z,.afterChange ;sprite inactive add d ld [hl],a .afterChange add hl,bc dec e jr nz,.loop .done pop hl pop de pop bc pop af ret ;--------------------------------------------------------------------- ; Routine: DrawMapToBackBuffer ; Description: Sets relevant variables so the map can be drawn ; Note: Uses [temp] to store tile attributes ;--------------------------------------------------------------------- DrawMapToBackBuffer:: ld a,[displayType] or a jr z,.mapType jp DrawCinemaToBackBuffer .mapType push bc push de push hl call SetupDrawCommon .outer push bc ;save vertical count "b" on stack push de ;save starting ptr to dest (hl) and source (de) push hl ;----copy 21 bg tiles into backBuffer/attributeBuffer ;save starting point, copy tile pattern numbers push de push hl ld a,MAPBANK ld [$ff70],a ld b,((bgTileMap>>8) & $ff) call .copy7BGTiles call .copy7BGTiles call .copy7BGTiles ;start over copying attributes pop hl pop de push de push hl ld a,h ;backBuffer -> attributeBuffer add 3 ld h,a ld b,((bgAttributes>>8) & $ff) call .copy7BGAttributes call .copy7BGAttributes call .copy7BGAttributes ;back to start again pop hl pop de push de push hl ;recopy FG tiles from shadow buffers ld a,TILESHADOWBANK ld [$ff70],a ldio a,[firstMonster] ld b,a call .copy7FGTiles call .copy7FGTiles call .copy7FGTiles pop hl pop de ld a,MAPBANK ld [$ff70],a ld a,h add 3 ld h,a call .copy7FGAttributes call .copy7FGAttributes call .copy7FGAttributes ;row done ;---begin old code 3-------------------------------------------------- IF 0 ;copy tile patterns & attributes for any BG tiles to --------- ;tile & attribute shadow buffers ;save starting point push de push hl ;use hl for map source / shadow buffer dest ld h,d ld l,e ;setup loop ld a,MAPBANK ld [$ff70],a ldio a,[firstMonster] ld b,a ld c,21 .copyBGTiles ld a,[hl] cp b jr c,.isBGTile inc hl dec c jr nz,.copyBGTiles jr .copyBGTilesDone .isBGTile ld d,((bgTileMap>>8) & $ff) ld e,a ld a,TILESHADOWBANK ld [$ff70],a ld a,[de] ld [hl],a ld a,ATTRSHADOWBANK ld [$ff70],a ld d,((bgAttributes>>8) & $ff) ld a,[de] and %00000111 ld [hl+],a ld a,MAPBANK ld [$ff70],a dec c jr nz,.copyBGTiles .copyBGTilesDone ;retrieve starting point & save again pop hl pop de push de push hl ;copy set of 21 bytes from TILESHADOWBANK to backBuffer ld a,TILESHADOWBANK ld [$ff70],a call .copy21 ;retrieve starting point pop hl pop de ;copy set of 21 bytes from ATTRSHADOWBANK to backBuffer ld a,h add 3 ld h,a ld a,ATTRSHADOWBANK ld [$ff70],a call .copy21 ENDC ;row done ;----end old code 3--------------------------------------------------- ;------begin old code 2----------------------------------------------- IF 0 ;copy tile pattern numbers from map/buffer to backBuffer ld a,MAPBANK ld [$ff70],a ldio a,[firstMonster] ;get index of first fg class ld b,a ld c,21 push de push hl .copyTileNumbers ld a,[de] ;next class number from map cp b jr nc,.isFGTile ;lookup tile used for background push bc ld b,((bgTileMap>>8) & $ff) ld c,a ld a,[bc] ld [hl+],a inc de pop bc dec c jr nz,.copyTileNumbers jr .setupCopyAttributes .isFGTile ;lookup class number in tile shadow buffer ;push bc ld a,TILESHADOWBANK ld [$ff70],a ld a,[de] inc de ld [hl+],a ld a,MAPBANK ld [$ff70],a dec c jr nz,.copyTileNumbers .setupCopyAttributes pop hl ;go back to start of line pop de ld a,h ;copy to attributeBuffer add 3 ld h,a ld c,21 ;loop 21 times .copyAttributes ld a,[de] ;next class number from map cp b jr nc,.isFGAttribute ;BG Attribute push bc ld b,((bgAttributes>>8) & $ff) ld c,a ld a,[bc] and %00000111 ld [hl+],a inc de pop bc dec c jr nz,.copyAttributes jr .rowDone .isFGAttribute ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ld [hl+],a inc de ld a,MAPBANK ld [$ff70],a dec c jr nz,.copyAttributes .rowDone ENDC ;------end old code 2----------------------------------------------- ;old loop code ;-------old code begin------------------------------------------------ IF 0 ld a,MAPBANK ;set RAM bank to the map bank ld [$ff70],a ld c,21 ;times to loop horizontally .inner push bc ld a,[de] ;load a tile index from level map cp b ;index of first monster jr c,.isBGTile ;< first monster .isFGTile ;retrieve FG tile info from shadow buffers parallel to main map ld a,ATTRSHADOWBANK ;set RAM bank to the attribute shadow bank ld [$ff70],a ld a,[de] ;attributes ldio [temp],a ld a,TILESHADOWBANK ;set RAM bank to the tile shadow bank ld [$ff70],a ld a,[de] ;tile to draw inc de ld [hl],a ;store tile in backBuffer ld a,MAPBANK ;set RAM bank to the map bank ld [$ff70],a jr .gotTile .isBGTile inc de or a jr z,.isNullTile ld c,a ;ld a,TILEINDEXBANK ;select RAM bank of tile index maps ;ld [$ff70],a ld b,((bgAttributes>>8)&$ff) ld a,[bc] ;attributes for this tile and %00000111 ;get palette only ldio [temp],a ;store for later ld b,((bgTileMap>>8)&$ff) ;get ptr to tile to draw in bc ld a,[bc] ;get tile to draw ld [hl],a ;store tile in backBuffer jr .gotTile .isNullTile ld [temp],a ;attributes zero ld [hl],a ;store tile in backBuffer .gotTile push hl ld a,h add 3 ;768 bytes to get from backbuffer to attr buffer ld h,a ld a,[temp] ;get attributes for this tile ld [hl],a ;store attribute in buffer pop hl ;back to map buffer .afterDrawTile inc hl ;inner loop termination test pop bc dec c jr nz,.inner ENDC ;-------old code end-------------------------------------------------- pop hl ;retrieve initial pointers pop de ld a,[mapPitch] ;mapPtr += mapPitch add e ld e,a jr nc,.hlNoCarry inc d .hlNoCarry ld a,32 ;bgTileMapPtr += 32 add l ld l,a jr nc,.deNoCarry inc h .deNoCarry ;loop the outer loop again? pop bc dec b jr nz,.outer call PostDrawCommon .done ;map is drawn, bitch ld a,MAPBANK ;set RAM bank to the map bank ld [$ff00+$70],a pop hl pop de pop bc ret .copy7BGTiles ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] ld [hl+],a ret .copy7BGAttributes ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ld a,[de] inc de ld c,a ld a,[bc] and %00000111 ld [hl+],a ret .copy7FGTiles ld a,[hl] cp b jr c,.notMonster0 ld a,[de] ;get monster tile ld [hl],a .notMonster0 inc hl inc de ld a,[hl] cp b jr c,.notMonster1 ld a,[de] ;get monster tile ld [hl],a .notMonster1 inc hl inc de ld a,[hl] cp b jr c,.notMonster2 ld a,[de] ;get monster tile ld [hl],a .notMonster2 inc hl inc de ld a,[hl] cp b jr c,.notMonster3 ld a,[de] ;get monster tile ld [hl],a .notMonster3 inc hl inc de ld a,[hl] cp b jr c,.notMonster4 ld a,[de] ;get monster tile ld [hl],a .notMonster4 inc hl inc de ld a,[hl] cp b jr c,.notMonster5 ld a,[de] ;get monster tile ld [hl],a .notMonster5 inc hl inc de ld a,[hl] cp b jr c,.notMonster6 ld a,[de] ;get monster tile ld [hl],a .notMonster6 inc hl inc de ret .copy7FGAttributes ld a,[de] cp b jr c,.fgNotMonster0 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster0 inc hl inc de ld a,[de] cp b jr c,.fgNotMonster1 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster1 inc hl inc de ld a,[de] cp b jr c,.fgNotMonster2 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster2 inc hl inc de ld a,[de] cp b jr c,.fgNotMonster3 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster3 inc hl inc de ld a,[de] cp b jr c,.fgNotMonster4 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster4 inc hl inc de ld a,[de] cp b jr c,.fgNotMonster5 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster5 inc hl inc de ld a,[de] cp b jr c,.fgNotMonster6 ld a,ATTRSHADOWBANK ld [$ff70],a ld a,[de] ;get monster tile ld [hl],a ld a,MAPBANK ld [$ff70],a .fgNotMonster6 inc hl inc de ret IF 0 ;loop unrolled for max speed .copy21 ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ld a,[de] inc de ld [hl+],a ret ENDC SetupDrawCommon: ;set VRAM bank to zero ld a,MAPBANK ld [$ff00+$4f],a ;find address to start getting tile indices from ld a,[mapPitchMinusOne] ld c,a ld a,[mapTop] ld e,a xor a .jTimesPitch sla e ;times two rla ;carry from low bit into high bit srl c ;c is pitch-1, counter of how many times to shift jr nz,.jTimesPitch ld d,a ;high byte into d; de is now == j * pitch ld a,[mapLeft] add e ld e,a ;de is now (j*pitch) + i ld hl,map ;add in base address of map add hl,de ld d,h ld e,l ;get memory address of backBuffer in hl ld hl,backBuffer ;start looping ld b,19 ;times to loop vertically ret PostDrawCommon: ;if the map is scrolled as far as possible right and/or down we ;need to clear the right and/or bottom border so the jiggle effect ;won't look goofy ld a,[mapMaxLeft] ld b,a ld a,[mapLeft] cp b jr c,.rightBorderOkay ;set up vertical loop clearing tiles to zero ld hl,(backBuffer + 20) ld de,32 ld c,19 xor a .vloop ld [hl],a add hl,de dec c jr nz,.vloop .rightBorderOkay ;does bottom border need clearing? ld a,[mapMaxTop] ld b,a ld a,[mapTop] cp b jr c,.done ;set up horizontal loop clearing tiles to zero ld hl,(backBuffer + (32*18)) ld c,21 xor a .hloop ld [hl+],a dec c jr nz,.hloop .done ret ;--------------------------------------------------------------------- ; Routine: DrawCinemaToBackBuffer ; Alters: af ; Description: Sets relevant variables so the map can be drawn ; Note: Uses [temp] to store tile attributes ;--------------------------------------------------------------------- DrawCinemaToBackBuffer:: push bc push de push hl call SetupDrawCommon .outer push de ;save starting ptr to dest (hl) and source (de) push hl ld c,21 ;times to loop horizontally .inner push bc ;retrieve tile info from shadow buffers parallel to main map ld a,ATTRSHADOWBANK ;set RAM bank to the attribute shadow bank ld [$ff70],a ld a,[de] ;attributes ldio [temp],a ld a,TILESHADOWBANK ;set RAM bank to the tile shadow bank ld [$ff70],a ld a,[de] ;tile to draw inc de ld [hl],a ;store tile in backBuffer push hl ld a,h add 3 ;768 bytes to get from backbuffer to attr buffer ld h,a ld a,[temp] ;get attributes for this tile ld [hl],a ;store attribute in buffer pop hl ;back to map buffer .afterDrawTile inc hl ;inner loop termination test pop bc dec c jr nz,.inner pop hl ;retrieve initial pointers pop de ld a,[mapPitch] ;mapPtr += mapPitch add e ld e,a jr nc,.hlNoCarry inc d .hlNoCarry ld a,32 ;bgTileMapPtr += 32 add l ld l,a jr nc,.deNoCarry inc h .deNoCarry ;loop the outer loop again? dec b jr nz,.outer call PostDrawCommon .done ;map is drawn, bitch ld a,MAPBANK ;set RAM bank to the map bank ld [$ff00+$70],a pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: ShowTitle ; Arguments: de - pointer to text ; Description: Shows the text centered on-screen and waits until ; the user presses a button to continue. ; Alters: a,hl ;--------------------------------------------------------------------- ShowTitle:: push bc ld a,[de] ;length of text inc de ld c,a ld hl,spriteOAMBuffer+3 .loop xor a ;sprite attributes ld [hl-],a ld a,[de] ;letter inc de ld [hl-],a ld a,16 ;calculate x coordinate sub c sla a ;times 8 for pixels sla a sla a ld [hl-],a ;y coordinate ld a,80 ld [hl],a ld a,l ;add 7 to hl add 7 ld l,a ld a,h adc 0 ld h,a dec c jr nz,.loop pop bc ret ;--------------------------------------------------------------------- ; Routines: SetSpeakerToFirstHero ; Arguments: None. ; Returns: c - index of first hero present ; [dialogSpeakerIndex] ; [dialogJoyIndex] ; Alters: af, c ; Description: Finds the first hero on the map and sets up ; some dialog parameters based on who it is. ;--------------------------------------------------------------------- SetSpeakerToFirstHero:: push de push hl xor a ld hl,hero0_index call .setParameters or a jr nz,.done ld a,1 ld hl,hero1_index call .setParameters .done pop hl pop de ret .setParameters ld [dialogJoyIndex],a ld a,[hl-] ;get hero index or a ;non-zero? ret z ;not present ld c,a ;class index ld de,HERODATA_TYPE add hl,de ld a,[hl] ld [dialogSpeakerIndex],a ;flag indicating speaker ld a,1 ;operation successful ret ;--------------------------------------------------------------------- ; Routines: SetSpeakerFromHeroIndex ; Arguments: c - index of speaking hero ; Returns: [dialogSpeakerIndex] ; [dialogJoyIndex] ; Alters: af ; Description: ;--------------------------------------------------------------------- SetSpeakerFromHeroIndex:: push de push hl ld hl,hero0_index ld a,[hl-] cp c ld a,0 jr nz,.setHero1 call .setParameters jr .done .setHero1 ld a,1 ld hl,hero1_data call .setParameters .done pop hl pop de ret .setParameters ld [dialogJoyIndex],a ld de,HERODATA_TYPE add hl,de ld a,[hl] ld [dialogSpeakerIndex],a ;flag indicating speaker ret ;--------------------------------------------------------------------- ; Routine: SetPressBDialog ;--------------------------------------------------------------------- SetPressBDialog: ld a,DLG_BORDER | DLG_PRESSB ld [dialogSettings],a ret ;--------------------------------------------------------------------- ; Routine: SetDialogJoy:: ; Arguments: None. ; Returns: hl - pointer to appropriate joy inputs ; Alters: af,hl ;--------------------------------------------------------------------- SetDialogJoy:: ld a,[displayType] cp 1 jr z,.cinemaType ld a,[canJoinMap] cp 2 ;asynchronous join? jr z,.cinemaType ld hl,curInput0 ld a,[dialogJoyIndex] or a ret z inc hl ret .cinemaType ld hl,myJoy ret ;--------------------------------------------------------------------- ; Routine: CheckDialogContinue ; Arguments: None. ; Returns: a - 1 if done (B is pressed), 0 if not done ; Alters: af ; Description: Calls CheckDialogSkip and then sees if button B of ; the speaker's joystick is pressed. ;--------------------------------------------------------------------- CheckDialogContinue:: push hl call CheckSkip call SetDialogJoy ld a,[dialogSettings] and DLG_WAITRELEASE jr nz,.waitRelease ld a,[hl] and JOY_B jr z,.returnFalse ld hl,dialogSettings set DLG_WAITRELEASE_BIT,[hl] jr .returnFalse .waitRelease ld a,[hl] and JOY_B jr nz,.returnFalse ld hl,dialogSettings res DLG_WAITRELEASE_BIT,[hl] bit DLG_CLEARSKIP_BIT,[hl] jr z,.afterClearSkip res DLG_CLEARSKIP_BIT,[hl] push hl ld de,0 call SetDialogSkip pop hl .afterClearSkip bit DLG_NOCLEAR_BIT,[hl] res DLG_NOCLEAR_BIT,[hl] jr nz,.returnTrue call ClearDialog .returnTrue ld a,1 jr .done .returnFalse xor a .done pop hl ret ;--------------------------------------------------------------------- ; Routines: ShowDialogAtTop ; ShowDialogAtTopNoWait ; ShowDialogAtBottom ; ShowDialogAtBottomNoWait ; ClearDialog ; Arguments: [dialogBank] - bank containing text ; c - class index of speaking character ; de - pointer to gtx text ; Description: Shows the text centered at the top or bottom dialog ; bar & waits until the user presses a button to ; continue. ; Alters: none ; Note: Format of gtx: ; BYTE number of lines ; REPT[nLines]: ; BYTE spaces to center ; BYTE num chars in line ; BYTE[nChars] characters ;--------------------------------------------------------------------- ShowDialogNPC:: ld a,[dialogNPC_heroIndex] ld c,a call SetSpeakerFromHeroIndex ld a,[dialogNPC_speakerIndex] ld c,a call ShowDialogAtTop call ClearDialog ret ShowDialogHero:: ld a,[dialogNPC_heroIndex] ld c,a call SetSpeakerFromHeroIndex call ShowDialogAtBottom call ClearDialog ret ShowDialogAtTop:: ld a,[dialogBank] push af push bc push de push hl call ChooseFromDialogAlternates ld b,0 ;lines to skip at top call ShowDialogCommon call ShowDialogAtTopCommon call ShowDialogWait pop hl pop de pop bc pop af ret ShowDialogAtTopNoWait:: ld a,[dialogBank] push af push bc push de push hl call ChooseFromDialogAlternates ld b,0 ;lines to skip at top call ShowDialogCommon call ShowDialogAtTopCommon pop hl pop de pop bc pop af ret ShowDialogAtTopCommon:: call DrawDialogBorderAtBottom call GfxBlitBackBufferToWindow xor a ldh [$ff4a], a ;set window y position ld a,[de] ;number of lines rlca ;times 8 = pixels for window rlca rlca add 7 ld [hblankWinOff],a ld a,143 ld [hblankWinOn],a ld a,[hblankFlag] bit 1,a jr nz,.afterSetLYC ld a,143 ld [$ff45],a ;lyc ld a,[hblankFlag] .afterSetLYC or %10 ;allow window to show ld [hblankFlag],a ld a,OBJROM call SetActiveROM ret ShowDialogAtBottom:: ld a,[dialogBank] push af push bc push de push hl call ChooseFromDialogAlternates ld b,1 ;lines to skip at top call ShowDialogCommon call ShowDialogAtBottomCommon call ShowDialogWait pop hl pop de pop bc pop af ret ShowDialogAtBottomNoWait:: ld a,[dialogBank] push af push bc push de push hl call ChooseFromDialogAlternates ld b,1 ;lines to skip at top call ShowDialogCommon call ShowDialogAtBottomCommon pop hl pop de pop bc pop af ret ShowDialogAtBottomCommon:: call DrawDialogBorderAtTop call GfxBlitBackBufferToWindow ld a,143 ld [hblankWinOff],a ;set window y pos. Req'd for actual GBC, not emulator ld a,[de] ;# lines cpl add 1+17 ;(max lines) - (text lines+1) rlca rlca rlca ;times 8 ldh [$ff4a], a ;set window y position ld a,[de] ;number of lines rlca ;times 8 = pixels for window rlca rlca add 8 cpl ;make negative (+1), subtract from 143 add 144 ;+1 2's compl, +143 ld [hblankWinOn],a ld a,[hblankFlag] bit 1,a jr nz,.afterSetLYC ld a,[hblankWinOn] ld [$ff45],a ;lyc ld a,[hblankFlag] .afterSetLYC or %10 ;allow window to show ld [hblankFlag],a ld a,OBJROM call SetActiveROM ret ClearDialog:: push af xor a ld [amShowingDialog],a ld a,[hblankFlag] ;turn off dialog box and window and %11111101 ld [hblankFlag],a call VWait ;call InstallGamePalette ld a,1 ldio [paletteBufferReady],a call VWait pop af ret ShowDialogWait:: ;change both heroes to idle ld a,[heroesIdle] push af ld a,1 ld [heroesIdle],a call .waitInputZero .wait call UpdateObjects call RedrawMap call CheckDialogContinue or a jr z,.wait ;call .waitInput ;call .waitInputZero pop af ld [heroesIdle],a ret .waitInputZero DialogWaitInputZero:: call UpdateObjects call RedrawMap ld h,((curInput0>>8) & $ff) ld a,[dialogJoyIndex] add (curInput0 & $ff) ld l,a ld a,[hl] and %11110000 jr nz,DialogWaitInputZero ret ;--------------------------------------------------------------------- ; Routines: ShowDialogCommon ; Arguments: a - bank message is in ; b - lines to skip at top ; c - class index of speaking character ; de - pointer to gtx text beginning with #lines ; Description: ; Alters: af ; Note: Format of gtx: ; BYTE number of lines ; REPT[nLines]: ; BYTE spaces to center ; BYTE num chars in line ; BYTE[nChars] characters ;--------------------------------------------------------------------- ShowDialogCommon:: push de push bc ;save class index of speaking character call SetActiveROM ld a,1 ld [amShowingDialog],a ;wait until the backbuffer is blitted .waitBackBuffer ldio a,[backBufferReady] or a jr z,.canMessWithBackBuffer call VWait jr .waitBackBuffer .canMessWithBackBuffer ;clear the backbuffer and attribute buffer for given #lines ld a,[de] ;b = number of lines + 1 add 1 ld b,a ld hl,backBuffer .clearLines call ClearGTXLine push bc ld bc,32 add hl,bc pop bc dec b jr nz,.clearLines ;xor a ;.outer1 ld c,32 ;.inner1 ld [hl+],a ;dec c ;jr nz,.inner1 ;dec b ;jr nz,.outer1 ;ld a,[de] ;b = number of lines + 1 ;add 1 ;ld b,a ;ld hl,attributeBuffer ;xor a ;.outer2 ld c,32 ;.inner2 ld [hl+],a ;dec c ;jr nz,.inner2 ;dec b ;jr nz,.outer2 ;adjust hl down a line? pop bc push bc ld hl,backBuffer bit 0,b jr z,.hlOkay ld bc,32 add hl,bc .hlOkay ;for each line of text... ld a,[de] ;b = number of lines inc de ld b,a .line call WriteGTXLine ;go to next line dec b jr nz,.line ;retrieve class index of speaking character and ;blit that tile to the top-left corner of the buffer pop bc call DrawTileToTLCorner ;call GfxBlitBackBufferToWindow pop de ret ;--------------------------------------------------------------------- ; Routine: ClearGTXLine ; Arguments: ; hl - backbuffer location to draw at ; Alters: af ;--------------------------------------------------------------------- ClearGTXLine:: push bc push hl push hl ;clear backbuffer xor a ld c,32 .loop ld [hl+],a dec c jr nz,.loop ;clear attr buffer xor a pop hl ld bc,$300 add hl,bc ld c,32 .loop2 ld [hl+],a dec c jr nz,.loop2 pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: WriteGTXLine ; Arguments: de - pointer to gtx text beginning with centerSpaces ; hl - location to draw at ; Alters: hl,de ;--------------------------------------------------------------------- WriteGTXLine:: ;advance hl spaces required to center text push bc ld b,0 ld a,[de] inc de ld c,a add hl,bc ;get the char count for this line ld a,[de] inc de ld c,a or a jr z,.afterLoop ;copy the characters to the buffer .loop ld a,[de] inc de ld [hl+],a dec c jr nz,.loop .afterLoop ;advance hl to next line ld a,l and ~31 add 32 ld l,a ld a,0 adc h ld h,a pop bc ret GfxBlitBackBufferToWindow:: ;xor a ;ld c,38 ;38*16 = 608 ;ld de,$9c00 ;dest = window map memory ;ld hl,$c000 ;source ;call VMemCopy ;ret ld a,$9c ;copy to window map memory ldio [backBufferDestHighByte],a ld a,1 ldio [backBufferReady],a .vwait call VWait ldio a,[backBufferReady] ;wait until buffer is copied or a jr nz,.vwait ld a,$98 ;go back to copying to bg map memory ldio [backBufferDestHighByte],a ret GfxShowStandardTextBox:: ;set interrupt to turn window off at bottom of screen ld a,143 ld [hblankWinOff],a ;set window y pos. Req'd for actual GBC, not emulator ld a,96 ldh [$ff4a], a ;set window y position ld [hblankWinOn],a ld a,[hblankFlag] bit 1,a jr nz,.afterSetLYC ld a,[hblankWinOn] ld [$ff45],a ;lyc ld a,[hblankFlag] .afterSetLYC or %10 ;allow window to show ld [hblankFlag],a ret DrawDialogBorderAtTop: push hl ld hl,$c000 ;9c00 call DrawDialogBorder pop hl ret DrawDialogBorderAtBottom: push de push hl ld hl,$c000 ;9c00 ld a,[de] ;num lines ld d,a xor a srl d rra srl d rra srl d rra ld e,a add hl,de call DrawDialogBorder pop hl pop de ret DrawDialogBorder: push bc push hl ld a,[dialogSettings] and DLG_BORDER jr z,.done ;draw border at edge push hl ;xor a ;ldio [$ff4f],a ;VRAM bank ld c,20 ld a,252 .drawBorder ld [hl+],a dec c jr nz,.drawBorder dec hl ld a,[dialogSettings] and DLG_PRESSB jr z,.clearBG ld [hl],253 .clearBG pop hl ;clear bg attributes ld bc,$300 add hl,bc ;ld a,1 ;ldio [$ff4f],a ;VRAM bank ld c,20 xor a .clearBGLoop ld [hl+],a dec c jr nz,.clearBGLoop .done pop hl pop bc ret DrawTileToTLCorner: ;class index in c, 1 line down in b .drawTile ld hl,backBuffer bit 0,b jr z,.hlOkay ld l,32 .hlOkay ld a,c or a jr z,.useNullTile ;use null tile ld a,TILEINDEXBANK ld [$ff70],a ld b,((fgAttributes>>8) & $ff) ld a,[bc] bit 5,a ;2x2 monster? jr nz,.speaker2x2 and %00000111 or %00001000 ;coming from bank 1 ld h,((attributeBuffer>>8) & $ff) ld [hl],a ld h,((backBuffer>>8) & $ff) ld b,((fgTileMap>>8) & $ff) ld a,[bc] ;a is tile to draw add 3 ;get right-facing ld [hl],a ret .speaker2x2 and %00000111 ;color or %00001000 ;coming from bank 1 push hl push hl ld h,((attributeBuffer>>8) & $ff) ld [hl+],a ld [hl+],a push de ld de,30 add hl,de pop de ld [hl+],a ld [hl-],a ld h,((backBuffer>>8) & $ff) ld b,((fgTileMap>>8) & $ff) ld a,[bc] ;a is tile to draw add 12 ;get right-facing ld [hl+],a inc a ld [hl+],a pop hl sub 3 ld [hl+],a inc a ld [hl+],a pop hl ;kludge for two-color BRAINIAC ld a,[dialogSettings] bit DLG_BRAINIAC_BIT,a ret z res DLG_BRAINIAC_BIT,a ld [dialogSettings],a ld h,((attributeBuffer>>8) & $ff) inc hl ld a,8+3 ;green color from bank 1 ld [hl],a push de ld de,32 add hl,de pop de ld [hl+],a ret .useNullTile xor a ld [hl],a ld h,((attributeBuffer>>8) & $ff) ld [hl],a ret ;--------------------------------------------------------------------- ; Routine: ChooseFromDialogAlternates ; Arguments: de - pointer to gtx text ; Returns: de - adjusted pointer ; Alters: de ; Description: de points to start of an indeterminate number of ; byte triplets of the form: ; [mask] [offsetL] [offsetH] ; This routine finds a mask that (when ANDed) matches ; the value in [dialogSpeakerIndex] and jumps to the ; gtx alternate beginning at the given offset. The ; offset given for the cursor being at a position of ; 1 past [offsetH] of the matching triplet. ;--------------------------------------------------------------------- ChooseFromDialogAlternates: push af push bc push hl call SetActiveROM ld h,d ld l,e ld a,[dialogSpeakerIndex] ld c,a .attemptMatch ld a,[hl+] ;mask and c jr nz,.foundMatch inc hl ;skip offset to look at next mask inc hl jr .attemptMatch .foundMatch ld a,[hl+] ;retrieve offset to start of gtx proper ld e,a ld a,[hl+] ld d,a add hl,de ld d,h ld e,l pop hl pop bc pop af ret ;--------------------------------------------------------------------- ; Routine: CheckSkip ; Arguments: None. ; Returns: Nothing. ; Alters: af ; Description: Intended for use in cinemas and in-game dialog, ; resets the pc and sp to an address set with ; SetDialogSkip. Sets to the skip address if start is ; pushed, to fast-forward address if B is pushed. ;--------------------------------------------------------------------- CheckSkip:: push hl ld a,[displayType] cp 1 jr z,.cinemaType ld a,[canJoinMap] ;asynchronous join? cp 2 jr z,.cinemaType ld hl,curInput0 ld a,[dialogJoyIndex] ;0 or 1 add l ld l,a jr .afterSetJoy .cinemaType ld hl,myJoy .afterSetJoy ld a,[hl] ;get the input and JOY_START jr nz,.startPressed ld a,[hl] and JOY_B jr z,.done ;no buttons pushed .abPressed push hl ld hl,levelCheckSkip ;fast forward address jr .restore .startPressed push hl ld hl,levelCheckSkip+2 ;skip address .restore ld a,[hl] or a jr nz,.addressOkay inc hl ld a,[hl-] or a jr nz,.addressOkay pop hl jr .done .addressOkay ;make the class/object ROM the current ld a,OBJROM call SetActiveROM xor a ld e,[hl] ld [hl],a inc hl ld d,[hl] ld [hl],a pop hl cp d jr nz,.addrOkay cp e jr z,.done ;null address .addrOkay ld a,$f0 call WaitInputZero ;reset all one-shot dialog options ld hl,dialogSettings res DLG_BRAINIAC_BIT,[hl] res DLG_NOCLEAR_BIT,[hl] res DLG_CLEARSKIP_BIT,[hl] ;restore stack pointer ld a,[levelCheckStackPos] ld l,a ld a,[levelCheckStackPos+1] ld h,a ld sp,hl ;push return address on stack and go there push de ret .done pop hl ret ;--------------------------------------------------------------------- ; Routine: Delay ; Arguments: a - number of 1/60 seconds to delay ; Alters: af ; Description: Updates and displays objects for specified number of ; 1/60 seconds. Jumps to [levelCheckSkip] if start ; button is pressed if addr is non-null. ;--------------------------------------------------------------------- Delay:: push bc push de push hl .delay push af call UpdateObjects call RedrawMap call CheckSkip .keepGoing pop af dec a jr nz,.delay .waitBlit ldio a,[backBufferReady] or a jr nz,.waitBlit ;if we're in a cinema and we get a YANK from the remote player ;then we need to kill into the cinema script ld a,[timeToChangeLevel] or a jr z,.done ld a,[inLoadMethod] or a jr z,.done call BlackoutPalette ld a,[loadStackPosL] ld l,a ld a,[loadStackPosH] ld h,a ld sp,hl jp AfterLoadLevelMethod .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: GetRandomNumZeroToN ; Arguments: a - maximum desired random number "N" ; Returns: a - random number between 0 and N ; Alters: af ;--------------------------------------------------------------------- GetRandomNumZeroToN:: or a ret z push bc push hl inc a jr z,.handleFF ld b,a ;b is N PUSHROM ld a,BANK(randomTable) call SetActiveROM ld hl,randomLoc inc [hl] ld l,[hl] ld h,((randomTable>>8) & $ff) ld a,[hl] bit 7,b jr nz,.loop ;N+1>=128 ;divide raw number by two until it's less than limit*2 ld c,b sla c ;c = (limit * 2) + 1 inc c .fastReduce cp c ;a < limit*2 + 1? jr c,.loop ;yes, go to slower precision work srl a ;a/=2 jr .fastReduce .loop cp b ;subtract N while r > N jr c,.done sub b jr .loop .done ld b,a POPROM ld a,b pop hl pop bc ret .handleFF PUSHROM ld a,BANK(randomTable) call SetActiveROM ld hl,randomLoc inc [hl] ld l,[hl] ld h,((randomTable>>8) & $ff) ld a,[hl] ld b,a POPROM ld a,b pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: GetRandomNumMask ; Arguments: a - bit mask for random number ; Returns: a - random number ; Alters: af ;--------------------------------------------------------------------- GetRandomNumMask:: push bc push hl ld b,a ;b is bitmask PUSHROM ld a,BANK(randomTable) call SetActiveROM ld hl,randomLoc inc [hl] ld l,[hl] ld h,((randomTable>>8) & $ff) ld a,[hl] and b .done ld b,a POPROM ld a,b pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: SetupFadeFromWhite ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeFromWhite:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;set cur palette to be all white ld hl,fadeCurPalette call FadeCommonSetPaletteToWhite ;set final palette to be copy of current game palette ld hl,gamePalette ld de,fadeFinalPalette call FadeCommonCopyPalette pop af call FadeInit pop hl pop de pop bc ret FadeCommonSetPaletteToWhite:: ld c,64 .loop ld a,$ff ld [hl+],a ld a,$7f ld [hl+],a dec c jr nz,.loop ret CopyPalette64:: FadeCommonCopyPalette:: push bc push de push hl ld a,FADEBANK ld [$ff70],a ld c,128 .loop ld a,[hl+] ld [de],a inc de dec c jr nz,.loop pop hl pop de pop bc ret CopyPalette32:: push bc push de push hl ld a,FADEBANK ld [$ff70],a ld c,64 .loop ld a,[hl+] ld [de],a inc de dec c jr nz,.loop pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: InstallGamePalette ; Arguments: None. ; Alters: af ; Description: Sets gamePalette to be installed to the hardware ; on the next VBlank. ;--------------------------------------------------------------------- InstallGamePalette:: push hl push de ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ld a,1 ldio [paletteBufferReady],a .wait ldio a,[paletteBufferReady] ;wait for vblank to install it or a jr nz,.wait pop de pop hl ret ;--------------------------------------------------------------------- ; Routine: SetupFadeToWhite ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeToWhite:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;set final palette to be all white ld hl,fadeFinalPalette call FadeCommonSetPaletteToWhite ;set cur palette to be copy of current game palette ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette pop af call FadeInit pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: SetupFadeFromBlack ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeFromStandard:: SetupFadeFromBlack:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;set cur palette to be all white ld hl,fadeCurPalette call FadeCommonSetPaletteToBlack ;set final palette to be copy of current game palette ld hl,gamePalette ld de,fadeFinalPalette call FadeCommonCopyPalette pop af call FadeInit pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: SetupFadeToBlack ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeToStandard:: SetupFadeToBlack:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;set final palette to be all black ld hl,fadeFinalPalette call FadeCommonSetPaletteToBlack ;set cur palette to be copy of current game palette ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette pop af call FadeInit pop hl pop de pop bc ret FadeCommonSetPaletteToBlack:: ld c,64 xor a .loop ld [hl+],a ld [hl+],a dec c jr nz,.loop ret ;--------------------------------------------------------------------- ; Routine: SetupFadeFromBlackBGOnly ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeFromBlackBGOnly:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ;set cur palette to be all black ld hl,fadeCurPalette call FadeCommonSetPaletteToBlackBGOnly ;set final palette to be copy of current game palette ld hl,gamePalette ld de,fadeFinalPalette call FadeCommonCopyPalette ld a,32 ld [fadeRange],a pop af call FadeInit pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: BlackoutPalette ; Arguments: ; Alters: af ; Description: Sets fadeCurPalette and final palette to all black ;--------------------------------------------------------------------- BlackoutPalette:: push bc push de push hl ld a,FADEBANK ld [$ff70],a ld hl,fadeFinalPalette call FadeCommonSetPaletteToBlack ld hl,fadeCurPalette call FadeCommonSetPaletteToBlack ;turn off any existing fade ld hl,specialFX res 0,[hl] ;reset fade bit ;install the current palette on the next VBlank ld a,1 ldio [paletteBufferReady],a .wait ldio a,[paletteBufferReady] ;wait for vblank to install it or a jr nz,.wait pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: SetupFadeToBlackBGOnly ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeToBlackBGOnly:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ld hl,gamePalette ld de,fadeFinalPalette call FadeCommonCopyPalette ;set final palette BG Colors to be all black ld hl,fadeFinalPalette call FadeCommonSetPaletteToBlackBGOnly ;set cur palette to be copy of current game palette ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ld a,32 ld [fadeRange],a pop af call FadeInit pop hl pop de pop bc ret FadeCommonSetPaletteToBlackBGOnly:: ld c,32 xor a .loop ld [hl+],a ld [hl+],a dec c jr nz,.loop ret ;--------------------------------------------------------------------- ; Routine: SetupFadeFromSaturated ; Arguments: a - steps ; b - amount of saturation (white) to start at ; Alters: af ;--------------------------------------------------------------------- SetupFadeFromSaturated:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;copy game palette to starting palette and ending palette ld hl,gamePalette ld de,fadeFinalPalette call FadeCommonCopyPalette ld de,fadeCurPalette call FadeCommonCopyPalette ld l,b ;saturation ;add saturation to each color ld h,64 .setup call FadeCommonGetColor dec de dec de call GetRedComponent call .saturate call SetRedComponent call GetGreenComponent call .saturate call SetGreenComponent call GetBlueComponent call .saturate call SetBlueComponent ;save color ld a,c ld [de],a inc de ld a,b ld [de],a inc de dec h jr nz,.setup pop af call FadeInit pop hl pop de pop bc ret .saturate add l bit 7,l jr nz,.satneg cp 32 ;over the limit? ret c ld a,$1f ret .satneg xor a ret ;--------------------------------------------------------------------- ; Routine: SetupFadeToGamePalette ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeToGamePalette:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;set final palette to be current game palette ld hl,gamePalette ld de,fadeFinalPalette call FadeCommonCopyPalette pop af call FadeInit pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: SetupFadeToHalfbrite ; Arguments: a - steps ; Alters: af ;--------------------------------------------------------------------- SetupFadeToHalfbrite:: push bc push de push hl push af ld a,FADEBANK ld [$ff70],a ;set final palette to be halfbrite game palette ld hl,gamePalette ld de,fadeCurPalette ld c,64 .copyHalfbrite push bc ld a,[hl+] ld c,a ld a,[hl-] ld b,a call GetRedComponent srl a call SetRedComponent call GetGreenComponent srl a call SetGreenComponent call GetBlueComponent srl a call SetBlueComponent ld a,c ld [hl+],a ld a,b ld [hl+],a pop bc dec c jr nz,.copyHalfbrite ;set cur palette to be copy of current game palette ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette pop af call FadeInit pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: FadeCommonGetColor ; Arguments: de - ptr to next color ; Returns: bc - next color ; Alters: af,de ;--------------------------------------------------------------------- FadeCommonGetColor: ld a,[de] inc de ld c,a ld a,[de] inc de ld b,a ret ;--------------------------------------------------------------------- ; Routine: FadeInit ; Arguments: a - number of steps ; [fadeCurPalette], [fadeFinalPalette] already setup ; with palettes to fade between ; Alters: af ; Description: Sets up and uses fadeDelta[32*3] ; and fadeError[32*3]. ; FadeStep must then be called every vblank until ; [specialFX:0] becomes zero. ;--------------------------------------------------------------------- FadeInit:: push bc push de push hl ld [fadeSteps],a ld [fadeStepsToGo],a ld a,FADEBANK ld [$ff70],a ;for each color component, difference is (c2-c1) ;subtract each element of fadeCurPalette from fadeFinalPalette ;and store separate RGB offsets in fadeDelta. ;fadeCurPalette RGB elements in fadeCurRGB. ;clear out fadeError and fadeDelta ld hl,fadeError ld de,fadeDelta ld c,192 xor a .clearError ld [hl+],a ld [de],a inc de dec c jr nz,.clearError ;begin by storing each color component of each color in ;fadeCurPalette into fadeDelta ld a,64 ld hl,fadeDelta ld de,fadeCurPalette .copyCurToDelta push af call FadeCommonGetColor call GetRedComponent ld [hl+],a call GetGreenComponent ld [hl+],a call GetBlueComponent ld [hl+],a pop af dec a jr nz,.copyCurToDelta ;copy fadeDelta[192] to fadeCurRGB[192]. ;ld hl,fadeDelta ;ld de,fadeCurRGB ;ld c,192 ;.copyToCurRGB ;ld a,[hl+] ;ld [de],a ;inc de ;dec c ;jr nz,.copyToCurRGB ;fadeDelta[...] = fadeFinalPalette[...] - fadeDelta[...] ld a,64 ld hl,fadeDelta ld de,fadeFinalPalette .findStep push af call FadeCommonGetColor call GetRedComponent sub [hl] ld [hl+],a call GetGreenComponent sub [hl] ld [hl+],a call GetBlueComponent sub [hl] ld [hl+],a pop af dec a jr nz,.findStep ;indicate we've got a fade goin on ld a,FX_FADE ld [specialFX],a pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: FadeStep ; Alters: af ; Description: Peforms the next step of the fade in progress. ; Should only be called if [specialFX] & FX_FADE is 1. ; fadeRange is reset to 64 afterwards. ;--------------------------------------------------------------------- FadeStep:: push bc push de push hl .waitReady ldio a,[paletteBufferReady] ;wait for vblank or a jr nz,.waitReady ;loop 64 times, adding the fade delta for each component ;to the error. If error >= 32: ; error -= 32; ; increment component; ;Then flag the newly created palette to be displayed ld a,FADEBANK ld [$ff70],a ld a,[fadeStepsToGo] dec a ld [fadeStepsToGo],a jr z,.lastFade ;ld c,64 ;ld hl,fadeError ;ld de,fadeCurRGB ; ;.fadeInner ;ld a,[de] ;red component ;call .addDeltaToError ;ld [de],a ;inc de ; ;ld a,[de] ;green component ;call .addDeltaToError ;ld [de],a ;inc de ;ld a,[de] ;blue component ;call .addDeltaToError ;ld [de],a ;inc de ;;dec c ;jr nz,.fadeInner ;copy RGB palette to 15-bit palette ;ld a,64 ;ld bc,0 ;ld hl,fadeCurRGB ;ld de,fadeCurPalette ;.RGBtoCur ;push af ;ld a,[hl+] ;call SetRedComponent ;ld a,[hl+] ;call SetGreenComponent ;ld a,[hl+] ;call SetBlueComponent ;ld a,c ;ld [de],a ;inc de ;ld a,b ;ld [de],a ;inc de ;pop af ;dec a ;jr nz,.RGBtoCur ld a,[fadeRange] ld hl,fadeError ld de,fadeCurPalette .fadeInner push af ;get current color in bc, though keep de where it was call FadeCommonGetColor dec de dec de call GetRedComponent call .addDeltaToError call SetRedComponent ;store component call GetGreenComponent call .addDeltaToError call SetGreenComponent ;store component call GetBlueComponent call .addDeltaToError call SetBlueComponent ;store component ;store back in cur table ld a,c ld [de],a inc de ld a,b ld [de],a inc de pop af dec a jr nz,.fadeInner .install ;make mapColor the current color 0 ld de,mapColor ld hl,fadeCurPalette ld a,[hl+] ld [de],a inc de ld a,[hl+] ld [de],a ;install the current palette on the next VBlank ld a,1 ldio [paletteBufferReady],a pop hl pop de pop bc ret .lastFade ;finally copy actual palette ld hl,fadeFinalPalette ld de,fadeCurPalette call FadeCommonCopyPalette ld a,64 ld [fadeRange],a xor a ld [specialFX],a jr .install .addDeltaToError ;accepts: a - color value ;returns: a - new color value push bc push af ld a,[fadeSteps] ld b,a cpl add 1 ld c,a push hl push de ld de,$ff40 ;-192 add hl,de pop de ld a,[hl] pop hl bit 7,a ;negative? jr nz,.negative .positive add a,[hl] cp b jr c,.done ;>=32 ld c,0 .while_pos_ge_32 sub b inc c cp b jr nc,.while_pos_ge_32 ld [hl+],a pop af add c pop bc ret .negative add a,[hl] cp c jr nc,.done ;<= -32 ld b,0 .while_neg_le_n32 sub c inc b cp c jr c,.while_neg_le_n32 ld [hl+],a pop af sub b pop bc ret .done ld [hl+],a pop af pop bc ret ;--------------------------------------------------------------------- ; Routine: SetColor0AllPalettes ; Arguments: bc - color to set to ; hl - ptr to start of palettes ; Alters: af ;--------------------------------------------------------------------- SetColor0AllPalettes:: push de push hl ld d,16 .loop ld a,c ld [hl+],a ld a,b ld [hl+],a ld a,l add 6 ld l,a dec d jr nz,.loop pop hl pop de ret ;--------------------------------------------------------------------- ; Routine: SetColors123AllPalettes ; Arguments: bc - color to set to ; hl - ptr to start of palettes ; Alters: af ;--------------------------------------------------------------------- SetColors123AllPalettes:: push de push hl ld d,16 .loop inc hl inc hl ld e,3 .inner ld a,c ld [hl+],a ld a,b ld [hl+],a dec e jr nz,.inner dec d jr nz,.loop pop hl pop de ret ;--------------------------------------------------------------------- ; Routine: LighteningOut ; Alters: af ;--------------------------------------------------------------------- LighteningOut:: push bc push de push hl ld a,FADEBANK ld [$ff70],a ;white background ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ld hl,fadeCurPalette ld bc,$7fff call SetColor0AllPalettes ld a,128 ldio [paletteBufferReady],a ld c,3 call .pause ld bc,0 ld hl,fadeCurPalette call SetColors123AllPalettes ld a,128 ldio [paletteBufferReady],a ld c,7 call .pause pop hl pop de pop bc ret .pause call VWait dec c jr nz,.pause ret ;--------------------------------------------------------------------- ; Routine: LighteningIn ; Alters: af ;--------------------------------------------------------------------- LighteningIn:: push bc push de push hl ld a,FADEBANK ld [$ff70],a ;black fg on white background ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ld hl,fadeCurPalette ld bc,$7fff call SetColor0AllPalettes ld bc,0 call SetColors123AllPalettes ld a,128 ldio [paletteBufferReady],a ld c,7 call .pause ;normal fg on white background ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ld hl,fadeCurPalette ld bc,$7fff call SetColor0AllPalettes ld a,128 ldio [paletteBufferReady],a ld c,3 call .pause ;normal ld hl,gamePalette ld de,fadeCurPalette call FadeCommonCopyPalette ld a,128 ldio [paletteBufferReady],a pop hl pop de pop bc ret .pause call VWait dec c jr nz,.pause ret ;--------------------------------------------------------------------- ; Routines: GetRedComponent ; GetGreenComponent ; GetBlueComponent ; SetRedComponent ; SetGreenComponent ; SetBlueComponent ; Arguments: Get: bc - 15 bit BGR value ; Set: bc - 15 bit BGR value, a - value to set ; Returns: Get: a - color component ; Alters: af, bc ;--------------------------------------------------------------------- GetRedComponent:: ld a,c and %00011111 ret GetGreenComponent:: push de ld a,b IF 1 ld e,c sla e rla sla e rla sla e rla and %00011111 pop de ret ENDC IF 0 ld e,c sla e rl d sla e rl d sla e rl d ld a,d and %00011111 pop de ret ENDC GetBlueComponent:: ld a,b rrca rrca and %00011111 ret SetRedComponent:: push af ld a,c and %11100000 ld c,a pop af or c ld c,a ret SetGreenComponent:: push de ld d,a rrca rrca rrca and %00000011 ld e,a ld a,b and %01111100 or e ld b,a ld a,d swap a rlca and %11100000 ld d,a ld a,c and %00011111 or d ld c,a pop de ret SetBlueComponent:: push af ld a,b and %00000011 ld b,a pop af rlca rlca or b ld b,a ret ;--------------------------------------------------------------------- ; Routine: PlaySound ; Arguments: hl - addr of table 1st byte of which indicates sound ; type (1-4) and remainder is data specific to that ; type. ; Alters: af, hl ;--------------------------------------------------------------------- PlaySound:: ld a,[hl+] cp 1 jr nz,.check2 xor a ld [musicOverride1],a call PlaySoundChannel1 ld a,3 ld [musicOverride1],a ret .check2 cp 2 jr nz,.check4 call PlaySoundChannel2 ret .check4 cp 4 jr nz,.done xor a ld [musicOverride4],a call PlaySoundChannel4 ld a,3 ld [musicOverride4],a ret .done ret ;--------------------------------------------------------------------- ; Routine: PlaySoundChannel1 ; Arguments: hl - addr of 5 sound bytes for sweep, duty/len, ; envelope, freq_lo, and freq_high ; Alters: af, hl ;--------------------------------------------------------------------- PlaySoundChannel1:: ld a,[musicOverride1] or a ret nz .playSound ld a,[hl+] ldio [$ff10],a ld a,[hl+] ldio [$ff11],a ld a,[hl+] ldio [$ff12],a ld a,[hl+] ldio [$ff13],a ld a,[hl+] ldio [$ff14],a ret ;--------------------------------------------------------------------- ; Routine: PlaySoundChannel2 ; Arguments: hl - addr of 4 sound bytes for duty/len, ; envelope, freq_lo, and freq_high ; Alters: af, hl ;--------------------------------------------------------------------- PlaySoundChannel2:: ld a,[hl+] ldio [$ff16],a ld a,[hl+] ldio [$ff17],a ld a,[hl+] ldio [$ff18],a ld a,[hl+] ldio [$ff19],a ret ;--------------------------------------------------------------------- ; Routine: PlaySoundChannel3 ; Arguments: hl - addr of 4 sound bytes channel 4 ; Alters: af, hl ;--------------------------------------------------------------------- PlaySoundChannel3:: ld a,$80 ldio [$ff1a],a ld a,[hl+] ldio [$ff1b],a ld a,[hl+] ldio [$ff1c],a ld a,[hl+] ldio [$ff1d],a ld a,[hl+] ldio [$ff1e],a ret ;--------------------------------------------------------------------- ; Routine: PlaySoundChannel4 ; Arguments: hl - addr of 4 sound bytes for length, envelope, ; frequency, and consecutive ; Alters: af, hl ;--------------------------------------------------------------------- PlaySoundChannel4:: ld a,[musicOverride4] or a ret nz .playSound ld a,[hl+] ldio [$ff20],a ld a,[hl+] ldio [$ff21],a ld a,[hl+] ldio [$ff22],a ld a,[hl+] ldio [$ff23],a ret ;--------------------------------------------------------------------- ; Routine: WaitInput ; Arguments: a - button mask [7:4] buttons, [3:0] dpad ; Alters: af ;--------------------------------------------------------------------- WaitInput:: push bc push de ld b,a .wait push bc push hl call UpdateObjects call RedrawMap pop hl pop bc ld h,((curJoy0>>8) & $ff) ld a,[dialogJoyIndex] add (curJoy0 & $ff) ld l,a ld a,[hl] and b jr z,.wait pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: WaitInputZero ; Arguments: a - button mask [7:4] buttons, [3:0] dpad ; hl - address of joystick button code to check ; Alters: af ;--------------------------------------------------------------------- WaitInputZero:: push bc push de ld b,a .wait push bc push hl call UpdateObjects call RedrawMap pop hl pop bc ld a,[hl] and b jr nz,.wait pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: WaitInputClick ; Arguments: a - button mask [7:4] buttons, [3:0] dpad ; Alters: af ; Description: WaitInputZero ; WaitInput ; WaitInputZero ;--------------------------------------------------------------------- WaitInputClick:: push bc push hl ld b,a ld hl,myJoy call WaitInputZero ld a,b call WaitInput ld a,b call WaitInputZero pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: ResetSprites ; Arguments: none ; Alters: af ; Description: Sets all spritesUsed flags to false and sets each ; sprite y position in the OAM buffer to zero. ;--------------------------------------------------------------------- ResetSprites:: push bc push de push hl ;clear sprites used table ld a,TILEINDEXBANK ld [$ff70],a ld hl,spritesUsed xor a ld c,40 .clr2 ld [hl+],a dec c jr nz,.clr2 ;clear sprites ld hl,spriteOAMBuffer ld c,40 ld de,3 .clr3 ld [hl+],a add hl,de dec c jr nz,.clr3 xor a ld [oamFindPos],a ld a,40 ld [numFreeSprites],a pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: AllocateSprite ; Arguments: none ; Returns: a - 00-9C=success (lowptr), ff=failure ; Alters: af ; Description: Loops through spritesUsed flag table, finds a free ; sprite, and returns that sprite's loPtr. ;--------------------------------------------------------------------- AllocateSprite:: ;any free sprites? ld a,[numFreeSprites] or a jr nz,.freeSpriteExists ld a,$ff ret .freeSpriteExists push bc push de push hl dec a ld [numFreeSprites],a ;we know there's at least one free sprite so start at ;the the search position (which is guaranteed to be ;<= pos of first free) and loop till we find it ld a,TILEINDEXBANK ld [$ff70],a ld h,((spritesUsed>>8)&$ff) ld a,[oamFindPos] ld l,a .loop ld a,[hl+] ;get sprite used flag or a jr nz,.loop ;not free .foundSprite dec hl ld a,1 ;mark sprite as used ld [hl],a ld a,l ;return loptr in a inc a ld [oamFindPos],a ld a,l ;change 1-byte offset to 4-byte offset (loPtr) rlca ;times 2 rlca ;times 2 again .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: FreeSprite ; Arguments: a - loptr to sprite ; Alters: af ; Description: Sets the sprite's YPOS to zero ; Flags the sprite as unused ; oamFindPos = min(thisPos, oamFindPos) ; numFreeSprites++ ;--------------------------------------------------------------------- FreeSprite:: ;if loptr is $ff then don't bother cp $ff ret z push hl ld l,a ld h,((spriteOAMBuffer>>8) & $ff) xor a ld [hl],a ;ypos to zero ld a,TILEINDEXBANK ld [$ff70],a rrc l ;convert loptr to sprite index rrc l ld h,((spritesUsed>>8) & $ff) xor a ld [hl],a ;clear sprite used flag ;set find pos to be mininum ld a,[oamFindPos] cp l jr c,.findPosIsMin ld a,l ld [oamFindPos],a .findPosIsMin ;add one to # of free sprites ld hl,numFreeSprites inc [hl] pop hl ret ;--------------------------------------------------------------------- ; Routine: CreateMetaSprite ; Arguments: ; bc - width (b) and height (c) of metasprite, in 8x8 ; tiles. ; d - initial pattern number for first sprite. ; e - default attributes for each sprite. ; hl - ptr to location to store metasprite info. Should ; be w*h + 1 in size. ; [metaSprite_x], [metaSprite_y] - location of TL corner ; Alters: af ;--------------------------------------------------------------------- CreateMetaSprite:: push bc push de push hl ld a,[metaSprite_x] ld [metaSprite_first_x],a ;calculate width times height push bc xor a .calcTotalSize add a,b dec c jr nz,.calcTotalSize pop bc ;store total sprites used in metaSpriteInfo ld [hl+],a ;go through and allocate each sprite, set it up, and store its ;loptr in the metaSpriteInfo push bc .height pop af ;setup width from original value push af ld b,a ld a,[metaSprite_first_x] ld [metaSprite_x],a .width call AllocateSprite ld [hl+],a ;save loptr ;set up sprite push hl ld l,a ld h,((spriteOAMBuffer>>8) & $ff) ld a,[metaSprite_y] ld [hl+],a ld a,[metaSprite_x] ld [hl+],a add 8 ld [metaSprite_x],a ld a,d ;pattern number ld [hl+],a inc d ld [hl],e ;attributes pop hl dec b jr nz,.width ld a,[metaSprite_y] add 8 ld [metaSprite_y],a dec c jr nz,.height .done pop bc pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: CreateMetaSpriteUsingMask ; Arguments: ; bc - width (b) and height (c) of metasprite, in 8x8 ; tiles. ; d - initial pattern number for first sprite. ; e - default attributes for each sprite. ; hl - ptr to location to store metasprite info. Should ; be w*h + 1 in size and location 1+ should contain ; a zero if its corresponding sprite is not to ; be allocated after all. ; [metaSprite_x], [metaSprite_y] - location of TL corner ; Alters: af ;--------------------------------------------------------------------- CreateMetaSpriteUsingMask:: push bc push de push hl ld a,[metaSprite_x] ld [metaSprite_first_x],a ;calculate width times height push bc xor a .calcTotalSize add a,b dec c jr nz,.calcTotalSize pop bc ;store total sprites used in metaSpriteInfo ld [hl+],a ;go through and allocate each sprite marked with non-zero, ;set it up, and store its loptr in the metaSpriteInfo push bc .height pop af ;setup width from original value push af ld b,a ld a,[metaSprite_first_x] ld [metaSprite_x],a .width ld a,[hl] ;load flag from destination or a ld a,$ff jr z,.afterAllocate call AllocateSprite .afterAllocate ld [hl+],a ;save loptr cp $ff jr z,.afterSetup ;set up sprite push hl ld l,a ld h,((spriteOAMBuffer>>8) & $ff) ld a,[metaSprite_y] ld [hl+],a ld a,[metaSprite_x] ld [hl+],a ld a,d ;pattern number ld [hl+],a ld [hl],e ;attributes pop hl .afterSetup ld a,[metaSprite_x] add 8 ld [metaSprite_x],a inc d dec b jr nz,.width ld a,[metaSprite_y] add 8 ld [metaSprite_y],a dec c jr nz,.height .done pop bc pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: ScrollMetaSprite ; Arguments: bc - x (b) and y (c) offset to scroll each sprite. ; hl - ptr to metaSpriteInfo created with ; CreateMetaSprite ; Alters: af ;--------------------------------------------------------------------- ScrollMetaSprite:: push de ld a,[hl+] ;number of sprites .loop push af ld a,[hl+] ;loptr to sprite ld e,a ld d,((spriteOAMBuffer>>8) & $ff) ld a,[de] ;get the y position add c ;add y offset ld [de],a inc de ld a,[de] ;get the x position add b ;add x offset ld [de],a inc de pop af dec a jr nz,.loop pop de ret ;--------------------------------------------------------------------- ; Routine: SetMetaSpritePos ; Arguments: bc - desired x (b) and y (c) pixel position in sprite ; coords ; hl - ptr to metaSpriteInfo created with ; CreateMetaSprite ; Alters: af ;--------------------------------------------------------------------- SetMetaSpritePos:: push bc push hl inc hl ;go to y pos of first sprite ld l,[hl] ld h,((spriteOAMBuffer>>8) & $ff) ld a,c ;desired y pos sub [hl] ld c,a ;becomes offset to scroll inc hl ld a,b sub [hl] ld b,a ;becomes offset to scroll pop hl call ScrollMetaSprite pop bc ret ;--------------------------------------------------------------------- ; Routine: FreeMetaSprite ; Arguments: hl - ptr to metaSpriteInfo created with ; CreateMetaSprite ; Alters: af ;--------------------------------------------------------------------- FreeMetaSprite:: push bc push hl ld a,[hl+] ;number of sprites ld c,a .freeASprite ld a,[hl+] ;get loptr call FreeSprite dec c jr nz,.freeASprite pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: CreateBigExplosion ; Arguments: bc - tile width and height of explosion area ; d - max sprites (must be >0) ; e - flags for allowed explosion types: ; :0 - small round explosions ; :1 - shrapnel plus ; :2 - big (2x2) round explosions (4 sprites ea) ; hl - TL map corner (e.g. $d0ca) of explosion ; [bulletColor] ; Returns: Nothing. ; Alters: af ; Description: Creates a big explosion of randomly dispersed smaller ; explosions within the given area. ; ;--------------------------------------------------------------------- CreateBigExplosion:: push bc push de push hl ;limit the number of sprites according to the system's ;resources ld a,[numFreeSprites] cp d jr nc,.numSpritesOkay ld d,a .numSpritesOkay or a jr nz,.continue jp .done .continue call ConvertLocHLToXY ld a,[bulletColor] .loop ;limit myself to smaller explosions if I have less than 4 ;sprites left push af push hl ld a,d cp 4 jr nc,.afterLimitToSmaller res 2,e ;remove larger fr possible explosions flags ld a,e or a jr nz,.afterLimitToSmaller ld d,1 jr .afterCreateExplosion .afterLimitToSmaller ;select random tile position within area ;width ld a,b dec a call GetRandomNumZeroToN add h ld h,a ;height ld a,c dec a call GetRandomNumZeroToN add l ld l,a call ConvertXYToLocHL ld a,l ld [bulletLocation],a ld a,h ld [bulletLocation+1],a ;choose random explosion ld a,e call GetRandomNumMask bit 2,a jr z,.checkType1 .isType2 bit 2,e ;this type allowed? jr z,.isType0 ;type two - big 2x2 explosion ld a,6 ld [bulletColor],a push bc ld b,32 call .create2x2Frame inc hl call .create2x2Frame push de ld d,0 ld a,[mapPitch] ld e,a add hl,de pop de dec hl call .create2x2Frame inc hl call .create2x2Frame pop bc dec d dec d dec d jr .afterCreateExplosion .checkType1 bit 1,a jr z,.isType0 .isType1 bit 1,e ;this type allowed? jr z,.isType2 ;type one - shrapnel ld a,64 jr .determinedFrame .isType0 ;default bit 0,e ;this type allowed? jr z,.isType1 ;type zero - small round explosion ld a,5 ld [bulletColor],a ld a,16 .determinedFrame push bc ld b,a call CreateExplosion call .offsetSprite pop bc .afterCreateExplosion pop hl .beforeRestoreColor pop af ld [bulletColor],a dec d jr z,.done jp .loop .done pop hl pop de pop bc ret .offsetSprite or a ret z push de push hl call IndexToPointerHL ;get ptr to explosion class ld a,OBJBANK ldio [$ff70],a ld de,OBJ_SPRITELO add hl,de ld l,[hl] ld h,((spriteOAMBuffer>>8) & $ff) ld a,%111 call GetRandomNumMask add [hl] ld [hl+],a ld a,%111 call GetRandomNumMask add [hl] ld [hl],a pop hl pop de ret .create2x2Frame ld a,l ld [bulletLocation],a ld a,h ld [bulletLocation+1],a call CreateExplosion ld a,b add 8 ld b,a ret ;--------------------------------------------------------------------- ; Routine: BlitMap ; Arguments: bc - tile width and height of area to copy ; de - destination XY coords ; hl - source XY coords ; Returns: Nothing. ; Alters: af ; Description: Copies a section of the current map, not overwriting ; any objects ;--------------------------------------------------------------------- BlitMap:: push bc push de push hl push hl ld h,d ld l,e call ConvertXYToLocHL ld d,h ld e,l pop hl call ConvertXYToLocHL ld a,MAPBANK ldio [$ff70],a .blitMapOuter push bc push de push hl ldio a,[firstMonster] ld c,a .blitMapInner ld a,[de] cp c ;< first monster? jr nc,.blitSkip ld a,[hl] ld [de],a .blitSkip inc hl inc de dec b jr nz,.blitMapInner pop hl pop de push hl ld a,[mapPitch] ld h,0 ld l,a add hl,de ld d,h ld e,l pop hl ld a,[mapPitch] ld b,0 ld c,a add hl,bc pop bc dec c jr nz,.blitMapOuter pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: ConvertLocHLToXY ; Arguments: hl - location ($D000-$DFFF) ; Returns: hl - h = x index, l = y index ; Alters: a,hl ; Description: x = location & (pitch-1) ; y = (location - $D000) / pitch ;--------------------------------------------------------------------- ConvertLocHLToXY:: ld a,[mapPitchMinusOne] and l push af ;push a (x index) on stack ld a,h ;subtract $D000 from hl by adding $3000 add $30 ld h,a ld a,[mapPitchMinusOneComplement] ;times to left-shift .shift rlca ;shift a bit left out of a jr nc,.shiftDone ;hl<<=1 if bits left in a sla l rl h jr .shift .shiftDone ld l,h pop af ld h,a ;h = x index, l = y index ret ;--------------------------------------------------------------------- ; Routine: ConvertXYToLocHL ; Arguments: hl - h = x index, l = y index ; Returns: hl - location ptr ($D000-$DFFF) ; Alters: a,hl ; Description: hl = $d000 + (y * pitch) + x ; Instead of having y in the LoByte and left-shifting it ; by the bits in the pitch, we'll put y in the HiByte ; and right-shift it by 8-bitsInPitch. Fewer ops. ;--------------------------------------------------------------------- ConvertXYToLocHL:: push de ;multiply y*pitch ld a,[mapPitchMinusOneComplement] ld d,l ld e,0 .shift rlca ;if bits left in A then keep shifting jr nc,.shiftDone srl d rr e jr .shift .shiftDone ld l,h ;add x + $d000 ld h,$d0 add hl,de pop de ret ;--------------------------------------------------------------------- ; Routine: LCheckGetVectorToState ; Arguments: hl - address of method table ; Returns: hl - methodTable[mapState] ; Alters: af,hl ; Description: Use the VECTORTOSTATE macro. ;--------------------------------------------------------------------- LCheckGetVectorToState:: push de ldio a,[mapState] ld d,0 ld e,a sla e rl d add hl,de pop de ld a,[hl+] ld h,[hl] ld l,a ret ;--------------------------------------------------------------------- ; Routine: SaveIdle ; Arguments: None. ; Returns: ; Alters: af,hl ; Description: Saves the current state of [heroesIdle] and [allIdle] ; in [dialogIdleSettings] and activates both idle ; settings ;--------------------------------------------------------------------- SaveIdle:: ld a,[heroesIdle] rlca ld hl,allIdle or [hl] ld [dialogIdleSettings],a ld a,1 ld [heroesIdle],a ld [allIdle],a ret ;--------------------------------------------------------------------- ; Routine: RestoreIdle ; Arguments: None. ; Returns: ; Alters: af,hl ; Description: Restores the idle settings to what they were previous ; to SaveIdle ;--------------------------------------------------------------------- RestoreIdle:: ld a,[dialogIdleSettings] push af and 1 ld [allIdle],a pop af srl a ld [heroesIdle],a ret ;--------------------------------------------------------------------- ; Routine: MakeIdle ; Arguments: None. ; Returns: ; Alters: af ; Description: Sets [heroesIdle] and [allIdle] to 1 ;--------------------------------------------------------------------- MakeIdle:: ld a,1 ld [heroesIdle],a ld [allIdle],a ret ;--------------------------------------------------------------------- ; Routine: MakeNonIdle ; Arguments: None. ; Returns: ; Alters: af ; Description: Sets [heroesIdle] and [allIdle] to 0 ;--------------------------------------------------------------------- MakeNonIdle:: xor a ld [heroesIdle],a ld [allIdle],a ret ;--------------------------------------------------------------------- ; Routine: UseAlternatePalette ; Arguments: None. ; Returns: Nothing. ; Alters: af ; Description: Darkens colors 1 & 2 of each palette, intended for ; use on the light-background maps. ;--------------------------------------------------------------------- UseAlternatePalette:: push bc push hl ld a,FADEBANK ldio [$ff70],a ld c,16 ld hl,gamePalette+2 .loop call .halve call .halve inc hl inc hl inc hl inc hl dec c jr nz,.loop pop hl pop bc ret .halve ld a,[hl+] ;color[i]>>=1; ld b,a ld a,[hl] rrca rr b and %00111101 ld [hl-],a ld a,b and %11101111 ld [hl+],a inc hl ret ;--------------------------------------------------------------------- ; Routine: GetMyHero ; Arguments: None. ; Returns: a - class index of local hero (i.e. not remote) ; hl - pointer to hero0_data or hero1_data approprately ; Alters: af, hl ;--------------------------------------------------------------------- GetMyHero:: ld a,[amLinkMaster] cp 0 jr z,.getHero1 ;get hero zero if link master ld a,[hero0_index] ld hl,hero0_data ret .getHero1 ld a,[hero1_index] ld hl,hero1_data ret ;--------------------------------------------------------------------- ; Routine: GetBGAttributes ; Arguments: a - class index ; Alters: af ; Returns: a - attributes for given class index ; Returns full set off attributes including: ; [2:0] - color FLAG_PALETTE ; [3] - can walk over FLAG_WALKOVER ; [4] - can shoot over FLAG_SHOOTOVER ;--------------------------------------------------------------------- GetBGAttributes:: push hl ld l,a ld h,((bgAttributes>>8) & $ff) ld a,TILEINDEXBANK ldio [$ff70],a ld a,[hl] pop hl ret ;--------------------------------------------------------------------- ; Routine: UpdateDialogBalloons ; Arguments: de - intial pos in [spritesUsed] ; hl - initial pos in spriteOAMBuffer ; Alters: af, de, hl ;--------------------------------------------------------------------- UpdateDialogBalloons:: ld a,[amShowingDialog] or a ret nz ;no balloons during dialog ldio a,[updateTimer] and %00010000 ret z ;all blank push bc call FindNextFreeSprite jr z,.done ld a,[dialogBalloonClassIndex] ld c,a call GetFirst .setNextBalloon or a jr z,.done call PutBalloonAboveObject ;remake de from hl push de inc hl inc hl inc hl inc hl call .remakeDEfromHL call FindNextFreeSprite pop de jr z,.done call GetNextObject jr .setNextBalloon .done call .remakeDEfromHL pop bc ret .remakeDEfromHL ld a,l ;e = l/4 rrca rrca ld e,a ld d,((spritesUsed>>8)&$ff) ret ;--------------------------------------------------------------------- ; Routine: DisableDialogBalloons ; Arguments: a - mask of objects (up to 8) to disable. %101 ; would disable the first and third speakers, etc. ; Speakers after the eigth are disabled. ; Alters: af ;--------------------------------------------------------------------- DisableDialogBalloons:: push bc push de push hl ld b,a ld a,[dialogBalloonClassIndex] or a jr z,.done ld c,a call GetFirst .disableNext or a jr z,.done ld a,b or a jr z,.disableAfter8 and 1 jr z,.continue ld a,1 call SetMisc .continue srl b call GetNextObject jr .disableNext .disableAfter8 ld b,8 ld a,[dialogBalloonClassIndex] ld c,a call GetFirst .find9th or a jr z,.done call GetNextObject dec b jr nz,.find9th .disableAfter8Next or a jr z,.done ld a,1 call SetMisc call GetNextObject jr .disableAfter8Next .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: FindNextFreeSprite ; Arguments: de - ptr to position within spritesUsed to begin ; resetting ; hl - ptr to sprite OAM buffer corresponding to ; de ; Alters: af,de,hl ; Returns: a - 0 on failure ;--------------------------------------------------------------------- FindNextFreeSprite: ld a,e cp 40 jr nc,.notFound push bc ld a,TILEINDEXBANK ldio [$ff70],a ld bc,4 .checkNext ld a,[de] or a jr z,.foundIt inc de add hl,bc ld a,e cp 40 jr c,.checkNext pop bc .notFound xor a ret .foundIt ld a,1 or a pop bc ret ;--------------------------------------------------------------------- ; Routine: PutBalloonAboveObject ; Arguments: de - ptr to object ; hl - ptr to sprite OAM buffer ; Alters: af ;--------------------------------------------------------------------- PutBalloonAboveObject: push de push hl ld [hl],0 ;zero sprite in case we don't use it push hl call GetMisc pop hl or a jr nz,.done ;already spoke call GetCurLocation call ConvertLocHLToSpriteCoords ld d,h ld e,l pop hl push hl ld a,e or a jr z,.afterAdjustCoords ;leave zero at zero sub 8 ld e,a ld a,d add 8 ld d,a .afterAdjustCoords ld [hl],e ;y coord inc hl ld [hl],d ;x coord inc hl ld a,80 ;pattern number ld [hl+],a xor a ld [hl],a ;palette/etc .done pop hl pop de ret ;--------------------------------------------------------------------- ; Routine: ResetFreeSprites ; Arguments: de - ptr to position within spritesUsed to begin ; resetting ; hl - ptr to sprite OAM buffer corresponding to ; de ; Alters: af,de,hl ; Returns: Nothing. ; Description: Sets y=0 of all sprites after initial position not ; flagged as in use; necessary for resetting ; environmental effects ;--------------------------------------------------------------------- ResetFreeSprites:: ld a,e cp 40 ret nc push bc ld a,TILEINDEXBANK ldio [$ff70],a ld bc,4 .resetNext ld a,[de] or a jr nz,.afterReset ld [hl],a ;ypos = 0 .afterReset add hl,bc inc de ld a,e cp 40 jr c,.resetNext pop bc ret ;--------------------------------------------------------------------- ; Routine: SetEnvEffect ; Arguments: a - env effect such as ENV_RAIN ; Alters: af ; Returns: Nothing. ; Description: Sets an environmental effect and quickly updates it ; a number of times to be in full swing by the time ; the player sees it ;--------------------------------------------------------------------- SetEnvEffect:: push bc ld [envEffectType],a ld c,16 .updateEffect call UpdateEnvEffect dec c jr nz,.updateEffect pop bc ret ;--------------------------------------------------------------------- ; Routine: UpdateEnvEffect ; Arguments: None. ; Alters: af ; Returns: Nothing. ; Description: Sets unused sprites to be dialog/rain/snow etc based ; on [envEffectType]. Calls UpdateDialogBalloons and ; ResetFreeSprites ;--------------------------------------------------------------------- UpdateEnvEffect:: push bc push de push hl ld de,spritesUsed ld hl,spriteOAMBuffer ld c,0 ld a,[dialogBalloonClassIndex] or a jr z,.afterUpdateBalloons inc c call nz,UpdateDialogBalloons .afterUpdateBalloons ld a,[envEffectType] or a jr z,.afterEffect ldio a,[randomLoc] push af ld a,[asyncRandLoc] ldio [randomLoc],a ld a,[envEffectType] call .updateAppropriate ldio a,[randomLoc] ldio [asyncRandLoc],a pop af ldio [randomLoc],a .afterEffect call ResetFreeSprites pop hl pop de pop bc ret .updateAppropriate inc c cp ENV_RAIN jr nz,.checkSnow ld d,e LONGCALLNOARGS EnvRain ret .checkSnow cp ENV_SNOW jr nz,.checkDirt ld d,e LONGCALLNOARGS EnvSnow ret .checkDirt cp ENV_DIRT jr nz,.checkClouds ld d,e LONGCALLNOARGS EnvDirt ret .checkClouds cp ENV_CLOUDS jr nz,.checkWindySnow ld d,e LONGCALLNOARGS EnvClouds ret .checkWindySnow cp ENV_WINDYSNOW jr nz,.checkCounter ld d,e LONGCALLNOARGS EnvWindySnow ret .checkCounter cp ENV_COUNTER jr nz,.checkDisco ;reset first two sprites to y=16 ld hl,spriteOAMBuffer ld de,4 ld [hl],16 add hl,de ld [hl],16 ret .checkDisco cp ENV_DISCO ret nz LONGCALLNOARGS EnvDisco ret ;--------------------------------------------------------------------- SECTION "GfxSupport",ROMX ;--------------------------------------------------------------------- EnvRain: call EnvSetupDEHL ld b,0 .nextDrop call FindNextFreeSprite ret z inc b ld a,[hl] or a jr nz,.updatePosition .newDrop ;create new raindrop ld a,63 call GetRandomNumMask cpl add 16 ld [hl+],a ;ypos ld a,255 call GetRandomNumMask ;add 8 ;ld [hl],a ;ld a,63 ;call GetRandomNumMask ;add [hl] ;sub 64 ld [hl+],a ;xpos ld [hl],81 ;pattern inc hl ld [hl],2 ;palette inc hl inc de jr .nextDrop .updatePosition ld a,[hl] add 8 ld [hl],a and 184 cp 184 jr nz,.afterRemove .remove ld [hl],0 .afterRemove inc hl ld a,[hl] add 4 ld [hl+],a ld a,[hl+] cp 81 ;rain pattern jr z,.dropOkay ;change into a rain sprite dec hl ld [hl],81 inc hl ld [hl],2 ;push hl ;dec hl ;dec hl ;ld [hl],0 ;reset sprite ;pop hl .dropOkay inc hl inc de jp .nextDrop EnvSnow: call EnvSetupDEHL ld b,0 .nextFlake call FindNextFreeSprite ret z inc b ld a,[hl] or a jr nz,.updatePosition .newFlake ;create new snowflake ld a,63 call GetRandomNumMask cpl add 16 ld [hl+],a ;ypos ld a,255 call GetRandomNumMask ;add 8 ;ld [hl],a ;ld a,63 ;call GetRandomNumMask ;add [hl] ;sub 10 ld [hl+],a ;xpos ld [hl],74 ;pattern inc hl ld [hl],0 ;palette inc hl inc de jr .nextFlake .updatePosition ld a,[hl] ;add 4 inc a ld [hl],a and 184 cp 184 jr nz,.afterRemove .remove ld [hl],0 .afterRemove ;get deltax offset for this flake mem loc + y loc ld a,l rrca rrca add [hl] ;plus y coord and 63 push hl add (flakeSineTable & $ff) ld l,a ld a,0 adc ((flakeSineTable>>8)&$ff) ld h,a ld a,[hl] pop hl inc hl add [hl] ld [hl+],a ;new x coord ld a,[hl+] cp 74 ;flake pattern jr z,.flakeOkay ;change into a snowflake sprite dec hl ld [hl],74 inc hl ld [hl],0 ;push hl ;dec hl ;dec hl ;ld [hl],0 ;reset sprite ;pop hl .flakeOkay inc hl inc de jp .nextFlake EnvDirt: call EnvSetupDEHL ld b,0 .nextGrit call FindNextFreeSprite ret z inc b ld a,[hl] or a jr nz,.updatePosition .newGrit ;create new sand ld a,127 call GetRandomNumMask ld [hl],a ;ypos ld a,31 call GetRandomNumMask add [hl] sub 10 ld [hl+],a ld a,63 call GetRandomNumMask cpl add 8 ld [hl+],a ;xpos ld [hl],72 ;pattern inc hl ld [hl],6 ;palette inc hl inc de jr .nextGrit .updatePosition ld a,l ;y += (-1,0,1,2) rrca rrca and %11 sub 1 add [hl] ld [hl+],a ld a,[hl] add 8 ld [hl+],a and 184 cp 184 jr nz,.afterRemove .remove push hl dec hl dec hl ld [hl],0 pop hl .afterRemove ld a,[hl+] cp 72 ;grit pattern jr z,.gritOkay push hl dec hl dec hl dec hl ld [hl],0 ;reset sprite pop hl .gritOkay inc hl inc de jp .nextGrit EnvWindySnow: call EnvSetupDEHL ld b,0 .nextFlake call FindNextFreeSprite ret z inc b ld a,[hl] or a jr nz,.updatePosition .newFlake ;create new flake ld a,127 call GetRandomNumMask ld [hl],a ;ypos ld a,31 call GetRandomNumMask add [hl] sub 10 ld [hl+],a ld a,63 call GetRandomNumMask cpl add 168 ld [hl+],a ;xpos ld [hl],74 ;pattern inc hl ld [hl],0 ;palette inc hl inc de jr .nextFlake .updatePosition ld a,l ;y += (-1,0,1,2) rrca rrca and %11 sub 1 add [hl] ld [hl+],a ld a,[hl] sub 8 ld [hl+],a and 248 cp 248 jr nz,.afterRemove .remove push hl dec hl dec hl ld [hl],0 pop hl .afterRemove ld a,[hl+] cp 74 ;flake pattern jr z,.flakeOkay ;change into a snowflake sprite dec hl ld [hl],74 inc hl ld [hl],0 ;push hl ;dec hl ;dec hl ;dec hl ;ld [hl],0 ;reset sprite ;pop hl .flakeOkay inc hl inc de jp .nextFlake EnvClouds: call EnvSetupDEHL ld b,0 .nextCloud call FindNextFreeSprite ret z inc b ld a,[hl] or a jr nz,.updatePosition ld a,b and %11 jr nz,.addToCloud ;one in 8 chance of creating a cloud ld a,1 call GetRandomNumMask or a jr z,.newCloud inc hl inc hl inc hl inc hl inc de jr .nextCloud .newCloud ;create new cloud ld a,144 call GetRandomNumZeroToN add 16 ld [hl+],a ;ypos ld [$c01e],a ld a,63 call GetRandomNumMask cpl ld [hl+],a ;xpos ld [$c01f],a ld a,3 call GetRandomNumMask add 82 ld [hl+],a ;pattern ld [hl],4 ;palette inc hl inc de jr .nextCloud .addToCloud push de ld a,7 call GetRandomNumMask ld d,a ld a,[$c01e] add d ld [hl+],a ;ypos ld a,7 call GetRandomNumMask ld d,a ld a,[$c01f] add d ld [hl+],a ;xpos ld a,3 call GetRandomNumMask add 82 ld [hl+],a ;pattern ld [hl],4 ;palette inc hl pop de inc de jr .nextCloud .updatePosition inc hl ;bit 2,l ;jr z,.updateOnTimer jr .updateOnTimer inc [hl] jr .afterIncr .updateOnTimer ldio a,[updateTimer] and 1 jr z,.afterIncr inc [hl] .afterIncr ld a,[hl] cp 178 jr nz,.afterRemove dec hl ld [hl],0 inc hl .afterRemove inc hl inc hl inc hl inc de jp .nextCloud EnvSetupDEHL: ld d,((spritesUsed>>8)&$ff) ld a,e rlca rlca ld l,a ld h,((spriteOAMBuffer>>8)&$ff) ret flakeSineTable: DB $ff,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 DB 0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0 DB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,$ff DB 0,0,$ff,0,0,$ff,0,0,$ff,0,$ff,0,0,$ff,0,0 ;--------------------------------------------------------------------- ; EnvDisco ; Uses binary data "discoLights" to set all colors to purple in ; drawing buffer except where lights are flashing. Uses levelVars[0] ; to determine current frame ;--------------------------------------------------------------------- EnvDisco: push bc push de push hl ;setup hl to point to light data for appropriate frame ld de,20*18 ld hl,discoLights ld a,[levelVars] or a jr z,.frameSet .times360 add hl,de dec a jr nz,.times360 .frameSet ld de,attributeBuffer ld b,18 ;18 rows .outer ld c,20 ;20 columns .inner ld a,[hl+] or a jr nz,.afterSetColor ld a,[de] or %111 ld [de],a .afterSetColor inc de dec c jr nz,.inner push hl ld hl,12 add hl,de ld d,h ld e,l pop hl dec b jr nz,.outer pop hl pop de pop bc ret discoLights: INCBIN "Data/discolights.dat" ;Not in HOME ;--------------------------------------------------------------------- SECTION "FontSection",ROMX,BANK[MAP0ROM],ALIGN[4] fontData: INCBIN "Data/font.bin" blankTileData: DW 0,0,0,0,0,0,0,0 explosionSprites: INCBIN "Data/Sprites/explosions0-85.bin" SECTION "ReservedSpriteDMAHandler",HRAM[$FF80] SpriteDMAHandler:: DS (oamHandlerFinish - oamHandlerStart) ;--------------------------------------------------------------------- SECTION "GfxSupportSection",ROMX[$4000] ;--------------------------------------------------------------------- ;$4000 randomTable: DB $9f,$d2,$e6,$e7,$70,$db,$11,$63,$6b,$37,$99,$98,$30,$9c,$d9,$35 DB $65,$af,$56,$ee,$b1,$00,$fd,$c7,$61,$48,$df,$45,$2e,$41,$6d,$9b DB $13,$40,$d8,$fa,$91,$02,$29,$e0,$cb,$5d,$28,$fb,$2f,$77,$ea,$f9 DB $7e,$92,$5b,$75,$b5,$fc,$ae,$a2,$71,$cc,$a9,$3f,$7f,$7d,$ad,$7c DB $73,$a5,$f8,$03,$9e,$25,$f6,$e8,$4d,$33,$b3,$44,$aa,$26,$08,$6e DB $82,$97,$96,$19,$c8,$b4,$ba,$d3,$1f,$d0,$f5,$06,$54,$86,$49,$e2 DB $69,$43,$0b,$b0,$f1,$83,$a8,$9d,$38,$42,$ef,$e4,$74,$12,$20,$a0 DB $55,$01,$66,$23,$3d,$51,$c0,$79,$10,$de,$eb,$d5,$09,$8e,$5e,$67 DB $4a,$7a,$3e,$4b,$68,$8d,$e9,$62,$1b,$dd,$da,$bb,$53,$22,$3c,$b6 DB $ff,$81,$24,$8b,$d4,$6f,$d7,$9a,$d6,$21,$f4,$0a,$b2,$bc,$a7,$36 DB $34,$64,$c5,$a6,$4e,$b9,$f3,$0e,$f0,$3b,$cd,$0d,$17,$ec,$1a,$8a DB $e3,$16,$93,$05,$c9,$14,$c1,$cf,$52,$2c,$1e,$bf,$88,$27,$1d,$f7 DB $5c,$ac,$ab,$3a,$bd,$a1,$f2,$04,$e5,$2d,$e1,$c2,$15,$fe,$8c,$6a DB $2b,$84,$1c,$d1,$47,$c6,$58,$c3,$0f,$ce,$5f,$90,$8f,$76,$60,$0c DB $94,$2a,$6c,$89,$39,$46,$18,$95,$7b,$dc,$b7,$72,$78,$5a,$57,$ca DB $4f,$a4,$59,$07,$32,$c4,$ed,$b8,$50,$85,$a3,$31,$4c,$87,$80,$be ;0=star 1=moon 2=flower 3=crouton 4=i 5=monkey 6=wrench 7=man ;$4100 init_flightCodes: DB $0f DB $00,$00,$06 DB $00,$00,$23 DB $00,$00,$29 DB $00,$00,$3a DB $00,$00,$47 DB $00,$00,$59 DB $00,$00,$66 DB $00,$00,$a3 DB $00,$00,$a8 DB $00,$00,$0a DB $00,$00,$3d DB $63,$02,$71 ;initial landing star flower wrench crouton DB $33,$53,$81 ;mouse landing monkey crouton crouton crouton DB $65,$70,$c7 ;farm landing man star wrench monkey DB $12,$01,$55 ;palace star moon moon flower DB $00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00