;Class.asm ;Gfx.asm ;Map.asm ;Object.asm ;Music.asm ;--------------------------------------------------------------------- ; user.asm ; 12.18.99 by Abe Pralle ;--------------------------------------------------------------------- INCLUDE "Source/Defs.inc" INCLUDE "Source/Start.inc" INCLUDE "Source/Items.inc" MIN_VBLANKS EQU 2 INTCLK EQU $83 EXTCLK EQU $82 SECTION "User",ROM0 ;--------------------------------------------------------------------- ; Subroutine: UserMain ; Description: Sets up game then goes into main loop ;--------------------------------------------------------------------- UserMain:: call InitGfx ;set up initial location + hero ;initial L0009 (demo intro) ld a,LEVELSTATEBANK ld [$ff70],a xor a ld [curLevelStateIndex],a xor a ldio [mapState],a ldio [mapState+1],a ;initial level index ld a,((INITIALMAP>>8) & $ff) ld [curLevelIndex+1],a ld a,(INITIALMAP & $ff) ld [curLevelIndex],a ld hl,$1102 call SetJoinMap call SetRespawnMap ld a,[heroesUsed] or INITTYPE0 ld [heroesUsed],a ;hero 0 initial setup ld a,(INITHERO0 & $ff) ld [hero0_class],a ld a,((INITHERO0>>8)&$ff) ld [hero0_class+1],a ld a,(INITLOC0 & $ff) ld [hero0_enterLevelLocation],a ld a,((INITLOC0>>8) & $ff) ld [hero0_enterLevelLocation+1],a ld a,INITEXIT0 ld [hero0_enterLevelFacing],a ld a,INITTYPE0 ld [hero0_type],a xor a ld [hero0_health],a ;hero 1 initial setup ld a,(INITHERO1 & $ff) ld [hero1_class],a ld a,((INITHERO1>>8)&$ff) ld [hero1_class+1],a ld a,(INITLOC1 & $ff) ld [hero1_enterLevelLocation],a ld a,((INITLOC1>>8) & $ff) ld [hero1_enterLevelLocation+1],a ld a,INITEXIT1 ld [hero1_enterLevelFacing],a ld a,INITTYPE1 ld [hero1_type],a xor a ld [hero1_health],a ld a,1 ld [timeToChangeLevel],a jr .loadNextLevel .game ld a,[timeToChangeLevel] or a jr z,.continue ;switch levels ld b,METHOD_DIE call IterateAllLists ld a,15 call SetupFadeToBlack call WaitFade .loadNextLevel call LoadNextLevel call UpdateObjects call GentleCameraAdjust call levelCheckRAM call RedrawMap ld a,15 call SetupFadeFromBlack call WaitFade ;call LighteningIn .continue call MainLoopUpdateObjects call GentleCameraAdjust call levelCheckRAM .afterLevelCheck call RedrawMap jr .game ;--------------------------------------------------------------------- ; Routine: SetActiveROM ; Argument: a - desired ROM bank ; Returns: Nothing. ; Alters: af ; Description: Switches to a new ROM bank by writing the new bank ; number to [$2100]. Also saves the bank in ; [curROMBank]. ;--------------------------------------------------------------------- SetActiveROM:: ldio [curROMBank],a ld [$2100],a ret ;--------------------------------------------------------------------- ; Routine: LongCall ; Arguments: stack: ; +0: parameter de ; +2: parameter af ; +4: empty (for addr of routine) ; +6: empty (return addr from routine) ; +8: af - old ROM bank ; +10: return addr from LongCall ; a - bank of routine ; de - address of routine ; Returns: Whatever routine normally returns (excluding F). ; Alters: af, hl ; Description: ;--------------------------------------------------------------------- LongCall:: ldio [curROMBank],a ;switch to ROM containing routine ld [$2100],a push hl ld hl,sp+6 ;point hl to empty spot in stack ld [hl],e inc hl ld [hl],d ;save addr of method inc hl ld de,.returnAddress ld [hl],e ;save return addr of method inc hl ld [hl],d pop hl pop de pop af ret ;call method .returnAddress ld [longCallTempA],a pop af ;get old ROM bank ldio [curROMBank],a ld [$2100],a ld a,[longCallTempA] ret ;return from this routine ;--------------------------------------------------------------------- ; Routine: LongCallNoArgs ; Arguments: a - RAM bank of routine ; hl - address of routine ; Returns: Nothing. ; Alters: af ; Description: Quick & dirty long call (handles bank swapping) ; for routines that don't require arguments or return ; values. ;--------------------------------------------------------------------- LongCallNoArgs:: push bc ld b,a ld a,[curROMBank] push af ;save old bank ld a,b ld [curROMBank],a ;swap in new bank ld [$2100],a ld bc,.returnAddress push bc jp hl .returnAddress pop af ;retrieve old bank & swap it in ld [curROMBank],a ld [$2100],a pop bc ret WaitFade:: call FadeStep ;took out distorts synchronization ;send a null control byte ;ld a,LNULL ;call ExchangeByte ;call HandleRemoteInput call CheckSkip ld a,[specialFX] and FX_FADE jr nz,WaitFade ;allow last palette to install .waitInstall ldio a,[paletteBufferReady] ;wait for vblank or a jr nz,.waitInstall ret ;--------------------------------------------------------------------- ; Routine: CheckSpecialFX ; Alters: af ; Description: Performs any special effects upkeep ;--------------------------------------------------------------------- CheckSpecialFX: ld a,[specialFX] and FX_FADE jr z,.done call FadeStep ret .done ret ;--------------------------------------------------------------------- ; Subroutine: UpdateObjTimers ; Alters: af ; Description: Updates timers used for object movement ;--------------------------------------------------------------------- UpdateObjTimers:: ld a,[objTimerBase] inc a ld [objTimerBase],a ;put 2 LSB bits in 4:3 rlca rlca rlca and %00011000 ld [objTimer60ths],a ret ;--------------------------------------------------------------------- ; Subroutine: UpdateHeroTimers ; Alters: af ; Description: Updates timers used for hero/hero bullet movement ;--------------------------------------------------------------------- UpdateHeroTimers: ld a,[heroTimerBase] inc a ld [heroTimerBase],a ;put 2 LSB bits in 4:3 rlca rlca rlca and %00011000 ld [heroTimer60ths],a ret ;--------------------------------------------------------------------- ; Subroutine: VWait ; Description: Waits until a vertical blank occurs and then returns ;--------------------------------------------------------------------- VWait:: .vwait halt ;stop processor until interrupt nop ;pad to prevent weird stuff after halt ;interrupt happened, let's look at our flag ldio a,[vblankFlag] or a ;a=a|a; tells us if vblankFlag is 1 or 0 jr z,.vwait ;not the vblank flag after all ;If we're here then a vblank has occurred. Get on with our lives. xor a ;clear vblank flag ldio [vblankFlag],a ret ;--------------------------------------------------------------------- ; Subroutine: OnVBlank ; Description: Called every vertical blank. Sets "vblankFlag" to ; 1 to indicate a vertical blank has occurred ;--------------------------------------------------------------------- OnVBlank:: push af ;save all registers on stack push bc push de push hl ld a,1 ;set "vblankFlag" to 1 ldio [vblankFlag],a ;store current VRAM bank in use ld a,[$ff00+$4f] push af ;update timers ld hl,vblankTimer inc [hl] ;is the backBuffer ready for DMA blit to screen? ldio a,[backBufferReady] or a jr z,.checkDMALoad ;wasn't ready ld a,[displayType] or a jr nz,.afterVblankCheck ;cinema type ldio a,[vblankTimer] ld hl,vblankTemp sub [hl] ldio [vblanksPerUpdate],a ;update no faster than 1-frame-every-so-many-blanks clocks cp MIN_VBLANKS jr c,.checkDMALoad ;too soon to update ;MUST SYNCHRONIZE WITH REMOTE TO DYNAMICALLY CHANGE THIS ;jr z,.rightOn ;exactly right ;updating too many objects; decrease iterateNumObjects ;ld hl,iterateNumObjects ;ld a,[hl] ;cp 17 ;jr c,.rightOn ;don't risk going below 16 per update ;dec [hl] .rightOn ldio a,[vblankTimer] ;save time of this screen update ldio [vblankTemp],a .afterVblankCheck ld hl,updateTimer inc [hl] xor a ldio [backBufferReady],a ;signal we've blitted backbuffer ;set VRAM bank to 0 xor a ld [$ff00+$4f],a ;use DMA to transfer sprite OAM buffer to VRAM call SpriteDMAHandler ;Initiate DMA transfer of backbuffer to VRAM ld hl,backBuffer ld a,h ld [$ff00+$51],a ;high byte of source ld a,l ld [$ff00+$52],a ;low byte of source ldio a,[backBufferDestHighByte] ld [$ff00+$53],a ;high byte of dest xor a ld [$ff00+$54],a ;low byte of dest ld a,37 ;copy (37+1)*16 = 608 bytes ld [$ff00+$55],a ;store length to start DMA ;set VRAM bank to 1 (tile attributes) ld a,1 ld [$ff00+$4f],a ;Initiate DMA transfer of tile attributes to VRAM ld hl,attributeBuffer ld a,h ld [$ff00+$51],a ;high byte of source ld a,l ld [$ff00+$52],a ;low byte of source ldio a,[backBufferDestHighByte] ld [$ff00+$53],a ;high byte of dest xor a ld [$ff00+$54],a ;low byte of dest ld a,37 ;copy (37+1)*16 = 608 bytes ld [$ff00+$55],a ;store length to start DMA ld a,[desiredPixelOffset_x] ld [curPixelOffset_x],a ld a,[desiredPixelOffset_y] ld [curPixelOffset_y],a jr .scroll .checkDMALoad ldio a,[dmaLoad] or a jr z,.scroll .checkLoadBank0 bit 0,a jr z,.checkLoadBank1 .loadBank0 res 0,a ldio [dmaLoad],a ;indicate we've loaded it xor a ld [$ff4f],a ;Initiate DMA transfer to bank 0 VRAM ld a,[dmaLoadSrc0+1] ld [$ff00+$51],a ;high byte of source ld a,[dmaLoadSrc0] ld [$ff00+$52],a ;low byte of source ld a,[dmaLoadDest0+1] ld [$ff00+$53],a ;high byte of dest ld a,[dmaLoadDest0] ld [$ff00+$54],a ;low byte of dest ld a,[dmaLoadLen0] ;copy (N+1)*16 bytes ld [$ff00+$55],a ;store length to start DMA .checkLoadBank1 ldio a,[dmaLoad] bit 1,a jr z,.scroll .loadBank1 res 1,a ldio [dmaLoad],a ;indicate we've loaded it ld a,1 ld [$ff4f],a ;Initiate DMA transfer to bank 1 VRAM ld a,[dmaLoadSrc1+1] ld [$ff00+$51],a ;high byte of source ld a,[dmaLoadSrc1] ld [$ff00+$52],a ;low byte of source ld a,[dmaLoadDest1+1] ld [$ff00+$53],a ;high byte of dest ld a,[dmaLoadDest1] ld [$ff00+$54],a ;low byte of dest ld a,[dmaLoadLen1] ;copy (N+1)*16 bytes ld [$ff00+$55],a ;store length to start DMA .scroll ;Adjust scroll coordinates ld hl,lineZeroHorizontalOffset ldio a,[jiggleDuration] or a jr z,.useNormalScreenOffsets ;jiggle the screen! dec a ldio [jiggleDuration],a ;determine jiggle type ld a,[jiggleType] or a jr nz,.takeoffJiggle .normalJiggle ;pick a "random value" ld a,[jiggleLoc] add 17 ld [jiggleLoc],a ld b,a ;store random value in b and %00000111 ;random x offset ldio [baseHorizontalOffset],a add [hl] ;add lineZeroHorizontalOffset ldio [$ff43],a swap b ld a,%00000111 ;random y offset and b ldio [$ff42],a jr .done .takeoffJiggle ld a,[jiggleLoc] add 17 ld [jiggleLoc],a ld b,a ;store random value in b and %11 ;x offset ldio [$ff43],a swap b ld a,%11 and b ld b,a ld a,[curPixelOffset_y] add b cp 8 jr c,.takeoffVOkay ld a,7 .takeoffVOkay ldio [$ff42],a jr .done .useNormalScreenOffsets ld a,[curPixelOffset_x] ldio [baseHorizontalOffset],a add [hl] ;add lineZeroHorizontalOffset ldio [$ff43],a ld a,[curPixelOffset_y] ldio [$ff42],a ;new palette to copy? ldio a,[paletteBufferReady] or a jr z,.afterPaletteCopy ld c,16 ;c is count ld hl,fadeCurPalette ld a,%10000000 ld [$ff68],a ld [$ff6a],a .paletteCopyBG ld a,[hl+] ;copy sets of 4 bytes to avoid minute but ld [$ff69],a ;killer delays decrementing the counter ld a,[hl+] ld [$ff69],a ld a,[hl+] ld [$ff69],a ld a,[hl+] ld [$ff69],a dec c jr nz,.paletteCopyBG ld c,16 ;c is count .paletteCopyFG ld a,[hl+] ld [$ff6b],a ld a,[hl+] ld [$ff6b],a ld a,[hl+] ld [$ff6b],a ld a,[hl+] ld [$ff6b],a dec c jr nz,.paletteCopyFG xor a ldio [paletteBufferReady],a .afterPaletteCopy .done ;update music ldio a,[musicEnabled] and %10000 jr z,.doneMusic ld hl,musicNoteCountdown dec [hl] call z,PlayMusic .doneMusic ;restore VRAM bank that was in use pop af ld [$ff00+$4f],a pop hl ;restore all regs from stack pop de pop bc pop af reti ;return from interrupt ;--------------------------------------------------------------------- ; Subroutine: OnHBlank ; Description: Called after every line is drawn. ;--------------------------------------------------------------------- OnHBlank:: push af push bc push hl OnHBlank_afterPush: ldio a,[$ff41] ;get stat register bit 2,a ;equal to lyc? jp z,FinishHBlankPlayingSample .continue ld hl,hblankFlag bit 0,[hl] ;turning window on or off? jr nz,OnHBlank_turnOffWindow ;turn on window bit 1,[hl] ;allowed to? jr nz,.turnOn jp z,FinishHBlankPlayingSample .turnOn set 0,[hl] ldio a,[hblankWinOff] ld [$ff45],a ;reset lyc to win off pos ld hl,$ff40 ;turn window on set 5,[hl] OnHBlank_SetBGColorBlack: ;set background palette 0, color zero to black ld b,0 ld c,$68 ld hl,$ff69 ld a,%10000000 ;specification 0 ld [c],a ld [hl],b ld [hl],b ;ld a,%10000110 ;white ;ld [c],a ;ld [hl],h ;ld [hl],h ld a,%10001000 ;palette 1 ld [c],a ld [hl],b ld [hl],b ld a,%10010000 ;palette 2 ld [c],a ld [hl],b ld [hl],b ld a,%10011000 ;palette 3 ld [c],a ld [hl],b ld [hl],b ld a,%10100000 ;palette 4 ld [c],a ld [hl],b ld [hl],b ld a,%10101000 ;palette 5 ld [c],a ld [hl],b ld [hl],b ld a,%10110000 ;palette 6 ld [c],a ld [hl],b ld [hl],b ld a,%10111000 ;palette 7 ld [c],a ld [hl],b ld [hl],b jp FinishHBlankPlayingSample OnHBlank_turnOffWindow: res 0,[hl] ldio a,[hblankWinOn] ld [$ff45],a ;reset lyc to win on pos ld hl,$ff40 ;turn window off res 5,[hl] ;restore background palette 0, color zero push de ld c,$68 ld hl,mapColor ld a,[hl+] ld d,[hl] ld e,a ld hl,$ff69 HBlankSetBGColorCDEHL_DEPushed: ld a,%10000000 ;specification 0 ld [c],a ld [hl],e ld [hl],d ld a,%10001000 ;specification 1 ld [c],a ld [hl],e ld [hl],d ld a,%10010000 ;specification 2 ld [c],a ld [hl],e ld [hl],d ld a,%10011000 ;specification 3 ld [c],a ld [hl],e ld [hl],d ld a,%10100000 ;specification 4 ld [c],a ld [hl],e ld [hl],d ld a,%10101000 ;specification 5 ld [c],a ld [hl],e ld [hl],d ld a,%10110000 ;specification 6 ld [c],a ld [hl],e ld [hl],d ld a,%10111000 ;specification 7 ld [c],a ld [hl],e ld [hl],d ;ld a,%10000110 ;white ;ld [c],a ;ld a,[fadeCurPalette+6] ;ld [hl],a ;ld a,[fadeCurPalette+7] ;ld [hl],a pop de .done jp FinishHBlankPlayingSample ;--------------------------------------------------------------------- ; Subroutine: CinemaOnHBlank ; Description: Called after every line is drawn. ;--------------------------------------------------------------------- CinemaOnHBlank:: push af push bc push hl ldio a,[$ff41] ;get stat register bit 2,a ;equal to lyc? jp z,FinishHBlankPlayingSample .continue ld hl,hblankFlag bit 0,[hl] ;turning window on or off? jr nz,.turnOff ;turn on window bit 1,[hl] ;allowed to? jr nz,.turnOn jp z,FinishHBlankPlayingSample .turnOn set 0,[hl] ldio a,[hblankWinOff] ld [$ff45],a ;reset lyc to win off pos ld hl,$ff40 ;turn window on set 5,[hl] jp FinishHBlankPlayingSample .turnOff res 0,[hl] ldio a,[hblankWinOn] ld [$ff45],a ;reset lyc to win on pos ld hl,$ff40 ;turn window off res 5,[hl] .done jp FinishHBlankPlayingSample ;--------------------------------------------------------------------- ; Subroutine: HOffsetOnHBlank ; Description: Called after every line is drawn. Sets each line's ; horizontal offset from horizontalOffset[144] ;--------------------------------------------------------------------- HOffsetOnHBlank:: push af push bc push hl ;save current RAM bank ldio a,[$ff70] push af ld a,TILEINDEXBANK ldio [$ff70],a ;add to the horizontal offset for next line ld c,$44 ;get $ff44 ld a,[c] ;ypos of refresh (index to array) dec c ;c=$43 ($ff43) inc a ld l,a ld h,((horizontalOffset>>8)&$ff) ldio a,[baseHorizontalOffset] add [hl] ld [c],a ;xpos of screen .afterAdjustOffsets pop af ldio [$ff70],a jp OnHBlank_afterPush ;--------------------------------------------------------------------- ; Subroutine: SeasonsOnHBlank ; Description: Called after every line is drawn. Sets color 0 (all ; bg palettes) to white on line 143 and to brown ($888) ; on line 39. ;--------------------------------------------------------------------- SeasonsOnHBlank:: push af push bc push hl ld a,[amShowingDialog] or a jr nz,.seasonsWindow ;jr z,.normal ;ld a,[hblankFlag] ;and %11 ;jr nz,.seasonsWindow .normal ldio a,[$ff44] ;ypos cp 143 jr z,.toWhite cp 39 jp nz,.seasonsWindow .toBrown push de ld c,$68 ld hl,fadeCurPalette+62 ld a,[hl+] ld d,[hl] ld e,a ld hl,$ff69 jp HBlankSetBGColorCDEHL_DEPushed .toWhite push de ld c,$68 ld hl,mapColor ld a,[hl+] ld d,[hl] ld e,a ld hl,$ff69 jp HBlankSetBGColorCDEHL_DEPushed .seasonsWindow ldio a,[$ff41] ;get stat register bit 2,a ;equal to lyc? jp z,FinishHBlankPlayingSample .continue ld hl,hblankFlag bit 0,[hl] ;turning window on or off? jr nz,.turnOff ;turn on window bit 1,[hl] ;allowed to? jr z,.toBrown ;jr nz,.turnOn ;jp FinishHBlankPlayingSample .turnOn set 0,[hl] ldio a,[hblankWinOff] ld [$ff45],a ;reset lyc to win off pos ld hl,$ff40 ;turn window on set 5,[hl] jp OnHBlank_SetBGColorBlack .turnOff res 0,[hl] ldio a,[hblankWinOn] ld [$ff45],a ;reset lyc to win on pos ld hl,$ff40 ;turn window off res 5,[hl] jr .toBrown ;--------------------------------------------------------------------- ; Routine: GetInput ; Description: Swaps in the link code bank, passes the work along to ; HandleInput, and swaps in the object bank before ; ending. ;--------------------------------------------------------------------- GetInput:: LONGCALLNOARGS HandleInput ;if the heroes are idle then set both inputs to zero ld a,[heroesIdle] or a ret z xor a ld [curJoy0],a ld [curJoy1],a ret ;--------------------------------------------------------------------- ; Routine: CheckPause ; Description: Checks for pause button being pressed ;--------------------------------------------------------------------- CheckPause: ld hl,dialogJoyIndex ld a,[hl] push af ld a,[heroesPresent] cp %11 jr z,.checkBoth dec a ld [hl],a ld a,[myJoy] bit JOY_START_BIT,a jr z,.done jr .checkModes .checkBoth ld [hl],0 ld a,[curInput0] bit JOY_START_BIT,a jr nz,.checkModes ld [hl],1 ld a,[curInput1] bit JOY_START_BIT,a jr z,.done .checkModes ld a,[amShowingDialog] or a jr nz,.done ld a,[displayType] or a jr nz,.done ld a,[amChangingMap] or a jr nz,.done ld a,[heroesIdle] or a jr nz,.done ;(show as dialog) ld a,[dialogSettings] push af call SetPressBDialog call SaveIdle ld de,.afterPause call SetDialogSkip ld a,BANK(GeneratePauseMessage) ld hl,GeneratePauseMessage call LongCallNoArgs ld a,1 ld [amShowingDialog],a ld de,backBuffer+63 call ShowDialogAtTopCommon call DialogWaitInputZero .wait call UpdateObjects call RedrawMap call SetDialogJoy bit JOY_SELECT_BIT,[hl] jr nz,.selectPressed call CheckDialogContinue or a jr z,.wait .afterPause call ClearDialog call RestoreIdle pop af ld [dialogSettings],a .done pop af ld [dialogJoyIndex],a ret .selectPressed call ClearDialog call RestoreIdle pop af ld [dialogSettings],a pop af ld [dialogJoyIndex],a ld a,EXIT_D ld [hero0_enterLevelFacing],a ld [hero1_enterLevelFacing],a ld hl,respawnMap ld a,[hl+] ld [curLevelIndex],a ld a,[hl+] ld [curLevelIndex+1],a ld a,1 ld [timeToChangeLevel],a ret ;--------------------------------------------------------------------- ; Routine: UpdateObjects ; Description: Waits for a vertical blank and then updates the ; objects ;--------------------------------------------------------------------- MainLoopUpdateObjects: call VWait ;wait for a vertical blank ld a,1 ld [checkInputInMainLoop],a call GetInput call CheckPause xor a ld [checkInputInMainLoop],a jr .doneWithInput .vwait call VWait ;wait for a vertical blank .doneWithInput call CheckSpecialFX ;wait for previous frame to be drawn ldio a,[backBufferReady] or a jp nz,.vwait jr UpdateObjectsCommon UpdateObjects:: call VWait ;wait for a vertical blank call GetInput .vwait call VWait ;wait for a vertical blank .doneWithInput call CheckSpecialFX ;wait for previous frame to be drawn ldio a,[backBufferReady] or a jp nz,.vwait UpdateObjectsCommon: ld a,[displayType] or a ret nz ;done if cinema type ;check each object ld b,METHOD_CHECK ld a,[iterateNumObjects] ld c,a call IterateMaxObjects ;update the timers that hero/hero bullets base moves off of call UpdateHeroTimers ;make sure we check the hero & hero's bullets each time ld hl,hero0_index call .checkHeroObjects ld hl,hero1_index call .checkHeroObjects ret .checkHeroObjects ld a,[hl+] ;heroX_index or a ret z ;this hero doesn't exist ld c,a call GetFirst ld b,METHOD_CHECK ;ld e,[hl] ;heroX_objectL ;inc hl ;ld d,[hl] ;heroX_objectH ;inc hl call CallMethod inc hl inc hl ld a,[hl] ;heroX_bulletIndex ld c,a call GetFirst call IterateList ret ;--------------------------------------------------------------------- ; Routine: RedrawMap ; Description: Redraws the map for the next vblank ;--------------------------------------------------------------------- RedrawMap:: call RestrictCameraToBounds call ScrollToCamera call DrawMapToBackBuffer call UpdateEnvEffect ld a,1 ldio [backBufferReady],a ;signal we're ready for DMA ret ;--------------------------------------------------------------------- ; Routine: HandleRemoteInput ; Arguments: a - remoteInput ; Returns: a - remoteInput ; zflag - set if must repeat ; Alters: af ;--------------------------------------------------------------------- HandleRemoteInput:: bit 7,a ;test bit 7 ret z ;got the BCB ;handle the link command code we received. call HandleLCC ;indicate we need to try exchanging our control bytes again ld a,1 or a ;don't set zero flag ret ;--------------------------------------------------------------------- ; Routine: HandleLCC ; Arguments: a - value of the Link Command Code. ; Returns: nothing. ; Alters: af ;--------------------------------------------------------------------- HandleLCC: .checkLGETGAMESTATE cp LGETGAMESTATE jr nz,.checkLGETMAPINDEX ;LGETGAMESTATE LONGCALLNOARGS TransmitGameState ret .checkLGETMAPINDEX cp LGETMAPINDEX jr nz,.checkLUPDATESTATE ;LGETMAPINDEX ld a,[displayType] or a jr nz,.returnDifferentMapCode ;cinema type ld a,[amChangingMap] or a jr nz,.returnWaitCode ld a,[canJoinMap] ;or a ;jr z,.returnWaitCode cp 2 jr z,.returnDifferentMapCode ;do this map independently ld a,[curLevelStateIndex] jr .returnMapIndex .returnWaitCode ld a,$ff jr .returnMapIndex .returnDifferentMapCode ld a,$fe .returnMapIndex call TransmitByte ret .checkLUPDATESTATE cp LUPDATESTATE jr nz,.checkLUPDATEHERO ;LUPDATESTATE push hl ld a,LEVELSTATEBANK ld [$ff70],a call ReceiveByte ld h,((levelState>>8) & $ff) ld l,a call ReceiveByte ld [hl],a pop hl ret .checkLUPDATEHERO cp LUPDATEHERO jr nz,.checkLYANKPLAYER ;LUPDATEHERO call ReceiveByte ld [heroesUsed],a ret .checkLYANKPLAYER cp LYANKPLAYER jr nz,.checkLRESYNCHRONIZE ;LYANKPLAYER ;get exit direction call ReceiveByte ld [hero0_enterLevelFacing],a ;get new map coordinates push bc push af call ReceiveByte ld c,a call ReceiveByte ld b,a ld a,[hero0_enterLevelFacing] and 7 ld [hero0_enterLevelFacing],a ld [hero1_enterLevelFacing],a pop af cp 8 jr nc,.changeMap ld a,[curLevelIndex] cp c jr nz,.changeMap ld a,[curLevelIndex+1] cp b jr z,.noChangeMap .changeMap ld a,c ld [curLevelIndex],a ;map index lobyte ld a,b ld [curLevelIndex+1],a ;map index lobyte ld a,1 ld [timeToChangeLevel],a .noChangeMap ;already on this map pop bc ret .checkLRESYNCHRONIZE cp LRESYNCHRONIZE jr nz,.checkLGETRANDOMSEED LONGCALLNOARGS GuestContinueSynchronization ret .checkLGETRANDOMSEED cp LGETRANDOMSEED jr nz,.checkLTERMINATE ldio a,[randomLoc] call TransmitByte ret .checkLTERMINATE cp LTERMINATE jr nz,.checkLSYNCHRONIZE ld a,[amLinkMaster] cp 1 jr z,.terminateMaster ;terminate slave rst $00 .terminateMaster ld a,$fe ld [amLinkMaster],a ret .checkLSYNCHRONIZE cp LSYNCHRONIZE jr nz,.checkLLOCKHEROES ;LSYNCHRONIZE ;am I ready to synchronize? ld a,[checkInputInMainLoop] or a jr z,.notReadyToSync ld a,[amShowingDialog] or a jr nz,.readyIfCinema ld a,[canJoinMap] or a jr z,.notReadyToSync jr .readyToSynchronize .readyIfCinema ld a,[displayType] or a jr nz,.readyToSynchronize ;not ready .notReadyToSync ld a,LSYNCHWAIT call TransmitByte ret .readyToSynchronize ld a,LSYNCHREADY call TransmitByte LONGCALLNOARGS HostSynchronize ret .checkLLOCKHEROES cp LLOCKHEROES jr nz,.checkLNOLINK call ReceiveByte ;receive lock or unlock from remote ld [heroesLocked],a ret .checkLNOLINK cp LNOLINK jr nz,.checkLLINKTEST ret .checkLLINKTEST cp LLINKTEST jr nz,.checkLCHANGEAPPXMAP LONGCALLNOARGS LinkTest ret .checkLCHANGEAPPXMAP cp LCHANGEAPPXMAP jr nz,.checkLADDINVITEM LONGCALLNOARGS NewAppxLocation ret .checkLADDINVITEM cp LADDINVITEM jr nz,.checkLREMINVITEM push bc call ReceiveByte ;get bc (inventory item) ld c,a call ReceiveByte ld b,a ;duplicate code also in Map.asm push hl call PointHLToInventory or c ld [hl],a pop hl pop bc ret .checkLREMINVITEM cp LREMINVITEM jr nz,.checkLUPDATEMEMORY ;duplicate code also in Map.asm push bc call ReceiveByte ;get bc (inventory item) ld c,a call ReceiveByte ld b,a ;duplicate code also in Map.asm push hl call PointHLToInventory xor $ff or c xor $ff ld [hl],a pop hl pop bc ret .checkLUPDATEMEMORY cp LUPDATEMEMORY jr nz,.unknown push hl call ReceiveByte ;memory bank of data ldio [$ff70],a call ReceiveByte ;address ld l,a call ReceiveByte ld h,a call ReceiveByte ;new value ld [hl],a pop hl ret .unknown ret ;--------------------------------------------------------------------- ; Routines: LLTransmitByte ; Arguments: a - byte to send ; [amLinkMaster] - should be set to 1 or 0 ; Returns: Nothing. ; Alters: af ; Note: DON'T CALL THIS DIRECTLY. It should only be called ; via TransmitByte and ReceiveByte. ; Description: Low-level routine to transmit a byte via the link ; cable. ;--------------------------------------------------------------------- LLTransmitByte: di ;be sure we're not interrupted ldio [$ff01],a ;store the data to transfer ld a,INTCLK ldio [$ff02],a ;let's do it .waitForCompletion ldio a,[$ff02] ;12 and $80 ; 8 jr nz,.waitForCompletion ; 8 ;go into slave mode to await next byte ld a,EXTCLK ; 8 ldio [$ff02],a ;12 TOTAL = 48 ;clear pending interrupts xor a ei ld [$ff0f],a ret ;--------------------------------------------------------------------- ; Routines: LLReceiveByte ; Arguments: [amLinkMaster] - should be set to 1 or 0 ; Returns: a - byte received from linked GameBoy. ; Alters: af ; Note: DON'T CALL THIS DIRECTLY. It should only be called ; via TransmitByte and ReceiveByte. ; Description: Low-level routine to receive a byte via the link ; cable. If no signal within nine seconds aborts link ; connection and: ; Master - continues game as slaveless master ($fe). ; Slave - restarts game. ;--------------------------------------------------------------------- LLReceiveByte: push bc push de ld de,$0C00 ;abort timer counts down $C00 * 256 times ld c,0 ;(about 1.25 sec per $100) .waitForCompletion ldio a,[$ff02] and $80 jr z,.gotValue ;update our abort timer dec c jr nz,.waitForCompletion dec de xor a cp d jr nz,.waitForCompletion cp e jr nz,.waitForCompletion jr .linkLost .gotValue ldio a,[$ff01] ;return the value we received ;kill some time before we let ourselves change to master ;to give the current master time to change to slave push af .killOuter ld a,6 .killTime dec a ; 4 jr nz,.killTime ; 4/8 TOTAL = 8, *6=48 pop af jr .done .linkLost ld a,[amLinkMaster] or a jr z,.amSlave cp 1 jr z,.amMaster ;link already lost, restore stack & jump to bail-out address ;if not 0 ld a,[linkBailOut] ;get bail-out address ld e,a ld a,[linkBailOut+1] ld d,a xor a cp d jr nz,.bail cp e jr nz,.bail ;null bail address; just quit jr .done .bail ;restore the stack before jumping to the bail address ld a,[linkBailOut+2] ld l,a ld a,[linkBailOut+3] ld h,a ld sp,hl push de ret .amMaster ld a,$fe ld [amLinkMaster],a call RemoveRemoteHero jr .done .amSlave rst $00 ;restart the game .done pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: TransmitByte ; Argument: a - byte to send ; Returns: Nothing. ; Alters: af ; Description: Transmits a byte via the link cable to a remote GBC. ;--------------------------------------------------------------------- TransmitByte:: push bc ld b,a ;If I was the last one to transmit, receive a byte as an ;acknowledgement. ld a,[lastLinkAction] or a jr z,.afterOrientStream call LLReceiveByte .afterOrientStream ld a,1 ;our action this time is to transmit ld [lastLinkAction],a ld a,b call LLTransmitByte .done pop bc ret ;--------------------------------------------------------------------- ; Routine: ReceiveByte ; Arguments: None. ; Returns: a - byte received. ; Alters: af ; Description: Receives a byte from a remote machine. ;--------------------------------------------------------------------- ReceiveByte:: ;If necessary we'll transmit a value to avoid receiving twice ;in a row. ld a,[lastLinkAction] or a jr nz,.afterOrientStream ld a,1 call LLTransmitByte .afterOrientStream xor a ;our action this time is to receive ld [lastLinkAction],a call LLReceiveByte ret ;--------------------------------------------------------------------- ; Routine: ExchangeByte ; Argument: a - byte to send ; Returns: a - byte received in return ; Alters: af ; Description: Uses value of [amLinkMaster] (Master should be $01 and ; Slave should be $00) to determine sequencing of ; TransmitByte and ReceiveByte. ;--------------------------------------------------------------------- ExchangeByte:: push bc ld b,a ld a,[amLinkMaster] or a jr z,.slaveExchange ;masterExchange ld a,b call TransmitByte call ReceiveByte jr .done .slaveExchange call ReceiveByte ld c,a ld a,b call TransmitByte ld a,c .done pop bc ret ;--------------------------------------------------------------------- ; Routine: TransmitData ; Arguments: a - RAM bank to switch to (may/may not make a diff) ; bc - number of bytes to transmit ; hl - starting address of data to transmit ; Returns: Nothing. ; Alters: af ;--------------------------------------------------------------------- TransmitData:: push bc push hl ldio [$ff70],a .loop ld a,[hl+] call TransmitByte dec bc xor a cp b jr nz,.loop cp c jr nz,.loop pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: ReceiveData ; Arguments: a - RAM bank to switch to (may/may not make a diff) ; bc - number of bytes to receive ; hl - starting address to store data ; Returns: Nothing. ; Alters: af ;--------------------------------------------------------------------- ReceiveData:: push bc push hl ldio [$ff70],a ;change RAM bank .loop call ReceiveByte ld [hl+],a dec bc xor a cp b jr nz,.loop cp c jr nz,.loop pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: TransmitCompressedData ; Arguments: a - RAM bank to switch to (may/may not make a diff) ; bc - number of bytes to transmit ; hl - starting address of data to transmit ; Returns: Nothing. ; Alters: af ; Description: Packs bytes 8:1 into the backBuffer by combining ; bit[0] from every eight bytes into one byte. The ; left-most bit will be from byte[0] and the right-most ; from byte[7]. ;--------------------------------------------------------------------- TransmitCompressedData:: push bc push de push hl ldio [$ff70],a ;divide len by 8 (>>3) srl b rr c srl b rr c srl b rr c push bc ;save length ;----Compress the data into backBuffer------------------------ ld de,backBuffer ;compression buffer .nextByte push de ;push destination ld de,8 ;d is compressed (0), e is times to loop .nextBit ld a,[hl+] ;get the next byte rrca ;shift out bit[0] into the carry flag rl d ;rotate onto right side of result dec e jr nz,.nextBit ld a,d ;a has compressed byte pop de ;pop destination ld [de],a ;store the compressed byte inc de dec bc xor a cp b jr nz,.nextByte cp c jr nz,.nextByte pop bc ;done with compression, retrieve len ld hl,backBuffer ;transmit the compressed data xor a call TransmitData pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: ReceiveCompressedData ; Arguments: a - RAM bank to switch to (may/may not make a diff) ; bc - number of bytes to receive ; hl - starting address of data to receive ; Returns: Nothing. ; Alters: af ; Description: Receives numBytes/8 into the backBuffer, then unpacks ; each byte 1:8 to the data address. ;--------------------------------------------------------------------- ReceiveCompressedData:: push bc push de push hl push af ;save original RAM bank push hl ;save original dest ;----Calculate numBytes/8 (>>3)------------------------------- srl b rr c srl b rr c srl b rr c ld hl,backBuffer ;receive the compressed data xor a call ReceiveData pop hl ;retrieve original dest pop af ;retrieve original RAM bank ldio [$ff70],a ;----Decompress the data into the destination buffer---------- ld de,backBuffer ;decompression buffer .nextByte ld a,[de] ;get a byte from the buffer inc de push de ;push source ld d,a ;store compressed byte in d ld e,8 ;e is times to loop .nextBit xor a rl d ;get a bit off left side of compressed rla ;shift onto right side of uncompressed ld [hl+],a ;store in final destination dec e jr nz,.nextBit pop de ;pop source dec bc xor a cp b jr nz,.nextByte cp c jr nz,.nextByte pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: CheckSimultaneousLCC ; Argument: a - byte received from link exchange ; Returns: not z flag - this machine must repeat its command ; z flag set - everything is okay ; Alters: af ; Description: Called after one machine has sent the first byte of ; a Link Command Code. If the remote machine ; coincidentally sent its own LCC at the same time then ; the Slave must delay its own LCC until the Master's ; LCC has been handled. ;--------------------------------------------------------------------- CheckSimultaneousLCC:: bit 7,a ;see if we got a LCC or a BCB. ret z ;Got a BCB, everything's cool. ;Got a LCC. If I'm the Master then the other machine must ;yield to me so everything's still cool. push af ld a,[amLinkMaster] or a jr z,.amSlave pop af xor a ret .amSlave ;I must yield to the Master. Handle his request and then ;return a value indicating I must repeat my own request. pop af call HandleLCC ld a,1 or a ret ;--------------------------------------------------------------------- ; Routine: YankRemotePlayer ; Arguments: a - exit to set to (>7 means &7 and don't check ; to see if you're on the map) ; ; hl - map to set to in BCD (e.g. $0205) ; Returns: Nothing. ; Alters: af ; Description: Interrupts whatever the other player is doing and ; sets him to come to the specified map. Also sets ; the join/respawn map to the map to set to. ;--------------------------------------------------------------------- YankRemotePlayer:: push af call UpdateState call SetJoinMap call SetRespawnMap pop af ;verify link established push hl ld hl,amLinkMaster bit 7,[hl] pop hl ret nz push af push hl ld a,2 ;two additional things on stack ld hl,.linkBailAddress call SetLinkBailOutAddress pop hl .sendYank ld a,LYANKPLAYER call ExchangeByte call CheckSimultaneousLCC jr nz,.sendYank pop af ;remote machine is listening; send map coords call TransmitByte ;exit dir ld a,l call TransmitByte ld a,h call TransmitByte .linkBailAddress push hl ld hl,0 xor a call SetLinkBailOutAddress pop hl ret ;--------------------------------------------------------------------- ; Routine: RemoveRemoteHero ; Arguments: None. ; Returns: Nothing. ; Alters: af ; Description: Deletes the remote hero and removes traces of its ; presence. ;--------------------------------------------------------------------- RemoveRemoteHero:: push bc push de push hl ;determine which is the remote hero ld a,[amLinkMaster] or a jr z,.amSlave .amMaster ld hl,hero1_index jr .determinedRemoteHero .amSlave ld hl,hero0_index .determinedRemoteHero ;remove remote hero from map if present ld a,[hl] ;heroX_index or a jr z,.done ;not here ;save the current ROM & switch in the object ROM ldio a,[curROMBank] push af ld a,CLASSROM call SetActiveROM ;----remove this one's heroesPresent flag---- ld a,[hl] ;heroX_index push af ld a,l and 16 IF HERODATASIZE!=16 fix this ENDC swap a ;a is now 1 or 0 add 1 ;now 2 or 1 xor $ff ;now ~2 or ~1 ld b,a ld a,[heroesPresent] and b ld [heroesPresent],a ;push hl ;ld de,(HERODATA_TYPE - HERODATA_INDEX) ;add hl,de ;ld a,[hl] ;heroX_type ;xor $ff ;ld b,a ;ld a,[heroesPresent] ;and b ;ld [heroesPresent],a ;pop hl xor a ld [hl],a ;heroX_index pop af ld c,a call GetFirst ld b,METHOD_DIE call CallMethod ;restore the old ROM pop af call SetActiveROM .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: DebugMesg ; Argument: hl - pointer to a gtx structure ; Returns: Nothing. ; Alters: af ; Description: Displays the given gtx string in a window for a ; brief period. ;--------------------------------------------------------------------- DebugMesg:: push bc push de push hl ldio a,[$ff40] and %10000000 jr z,.done ld d,h ld e,l xor a ;-------Show Dialog At Top------------------- push af push bc push de push hl ld b,0 ;lines to skip at top ld a,[curROMBank] call ShowDialogCommon 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 pop hl pop de pop bc pop af ;-------Show Dialog At Top------------------- ld bc,16384 call TimerDelay call ClearDialog .done pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: DebugVal ; Argument: a - byte to show as a hex value ; Returns: Nothing. ; Alters: Nothing. ; Description: Displays the given value in hex using a Dialog ; window for a brief period. Game must be on. ;--------------------------------------------------------------------- DebugVal:: push af push bc push de push hl ld b,a ;save byte ldio a,[$ff40] and %10000000 jr z,.done ld hl,$c200 ld [hl],1 inc hl ld [hl],1 inc hl ld [hl],2 inc hl ld a,b ld c,0 swap a and $0f add 200 ld [hl+],a ld a,b and $0f add 200 ld [hl+],a ld de,$c200 xor a ;-------Show Dialog At Top------------------- push af push bc push de push hl ld b,0 ;lines to skip at top ld a,[curROMBank] call ShowDialogCommon 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 pop hl pop de pop bc pop af ;-------Show Dialog At Top------------------- ld bc,8192 ;16384 call TimerDelay call ClearDialog .done pop hl pop de pop bc pop af ret ;--------------------------------------------------------------------- ; Routine: TimerDelay ; Argument: bc - number of 16384's of a second to delay ; Alters: af ;--------------------------------------------------------------------- TimerDelay:: push bc push de push hl ld hl,$ff04 ld d,0 ;prev value of time ld [hl],0 .wait ld a,[hl] ld e,a xor d ;equal to prev value? jr z,.wait ld d,e dec bc xor a cp b jr nz,.wait cp c jr nz,.wait pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: SetDialogSkip ; SetDialogForward ; Arguments: de - position to skip or fast forward to ; Alters: af ; Description: Saves the stack pointer (minus the space that this ; function call is taking up) and sets the go-to ; address for fast forwarding (any button pressed) ; or skipping (start button pressed). ;--------------------------------------------------------------------- SetDialogSkip:: push hl ld hl,sp+4 ;stack ptr pos once returned from this fn ld a,e ld [levelCheckSkip+2],a ;set skip forward addr ld a,d ld [levelCheckSkip+3],a jr SetDialogCommon SetDialogForward:: push hl ld hl,sp+4 ;stack ptr pos once returned from this fn ld a,e ;set fast forward addr ld [levelCheckSkip],a ld a,d ld [levelCheckSkip+1],a jr SetDialogCommon SetSkipStackPos:: push hl ld hl,sp+4 ;stack ptr pos once returned from this fn SetDialogCommon: ld a,l ld [levelCheckStackPos],a ld a,h ld [levelCheckStackPos+1],a pop hl ret ;--------------------------------------------------------------------- ; Routine: ClearDialogSkipForward ; Arguments: None. ; Alters: af,hl ;--------------------------------------------------------------------- ClearDialogSkipForward:: call ClearDialog call ClearSkipForward ret ;--------------------------------------------------------------------- ; Routine: ClearSkipForward ; Arguments: None. ; Alters: af,hl ;--------------------------------------------------------------------- ClearSkipForward:: ld de,0 call SetDialogSkip call SetDialogForward ret ;--------------------------------------------------------------------- ; Routine: SetRespawnMap ; Arguments: hl - map to go to after hero dies ; Returns: Nothing. ; Alters: af ;--------------------------------------------------------------------- SetRespawnMap:: ld a,l ld [respawnMap],a ld a,h ld [respawnMap+1],a ret ;--------------------------------------------------------------------- ; Routine: SetJoinMap ; Arguments: hl - map to join from 2nd player title screen ; Returns: Nothing. ; Alters: af ;--------------------------------------------------------------------- SetJoinMap:: ld a,l ld [joinMap],a ld a,h ld [joinMap+1],a ret ;--------------------------------------------------------------------- ; Routine: SetLinkBailOutAddress ; Arguments: a - number of additional words to add to stack ; pointer ; hl - saves stack pointer and bailout address into ; [linkBailOut0...3]. ; Returns: Nothing. ; Alters: af ;--------------------------------------------------------------------- SetLinkBailOutAddress:: push hl push af ;save bail out address ld a,l ld [linkBailOut],a ld a,h ld [linkBailOut+1],a ;save stack pointer (plus a*2 + 6 for things pushed on stack) ld hl,sp+6 pop af or a jr z,.afterAdjustStackPointer .adjustStackPointer inc hl inc hl dec a jr nz,.adjustStackPointer .afterAdjustStackPointer ld a,l ld [linkBailOut+2],a ld a,h ld [linkBailOut+3],a pop hl ret ;--------------------------------------------------------------------- ; Routine: RemoveSpriteObjectsFromMap ;--------------------------------------------------------------------- RemoveSpriteObjectsFromMap: ;----remove all objects from the map-------------------------- ld a,OBJLISTBANK ldio [$ff70],a ld hl,objExists+1 .removeObjectsLoop push hl ld a,[hl] or a jr z,.removeObjects_continue ld a,l call IndexToPointerDE ld a,[numClasses] ld b,a inc b ld h,((objClassLookup>>8) & $ff) ld a,[hl] cp b ;this obj a regular creature? jr nc,.removeObjects_continue call GetFacing bit 7,a ;sprite? jr z,.restoreObjListBank ;no ld c,a call RemoveFromMap .restoreObjListBank ld a,OBJLISTBANK ldio [$ff70],a .removeObjects_continue pop hl inc hl ld a,h cp ((objExists>>8) & $ff) + 1 jr nz,.removeObjectsLoop ret ;--------------------------------------------------------------------- ; Routine: GetMethodAddrFromPointer ; Arguments: hl - pointer to method address ; Returns: hl - pointer to method ; Alters: af ;--------------------------------------------------------------------- GetMethodAddrFromPointer:: PUSHROM ld a,BANK(classTable) call SetActiveROM ld a,[hl+] ld h,[hl] ld l,a POPROM ret ;--------------------------------------------------------------------- ; Routine: InstallHBlankHandler ; Arguments: hl - pointer to hblank handler ; Returns: Nothing. ; Alters: af ;--------------------------------------------------------------------- InstallHBlankHandler:: di ld a,l ld [hblankVector+1],a ;+0 is opcode "jp" ld a,h ld [hblankVector+2],a ei ret ;--------------------------------------------------------------------- ; Routine: LockRemoteHeroesUsed ; Arguments: None. ; Returns: z - lock attempt unsuccessful ; nz - success ; Alters: af ; Description: Informs the remote machine that this machine is ; messing with the heroes to prevent collisions ;--------------------------------------------------------------------- LockRemoteHeroesUsed:: ld a,[amLinkMaster] bit 7,a jr nz,.lockOkay .sendLock ld a,[heroesLocked] or a jr nz,.returnFailure ld a,LLOCKHEROES call ExchangeByte call CheckSimultaneousLCC jr nz,.sendLock ld a,1 ;send "locked" to remote call TransmitByte .lockOkay ld a,1 ld [heroesLocked],a or a ret .returnFailure xor a ret ;--------------------------------------------------------------------- ; Routine: UpdateRemoteHeroesUsed ; Arguments: None. ; Returns: Nothing. ; Alters: af ; Description: Sends current [heroesUsed] to the remote machine ; if present. Also unlocks heroesUsed if locked. ;--------------------------------------------------------------------- UpdateRemoteHeroesUsed:: ld a,[amLinkMaster] bit 7,a jr z,.updateHeroesUsed ;no link, free lock xor a ld [heroesLocked],a ret .updateHeroesUsed ld a,LUPDATEHERO call ExchangeByte call CheckSimultaneousLCC jr nz,.updateHeroesUsed ;must repeat ld a,[heroesUsed] call TransmitByte ld a,[heroesLocked] or a ret z ;not locked don't bother .sendLock ld a,LLOCKHEROES call ExchangeByte call CheckSimultaneousLCC jr nz,.sendLock xor a ;send "unlocked" to remote ld [heroesLocked],a call TransmitByte ret ;--------------------------------------------------------------------- ; Routine: PlaySample ; Arguments: a - bank of sample ; hl - start address of sample ; Alters: af,hl ; Description: ;--------------------------------------------------------------------- PlaySample:: ;start sample playing di ldio [sampleBank],a xor a ldio [samplePlaying],a ei ld a,l ldio [sampleAddress],a ld a,h ldio [sampleAddress+1],a ld a,$0f ldio [sampleMask],a ld a,$86 ldio [$ff1a],a ;sound 3 enable ld hl,$ff26 set 2,[hl] ld a,1 ldio [samplePlaying],a ret ;--------------------------------------------------------------------- ; FinishHBlankPlayingSample ;--------------------------------------------------------------------- FinishHBlankPlayingSample:: ldio a,[samplePlaying] or a jr z,.done .nextSample ld hl,sampleAddress ld a,[hl+] ld h,[hl] ld l,a .loadNextSample ldio a,[sampleBank] ld [$2100],a ldio a,[sampleMask] xor $ff ldio [sampleMask],a cp $0f jr nz,.getLeftNibble .getRightNibble and a,[hl] inc hl jr .normalData ;will never be special code .getLeftNibble and a,[hl] ;next sample byte .checkForSpecialCodes cp $80 jr nz,.normalData ;code indicating termination or link follows inc hl ld a,[hl+] or a jr nz,.link ld [samplePlaying],a ld a,$ff ld [$ff24],a ;full volume both channels jr .restoreBank .link ld a,[hl+] ld [sampleBank],a ld a,[hl+] ld h,[hl] ld l,a jr .loadNextSample .normalData ld b,a swap a or b or $88 ldio [$ff24],a ;sound enabled/volume .saveNewAddress ld a,l ldio [sampleAddress],a ld a,h ldio [sampleAddress+1],a .restoreBank ldio a,[curROMBank] ld [$2100],a .done pop hl pop bc pop af reti ;--------------------------------------------------------------------- ; Routine: Lookup8 ; Arguments: a - index ; hl - start lookup table ; Alters: af,hl ; Returns: a - table[a] ;--------------------------------------------------------------------- Lookup8:: add l ld l,a ld a,h adc 0 ld h,a ld a,[hl] ret ;--------------------------------------------------------------------- ; Routine: Lookup16 ; Arguments: a - index ; hl - start lookup table ; Alters: af,hl ; Returns: hl - table[a*2] ;--------------------------------------------------------------------- Lookup16:: push de ld e,a ld d,0 sla e rl d add hl,de ld a,[hl+] ld h,[hl] ld l,a pop de ret ;--------------------------------------------------------------------- ; Routine: LookupIndexOfData8 ; Arguments: a - data ; hl - start of lookup table ; Alters: af,hl ; Returns: a - where table[a] is original data a. ; Data must exist! ;--------------------------------------------------------------------- LookupIndexOfData8:: push bc ld c,0 .findLoop cp [hl] jr z,.done inc c inc hl jr .findLoop .done ld a,c pop bc ret ;--------------------------------------------------------------------- ; Routine: FindFirstBGLoc ; Arguments: hl - bg class to find (e.g. classClearanceBG) ; Returns: hl - first location of class ; a - 0 on failure ; zflag - or a ; Alters: af ;--------------------------------------------------------------------- FindFirstBGLoc:: push bc push de push hl pop bc call FindClassIndex ld b,a ld a,MAPBANK ld [$ff70],a ;setup de with first out-of-bounds index ld a,[mapTotalSize] ld e,a ld a,[mapTotalSize+1] ld d,a ld hl,map .lookForFirst ld a,[hl+] cp b jr z,.foundIt ;hl < de? ld a,h cp d jr c,.lookForFirst ld a,l cp e jr c,.lookForFirst ;not found xor a jr .done .foundIt dec hl ld a,1 or a .done pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: LinkTransmitMemoryLocation ; Arguments: a - RAM bank ; hl - memory location to transmit to the remote ; GameBoy ; Alters: af ;--------------------------------------------------------------------- LinkTransmitMemoryLocation:: push bc ld b,a ld a,[amLinkMaster] bit 7,a jr nz,.done ;not linked .requestTransmit ld a,LUPDATEMEMORY call ExchangeByte call CheckSimultaneousLCC jr nz,.requestTransmit ld a,b ldio [$ff70],a call TransmitByte ld a,l call TransmitByte ld a,h call TransmitByte ld a,[hl] call TransmitByte .done pop bc ret ;--------------------------------------------------------------------- ; Link Code ;--------------------------------------------------------------------- SECTION "LinkCodeSection",ROMX linkCode: ;--------------------------------------------------------------------- ; Routine: HandleInput ; Description: Polls the buttons and stores the input in [curInput0]. ; Then performs some network code and sets up [curJoy0], ; [curJoy1], [curInput0], and [curInput1]. curJoyX may ; be set to zero elsewhere to prevent the heroes from ; moving but curInput0 and curInput1 will always be the ; original values. ; ; $80 - 7:Start ; $40 - 6:Select ; $20 - 5:B ; $10 - 4:A ; $08 - 3:Down ; $04 - 2:Up ; $02 - 1:Left ; $01 - 0:Right ; ; A linked Master should read its input from [curJoy0]. ; A linked Slave should read its input from [curJoy1]. ; To make this easier [myJoy] is set up to be the ; appropriate one. ; ; If no link connection established, attempt a link ; connection. ; ; If no link: ; Convert curInput0->Joy1 (result will be same as ; encoding then decoding curInput). ; ; If link connection established: ; Exchange Control Byte with linked machine. If ; Command Code gotten in return, perform requested ; action and then repeat attempt to exchange control ; byte. ; ; If Master: curInput0->Joy1, remoteInput->Joy2 ; If Slave: curInput0->Joy2, remoteInput->Joy1 ;--------------------------------------------------------------------- HandleInput: ld a,$20 ldio [$ff00],a ;select P14 ldio a,[$ff00] ldio a,[$ff00] ;wait a few cycles cpl and $0f ld b,a ;b has direction info ld a,$10 ;select P15 ld [$ff00],a ldio a,[$ff00] ;wait mo ldio a,[$ff00] ;wait mo ldio a,[$ff00] ;wait mo ldio a,[$ff00] ;wait mo ldio a,[$ff00] ;wait mo ldio a,[$ff00] ;wait mo cpl and $0f swap a or b ;a has all buttons ld [curInput0],a ld a,$30 ;deselect P14 and P15 ldio [$ff00],a ;--if no link, attempt link connection ---------------------- ld a,[amLinkMaster] cp $ff jr z,.afterLinkAttempt ;L1101 attempts link as slave cp $fe ;attempt link as master? jr nz,.afterLinkAttempt .attemptLinkAsMaster ld a,$55 ldio [$ff01],a ;exchange data = $55 ld a,INTCLK ;ready to xchg, use my clock ldio [$ff02],a .waitMasterLinkAttempt ldio a,[$ff02] and $80 jr nz,.waitMasterLinkAttempt ;see what we got ldio a,[$ff01] cp $aa jr nz,.afterLinkAttempt ;found a Slave! That means I'm the Master! ld a,EXTCLK ;switch to receive mode ldio [$ff02],a ld a,1 ld [amLinkMaster],a ld [lastLinkAction],a .afterLinkAttempt ld a,[amLinkMaster] bit 7,a jr z,.amLinked ;no link, convert curInput->curJoy0. ld a,[curInput0] call ConvertInput ld [curInput0],a ld [curJoy0],a ld [myJoy],a xor a ld [curJoy1],a ld [curInput1],a ret .amLinked IF 0 ;----every second or so, get the remote machine's ;----random seed and make sure it matches ours. ;----Resynchronize the machines if not ld a,[amLinkMaster] cp 1 jr nz,.exchangeBCB ;only master can initiate ld a,[updateTimer] ;not time yet and 31 cp 31 jr nz,.exchangeBCB ;don't do it if can't join map ld a,[canJoinMap] or a jr z,.exchangeBCB .getRandomSeed ld a,LGETRANDOMSEED ;send the request call ExchangeByte call CheckSimultaneousLCC jr nz,.getRandomSeed ;must repeat ;get the actual seed call ReceiveByte ld b,a ld a,[randomLoc] cp b ;got same in return? jr z,.exchangeBCB ;continue if yes ;on same map? ld a,[heroesPresent] cp %11 jr nz,.exchangeBCB ;not on same map .resynchronize ;resynchronize machines ld a,LRESYNCHRONIZE call ExchangeByte call CheckSimultaneousLCC jr nz,.resynchronize LONGCALLNOARGS HostResynchronize ENDC .exchangeBCB ;----exchange Button Control Bytes with remote machine-------- ld a,[curInput0] call EncodeInput call ExchangeByte call HandleRemoteInput jr nz,.exchangeBCB ;must repeat ;--Decode Button Control Bytes-------------------------------- push af ;save remoteInput ld a,[amLinkMaster] or a jr z,.amLinkSlave ;I am the master. curInput0->curJoy0, remoteInput->curJoy1 pop af ;retrieve remoteInput call DecodeInput ld [curInput1],a ld [curJoy1],a ld a,[curInput0] call ConvertInput ld [curInput0],a ld [curJoy0],a ld [myJoy],a ret .amLinkSlave ld a,[curInput0] call ConvertInput ld [curInput1],a ld [curJoy1],a ld [myJoy],a pop af ;retrieve remoteInput call DecodeInput ld [curInput0],a ld [curJoy0],a ret ;--------------------------------------------------------------------- ; Routine: ConvertInput ; Argument: a - uncoded button control byte ; Returns: a - converted BCB, same as calling Encode then ; Decode but quicker ; Description: To simulate uncoded->encoded->decoded, forces buttons ; 7:4 to have A/B or Start/Select info but not both ; (A/B has priority). ; Alters: af ;--------------------------------------------------------------------- ConvertInput: push bc ld b,a ;save original and %00110000 ;has A/B info? ld a,b ;restore original jr z,.done ;if no AB info then conv. complete and %00111111 ;has AB info; clear out start/sel .done pop bc ret ;--------------------------------------------------------------------- ; Routine: EncodeInput ; Argument: a - uncoded button control byte ; 7:st 6:se 5:b 4:a 3:0=DULR ; Returns: a - coded button control byte ; 7=0 ; 6=0 - 5:4 = ba ; =1 - 5:4 = te (start, select) ; 3:0 = DULR ; Alters: af ;--------------------------------------------------------------------- EncodeInput: push bc push hl ld b,a ;save original and %00001111 ld c,a ;save D-PAD ld h,((encodeControlByteTable>>8) & $ff) ld a,b swap a and %00001111 add (encodeControlByteTable & $ff) ld l,a ld a,[hl] ;get encoded buttons or c ;combine with D-PAD pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: DecodeInput ; Argument: a - coded Control Byte ; Returns: a - uncoded button Control Byte ; Alters: af ;--------------------------------------------------------------------- DecodeInput: push bc push hl ld b,a ;save original and %00001111 ld c,a ;save D-PAD ld h,((decodeControlByteTable>>8) & $ff) ld a,b swap a and %00000111 add (decodeControlByteTable & $ff) ld l,a ld a,[hl] ;get decoded buttons or c ;combine with D-PAD pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: TransmitGameState ; Arguments: none ; Returns: none ; Alters: af ; Description: Transmits relevant game state data to Slave ; Includes hero data so slave's classes will be set ; appropriately ;--------------------------------------------------------------------- TransmitGameState: push bc push hl ld hl,.linkBailAddress xor a call SetLinkBailOutAddress ld hl,gameState ld bc,5 xor a ;RAM bank doesn't matter call TransmitData ld hl,levelState ld bc,256 ld a,LEVELSTATEBANK call TransmitData ld hl,inventory ld bc,16 xor a call TransmitData ld hl,flightCode ld bc,256 ld a,FLIGHTCODEBANK call TransmitData ld hl,hero0_data ld bc,HERODATASIZE * 2 xor a call TransmitData ld a,[appomattoxMapIndex] call TransmitByte ;send the joinMap ld a,[joinMap] call TransmitByte ld a,[joinMap+1] call TransmitByte .linkBailAddress ld hl,0 xor a call SetLinkBailOutAddress pop hl pop bc ret ;--------------------------------------------------------------------- ; Routine: HostSynchronize ; Arguments: none ; Returns: none ; Alters: af ; Description: Transmits relevant map data to Guest ;--------------------------------------------------------------------- HostResynchronize: push bc push hl jr HostSynchronizeCommon HostSynchronize: push bc push hl ld hl,.nogo xor a call SetLinkBailOutAddress ld a,1 ;make sure it's looking at 1x1 ldio [curObjWidthHeight],a call ReceiveByte ;guest's requested exit direction ld hl,$0101 ;start looking at (1,1) call FindExitLocation xor a ;didn't find it if $0000 cp h jr nz,.goAhead cp l jr nz,.goAhead ;nogo xor a call TransmitByte .nogo ld hl,0 xor a call SetLinkBailOutAddress pop hl pop bc ret .goAhead call ConvertLocHLToXY ld a,1 call TransmitByte ldio a,[mapState] ;level state call TransmitByte ldio a,[mapState+1] call TransmitByte ;make sure backbuffer doesn't redraw during hero loading xor a ldio [backBufferReady],a ;activate heroes 0 and 1 ld a,[hero0_index] or a jr nz,.hero0_active ld a,1 ld [hero0_index],a .hero0_active ld a,[hero1_index] or a jr nz,.hero1_active ld a,1 ld [hero1_index],a .hero1_active call HostExchangeHeroData ;set hero 1 to joystick 1 push hl ld a,[hero1_type] ld hl,heroJoyIndex or [hl] ld [hl],a pop hl inc hl ld b,h ld c,l PREPLONGCALL .afterSetupHero LONGCALL PrepSetupHeroBC ;bc is correct hero data .afterSetupHero HostSynchronizeCommon: xor a ld [backBufferReady],a ;wait on ready signal from guest .waitReady call ReceiveByte cp LSYNCHREADY jr nz,.waitReady ;send all my hero data ;re-send all my hero data ld hl,hero0_data ld bc,HERODATASIZE*2 xor a call TransmitData ld a,[randomLoc] ;current random value/seed call TransmitByte ld a,[heroesIdle] call TransmitByte LONGCALLNOARGS RemoveSpriteObjectsFromMap ;----transmit map--------------------------------------------- ld hl,map ld bc,4096 ld a,MAPBANK call TransmitData ;fadeCurPalette ld hl,fadeCurPalette ld bc,128 xor a call TransmitData ;gamePalette ld hl,gamePalette ld bc,128 ld a,FADEBANK call TransmitData ;first 16 bytes of level check RAM ld hl,levelCheckRAM ld bc,16 xor a call TransmitData ;spriteOAMdata ld hl,spriteOAMBuffer ld bc,160 xor a call TransmitData ld hl,headTable ;headTable - linked list head ld bc,256 ld a,OBJLISTBANK call TransmitData ld hl,objExists ;objExists, FOF table ld bc,512 ld a,OBJLISTBANK call TransmitCompressedData ld a,[numClasses] call TransmitByte ;bc = numClasses times two + 2 ld a,[numClasses] ld b,0 ld c,a sla c rl b inc bc inc bc ld hl,classLookup ;objExists, FOF table ;ld bc,512 numClasses * 2 ld a,OBJLISTBANK call TransmitData ld hl,fgTileMap ld a,[numClasses] ld b,0 ld c,a ld a,OBJLISTBANK call TransmitData ld hl,objClassLookup ;class indices for each obj ld bc,256 ld a,OBJLISTBANK call TransmitData ld hl,associatedIndex ld bc,256 ld a,OBJLISTBANK call TransmitData ld hl,spritesUsed ld bc,40 ld a,OBJLISTBANK call TransmitCompressedData ;---------------transmit used objects------------------------- ld a,OBJLISTBANK ld [$ff70],a ld de,objExists+1 .transmitUsedObject ld a,[de] ;is this object used? or a jr z,.afterTransmitUsedObject ;not used PREPLONGCALL .afterCvtToPtr ld a,e ;get object index LONGCALL IndexToPointerHL ;cvt to ptr .afterCvtToPtr ld bc,16 ld a,OBJBANK call TransmitData ld a,OBJLISTBANK ld [$ff70],a .afterTransmitUsedObject inc de ld a,e or a jr nz,.transmitUsedObject ld a,[numFreeSprites] call TransmitByte ld a,[firstFreeObj] call TransmitByte ld a,[randomLoc] call TransmitByte ld a,[guardAlarm] call TransmitByte ;ld a,[dialogBank] ;call TransmitByte ld a,[respawnMap] call TransmitByte ld a,[respawnMap+1] call TransmitByte ldio a,[mapState] ;level state call TransmitByte ldio a,[mapState+1] call TransmitByte ld hl,levelVars ld bc,64 xor a ;RAM bank doesn't matter call TransmitData ld hl,musicBank ld bc,64 xor a ;RAM bank doesn't matter call TransmitData ld hl,musicStack ld bc,128 ld a,MUSICBANK call TransmitData ldio a,[musicEnabled] call TransmitByte LONGCALLNOARGS LinkRemakeLists .done pop hl pop bc ret HostExchangeHeroData: ;send out my hero data ld a,[amLinkMaster] or a jr z,.slave_sendHero1_recvHero0 .master_sendHero0_recvHero1 ld hl,hero1_data push hl ld hl,hero0_data jr .setHeroSequence .slave_sendHero1_recvHero0 ld hl,hero0_data push hl ld hl,hero1_data .setHeroSequence ;send my hero data ld bc,HERODATASIZE xor a call TransmitData ;get remote hero data pop hl xor a call ReceiveData ret ;--------------------------------------------------------------------- ; Routine: LinkTest ; Arguments: none ; Returns: none ; Alters: af ; Description: Fills 4k of memory with repeating pattern $00-$ff, ; transmits that data to Slave, receives that data ; back, compares it to the original pattern, and ; finally prints out a Debug message of 1 for equal ; or 0 for not equal. ;--------------------------------------------------------------------- LinkTest: push bc push de push hl di ;fill $d000-$cfff with repeating pattern $00-$ff ld a,1 ld [$ff70],a ld hl,$d000 xor a .fill ld [hl+],a inc a jr nz,.fill ld a,h cp $e0 ld a,0 ;avoid setting z flag here jr nz,.fill ld a,4 .transfer32k push af ld a,1 ld bc,$1000 ld hl,$d000 call TransmitData ld a,1 call ReceiveData pop af dec a jr nz,.transfer32k ;compare received data to original pattern ld b,0 ;comparing to $00 ld hl,$d000 .compare ld a,[hl+] cp b jr nz,.notEqual inc b ld a,h cp $e0 jr nz,.compare .equal xor a ldio [$ff0f],a ei ld a,1 call DebugVal jr .infi .notEqual xor a ldio [$ff0f],a ei xor a call DebugVal dec hl ld a,h call DebugVal ld a,l call DebugVal di .infi jr .infi pop hl pop de pop bc ret ;--------------------------------------------------------------------- ; Routine: GeneratePauseMessage ; Arguments: none ; Returns: none ; Alters: all ; Description: Creates appropriate Pause Message ;--------------------------------------------------------------------- GeneratePauseMessage: ld a,[dialogBank] push af ;wait until the backbuffer is blitted .waitBackBuffer ldio a,[backBufferReady] or a jr z,.canMessWithBackBuffer call VWait jr .waitBackBuffer .canMessWithBackBuffer ;generate gtx at backbuffer+$800 ;de = level name index ld a,[curLevelStateIndex] ld d,0 ld e,a ;level index * 2 sla e rl d ld hl,levelNames add hl,de ld a,[hl+] ld e,a ld a,[hl+] ld d,a ld hl,backBuffer ld a,BANK(levelNames) ld [dialogBank],a call ClearGTXLine call WriteGTXLine ;write char name push hl push hl LDHL_CURHERODATA HERODATA_TYPE ld a,[hl] ld c,$ff .findCharIndex inc c rrca bit 7,a jr z,.findCharIndex ld a,c ld hl,heroNames call .lookupIndexAToHLToDE pop hl call ClearGTXLine call WriteGTXLine pop hl ;write map coordinates add sp,-24 ;create temporary buffer on stack push hl ld hl,sp+2 ld d,h ld e,l ld [hl],16 ;spaces to center inc hl ld [hl],4 ;number of chars inc hl ld a,[curLevelStateIndex] push af and $f add 210 ;'A' character ld [hl+],a pop af ld [hl],$f9 ;hyphen inc hl swap a and $f cp 10 jr c,.oneDigit ld [hl],201 ;'1' inc hl sub 10 .oneDigit add 200 ;get digit '0'-'9' ld [hl+],a ld [hl],0 ;blank space may or may not be used pop hl push de call WriteGTXLine ;de is line to write pop de ;write map coordinates if landing zone------------------------ ld c,2 ;# of items in inventory screen push bc ;see if we're at an LZ ld a,[curLevelStateIndex] call .getFlightCodeBCFromMapA pop bc jr z,.afterWriteCoords push hl ld h,d ld l,e ld [hl],8 ;spaces to center inc hl ld [hl],4 ;number of chars inc hl push bc ld a,[curLevelStateIndex] call .getFlightCodeBCFromMapA call .writeCoordsBC pop bc pop hl call ClearGTXLine call WriteGTXLine ;de is line to write inc c .afterWriteCoords add sp,24 ;free up temporary stack space ;write inventory call GetFirstInventoryIndex cp $ff jr z,.afterWriteInventory ;blank line push af ld de,blankLine call ClearGTXLine call WriteGTXLine inc c pop af ;remaining inventory .nextInventoryItem ld b,a ;obj index in b push af push hl ld hl,itemNames call .lookupIndexAToHLToDE pop hl inc de ld a,[de] dec de or a jr z,.skipItem ;an upgrade or something call ClearGTXLine push hl call WriteGTXLine ;write object color ld a,b add (itemColors&$ff) ld e,a ld a,((itemColors>>8)&$ff) adc 0 ld d,a ld a,[de] or 8 pop de push hl ld hl,$300 add hl,de ld [hl],a pop hl inc c .skipItem pop af call GetNextInventoryIndex cp $ff jr nz,.nextInventoryItem .afterWriteInventory inc c ld de,restart_message call ClearGTXLine call WriteGTXLine ld a,c ld [backBuffer+63],a ;#lines pop af ld [dialogBank],a ret .getFlightCodeBCFromMapA ;returns flight code in bc, zflag push de push hl ld de,3 ld b,a ld a,FLIGHTCODEBANK ldio [$ff70],a ld hl,flightCode ld c,[hl] ;number of flight codes add hl,de ;start at byte 2/3 (map index) .findFlightCode ld a,[hl] cp b jr z,.getFlightCodeMatch add hl,de dec c jr nz,.findFlightCode xor a ;not found pop hl pop de ret .getFlightCodeMatch dec hl ld b,[hl] dec hl ld c,[hl] pop hl pop de ld a,1 or a ret .lookupIndexAToHLToDE rlca add l ld l,a ld a,h adc 0 ld h,a ld a,[hl+] ld d,[hl] ld e,a ret .writeCoordsBC ld a,b swap a call .writeCoordA ld a,b call .writeCoordA ld a,c swap a call .writeCoordA ld a,c call .writeCoordA ret .writeCoordA and $f add $c0 ;first of 8 coordinate symbols ld [hl+],a ret restart_message: GTXSTRINGC "SELECTgoRESTART" blankLine: DB 0,0 ;--------------------------------------------------------------------- ; Routine: CopyMessageDEToHL ; Arguments: de - pointer to message ; hl - pointer to dest ; Returns: none ; Alters: all ; Description: First byte at [de] is number of bytes to copy from ; [de] to [hl]. Must be >= 1! ;--------------------------------------------------------------------- CopyMessageDEToHL: ld a,[de] inc de ld c,a .loop ld a,[de] inc de ld [hl+],a dec c jr nz,.loop ret levelNames: DW L0000_Name,L0100_Name,L0200_Name,L0300_Name DW L0400_Name,L0500_Name,L0600_Name,L0700_Name DW L0800_Name,L0900_Name,L1000_Name,L1100_Name DW L1200_Name,L1300_Name,L1400_Name,L1500_Name DW L0001_Name,L0101_Name,L0201_Name,L0301_Name DW L0401_Name,L0501_Name,L0601_Name,L0701_Name DW L0801_Name,L0901_Name,L1001_Name,L1101_Name DW L1201_Name,L1301_Name,L1401_Name,L1501_Name DW L0002_Name,L0102_Name,L0202_Name,L0302_Name DW L0402_Name,L0502_Name,L0602_Name,L0702_Name DW L0802_Name,L0902_Name,L1002_Name,L1102_Name DW L1202_Name,L1302_Name,L1402_Name,L1502_Name DW L0003_Name,L0103_Name,L0203_Name,L0303_Name DW L0403_Name,L0503_Name,L0603_Name,L0703_Name DW L0803_Name,L0903_Name,L1003_Name,L1103_Name DW L1203_Name,L1303_Name,L1403_Name,L1503_Name DW L0004_Name,L0104_Name,L0204_Name,L0304_Name DW L0404_Name,L0504_Name,L0604_Name,L0704_Name DW L0804_Name,L0904_Name,L1004_Name,L1104_Name DW L1204_Name,L1304_Name,L1404_Name,L1504_Name DW L0005_Name,L0105_Name,L0205_Name,L0305_Name DW L0405_Name,L0505_Name,L0605_Name,L0705_Name DW L0805_Name,L0905_Name,L1005_Name,L1105_Name DW L1205_Name,L1305_Name,L1405_Name,L1505_Name DW L0006_Name,L0106_Name,L0206_Name,L0306_Name DW L0406_Name,L0506_Name,L0606_Name,L0706_Name DW L0806_Name,L0906_Name,L1006_Name,L1106_Name DW L1206_Name,L1306_Name,L1406_Name,L1506_Name DW L0007_Name,L0107_Name,L0207_Name,L0307_Name DW L0407_Name,L0507_Name,L0607_Name,L0707_Name DW L0807_Name,L0907_Name,L1007_Name,L1107_Name DW L1207_Name,L1307_Name,L1407_Name,L1507_Name DW L0008_Name,L0108_Name,L0208_Name,L0308_Name DW L0408_Name,L0508_Name,L0608_Name,L0708_Name DW L0808_Name,L0908_Name,L1008_Name,L1108_Name DW L1208_Name,L1308_Name,L1408_Name,L1508_Name DW L0009_Name,L0109_Name,L0209_Name,L0309_Name DW L0409_Name,L0509_Name,L0609_Name,L0709_Name DW L0809_Name,L0909_Name,L1009_Name,L1109_Name DW L1209_Name,L1309_Name,L1409_Name,L1509_Name DW L0010_Name,L0110_Name,L0210_Name,L0310_Name DW L0410_Name,L0510_Name,L0610_Name,L0710_Name DW L0810_Name,L0910_Name,L1010_Name,L1110_Name DW L1210_Name,L1310_Name,L1410_Name,L1510_Name DW L0011_Name,L0111_Name,L0211_Name,L0311_Name DW L0411_Name,L0511_Name,L0611_Name,L0711_Name DW L0811_Name,L0911_Name,L1011_Name,L1111_Name DW L1211_Name,L1311_Name,L1411_Name,L1511_Name DW L0012_Name,L0112_Name,L0212_Name,L0312_Name DW L0412_Name,L0512_Name,L0612_Name,L0712_Name DW L0812_Name,L0912_Name,L1012_Name,L1112_Name DW L1212_Name,L1312_Name,L1412_Name,L1512_Name DW L0013_Name,L0113_Name,L0213_Name,L0313_Name DW L0413_Name,L0513_Name,L0613_Name,L0713_Name DW L0813_Name,L0913_Name,L1013_Name,L1113_Name DW L1213_Name,L1313_Name,L1413_Name,L1513_Name DW L0014_Name,L0114_Name,L0214_Name,L0314_Name DW L0414_Name,L0514_Name,L0614_Name,L0714_Name DW L0814_Name,L0914_Name,L1014_Name,L1114_Name DW L1214_Name,L1314_Name,L1414_Name,L1514_Name DW L0015_Name,L0115_Name,L0215_Name,L0315_Name DW L0415_Name,L0515_Name,L0615_Name,L0715_Name DW L0815_Name,L0915_Name,L1015_Name,L1115_Name DW L1215_Name,L1315_Name,L1415_Name,L1515_Name L0000_Name: GTXSTRINGC "THEoHIVE" L0001_Name: GTXSTRINGC "MADoBEEoPASS" L0002_Name: GTXSTRINGC "BEEoCOUNTRY" L0003_Name: GTXSTRINGC "BIGoEDaSoSHEEPoFARM" L0004_Name: GTXSTRINGC "HILLoBROTHERSoRANCH" L0005_Name: GTXSTRINGC "TRAKKTORoCOUNTRY" L0006_Name: GTXSTRINGC "SUNSEToVILLAGE" L0007_Name: GTXSTRINGC "CRAZYoCROWoGULCH" L0008_Name: GTXSTRINGC "SNEAKYoTREEoVALLEY" L0009_Name: GTXSTRINGC "PROVOLONE" L0010_Name: GTXSTRINGC "MUENSTER" L0011_Name: GTXSTRINGC "HOUSEoOFoSEASONS" L0012_Name: GTXSTRINGC "COMMANDoCORE" L0013_Name: GTXSTRINGC "ITCHYoTRIGGER" L0014_Name: GTXSTRINGC "THEoFAULT" L0015_Name: GTXSTRINGC "LOOSEoJARGON" L0100_Name: L0101_Name: L0102_Name: GTXSTRINGC "RIVER" L0103_Name: GTXSTRINGC "LILoEDaSoSHEEPoFARM" L0104_Name: GTXSTRINGC "SPRING" L0105_Name: GTXSTRINGC "DARKERoFOREST" L0106_Name: GTXSTRINGC "DARKISHoFOREST" L0107_Name: GTXSTRINGC "KIDNAPoCORNERoeLZf" L0108_Name: GTXSTRINGC "SNAKEoPIToeLZf" L0109_Name: GTXSTRINGC "CHEDDAR" L0110_Name: GTXSTRINGC "HAVARTI" L0111_Name: GTXSTRINGC "GOBLINoPIT" L0112_Name: GTXSTRINGC "HIVEoENTRANCE" L0113_Name: GTXSTRINGC "FRIENDLYoFIRE" L0114_Name: GTXSTRINGC "PATHoOFoSHADOWS" L0115_Name: GTXSTRINGC "DOUBLEoENTENDRE" L0200_Name: GTXSTRINGC "FORBIDDENoVILLAGE" L0201_Name: GTXSTRINGC "STRANGEoMIST" L0202_Name: L0203_Name: L0204_Name: GTXSTRINGC "RIVER" L0205_Name: GTXSTRINGC "JACOBaSoBRIDGE" L0206_Name: L0207_Name: L0208_Name: L0209_Name: L0210_Name: GTXSTRINGC "RIVER" L0211_Name: GTXSTRINGC "THEoBLOWERS" L0212_Name: GTXSTRINGC "THEoBELFRY" L0213_Name: GTXSTRINGC "CLOSEoQUARTERS" L0214_Name: GTXSTRINGC "JAILoBREAK" L0215_Name: GTXSTRINGC "BRAINIAC" L0300_Name: GTXSTRINGC "WEIRDoMIST" L0301_Name: GTXSTRINGC "ODDoMIST" L0302_Name: GTXSTRINGC "BIZARREoMISToeLZf" L0303_Name: GTXSTRINGC "MISToGATE" L0304_Name: GTXSTRINGC "MUNGAoFUNGA" L0305_Name: GTXSTRINGC "TRILINGoBURROW" L0306_Name: GTXSTRINGC "TWOoGUNS" L0307_Name: GTXSTRINGC "OUTPOSTgoDESOLATION" L0308_Name: GTXSTRINGC "DRYoGULCH" L0309_Name: GTXSTRINGC "SHOOToOUT" L0310_Name: GTXSTRINGC "REDoBENDoeLZf" L0311_Name: GTXSTRINGC "HIGHoGROUND" L0312_Name: GTXSTRINGC "THEoSTING" L0313_Name: GTXSTRINGC "INSOMNIAC" L0314_Name: GTXSTRINGC "RUNAWAY" L0315_Name: GTXSTRINGC "INSOMNIAC" L0400_Name: GTXSTRINGC "OUTPOSTgoDARKFROST" L0401_Name: GTXSTRINGC "PITCHoBLACK" L0402_Name: GTXSTRINGC "WYRMoDUSK" L0403_Name: GTXSTRINGC "GROMMOLD" L0404_Name: GTXSTRINGC "MILDEWoSTIRRING" L0405_Name: GTXSTRINGC "WESTGATE" L0406_Name: GTXSTRINGC "PIGSoINoAoBLANKET" L0407_Name: GTXSTRINGC "BIOS" L0408_Name: GTXSTRINGC "HOToVALLEYoOFoDEATH" L0409_Name: GTXSTRINGC "TUMBLEWEED" L0410_Name: GTXSTRINGC "OUTPOSTgoDRAGON" L0411_Name: GTXSTRINGC "THEoCELL" L0412_Name: GTXSTRINGC "STONEHEADoHOUSE" L0413_Name: L0414_Name: L0415_Name: GTXSTRINGC "FGB" L0500_Name: GTXSTRINGC "PENGUINoSMACKDOWN" L0501_Name: GTXSTRINGC "WINTER" L0502_Name: GTXSTRINGC "CHILLVILLE" L0503_Name: GTXSTRINGC "OLDoHOSS" L0504_Name: GTXSTRINGC "NORTHGATE" L0505_Name: GTXSTRINGC "FLOWERoTOWER" L0506_Name: GTXSTRINGC "SOUTHGATE" L0507_Name: GTXSTRINGC "WETLANDS" L0508_Name: GTXSTRINGC "LAaSHANDAaS" L0509_Name: GTXSTRINGC "OUTBACK" L0510_Name: GTXSTRINGC "SUMMER" L0511_Name: L0512_Name: GTXSTRINGC "LAaSHANDA" L0513_Name: L0514_Name: L0515_Name: GTXSTRINGC "FGB" L0600_Name: GTXSTRINGC "ICEoPLAINSoeLZf" L0601_Name: GTXSTRINGC "ICEWOLFoRUN" L0602_Name: GTXSTRINGC "KINGoCHUBBAaSoHALL" L0603_Name: GTXSTRINGC "IGNORANToHILLoPEOPLE" L0604_Name: GTXSTRINGC "TOWERoOFoPAIN" L0605_Name: GTXSTRINGC "EASTGATE" L0606_Name: GTXSTRINGC "ROCKoBOTTOMoBENDeLZf" L0607_Name: GTXSTRINGC "SWAMPYaSoLAIR" L0608_Name: GTXSTRINGC "GOONoHILL" L0609_Name: GTXSTRINGC "LASToRESORT" L0610_Name: GTXSTRINGC "BITTERoROCKoPARK" L0611_Name: L0612_Name: GTXSTRINGC "TELEPORToCHAMBER" L0613_Name: L0614_Name: L0615_Name: GTXSTRINGC "FGB" L0700_Name: GTXSTRINGC "THEoPLANEoOFoNOTHING" L0701_Name: GTXSTRINGC "KIWIoKEEP" L0702_Name: GTXSTRINGC "BAToCAVE" L0703_Name: GTXSTRINGC "UNDERLAKEoCAVERNS" L0704_Name: GTXSTRINGC "STONEHEADoCANYONeLZf" L0705_Name: GTXSTRINGC "MONKEYoHOLLER" L0706_Name: GTXSTRINGC "SWAMPLACE" L0707_Name: GTXSTRINGC "THEoBARROWS" L0708_Name: GTXSTRINGC "BLACKoSWAMPoPASSAGE" L0709_Name: GTXSTRINGC "HERDoLANDS" L0710_Name: GTXSTRINGC "DONaToSHOOToTHEoCROC" L0711_Name: GTXSTRINGC "SPACEoSTNoAPOCALYPSE" L0712_Name: GTXSTRINGC "HICKoLANDINGoeLZf" L0713_Name: L0714_Name: L0715_Name: GTXSTRINGC "FGB" L0800_Name: GTXSTRINGC "JACOBaSoOTHERoBRIDGE" L0801_Name: GTXSTRINGC "KIWIoROAD" L0802_Name: GTXSTRINGC "WINDYoPASS" L0803_Name: GTXSTRINGC "DJINNoLAKE" L0804_Name: GTXSTRINGC "ELDERoROCKoCANYON" L0805_Name: GTXSTRINGC "MONKEYoSURPRISE" L0806_Name: GTXSTRINGC "SCAREDIEoRUN" L0807_Name: GTXSTRINGC "SPIDERoMOORE" L0808_Name: GTXSTRINGC "CROUTONoWARoCAMP" L0809_Name: GTXSTRINGC "GRAPESHOT" L0810_Name: GTXSTRINGC "CROUTONoGRAVESoeLZf" L0811_Name: GTXSTRINGC "GOBLINoMODULE" L0812_Name: GTXSTRINGC "WARPoZONE" L0813_Name: L0814_Name: L0815_Name: GTXSTRINGC "FGB" L0900_Name: GTXSTRINGC "OUTPOSTgoDELTA" L0901_Name: GTXSTRINGC "CROUTONoSLAVEoCAMP" L0902_Name: GTXSTRINGC "WIZARDaSoPASSoeLZf" L0903_Name: GTXSTRINGC "CORNVILLE" L0904_Name: GTXSTRINGC "SPIDERWEEDoCANYON" L0905_Name: GTXSTRINGC "MONKEYoLANDINGoeLZf" L0906_Name: GTXSTRINGC "MOOREoGATE" L0907_Name: GTXSTRINGC "ARROWHEADoCITY" L0908_Name: GTXSTRINGC "CANNONBALL" L0909_Name: GTXSTRINGC "CROSSROADS" L0910_Name: GTXSTRINGC "WARZONE" L0911_Name: GTXSTRINGC "ARTILLERYoMODULE" L0912_Name: GTXSTRINGC "MONKEYoHOMEWORLD" L0913_Name: L0914_Name: L0915_Name: GTXSTRINGC "FGB" L1000_Name: GTXSTRINGC "GYROaSoBASEoCAMPeLZf" L1001_Name: GTXSTRINGC "CACTUSoPETE" L1002_Name: GTXSTRINGC "OUTPOSTgoDINGLE" L1003_Name: GTXSTRINGC "THEoBEACHoeLZf" L1004_Name: GTXSTRINGC "PUMPKINoPATCH" L1005_Name: GTXSTRINGC "AUTUMN" L1006_Name: GTXSTRINGC "OUTPOSTgoDESPAIR" L1007_Name: GTXSTRINGC "BUBoANDoJEB" L1008_Name: GTXSTRINGC "GRENADIERoGRAVEYARD" L1009_Name: GTXSTRINGC "BLACKoMAGIC" L1010_Name: GTXSTRINGC "GRENADIERoCASTLE" L1011_Name: GTXSTRINGC "DOCKINGoBAY" L1012_Name: GTXSTRINGC "MONKEYoLIBRARY" L1013_Name: L1014_Name: L1015_Name: GTXSTRINGC "FGB" L1100_Name: L1101_Name: L1102_Name: L1103_Name: L1104_Name: L1105_Name: L1106_Name: L1107_Name: L1108_Name: L1109_Name: L1110_Name: GTXSTRINGC "FGB" L1111_Name: GTXSTRINGC "HULKoMODULE" L1112_Name: GTXSTRINGC "DUKEaSoDISCO" L1113_Name: L1114_Name: L1115_Name: L1200_Name: L1201_Name: L1202_Name: L1203_Name: L1204_Name: L1205_Name: L1206_Name: L1207_Name: L1208_Name: L1209_Name: L1210_Name: L1211_Name: GTXSTRINGC "FGB" L1212_Name: GTXSTRINGC "THEoBESToLAIDoPLANS`" L1213_Name: L1214_Name: L1215_Name: L1300_Name: GTXSTRINGC "BCSoAPPOMATTOX" L1301_Name: GTXSTRINGC "FGB" L1302_Name: L1303_Name: L1304_Name: L1305_Name: L1306_Name: L1307_Name: L1308_Name: L1309_Name: L1310_Name: L1311_Name: GTXSTRINGC "FGB" L1312_Name: GTXSTRINGC "GOBLINoCOUNTRY" L1313_Name: L1314_Name: L1315_Name: L1400_Name: L1401_Name: L1402_Name: L1403_Name: L1404_Name: L1405_Name: L1406_Name: L1407_Name: L1408_Name: L1409_Name: L1410_Name: L1411_Name: GTXSTRINGC "FGB" L1412_Name: GTXSTRINGC "HIGHoNOON" L1413_Name: L1414_Name: L1415_Name: L1500_Name: L1501_Name: L1502_Name: L1503_Name: L1504_Name: ;THE KIDNAPPING! DB ((20-STRLEN("THEoKIDNAPPING "))/2),STRLEN("THEoKIDNAPPING ") COUNTER SET 1 REPT STRLEN("THEoKIDNAPPING") DB ((STRSUB("THEoKIDNAPPING",COUNTER,1)+145) & $ff) COUNTER SET COUNTER+1 ENDR DB 237 ;! L1505_Name: GTXSTRINGC "FGB" L1506_Name: L1507_Name: L1508_Name: L1509_Name: L1510_Name: L1511_Name: GTXSTRINGC "FGB" L1512_Name: GTXSTRINGC "GENERATORoCORE" L1513_Name: L1514_Name: L1515_Name: GTXSTRINGC "FGB" heroNames: DW ba_name,bs_name,haiku_name,flour_name,flower_name,grenade_name ba_name: GTXSTRING "BA" bs_name: GTXSTRING "BS" haiku_name: GTXSTRING "HAIKU" flour_name: GTXSTRING "CAPTAINoFLOUR" flower_name: GTXSTRING "LADYoFLOWER" grenade_name: GTXSTRING "KINGoGRENADE" itemNames: DW item000_Name,item001_Name,item002_Name,item003_Name,item004_Name DW item005_Name,item006_Name,item007_Name,item008_Name,item009_Name DW item010_Name,item011_Name,item012_Name,item013_Name,item014_Name DW item015_Name,item016_Name,item017_Name,item018_Name,item019_Name DW item020_Name,item021_Name,item022_Name itemColors: DB 1,1,0,0,0,0,0,1,3,1 ; 0- 9 DB 5,0,0,5,0,0,1,6,5,3 ;10-19 DB 2,4,5,0,0,0,0,0,0,0 ;20-29 ;0=Grey, 1=Red, 2=Blue, 3=Green, 4=Purple, 5=Yellow, 6=Brown/Orange, 7=Fuscia item000_Name: ITEMSTRING 246,"SNAKEoBITEoKIT" item001_Name: ITEMSTRING 254,"SPOREoMASK" item002_Name: ;ITEMSTRING 250,"CODE0400" DB 0,0 item003_Name: ;ITEMSTRING 250,"CODE0900" DB 0,0 item004_Name: ;ITEMSTRING 250,"CODE1002" DB 0,0 item005_Name: ;ITEMSTRING 250,"CODE1006" DB 0,0 item006_Name: ;ITEMSTRING 250,"CODE0410" DB 0,0 item007_Name: ITEMSTRING 249,"BAToJUICE" item008_Name: ITEMSTRING 248,"SPACEoMONEY" item009_Name: ITEMSTRING 247,"SPACEoSODA" item010_Name: ITEMSTRING 247,"HONEY" item011_Name: ITEMSTRING 254,"WRANGLINGoIRON" item012_Name: DB 0,0 ;BS Shoot Fast item013_Name: ITEMSTRING 253,"BUGoSPRAY" item014_Name: DB 0,0 ;BA High Impact Bullets item015_Name: ;ITEMSTRING 250,"CODE0307" DB 0,0 item016_Name: ITEMSTRING 250,"ALPHAoCLEARANCE" item017_Name: ITEMSTRING 250,"BETAoCLEARANCE" item018_Name: ITEMSTRING 250,"GAMMAoCLEARANCE" item019_Name: ITEMSTRING 250,"DELTAoCLEARANCE" item020_Name: ITEMSTRING 250,"EPSILONoCLEARANCE" item021_Name: ITEMSTRING 250,"ZETAoCLEARANCE" item022_Name: ITEMSTRING 251,"APPOMATTOXoKEY" SECTION "MiscSection",ROMX ;--------------------------------------------------------------------- ; Routine: NewAppxLocation ; Arguments: None. ; Returns: none ; Alters: af ; Description: ;--------------------------------------------------------------------- NewAppxLocation: push bc push de push hl ld a,[curLevelStateIndex] ld b,a ld a,[appomattoxMapIndex] cp b jr nz,.checkAppear ;remove appomattox from current map call ReceiveByte ;new map location ld [appomattoxMapIndex],a ld a,190 ldio [jiggleDuration],a call FindFirstLight ;remove appx ld c,a ;invisible wall index ld d,0 ld a,[mapPitch] ld e,a ld a,b ;light index call .drawLightRowTop call .drawLightRowMiddle call .drawLightRowMiddle call .drawLightRowMiddle call .drawLightRowMiddle call .drawLightRowBottom ld hl,EngineSound call PlaySound ;link up exit to $4040 (+0 +0) ld hl,mapExitLinks+EXIT_U*2 ld a,$40 ld [hl+],a ld [hl],a jr .done .checkAppear call ReceiveByte ;new map location ld [appomattoxMapIndex],a cp b ;appearing on my map jr nz,.checkInAppx ;place appomattox on current map ld a,190 ldio [jiggleDuration],a call AddAppomattox ld hl,EngineSound call PlaySound jr .done .checkInAppx ld a,b cp $0d jr nz,.checkAtAppxControls ;I'm inside the Appomattox! ld a,190 ldio [jiggleDuration],a ld hl,EngineSound call PlaySound ld a,[appomattoxMapIndex] or a jr nz,.landing .takingOff ;link down exit to $4040 (+0 +0) ld hl,mapExitLinks+EXIT_D*2 ld a,$40 ld [hl+],a ld [hl],a jr .done .landing ;convert map index to 16-bit BCD index ld b,a and %1111 call NumberToBCD ld d,a ld a,b swap a and %1111 call NumberToBCD ld e,a ld hl,mapExitLinks+EXIT_D*2 ld [hl],e inc hl ld [hl],d jr .done .checkAtAppxControls ;if I was at the controls when my buddy took off, kick me off cp $1e jr nz,.done ld hl,EngineSound call PlaySound ld a,$ff ld [levelVars+6],a ;VAR_SELSTAGE in $1401 .done pop hl pop de pop bc ret .drawLightRowTop push hl ld [hl+],a inc a ld [hl+],a inc a ld [hl+],a inc a ld [hl+],a sub 3 pop hl add hl,de ret .drawLightRowMiddle push hl push af sub b add 3 and 3 add b ld [hl+],a ;xor a ld a,c ld [hl+],a ld [hl+],a pop af ld [hl+],a sub b add 3 and 3 add b pop hl add hl,de ret .drawLightRowBottom push hl add 3 ld [hl+],a dec a ld [hl+],a dec a ld [hl+],a dec a ld [hl+],a dec a pop hl add hl,de ret FindFirstLight: ;leaves hl at mem location of first landing light ;b = first light index, c=first appx index ;a = invisible wall index ;must exist or infinite loop! ld bc,classInvisibleWallBG call FindClassIndex push af ld bc,classLandingLightsBG call FindClassIndex ld b,a ;index to look for push bc ld bc,classAppomattoxBG call FindClassIndex pop bc ld c,a ld a,MAPBANK ld [$ff70],a ;setup de with first out-of-bounds index ;ld a,[mapTotalSize] ;ld e,a ;ld a,[mapTotalSize+1] ;ld d,a ld hl,map .lookForFirstLight ld a,[hl+] cp b jr nz,.lookForFirstLight dec hl pop af ret AddAppomattoxIfPresent:: push bc ld a,[curLevelStateIndex] ld b,a ld a,[appomattoxMapIndex] cp b jr nz,.done call AddAppomattox .done pop bc ret EngineSound: DB 4,$00,$d7,$a9,$80 AddAppomattox: push bc push de push hl call FindFirstLight ;draw appx ld d,0 ld a,[mapPitch] ld e,a ld a,c ;appx index call .drawAppxMiddle call .drawAppxMiddle call .drawAppxMiddle call .drawAppxRow call .drawAppxRow call .drawAppxRow ;link exit up to $1300 (appomattox interior) ld hl,mapExitLinks+EXIT_U*2 xor a ld [hl+],a ld [hl],$13 pop hl pop de pop bc ret .drawAppxMiddle push hl inc hl inc a ld [hl+],a inc a ld [hl],a add 2 pop hl add hl,de ret .drawAppxRow push hl ld [hl+],a inc a ld [hl+],a inc a ld [hl+],a inc a ld [hl],a inc a pop hl add hl,de ret ;WARNING not in HOME section ;--------------------------------------------------------------------- ; Variables ;--------------------------------------------------------------------- SECTION "UserVarsHRAM",HRAM vblankFlag: DS 1 ;0=no interrupt, 1=vblank vblankTemp: DS 1 vblankTimer:: DS 1 vblanksPerUpdate: DS 1 backBufferReady:: DS 1 backBufferDestHighByte:: DS 1 paletteBufferReady:: DS 1 dmaLoad:: DS 1 ;1=load bank 0, 2=load bank 1 randomLoc:: DS 1 ;ff92 jiggleDuration:: DS 1 ;ff93 temp:: DS 1 ;ff94 drawMapTemp:: DS 2 ;ff95 hblankFlag:: DS 1 ;ff97 :0 top/bottom, :1 show, :2 wave hblankWinOn:: DS 1 ;ff98 hblankWinOff:: DS 1 ;ff99 firstMonster:: DS 1 ;ff9a curROMBank:: DS 1 ;ff9b updateTimer:: DS 1 ;ff9c curObjWidthHeight:: DS 1 ;7:4 width, 3:0 height scrollSpeed:: DS 1 ;7:4 fast speed (0,2,4,8) 3:0 slow speed mapState:: DS 2 ;ff9f transmitACK:: DS 1 ;ffa1 musicEnabled:: DS 1 ;ffa2 baseHorizontalOffset: DS 1 ;ffa3 samplePlaying: DS 1 ;ffa4 sampleBank: DS 1 ;ffa5 sampleAddress: DS 2 ;ffa6 sampleMask: DS 1 ;ffa8 jiggleType:: DS 1 ;ffa9 asyncRandLoc:: DS 1 ;ffaa IF 0 ;clear memory to ff ld hl,$c000 ld bc,$0f00 ;ld d,$ff ld d,0 xor a call MemSet ld hl,$d000 ld bc,$1000 ld a,1 call MemSet ld hl,$d000 ld bc,$1000 ld a,2 call MemSet ld hl,$d000 ld bc,$1000 ld a,3 call MemSet ld hl,$d000 ld bc,$1000 ld a,4 call MemSet ld hl,$d000 ld bc,$1000 ld a,5 call MemSet ld hl,$d000 ld bc,$1000 ld a,6 call MemSet ld hl,$d000 ld bc,$0020 ld a,7 call MemSet ld d,0 ld hl,$d020 ld bc,$0fe0 ld a,7 call MemSet ENDC