[stella] DD build 8

Subject: [stella] DD build 8
From: Glenn Saunders <cybpunks2@xxxxxxxxxxxxx>
Date: Sun, 21 Oct 2001 23:17:40 -0700
Okay, I succeeded in implementing Thomas' sprite logic routine into Death Derby. (I also threw in the VDEL code from Roger's recent post).

More of an achievement as far as original code goes was getting the sprite rotation system working. For someone new to assembly language, it's pretty exciting seeing your new original code actually work, even if it's a trivial thing. I've got the code that determines wether or not to do the hardware sprite flip, and the data laid out pointing to all the different frames in a complete rotation, and it worked. Although in this demo the cars are just statically pointing towards eachother, they are both using the same frame of animation, with the flip turned-on on the right. So I could write a routine that increments a simple counter 0-15 and get the cars to smoothly rotate around clockwise, using only 9 frames of data.

I thought about using different types of car shapes but it was so hard to maintain the image in the rotations that I'm sticking to one set for now.

I also changed some colors around. P0 has to be a different color from P1, and the missiles will share the same colors as their players. The PF can be white or grey on the black background. Maybe in the end I'll do a missile command/centipede sort of thing and remap the palette into psychadelic colors if the game winds up having waves. I always liked that style of color usage so common in the early days.

The problem I have now is that the horizontal positioning routine I borrowed from Gunfight is not working properly. I don't know what I'm doing wrong with it. Manual, could you check it?? The players move in big jumps when I change their start positions and if I make the players cross the screen flips out.

I thought about using the recently posted table method, but I was too lazy to try to convert the code over. I also don't know what I'm up to so far in actual ROM usage so it might be a bad idea to use the table method if the game's going to only be 4K.

Also, I had a question about HMOVE lines. It looks like I'm going to have to have HMOVE on either every line, or every other line, depending on the Y position of M0 and M1. Every other if they are on the same line of the line-pair, and every line if they are on even/odd lines. This is going to wind up wiping out the leftmost part of the safezone border line. If I set the ball priority above PF0 and PF1 couldn't I repaint it using the ball? And then I could just keep M0 to the right of the HMOVE lines hidden in black, correct? The HMOVE lines are narrow enough, I hope, to keep M0 from being affected by them.


Glenn Saunders - Producer - Cyberpunks Entertainment Personal homepage: http://www.geocities.com/Hollywood/1698 Cyberpunks Entertainment: http://cyberpunks.uni.cc

Attachment: DD_0008.bin
Description: Binary data

;Death Derby 2001
; By Glenn Saunders

;LINEAGE:

; How to Draw an Asymmetric Reflected Playfield
; by Roger Williams

; with a lot of help from Nick Bensema
; (this started out as his "How to Draw a Playfield")

	processor 6502
	include vcs.h

; CONSTANTS

; SCREEN GEOMETRY 	 CTR  ACTUAL 	SUBTOTAL
;----------------------- ---- --------- --------
ScoreHeight 		= 20; 20	20
; 	TopBorder	= 2   2		22
PlayfieldHeight		= 88; (176)	198
;	BottomBorder	= 2   2		200
;			 		---
;					200 visible lines

OverScanHeight		= 22; 22	222
;			 		---
;					222 total lines

;FIXED COLORS
Color0 = $34
Color1 = $C8
ColorPF = $FF;White
ColorSafeZone = $1E;Yellow

;INITIAL COUNTER VALUES
TombstoneHeight 	= 8  ; 8*2 = 16 (single scanlines) high per tombstone
TombstoneRowsPerScreen 	= 11-1 ; 11 rows of tombstones per screen
CarHeight 	= 8-1  ; 8 doubled scanlines (used as offset)



; constants that reference rotation index pointers
PointUp 	= 0
PointRight 	= 4
PointDown 	= 8
PointLeft 	= 12

TurnOnSpriteReflect = %00001000
TurnOffSpriteReflect = 0

CarPage		= $FF;00
CarDataAlign	=    $65

InitialSafeZone	= %10010000 ; initial safezone border graphics
SafeZone2	= %10000000 
FlipThreshold	= #9 ; flip sprite when
		    ;P0_CurrentRotationIndex >= 9









    SEG.U vars
    org $80

;TEMPORARY VARIABLES

Temp       	ds 1


;CurrentScanLine ds 1
; use Y instead

