; Venture for the Atari 2600 VCS
;
; Copyright 19?? Coleco
; Written by ????
;
; Reverse-Engineered by Manuel Polik (cybergoth@arcor.de)
; and Robert Mundschau (rmundschau@sbcglobal.net)
; Compiles with DASM
;
; Build command: (needs vcs.h)
; dasm venture.asm -f3 -lventure.list -sventure.sym -oventure.bin
;
; History
; 08.11.2K3     - Started
; 12.11.2K3     - Worked a few things from Initialisation out
; 17.11.2K3     - Halfway finished display
; 07.01.2K4     - Expanded all graphics data to include visual comments.
;		- Worked on commenting the initialization code.
; 11.01.2K4	- Worked on InitBigRoom
; 16.01.2K4     - Completing vertical blank.
; 22.01.2K4	- Display Kernal is finished.
; 23.01.2K4	- Begin at kernalDone.
; 02.02.2K4     - Collisions
; 02.08.2K4     - Object collsions and movement.
; 02.11.2K4     - Completed direction changes and movement.

    processor 6502
    include vcs.h

;----------------------------
; GAME CONSTANTS:
;
TIA_BASE_READ_ADDRESS 	= $30

SCREEN_BOTTOM_LINE	= $50   ; The region of the screen available for rendering rooms is $50 pairs of scanlines
				; tall.   This does not include the portion of the screen with the score and lives.
				; indicator.     

SPRITE_NOT_VISIBLE    	= $51	; When a sprite is not to be displayed anymore, the program
				; set the Y coordinate of the sprite to this constant value.

SPRITE_STATUS_DEAD    	= $F2	; This is the Status value used to indicate a game object is dead.	

PLAYER_SHOT_RANGE	= $1E	; How far the player's shot will fly if it doesn't hit anything.	


;------------------------
; RAM Address Equates:		
;                                       Zoomed Room Only.		Big Room
sprite0_Shape       = $80;$81  ; Shape	* Player *			* Hall Monster Small *
sprite1_Shape       = $82;$83  ; Shape	* Monster * or * Item *		* Hall Monster Small *
sprite2_Shape       = $84;$85  ; Shape	* Item * or * Monster *		* Hall Monster Small *
sprite3_Shape       = $86;$87  ; Shape	* Monster *			* Hall Monster Small *
sprite4_Shape       = $88;$89  ; Shape	* Monster *			* Hall Monster Small *
sprite5_Shape       = $8A;$8B  ; Shape	* Hall Monster Big *		* Hall Monster Small *

unusedRAM1	    = $8C   ; These 2 bytes of RAM are not used by the original code and are 	
unusedRAM2          = $8D   ; therefore available for hacking.

sprite7_Shape       = $8E;$8F  ; Used in the moving wall room only, to timeshare the treasure and
                               ; large hall monster on one sprite.

roomLockMask	    = $90   ; contains the bit mask to test/set bits in roomLockedFlags.
roomLockedFlags     = $91   ; The lower nybble of this byte are flags, one for each room on the 
			    ; current level.  When the player completes a room, its corresponding
			    ; bit is set in this byte.

roomDoneFlag	    = $92   ; bit 7 is cleared when entering a new room.  When the item is collected
			    ; bit 7 is set.  Then if the room is exited safely, it is locked.  There
			    ; may be another purpose to this byte I haven't determined yet.

mirroredRoom        = $93   ; reflection of room switched in the 6th bit

sprite0_Ypos        = $94   ; Ypos
sprite1_Ypos        = $95   ; Ypos
sprite2_Ypos        = $96   ; Ypos
sprite3_Ypos        = $97   ; Ypos
sprite4_Ypos        = $98   ; Ypos
sprite5_Ypos        = $99   ; Ypos
ballYpos            = $9A   ; ypos of ball
sprite7_Ypos        = $9B   ; Used in the moving wall room only, to timeshare the
                            ; treasure and large hall monster on one sprite.

sprite0_Status	    = $9C   ; The direction and speed of each game object.  The upper nybble is the
sprite1_Status	    = $9D   ; direction, and it corresponds to the values generated by a joystick.
sprite2_Status      = $9E   ; The 3 lowest order bits hold the object's speed 0 - 7.  0 is immobile	
sprite3_Status      = $9F   ; like an item.  7 is the fastest speed in the game.
sprite4_Status      = $A0
sprite5_Status      = $A1
ball_Status	    = $A2   
sprite7_Status	    = $A3

sprite0_Color       = $A4   ; Color
sprite1_Color       = $A5   ; Color
sprite2_Color       = $A6   ; Color
sprite3_Color       = $A7   ; Color
sprite4_Color       = $A8   ; Color
sprite5_Color       = $A9   ; Color

sprite0_Height      = $AA   ; negative signed Height
sprite1_Height      = $AB   ; negative signed Height
sprite2_Height      = $AC   ; negative signed Height
sprite3_Height      = $AD   ; negative signed Height
sprite4_Height      = $AE   ; negative signed Height
sprite5_Height      = $AF   ; negative signed Height

spriteColorSwap     = $B0   ; Used in the moving wall room only, to timeshare the
                            ; treasure and large hall monster on one sprite.

spriteHeightSwap    = $B1

sprite0_Timer	    = $B2   ; Timer value tracked for each sprite.  For Items and the player it
sprite1_Timer	    = $B3   ; is intialized to zero.
sprite2_Timer       = $B4   ;
sprite3_Timer       = $B5   ;
sprite4_Timer       = $B6   ;
sprite5_Timer       = $B7   ;
ball_RangeTimer	    = $B8   ; This location counts down to zero to count out the range of the player's shot.
sprite7_Timer	    = $B9   ; Set to $20 when the large hall monster activates.  The HM remains frozen visible
			    ; in the corner until this timer reaches zero.


live0GFX            = $BA   ; 1st live, highest bit set shows live
live1GFX            = $BB   ; 1st live, highest bit set shows live
live2GFX            = $BC   ; 1st live, highest bit set shows live

flickerOffset       = $BD   ; 0 or 3, swappwed every frame. Draw either sprites 0, 1, and 2
                            ; or sprites 3, 4, and 5.

roomOffset          = $BE   ; stores PF offset for current room

gameStateFlags1	    = $BF   ; Bit7 = 1 = all movement disabled.  Bit6 = 1 = In Zoomed-Room. 0 = Big Room.
			    ; Bit0 = 1 means the reset button was being pressed last frame, used
			    ; to debounce the switch it seems.

P1spritewidth       = $C0   ; width of player 1 in kernel (normal/4width)

;unknown            = $C1
;unknown            = $C2

PFcollisionFlags    = $C3   ; A set of flags to keep track of what objects collided with other objects
			    ; during the previously rendered frame.

randomNumPtr        = $C4   ; This location is used to generate pseudo-random numbers by acting as an index to
			    ; read a byte from the program ROM as a "random" number.  After each random number is 
			    ; read, this location is incremented.

LastPlayerDirection = $C5   ; Every time the player pushes the joystick the last direction pushed
                            ; is stored here so that even if the player stops pushing we can
                            ; recall the last direction traveled to fire the shot.

livesCounter        = $C6   ; Starts of with 3 lives

score_1_2           = $C7   ; These 2 bytes hold the players score divided by 100 in BCD format.
score_3_4           = $C8   ; 

shotReadyFlag	    = $C9   ; When bit7 is set the player can fire.  

P1repositionEven    = $CA   ; line to reposition GRP1 even frame. 
P1repositionOdd     = $CB   ; line to reposition GRP1 odd frames.
                            ; These values never change within a room.
                            ; The result is an invisble barrier to some monsters.

pauseTimer          = $CC   ; When bit7 in gameStateFlags is set to pause the gameplay, then this
			    ; byte contains a timer decremented each frame.  When the timer transitions
			    ; from 1 to zero, bit7 in gameStateFlags is cleared to unpause gameplay.
		            ; If pauseTimer is intialized to zero when bit7 of gameStateFlags is set, then
		            ; the game is over, and reset must be pressed to unfreeze the game.

; unknown           = $CD
currentLevel        = $CE   ; Initialized to 0-3 based on the difficulty switches. Incremented everytime the
			    ; player completes a level.  There is nothing to prevent it wrapping back to zero.
			    ; Weird things may happen if that were to occur.

sprite0_Xpos        = $CF   ; X-Position
sprite1_Xpos        = $D0   ; X-Position
sprite2_Xpos        = $D1   ; X-Position
sprite3_Xpos        = $D2   ; X-Position
sprite4_Xpos        = $D3   ; X-Position
sprite5_Xpos        = $D4   ; X-Position
ballXpos            = $D5   ; xpos of ball
spriteXposSwap      = $D6   ; Used in the moving wall room only, to timeshare
                            ; the treasure and large hall monster on one sprite.

playerObjIndex      = $D7   ; This location stores the number of the sprite (0-5) that corresponds
			    ; to the player.  It is always 0 or 6.  A value of 6 means the player
			    ; is represented by the ball. 

pointsForKill       = $D8   ; This byte holds the number of points/100 in BCD that the player
			    ; will score for killing a monster in a ZoomedRoom. It begins at
		            ; 1-4 based on difficulty switches and increments each level up to 9 max.
			    ; The player scores double the number of points for picking up an item.

HMspriteNumber      = $D9   ; Bit 7 set to disable large hall monster, else the number within is
                            ; the hall monster sprite 0-5.  It seems to be restricted to 3 or 4.  $80 
			    ; means the large hall monster is inactive.

currentRoom         = $DA   ; The number of the room the player is currently in 0 to 9.

SpriteSwapFlag	    = $DB   ; Only in the moving walls room.  Set to 1 to indicate the HM sprite
                            ; is swapped onto the screen, and the treasure sprite is swapped out.
                            ; This byte is 0 when the item is swapped in and the Hall
                            ; monster is swapped out.

HallMonsterTimer    = $DC   ; This counter is decremented every 256 frames. When it reaches zero,
                            ; the big hall monster appears.

FrameCounter        = $DD   ; 8-bit frame counter.  The engine alternates drawing 3 of 6
                            ; sprites on even and odd frames.

sound1Active	    = $DE   ; This byte holds an offset into a table of sound generation values.
			    ; When this byte > 0 the sound is on.  When it decrements to zero
			    ; the sound turns off.

soundUnknown1	    = $DF

noteTimer1          = $E0

soundDuration       = $E1

;unknown	    = $E2

InitStatusforHM	    = $E3   ; Holds the value used to initialize the status byte of the large hall monster
			    ; whenever we enter a new zoomed room.  At the start of a game it is set from the
			    ; state of the difficulty switches.  The speed increments once per level completed.
;unknown	    = $E4

difficulty          = $E5   ; Difficulty 0-3

pointsScored        = $E6   ; The number of points scored this frame/100 and in BCD format.  Cleared to zero
			    ; at the beginning of each frame.

P0ShapeThisFrameLo  = $E7   ; 16-bit Pointer to GRP0 shape to be rendered this frame. (odd/even)
P0ShapeThisFrameHi  = $E8

P1ReposThisFrame    = $E9   ; desired repositioning line for current frame

desiredYposP0       = $EA   ; y position for next P0 sprite drawn this frame.  Note that a Y
			    ; position of 0 corresponds to scanline 17 of 192 in the kernel.

activelyDrawP0      = $EB   ; Set to 0 when P0 is not being drawn.  Contains the negative non-zero 
			    ; count of lines remaining to be drawn for P0.

preloadHeightP0     = $EC   ; preloaded height for the P0 sprite in the next frame.  If all
			    ; sprites were the same height this byte would not be needed.

saveCXP0FB	    = $ED   ; Mid-kernal saving of collision register information.
saveCXP1FB          = $EE 
saveCXBLPF          = $EF
saveCXPPMM  	    = $F0

spritePointer1      = $ED;$EE    ; Points to a sprite shape for the score.
spritePointer2      = $EF;$F0    ; Points to a sprite shape for the score.
spritePointer3      = $F1;$F2    ; Points to a sprite shape for the score.
resetShotFlag	    = $F1        ; RE-USED from spritePointer3. Set to 0 at the beginning of collision detection.
				 ; If the shot hits a sprite, wall, or edge of the playfield this location it incremented
				 ; to indicate the shot should be reset for firing by the player.
currentShapeP1      = $F2        ; RE-USED from spritePointer3. Points to GRP1 shape
spritePointer4      = $F3;$F4    ; Points to a sprite shape for the score.

desiredYposP1       = $F4   ; RE-USED from spritePointer4: y position for next P1 sprite

activelyDrawP1      = $F5   ; Set to 0 when P1 is not being drawn.   Otherwise it contains the negative non-zero 
			    ; count of lines remaining to be drawn for P1.

preloadHeightP1     = $F6   ; preloaded height for next P1 sprite.  Used twice per frame, once for 
			    ; each P1 instance in the frame.

savePFindex	    = $F7   ; Used to save the current index to the PF grpahics while in the 
			    ; kernel.
tempVar3            = $F7   ; Various temporary data
tempVar1            = $F8   ; Various temporary data
tempVar2            = $F9   ; Various temporary data

HMTimerSetup	    = $FA   ; This location holds the value used to reset the HM timer every time
			    ; the player enters a zoomed room.  It starts at 6 - diff and decrements once
			    ; per level to a minimum of 3.   The large hall monster appears after the 
			    ; the player has been in a room for HMTimerSetup*256 Frames.


    ORG $F000

Mainloop
; Control passes to the mainloop on cycle 11 of the first visible scanline.  However, because of
; the way this loop is structured, nothing is drawn on the first scanline.  This prevents us from
; seeing the HMOVE move bar in the first digit of the displayed score.
; Diplay score and remaining lives
;
; The kernel does three sprites per frame:
; shape flickerOffset is done with GRP0
; shape flickerOffset+1 is done with GRP1
; shape flickerOffset+2 is done with GRP1

        LDA #$07    		;11+2 = [13]
        STA tempVar1     	;