;CurrentTombstoneRow	ds 1; 11->0 outer loop counter
; use X instead

CurrentTombstoneSubRow 	ds 1; 7->0 inner loop counter


; ALTERNATING SAFEZONE BORDER STRIP
CurrentSafeZone ds 1
; PLAYFIELD BITMAP
PF1DataRAM	ds TombstoneRowsPerScreen+1
PF2DataRAM	ds TombstoneRowsPerScreen+1
PF1bDataRAM	ds TombstoneRowsPerScreen+1
PF2bDataRAM	ds TombstoneRowsPerScreen+1

;sprite positiong
P0_X		ds 1
P0_Y		ds 1

P1_X		ds 1
P1_Y		ds 1

P1_YFullres		ds 1
P0_YFullres		ds 1

M0_X		ds 1
M0_Y		ds 1

M1_X		ds 1
M1_Y		ds 1

FrameCounter1	ds 1; use this for timing purposes

;sprite graphics pointers
P0_CurrentRotationSequence ds 1; 0-15
P1_CurrentRotationSequence ds 1; 0-15

;these above reference addresses that get stored below

P0_CurrentFramePtr ds 2; this will wind up being a constant $FF in the high byte
P1_CurrentFramePtr ds 2; this will wind up being a constant $FF in the high byte

M0_CurrentFramePtr ds 2
M1_CurrentFramePtr ds 2

;P0_CurrentRowCounter ds 1
;P1_CurrentRowCounter ds 1
;M0_CurrentRowCounter ds 1
;M1_CurrentRowCounter ds 1


; stolen from OUTLAW source
;PF0Array            ds 1   ; PF0 array, 18 Bytes
ScoreshapeLow01     ds 1   ; Shape of player 1 lower score digit
ScoreshapeLow02     ds 1   ; Shape of player 2 lower score digit
ScoreshapeHi01      ds 1   ; Shape of player 1 higher score digit
ScoreshapeHi02      ds 1   ; Shape of player 2 higher score digit
bcdScore01Backup    ds 1   ; Backups score for player 1
rightScoreOnOff     ds 1   ; 0F for Right score on, 00 for off
gameState           ds 1   ; 0F running/EF saver/00 select/XX counter



    SEG code
    org  $F000

;FrameCounter = $93 was going to try some color cycling


Start
	SEI  ; Disable interrupts, if there are any.
	CLD  ; Clear BCD math bit.
	LDX  #$FF
	TXS  ; Set stack to beginning.
	

	; CLEAR OUT RAM
	LDA #0
KeepZeroing
	STA 0,X
	DEX
	BNE KeepZeroing

SetColors
	LDA #0
	STA COLUBK  ; Background will be black.
	
	LDA #ColorPF
	STA COLUPF
	
	LDA #PF_Reflect
	STA CTRLPF  ; set playfield to reflect

	LDA #Color0
	STA COLUP0
	LDA #Color1
	STA COLUP1
	
	LDA #60
	STA FrameCounter1
	
InitializeSprites
; set high byte for frame pointers
	; this should only have to be done once for the whole game
	; since all the car graphics are on the same page of ROM
	LDA CarPage; $FF
	STA P0_CurrentFramePtr+1
	STA P1_CurrentFramePtr+1

	
; set initial X,Y of P0, P1
	LDA #30; start P0 on the left
	STA P0_X
	LDA #100; start P0 halfway down
	STA P0_YFullres
	LSR	; divide by 2
	STA P0_Y

	LDA #112; start P1 on the right
	STA P1_X
	
	LDA #100; start P1 halfway down
	STA P1_YFullres
	LSR	; divide by 2
	STA P0_Y
	;
	LDA P0_YFullres		;vertical delay becomes
	EOR #1
	STA VDELP0	;least significant bit
	LDA P1_YFullres		;of player position
	EOR #1		;(thoughtfully placed in bit 0
	STA VDELP1	;by Stella's designers)

; set initial rotations
	LDX #PointRight; start P0 car pointing right
	STX P0_CurrentRotationSequence; store for later


	LDX #PointLeft; start P1 car pointing left
	STX P1_CurrentRotationSequence; store for later



	LDX #TombstoneRowsPerScreen
InitializeTombstones; copy from ROM to RAM

	LDA #InitialSafeZone
	STA CurrentSafeZone

	LDA PF1Data,X
	STA PF1DataRAM,X

	LDA PF2Data,X
	STA PF2DataRAM,X

	LDA PF1bData,X
	STA PF1bDataRAM,X

	LDA PF2bData,X
	STA PF2bDataRAM,X
	
    	DEX
    	BPL InitializeTombstones

MainLoop
	JSR VBArea
	JSR DrawScreen
	JSR OverScan
	JMP MainLoop      ;Continue forever.

;SUB
ClearTombstones
	LDX #TombstoneRowsPerScreen
KeepClearing 
	DEX
	STA <PF1DataRAM,X
	STA <PF2DataRAM,X
	STA <PF1bDataRAM,X
	STA <PF2bDataRAM,X
	BNE KeepClearing
	RTS  

;SUB
OverScan
	LDX #OverScanHeight

KillLines
	STA WSYNC
	DEX
	BNE KillLines
	RTS

;HORIZONTAL POSITIONING SUBROUTINE FROM MANUEL POLIK's GUNFIGHT	
;SUB (alternate beginning of below)
PosP1
            CLC 
            ADC #$08
;SUB
PosP0
            CMP #$A0
            BCC NH2
            SBC #$A0
NH2
            TAY
            LSR
            LSR
            LSR
            LSR
            STA Temp
            TYA
            AND #15
            CLC
            ADC Temp
            LDY Temp
            CMP #15
            BCC NH
            SBC #15
            INY
NH
            EOR #7
            ASL
            ASL
            ASL
            ASL
            STA HMP0,X
            INY                         ; Waste 5 cycles, 1 Byte
            STA WSYNC
            INY                         ; Waste 7(!) cycles, 1 Byte
            BIT 0                       ; Waste 3 cycles, 2 Byte
PosDelay    DEY
            BPL PosDelay
            STA RESP0,X
            RTS
;/HORIZONTAL POSITIONING SUBROUTINE	
	
;SUB
VBArea
        LDX #0 ; store to HMP0
        LDA P0_X; load current X value of P0
        JSR PosP0; call coarse pos calc routine for P0

	;LDA  #2
	STA  WSYNC

        LDX #1; store to HMP1
        LDA P1_X; load current X value of P1
        JSR PosP1; call coarse pos calc routine for P1
        
	;LDA  #2
	STA  WSYNC

	;later on we need to add the horizontal positioning
	;of the two missiles



	LDA P0_YFullres
	LSR
	STA P0_Y
	
	LDA P1_YFullres
	LSR
	STA P1_Y
	
	;
	LDA P0_YFullres		;vertical delay becomes
	EOR #1
	STA VDELP0	;least significant bit
	LDA P1_YFullres		;of player position
	EOR #1		;(thoughtfully placed in bit 0
	STA VDELP1	;by Stella's designers)




;The calculation of the object pointer (done outside the kernel, if
;Thomas didnt make that clear enough) looks like this:


	;this will have been modified by the controller routines
UpdateCurrentFramePtrP0
	LDY #TurnOffSpriteReflect; initialize to no flip
	LDX P0_CurrentRotationSequence;0-15
	CPX #FlipThreshold
	; A < #FlipThreshold  --->  N=1, Z=0, C=0
	; A = #FlipThreshold  --->  N=0, Z=1, C=1
	; A > #FlipThreshold  --->  N=0, Z=0, C=1
	BMI .Continue0   ; if A < 9 then sigN will be 1
			; so do not flip, just .Continue
FlipSprite0
	LDY #TurnOnSpriteReflect

.Continue0
	STY REFP0
	; load low byte pointer to the start
	; of gfx for the current frame
	LDA RotationSequence,X
	;LDA <CarRotation0
        SEC ; set carry bit
	; subtract the Y position of P0
        SBC P0_Y
        ADC #CarHeight+1
	; POINTER is initialized as offset -PO_Y away from the last scanline
	; of CarRotation0 graphics.
	; STORE THE LOW BYTE POINTER
        STA P0_CurrentFramePtr
	;this will have been modified by the controller routines

UpdateCurrentFramePtrP1
	LDY #TurnOffSpriteReflect; initialize to no flip
	LDX P1_CurrentRotationSequence;0-15
	CPX #FlipThreshold
	; A < #FlipThreshold  --->  N=1, Z=0, C=0
	; A = #FlipThreshold  --->  N=0, Z=1, C=1
	; A > #FlipThreshold  --->  N=0, Z=0, C=1
	BMI .Continue1   ; if A < 9 then sigN will be 1
			; so do not flip, just .Continue