StatusDisplay
        LDY tempVar1     
        LDX charset,Y           ; X contains the '0' shape
        LDA (spritePointer1),Y 
        STA GRP0                ; Draw 1st digit
        LDA #$00
        STA PF1                 ; Clear PF1 for left half of screen.
        STA WSYNC               ; Sync				 Cycles = 0
        LDA (spritePointer2),Y  					; 5
        STA GRP1                ; Draw 2nd digit			; 3
        LDA (spritePointer3),Y 						; 5
        STA GRP0                ; Draw 3rd digit			; 3
        LDA (spritePointer4),Y 						; 5
        LDY tempVar1     						; 3
        STA GRP1                ; Draw 4th digit			; 3
        STX GRP0                ; Draw 0				; 3
        STX GRP1                ; Draw 0				; 3 
        STX GRP0                ; (Req'd for VDEL)			; 3 
        LDA tempVar2     						; 3 
        STA PF1                 ; display remaining lives		; 3 
        DEC tempVar1     						; 5
        BPL StatusDisplay   	; The loop repeats 8 times.		; 2
						       ; Total Cycles =  51 of scanline 9 of 192

; Position sprites for room display.  
        LDX flickerOffset						; 3
        LDA sprite0_Xpos,X      ; Get xpos of 1st sprite		; 4
        LDX #$00    							; 2
        STX NUSIZ0  		; Injected cleanup code after		; 3
        STX VDELP0  		; status display.			; 3
        STX VDELP1  							; 3
        STX PF1     							; 3
        STX GRP0    							; 3
        STX GRP1                					; 3
        JSR PosObject           ; Position P0 sprite.			; 6 = 33 + 51 = 84
				; We call PosObject on cycle 8 of scanline 10,
				; control returns on cycle 6 of scanline 12.
									; cycle 6
        LDX flickerOffset     						; 3
        LDA sprite1_Xpos,X      ; Get xpos of top P1 sprite		; 4
        LDX #$01    							; 2
        JSR PosObject           ; Position P1 sprite for first display 	; 6 = cycle 21
				; within the frame.
				; We call PosObject on cycle 21 of scanline 12.
				; control returns on cycle 6 of scanline 14

	; *** There are 67 wasted cycles on scanline 14. ***	

        STA WSYNC   		; Sync to end of scanline 14
        STA HMOVE               ; Fine Position				; cycle 3, line 15 of 192.

; Set P0 color.
        LDX flickerOffset     
        STX spritePointer2      ; Store offset (temporary?).  Is this ever used?
        LDA sprite0_Color,X   
        STA COLUP0              ; Set the color of P0 for the entire frame.

; Set the width of the P1 sprite for this screen.
        LDA P1spritewidth     
        STA NUSIZ1              ; P1 either normal or quad width
        STY WSYNC   		; End scanline 15 of 192.
        STA HMCLR               ; Clear horizontal motion			; 3 
        INY                     ; Y = 0.  Since it came back from		; 5
				; PosObject set to $FF.
	;-----
	; When control falls through from above we are just setting up to draw the room below
	; the already rendered score and lives display.  This kernal uses P1 twice per frame.
	; The second time P1 needs to be used we come to this point through the 
	; setUpForNextP1 label to finish the initialization of P1 after it has already
	; been repositioned horizontally over the last for scanlines.
	;-----
setUpForNextP1			; Control passes from above on cycle 5 of	; [5]/[14] - line 2
				; scanline 16.  The cycle for control entering
				; through the the setUpForNextP1 is cycle 14.
        INX 			; X = flickeroffset + 1 or + 2 depending	; 16 - worst case
				; which instance of P1 we are setting up.
        LDA sprite0_Color,X      						; 20
        STA COLUP1              ; Set color for P1				; 23

        LDA sprite0_Ypos,X   							; 27
        STA desiredYposP1       ; Set Y pos for GRP1				; 30
        BPL P1SpriteNotOnYet    ; Draw immediately on the first line?		; 32/33
        LDA sprite0_Height,X    ; Y:						; 36 - worst case
        STA activelyDrawP1      ; Set current height				; 39

P1SpriteNotOnYet								; [33]/[39] - line 2
        LDA sprite0_Height,X    ;						; 43 - worst case
        STA preloadHeightP1     ; Preload height for P1				; 47
        TXA         								; 49
        ASL									; 51
        TAX                     ; sprite # * 2					; 53
        LDA sprite0_Shape,X   							; 57
        STA currentShapeP1							; 60     
        LDA sprite0_Shape+1,X   						; 64
        STA currentShapeP1+1     ; Set shape for GRP1				; 67
        LDX savePFindex          ; x-> PF offset, depending on current room	; 70

; Draw first kernel line. Drawing of the room graphics begins on scanline 17 of 192.
; ------
; NOTE: Venture is a 2 scanline kernel.  That is, there is a minimum horizontal 
; resolution for all graphics of 2 scanlines.  Also, all sprites and missles move
; vertically in increments of 2 scanlines.  So there is no use of VDELPx in the 
; drawing of the current room.  
;
; Its important to note that pixels for P0 are in alignment with the 2 line kernal, but
; visible pixels for P1 or the Ball are offset from P0 pixels by 1 scanline.  


NextLine	SUBROUTINE
        LDA activelyDrawP0      ; Are we drawing P0?				; 73
        STA WSYNC								; 76 cycles!
	; Note: in the worst case, zero cycles remain. The worst case is when,
	; the kernal is repositioning P1 for its second appearance in the
	; current frame.
   
        BNE .DrawP0              ; Yes: We are already drawing P0 so go do it.	; 2/3
        CPY desiredYposP0        ; No:  Start drawing P0?			; 5
        BNE .SkipStartP0         ; No:  Skip start				; 7/8
        LDA preloadHeightP0      ; Yes:						; 10
        STA activelyDrawP0       ; Activate the drawing of P0 for as many       ; 13
        JMP .Continue1           ; frames as its preloaded height indicates.	; 16

.DrawP0										; [3] - Line 1
        LDA (P0ShapeThisFrameLo),Y   ; Load next byte of P0 graphic data and	; 8	
        STA GRP0                ; set shape of P0 for the current scanline.	; 11
        INC activelyDrawP0     	; scanline reduce remaining lines to draw for 	; 16
				; P0, and simultaneously increment the P0
				; graphics index.  All sprite graphic data ends
				; with a zero byte to turn the sprite off.

.Continue1			; With P0 taken care of proceed			; [16] - Line 1
        LDA pf1shapesleft,X     ; to draw the Playfield graphics.		; 20
        STA PF1                 ;						; 23
        LDA pf2shapesleft,X     ;						; 27
        STA PF2                 ; Draw left half of PF				; 30
        BIT mirroredRoom        ; is Room mirrored?				; 33
        BVS .SkipPF             ; Y: Skip changing PF				; 35/36
        NOP                     ;						; 37
        NOP                     ;						; 38
        NOP                     ; Waste cycles					; 40
        LDA pf2shapesright,X 							; 44
        STA PF2                 ; Draw right PF2 - asymetrical playfield	; 47
        LDA pf1shapesright,X 							; 51
        STA $0100+PF1           ; Draw right PF1, wasting an additional 	; 55
				; cycle to stay in sync at .Continue2


	

.Continue2								; [55] - line 1
        STX savePFindex         ; Save a copy of the PF graphics	; 58
				; index in case we jump to the 
				; P1 repositioning kernel.	
        LDA activelyDrawP1      ; Draw P1?				; 61
        BNE .DrawP1             ; Y: Goto draw				; 63/64
        CPY desiredYposP1       ; Start drawing P1?			; 66
        BNE .SkipStartP1        ; N: Skip start				; 68/69
        LDA preloadHeightP1     ; 					; 71
        STA activelyDrawP1      ; Store height of sprite		; 74
        CPY ballYpos            ; Draw Ball?				; 01 - begin 2nd line
        JMP .Continue3   						; 04

.SkipStartP0								; [8] - line 1
        NOP         							; 10
        LDA flickerOffset       ; Waste cycles				; 13
        JMP .Continue1							; 16

.SkipStartP1								; [69] - line 1
        NOP         							; 71
        LDA flickerOffset       ; Waste Cycles				; 74
        CPY ballYpos            ; Draw Ball?				; 01 - begin 2nd line
        JMP .Continue3   						; 04

.WasterRTS
        RTS         

.SkipPF									; 36 - line 1
        JSR .WasterRTS   						; 47
        STX savePFindex     						; 50
        NOP               ; Waste cycles				; 52
        JMP .Continue2   						; 55 perfect sync!

.SkipBall								; [7] - line 2
        LDA #$00    							; 9
        STA ENABL         ; Disable Ball				; 12
        BEQ .Continue4   						; 15

.SkipPFAgain1								; [40] - line 2
        JSR .WasterRTS   						; 52
        JMP .Continue5   						; 55

.DrawP1									; [64] - line 1
        INC activelyDrawP1       ; reduce remaining height		; 69
        LDA (currentShapeP1),Y   ; Load shape				; 74
        CPY ballYpos             ; Draw Ball?				; 01 - begin 2nd line

; Second kernel line. Draws P1, Ball and the PF.

        STA GRP1                ; Set shape				; 04

.Continue3								; [04] - line 2
        BNE .SkipBall           ; No:  Don't draw ball.			; 6/7	
        LDA #$02                ; Yes: Draw Ball!				; 8
        STA ENABL               ; Enable Ball				; 11
        NOP                     ;					; 13
        NOP                     ; Waste cycles				; 15

.Continue4								; [15] - line 2
        LDA pf1shapesleft,X 						; 19
        STA PF1     							; 22
        LDA pf2shapesleft,X						; 26
        STA PF2                 ; Draw left half of PF			; 29
        TYA                     ; A -> Kernal Line-Pair Counter		; 31
        CMP PFshapechanges,X    ; change PF shape?			; 35
        BNE .KeepPFShape        ;					; 37/38
        BVS .SkipPFAgain1       ; Mirrored? V flag is still intact!	; 39/40
        LDA pf2shapesright,X 	; No:					; 43
        STA $010F               ; Draw right PF2(!) + 1 cycle waste	; 47
        LDA pf1shapesright,X 						; 51
        STA PF1                 ; Draw right PF1			; 54 - out of sync?

.Continue5								; [55] - line 2
        INY                     ; 2 line kernal, line-pair done.	; 57
        CPY P1ReposThisFrame    ; Reposition GRP1 now?			; 60
        BEQ RepositionP1Kernel  ;					; 62/63
        INX                     ; Advance PF offset to next line	; 64
        JMP NextLine            ; Continue with next normal line	

.KeepPFShape								; [38] - line 2
        BVS .SkipPFAgain2       ; Mirrored? V flag is still intact!	; 40/41
        LDA pf2shapesright,X 	; No:					; 44
        STA PF2     		; Draw right PF2(!)			; 47
        LDA pf1shapesright,X 						; 51
        STA PF1                 ; Draw right half of PF			; 54

.SkipPFAgain2								; [41]/[54] - line 2
        INY                     ; 2 line kernal, line-pair done.	; 43/56
        CPY #SCREEN_BOTTOM_LINE ; Done With Kernel?			; 46/59
        BEQ .BailOut            ; Y: Quit Kernel			; 48/49, 61/62
        JMP NextLine            ; N: Continue with next normal line	; 51/64

.BailOut								; [49]/[62] - line 2
        JMP kernelDone   						; 52/65


;========================================================================================
	SUBROUTINE		; These small routines are part of the RepositionP1Kernel
				; which has its etry point below.
.SkipStartP0								; [07] - Line 1
        INC tempVar2		; Waste time?				; 12
        JMP .Continue1   						; 15
;--------
.1skipcalc								; [58] - Line 1
        BCC .Continue2  	; This branch is always taken.		; 61
;--------
.TurnBallOff								; [06] - Line 2
        BNE .Continue3		; This branch is always taken.		; 09

;-------
; NOTE:  P1ReposThisFrame values ALWAYS coincide with a PFshapechange value for the room
; being displayed.  The kernel will not work if the value in P1ReposThisFrame does not
; match a value in PFshapechange for the current room.  Repositioning must not be set
; to occur on or between the kernal line pairs Y=$4E or Y=$4F (the last line), or the
; kernel will draw to many lines.
;
; ALSO:  The RepositionP1Kernal only has enough cycles to draw a reflected playfield,
; so the 4 scanlines where it occurs in the frame must be symetrical even if the room
; otherwise is not a mirrored room! 
;
; Basically the entire kernel from above is repeated again TWICE(!) except it repositions
; P1 horizontally rather than drawing P1.  The kernel still must draw the PF, P0, and Ball
; while it repositions P1.
; 

;--------
RepositionP1Kernel							; [63] - Line 2
        INX 			; Increment the PF graphics index.  	; 65
        LDA pf1shapesleft,X 	; Get ahead of ourselves and begin load	; 69
        STA PF1     		; loading the PF graphics for the next	; 72
				; line 1.
        LDA activelyDrawP0     	; Is P0 visible this kernel line-pair?	; 75
        BNE .DrawP0   		; Yes: Skip ahead to draw it.		; 01/02 - Begin Line 1!
        CPY desiredYposP0     	; No: Should we be drawing it?		; 04
        BNE .SkipStartP0   	;     No: skip out.			; 06/07
        LDA preloadHeightP0     ;    Yes: Initialize P0 drawing values.	; 09
        STA activelyDrawP0     						; 12		
        JMP .Continue1   						; 15

.DrawP0									; [02]
        LDA (P0ShapeThisFrameLo),Y 					; 07
        STA GRP0    		; load P0 graphics for the line.	; 10
        INC activelyDrawP0     	; count the line drawn for P0.		; 15

.Continue1								; [15] - Line 1
        LDA pf2shapesleft,X 	;					; 19
        STA PF2     							; 22
	
	; Note: we are losing the PF graphics index stored only in X.
	; Later in the routine we will restore it from the value
	; in P1ReposThisFrame that brought us to this alternate kernal.

        LDX flickerOffset     	; load the desired X position for P1	; 25
        LDA sprite2_Xpos,X 	; which is for either sprite 2 or	; 29
				; sprite 5 according to flickerOffset,
				; which in turn is set according to if
				; the frame is even or odd.
									
        TAX         							; 31
        AND #$0F    							; 33
        STA tempVar2     						; 36
        TXA       							; 38  
        LSR								; 40
        LSR								; 42
        LSR								; 44
        LSR								; 46
        TAX         		; X = (Xpos >> 4)			; 48
        CLC         							; 50
        ADC tempVar2    	; A = (Xpos & $0F) + (Xpos >> 4)	; 53
        CMP #$10    							; 55
        BCC .1skipcalc   						; 57/58
        SBC #$0F    							; 59
        INX         		; X = (Xpos >> 4) + 1			; 61

.Continue2								; [61] - Line 1
        ASL								; 63
        ASL								; 65
        ASL								; 67
        ASL								; 69
        EOR #$70    							; 71
        STA HMP1    							; 74

        LDA #$00    							; 00 - Begin Line 2
        CPY ballYpos     	; Should Ball be drawn:			; 03
        BNE .TurnBallOff   	; No: skip out to waste time.		; 05/06
        LDA #$02    		; Yes: Turn the ball on.		; 07
        NOP         							; 09

.Continue3								; [09] - Line 2
        STA ENABL   	; Enable/Disable according to what is in A.	; 12

.1loop									; [12] - Line 2
        DEX         
        BPL .1loop 
        NOP         
        STA RESP1 	; Set rough position for P1.  
        STA WSYNC	; end the second line in thefirst kernal pair.		

	; ---------------
	; We are now beginning the 2nd kernalline-pair of two in 
	; the P1 repositioning routine.
	; NOTE:  No changes are made to the PF registers for this or the next
	;        scanline.  So 4 scanlines have identical and reflected PF 
	;        graphics when P1 is being repositioned.
	; ---------------
   	SUBROUTINE		; Let's reuse local labels.		; [00] - Begin line 1
        INY         							; 02
        LDA activelyDrawP0	; Are we drawing P0?			; 05
        BNE .DrawP0   		; Yes: then branch to draw P0.		; 07/08
        CPY desiredYposP0     	; No:  Should we start drawing P0? 	; 10
        BNE .Continue1   	;	No: Skip ahead.			; 12/13
        LDA preloadHeightP0    	;	Yes: Initialize the P0		; 15
        STA activelyDrawP0     	;	     graphics index/counter	; 18
        JMP .Continue1   	;					; 21

.DrawP0									; [08] - line 1
        LDA (P0ShapeThisFrameLo),Y 	; Draw P0 and increment the 	; 13
        STA GRP0    			; index/counter for P0.		; 16
        INC activelyDrawP0     						; 21

.Continue1								; [13]/[21] - line 1
        LDX flickerOffset     	; Initialize to point at the sprite	; 24 - worst case timing.
        INX         		; data for the next instance of P1.	; 26

				
				
				
        LDA CXP0FB  		; We are recycling P1 in the frame so	; 29
        STA saveCXP0FB          ; we preserve collision information 	; 32
        LDA CXP1FB  		; for the first half of the kernel.	; 35
        STA saveCXP1FB    						; 38
        LDA CXBLPF  							; 41
        STA saveCXBLPF     						; 44
        LDA CXPPMM  							; 47
        STA saveCXPPMM  						; 50

        INC savePFindex     	; Increment the PF graphics index?!	; 55
				; NOTE: This means the PF graphics
				; will be different next scanline. 
				; For the 4 scanlines within this 								; alternate kernel the PF grpahics were
				; mirrored and unchanging even if the 
				; rest of the room is asymetrical. 

        LDA #$00    		; Deactivate P1 in case it was being	; 57
        STA activelyDrawP1      ; drawn before we began repositioning.	; 60
        CPY ballYpos     	; Test if the ball should be turned on	; 63
        BNE .ballOff   		; No: skip ahead to disable the Ball	; 65/66
        LDA #$02    		; Yes: Load the value to enable the 	; 67
				; Ball.
.ballOff								; [66]/[67] - Line 1
        STA WSYNC   		; sync for HMOVE.			; 70 - worst case timing. 

									; [00] - line 2
        STA HMOVE   		; fine adjustment of P1	position.	; 03
        STA ENABL   		; enable/disble ball from value in A.   ; 06
        STA CXCLR   		; clear all collision registers.	; 09	
        INY         		; Nothing more will be drawn on this	; 11
				; scanline and the kernel line-pair is
				; ending so we increment the kernel 
				; line-pair counter in Y.
        JMP setUpForNextP1   	; We jump back to the top of the kernel ; 14
				; which will complete the initialization
				; of the second P1, by

;======================================================================================
; Control comes to kernelDone when the kernel line-pair counter in Y reaches $50.
; At this point we have drawn 16 + 80*2 scanliens = 176 visible scanlines!?
; Control arrives on cycle 52 or 65 of the last visible scanline.
;------------
kernelDone	SUBROUTINE							; [52]/[65] - line 2
        LDA #$02    								; 67 - worst case
        STA WSYNC           	; sync to end of last visible line.		; 70 - end kernel.
        STA VBLANK  		; Turn on VBLANK, to begin overscan

        LDX #$30    		; Set the overscan timer.
        STX TIM64T  		; $30 = 48 -> 48 * 64 = 3072 cycles
				; 3072 / 76 = 40.41 scanlines worth
				; = 41 overscan scanlines per frame.

				; ================================
				; Total lines per frame:
                                ;      3 vertical sync
				;     43 vertical blank
				;    176 visible scanlines.
				; +   41 overscan scanlines.
				; ------
				;    263 total scanlines per frame. (I think)
				; =================================

        LDA SpriteSwapFlag	; If the sprites are swapped, then swap them back and clear the 
        BEQ .1skip              ; swapped flag. (sprite swapping occurs only in moving wall room)
        LDX HMspriteNumber     
        JSR ItemHMDataSwap   
        DEC SpriteSwapFlag     
.1skip

        LDA SWCHB   		; Read the console switches to check for a reset.
        LSR			; Shift the RESET switch state flag into carry.
        BCS .noReset   		; If C=1, then the reset switch is not pressed, so skip ahead. 

        LDA gameStateFlags1     ; RESET IS PRESSED:  So we pause the game by setting bit 7 in 
        ORA #$81    		; gameStateFlags1, and record the reset switch is closed by setting
        STA gameStateFlags1    	; bit0.  The game will remain paused and not reset until the reset
				; switch is released (see below).
 
.noReset
        LDA gameStateFlags1  	; If bit7 is set the gameplay is paused either because the player just
        BPL gameNotPaused   	; entered a new room, the game is over, or reset is being held down.
        LSR			; Test to see if the reset button was being pressed.
        BCC gameNotReset   	; NO: skip ahead the game is paused, but not being reset.
        LDA SWCHB   		; YES: Check if the player has released the reset button because
        LSR			;      the game does not reset until the reset button is pressed
        BCC .2skip   		;      and released.
        LDX #$80    		; YES: The reset switch is now released, so we reset the game.  Note
        JSR InitGame   		; that setting X=$80 before calling InitGame, causes Initgame to
        BEQ .2skip   		; clears only RAM from $80 to $FB, which is different than the powerup
				; reset which clears all TIA registers along with the RAM.

gameNotReset			; Control comes to this point when the gameplay is paused, but the
				; reset switch is not being pressed.
        LDA pauseTimer     	; If (pauseTimer == $00) then
        BEQ .2skip   		;	remain paused the player is dead and game play stops!
        DEC pauseTimer     	; else if (pauseTimer > 1) then
        BNE .2skip   		; 	remain paused, but decrement the timer.
				; else the timer in pauseTimer is expired and gameplay resumes.  
				; Fall through to resume gameplay.

        DEC $CD     		; not sure what $CD is???  
        BPL .3skip   		; but when it is negative, then	
        LDA gameStateFlags1     
        AND #$7F    
        STA gameStateFlags1     ; the game is unpaused.


        LDA roomLockedFlags    
        CMP #$0F    		; If all 4 bits are set, then all rooms on the level are done.
        BEQ levelCompleted   	; YES: go to the next level.

        BIT gameStateFlags1     
        BVS .2skip   
        LDA #$27    
        STA sound1Active     
        BNE .2skip   		; branch always taken.
	;-------------------

levelCompleted		
        LDA #$FF    
        STA pauseTimer     	; The game always pauses at the end of a level.
        ROR gameStateFlags1     
        LDA #$02    
        STA $CD     
        BNE .2skip   		; branch always taken.

.3skip
        DEC $CD     
        BMI LF265   

        LDX pointsForKill     	; Increase the number of points scored for picking up an item
        CPX #$09    		; Unless it is already at 900 points which is the max.
        BEQ .4skip  
        INC pointsForKill     
.4skip

        INC currentLevel     
        LDX currentLevel     
        LDA #$06    
        STA HMTimerSetup     	; Reset to 6 the same as at powerup.
        CPX #$04    
        BPL LF25F   
        INC $E2     
        INC $E4     
        INC difficulty     
        CPX #$02    
        BNE LF25F   
        INC InitStatusforHM     
LF25F
        LDA #$00    
        STA roomLockedFlags     
        BEQ LF26D   
LF265
        DEC livesCounter     
        BPL LF26D   
        INC livesCounter     
        BEQ .2skip   
LF26D
        JSR LF8E8   
.2skip
        JMP FinishOverscan   

;-------------------
gameNotPaused	SUBROUTINE
        LDX flickerOffset    	; We look at flicker offset to determine which sprites were active 
        BEQ postFrame012   		; during the last frame, and need to be processed during overscan.
        JMP postFrame345   

postFrame012		; Control comes to this point following a frame where sprites 0, 1, and 2
			; were being displayed.

        STX PFcollisionFlags	; = 0  
        LDX playerObjIndex     
        LDA sprite0_Status,X   	; Isolate the last joystick information for the player.
        AND #$F0    
        CMP #$F0    
        BNE .1skip   			; If any direction is being pressed, then skip ahead.

        LDA $C1     
        BEQ LF2AE   
        LDA $C2     
        STA LastPlayerDirection     
        BNE LF2AE   

.1skip
        STA LastPlayerDirection     	; This set of tests makes no sense, yet. ???
        CMP #$A0 	; Left and Up?   
        BEQ .diagonal   
        CMP #$90	; Left and Down?    
        BEQ .diagonal   
        CMP #$60	; Right and Up?    
        BEQ .diagonal   
        CMP #$50    	; Right and Down?
        BNE .straight   	

.diagonal
        STA $C2     
        LDA #$06    			; Seems to be some sort of timer for player changes of direction. ???
        STA $C1  
   
.straight
        LDA $C1     
        BEQ LF2AE   
        DEC $C1     
LF2AE

        LDA sprite0_Xpos,X   
        STA tempVar1     
        LDA sprite0_Ypos,X   
        STA tempVar2     
        LDA currentRoom     
        CMP #$08    
        BMI .zoomedRoomCalcIndex  

.bigRoomCalcIndex	; A = currentRoom = 8 or 9
        LDX #$01    
        STX roomLockMask     ; In big rooms roomLockMask holds the room-lock bitmask used to check if 
			; the room-locked flag for the room corresponding to each door is set or not.

        SEC         
        SBC #$08	; A = 0 or 1    
        ASL
        ASL
        ASL
        ASL		; A = A * 16 = 0 or 16
        TAX         

        LDY #$08    	; 8 doors in each big room to check.
        BNE .nextDoor  

.zoomedRoomCalcIndex	; A = currentRoom = { 0, 1, 2, 3, 4, 5, 6, or 7 }
        ASL
        ASL
        ADC #$01	; A = currentRoom * 4 + 1 = { 1, 5, 9, 13, 17, 21, 25, 29 }    
        TAX         

        LDY #$02    	; 2 doors in each zoomed room to check.

; Just a reminder of the meaning of bits 6 and 7 in the byte containing the Y-coordinate
; if each door:
; %00 = Vertical orientation approach from left moving right to pass the through door.
; %01 = Vertical orientation approach from right moving left to pass the through door.
; %10 = Horizontal orientation approach from bottom moving up to pass the through door.
; %11 = Horizontal orientation approach from top moving down to pass the through door.
;
.nextDoor	
        LDA doorYPositions,X 	; Get door y-coor and flags in bits 7 and 6.
        BMI .horizontalDoor   	; I bit7 is set, then the door is oriented horizontally.

.verticalDoor			; Bit7=0 means the door is oriented vertically.  
        ASL			; Multiply the Y value by 2 and move bit 6 to bit 7.  bit7 is discarded.
        STA tempVar3     	; Save a copy to remember the bit6 flag.
        AND #$7E    		; Mask out the bit6, and preserve only the Y value.
        SEC         		; no borrow.
        SBC tempVar2     	; Subtract the player's Y position.
        BPL .positive1  	; A positive result requires no adjustment, but a negative result
        EOR #$FF    		; is inverted. (-1) becomes 0, (-2) becomes 1, (-3) becomes 2.


.positive1
        CMP #$02    		; Acc must be 0 or 1 for the subtraction of 2 to yield a negative.
        BPL .doorNotTouched     ; If the doorY - playerY was not 1,0,-1, or -2, then door not touched.
				; So a verticalDoor will trigger over a range of 4 pixels.
				;-----------------
				; Its not clear why the door Y positions are not set to produce 
				; values 0 to 3 rather than 1 to -2 to indicate door contact. 
				; changing the code and data would free ROM bytes.
				;------------------
        LDA tempVar3     	; Test the bit6 flag from the Door-Y-coordinate byte saved earlier.
        BMI .approachFromRight  ; If the bit is set, the program expects the player to approach the
				; door from the right

.approachFromLeft		; If bit6 is clear, the program expects the player to approach the 
                                ; door from the left side.
        LDA doorXPositions,X 	; playerY was in range for the door so fetch the door X coordinate.
				; NOTE: The X-coor does not get multiplied by 2.
        SEC         		
        SBC tempVar1     	; DoorX - PlayerX >= 0?
        BPL .doorNotTouched   	; Yes: player is too far left to trigger the door.
				; NOTE: C=0 if the result of the previous subtraction is negative?
        ADC #$05    		; No:  If DoorX - PlayerX + 5 < 0 ?
        BMI .doorNotTouched   	;      YES: player is too far right to trigger the door.
        BPL .inDoorZone1   	;      NO:  player is in the activation zone of the door.
	;----------------------- 
.approachFromRight		; Alternately, if bit 6 is set, then we expect the player to approach
				; the door in question from the right.
        LDA doorXPositions,X 	; 
        STA tempVar3     	; 
        LDA tempVar1     
        SEC         
        SBC tempVar3     	; Calculate PlayerX - DoorX >= 0 ?
        BPL .doorNotTouched     ; YES: Player is too far to the right of the door to activate it.
        ADC #$05    		; No:  Calulate PlayerX - DoorX + 5 < 0 ?
        BMI .doorNotTouched     ;      Yes: The player is too far left to activate the door.
				;      No:  Fall through, the player is in the door's activation zone.
				
.inDoorZone1			
        LDA roomLockMask     	; Is the room locked blocking player entry?
        BIT roomLockedFlags     
        BEQ doorActivated   	; No:  Activate the door to enter the new room.

        LDA doorXPositions,X	; Yes: The room is locked, bounce off the door.  Please notice in the 
        STA ballXpos     	; region testing above a condition of DoorX=PlayerX will not activate the
        JMP postFrame345   	; door, thus we can set the PlayerX from DoorX safely.
	;------------------------

.horizontalDoor			; We repeat the same logic for a horizontal door as we did for a vertical
				; door above, except the roles of X and Y are reversed in the calculations.
        ASL
        STA tempVar3     
        LDA doorXPositions,X 
        SEC         
        SBC tempVar1     
        BPL .positive2  
        EOR #$FF    
.positive2

        CMP #$02    
        BPL .doorNotTouched   
        LDA tempVar3     
        BMI .approachFromTop   	; Test bit 6 for Y-table byte to determine the expected approach vector.

.approachFromBottom
        LDA tempVar2     
        SEC         
        SBC tempVar3     
        BPL .doorNotTouched   
        ADC #$05    
        BMI .doorNotTouched   
        BPL .inDoorZone2   

.approachFromTop
        AND #$7E    
        STA tempVar3     
        SEC         
        SBC tempVar2     
        BPL .doorNotTouched   
        ADC #$05    
        BMI .doorNotTouched   

.inDoorZone2
        LDA roomLockMask     	; Check if the room is locked?
        BIT roomLockedFlags     
        BEQ doorActivated   	; No: Enter the room.

        LDA tempVar3     	; Yes: Bounce off.
        STA ballYpos     
        BNE postFrame345  
 
.doorNotTouched
        INX         		; Increment the Door data index by 2.  
        INX         
        DEY         		; Decrement count of doors remaining to check in Y.
        BEQ postFrame345   	; If Y reaches 0, then no door was being touched.

        TYA         		; Every other time through the loop (because each room has 2 doors),
        LSR			; The room Lock Mask is advanced to the next room's lock flag position.
        BCS .sameRoom   
        ASL roomLockMask  	; -> here is the key to the locking of doors.  This mask shifts 1 bit every 	    			; that maps to once per room even in the zoomed rooms. 
.sameRoom
        JMP .nextDoor   
;--------------------------------
;
doorActivated	
	; Control comes to this routine when it is detected that the player is within the activation
	; zone of a door.  The X register holds the index to the Door that was activated.

        BIT gameStateFlags1     ; Test Bit6 in Game State flags to see if we are entering a Big Room
        BVC .enterZoomedRoom   	; or a Zoomed Room.

.enterBigRoom
        LDA #$08    		; Activate the sound effect sequence for entering a Big Room.
        STA sound1Active    
 
        DEX         		; Decrementing the index in X points the door index to the equivalent
				; door data for the door in the room being entered.

        LDA doorXPositions,X 	; In BigRooms the player is represented by the ball.  So we set the 
        STA ballXpos     	; position of the ball to match the door position of the door just	
        LDA doorYPositions,X 	; passed through.
        ASL
        AND #$7E    		
        STA ballYpos     

        LDA roomLockedFlags     ; Decide if the Zoomed Room we are leaving should be locked?
        BIT roomDoneFlag     
        BPL .doNotLock   	; If the item was not picked up, the room is not done.
        ORA roomLockMask     	; otherwise we set the locked flag corresponding to the room.
.doNotLock
        STA roomLockedFlags     

        TXA         		; Because of the way the Door data table is arranged we calculate
        LSR			; whether the Big Room being entered is Level 1 (room 8) or Level 2
        LSR			; (room 9) by dividing the Door Data index in X by 16.  After which
        LSR			; the remaining value is 0 or 1.  To which we add 8 to get 8 or 9.
        LSR
        CLC         
        ADC #$08    
        BNE .goNewRoom   	; This branch is always taken.  Register A = the new value for 
				; currentRoom

.enterZoomedRoom
        INX        		; Incrementing the index in X points the door index to the equivalent
				; door data for the door in the room being entered.

        LDA doorXPositions,X 	; Position the player at the door entered.
        STA sprite0_Xpos     
        LDA doorYPositions,X 
        ASL
        AND #$7E    
        STA sprite0_Ypos

        LDA #$F9		; Set the height for the player sprite.
        STA sprite0_Height     

        LDA #$50    
        CLC         
        SBC sprite0_Ypos     
        STA sprite0_Shape     
        LDA #$FF    
        STA sprite0_Shape+1   	; Set the player graphics pointer adjusted for the current Y position.  

        TXA         
        LSR
        LSR			; Calculate the new room number from the door data index.

.goNewRoom
        STA currentRoom     	; Save the new room number.
        JSR InitRoom   		; Initialize the new Room.
        JMP FinishOverscan  	; We are entering a new room so skip collision detection and monster
				; movement.
;-------------------------
 
postFrame345	SUBROUTINE
	; Control comes to this point during overscan for every odd frame, and on any even frame when
	; the player does not activate a door.  This portion of overscan deals with checking for 
	; collisions.  If the player passed through a doorway, then collisions are impossible for
	; the current frame.
	; It takes 2 frames to collect collision data for all 6 sprites and two for the Ball.
	;
	; The bits in collsionFlags are between sprites and the playfield.
	; bit7 = sprite 0
	; bit6 = sprite 1
	; bit5 = sprite 2
	; bit4 = Ball even frame
	; bit3 = sprite 3
	; bit2 = sprite 4
	; bit1 = sprite 5
	; bit0 = ball odd frame

        ASL PFcollisionFlags     	; Make room for next collision flag. New flags are shifted in from the
        LDA saveCXP0FB     	; right.  The flag is currently cleared.
        ORA CXP0FB  		; P0 could be before or after the P1 repositioning, so we OR the two
        BPL .1skip   		; collision flags together.
        INC PFcollisionFlags    	; Set the flag, a collision occurred. 
.1skip				; No collision, the flag remains cleared.

        ASL PFcollisionFlags     	; Repeat for the two instances of P1 and the ball.
        LDA P1ReposThisFrame     
        CMP #$50    
        BNE .2skip   
        LDA CXP1FB  
        BCS .3skip   
.2skip
        LDA saveCXP1FB     
.3skip
        BPL .4skip   
        INC PFcollisionFlags     
.4skip
        ASL PFcollisionFlags     
        LDA CXP1FB  
        BPL .5skip   
        INC PFcollisionFlags     
.5skip
        LDA flickerOffset     
        BEQ .6skip  
        ASL PFcollisionFlags     
        LDA spritePointer2     
        ORA CXBLPF  
        BPL .7skip  
        INC PFcollisionFlags     
.7skip
        ASL PFcollisionFlags     
.6skip

        LDA currentRoom    	; Are we in a large room or a zoomed room. 
        CMP #$08    
        BMI zoomRoomCollisions	; Zoomed room, jump ahead.
				; Big Room, fall through.

bigRoomCollisions	SUBROUTINE
        BIT saveCXP0FB     	; In a Big Room the player is the Ball.  So we check to see if the 
        BVS playerHit   	; ball touched any of the 3 sprites in the frame.   If it did, then
        BIT saveCXP1FB  	; the player loses a life.   
        BVS playerHit   
        BIT CXP0FB  
        BVS playerHit   
        BIT CXP1FB  
        BVS playerHit   
        JMP updateScore   	; Player not killed this frame.
playerHit
        JMP playerKilled   	; Player died.


zoomRoomCollisions	SUBROUTINE
        LDX flickerOffset     ; Are we dealing with sprites 0, 1, and 2, or sprites 3, 4, and 5?
        BNE sprites345  

.sprites012 
        LDX #$07    		; Setting LDX to 7 will point at the SpriteSwap data locations.
        JSR playerCollisionTest   		; Did player collide with the large Hall Monster?
        BCS playerHit   	; Yes:	Ouch!
				; No:   Fall through to next test.

        LDY currentRoom     	; Note: We are in an even frame in which P0 is the player's sprite.
        BIT saveCXPPMM 		; So we check if P0 is touching either instance of P1 in the frame.    
        BPL .1skip   		; No: P0 is not touching the 1st instance of P1, so skip to next test.

        CPY #$03    		; Is this the moving walls room (#3)?  
        BEQ playerHit   	; YES:  then the player touched a wall and is dead.
        LDA RepositionTable,Y 	; Else: If bit7 of the P1 reposition value is clear, then sprite 1 is
        BPL playerHit   	; a monster and the player is hit.  Otherwise, sprite 1 is the item
        LDX #$01    		; and the player picks it up.
        BNE .item 
  
.1skip
        BIT CXPPMM  		; Check for contact between sprite0 (player) and sprite2
        BPL shotCheck   ; If no contact then branch to next collision test.

        CPY #$03    		; Yes the player is touching sprite 2.  If we are in the moving walls
        BEQ playerHit   	; room then the player has hit a wall and dies.

        LDA RepositionTable,Y 	; If bit7 of the Y reposition value for the current room is set, then
        BMI playerHit   	; sprite2 is a monster and the player is hit.  Else sprite2 is the item
        LDX #$02    		; and we fall through to pick it up.
.item
        BNE touchingItem   	; ALWAYS jump to the routine that handles picking up an item.  The number
				; of the sprite (1 or 2) that is the item is in the X register.
;----------
; Collision detection for odd frames when we display sprites 3, 4 and 5. 
sprites345	SUBROUTINE
        LDX #$04 		; We are going to test for colllisions with sprite 4 a little later.
   
        LDY currentRoom     	; Are we in the moving walls room?
        CPY #$03    		; 
        BNE .1skip   		; No:  Then the humming noise is not active and we skip ahead.
				; Yes:  Fall through to update humming sound effect.
        LDA HMspriteNumber	; Is the large hall monster active?
        BPL .2skip   		; Yes:  Skip ahead because Roar sound overrides humming wall sound.
        LDA sprite2_Xpos    	; No:	Set the volume for the humming sound effect in the moving wall
        LSR			;       room.  It is based on the oscillating position of the moving
        LSR                     ;       walls.
        AND #$07    
        STA AUDV1   

.2skip				; X is currently 4, but if the Hall monster is active then we need to test
        LDX #$05    		; sprite 5 as well as 3 and 4 for collision with the player sprite 0.
.1skip				; Control skips to this point to test only sprites 3 and 4.

.1loop
        JSR playerCollisionTest ; Is Sprite0 touching sprite X?
        BCC .3skip   		; NO:  Skip ahead.
        CPX #$04    		; YES: Then, is it sprite 4 or 5?
        BPL playerKilled   	;      YES: The player is killed.
        CPY #$03    		;      NO:  Then, are we in Room 3? (moving wall room?)
        BEQ touchingItem   	;	    YES: Player is touching sprite 3 in the moving wall room which is the treasure.
        BNE playerKilled   	;           No:  Player is touching sprite 3 in another room and the player dies.
.3skip	
        DEX         		; Decrement sprite counter in X.
        CPX #$02    		; When X reaches 2, we are finished testing for collisions.
        BNE .1loop  	

;---------------	
; This code executes for both even and odd frames to update the player's shot.
; Y = currentRoom
;
shotCheck	SUBROUTINE
        CPY #$03    		; If we are in the Moving Walls room the player can not shoot, so we skip ahead to update.
        BEQ updateScore   	; the player's score.
        BIT shotReadyFlag     	; If the shotReadyFlag is set, then the shot is not in flight and requires no update, 
        BMI updateScore   	; skip ahead to update the player's score.

				; The shot is in flight we will therefore check for its collision with the monsters in the 
				; current room.
        LDX #$01    		; The item is either sprite 1 or 2, we test bit7 in the RepositionTable for the room to 
        LDY currentRoom     	; (this seems like a wasted instruction, Y should already contain currentRoom) 
        LDA RepositionTable,Y   ; see which is the item, and set X to point at the other which must be a monster.
        BPL .1skip   
        LDX #$02    
.1skip
        JSR shotCollisionTest   ; X is sprite1 or 2, depending on which is the monster in this room.		
        BCS monsterKilled   	; C=1 so monster is dead.

        LDX #$03    
        JSR shotCollisionTest   ; X = sprite3
        BCS monsterKilled   	; C=1 so monster is dead.

        LDX #$04    
        JSR shotCollisionTest   ; X = sprite4
        BCC updateScore  	; C=0 so monster is alive jump ahead, else monster killed and we fall through.
 
;------- Fall through possible  ---------------------

monsterKilled	SUBROUTINE
	; Control is passed to this routine when it has been detected that the player's shot has hit a monster.
	; X holds the number of the sprite that corresponds to the monster hit.
        LDA #SPRITE_STATUS_DEAD    		
        CMP sprite0_Status,X   ; If the monster is already a corpse do not give the player more points.
        BEQ .1skip   

        LDY roomDoneFlag     	; If the player has not yet picked up the room's item, do not award points for 
        BEQ .1skip   		; killing the monster.

        LDY pointsForKill     	; Give the player points for the kill
        STY pointsScored      

.1skip
        STA sprite0_Status,X   ; Set the status of the monster sprite to SPRITE_STATUS_DEAD, which seems to mean dead???
        LDA #$20    
        STA sound1Active    	; Activate the kill monster sound. 
        ASL
        STA sprite0_Timer,X 	; Set the monster sprite Timer value to $40.  So the corpse is displayed for 128 frames.  

        LDA #$F6    		
        SEC         
        SBC sprite0_Ypos,X   
        TAY         
        TXA         
        ASL
        TAX         
        STY sprite0_Shape,X   	; Change the image pointer for the monster to point at the corpse image.

        LDA #$80    		; Reset the shot, and make it ready to fire.
        STA shotReadyFlag     
        BNE updateScore   	; Branch is always taken.
;---------------------------------------------------------	

touchingItem	SUBROUTINE
; This routine is called when the player collides with the room's item.
; X = the sprite that represents the item in the current room.
        LDA #SPRITE_NOT_VISIBLE    
        STA sprite0_Ypos,X   	; Make the item sprite invisible, by moving it off the bottom of the screen.

        CLC         
        SED         
        LDA pointsForKill     
        ADC pointsForKill     
        STA pointsScored     	; The player scores double the points for picking up the item as for killing
        CLD         		; a monster.

        DEC roomDoneFlag     	; Set bit7 -> $00 - 1 = $FF, to indicate the room's item was collected.

        LDA #$2A    		; Activate the sound effect for collecting an item.
        STA sound1Active     	
        BNE updateScore   	; This branch is always taken.
;----------------------------------------------------------

playerKilled	SUBROUTINE
	; This rountine is called when the player dies.
        LDA gameStateFlags1     
        ORA #$80    
        STA gameStateFlags1  	; Set bit7 to pause the gameplay.   
        LDA #$19    
        STA sound1Active     	; Activate the death noise.
        LDX #$FF    
        STX pauseTimer     	; Freeze game play when the death sound plays. (~ 4 sec)
        INX 	; X = 0
        STX AUDV1   		; Silence any currently active sound.
        INX     ; X = 1
        STX $CD	; = 1	???  I still don't know what $CD is for!!!!
        BNE playerDiedSkip   	; This branch is always taken.
;----------------------------
	
updateScore	SUBROUTINE
        SED         
        CLC         
        LDA score_3_4     
        ADC pointsScored  	; Add the points scored this frame to the player's total score.   
        STA score_3_4     
        LDA score_1_2     
        ADC #$00    
        STA score_1_2     
        CLD         

        LDX flickerOffset	; Odd or even frame?
        BNE .1skip		; On odd frames we skip ahead to possibly update the sprite positions.  
				; On even frames we update the timers that control how fast game objects
				; have their positions updated.

        ASL live0GFX     	; This timer cycles once every 16 frames.  8 pairs of even/odd frames.
        BCC .2skip   		; The pattern of values for this timer is:
        INC live0GFX  		; $01, $02, $04, $08, $10, $20, $40, $80, -> $01 ... 
.2skip

        ASL live1GFX     	; This timer cycles once every 10 frames.  5 pairs of even/odd frames.
        BCC .3skip   		; The pattern of values for this timer is:
        LDA #$08	    	; $08, $10, $20, $40, $80, -> $08 ... 
        STA live1GFX     
.3skip

        ASL live2GFX     	; This timer cycles once every 6 frames.  3 pairs of even/odd frames.
        BCC .1skip   		; The pattern of values for this timer is:
        LDA #$20    		; $20, $40, $80, -> $02 ...
        STA live2GFX
     
.1skip
        LDX #$00    		; Again we check is this is an even or odd frame.
        LDA flickerOffset     
        BNE oddFrame   
        BIT gameStateFlags1     ; Check if we are in a Zoomed Room or a Big Room.
        BVS evenFrame   	; For Big Rooms X must be 6 for both odd and even frames and never 0.

playerDiedSkip			
        JMP FinishOverscan   	; Since the player died we do not need to update sprite positions this frame.
;- - - - - - - - - - - - - - - 
	SUBROUTINE
evenFrame			; For even frames, X is initialized to 6 (ball) going into the loop.  For odd frames X is 0.
        LDX #$06    		; If the player is in a large room then X is set to 6 (ball) for both odd and even frames.
oddFrame

nextSprite
        STX tempVar3 		; Save the loop/object index in TempVar3.    
        LDA #$00    
        STA resetShotFlag	; = 0 Clear the flag, if the shot touches something we will set this flag to remember to 
				;     reset it back to the player ready to be fired again. 

        STA tempVar2     	; = 0 
        CPX #$06    		; If X = 6 (ball) or X = 7 (Large HM), then skip ahead.
        BCS .1skip   
        LDY currentRoom     	; Or if the currentRoom is the Moving Wall room, then skip ahead.
        CPY #$03    
        BEQ .1skip   
        TXA         		; Otherwise, if the loop/object index is < 3, then we change tempVar2
        CMP #$03    		; from 0 to (loop/object index) - 3 = [-1|-2|-3].  If loop/object index is >=3
        BCC .2skip   		; then we set tempVar2 to loop/object index = [3|4|5]
        SBC #$03    
.2skip
        STA tempVar2     	
.1skip				; Here is a summary of the possible values of tempVar2 as a function of loop/object index in X
				; Index =		tempVar2 =
				;	0			 0 -> P0		
				; 	1			 1 -> P1 first instance in even frame.
				; 	2			 2 -> P1 second instance in even frame.
				;	3			 0 -> P0
				;	4			 1 -> P1 first instance in odd frame.
				; 	5			 2 -> P1 second instance in odd frame.
				;       6			 0 -> Ball
				;  	7 			 0 -> Large Hall Monster (HM)
				; This value is used later on to constrict the vertical movement of P1 sprites.


        LDA sprite0_Status,X    ; 
        STA tempVar1     	; Okay so the Status has been copied into tempVar1

        LDY flickerOffset     	; Is the frame odd or even?
        BEQ PFtestFinished   	; EVEN:  Skip ahead because the PF collision flags are only ready to be tested on odd frames.

        CMP #SPRITE_STATUS_DEAD    		
        BNE .notDead   

        ASL PFcollisionFlags    ; The sprite is dead so we don't care if it is touching the PF.  Just throw the flag away
        JMP .3skip   		; Jumping to .3skip below is okay because we know that the dead sprite can not be the player.



.notDead
        AND #$07    		; Isolate the lower 3 bits of the living sprites status.
        TAY         		; Y -> 0=immobile 1=veryslow 2=dead 3=slow 4=monstersL1; 5=monstersL2; 6=player|Large HM|L3; 7=L4
        LDX whichGFXTable,Y 	; Use that 3 bit status value to read an index of 0, 1, or 2 into X.
        LDA live0GFX,X 		; Load the GFX timer pointed at by X.  
        LDX tempVar3     	; Restore the sprite index into X.
        AND eventMaskTable,Y 	; A Logical AND of the GFX timer and the eventMask.
        BEQ .4skip   		; No update event for this sprite so skip ahead.

        CPX HMspriteNumber     	; Is this sprite the large HM?
        BNE .5skip   		; NO:	skip ahead.
				; YES:	fall through

        LDA #$02 		; I believe this is to restrict updates of the large hall monster to every other frame pair	
        BIT FrameCounter     	; because sometimes it is being swapped every other frame pair.  ???
        BNE .5skip   		

.4skip
        ASL PFcollisionFlags    ; No action this frame pair for this sprite, discard its PF collision flag.
        JMP objectDone   

.5skip
        CPX #$07    		; The large HM can pass through walls it has no PF collision flag to be checked, skip ahead.
        BEQ .3skip   

        ASL PFcollisionFlags	; Test the PF collision flag for the current sprite by moving it into Carry.     
        BCC .6skip   		; If it is clear, then no PF collision occured in the last frame pair for the sprite.

        LDA sprite0_Ypos,X   	; PF COLLISION! Make sure the sprite is not dead.
        CMP #SPRITE_NOT_VISIBLE   
        BEQ .3skip   		; YES: The sprite is dead, so skip ahead and ignore the PF collision.

        JSR bounceOffWall   	; No: the sprite is alive, jump to a subroutine to bounce off the wall.
        INC resetShotFlag     	; Record that a collision with a wall occurred, so the shot will be returned to the player.
        BNE PFtestFinished      ; This branch is always taken.
;- - - - - - - - 
.6skip
        CPX playerObjIndex     	; Are we updating the player's sprite? [could be optimized since playerObjIndex is always 0]
        BNE .3skip   		; NO: skip ahead to next case.
				; YES: We are updating the player sprite, fall through.

        LDA sprite0_Status,X   	
        AND #$07    		; Get the player's speed.
        STA sprite0_Status,X   	; Save only the speed discarding the previous direction value.
        LDA SWCHA   		; Read the player's joystick and save its value as the new direction.
        AND #$F0    
        ORA sprite0_Status,X    
        STA sprite0_Status,X   	; In the player's status byte.
        STA tempVar1     	; Overwrite, the copy of the old status in tempVar1 with the new status.
        BNE PFtestFinished   	; This branch is always taken.

;- - - - - - - - - 
.3skip				; The object is not the player, and did not hit a wall...
        LDA sprite0_Timer,X     ; Is the timer for this object expired?
        BEQ PFtestFinished   	; Yes: it expired on an earlier frame, so skip ahead.
				; NO:  Is the timer actively counting down?
        BMI .timerExpired   	;      NO: bit7 being set means the timer function is disabled for this object.	
        DEC sprite0_Timer,X   	;      YES: decrement the timer until the corpse will disappear.
				;           Is the timer expired now?
        BNE PFtestFinished   	;	    NO:  not yet, skip ahead.
				;           YES: fall through to take the action related to the timer expiring.

.timerExpired
        CPX #$06    		; Was it the Ball range timer that expired?
        BNE .8skip   		; NO: skip ahead
				; YES: Its the ball reaching its maximum range.
        INC resetShotFlag     	;      Set the flag to reset the shot to the player later on.
        BNE PFtestFinished   	; branch always taken.

.8skip
        LDA sprite0_Status,X   	; Is it dead?
        CMP #SPRITE_STATUS_DEAD    
        BNE .9skip   		; NO:  skip ahead the timer is active for some other reason than timing display of a corpse.

        LDA #SPRITE_NOT_VISIBLE	; YES: Make the sprite that is currently a corpse disappear.
        STA sprite0_Ypos,X   	 
        BNE PFtestFinished   	; Branch always taken.
;- - - - - - - - - - 
.9skip
        JSR changeDirection   	; If the sprite is not dead and its timer has expired, then it changes the direction it is 
        STA tempVar1 		; traveling in.
   
				; At this point we have determined what direction the object should move this frame.
				; So at PFtestFinished the position of the object is updated for the chosen direction.

PFtestFinished	SUBROUTINE	;
;
;tempVar1 contains the direction the object will travel in its upper nybble encoded as a joystick position.
;	Joystick values reference table:
;	--------------------------------
; 	%0111 = Right
; 	%1011 = Left
; 	%1101 = Down
; 	%1110 = UP
;
;tempVar3 contains the index (0-7) to the object being moved.
;
        ASL tempVar1 		; Test RIGHT direction bit.
        LDX tempVar3     
        BCS .1skip   		; RIGHT bit set, so no movement to the right

        LDA sprite0_Xpos,X   	; Get the current X-pos of the object in preparation to move right.
        CPX #$06    		; If the object being updated is the Ball, then we must subtract 4 from the horizontal
        BCC .2skip   		; position of the ball to compensate for the difference in horizontal size between  
        SBC #$04    		; a sprite and the ball
	
.2skip
        CMP #$9C    		; If the object is at the right hand side of the screen, then we will not move
        BNE .3skip   		; it any further to the right.
        INC resetShotFlag     	; If is assumed that only the ball could reach the edge of the play area, since sprites 
        BNE .4skip   		; are constrained by the room walls.   This branch is always taken.
.3skip
        INC sprite0_Xpos,X   	; Move the object to the right by 1 pixel.

.4skip
        ASL tempVar1     	; The player moved RIGHT, so the LEFT bit must be set.   We throw it away and skip ahead.
        BCS .5skip   		; Notice that bad things happen if the LEFT bit is actually clear!

;- - - - - - - - - 
.1skip
        ASL tempVar1     	; Test LEFT direction bit.
        BCS .5skip   		; The bit is set, so the object is not moving to the left, skip ahead.

        LDA sprite0_Xpos,X   	; Load the object's current horizontal position.
        CMP #$01    		; If it is 1, then the object is at the left edge of the screen, then we assume it is the
        BNE .6skip   		; shot, and we fall through to reset the shot to the player rather than skip ahead and...
        INC resetShotFlag     
        BNE .5skip   
.6skip
        DEC sprite0_Xpos,X   	; ...move the object to the left.
;- - - - - - - - - 
.5skip
        ASL tempVar1		; Test the DOWN direction bit.     
        BCS .7skip   		; The bit is set, so the object is not moving down, skip ahead.
        LDA #$4E    		; $4E is the bottom edge of the screen.
        CPX #$06    		; Are we updating the Ball?
        BEQ .8skip   		; YES: Jump to ball handling code.
				; NO:  We are processing a sprite, so we need to compensate for the height of the sprite
				;      moving downward to know if it reached the bottom of the screen.
        BIT gameStateFlags1     ;      Are we in a Big Room or a Zoomed Room?
        BVS .9skip   		;      V=1:  We are in a Zoomed Room skip ahead.
        LDA #$4F    		;      V=0:  In Big Rooms we extend the bottom of the screen by 1 scan line pair.
.9skip				;            I presume this is needed to allow enough room for the HM under the bottom wall.
				;            Why not just set A to $AE and be done with it?  {chance for optimization?}

				; RECALL: a summary of the possible values of tempVar2 as a function of loop/object index in X
				; Index =		tempVar2 =
				;	0			 0 -> P0		
				; 	1			 1 -> P1 first instance in even frame.
				; 	2			 2 -> P1 second instance in even frame.
				;	3			 0 -> P0
				;	4			 1 -> P1 first instance in odd frame.
				; 	5			 2 -> P1 second instance in odd frame.
				;       6			 0 -> Ball
				;  	7 			 0 -> Large Hall Monster (HM)

        LDY tempVar2     	; If the object is 7 (large HM), 0 (P0 even frame), or 3 (P0 odd frame).
        BEQ .10skip   		; YES: There is no restriction on the vertical movement of the ball, large HM, or P0 so we 
				;      skip ahead to avoid any vertical movement boundary test.
				; NO:  The object is either 1, 2, 4, or 5 and represented on the screen by P1.  Since
				;      P1 is used twice per frame, we must restrict the vertical movement of these 
				;      objects so that they do not overlap on the screen.
				;      Is this object the first or second instance of P1 in the frame?
        CPY #$01    		;      FIRST INSTANCE:  Fall through to find the restriction on vertical movement
        BNE .10skip   		;      SECOND INSTANCE:  Skip ahead because the downward movement restriction for the
				;                        second instance of P1 in any frame is the bottom of the screen.
        LDA P1repositionEven    ; For a FIRST INSTANCE P1 object set the bottom of its movement vertical movement range to
        SEC         		; the P1 reposition line minus 1.
        SBC #$01    

	
.10skip				; At this point A holds the lowest vertical position the object is permitted to go to.
        CLC         		; Since the object's position is measured from its upper left hand corner, we subtract
        ADC sprite0_Height,X   	; the height of the object from the lowest vertical position allowed.  
				; NOTE: The sprite Height values are negative so we add them to achieve subtraction.

.8skip				; NOTE: The Ball is free to travel vertically, and has a height of 1, so the above adjustments
				; for all other objects are skipped in the case of the ball.

        CMP sprite0_Ypos,X      ; Has the object reached the boundary in A
        BNE .11skip   		; NO: skip ahead.
        INC resetShotFlag     	; YES: Reset, the shot!  What if a sprite hits the boundary? Does the shot get reset? No, in fact
        BNE .done   		; a test below will ignore the reset flag if the ball is not the object being updated this time
				; through the loop.  Skip ahead since the object can not be traveling up if it is traveling down.

.11skip
        INC sprite0_Ypos,X   	; Move the object down 1 pixel.
        TXA         		; Multiply the index in X by 2 to index into the table of word sized graphics data pointers.
        ASL
        TAX         
        DEC sprite0_Shape,X   	; Decrement the object's shape pointer by 1 to adjust for the increase in the object's Y pos.
        JMP .done   		; Skip ahead since the object can not be traveling up if it is traveling down.
;- - - - - - - - 
.7skip
        ASL tempVar1     	; Test the UP direction bit.
        BCS .done   		; If the bit is set, then we are finished updating the current object's position.

        CPX #$06    		; Else, Move the object up.  Is this the ball?
        BNE .12skip   		; NO:	skip ahead.
        LDA #$00    		; YES:  So set the upper movement boundary at 0.
        BEQ .13skip   		; Branch always taken.

.12skip
        LDA #$FF    		; For all sprites the upper movement boundary is -1 = $FF. 
        LDY tempVar2     	; Unless its the second instance of P1 in the frame, which has a lower upper movement
        CPY #$02    		; boundary.
        BCC .13skip   		; 
        LDA P1repositionEven    ; Set the upper movement boundary to the P1 reposition + 1 for second instances of P1.
        ADC #$01    		
			
.13skip				; At this point, the Accumulator has the upper movement boundary for the object.
        CMP sprite0_Ypos,X   	; Compare the boundary to the Y position of the object.
        BNE .14skip   		; Skip ahead if the object can move up.
        INC resetShotFlag     	; Otherwise, set the shot reset flag in case this is the ball being updated.
        LDA sprite0_Status,X  	; Turn off the UP direction bit for this object. 
        ORA #$10    	
        STA sprite0_Status,X   
        BNE .done   		

.14skip
        DEC sprite0_Ypos,X   	; Move the object up 1.
        TXA         
        ASL
        TAX         
        INC sprite0_Shape,X   	; Also update the graphics pointer.

.done				; At the .done label the object position is updated, all that remains is to 
        LDX tempVar3     	; Check if the shot reset flag is set.  If it is, then check if we are updating 
        LDA resetShotFlag     	; the ball.  If we are, then reset the shot, otherwise jump ahead.
        BEQ .15skip   		

        CPX #$06    		; Ball?
        BMI .16skip   		; No - normal sprite, objects 0 through 5.
        BNE .15skip   		; No - large hall monster, object 7.
        BIT gameStateFlags1  	; YES: its the ball, but are we in a Big Room or a Zoomed Room?   
        BVC .15skip   		;      BIG ROOM: In a big room the player is the ball, so reseting the shot has no meaning.
				;                and we skip ahead.
        LDY #$80    		;      ZOOMED ROOM:  Reset the shot to the player.
        STY shotReadyFlag     
        STY ball_Status     

.15skip
        JMP objectDone   	; Object update complete, 

.16skip
        LDY #$01    		; If a sprite touches the outer edge of the playfield, then we set the timer to 
        STY sprite0_Timer,X   	; have it change directions next frame.  If we didn't it could become stuck. (I think)
        BNE .15skip   

;-------------------------------
; It appears that when the timer expires anytime the sprite is a live monster, this routine is called to
; change the direction of the monster.
;
; INPUTS:
; X = the object being updated (0-7)
; tempVar3 = X  (backup copy)
;
changeDirection	SUBROUTINE
        LDY #$01    
        CPX #$06    		; Is this the shot?
        BEQ .1skip   		; YES:  The shot can not change direction in mid-flight, so skip ahead.
				; NO:   Is is the large Hall Monster (object 7)?
        BMI .sprites0to5   	;       NO:  skip ahead
				;       YES: Its the timer for the Large Hall monster.	
        STY sprite7_Timer	; Reset the Large Hall monster timer to 1.     
        BPL .homeOnPlayer   		; Skip ahead to the Large Hall monster player tracking routine.

.sprites0to5
        LDA currentRoom     		
        CMP #$03    		; Is this the moving walls room?
        BNE .3skip	  	; NO:  skip to process the object as a item or monster
 				; YES: fall through to the code for updating the direction of the oscillating walls..

.movingwalls			; Update the direction of a moving wall.
        LDY #$18    		; Set the object timer to $18 for even numbered moving wall objects.
        TXA         
        ROR			; Object # even or odd?
        BCC .2skip   	
        LDY #$0E    		; Set the object timer to $0E for odd numbered moving wall objects.	
.2skip
        STY sprite0_Timer,X   
      
	JSR bounceOffWall  	; Invert the current direction of the moving wall object by 180 degrees. 

        ORA #$06		; Set the wall speed bits.     
        BNE .done
		
;- - - - - - - -    
.3skip			
        LDY randomNumPtr     
        LDA $F000,Y 		; Get a "random" value.
        EOR FrameCounter    	; Scramble it with the frame counter. 
        AND #$30    		
        ORA #$08    		; Produce a value of $08, $18, $28, $38 as the next object timer value.
        STA sprite0_Timer,X   	; Save the new timer value.  When the object timer reaches zero the object
				; will change direction again.

        LDA $F002,Y 		; Get a "random" value.
        EOR FrameCounter     	; Scramble it with the frame counter.
        INY         		; Increment the "random" number pointer so it points at a new number next time.
        STY randomNumPtr     	

        AND #$07    		; Based on the difficulty, there is a random chance the monster will home in on the player.
        CMP difficulty     
        BMI .homeOnPlayer   

        EOR $F003,Y 		; Scramble the bits again with a "random" number
        AND #$07    		; Reduce the random value to a random direction 0-7
        TAY         
        LDA sprite0_Status,X   
        AND #$0F    
        ORA monsterDirTable,Y 	; Combine the new random direction for the object with its existing speed.
        BNE .done 		; This branch is always taken.  

;- - - - - - - - -
.homeOnPlayer
        LDY sprite0_Xpos,X   	; Fetch the X-pos of the object homing on the player.
        LDA #$50    		; Initialize the new direction to $50 which is RIGHT & DOWN

        BIT gameStateFlags1    	; Are we in a Big Room or a Zoomed Room?  
        BVC .bigroom   		

        CPY sprite0_Xpos 	; Compare the X position of the object to the X position of the player sprite.    
        BVS .4skip   		; V=1 from BIT instruction above! So this branch is always taken! Nice trick.

.bigroom			; Compare the X position of the object to the X position of the player as the ball.
        CPY ballXpos     

.4skip				
        BCC .5skip   		; If the player is to the RIGHT of the object, then skip ahead. 
        BNE .6skip   		; Else, if they are equal, set the RIGHT bit.  If the player is left of the 
        ADC #$40    		; object, then set the RIGHT bit and clear the LEFT bit.
.6skip
        ADC #$40    		

.5skip				; The RIGHT and LEFT direction bits are set to home in on the player.
        LDY sprite0_Ypos,X   	; Now we perform a similar function for the UP and DOWN bits.
        BIT gameStateFlags1     
        BVC .7skip   		; big room or zoomed room?  V is still set from BIT test earlier!
        CPY sprite0_Ypos    	 	
        BVS .8skip
.7skip
        CPY ballYpos     
.8skip
        BMI .9skip   
        BNE .10skip   
        ADC #$10    
.10skip
        ADC #$10    
.9skip
        AND #$F0    		; Combine the new object direction with the current object speed.
        STA tempVar3     
        LDA sprite0_Status,X   
        AND #$0F    
        ORA tempVar3     
        STX tempVar3     

.done	
        STA sprite0_Status,X   	; Save the new direction and speed for the object.
.1skip
        RTS         

objectDone				; This is the bottom of the loop to test each object for collisions and for 
					; timer expirations to change direction or disappear if a corpse.		
        INX         			; Increment the object counter in X. 
        LDA flickerOffset     		; Is this an even frame?
        BEQ FinishOverscan   		; YES: then only the ball/shot is updated on an even frame, exit the loop.
        CPX #$08    			; NO:  its an odd frame when all 7 game objects are updated.  Are all 7 done?
        BEQ FinishOverscan   		;	YES: all seven are done, exit the loop.
        JMP nextSprite   		; 	NO: update the next object.

; -----------------------------------
; -- This is the powerup entry point.
; -----------------------------------
;
Start	SUBROUTINE
        SEI         
        CLD			; Clear interrupts & decimal flag
        LDX #$FF    
        TXS			; Init Stack
        INX   		
        JSR InitGame
        LDA #$80    
        STA gameStateFlags1	; = $80  -> the game play is paused. 
        ASL
        STA pauseTimer		; = $00	 -> until someone pushes reset.

FinishOverscan	SUBROUTINE
        DEC FrameCounter     
        BNE .2skip  
        DEC HallMonsterTimer     
        BNE .2skip  	 	; Until the large hall monster timer reaches zero we skip ahead.
        BIT gameStateFlags1     ; Test bit6 in gameStateFlags1 to see if we are in a BigRoom or a 
				; Zoomed Room. 
        BVC .2skip  	 	; V=0 means its a big room, so no large hall monster ever appears.
        BMI .2skip  	 	; N=1 means the gameplay is paused (temporarily).

        LDX #$03    	 	; determine which sprite the large hall monster is represented by
	LDA sprite4_Ypos	; for this room?	
        CMP #SPRITE_NOT_VISIBLE    
        BNE .3skip   
        LDX #$04    
.3skip
        STX HMspriteNumber	; Save the index to the large sprite monster and simultaneously 
				; clear bit 7 to indicate the monster is active.     

        LDA currentRoom  	; If this is the moving wall room then, we face a special case      
        CMP #$03    		; because the room has 7, not 6 sprites like all other rooms.
        BEQ .1skip  		; If this is the moving wall room, then skip over this step. 
        LDA #$07    
        ORA sprite0_Status,X    ; For any room except the Moving Wall room set the three lower
        STA sprite0_Status,X    ; bits of the sprite0_Status,X.  I am guessing the three set bits
                                ; mean "home in on player"?

.1skip
        LDA #$0C    		
        STA AUDV1   		; Set the volume for the large hall monster's roar!

        LDA #$20    			
        STA sprite7_Timer     	; Some large hall monster flag? Perhaps the timer after appearing
				; until it starts to move?  

.2skip
        LDX #$00    		
        STX flickerOffset      	; Default to draw sprites 0, 1, and 2.
        STX SpriteSwapFlag 	; We are activating the hall monster, but the sprites aren't swapped
                                ; yet so set flag to 0.				
        LDA FrameCounter     	; Check if Frame is even or odd.
        LSR
        BCC .4skip   		; Frame counter even, then skip ahead.

        LDX #$03    		   
        STX flickerOffset     	; else, frame counter odd then prepare to draw sprites 3, 4 and 5.	
        TAY         		; Y = FrameCounter / 2

        LDX HMspriteNumber     	
        BMI .4skip   		; If the large hall monster is off (HMSpriteNumber=$80),
                                ; then skip ahead.
        LDA #$08    
        STA AUDC1   
        LDA #$1F    
        STA AUDF1   		; Set the ROAR! sound effect values for voice channel 1.
        LDA sprite0_Ypos,X   
        CMP #SPRITE_NOT_VISIBLE    
        BEQ LF746   
        TYA         
        LSR
        BCS .4skip   
LF746
        JSR ItemHMDataSwap   	; For the moving walls room we swap the item and big Hall Monster
                                ; sprite data every 2 frames.
        INC SpriteSwapFlag     	; SpriteSwapFlag is set to 1 when the sprite is displaying the Hall
                                ; Monster, 0 for the treasure.

.4skip
        LDA #$02    		; Load A with 2 to set the vertical sync flag in a moment.

.OverScanWait
        LDX INTIM   		; Wait here for the overscan timer to expire and then fall through 
        BNE .OverScanWait       ; to VerticalSync.

VerticalSync	SUBROUTINE
	; A = 2, X = 0
        STX WSYNC   
        STA VSYNC   		; Begin vertical sync.
        STX PF1     		; Clear the playfield registers.  NOTE: PF0 is never used so it 
        STX PF2     		; doesn't need to be cleared.
        STX ENABL   		; Turn off the ball in case it was on during the last visible
                                ; scanline of the previous frame.
        STA WSYNC   		; Begin second line of vertical sync.
        STA CXCLR   		; Clear all collision registers.




        LDX #$08    	; This loop sets 4 pointers in RAM to the graphics to draw the first 4
        LDY #$01   	; digits of the score
			;spritePointer1      = $ED:$EE    ; Points to a sprite shape for 1st digit
			;spritePointer2      = $EF:$F0    ; Points to a sprite shape for 2nd digit
			;spritePointer3      = $F1:$F2    ; Points to a sprite shape for 3rd digit
			;spritePointer4      = $F3:$F4    ; Points to a sprite shape for 4th digit
.1loop			;        First Pass			Second Pass
        LDA $0100+score_1_2,Y 	; Y=1				; Y=0
        DEX         	; *** Since this loop only executes 2 times we could eliminate
        DEX         	; *** these DEX instructions, and load X=4 above, and X=0 at the 
        DEX         	; *** end of the loop and ave 2 bytes ROM.
        DEX         	;	; X=4				; X=0
        ROR			; 
        AND #$78    	;	; A=([$C8]>>1) & %01111000	; A=([$C7]>>1) & %01111000	 
        STA spritePointer1,X   	; third digit of score          ; first digit of score
        LDA $0100+score_1_2,Y 
        ASL
        ASL
        ASL
        AND #$78    		; A=([$C8]<<3) & %01111000	; A=([$C7]<<3) & %01111000
        STA spritePointer2,X    ; fourth digit of score		; second digit of score
        LDA #>charset    
        STA spritePointer1+1,X	; Set high bytes of 16-bit sprite pointers.   
        STA spritePointer2+1,X   
        DEY         
        BPL .1loop   

        STA WSYNC  		; Sync to end of 3rd line of vertical sync.
        STX VSYNC   		; Turn off vertical sync.  X=0 from the loop above.

VerticalBlank	SUBROUTINE
        STX pointsScored	; = 0 

        LDA #$32    
        STA TIM64T  		; Set timer for vertical blank period.
				; 50 * 64 = 3200 cycles
				; 3200 / 76 cycles per scanline = 42.1 lines
				; = 43 scanlines of vertical blank.

	; In this next part we check the player's fire buttton and if he can fire.
        LDA currentRoom		; If the current room is the Moving wall room, then skip ahead.     
        CMP #$03    		; because shooting is disabled in that room.
        BEQ .1skip   		

        BIT shotReadyFlag     	; If bit7 of shotReadyFlag is clear then the player's
        BPL .2skip   		; player's shot is in flight or we are in a big room,
				; so we skip ahead. 

        LDA INPT4   		; The player's shot is available to shoot and the gun is 
        BMI .1skip   		; enabled in the current room  so we test the fire button on the
				; player's joystick.  If the button is not pressed we skip ahead to
				; draw the bullet in the ready position.  If the 

        BIT gameStateFlags1     ; ??? Purpose of this test is unknown, it seems to me all
        BMI .2skip   		; possible cases for the player's shot have been covered ???
				; Possibly the lock on all movement while tones play as the player
				; enters a new room?

	
	; The player is shooting, initialize the shot's in-flight variables.
        STX shotReadyFlag 	; = 0    Clear bit7 of shotReadyFlag to indicate the player's
                                ;        shot is in flight.
        LDA LastPlayerDirection     		; ???
        ORA #$07    
        STA ball_Status     	; Set the shot direction to the player's last direction and set
				; the speed of the shot to #$07.

        LDA #PLAYER_SHOT_RANGE    
        STA ball_RangeTimer 	; Set the countdown for the shot's range of flight.
        LDA #$0F    
        STA sound1Active 	; =$0F ???  

.1skip	; Control comes to this point to draw the ball relative to the player orientation.
	; If we fell through from above, the ball will be fired in the latest direction 
	; pushed by the player, if the direction and fire button changed since the last
	; frame, then the shot goes in the new direction.

        LDA LastPlayerDirection     
        ROR
        ROR
        ROR
        ROR
        AND #$0F		; Move the 4 bits that hold the joystick current position
				; to the lower nybble of X to index the Joystick Table.		
        TAX         
        LDA ShotToPlayerPosTable,X 
        TAY         
        AND #$0F    		; lower nybble is ball Y relative to player's
        CLC         		; current facing.
        ADC sprite0_Ypos     
        STA ballYpos     	
        TYA         		
        ROR
        ROR
        ROR
        ROR
        AND #$0F    		; upper nybble is ball X relative to the player's
        CLC         		; current facing + 1 (see adjustment below)
        ADC sprite0_Xpos     
        STA ballXpos     
        DEC ballXpos     	; subtract an additional 1 from the ball X-pos so that when
				; the facing is left the ball is 1 pixel left of the player.

.2skip	; the ball is in flight or the player is the ball as in a big room.
	; So do nothing for now.

; Get ready to Draw the score digits and player life indicator.
        LDX #$00		; Turn off both sprite graphics to stop drawing them in case 
        STX GRP0    		; they were on for the last scanline of the previous frame.
        STX GRP1    
        STX activelyDrawP0     	; Set the current heights to zero because we are not
        STX activelyDrawP1 	; drawing game sprites at the start of a frame.
    
        LDA #$01    
        JSR PosObject   	; A = 1 = horizontal position, and X = 0 = P0
        LDX #$01    
        LDA #$09    		
        STA COLUP0  		; Set the color for the score digits.
        STA COLUP1  		; Set the color for the score digits.
        JSR PosObject   	; A = 9 = horizontal position, and X = 1 = P1

				;-----
        LDY P1repositionEven    ; Set P1ReposThisFrame based on whether the current frame is 
        LDX flickerOffset     	; odd or even. 
        BEQ .3skip   
        LDY P1repositionOdd     ; It seems strange that we waste two bytes of RAM to hold these
.3skip				; values since they are constants.  Maybe there was a plan at
        STY P1ReposThisFrame    ; one point to make them dynamic.   At any rate this is a good 
      				; place to save 2 bytes of RAM.

				;-----
	LDY #$00    		; NOTE: X is either 0 or 3.
        LDA sprite0_Ypos,X   
        BPL .4skip   		; If the sprites Y position is positive, then that sprite is no
        LDY sprite0_Height,X   	; no longer being displayed.  So height is set to zero.
.4skip
	STY activelyDrawP0     
        STA desiredYposP0    
				;-----
 
        LDA sprite0_Height,X   	; Copy the height for P0 into preload variable.
        STA preloadHeightP0     
        TXA         
        ASL			; Double the index in X to manipulate the word sized sprite pointer
        TAX         
        LDA sprite0_Shape,X   	; Make a copy of the sprite pointer to be used for P0 for this
        STA P0ShapeThisFrameLo  ; frame.  
        LDA sprite0_Shape+1,X   
        STA P0ShapeThisFrameHi	     

        LDX #$04    		; Set the horizontal position of the ball for this frame.
        LDY ballXpos     	
        INY         		; note that 1 is added to the balll position to adjust for the
        TYA         		; fact that horizontal positioning of balls and missles using
				; the same code as for positioning sprites will result in the 
				; ball and missles being 1 pixel to the left of sprites positioned
				; using the same value in A.
        JSR PosObject		; X = 4 = Ball.   A = ballXPos + 1   
        STA WSYNC   
        STA HMOVE   

        LDA roomOffset     	; Make a copy of the offset to the PF graphics for the currentRoom
        STA savePFindex     	; for the next frame.

        LDX livesCounter     
        LDA livesPFshape,X 
        STA tempVar2        	; Prepare shape of remaining lives

        LDA #$03    		; Set last minute sprite control register values to display the 
        STA NUSIZ0  		; score digits.  P0 and P1 set to 3 copies close.
        STA NUSIZ1  
        STA VDELP0  		; Turn on vertical delay for P0 and P1 so the 48-pixel sprite
        STA VDELP1  		; routine to draw the score will work.
				; NOTE:  I should investigate if VDEL needs to be used for 
				; this game since the last two digits of the score are
				; always zero.  

        LDX sound1Active	; A value of zero means the sound effect is off.  so skip ahead.
        BEQ .5skip   		
        LDA audioDataTable,X 
        STA AUDC0   		
        LSR
        LSR
        LSR
        LSR
        STA soundDuration     	; ?Its not clear why we are saving the upper nybble from the audio
				; data table in soundDuration

        STX soundUnknown1     	; Its even less clear why we are saving the index in soundUnknown1
        LDA #$00    
        STA sound1Active   	; Turn off current sound?  
        BEQ .1jump   		; Branch always!

.5skip
        LDX noteTimer1    	; If the noteTimer is zero, nothing happens.  Otherwise it is  
        BEQ WaitVBLANK   	; decremented.  If it decrements to zero, then fall through to
        DEC noteTimer1     	; take action.  Otherwise, skip ahead to change nothing.
        BNE WaitVBLANK
   
.1jump
        INC soundUnknown1 	; I am guessing the sound data is stored in pairs of bytes.    
        LDX soundUnknown1     	; more work is needed
        CPX #$29    
        BNE .6skip   
        DEC soundUnknown1     
        DEC soundUnknown1     

.6skip
        LDA audioDataTable,X 
        ASL
        STA AUDV0   
        BNE .7skip   
        STA soundDuration ; = 0     

.7skip
        LSR
        LSR
        LSR
        LSR
        STA AUDF0   
        LDA soundDuration     
        STA noteTimer1     

WaitVBLANK
        LDY INTIM   	; Waiting for the vbank timer to expire.
        BNE WaitVBLANK   

        STY WSYNC   
        STY VBLANK      ;[3]  Turn VBLANK off
        STA HMCLR       ;[6]  Clear all horizontal move registers.
        JMP Mainloop    ;[11] Begin darwing the visible screen.

; Positions an object horizontally
; Inputs:  A = Desired position.
;          X = Desired object to be positioned.
; scanlines:  If control comes on or before cycle 31 then 2 scanlines are consumed.
;	      If control comes after cycle 31 then 3 scanlines are consumed.
; Outputs: Y = $FF
; control is returned on cycle 6 of the next scanline.
PosObject	SUBROUTINE
        TAY         	;[00]+2 = 02 
        AND #$0F    	;[02]+2 = 04 
        STA tempVar2    ;[04]+3 = 07
        TYA         	;[07]+2 = 09
        LSR		;
        LSR
        LSR
        LSR		;[09]+8 = 17
        TAY         	;[17]+2 = 19
        CLC             ;[19]+2 = 21
        ADC tempVar2    ;[21]+3 = 24
        CMP #$10    	;[24]+2 = 26
        BCC .1skip	;[26]+2 = 28 longest path only
        SBC #$0F 	;[28]+2 = 30   
        INY         	;[30]+2 = 32
.1skip
        ASL
        ASL
        ASL
        ASL		;[32]+8 = 40
        EOR #$70    	;[40]+2 = 42
        STA WSYNC   	;[42]+3 = 45  -> 76 - 45 = 31 cycles.
        STA HMP0,X 	; Why is this store done twice? 
        STA HMP0,X  
        INY         
.1loop
        DEY         
        BPL .1loop   
        STA RESP0,X 
        STA WSYNC   
        RTS         
; ---------------------------------------------------
; X will contain either zero or $80 when InitGame is called.
; X=$00 will wipe the registers and RAM clean.
; x=$80 will erase only the contents of RAM leaving the registers untouched. 
InitGame	SUBROUTINE
        LDY #$00    
ClearRAM	
        STY $00,X
	INX     
        CPX #$FB    
        BNE ClearRAM        ; Clear RAM, leave last 4 byte intact to preserve any return addresses
                            ; on the stack.
        
        STY AUDV0           ; Silence!
        INY         
        STY difficulty      ; Assume difficulty
        STY CTRLPF          ; Reflect Playfield
        LDA #$80    
        STA live0GFX        ; Show live 1 GFX
        STA live1GFX        ; Show live 1 GFX
        STA live2GFX        ; Show live 1 GFX
        LDA #$03            ;
        STA livesCounter    ; Init live Counter = 3
        ASL                 ; 3 * 2 
        STA HMTimerSetup    ; = 6. 
        ADC #$F0            ;
        STA InitStatusforHM             ; InitStatusforHM -> $F6 ????
        LDA SWCHB           ; Check Difficulty
        BPL .1skip  
        INC InitStatusforHM             ; Increase InitStatusforHM ????
.1skip
        ROL
        ROL
        ROL
        AND #$03    
        STA difficulty      ; Get basic difficulty from switches
        STA currentLevel    ; Gameplay starts at level 0 through 3 depending on the difficulty switches.
        STA pointsForKill   ; The initial points for killing a monster is the difficulty+1 (*100)
        INC pointsForKill             
        CLC                 ;
        ADC #$F4            ;
        STA $E2             ; ???
        STA $E4             ; ???

LF8E8	
        LDA currentLevel    ; If we fell through from above currentLevel has the difficulty.
        AND #$01    	    ; If the player 2 difficulty switch is set to B, then start at room 9,
                            ; else start in room 8.
        CLC         	    ; 
        ADC #$08 	  
        STA currentRoom  
   
        LDA #$4C    	    ; In either case the player as the Ball begins the game in the same 
        STA ballYpos        ; starting location.
        LDA #$44    
        STA ballXpos     

InitRoom	SUBROUTINE ; Or is this initLevel, and InitRoom is really below?
; ??? Is this the entry point for screen transtions?  Sharing common code with the
; primary intialization?
	
        LDY currentRoom		; Since bit 6 will always be off from currentRoom we use its value 
        STY mirroredRoom	; to disable mirroredRoom by default, then test to see if
        LDA #$40    		; mirroredRoom should be enabled below.
        STA pauseTimer		; ?Set the relative position of the shot to the player?
        ASL ; A=$80
        STA HMspriteNumber     	; HMspriteNumber = $80 means the large hall monster is not active.
        LDA pfroomoffsets,Y 	; Get a copy of the offset to the current room graphics.
        STA roomOffset     
        CMP #$59    		; If the roomOffset is < $59 then the room is not a mirrored room. 
        BCC .2skip   
        LDA #$40    
        STA mirroredRoom     	; else, it is a mirrored room.
.2skip
        LDX #$00    
        STX $CD	; = 0     
        STX sprite7_Timer	; = 0     
        CPY #$08    		; Here we are testing if the currentRoom is 8 or 9 which are the  
        BCC .3skip		; special rooms with 6 small hall monsters.   In which case we jump 
        JMP InitBigRoom   	; to a separate routine to continue room init.

.3skip				; We are not dealing with room 8 or 9.  It is one of the zoomed-in
				; rooms 0 through 7.
        STX P1spritewidth     	; X is 0 so we are defaulting to single width sprites, not quad
                                ; which are used in the moving walls room (currentRoom=3).
        STX sprite0_Timer	; = 0     
        STX playerObjIndex	; = 0     
        STX $C1			; = 0     
        STX ball_Status		; = 0   The ball is not in flight, nor is it ready to be shot.  
        STX roomDoneFlag	; = 0   
        INX         
        STX sound1Active	; = 1
        STX spriteXposSwap	; = 1  	Starting position for large HM
        STX sprite7_Ypos	; = 1 	upper left hand corner.
        LDA #$F7    
        STA spriteHeightSwap	; = -9	default height of Large HM is 9.  
        LDA InitStatusforHM     
        STA sprite7_Status	; = $F6 if P0diff = novice, else = $F7    
        LDX HMTimerSetup     
        STX HallMonsterTimer    ; = 6 at game start, and -1 for each level completed down to a minimum of 3.
   
        CPX #$03    	        ; HMTimerSetup will never fall below 3, thus setting the minimum
	BEQ .4skip  		; time that the large HM will take to appear at maximum difficulty.
        DEC HMTimerSetup     		
.4skip

        LDA #$53    
        STA sprite7_Shape	; = $53     
        LDA #$80    
        STA shotReadyFlag	; = $80   Upon entering a zoomed room the player's shot is ready 
				;         to be fired.  
        LDA #$C0    
        STA gameStateFlags1	; = $C0     
        LDA #$F6		;    
        STA sprite0_Status	; = $F6 -> F means no current direction of travel.  6 is the speed from 0 (immobile) to 7 (fastest)     
        LDA #$06    
        STA AUDF1	; = 6   
        LDX #$00    
.2loop
        LDA MonsterColorTable,Y 
        STA sprite1_Color,X   
        LDA $E4     
        STA sprite1_Status,X   
        INX         
        TXA         
        STA sprite0_Timer,X   
        CPX #$04    
        BNE .2loop   

        LDA RepositionTable,Y 
        STA P1repositionEven     
        LDA #$50    		; This matters in the collision detection routines elsewhere!
        STA P1repositionOdd     
        LDA #$43		; Set the player's color for zoomed in rooms = Red.     
        STA sprite0_Color        
        LDX #$00    
        STX FrameCounter     
        LDA currentRoom		; Load Y with currentRoom * 4 to index the table of sprite positions.     
        ASL
        ASL
        TAY         
.3loop
        STX tempVar3     
        LDA ZoomSpriteXYTable,Y 
        AND #$F0    
        CLC         
        ROR
        STA tempVar1     
        ROR
        ROR
        SEC         
        ADC tempVar1     
        STA sprite1_Xpos,X   	; Multiply the X nybble by 10.
        LDA ZoomSpriteXYTable,Y 
        AND #$0F    
        STA tempVar2     
        ASL
        ASL
        ADC tempVar2     
        SEC         
        SBC #$02    
        STA sprite1_Ypos,X	; Multiply the Y nybble by 5 and subtract 2.   
        STA tempVar2     
        LDA #$F7		; Set the height of the monster and item sprites to 9.	    
        STA sprite1_Height,X   	; NOTE: Each sprite graphics data sequence ends with $00 which turns 				; the sprite display off so each graphic is visible for 8 lines.
        TXA         
        ASL			; X = X * 2
        TAX         		
        LDA #$FE    		; The next step is to set the graphics pointers for the Monsters
        STA sprite7_Shape+1   ; and Treasure.
        STA sprite1_Shape+1,X   ; Set the high byte of the 16-bit sprite graphics pointer to point
        LDA currentRoom         ;  at the graphics table.
        ASL			;  A = currentRoom * 2
        ASL			;  A = currentRoom * 4
        ASL			;  A = currentRoom * 8
        ADC currentRoom     	;  A = currentRoom * 9
        ASL			;  A = currentRoom * 18 which is 2 * standard sprite height of 9.
        SBC tempVar2     	;  The Y position of the sprite is subtracted from the pointer so 
        CLC                     ; that ,Y will index the shape correctly.
        ADC #<SpriteImagesTable ; = $5E ; Add offset to beginning of the graphics from the start of
                                ; the page of memory.
        STA sprite1_Shape,X   	; Set low byte of 16-bit graphics pointer.  
        INY         
        LDX tempVar3     	; Restore sprite counter in X from tempVar3
        INX         
        CPX #$04    		; loop until all three monster sprites and the treasure sprite are
        BNE .3loop              ; initialized.

        LDX #$02    		; If P1repositionEven has bit 7 set, then sprite 2 is item.  
        LDA P1repositionEven     
        BMI .5skip  
        LDX #$04    		; Else, sprite 3 is the item.
.5skip
        AND #$7F    
        STA P1repositionEven    ; Reset bit 7 of P1repositionEven.
        LDA sprite0_Shape,X   	
        CLC         
        ADC #$09    		; Add 9 to the index to the item graphics.  The loop above pointed
				; it at the monster graphics.
        STA sprite0_Shape,X   
        TXA         
        LSR
        TAX 			; X is now either 1 or 2...    
        LDY #$00    
        STY sprite0_Timer,X    
        LDY currentRoom     
        LDA ItemColorTable,Y 
        STA sprite0_Color,X   
        LDX currentRoom     
        CPX #$03    
        BNE NotMovingWalls   	; Test for Moving wall room.

InitMovingWallRoom		; currentRoom = 3.
        ; In the moving wall room there are 7 sprites instead of the normal 6.  The code (elsewhere)
        ; will deal with this by alternating the item with the large hall monster if needed. 

        LDA #$34    		
        STA P1repositionOdd	; Set the P1 reposition points are fixed for the Moving walls room.
	LDA #$07    
        STA P1spritewidth     	; Set flag to indicate P1 is QUAD width for the moving walls.

        INX         		; X = 4
        LDY #$00    		; Y = 0							
.4loop	; This loop throws away any monster/item sprite values initialized above and sets
	; them to the values needed to represent the 4 walls and the diamond in the middle.
        LDA InitMovingWallTable,Y	; For each sprite.
        STA sprite1_Color,X   		; Set the color
        LDA InitMovingWallTable+1,Y 
        STA sprite1_Timer,X   		; Set the Timer value.
        LDA InitMovingWallTable+2,Y 
        STA sprite1_Xpos,X   		; Set the EXACT x-coordinate, not compressed like other zoomed rooms.
        LDA InitMovingWallTable+3,Y 
        STA sprite1_Ypos,X   		; Set the EXACT y-coordinate, not compressed like other zoomed rooms.
        LDA InitMovingWallTable+4,Y 
        STA sprite1_Height,X   		; Set the sprite height as a negative Y
        LDA InitMovingWallTable+5,Y 
        STA sprite1_Status,X   	; Set the sprite speed and direction.
        TXA         
        ASL
        TAX         
        LDA InitMovingWallTable+6,Y 	; Set the sprite shape pointer lo-byte.
        STA sprite1_Shape,X   
        TXA         
        LSR
        TAX         
        TYA         
        CLC         
        ADC #$07    			; Add 7 to index in Y to point at next block of sprite
        TAY				; initialization values.         
        DEX         
        BPL .4loop 
        DEX         			; X = $FE
        STX AUDC1   			; $FE = Funky moving wall room sound? 
NotMovingWalls
        RTS         			; Zoomed-Room initialization is done.

InitBigRoom	SUBROUTINE		; Y=currentRoom
        LDA #$80    
        STA gameStateFlags1		; = $80	= Game running, but movement paused as we enter a new room.
        ASL
        STA AUDV1   			; = $00 = Silence!
        STA shotReadyFlag       	; = $00   In a big room a player can never shoot, so we clear the 
					;         flag indicating the player can shoot.
        STA P1spritewidth		; = $00	  There are no Quad width sprites in this big rooms.     
        TAX 				; X = 0
        LDA $E2     	
        STA ball_Status     		; Make a copy of the speed/difficulty?
        LDA RepositionTable,Y 		; Set the scanlines for even and odd frames where P1 is 
        STA P1repositionEven    	; repositioned.  Based on currentRoom indexing a table. 
        STA P1repositionOdd     
        LDA ItemColorTable,Y 		; For big rooms the ItemColorTable holds the wall color,
        STA COLUPF			; not the hall monster sprite color!

.1loop			; For each small hall monster do:
        LDA #$01    
        STA sprite0_Timer,X   		; =$01 ? 
        LDA $E2     		
        STA sprite0_Status,X   		; =$F4+difficulty?
        LDA MonsterColorTable,Y 
        STA sprite0_Color,X   		; = color table indexed by room number.
        STA spriteColorSwap     	; Set $B0 to the color of the large hall monster sprites? 
        LDA #$FB		 
        STA sprite0_Height,X    	; The small hall monsters are 5 lines tall.
        INX         		
        CPX #$06    
        BNE .1loop   

        STX playerObjIndex		; = 6 for big rooms to indicate the player is the ball.  

        LDX #$00    			; Prepare for the loop to set the sprite positions.
        LDA currentRoom     
        SEC         
        SBC #$08    
        ASL		
        STA tempVar3     
        ASL
        ADC tempVar3     
        TAY         			; Y = 0 for room 8, and Y=6 for room 9.

.2loop
        LDA BigRoomSpritePosTable,Y 
        AND #$F0    
        CLC         
        ROR
        STA tempVar3     
        ROR
        ROR
        SEC         
        ADC tempVar3     
        STA sprite0_Xpos,X   		; X-Coordinate = (hi nybble * 10) + 1
        LDA BigRoomSpritePosTable,Y 	
        AND #$0F    
        STA tempVar3     
        ASL
        ASL
        ADC tempVar3     
        STA sprite0_Ypos,X   		; Y-Coordinate = (lo nybble * 5)
        STA tempVar3     		; Save a copy of Y-Coordinate to calculate the sprite
					; graphics pointer adjusted for Y position.
        STX tempVar1     		; Save copy of X
        TXA         
        ASL
        TAX         
        LDA #<(HallMonsterGraphics-1) 	; $4F    
        SEC         
        SBC tempVar3     
        STA sprite0_Shape,X   		; Set the graphics pointer lo-byte
        LDA #$FE    
        STA sprite0_Shape+1,X   	; Set the graphics pointer hi-byte
        LDX tempVar1     		; Restore sprite#/loop-counter in X.
        INY         
        INX         
        CPX #$06    
        BNE .2loop   
        RTS

playerCollisionTest	SUBROUTINE			
	; This routine tests for a collision between the player sprite (sprite 0) and the number 
	; sprite stored in X ( 4, 5, or 7).   6 is not used because an object index of 6 points to
	; the ball.  Comparisons against sprite 1 and 2 are possible, but not needed because they are 
	; detected using the hardware collision detection.
        LDA sprite0_Height,X   
        CLC         
        ADC #$01    
        CLC         
        ADC sprite0_Ypos     
        CMP sprite0_Ypos,X   
        BPL .noContact   
        LDA sprite0_Ypos     
        CLC         
        ADC #$05    
        CMP sprite0_Ypos,X   
        BMI .noContact   
        LDA #$00    
        STA tempVar3     
        LDA #$08    
        STA tempVar1     
        LDA currentRoom     
        CMP #$03    
        BNE LFAEA   
        CPX #$03    
        BEQ LFAEA   
        CPX #$07    
        BEQ LFAEA   
        TXA         
        LSR
        BCC LFAE4   
        LDA #$F9    
        STA tempVar3     
        LDA #$0E    
        STA tempVar1     
        BNE LFAEA   
LFAE4
        INC tempVar3     
        LDA #$06    
        STA tempVar1     
LFAEA
        LDA sprite0_Xpos     
        CLC         
        ADC tempVar3     
        SEC         
        SBC sprite0_Xpos,X   
        BCS LFAF8   
        EOR #$FF    
        ADC #$01    
LFAF8
        CMP tempVar1     
        BCS .noContact   
        SEC      		; C=1, means a collision has occurred.   
        RTS         

.noContact
        CLC         		; C=0, means no collision.
        RTS        
 
;------------------
ItemHMDataSwap	SUBROUTINE
	; This routine is used exclusively in the moving walls room.  Since the moving walls room
	; has 7 sprites and not 6 like all other rooms, it is necessary for the large hall monster
	; and the treasure to timeshare display in the kernal.   When the large hall monster
	; is active in the moving wall room, this rountine is called every other odd frame to
	; exchange the treasure sprite data with the large hall monster data.
        LDY sprite0_Xpos,X   
        LDA spriteXposSwap     
        STY spriteXposSwap     
        STA sprite0_Xpos,X   
        LDY sprite0_Ypos,X   
        LDA sprite7_Ypos     
        STY sprite7_Ypos      
        STA sprite0_Ypos,X   
        LDY sprite0_Color,X   
        LDA spriteColorSwap     
        STY spriteColorSwap     
        STA sprite0_Color,X   
        TXA         
        ASL
        TAX         
        LDY sprite0_Shape,X   
        LDA sprite7_Shape     
        STY sprite7_Shape     
        STA sprite0_Shape,X   
        RTS         

;----------------------
shotCollisionTest	SUBROUTINE		; Check if player shot hits monsters.
        LDA ballYpos     
        CLC         
        SBC sprite0_Ypos,X   
        BMI LFB6C   
        STA tempVar3     
        ADC #$F7    
        BPL LFB6C   
        LDA ballXpos     
        SEC         
        ADC #$00    
        SBC sprite0_Xpos,X   
        BCC LFB6C   
        CMP #$08    
        BCS LFB6C   
        TAY         
        LDA ballToPixelMaskTable,Y 
        STA tempVar1     
        LDY sprite0_Ypos,X   
        TXA         
        STX tempVar2     
        ASL
        TAX         
        TYA         
        SEC         
        ADC sprite0_Shape,X   
        STA P0ShapeThisFrameLo     
        LDA sprite0_Shape+1,X   
        STA P0ShapeThisFrameHi     
        LDX tempVar2     
        LDY tempVar3     
        LDA #$01    
        STA tempVar3     
LFB5D
        LDA (P0ShapeThisFrameLo),Y 
        AND tempVar1     
        BNE LFB6A   
        INY         
        DEC tempVar3     
        BPL LFB5D   
        BMI LFB6C   
LFB6A
        SEC         
        RTS         

LFB6C
        CLC         
        RTS         

;----------------------
; This routine is called whenever it is determined that a sprite (player or monster) has run into a wall.
; X holds the index (0-5) of the sprite that hit a wall.
; tempVar1 = sprite0_Status,X
;
; This routine reverses the direction stored in the upper nybble of the sprite's status byte.  The updated
; value is written back into tempVar1, and not into sprite0_Status,X.  The 3 lowest order bits representing
; the speed of the sprite are not affected.
;
bounceOffWall	SUBROUTINE
        LDA tempVar1     
        TAY         
        ASL
        AND #$A0    
        STA tempVar1     
        TYA         
        ROR
        AND #$50    

ShotToPlayerPosTable	; Shot relative to player table ???
	; RAW JOYSTICK VALUES!!!!!
	; lower nybble is relative X, upper nybble is relative Y.
	; Note that the first 5 locations of this table are code and not data since the
	; values 0 to 4 represent impossible values for a working Joystick to produce.

        ORA tempVar1     
        STA tempVar1     
        RTS         

;Joystick values reference table
; %0000 = n/a
; %0001 = n/a
; %0010 = n/a
; %0011 = n/a
; %0100 = n/a
; %0101 = Right and Down
; %0110 = Right and Up
; %0111 = Right
; %1000 = n/a
; %1001 = Left and Down
; %1010 = Left and Up
; %1011 = Left
; %1100 = n/a
; %1101 = Down
; %1110 = UP
; %1111 = Centered
     
	;      X-offset of shot from player + 1
	;      ^Y-offset of shot from player 
	;      |^	  
	.byte $85 ; Right and Down
	.byte $81 ; Right and Up
	.byte $93 ; Right
	.byte $00 ; n/a - byte is theorectically available.
	.byte $15 ; Left and Down 
	.byte $11 ; Left and Up
	.byte $03 ; Left
	.byte $00 ; n/a
	.byte $47 ; Down

audioDataTable	; Audio values.	There is a single byte of overlap from this table and the 1
		; above it.  This is because the index value of zero will never be used to index
		; the audioDataTable since an index of zero = sound off in the game logic.
	.byte $40 ; Up

		; DATA FORMAT:
		;	- The lower nybble of each byte in the table is the AUDCx value.
		;       - The upper nybble is the ??? 

	.byte $AE ; |X X XXX |
	.byte $24 ; |  X  X  |
	.byte $1C ; |   XXX  |
	.byte $14 ; |   X X  |
	.byte $0C ; |    XX  |
	.byte $04 ; |     X  |
	.byte $00 ; |        |
	.byte $AE ; |X X XXX |
	.byte $04 ; |     X  |
	.byte $0C ; |    XX  |
	.byte $14 ; |   X X  |
	.byte $1C ; |   XXX  |
	.byte $24 ; |  X  X  |
	.byte $00 ; |        | 
	.byte $3f ; |  xxxxxx|

	.byte $07 ; |     XXX|
	.byte $0E ; |    XXX |
	.byte $15 ; |   X X X|
	.byte $1C ; |   XXX  |
	.byte $23 ; |  X   XX|
	.byte $2A ; |  X X X |
	.byte $31 ; |  XX   X|
	.byte $39 ; |  XXX  X|
	.byte $00 ; |        |
	.byte $C8 ; |XX  X   |
	.byte $34 ; |  XX X  |
	.byte $2C ; |  X XX  |
	.byte $24 ; |  X  X  |
	.byte $1C ; |   XXX  |
	.byte $14 ; |   X X  |
	.byte $00 ; |        |
	.byte $68 ; | XX X   |
	.byte $14 ; |   X X  |
	.byte $1C ; |   XXX  |
	.byte $24 ; |  X  X  |
	.byte $2C ; |  X XX  |
	.byte $34 ; |  XX X  |
	.byte $00 ; |        |
	.byte $FA ; |XXXXX X |
	.byte $F9 ; |XXXXX  X|
	.byte $E1 ; |XXX    X|
	.byte $84 ; |X    X  |
	.byte $C4 ; |XX   X  |
	.byte $B4 ; |X XX X  |
	.byte $A4 ; |X X  X  |
	.byte $00 ; |        |

monsterDirTable
; This table translates a random direction encoded as 0-7 into a Joystick encoded direction value.
; The direction each object is traveling in the game is encoded as if a phantom joystick is controlling
; the direction the object goes.  This allows reuse of the code to move the player sprite to also move
; all the other game objects.
	.byte $50 ; | X X    | RIGHT & DOWN 	
	.byte $90 ; |X  X    | LEFT & DOWN
	.byte $D0 ; |XX X    | DOWN
	.byte $70 ; | XXX    | RIGHT
	.byte $B0 ; |X XX    | LEFT
	.byte $60 ; | XX     | RIGHT & UP
	.byte $A0 ; |X X     | LEFT & UP
	.byte $E0 ; |XXX     | UP

ItemColorTable
	.byte $74 ; | XXX X  | The color of the item or treasure in each room indexed by currentRoom. 
	.byte $14 ; |   X X  |
	.byte $53 ; | X X  XX|
	.byte $05 ; |     X X|
	.byte $05 ; |     X X|
	.byte $14 ; |   X X  |
	.byte $54 ; | X X X  |
	.byte $C4 ; |XX   X  |
	.byte $55 ; | X X X X| There is no item in a big room, so this is the Pink wall color for
                  ;            the first big room.
	.byte $94 ; |X  X X  | This is the blue wall color of the second big room.

MonsterColorTable
	.byte $05 ; |     X X|  Monster color indexed by room number.
	.byte $74 ; | XXX X  |
	.byte $D4 ; |XX X X  |
	.byte $43 ; | X    XX|
	.byte $45 ; | X   X X|
	.byte $05 ; |     X X|
	.byte $14 ; |   X X  |
	.byte $35 ; |  XX X X|
	.byte $D4 ; |XX X X  |
	.byte $34 ; |  XX X  |

ZoomSpriteXYTable
; This table holds the starting positions in X and Y coordinates for the 3 monsters and the room.
; item sprite in each zoomed.  Each room occupies a 4 byte block of the table.  Each byte contains
; an (X-coordinate/10) in the upper nybble and a (Y-coordinate)/5 in the lower nybble.
; The (0,0) coordinate appears to be the upper left hand corner.

; Room 0
	.byte $C7 ; |XX   XXX|  Monster 1 (X,Y)
	.byte $3E ; |  XXXXX |  Item (X,Y)
	.byte $91 ; |X  X   X|	Monster 2 (X,Y)
	.byte $6D ; | XX XX X|	Monster 3 (X,Y)
; Room 1
	.byte $5B ; | X XX XX|	Monster 1 (X,Y)
	.byte $3E ; |  XXXXX |	Item (X,Y)
	.byte $35 ; |  XX X X|	Monster 2 (X,Y)
	.byte $AD ; |X X XX X|	Monster 3 (X,Y)
; Room 2
	.byte $72 ; | XXX  X |	Monster 1 (X,Y)
	.byte $CE ; |XX  XXX |	Item (X,Y)
	.byte $B9 ; |X XXX  X|	Monster 2 (X,Y)
	.byte $CC ; |XX  XX  |	Monster 3 (X,Y)

; Room 3 - This part of the table is not used. Room 3 is the moving wall room which is special because
; it has 7 sprites.  Refer to InitMovingWallTable below.
livesPFshape
        .byte $00 ; |        | $FBDF
        .byte $01 ; |       X| $FBE0
        .byte $05 ; |     X X| $FBE1
        .byte $15 ; |   X X X| $FBE2

; Room 4 
        .byte $76 ; | XXX XX |	Monster 1 (X,Y)
        .byte $8E ; |X   XXX |	Item (X,Y)
        .byte $B1 ; |X XX   X|	Monster 2 (X,Y)
        .byte $41 ; | X     X|	Monster 3 (X,Y)
; Room 5 
        .byte $C1 ; |XX     X|	Monster 1 (X,Y)
        .byte $98 ; |X  XX   |	Item (X,Y)
        .byte $71 ; | XXX   X|	Monster 2 (X,Y)
        .byte $C3 ; |XX    XX|	Monster 3 (X,Y)
; Room 6
        .byte $71 ; | XXX   X|	Monster 1 (X,Y)
        .byte $68 ; | XX X   |	Item (X,Y)
        .byte $A9 ; |X X X  X|	Monster 2 (X,Y)
        .byte $74 ; | XXX X  |	Monster 3 (X,Y)
; Room 7
        .byte $84 ; |X    X  |	Monster 1 (X,Y)
        .byte $78 ; | XXXX   |	Item (X,Y)
        .byte $46 ; | X   XX |	Monster 2 (X,Y)
        .byte $B6 ; |X XX XX |	Monster 3 (X,Y)
;-- Note that sprite positions for the big rooms (8 and 9) are stored in another table.

; This large table contains the sprite initialization values for the moving walls room.
InitMovingWallTable
	; Bottom Moving Wall Data - Sprite 6
        .byte $34 ; |  XX X  |	; Sprite color
        .byte $0E ; |    XXX |	; Timer Value (suspect movement related) Rebound?
        .byte $46 ; | X   XX |	; Sprite X Position
        .byte $37 ; |  XX XXX|	; Sprite Y Position
        .byte $FB ; |XXXXX XX|	; Sprite Height as a negative number.
        .byte $D5 ; |XX X X X|	; Direction & speed? upper nyyble = direction;  lower nybble = speed.
        .byte $5C ; | X XXX  |	; Sprite shape pointer lower nybble with precalculated Y offset included.
	; Right Moving Wall Data - Sprite 5
        .byte $34 ; |  XX X  |
        .byte $18 ; |   XX   |	Only seems to effect movement if sixth data value is non-zero...
        .byte $60 ; | XX     |
        .byte $21 ; |  X    X|
        .byte $F3 ; |XXXX  XX|
        .byte $75 ; | XXX X X|
        .byte $77 ; | XXX XXX|
	; Treasure Data	- Sprite 4
        .byte $05 ; |     X X|
        .byte $00 ; |        |
	.byte $4E ; | X  XXX |
	.byte $26 ; |  X  XX |
	.byte $F7 ; |XXXX XXX|	
	.byte $00 ; |        | ; $B5 was left to right oscillation.  $E5 is up down oscillation.
	.byte $C7 ; |XX   XXX|
	; Left Moving Wall Data - Sprite 3 
	.byte $34 ; |  XX X  |
	.byte $18 ; |   XX   |
	.byte $3C ; |  XXXX  |
	.byte $21 ; |  X    X|
	.byte $F3 ; |XXXX  XX|
	.byte $B5 ; |X XX X X|
	.byte $77 ; | XXX XXX|
	; Top Moving Wall Data sprite 2
	.byte $34 ; |  XX X  |
	.byte $0E ; |    XXX |
	.byte $46 ; | X   XX |
	.byte $13 ; |   X  XX|
	.byte $FB ; |XXXXX XX|
	.byte $E5 ; |XXX  X X|
	.byte $80 ; |X       |

pf2shapesleft
;ROOM 0: (offset $00)
       .byte $FF ; |XXXXXXXX| $FC16
       .byte $00 ; |        | $FC17
       .byte $00 ; |        | $FC18
       .byte $00 ; |        | $FC19
       .byte $F7 ; |XXXX XXX| $FC1A
       .byte $00 ; |        | $FC1B
       .byte $FF ; |XXXXXXXX| $FC1C
       .byte $00 ; |        | $FC1D
       .byte $00 ; |        | $FC1E
       .byte $FF ; |XXXXXXXX| $FC1F
;ROOM 1: (offset $0A)
       .byte $FB ; |XXXXX XX| $FC20
       .byte $00 ; |        | $FC21
       .byte $F8 ; |XXXXX   | $FC22
       .byte $08 ; |    X   | $FC23
       .byte $F8 ; |XXXXX   | $FC24
       .byte $00 ; |        | $FC25
       .byte $00 ; |        | $FC26
       .byte $00 ; |        | $FC27
       .byte $FF ; |XXXXXXXX| $FC28
;ROOM 2: (offset $13)
       .byte $FF ; |XXXXXXXX| $FC29
       .byte $00 ; |        | $FC2A
       .byte $00 ; |        | $FC2B
       .byte $00 ; |        | $FC2C
       .byte $00 ; |        | $FC2D
       .byte $FF ; |XXXXXXXX| $FC2E
       .byte $00 ; |        | $FC2F
       .byte $00 ; |        | $FC30
;ROOM 8: (offset $1B)
       .byte $00 ; |        | $FC31
       .byte $70 ; | XXX    | $FC32
       .byte $71 ; | XXX   X| $FC33
       .byte $71 ; | XXX   X| $FC34
       .byte $71 ; | XXX   X| $FC35
       .byte $71 ; | XXX   X| $FC36
       .byte $70 ; | XXX    | $FC37
       .byte $71 ; | XXX   X| $FC38
       .byte $71 ; | XXX   X| $FC39
       .byte $01 ; |       X| $FC3A
       .byte $E1 ; |XXX    X| $FC3B
       .byte $E0 ; |XXX     | $FC3C
       .byte $00 ; |        | $FC3D
       .byte $07 ; |     XXX| $FC3E
       .byte $04 ; |     X  | $FC3F
       .byte $04 ; |     X  | $FC40
       .byte $87 ; |X    XXX| $FC41
       .byte $80 ; |X       | $FC42
       .byte $80 ; |X       | $FC43
       .byte $80 ; |X       | $FC44
       .byte $8F ; |X   XXXX| $FC45
       .byte $88 ; |X   X   | $FC46
       .byte $88 ; |X   X   | $FC47
       .byte $80 ; |X       | $FC48
       .byte $88 ; |X   X   | $FC49
       .byte $8F ; |X   XXXX| $FC4A
       .byte $00 ; |        | $FC4B
       .byte $00 ; |        | $FC4C
; ROOM 9: (offset $37)
       .byte $00 ; |        | $FC4D
       .byte $0F ; |    XXXX| $FC4E
       .byte $09 ; |    X  X| $FC4F
       .byte $01 ; |       X| $FC50
       .byte $09 ; |    X  X| $FC51
       .byte $0D ; |    XX X| $FC52
       .byte $05 ; |     X X| $FC53
       .byte $04 ; |     X  | $FC54
       .byte $07 ; |     XXX| $FC55
       .byte $C1 ; |XX     X| $FC56
       .byte $41 ; | X     X| $FC57
       .byte $40 ; | X      | $FC58
       .byte $70 ; | XXX    | $FC59
       .byte $10 ; |   X    | $FC5A
       .byte $10 ; |   X    | $FC5B
       .byte $1C ; |   XXX  | $FC5C
       .byte $04 ; |     X  | $FC5D
       .byte $04 ; |     X  | $FC5E
       .byte $FC ; |XXXXXX  | $FC5F
       .byte $00 ; |        | $FC60
       .byte $E0 ; |XXX     | $FC61
       .byte $20 ; |  X     | $FC62
       .byte $3C ; |  XXXX  | $FC63
       .byte $07 ; |     XXX| $FC64
       .byte $00 ; |        | $FC65
       .byte $00 ; |        | $FC66
       .byte $00 ; |        | $FC67
       .byte $00 ; |        | $FC68
       .byte $00 ; |        | $FC69
       .byte $07 ; |     XXX| $FC6A
       .byte $3C ; |  XXXX  | $FC6B
       .byte $20 ; |  X     | $FC6C
       .byte $E0 ; |XXX     | $FC6D
       .byte $00 ; |        | $FC6E
; ROOM 3: (offset $59)
       .byte $FF ; |XXXXXXXX| $FC6F
       .byte $00 ; |        | $FC70
       .byte $06 ; |     XX | $FC71
       .byte $07 ; |     XXX| $FC72
       .byte $E0 ; |XXX     | $FC73
       .byte $00 ; |        | $FC74
       .byte $00 ; |        | $FC75
       .byte $00 ; |        | $FC76
       .byte $E0 ; |XXX     | $FC77
       .byte $07 ; |     XXX| $FC78
       .byte $06 ; |     XX | $FC79
       .byte $00 ; |        | $FC7A
       .byte $FF ; |XXXXXXXX| $FC7B
; ROOM 4: (offset $66)
       .byte $03 ; |      XX| $FC7C
       .byte $02 ; |      X | $FC7D
       .byte $02 ; |      X | $FC7E
       .byte $02 ; |      X | $FC7F
       .byte $FE ; |XXXXXXX | $FC80
       .byte $00 ; |        | $FC81
       .byte $00 ; |        | $FC82
       .byte $00 ; |        | $FC83
       .byte $07 ; |     XXX| $FC84
       .byte $04 ; |     X  | $FC85
       .byte $FC ; |XXXXXX  | $FC86
; ROOM 5: (offset $71)
       .byte $FF ; |XXXXXXXX| $FC87
       .byte $00 ; |        | $FC88
       .byte $FF ; |XXXXXXXX| $FC89
       .byte $C0 ; |XX      | $FC8A
       .byte $C3 ; |XX    XX| $FC8B
       .byte $C2 ; |XX    X | $FC8C
       .byte $02 ; |      X | $FC8D
       .byte $7E ; | XXXXXX | $FC8E
; ROOM 6: (offset $79)
       .byte $F0 ; |XXXX    | $FC8F
       .byte $10 ; |   X    | $FC90
       .byte $1F ; |   XXXXX| $FC91
       .byte $00 ; |        | $FC92
       .byte $00 ; |        | $FC93
       .byte $00 ; |        | $FC94
       .byte $7F ; | XXXXXXX| $FC95
; ROOM 7: (offset $80)
       .byte $F0 ; |XXXX    | $FC96
       .byte $10 ; |   X    | $FC97
       .byte $1F ; |   XXXXX| $FC98
       .byte $01 ; |       X| $FC99
       .byte $01 ; |       X| $FC9A
       .byte $00 ; |        | $FC9B
       .byte $00 ; |        | $FC9C
       .byte $00 ; |        | $FC9D
       .byte $00 ; |        | $FC9E
       .byte $00 ; |        | $FC9F
       .byte $00 ; |        | $FCA0
       .byte $00 ; |        | $FCA1
       .byte $01 ; |       X| $FCA2
       .byte $01 ; |       X| $FCA3
       .byte $1F ; |   XXXXX| $FCA4
       .byte $10 ; |   X    | $FCA5
       .byte $F0 ; |XXXX    | $FCA6

pf2shapesright
; ROOM 0: (offset $00)
       .byte $FF ; |XXXXXXXX| $FCA7
       .byte $00 ; |        | $FCA8
       .byte $00 ; |        | $FCA9
       .byte $00 ; |        | $FCAA
       .byte $FE ; |XXXXXXX | $FCAB
       .byte $02 ; |      X | $FCAC
       .byte $FE ; |XXXXXXX | $FCAD
       .byte $00 ; |        | $FCAE
       .byte $00 ; |        | $FCAF
       .byte $FF ; |XXXXXXXX| $FCB0
; ROOM 1: (offset $0A)
       .byte $FF ; |XXXXXXXX| $FCB1
       .byte $00 ; |        | $FCB2
       .byte $FF ; |XXXXXXXX| $FCB3
       .byte $00 ; |        | $FCB4
       .byte $FF ; |XXXXXXXX| $FCB5
       .byte $00 ; |        | $FCB6
       .byte $00 ; |        | $FCB7
       .byte $00 ; |        | $FCB8
       .byte $FF ; |XXXXXXXX| $FCB9
; ROOM 2: (offset $13)
       .byte $FF ; |XXXXXXXX| $FCBA
       .byte $00 ; |        | $FCBB
       .byte $00 ; |        | $FCBC
       .byte $00 ; |        | $FCBD
       .byte $00 ; |        | $FCBE
       .byte $FE ; |XXXXXXX | $FCBF
       .byte $02 ; |      X | $FCC0
       .byte $03 ; |      XX| $FCC1
; ROOM 8: (offset $1B)
       .byte $00 ; |        | $FCC2
       .byte $3F ; |  XXXXXX| $FCC3
       .byte $20 ; |  X     | $FCC4
       .byte $20 ; |  X     | $FCC5
       .byte $00 ; |        | $FCC6
       .byte $20 ; |  X     | $FCC7
       .byte $20 ; |  X     | $FCC8
       .byte $20 ; |  X     | $FCC9
       .byte $3F ; |  XXXXXX| $FCCA
       .byte $00 ; |        | $FCCB
       .byte $FF ; |XXXXXXXX| $FCCC
       .byte $FF ; |XXXXXXXX| $FCCD
       .byte $00 ; |        | $FCCE
       .byte $00 ; |        | $FCCF
       .byte $07 ; |     XXX| $FCD0
       .byte $04 ; |     X  | $FCD1
       .byte $84 ; |X    X  | $FCD2
       .byte $84 ; |X    X  | $FCD3
       .byte $86 ; |X    XX | $FCD4
       .byte $80 ; |X       | $FCD5
       .byte $80 ; |X       | $FCD6
       .byte $9F ; |X  XXXXX| $FCD7
       .byte $90 ; |X  X    | $FCD8
       .byte $90 ; |X  X    | $FCD9
       .byte $90 ; |X  X    | $FCDA
       .byte $90 ; |X  X    | $FCDB
       .byte $1F ; |   XXXXX| $FCDC
       .byte $00 ; |        | $FCDD
; ROOM 9: (offset $37)
       .byte $00 ; |        | $FCDE
       .byte $7F ; | XXXXXXX| $FCDF
       .byte $40 ; | X      | $FCE0
       .byte $40 ; | X      | $FCE1
       .byte $40 ; | X      | $FCE2
       .byte $7E ; | XXXXXX | $FCE3
       .byte $02 ; |      X | $FCE4
       .byte $02 ; |      X | $FCE5
       .byte $02 ; |      X | $FCE6
       .byte $C2 ; |XX    X | $FCE7
       .byte $42 ; | X    X | $FCE8
       .byte $43 ; | X    XX| $FCE9
       .byte $70 ; | XXX    | $FCEA
       .byte $10 ; |   X    | $FCEB
       .byte $10 ; |   X    | $FCEC
       .byte $1C ; |   XXX  | $FCED
       .byte $04 ; |     X  | $FCEE
       .byte $04 ; |     X  | $FCEF
       .byte $7C ; | XXXXX  | $FCF0
       .byte $00 ; |        | $FCF1
       .byte $E0 ; |XXX     | $FCF2
       .byte $20 ; |  X     | $FCF3
       .byte $3C ; |  XXXX  | $FCF4
       .byte $07 ; |     XXX| $FCF5
       .byte $00 ; |        | $FCF6
       .byte $00 ; |        | $FCF7
       .byte $00 ; |        | $FCF8
       .byte $00 ; |        | $FCF9
       .byte $00 ; |        | $FCFA
       .byte $07 ; |     XXX| $FCFB
       .byte $3C ; |  XXXX  | $FCFC
       .byte $20 ; |  X     | $FCFD
       .byte $E0 ; |XXX     | $FCFE
       .byte $00 ; |        | $FCFF
; NOTE: there is no right side PF2 data for the reflected rooms.

BigRoomSpritePosTable
	; Room 8 sprite positions
	.byte $11 ; |   X   X|	; This table is the packed X and Y coordinates of all sprites for big rooms.
	.byte $65 ; | XX  X X|	  
	.byte $6A ; | XX X X |	X = hi nybble * 8 + hi nybble * 2 + 1
	.byte $0A ; |    X X |	Y = lo nybble * 5
	.byte $B4 ; |X XX X  |
	.byte $FA ; |XXXX X  |
	; Room 9 sprite positions
	.byte $15 ; |   X X X|
	.byte $72 ; | XXX  X |
	.byte $19 ; |   XX  X|
	.byte $C9 ; |XX  X  X|
	.byte $D4 ; |XX X X  |
	.byte $DE ; |XX XXXX |

RepositionTable
; bit 7 is set when ??? Need to figure this out. It has to do with which sprite is used to draw the item in the room.
	.byte $42 ; | X    X | Room 0
	.byte $42 ; | X    X | Room 1
	.byte $1E ; |   XXXX | Room 2
	.byte $1C ; |   XXX  | Room 3 - Moving Walls room
	.byte $2E ; |  X XXX | Room 4
	.byte $96 ; |X  X XX | Room 5	NOTE: bit 7 is set!
	.byte $9E ; |X  XXXX | Room 6	NOTE: bit 7 is set!
	.byte $9E ; |X  XXXX | Room 7 	NOTE: bit 7 is set!
	.byte $28 ; |  X X   | Room 8 
	.byte $26 ; |  X XX  | Room 9

pf1shapesleft	
; ROOM 0: (offset $00)
       .byte $01 ; |       X| $FD16
       .byte $01 ; |       X| $FD17
       .byte $01 ; |       X| $FD18
       .byte $01 ; |       X| $FD19
       .byte $01 ; |       X| $FD1A
       .byte $00 ; |        | $FD1B
       .byte $FF ; |XXXXXXXX| $FD1C
       .byte $80 ; |X       | $FD1D
       .byte $80 ; |X       | $FD1E
       .byte $FF ; |XXXXXXXX| $FD1F
; ROOM 1: (offset $0A)
       .byte $FF ; |XXXXXXXX| $FD20
       .byte $80 ; |X       | $FD21
       .byte $80 ; |X       | $FD22
       .byte $80 ; |X       | $FD23
       .byte $80 ; |X       | $FD24
       .byte $80 ; |X       | $FD25
       .byte $80 ; |X       | $FD26
       .byte $80 ; |X       | $FD27
       .byte $FF ; |XXXXXXXX| $FD28
; ROOM 2: (offset $13)
       .byte $FF ; |XXXXXXXX| $FD29
       .byte $80 ; |X       | $FD2A
       .byte $00 ; |        | $FD2B
       .byte $80 ; |X       | $FD2C
       .byte $80 ; |X       | $FD2D
       .byte $FF ; |XXXXXXXX| $FD2E
       .byte $00 ; |        | $FD2F
       .byte $00 ; |        | $FD30
; ROOM 8: (offset $1B)
       .byte $00 ; |        | $FD31
       .byte $00 ; |        | $FD32
       .byte $7F ; | XXXXXXX| $FD33
       .byte $40 ; | X      | $FD34
       .byte $40 ; | X      | $FD35
       .byte $40 ; | X      | $FD36
       .byte $40 ; | X      | $FD37
       .byte $40 ; | X      | $FD38
       .byte $00 ; |        | $FD39
       .byte $40 ; | X      | $FD3A
       .byte $7F ; | XXXXXXX| $FD3B
       .byte $00 ; |        | $FD3C
       .byte $00 ; |        | $FD3D
       .byte $F7 ; |XXXX XXX| $FD3E
       .byte $80 ; |X       | $FD3F
       .byte $80 ; |X       | $FD40
       .byte $87 ; |X    XXX| $FD41
       .byte $84 ; |X    X  | $FD42
       .byte $84 ; |X    X  | $FD43
       .byte $84 ; |X    X  | $FD44
       .byte $87 ; |X    XXX| $FD45
       .byte $80 ; |X       | $FD46
       .byte $80 ; |X       | $FD47
       .byte $80 ; |X       | $FD48
       .byte $80 ; |X       | $FD49
       .byte $FF ; |XXXXXXXX| $FD4A
       .byte $00 ; |        | $FD4B
       .byte $00 ; |        | $FD4C
; ROOM 9: (offset $37)
       .byte $00 ; |        | $FD4D
       .byte $F0 ; |XXXX    | $FD4E
       .byte $90 ; |X  X    | $FD4F
       .byte $10 ; |   X    | $FD50
       .byte $90 ; |X  X    | $FD51
       .byte $D0 ; |XX X    | $FD52
       .byte $5F ; | X XXXXX| $FD53
       .byte $40 ; | X      | $FD54
       .byte $70 ; | XXX    | $FD55
       .byte $10 ; |   X    | $FD56
       .byte $19 ; |   XX  X| $FD57
       .byte $09 ; |    X  X| $FD58
       .byte $09 ; |    X  X| $FD59
       .byte $09 ; |    X  X| $FD5A
       .byte $0F ; |    XXXX| $FD5B
       .byte $00 ; |        | $FD5C
       .byte $00 ; |        | $FD5D
       .byte $00 ; |        | $FD5E
       .byte $00 ; |        | $FD5F
       .byte $00 ; |        | $FD60
       .byte $00 ; |        | $FD61
       .byte $00 ; |        | $FD62
       .byte $00 ; |        | $FD63
       .byte $01 ; |       X| $FD64
       .byte $FF ; |XXXXXXXX| $FD65
       .byte $80 ; |X       | $FD66
       .byte $00 ; |        | $FD67
       .byte $80 ; |X       | $FD68
       .byte $FF ; |XXXXXXXX| $FD69
       .byte $01 ; |       X| $FD6A
       .byte $00 ; |        | $FD6B
       .byte $00 ; |        | $FD6C
       .byte $00 ; |        | $FD6D
       .byte $00 ; |        | $FD6E
; ROOM 3:  (offset $59)
       .byte $1F ; |   XXXXX| $FD6F
       .byte $10 ; |   X    | $FD70
       .byte $10 ; |   X    | $FD71
       .byte $11 ; |   X   X| $FD72
       .byte $10 ; |   X    | $FD73
       .byte $10 ; |   X    | $FD74
       .byte $00 ; |        | $FD75
       .byte $10 ; |   X    | $FD76
       .byte $10 ; |   X    | $FD77
       .byte $11 ; |   X   X| $FD78
       .byte $10 ; |   X    | $FD79
       .byte $10 ; |   X    | $FD7A
       .byte $1F ; |   XXXXX| $FD7B
; ROOM 4: (offset $66)
       .byte $FF ; |XXXXXXXX| $FD7C
       .byte $80 ; |X       | $FD7D
       .byte $00 ; |        | $FD7E
       .byte $80 ; |X       | $FD7F
       .byte $F0 ; |XXXX    | $FD80
       .byte $10 ; |   X    | $FD81
       .byte $1E ; |   XXXX | $FD82
       .byte $02 ; |      X | $FD83
       .byte $03 ; |      XX| $FD84
       .byte $00 ; |        | $FD85
       .byte $00 ; |        | $FD86
; ROOM 5: (offset $71)
       .byte $FF ; |XXXXXXXX| $FD87
       .byte $80 ; |X       | $FD88
       .byte $81 ; |X      X| $FD89
       .byte $80 ; |X       | $FD8A
       .byte $FF ; |XXXXXXXX| $FD8B
       .byte $00 ; |        | $FD8C
       .byte $00 ; |        | $FD8D
       .byte $00 ; |        | $FD8E
; ROOM 6: (offset $79)
       .byte $00 ; |        | $FD8F
       .byte $00 ; |        | $FD90
       .byte $01 ; |       X| $FD91
       .byte $01 ; |       X| $FD92
       .byte $7F ; | XXXXXXX| $FD93
       .byte $40 ; | X      | $FD94
       .byte $7F ; | XXXXXXX| $FD95
; ROOM 7: (offset $80)
       .byte $00 ; |        | $FD96
       .byte $00 ; |        | $FD97
       .byte $00 ; |        | $FD98
       .byte $00 ; |        | $FD99
       .byte $0F ; |    XXXX| $FD9A
       .byte $08 ; |    X   | $FD9B
       .byte $F8 ; |XXXXX   | $FD9C
       .byte $80 ; |X       | $FD9D
       .byte $00 ; |        | $FD9E
       .byte $80 ; |X       | $FD9F
       .byte $F8 ; |XXXXX   | $FDA0
       .byte $08 ; |    X   | $FDA1
       .byte $0F ; |    XXXX| $FDA2
       .byte $00 ; |        | $FDA3
       .byte $00 ; |        | $FDA4
       .byte $00 ; |        | $FDA5
       .byte $00 ; |        | $FDA6

pf1shapesright
; ROOM 0: (offset $00)
       .byte $FF ; |XXXXXXXX| $FDA7
       .byte $80 ; |X       | $FDA8
       .byte $00 ; |        | $FDA9
       .byte $80 ; |X       | $FDAA
       .byte $80 ; |X       | $FDAB
       .byte $80 ; |X       | $FDAC
       .byte $80 ; |X       | $FDAD
       .byte $80 ; |X       | $FDAE
       .byte $80 ; |X       | $FDAF
       .byte $FF ; |XXXXXXXX| $FDB0
; ROOM 1; (offset $0A)
       .byte $01 ; |       X| $FDB1
       .byte $01 ; |       X| $FDB2
       .byte $01 ; |       X| $FDB3
       .byte $00 ; |        | $FDB4
       .byte $FF ; |XXXXXXXX| $FDB5
       .byte $80 ; |X       | $FDB6
       .byte $00 ; |        | $FDB7
       .byte $80 ; |X       | $FDB8
       .byte $FF ; |XXXXXXXX| $FDB9
; ROOM 2: (offset $13) 
       .byte $FF ; |XXXXXXXX| $FDBA
       .byte $80 ; |X       | $FDBB
       .byte $00 ; |        | $FDBC
       .byte $80 ; |X       | $FDBD
       .byte $80 ; |X       | $FDBE
       .byte $80 ; |X       | $FDBF
       .byte $80 ; |X       | $FDC0
       .byte $FF ; |XXXXXXXX| $FDC1
; ROOM 8: (offset $1B) 
       .byte $00 ; |        | $FDC2
       .byte $7F ; | XXXXXXX| $FDC3
       .byte $40 ; | X      | $FDC4
       .byte $40 ; | X      | $FDC5
       .byte $00 ; |        | $FDC6
       .byte $40 ; | X      | $FDC7
       .byte $40 ; | X      | $FDC8
       .byte $40 ; | X      | $FDC9
       .byte $4F ; | X  XXXX| $FDCA
       .byte $48 ; | X  X   | $FDCB
       .byte $48 ; | X  X   | $FDCC
       .byte $78 ; | XXXX   | $FDCD
       .byte $00 ; |        | $FDCE
       .byte $00 ; |        | $FDCF
       .byte $FF ; |XXXXXXXX| $FDD0
       .byte $80 ; |X       | $FDD1
       .byte $80 ; |X       | $FDD2
       .byte $80 ; |X       | $FDD3
       .byte $07 ; |     XXX| $FDD4
       .byte $84 ; |X    X  | $FDD5
       .byte $84 ; |X    X  | $FDD6
       .byte $87 ; |X    XXX| $FDD7
       .byte $80 ; |X       | $FDD8
       .byte $80 ; |X       | $FDD9
       .byte $80 ; |X       | $FDDA
       .byte $80 ; |X       | $FDDB
       .byte $FF ; |XXXXXXXX| $FDDC
       .byte $00 ; |        | $FDDD
; ROOM 9: (offset $37) 
       .byte $00 ; |        | $FDDE
       .byte $FF ; |XXXXXXXX| $FDDF
       .byte $80 ; |X       | $FDE0
       .byte $80 ; |X       | $FDE1
       .byte $80 ; |X       | $FDE2
       .byte $FC ; |XXXXXX  | $FDE3
       .byte $04 ; |     X  | $FDE4
       .byte $04 ; |     X  | $FDE5
       .byte $04 ; |     X  | $FDE6
       .byte $04 ; |     X  | $FDE7
       .byte $04 ; |     X  | $FDE8
       .byte $06 ; |     XX | $FDE9
       .byte $00 ; |        | $FDEA
       .byte $00 ; |        | $FDEB
       .byte $00 ; |        | $FDEC
       .byte $00 ; |        | $FDED
       .byte $00 ; |        | $FDEE
       .byte $00 ; |        | $FDEF
       .byte $00 ; |        | $FDF0
       .byte $00 ; |        | $FDF1
       .byte $00 ; |        | $FDF2
       .byte $00 ; |        | $FDF3
       .byte $00 ; |        | $FDF4
       .byte $01 ; |       X| $FDF5
       .byte $FF ; |XXXXXXXX| $FDF6
       .byte $80 ; |X       | $FDF7
       .byte $00 ; |        | $FDF8
       .byte $80 ; |X       | $FDF9
       .byte $FF ; |XXXXXXXX| $FDFA
       .byte $01 ; |       X| $FDFB
       .byte $00 ; |        | $FDFC
       .byte $00 ; |        | $FDFD
       .byte $00 ; |        | $FDFE
       .byte $00 ; |        | $FDFF
; NOTE: There are no right side PF1 graphics for reflected rooms.

;--------------------------------
; Below are the tables of coordinates for the doorways in the game.
;

doorXPositions
; LEVEL 1: (Room 8 = Big Room)
;
;   Room 0: "Backwards C"
;     Door 0 - X - Right side door
	.byte 145 ; Big Room
	.byte 130 ; Zoomed Room
;     Door 1 - X - Left side door with bottom approach.
	.byte 110 ; Big Room 
	.byte 59  ; Zoomed Room
;
;   Room 1: "C-shaped room"
;     Door 2 - X - Right side door
	.byte 65  ; Big Room
	.byte 130 ; Zoomed Room
;     Door 3 - X - Top side door
	.byte 34  ; Big Room
	.byte 55  ; Zoomed Room
;
;   Room 2: "Snake room"
;     Door 4 - X - Right side door
	.byte 141 ; Big Room
	.byte 130 ; Zoomed Room
;     Door 5 - X - Left side door
	.byte 88  ; Big Room
	.byte 23  ; Zoomed Room
;
;   Room 3: Moving Walls room.
;     Door 6 - X - Right side
	.byte 53  ; Big Room
	.byte 118 ; Zoomed Room
;     Door 7 - X - Left side
	.byte 20  ; Big Room
	.byte 35  ; Zoomed Room

; LEVEL 2: (Room 9 = Big Room)
;
;   Room 4: 
;     Door 8 - X
	.byte 16 ; Big Room
	.byte 22 ; Zoomed Room
;     Door 9 - X
	.byte 65  ; Big Room
	.byte 132 ; Zoomed Room
;
;   Room 5: The 'T' shaped room 
;     Door 10 - X
	.byte 114 ; Big Room
	.byte 77  ; Zoomed Room
;     Door 11 - X
	.byte 114 ; Big Room
	.byte 77  ; Zoomed Room
;
;   Room 6: - The 'A' shaped room.
;     Door 12 - X
	.byte 82  ; Big Room
	.byte 77  ; Zoomed Room
;     Door 13 - X
	.byte 82  ; Big Room
	.byte 77  ; Zoomed Room
;
;   Room 7: 
;     Door 14 - X
	.byte $91 ; Big Room
	.byte $84 ; Zoomed Room
;     Door 15 - X
	.byte $10 ; Big Room
	.byte $16 ; Zoomed Room


doorYPositions
; This table contains the Y-coordinates of each door along with a 2 bit code indicating
; orientation of the doorway.   Bits 7 and 6 of each byte encode the orientation of the
; doorway:
; %00 = Vertical orientation approach from left moving right to pass through door.
; %01 = Vertical orientation approach from right moving left to pass through door.
; %10 = Horizontal orientation approach from bottom moving up to pass through door.
; %11 = Horizontal orientation approach from top moving down to pass through door.
;
; The remaining 6 bits of each byte contain the Y-coordinate of the door divided by 2.
; Y ranges in the game from 0 to 79.  So in this table it can range from 0 to 39.   
;
; Declare the following constants to faciltate the declaration of doorway data:

VerticalLeft		EQU	(%00 << 6)
VerticalRight		EQU	(%01 << 6)
HorizontalUp		EQU	(%10 << 6)	
HorizontalDown		EQU	(%11 << 6)

; LEVEL 1:
;   Room 0:
;     Door 0 - Y
	.byte 48/2 + VerticalRight	; Big Room
	.byte 10/2 + VerticalLeft	; Zoomed Room
;     Door 1 - Y
	.byte 50/2 + HorizontalUp	; Big Room
	.byte 18/2 + HorizontalDown	; Zoomed Room
;   Room 1:
;     Door 2 - Y 
	.byte 62/2 + VerticalRight	; Big Room
	.byte 60/2 + VerticalLeft	; Zoomed Room
;     Door 3 - Y
	.byte 36/2 + HorizontalDown	; Big Room
	.byte 4/2  + HorizontalUp	; Zoomed Room
;   Room 2: 
;     Door 4 - Y
	.byte 10/2 + VerticalRight	; Big Room
	.byte 12/2 + VerticalLeft	; Zoomed Room
;     Door 5 - Y
	.byte 10/2 + VerticalLeft	; Big Room
	.byte 12/2 + VerticalRight	; Zoomed Room 
;   Room 3: "Moving wall room"
;     Door 6 - Y
	.byte 14/2 + VerticalRight	; Big Room
	.byte 36/2 + VerticalLeft	; Zoomed Room 
;     Door 7 - Y
	.byte 18/2 + VerticalLeft	; Big Room
	.byte 36/2 + VerticalRight	; Zoomed Room 

; LEVEL 2:
;   Room 4:
;     Door 8 - Y
	.byte 8/2  + VerticalLeft	; Big Room
	.byte 8/2  + VerticalRight	; Zoomed Room 
;     Door 9 - Y
	.byte 8/2  + VerticalRight	; Big Room
	.byte 8/2  + VerticalLeft	; Zoomed Room 
;   Room 5:
;     Door 10 - Y
	.byte 26/2 + HorizontalUp	; Big Room
	.byte 70/2 + HorizontalDown	; Zoomed Room 
;     Door 11 - Y
	.byte 26/2 + HorizontalUp	; Big Room
	.byte 70/2 + HorizontalDown	; Zoomed Room 
;   Room 6:
;     Door 12 - Y
	.byte 44/2 + HorizontalUp	; Big Room
	.byte 70/2 + HorizontalDown	; Zoomed Room 
;     Door 13 - Y
	.byte 44/2 + HorizontalUp	; Big Room
	.byte 70/2 + HorizontalDown	; Zoomed Room 
;   Room 7:
;     Door 14 - Y
	.byte 60/2 + VerticalRight	; Big Room
	.byte 36/2 + VerticalLeft	; Zoomed Room 
;     Door 15 - Y
	.byte 60/2 + VerticalLeft	; Big Room
	.byte 36/2 + VerticalRight	; Zoomed Room 
; --------------------------------------


; These next 2 tables are used in conjunction with the liveGFX timers to determine when sprite related events 
; occur during the game. The end result is an set of combinations to control how often each sprite will have its
; position updated.
;

; SPR STATUS=	GFX=	eventMask=	GFX Pattern =						Update Pattern
; -----------	----	----------	--------------------------------------------------	-----------------
;  %000 = 0	0	%00000000	$01, $02, $04, $08, $10, $20, $40, $80, -> $01 ...	Never (used for items)	
;  %001 = 1	1	%10000000	$08, $10, $20, $40, $80, -> $08 ...			Every 5th frame pair (6/sec)
;  %010 = 2	0	%10001000	$01, $02, $04, $08, $10, $20, $40, $80, -> $01 ...	Every 4th frame pair (7.5/sec)
;  %011 = 3	2	%10000000	$20, $40, $80, -> $02 ...				Every 3rd frame pair (10/sec)
;  %100 = 4	0	%10101010	$01, $02, $04, $08, $10, $20, $40, $80, -> $01 ...	Every 2nd frame pair (15/sec)
;  %101 = 5	1	%11010000	$08, $10, $20, $40, $80, -> $08 ...			Every 3 of 5 frame pairs (18/sec)
;  %110 = 6	2	%11000000	$20, $40, $80, -> $02 ...				Every 2 of 3 frame pairs (20/sec)
;  %111 = 7	2	%11100000	$20, $40, $80, -> $02 ...				Every frame pair (30/sec)

whichGFXTable
	.byte $00 ; |        | Which timer is used.
	.byte $01 ; |       X|
	.byte $00 ; |        |
	.byte $02 ; |      X |
	.byte $00 ; |        |
	.byte $01 ; |       X|
	.byte $02 ; |      X |
	.byte $02 ; |      X |

eventMaskTable
	.byte $00 ; |        | The event mask logically AND'ed with the timer identified in the previous table.
	.byte $80 ; |X       |
	.byte $88 ; |X   X   |
	.byte $80 ; |X       |
	.byte $AA ; |X X X X |
	.byte $D0 ; |XX X    |
	.byte $C0 ; |XX      |
	.byte $E0 ; |XXX     |

;------------------------------------------------
HallMonsterGraphics
	.byte $70 ; | XXX    | hall monster small
	.byte $A8 ; |X X X   |
	.byte $F8 ; |XXXXX   |
	.byte $88 ; |X   X   |
	.byte $00 ; |        |
	.byte $18 ; |   XX   | hall monster big
	.byte $3C ; |  XXXX  |
	.byte $5A ; | X XX X |
	.byte $66 ; | XX  XX |
	.byte $3C ; |  XXXX  |
	.byte $42 ; | X    X |
	.byte $24 ; |  X  X  |
	.byte $18 ; |   XX   |
	.byte $00 ; |        |

;------------------------------------------------
SpriteImagesTable
	.byte $38 ; |  XXX   | zombie
	.byte $54 ; | X X X  |
	.byte $6C ; | XX XX  |
	.byte $39 ; |  XXX  X|
	.byte $7E ; | XXXXXX |
	.byte $98 ; |X  XX   |
	.byte $24 ; |  X  X  |
	.byte $66 ; | XX  XX |
	.byte $00 ; |        |

	.byte $3F ; |  XXXXXX| chest
	.byte $21 ; |  X    X|
	.byte $3F ; | XXXXXXX|
	.byte $42 ; | X    X |
	.byte $FE ; |XXXXXXX |
	.byte $82 ; |X     X |
	.byte $82 ; |X     X |
	.byte $FE ; |XXXXXXX |
	.byte $00 ; |        |

	.byte $18 ; |   XX   | ghoul
	.byte $BD ; |X XXXX X|
	.byte $A5 ; |X X  X X|
	.byte $FF ; |XXXXXXXX|
	.byte $3C ; |  XXXX  |
	.byte $24 ; |  X  X  |
	.byte $24 ; |  X  X  |
	.byte $66 ; | XX  XX |
	.byte $00 ; |        |

	.byte $18 ; |   XX   | helmet
	.byte $BD ; |X XXXX X|
	.byte $FF ; |XXXXXXXX|
	.byte $42 ; | X    X |
	.byte $24 ; |  X  X  |
	.byte $18 ; |   XX   |
	.byte $00 ; |        |
	.byte $00 ; |        |
	.byte $00 ; |        |

	.byte $00 ; |        |
	.byte $C6 ; |XX   XX | snake
	.byte $CA ; |XX  X X |
	.byte $2A ; |  X X X |
	.byte $4A ; | X  X X |
	.byte $51 ; | X X   X|
	.byte $21 ; |  X    X|
	.byte $00 ; |        |
	.byte $00 ; |        |

	.byte $08 ; |    X   | apple
	.byte $10 ; |   X    |
	.byte $7C ; | XXXXX  |
	.byte $FE ; |XXXXXXX |
	.byte $FE ; |XXXXXXX |
	.byte $7C ; | XXXXX  |
	.byte $38 ; |  XXX   |
	.byte $00 ; |        |
	.byte $00 ; |        |

	.byte $F8 ; |XXXXX   | Horizontal wall (quad wide)
	.byte $F8 ; |XXXXX   |
	.byte $F8 ; |XXXXX   |
	.byte $F8 ; |XXXXX   |
	.byte $00 ; |        |

	.byte $80 ; |X       | vertical wall (quad wide)
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $80 ; |X       |
	.byte $00 ; |        |  Its important that the height of the two walls together is 18 just like
	          ;             the monster Monster/Item graphics for all other rooms because the 
		  ;             graphics pointers are set as 18 * currentRoom for all zoomed-rooms.

	.byte $44 ; | X   X  | ettin
	.byte $AA ; |X X X X |
	.byte $44 ; | X   X  |
	.byte $FE ; |XXXXXXX |
	.byte $BA ; |X XXX X |
	.byte $BA ; |X XXX X |
	.byte $28 ; |  X X   |
	.byte $6C ; | XX XX  |
	.byte $00 ; |        |

	.byte $99 ; |X  XX  X| chess piece 
	.byte $DB ; |XX XX XX|
	.byte $7E ; | XXXXXX |
	.byte $34 ; |  XX X  |
	.byte $2C ; |  X XX  |
	.byte $24 ; |  X  X  |
	.byte $66 ; | XX  XX |
	.byte $FF ; |XXXXXXXX|
	.byte $00 ; |        |

	.byte $24 ; |  X  X  | goblin
	.byte $3C ; |  XXXX  |
	.byte $DB ; |XX XX XX|
	.byte $7E ; | XXXXXX |
	.byte $7E ; | XXXXXX |
	.byte $3C ; |  XXXX  |
	.byte $42 ; | X    X |
	.byte $C3 ; |XX    XX|
	.byte $00 ; |        |

	.byte $3C ; |  XXXX  | vial
	.byte $18 ; |   XX   |
	.byte $7E ; | XXXXXX |
	.byte $DF ; |XX XXXXX|
	.byte $FF ; |XXXXXXXX|
	.byte $7E ; | XXXXXX |
	.byte $3C ; |  XXXX  |
	.byte $00 ; |        |
	.byte $00 ; |        |

	.byte $00 ; |        |
	.byte $7B ; | XXXX XX| dragon
	.byte $3A ; |  XXX X |
	.byte $0A ; |    X X |
	.byte $3E ; |  XXXXX |
	.byte $5E ; | X XXXX |
	.byte $92 ; |X  X  X |
	.byte $1B ; |   XX XX|
	.byte $00 ; |        |

	.byte $99 ; |X  XX  X| crown
	.byte $DB ; |XX XX XX|
	.byte $FF ; |XXXXXXXX|
	.byte $AB ; |X X X XX|
	.byte $FF ; |XXXXXXXX|
	.byte $00 ; |        |
	.byte $00 ; |        |
	.byte $00 ; |        |
	.byte $00 ; |        |

	.byte $24 ; |  X  X  | Spider
	.byte $A5 ; |X X  X X|
	.byte $5A ; | X XX X |
	.byte $3C ; |  XXXX  |
	.byte $5A ; | X XX X |
	.byte $A5 ; |X X  X X|
	.byte $24 ; |  X  X  |
        .byte $00 ; |        |
        .byte $00 ; |        |

        .byte $00 ; |        |
        .byte $00 ; |        |
	.byte $07 ; |     XXX| key
	.byte $FD ; |XXXXXX X|
	.byte $A7 ; |X X  XXX|
        .byte $00 ; |        |
        .byte $00 ; |        |
        .byte $00 ; |        |
        .byte $00 ; |        |

        .byte $7C ; | XXXXX  | diamond
        .byte $82 ; |X     X |
        .byte $FE ; |XXXXXXX |
        .byte $44 ; | X   X  |
        .byte $28 ; |  X X   |
        .byte $10 ; |   X    |
        .byte $00 ; |        |
        .byte $00 ; |        |
        .byte $00 ; |        |

        .byte $72 ; | XXX  X | corpse
        .byte $93 ; |X  X  XX|
        .byte $ED ; |XXX XX X|
        .byte $5F ; | X XXXXX|
        .byte $5C ; | X XxX  |
        .byte $7D ; | XXXXX X|
        .byte $56 ; | X X XX |
        .byte $DD ; |XX XXX X|
        .byte $00 ; |        |


charset
       .byte $3C ; |  XXXX  | $FF00
       .byte $66 ; | XX  XX | $FF01
       .byte $66 ; | XX  XX | $FF02
       .byte $66 ; | XX  XX | $FF03
       .byte $66 ; | XX  XX | $FF04
       .byte $66 ; | XX  XX | $FF05
       .byte $66 ; | XX  XX | $FF06
       .byte $3C ; |  XXXX  | $FF07

       .byte $7E ; | XXXXXX | $FF08
       .byte $18 ; |   XX   | $FF09
       .byte $18 ; |   XX   | $FF0A
       .byte $18 ; |   XX   | $FF0B
       .byte $18 ; |   XX   | $FF0C
       .byte $38 ; |  XXX   | $FF0D
       .byte $18 ; |   XX   | $FF0E
       .byte $08 ; |    X   | $FF0F

       .byte $7E ; | XXXXXX | $FF10
       .byte $60 ; | XX     | $FF11
       .byte $60 ; | XX     | $FF12
       .byte $3C ; |  XXXX  | $FF13
       .byte $06 ; |     XX | $FF14
       .byte $06 ; |     XX | $FF15
       .byte $46 ; | X   XX | $FF16
       .byte $3C ; |  XXXX  | $FF17

       .byte $3C ; |  XXXX  | $FF18
       .byte $46 ; | X   XX | $FF19
       .byte $06 ; |     XX | $FF1A
       .byte $06 ; |     XX | $FF1B
       .byte $1C ; |   XXX  | $FF1C
       .byte $06 ; |     XX | $FF1D
       .byte $46 ; | X   XX | $FF1E
       .byte $3C ; |  XXXX  | $FF1F

       .byte $0C ; |    XX  | $FF20
       .byte $0C ; |    XX  | $FF21
       .byte $7E ; | XXXXXX | $FF22
       .byte $4C ; | X  XX  | $FF23
       .byte $4C ; | X  XX  | $FF24
       .byte $2C ; |  X XX  | $FF25
       .byte $1C ; |   XXX  | $FF26
       .byte $0C ; |    XX  | $FF27

       .byte $3C ; |  XXXX  | $FF28
       .byte $46 ; | X   XX | $FF29
       .byte $06 ; |     XX | $FF2A
       .byte $06 ; |     XX | $FF2B
       .byte $3C ; |  XXXX  | $FF2C
       .byte $60 ; | XX     | $FF2D
       .byte $60 ; | XX     | $FF2E
       .byte $7E ; | XXXXXX | $FF2F

       .byte $3C ; |  XXXX  | $FF30
       .byte $66 ; | XX  XX | $FF31
       .byte $66 ; | XX  XX | $FF32
       .byte $66 ; | XX  XX | $FF33
       .byte $7C ; | XXXXX  | $FF34
       .byte $60 ; | XX     | $FF35
       .byte $62 ; | XX   X | $FF36
       .byte $3C ; |  XXXX  | $FF37

       .byte $30 ; |  XX    | $FF38
       .byte $30 ; |  XX    | $FF39
       .byte $30 ; |  XX    | $FF3A
       .byte $18 ; |   XX   | $FF3B
       .byte $0C ; |    XX  | $FF3C
       .byte $06 ; |     XX | $FF3D
       .byte $42 ; | X    X | $FF3E
       .byte $3E ; |  XXXXX | $FF3F

       .byte $3C ; |  XXXX  | $FF40
       .byte $66 ; | XX  XX | $FF41
       .byte $66 ; | XX  XX | $FF42
       .byte $66 ; | XX  XX | $FF43
       .byte $3C ; |  XXXX  | $FF44
       .byte $66 ; | XX  XX | $FF45
       .byte $66 ; | XX  XX | $FF46
       .byte $3C ; |  XXXX  | $FF47

       .byte $3C ; |  XXXX  | $FF48
       .byte $46 ; | X   XX | $FF49
       .byte $06 ; |     XX | $FF4A
       .byte $3E ; |  XXXXX | $FF4B
       .byte $66 ; | XX  XX | $FF4C
       .byte $66 ; | XX  XX | $FF4D
       .byte $66 ; | XX  XX | $FF4E
       .byte $3C ; |  XXXX  | $FF4F

       .byte $3C ; |  XXXX  | $FF50
       .byte $5A ; | X XX X | $FF51
       .byte $FF ; |XXXXXXXX| $FF52
       .byte $DB ; |XX XX XX| $FF53
       .byte $66 ; | XX  XX | $FF54
       .byte $3C ; |  XXXX  | $FF55
       .byte $00 ; |        | $FF56

;-----------------
; This table contains a set of values for each room in the game.  When the 
; kernal line counter in Y reaches each value in the table, the graphics
; index in X is incremented by 1 to change the PF graphics for the next and
; subsequent scanlines.
;
; IF ( Y = PFshapchanges[X] ), THEN X = X + 1;
;
; Changing the values in this table will distort the wall thicknesses and
; heights of the displayed room walls.
;
; If we change the kernal logic so all rooms use the same height wall sections,
; then most if not all of this ROM code be reclaimed for other uses.
;
; For some reason, the pfshapchange sequences for level 1 rooms are terminated 
; with $00, but the sequences for level 2 rooms are terminated with $FF.

PFshapechanges
; Room 0: (pfroomoffsets = $00)
        .byte $01 ; |       X|
        .byte $0B ; |    X XX|
        .byte $0F ; |    XXXX|
        .byte $19 ; |   XX  X|
        .byte $1B ; |   XX XX|
        .byte $2F ; |  X XXXX|
        .byte $31 ; | XX    X|
        .byte $41 ; | X     X|
        .byte $4D ; | X  XX X|
	.byte $00 ; |        |
; Room 1: (pfroomoffsets = $0A)
	.byte $01 ; |       X|
	.byte $11 ; |   X   X|
	.byte $13 ; |   X  XX|
	.byte $29 ; |  X X  X|
	.byte $2B ; |  X X XX|
	.byte $3D ; |  XXXX X|
	.byte $41 ; | X     X|
	.byte $4D ; | X  XX X|
	.byte $00 ; |        |
; Room 2: (pfroomoffsets = $13)
	.byte $01 ; |       X|
	.byte $0D ; |    XX X|
	.byte $11 ; |   X   X|
	.byte $1D ; |   XXX X|
	.byte $21 ; |  X    X|
	.byte $23 ; |  X   XX|
	.byte $4D ; | X  XX X|
	.byte $00 ; |        |
; Room 8: (pfroomoffsets = $1B) 
	.byte $03 ; |      XX|
	.byte $05 ; |     X X|
	.byte $07 ; |     XXX|
	.byte $09 ; |    X  X|
	.byte $0B ; |    X XX|
	.byte $0D ; |    XX X|
	.byte $0F ; |    XXXX|
	.byte $11 ; |   X   X|
	.byte $13 ; |   X  XX|
	.byte $1B ; |   XX XX|
	.byte $1D ; |   XXX X|
	.byte $1F ; |   XXXXX|
	.byte $23 ; |  X   XX|
	.byte $25 ; |  X  X X|
	.byte $27 ; |  X  XXX|
	.byte $2B ; |  X X XX|
	.byte $2D ; |  X XX X|
	.byte $2F ; |  X XXXX|
	.byte $31 ; |  XX   X|
	.byte $37 ; |  XX XXX|
	.byte $39 ; |  XXX  X|
	.byte $3B ; |  XXX XX|
	.byte $3D ; |  XXXX X|
	.byte $3F ; |  XXXXXX|
	.byte $43 ; | X    XX|
	.byte $45 ; | X   X X|
	.byte $47 ; | X   XXX|
	.byte $00 ; |        |
; Room 9: (pfroomoffsets = $37)
	.byte $03 ; |      XX|
	.byte $05 ; |     X X|
	.byte $07 ; |     XXX|
	.byte $09 ; |    X  X|
	.byte $0B ; |    X XX|
	.byte $0D ; |    XX X|
	.byte $0F ; |    XXXX|
	.byte $11 ; |   X   X|
	.byte $13 ; |   X  XX|
	.byte $15 ; |   X X X|
	.byte $17 ; |   X XXX|
	.byte $19 ; |   XX  X|
	.byte $1B ; |   XX XX|
	.byte $1D ; |   XXX X|
	.byte $1F ; |   XXXXX|
	.byte $21 ; |  X    X|
	.byte $25 ; |  X  X X|
	.byte $29 ; |  X X  X|
	.byte $2B ; |  X X XX|
	.byte $2F ; |  X XXXX|
	.byte $31 ; |  XX   X|
	.byte $33 ; |  XX  XX|
	.byte $35 ; |  XX X X|
	.byte $37 ; |  XX XXX|
	.byte $39 ; |  XXX  X|
	.byte $3B ; |  XXX XX|
	.byte $3D ; |  XXXX X|
	.byte $3F ; |  XXXXXX|
	.byte $41 ; | X     X|
	.byte $43 ; | X    XX|
	.byte $45 ; | X   X X|
	.byte $47 ; | X   XXX|
	.byte $49 ; | X  X  X|
	.byte $FF ; |XXXXXXXX|
; Room 3: (pfroomoffsets = $59)
        .byte $01
	.byte $0D
	.byte $1B
	.byte $1F
	.byte $21
	.byte $25
	.byte $29
	.byte $2D
	.byte $2F
	.byte $33
	.byte $41
	.byte $4D
        .byte $00
; Room 4: (pfroomoffsets = $66)
	.byte $01
	.byte $09
	.byte $0D
	.byte $17
	.byte $19
	.byte $21
	.byte $23
	.byte $2B
	.byte $2D
	.byte $4D
	.byte $FF
; Room 5: (pfroomoffsets = $71)
        .byte $01
	.byte $0C
	.byte $15
	.byte $1F
	.byte $21
	.byte $37
	.byte $4D
	.byte $FF
; Room 6: (pfroomoffsets = $79)
        .byte $01
	.byte $1B
	.byte $1D
	.byte $33
	.byte $35
	.byte $4D
	.byte $FF
; Room 7: (pfroomoffsets = $80)
	.byte $01 
	.byte $09 
	.byte $0B 
	.byte $11 
	.byte $13 
	.byte $1B 
	.byte $1D 
	.byte $25 
	.byte $29 
	.byte $31
	.byte $33 
	.byte $3B 
	.byte $3D 
	.byte $43 
	.byte $45 
	.byte $4D 
	.byte $FF 

ballToPixelMaskTable	
	; This table is to check for ball collisions with individual pixels of monster sprites.
        .byte $C0,$60,$30,$18,$0C,$06,$03,$03


; Offsets for PF shapes for the 10 different rooms.  It is also the same offset used to
; index the pfshapechages table that defines the vertical height of each section of wall
; within a room.
; From InitGame we know that rooms with offsets >= $59 are mirrored rooms.  
pfroomoffsets
        .byte $00,$0A,$13,$59,$66,$71,$79,$80,$1B,$37


        .word Start
        .word Start
        .word Start