FlipSprite1
	LDY #TurnOnSpriteReflect

.Continue1
	STY REFP1

	LDA RotationSequence,X
        SEC 
        SBC P1_Y
        ADC #CarHeight+1
        STA P1_CurrentFramePtr



; this shouldn't be necessary because the high byte is always constant
	; load a pointer to the page of memory
	; data for the CarRotation0 frame (HIGH BYTE)

        LDA #CarPage; $FF
        STA P0_CurrentFramePtr+1
        STA P1_CurrentFramePtr+1
	
HMOVEDelay          
	DEX
        BNE HMOVEDelay
        STA HMOVE ; Do it on cycle 74!!!
	STA WSYNC

	
	STA VSYNC ;Begin vertical sync.
	STA WSYNC ;  First line of VSYNC
	STA WSYNC ;  Second line of VSYNC.

	LDA #44   ;init timer for overscan
	STA TIM64T

	STA WSYNC ;  Third line of VSYNC.
	STA VSYNC ;  (0)


VBLOOP	LDA INTIM
	BNE VBLOOP ; Whew!
	
	STA WSYNC
	STA VBLANK  ;End the VBLANK period with a zero.
	

	LDA #0
	STA PF0
	STA PF1
	STA PF2; zero out playfield
	RTS

;SUB
DrawScreen
	LDX #ScoreHeight; burn through 20 total scanlines
DrawScore
	STA WSYNC
	DEX
	BNE DrawScore

TopBorder ; 2 lines
	LDA #$FF 
	STA PF0 ; draw a solid line
	STA PF1
	STA PF2
	LDA #InitialSafeZone
	STA WSYNC
	; draw a solid line except for the safezone border
	STA PF0 

	;ScanGo will finish the line off

FinalInitialization
	;INITIALIZE TOMBSTONE ROW COUNTERS
	LDX #TombstoneRowsPerScreen+1
	
	;TombstoneRowsPerScreen held in X register through kernel
	LDA #TombstoneHeight+1
	; NOTE: pad these by one because the first time through it decrements
	; at the top of the loop

	STA CurrentTombstoneSubRow; store TombstoneHeight to RAM

	

	LDY #PlayfieldHeight ; store scanline counter in Y throughout
		; the whole kernel.  Decrement every other scanline





;THIS AREA IS A 2-LINE KERNEL

;START FIRST LINE OF LINE-PAIR
ScanLoop1
	;INNER LOOP
	DEC CurrentTombstoneSubRow ;next row of current tombstone
	BNE ScanGo1

	LDA #TombstoneHeight; if counter reaches zero, reset to 7
	STA CurrentTombstoneSubRow; and store back to RAM
	DEX ;CurrentTombstoneRow = CurrentTombstoneRow - 1
	    ;outer loop - indexes next tombstone row
ScanGo1
	STA WSYNC
	; Time to begin cycle counting

				;	0
	;STA.W HMOVE		;+4	4
	
	NOP 			;+2	2
	NOP			;+2	4
	
	;will probably have to do an HMOVE on every line to 
	;simplify logic.  HMOVE is only necessary for the missiles

	LDA <PF1DataRAM-1,X       ;+4	8

	;I'm not sure why the -1 is necessary here to make it work


	STA PF1               	;+3  = *11*  < 29	;PF1 visible
	
	LDA <PF2DataRAM-1,X       ;+4	15
	STA PF2                 ;+3  = *19*  < 40	;PF2 visible

	NOP			;+2	20
	NOP			;+2	22
	NOP			;+2	24
	NOP			;+2	26
	NOP			;+2	28
	NOP			;+2 	30
	NOP			;+2	32
	NOP			;+2	34
	
	LDA <PF1bDataRAM-1,X	;+4	38

	;PF1 no longer visible, safe to rewrite
	STA PF1			;+3 = *41*


	LDA <PF2bDataRAM-1,X	;+3     44
	
	;PF2 rewrite must begin at exactly cycle 45!!, no more, no less
	STA PF2			;+3  = *47*  ; > 46 PF2 no longer visible
	TXS			;+2	49
	NOP			;+2	51

	;preserve X register
				
	NOP			;+2	53
	NOP			;+2	55
	NOP			;+2	57
	NOP			;+2	59
	NOP			;+2	61
	NOP			;+2	63
	NOP			;+2	65
	NOP			;+2	67
	LDA #0			;+2	69
	; CLEAR OUT PLAYFIELD FOR SPRITE HANDLING BELOW
	STA PF2			;+3	72
	STA PF1			;+3	75	



	
	;PERFECT TIMING, NO WSYNC NECESSARY
	; PUT ONE BACK IN IF THE NOPs are replaced with code
	; that has varying timing
	
;START SECOND LINE OF LINE-PAIR
ScanGo2	; do all the sprite routines here
	; WSYNC PUT BACK IN IF NECESSARY
	; start cycle counting again
				; 	0

;CONVERTED CODE
P0Loop
	TYA			;+2	
	SEC			;+2
	SBC  P0_Y		;+3
	ADC #CarHeight+2	;+2
	BCC P1Loop		;+2/+3

	LDA (P0_CurrentFramePtr),Y ; +5
	;LDA #$FF		;+2
	
	STA GRP0		;+3
	
;				MAX 19 cycles
				;	19
P1Loop
	TYA			;+2	
	SEC			;+2
	SBC  P0_Y		;+3
	ADC #CarHeight+2	;+2
	BCC .endLoop		;+2/+3
	LDA (P1_CurrentFramePtr),Y 
	;LDA #$FF		;+2
	STA GRP1		;+3

.endLoop
	TSX; grab tombstone counter back again
	DEY ; Decrement ScanlinePair counter
	BNE ScanLoop1; keep going until scanline counter reaches 0
DoBorder
	LDA #$FF ; this may overload the timing of the sprite kernel line
		 ; and have to be moved under WSYNC!!

	STA WSYNC; finish last line of sprites
	STA PF0 ; draw a straight line
	STA PF1
	STA PF2
	STA WSYNC; line 1 of bottom border
	STA WSYNC; line 2 of bottom border

EndKernel
	STA VBLANK ; Make TIA output invisible,
	; Y is already zero
	STY PF0
	STY PF1
	STY PF2
	STY GRP0
	STY GRP1
	STY ENAM0
	STY ENAM1
	STY ENABL
	RTS; END DrawScreen

;THE GRAPHICS        
	org $FE00

scoreshapedata: 
		.byte %01000100 ; | X   X  |
                .byte %10101010 ; |X X X X |
                .byte %10101010 ; |X X X X |
                .byte %10101010 ; |X X X X |
                .byte %01000100 ; | X   X  |

                .byte %11001100 ; |XX  XX  |
                .byte %01000100 ; | X   X  |
                .byte %01000100 ; | X   X  |
                .byte %01000100 ; | X   X  |
                .byte %11101110 ; |XXX XXX |

                .byte %11101110 ; |XXX XXX |
                .byte %00100010 ; |  X   X |
                .byte %01100110 ; | XX  XX |
                .byte %10001000 ; |X   X   |
                .byte $11101110 ; |XXX XXX |

                .byte %11101110 ; |XXX XXX |
                .byte %00100010 ; |  X   X |
                .byte %01000100 ; | X   X  |
                .byte %00100010 ; |  X   X |
                .byte %11001100 ; |XX  XX  |

                .byte %10001000 ; |X   X   |
                .byte %10101010 ; |X X X X |
                .byte %11101110 ; |XXX XXX |
                .byte %00100010 ; |  X   X |
                .byte %00100010 ; |  X   X |

                .byte %11101110 ; |XXX XXX |
                .byte %10001000 ; |X   X   |
                .byte %11001100 ; |XX  XX  |
                .byte %00100010 ; |  X   X |
                .byte %11001100 ; |XX  XX  |

                .byte %01000100 ; | X   X  |
                .byte %10001000 ; |X   X   |
                .byte %11101110 ; |XXX XXX |
                .byte %10101010 ; |X X X X |
                .byte %11101110 ; |XXX XXX |

                .byte %11101110 ; |XXX XXX |
                .byte %00100010 ; |  X   X |
                .byte %01000100 ; | X   X  |
                .byte %10001000 ; |X   X   |
                .byte %10001000 ; |X   X   |

                .byte %11101110 ; |XXX XXX |
                .byte %10101010 ; |X X X X |
                .byte %11101110 ; |XXX XXX |
                .byte %10101010 ; |X X X X |
                .byte %11101110 ; |XXX XXX |

                .byte %11101110 ; |XXX XXX |
                .byte %10101010 ; |X X X X |
                .byte %11101110 ; |XXX XXX |
                .byte %00100010 ; |  X   X |
                .byte %01000100 ; | X   X  |

	org $FF00
;               REFLECTED  PLAYFIELD            
;                                               
; PF0|   PF1  |  PF2   ||   PF2b |   PF1b |PF0b|
;4567|76543210|01234567||76543210|01234567|7654|


;INITIAL TITLE GRAPHICS
;TO BE COPIED TO RAM

;SafeZone ;     7654----
;	.byte %10011001


PF1Data  ;D    76543210
	.byte %01111001
	.byte %01000101
	.byte %01000101
	.byte %01000101
	.byte %01111001
	.byte %00000000
	.byte %01111001
	.byte %01000101
	.byte %01000101
	.byte %01000101
	.byte %01111001

	
PF2Data  ;EA   01234567
	.byte %00101111
	.byte %10100000
	.byte %11100111
	.byte %00100000
	.byte %11101111
	.byte %00000000
	.byte %00101111
	.byte %00100000
	.byte %11100111
	.byte %00100000
	.byte %11101111	


PF2bData ;     76543210;<--- scanning order

	.byte %11011110
	.byte %00010001
	.byte %10011110
	.byte %01010001
	.byte %10011110
	.byte %00000000
	.byte %01000100
	.byte %01000100
	.byte %11000100
	.byte %01000100
	.byte %11011111

	
PF1bData;      01234567;<--- scanning order


	.byte %00111110
	.byte %00100000
	.byte %00111110
	.byte %00100010
	.byte %00100010
	.byte %00000000
	.byte %00100010
	.byte %00100010
	.byte %00111110
	.byte %00100010	
	.byte %00100010	


; THE ROTATION SEQUENCE POINTERS

; when writing the driving controller code, I will
; index through this table of pointers which rotates
; through the frames.  These pointers only store the low byte
; value.  The high value is always going to be $FF anyway.


; since the shapes are stored upside down, the actual orientation
; is indicated in the notes.  the shapes in the sourcecode will
; appear upside-down

RotationSequence
	;NO FLIP BIT - FACE RIGHT
	.byte <CarRotation0;0  - point up
	.byte <CarRotation1;1  - 
	.byte <CarRotation2;2  - 
	.byte <CarRotation3;3  - 
	.byte <CarRotation4;4  - point right
	.byte <CarRotation5;5  - 
	.byte <CarRotation6;6  - 
	.byte <CarRotation7;7  - 
	.byte <CarRotation8;8  - point down
	; WITH FlipThreshold - FACE LEFT
	.byte <CarRotation7;9  - 
	.byte <CarRotation6;10 - 
	.byte <CarRotation5;11 - 
	.byte <CarRotation4;12 - point left
	.byte <CarRotation3;13 - 
	.byte <CarRotation2;14 - 
	.byte <CarRotation1;15 - 

	
	org $FF00+CarDataAlign
	; make sure all sprite graphics are at least 'CarDataAlign' bytes
	; above the page in order to make sure that the vertical
	; logic routine will work properly


; THIS STORES HALF OF THE ROTATIONS.
; THE OTHER HALF ARE GENERATED BY USING THE HARDWARE PLAYER FLIP FUNCTION

; note that this rotation frame doesn't need an upside down version because it is symmetrical


;9 frames * 8 bytes per frame = 56 bytes used

CarRotation0;UP (ACTUAL)
  .byte %00000000
  .byte %01011010; .X.XX.X.
  .byte %01111110; .XXXXXX.
  .byte %01100110; .XX..XX.
  .byte %00011000; ...XX...
  .byte %01011010; .X.XX.X.
  .byte %01111110; .XXXXXX.
  .byte %01011010; .X.XX.X.
  .byte %00011000; ...XX...

CarRotation1
  .byte %00000000
  .byte %00000110; ....XX..
  .byte %00011110; ..XXXX..
  .byte %01110100; XXX.X...
  .byte %00011010; XX.XX.X.
  .byte %00011010; ...XX.X.
  .byte %01011111; .X.XXXXX
  .byte %00111100; ..XXXX..
  .byte %00101100; ..X.XX..

CarRotation2
  .byte %00000000
  .byte %00011000; ...XX...
  .byte %01111000; .XXXX...
  .byte %01000010; .X....X.
  .byte %11011011; XX.XX.XX
  .byte %11011100; XX.XXX..
  .byte %00011110; ...XXXX.
  .byte %00110110; ..XX.XX.
  .byte %00010000; ...X....

CarRotation3
  .byte %00000000
  .byte %00110000; ..XX....
  .byte %00110010; ..XX.X..
  .byte %01100011; .XX...XX
  .byte %01011110; .X.XXXX.
  .byte %11111111; XXXXXXXX
  .byte %11000111; XX...XXX
  .byte %00011100; ...XXX..
  .byte %00000100; .....X..

CarRotation4;RIGHT|LEFT  
  .byte %00000000
  .byte %00000000; ........
  .byte %11101110; XXX.XXX.
  .byte %01100100; .XX..X..
  .byte %11011111; XX.XXXXX
  .byte %11011111; XX.XXXXX
  .byte %01100100; .XX..X..
  .byte %11101110; XXX.XXX.
  .byte %00000000; ........

CarRotation5   
  .byte %00000000
  .byte %00000100; .....X..
  .byte %00011100; ...XXX..
  .byte %11000111; XX...XXX
  .byte %11111111; XXXXXXXX
  .byte %01011110; .X.XXXX.
  .byte %01100011; .XX...XX
  .byte %00110010; ..XX.X..
  .byte %00110000; ..XX....

CarRotation6
  .byte %00000000
  .byte %00010000; ...X....
  .byte %00110110; ..XX.XX.
  .byte %00011110; ...XXXX.
  .byte %11011100; XX.XXX..
  .byte %11011011; XX.XX.XX
  .byte %01000010; .X....X.
  .byte %01111000; .XXXX...
  .byte %00011000; ...XX...

CarRotation7   
  .byte %00000000
  .byte %00101100; ..X.XX..
  .byte %00111100; ..XXXX..
  .byte %01011111; .X.XXXXX
  .byte %00011010; ...XX.X.
  .byte %11011010; XX.XX.X.
  .byte %11101000; XXX.X...
  .byte %00111100; ..XXXX..
  .byte %00001100; ....XX..

CarRotation8;DOWN (ACTUAL)
  .byte %00000000
  .byte %00011000; ...XX...
  .byte %01011010; .X.XX.X.
  .byte %01111110; .XXXXXX.
  .byte %01011010; .X.XX.X.
  .byte %00011000; ...XX...
  .byte %01100110; .XX..XX.
  .byte %01111110; .XXXXXX.
  .byte %01011010; .X.XX.X.


  
  
;missiles are used as pseudoplayers
;data is encoded as width and pixel offsets.

;76543210
;XXXX    <- OFFSET (typically 0 through +8 pixels)
;    XX  <- NUSIZ data

;EXAMPLE:
;LDA (M0_ShapeFrame),Y	;
;STA HMM0		;
;LSL			;
;LSL			;
;STA NUSIZ0		;

;32 bytes used

Ped1_1;   OOOOWW__
   .byte %11110100 ; .XX.....
   .byte %11100000 ; ..X.....
   .byte %11011000 ; ...XXXX.
   .byte %11010100 ; ...XX...
   .byte %11111000 ; .XXXX...
   .byte %00000000 ; ........
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...
   
Ped1_2;   OOOOWW__
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...
   .byte %00000000 ; ........
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...

Ped1_3;   OOOOWW__
   .byte %11110100 ; .XX.....
   .byte %00000000 ; ..X.....
   .byte %11011100 ; ...XXXX.
   .byte %11100100 ; ..XX....
   .byte %11010100 ; ...XX...
   .byte %00000000 ; ........
   .byte %11010100 ; ...XX...
   .byte %11010100 ; ...XX...

Ped1_4;   OOOOWW__
   .byte %11011100 ; ...XXXX.
   .byte %11010000 ; ...X....
   .byte %11011100 ; ...XXXX.
   .byte %11010100 ; ...XX...
   .byte %00001100 ; XXXX....
   .byte %11101100 ; ..XXXX..
   .byte %11110100 ; .XX.....
   .byte %11110100 ; .XX.....





;add score graphics later	
	org $FFFC
        .word Start
        .word Start

Current Thread