; Stella Megademo part 2! ; This demo contains the most interesting demos posted to the Stellalist ; from the very beginning to December '99 in more or less chronological ; order. ; ; It compiles with DASM and is tested with Z26. ; No tests on the real thing, sorry. ; (Bug reports are only accepted when they include the fix :-)) ; ; Done by Manuel Polik (cybergoth@nexgo.de) ; ; Featured this time are: ; ; ################################################################### ; Matt by John Matthews ; ; It displays 'Matt' with playfield graphics and has rainbow colors ; scrolling through it. ; Actually I changed nearly 100% of the code, there's only ; the graphics left. ; And even these I turned upside down :-) ; ################################################################### ; Robbie by John Matthews ; ; It displays an animated robot sprite ; Again I changed 80% of the original code, I use only one variable ; instead of five. Most important I reduced the sprite data a lot, ; there's no need to have the robot body 4 times in the ROM... ; ################################################################### ; How To Draw A Playfield by Nick Bensema ; ; Vertical scrolling playfield demonstration saying 'Hello'. ; Only changed 20%. No need to do a lot, just removed some garbage and ; fixed a little bug :-) ; ################################################################### ; Another Playfield by Chris Cracknell ; ; Draws a Bat to the playfield and let's you move a 'Bira Bira' sprite ; around with the joystick ; ; I finally managed to code a working single line kernel for this ; ################################################################### ; Aaaargh by Chris Cracknell ; ; Moves both a friendly & an evil sprite left to right and back ; ; Rewrote it from scratch for space optimizing. ; ################################################################### ; Another Playfield code by Erik Mooney & Tennessee Carmel-Veilleux ; ; Another playfield variant. ; ; Did the usual space optimizing. ; Added the sound bit from Tennessee Carmel-Veilleuxs variant for ; the V2.0 of the Mega Demo ; ################################################################### ; X-Mas demo by Piero Cavino ; ; Brilliant thingy toying around with missiles. ; Prepare to get hypnotized! ; ; Didn't need to touch it at all, perfect code! ; ################################################################### ; Ruffin Bailys demo ; ; Some Playfield'n'Sprite work in progress he once sent to the list ; ; Being buggy work-in-progress code, I had to spend some time to get ; it working in a way I assumed it was intended to work. ; 100% rewrote the display kernel from scratch, but the joystick ; reading routines were already that brill! ; ################################################################### ; Sprites by Bob Colbert ; ; Shows 6 copies of player 0 bouncing around the screen. ; ; I did a lot of optimizing the needed space. The original code was ; very good, though - in fact the most advanced homebrew code I've seen ; so far... ; ################################################################### ; Big Move by Eckhard Stolberg ; ; Shows a movable(!) 6-char display. ; ; Did only the usual byte-saving here and there. ; ################################################################### ; Invaders by Eckhard Stolberg ; ; Shows 17 invaders at once! ; ; Only removed the crappy looking 18th invader ; ################################################################### ; Ship Demo by Kurt Woloch ; ; Shows a sinking PF ship and plays Celine Dion ; ; Didn't change it recognisable. ; ################################################################### ; Grid Demo by Gene Johannsen ; ; Shows a blinking Gridboard ; ; Didn't change it recognisable. ; ################################################################### ; Horizontal Scrolling Playfield Thing by by Rob Kudla ; ; Well... see its name :-) ; ; Did some little tweaking, because I thought the first line on ; top was crappy looking... ; ################################################################### ; Reserved Variables $80+$81 & $82 ; (These cannot be used within the demos) demoVector = $80 ; vector used to skip to the next demo switchesRead = $82 ; stores the value of the switches ; Variable for Matt demo topColor = $83 ; color at top of letters ; Variable for Robbie demo frameNumber = $83 ; Number of frames drawn. ; Variable for the Cavino X-Mas demo frameNumber = $83 ; Number of frames drawn. ; Variables for Ruffins demo ypos = $83 ; Variable for Nickfield demo verticalShift = $83 ; Offset of the playfield scrolling ; Variables for Aaaargh frameNumber = $83 ; Number of frames drawn. ; Variables for Another VERTPOS = $83 ;This is the vertical position of the sprite ; Variables for Sprites demo MAXSPRITE = $05 hpos = $83 ; horizontal position of sprites 0 - 5 vpos = $89 ; vertical position of sprites 0 - 5 vline = $A0 ; current vertical line being drawn sprhmot = $A1 ; vertical motion for sprite 0 - 5 sprvmot = $A7 ; horizontal motion for sprite 0 - 5 flglst = $C0 ; 0 - 5 nxtsprt = $C8 ; 0 - 5 curclr = $D0 ; current color(?) p0count = $D1 ; number of lines left to draw for player 0 sprtptr = $D2 ; pointer to current sprite tempVar = $D3 ; temp variable tempVar2 = $D4 ; another temp variable sprtlst = $D6 ; list of sprites to draw 0 - 5 ; Variables for Big Move demo s3 = $84 s4 = $86 s5 = $88 s6 = $8A DelayPTR = $8C LoopCount = $8E BottomDelay = $90 Temp = $92 s1 = $94 s2 = $96 MoveCount = $E0 TopDelay = $E1 ; Variables for Ship demo SoundCount = $83 DecayCount = $84 SinkLinesL = $85 SinkLinesH = $86 SinkCount = $87 ;This counts the frames until the ship goes down again by SinkLevel = $88 ;This counts the lines remaining from the ship display. ShipTemp = $89 PlayfieldY = $90 ; Ship colors White = $0E Red = $46 Pink = $4E Yellow = $1E Brown = $20 Skyblue = $9C Waterblue = $88 Shadowblue = $80 ; Invaders variables PTR18 = $83 ; pointer to graphics for 18 sprites display HideGFX = $85 ; bitmap to put over 18 sprites display ShowCount = $8A ; display this many sprites SaveStack = $8B ; holds stack pointer during 18 sprites disp. LastJoy = $8C ; last joystick value AnimCount = $8D ; change animation frame when zero ; Grid equates red = %00110010 orange = %00010110 yellow = %00011010 green = %11000010 blue = %01110010 purple = %01010100 black = %00000000 squarerows = 30 ; number of scan lines to make a square. ; Grid variables gbcounter = $83 ; Which piece in the gameboard rowcounter = $84 ; Which scanline are we on tmp = $85 ; tmp location for swap rndl = $86 ; for random number generating routine rndh = $87 ; for random number generating routine gameboard = $88 ; The gameboard itself ramdrawline = $C9 ; ; RobField variables CurrentFrame = $83 CurrentPFPtr = $84 PF0Data = $85 PF1Data = $86 PF2Data = $87 PFCarry = $88 ; Code Begin processor 6502 include vcs.h ORG $F000 ; This part is the Matt demo Start JMP MattReset ; Reset everything for Matt MattLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR MattScreen ; MattScreen does Overscan BEQ MattLoop ; Repeat ORG $F010 ; This part is the Robbie demo (There's no need to reset anything) RobbieLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR RobbieScreen ; RobbieScreen does Overscan BEQ RobbieLoop ; Repeat ORG $F020 ; This part is the Cavino X-Mas demo (There's no need to reset anything) XmasLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR XmasScreen ; XmasScreen does Overscan BEQ XmasLoop ; Repeat ORG $F030 ; This part is the Cavino X-Mas demo (There's no need to reset anything) RuffinLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR RuffinScreen ; RuffinScreen does Overscan BEQ RuffinLoop ; Repeat ORG $F040 ; This part is the How To Draw A Playfield demo (no reset, too) NickFieldLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR NickFieldScreen ; NickFieldScreen does Overscan BEQ NickFieldLoop ; Repeat ORG $F050 ; This part is the Aaaargh demo (There's no need to reset anything) LDA #$01 STA CTRLPF AaaarghLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR AaaarghScreen ; AaaarghScreen does Overscan JMP AaaarghLoop ; Repeat ORG $F060 ; This part is the Another demo (reset bit done right here) LDA #$60 ; STA VERTPOS ; Starting vertical position AnotherLoop JSR VerticalSync ; Common vertical sync JSR AnotherVBlank ; Another vertical blank JSR AnotherScreen ; AnotherScreen does Overscan JMP AnotherLoop ; Repeat ORG $F070 ; This part is the How To Draw A Playfield 2 demo (no reset, too) ErikFieldLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR ErikFieldScreen ; ErikFieldScreen does Overscan BEQ ErikFieldLoop ; Repeat ORG $F080 ; This part is the Sprites demo JSR SpritesReset SpritesLoop JSR VerticalSync ; Common vertical sync JSR SpritesVBlank ; Sprites vertical blank JSR SpritesScreen ; SpritesScreen does Overscan JMP SpritesLoop ; Repeat ORG $F090 ; This part is the BigMove demo JSR BigMoveReset BigMoveLoop JSR VerticalSync ; Common vertical sync JSR BigMoveVBlank ; BigMove vertical blank JSR BigMoveScreen ; BigMoveScreen does Overscan JMP BigMoveLoop ; Repeat ORG $F0A0 ; This part is the Ship demo JSR ShipReset ShipLoop JSR VerticalSync ; Common vertical sync JSR ShipVBlank ; Ship vertical blank JSR ShipScreen ; ShipScreen does Overscan JMP ShipLoop ; Repeat ORG $F0B0 ; This part is the Invaders demo JSR InvadersReset InvadersLoop JSR VerticalSync ; Common vertical sync JSR InvadersVBlank ; Invaders vertical blank JSR InvadersScreen ; InvadersScreen does Overscan JMP InvadersLoop ; Repeat ORG $F0C0 ; This part is the Grid demo JSR GridReset GridLoop JSR VerticalSync ; Common vertical sync JSR VerticalBlank ; Do-nothing vertical blank JSR GridScreen ; GridScreen does Overscan JMP GridLoop ; Repeat ORG $F0D0 ; This part is the RobField demo JSR RobFieldReset RobFieldLoop JSR VerticalSync ; Common vertical sync JSR RobFieldVBlank ; RobField vertical blank JSR RobFieldScreen ; RobFieldScreen does Overscan JMP RobFieldLoop ; Repeat ORG $F0E0 ; Loop to the beginning LDA #$00 STA demoVector JMP (demoVector) ; This is the one & only vertical sync. Every demo uses it VerticalSync LDA #$02 ; STA WSYNC ; Finish current line STA VSYNC ; start vertical sync LDA #$03 ; STA TIM64T ; LDA SWCHB ; Reset/Select button.... CMP switchesRead ; same as last read? BEQ WaitVSync ; Y: Continue STA switchesRead ; N: Store new value LSR ; Reset? BCS NoReset ; N: Continue JMP Start ; Y: Start over NoReset LSR ; Select? BCS WaitVSync ; N: Continue with vertical sync LDA demoVector ; Skip to next demo ADC #$10 ; STA demoVector ; LDX #$FF ; TXS ; Restore Stack STA VSYNC ; stop vertical sync JMP (demoVector) ; Jump to the next demo WaitVSync JMP WaitIntimReady ; Wait until vertical sync finished ; This is the standard do-nothing vertical blank VerticalBlank JSR VBlankInit ; WaitIntimReady LDA INTIM ; Wait until vertical blank finished BNE WaitIntimReady ; RTS ; This wastes X Lines Waste STA WSYNC ; Waste a line DEX ; BNE Waste ; if X is not zero, do more lines RTS ; This positions a player PosPlayer1 STA WSYNC PosPlayer2 DEX ; BNE PosPlayer2 ; kill some time... STA RESP0 ; start player 0 at this point RTS ; This is a usual vertical Blank init VBlankInit STA WSYNC ; Finish current line STA VSYNC ; Stop vertical sync LDA #$02 ; STA VBLANK ; Start vertical blank LDA #$2B ; STA TIM64T ; Init timer RTS ; This resets the Matt demo MattReset SEI ; Disable interrupts CLD ; Binary mode LDY switchesRead ; LDX #$00 ; LDA #$00 ; Clearloop STA VSYNC,X ; TXS ; Sets stack to #$FF at end of loop INX ; BNE Clearloop ; zero out the zero page LDA #$F0 ; STA demoVector+1 ; Init the demoVector STY switchesRead ; JMP MattLoop ; ; This builds the screen for the Matt demo: MattScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank INC topColor ; Increment to new top color LDA topColor ; Load it LDX #20 ; JSR Waste ; Waste 32 lines LDX #$1F ; 32 playfield lines DrawMatt LDY matttable,X ; get the current line of playfield STY PF1 ; store it in playfield 1 STY PF2 ; store it in playfield 2 LDY #$04 ; Lines STA COLUPF ; store in playfield register STA WSYNC ; Finish current line ADC #$01 ; increase by one DEY ; BNE Lines ; DEX ; decrease X by one BPL DrawMatt ; draw next 4 lines LDX #$4A ; Waste lines to complete 262 JMP Waste ; (Finish Screen / Overscan) matttable .byte $00 ; ........ .byte $03 ; ......xx .byte $01 ; .......x .byte $01 ; .......x .byte $01 ; .......x .byte $01 ; .......x .byte $09 ; ....x..x .byte $0F ; ....xxxx .byte $00 ; ........ .byte $03 ; ......xx .byte $01 ; .......x .byte $01 ; .......x .byte $01 ; .......x .byte $01 ; .......x .byte $09 ; ....x..x .byte $0F ; ....xxxx .byte $00 ; ........ .byte $0C ; ....xx.. .byte $0C ; ....xx.. .byte $0C ; ....xx.. .byte $0F ; ....xxxx .byte $0C ; ....xx.. .byte $07 ; .....xxx .byte $03 ; ......xx .byte $00 ; ........ .byte $0C ; ....xx.. .byte $0C ; ....xx.. .byte $0C ; ....xx.. .byte $0D ; ....xx.x .byte $0F ; ....xxxx .byte $0E ; ....xxx. .byte $0C ; ....xx.. ; This builds the screen for the Robbie demo: RobbieScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank LDX #$08 ; LDA frameNumber ; ROL ; BCS DontTurn ; LDX #$F7 ; This sequence makes robot turn DontTurn STX REFP0 ; every 128 frames LDX #$20 ; Waste 32 Lines JSR Waste ; LDX #$05 ; JSR PosPlayer1 STA WSYNC ; Finish current line LDA #$A2 ; STA COLUP0 ; make robot grey LDX #$08 ; Body LDA robbiedata,X ; STA GRP0 ; STA WSYNC ; DEX ; BPL Body ; Draw robot body line by line LDA #$1F ; STA COLUP0 ; make chains yellow LDA frameNumber ; Get current frame number AND #$0C ; Mask '....xx..' TAX ; We use the Offsets 0, 4, 8, 12 LDY #$04 ; They change every fourth frame Chaines LDA chaindata,X ; -> Perfect for smooth animation! STA GRP0 ; store this line of data in player graphic 0 register STA WSYNC ; done with this line INX ; Next line DEY ; BNE Chaines ; Draw Chaines STY GRP0 ; Clear Sprite INC frameNumber ; One frame done NextScr LDX #$AF ; Waste lines to complete 262 JMP Waste ; (Finish Screen / Overscan) robbiedata .byte $18 ; ...xx... .byte $99 ; x..xx..x .byte $BD ; x.xxxx.x .byte $FF ; xxxxxxxx .byte $7E ; .xxxxxx. .byte $18 ; ...xx... .byte $78 ; .xxxx... .byte $78 ; .xxxx... .byte $38 ; ..xxx... chaindata .byte $76 ; .xxx.xx. .byte $29 ; ..x.x..x .byte $94 ; x..x.x.. .byte $6E ; .xx.xxx. .byte $3A ; ..xxx.x. .byte $A9 ; x.x.x..x .byte $95 ; x..x.x.x .byte $5C ; .x.xxx.. .byte $5C ; .x.xxx.. .byte $A9 ; x.x.x..x .byte $95 ; x..x.x.x .byte $3A ; ..xxx.x. .byte $6E ; .xx.xxx. .byte $A8 ; x.x.x... .byte $15 ; ...x.x.x .byte $76 ; .xxx.xx. ; This builds the screen for the Nickfield demo: NickFieldScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank LDA #$02 ; STA CTRLPF ; Display playfield in score mode LDY #192 ; NickLoop TYA ; SBC verticalShift ; LSR ; Divide by 4 LSR ; AND #7 ; X values ranging from 0-7 TAX ; STA WSYNC ; Finish current line LDA nicklcolor,X ; STA COLUP0 ; New left color LDA nickpfdata0,X ; STA PF0 ; LDA nickpfdata1,X ; STA PF1 ; LDA nickpfdata2,X ; STA PF2 ; New playfield data LDA nickrcolor,X; STA COLUP1 ; New right color DEY BNE NickLoop STA WSYNC ; Finish current line STY PF0 ; STY PF1 ; STY PF2 ; Clear playfield INC verticalShift ; LDX #$1D ; Waste 29 lines JMP Waste ; (Overscan) nickpfdata0 .byte $00 ; ........ .byte $f0 ; xxxx.... .byte $00 ; ........ .byte $A0 ; x.x..... .byte $A0 ; x.x..... .byte $E0 ; xxx..... .byte $A0 ; x.x..... .byte $A0 ; x.x..... nickpfdata1 .byte $00 ; ........ .byte $FF ; xxxxxxxx .byte $00 ; ........ .byte $77 ; .xxx.xxx .byte $44 ; .x...x.. .byte $64 ; .xx..x.. .byte $44 ; .x...x.. .byte $74 ; .xxx.x.. nickpfdata2 .byte $00 ; ........ .byte $FF ; xxxxxxxx .byte $00 ; ........ .byte $EE ; xxx.xxx. .byte $A2 ; x.x...x. .byte $A2 ; x.x...x. .byte $A2 ; x.x...x. .byte $E2 ; xxx...x. nicklcolor .byte $00,$FF,$00,$22,$26,$2A,$2C,$2E nickrcolor .byte $00,$1F,$00,$6E,$6C,$6A,$66,$62 AaaarghScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank lda #$96 ; Set Player color sta COLUP0 ; LDA frameNumber ; LSR LSR LSR LSR TAX ADC #$08 AND #$0F TAY LDA AaaarghTab,x TAX LDA AaaarghTab,y PHA JSR PosPlayer1 ; STA WSYNC ; Set player position ldx #$08 ; 9 Spritelines ldy #$08 ; Offset 9 JSR DrawFoePlayer ; Draw player lda #$38 ; sta COLUP0 ; Set foe color PLA TAX JSR PosPlayer1 ; STA WSYNC ; Set foe position ldx #$08 ; 9 Spritelines ldy #$11 ; Offset 18 JSR DrawFoePlayer ; Draw foe LDX #$C8 ; INC frameNumber ; JMP Waste ; DrawFoePlayer lda sprt1,y ; sta GRP0 ; sta WSYNC ; dey ; dex ; bpl DrawFoePlayer ; rts ; AaaarghTab .byte $05,$06,$07,$08,$09,$0A,$0B,$0C,$0C,$0B,$0A,$09,$08,$07,$06,$05 sprt1 .byte $00 ;........ .byte $66 ;.xx..xx. .byte $24 ;..x..x.. .byte $3C ;..xxxx.. .byte $18 ;...xx... .byte $18 ;...xx... .byte $FF ;xxxxxxxx .byte $3C ;..xxxx.. .byte $3C ;..xxxx.. sprt2 .byte $00 ;........ .byte $AA ;x.x.x.x. .byte $AA ;x.x.x.x. .byte $FF ;xxxxxxxx .byte $FF ;xxxxxxxx .byte $BB ;x.xxx.xx .byte $99 ;x..xx..x .byte $7E ;.xxxxxx. .byte $3C ;..xxxx.. ; This is the Another vertical blank AnotherVBlank JSR VBlankInit; LDA #$4F ;screen variables should clean this up later... STA COLUPF LDA #$32 ; STA COLUP0 ; Sprite colour LDY #$BF JMP WaitIntimReady AnotherScreen STA WSYNC ; Finish current line STA HMOVE STA WSYNC STA VBLANK ; Stop vertical blank AnotherDraw1 LDA #$00 BEQ AnotherContinue load STA WSYNC LDX #$00 TYA SEC SBC VERTPOS ADC #$1B BCC AnotherDraw1 TAX LDA p0data,X ;If not then load the sprite data. AnotherContinue STA GRP0 TYA LSR LSR LSR TAX LDA playf0,X STA PF0 LDA playf1,X STA PF1 LDA playf2,X STA PF2 DEY BNE load ;get ready for next scanline oscan2 JSR joy ;overscan. Time to read the joysticks. STY HMP0 LDX #$1E JMP Waste joy LDY #$00 LDA SWCHA ASL BCC right ASL BCC left ASL BCC down ASL BCC up RTS right LDY #$f0 ;set horizontal motion register to one pixel right rts left LDY #$10 ;set horizontal motion register to one pixel left rts up LDA VERTPOS ;make sure we haven't gone over the top of the screen CMP #$B0 BEQ NoClimb INC VERTPOS ;if not then increase the vertical position NoClimb RTS down LDA VERTPOS CMP #$20 BEQ NoSink DEC VERTPOS ;decrease the vertical position NoSink RTS playf0 .byte $00 ;playfield data... you know. That "BAT" .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $20 .byte $20 .byte $70 .byte $f0 .byte $f0 .byte $f0 .byte $e0 .byte $e0 .byte $c0 .byte $80 .byte $00 .byte $00 .byte $00 playf1 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $00 .byte $10 .byte $10 .byte $11 .byte $3b .byte $7b .byte $ff .byte $ff .byte $ff .byte $ff .byte $ff .byte $ff .byte $ff .byte $7c .byte $30 playf2 .byte $00 .byte $00 .byte $80 .byte $80 .byte $c0 .byte $c0 .byte $c0 .byte $e2 .byte $e2 .byte $f2 .byte $fa .byte $ff .byte $ff .byte $bf .byte $bf .byte $7f .byte $df .byte $cf .byte $a7 .byte $93 .byte $71 .byte $38 .byte $0c .byte $04 p0data .byte $00 ;sprite data. Stored upside down. BIRA BIRA! .byte $ff .byte $81 .byte $ff .byte $ff .byte $ff .byte $7e .byte $7e .byte $7e .byte $7e .byte $3c .byte $ff .byte $81 .byte $ff .byte $ff .byte $e7 .byte $66 .byte $3c .byte $3c .byte $42 .byte $7e .byte $42 .byte $ff .byte $99 .byte $66 .byte $99 .byte $ff .byte $ff ErikFieldScreen LDA SWCHA ;Read joystick 0 AND #$F0 ;Only care about top four bits, which is joystick 0 CMP #$F0 ;If top four=1111, stick centered, don't change BNE Stick TXA Stick STA COLUBK LDA #$55 ;Alternate pixels: 01010101 = $55 STA PF0 STA PF2 ;Store alternating bit pattern to the playfield registers ASL ;Because PF1 displays in the opposite bit order from PF0 STA PF1 ;and PF2, we need 10101010 instead of 01010101. INC frameNumber LDA frameNumber AND #$1F ; Get a 0-31 (5 bits) value for divider from y line STA AUDF0 ; Set frequency divider AND #$0F ; Get a 0-15 (4 bits) value for volume from y line STA AUDV0 ; Set audio volume LDA #$04 ; Pur 4 into A STA AUDC0 ; Set audio control to 0 (divide by 1) STA WSYNC ;End the current scanline - the last line of VBLANK. STA VBLANK ;End the VBLANK period. The TIA will display stuff LDY #192 ;We're going to use Y to count scanlines. ScanLoop STY COLUPF ;Keep changing the playfield color every line STA WSYNC ;Wait for end of scanline DEY BNE ScanLoop ;Count scanlines. LDA #$02 ; STA VBLANK ; Start vertical blank LDX #$1D ; Overscan JMP Waste ; ; This builds the screen for the Xmas demo: XmasScreen STA WSYNC LDX #7 LPP: DEX BPL LPP STA RESM1 STA RESM0 STA HMCLR STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank LDA #$FF STA ENAM1 STA ENAM0 INC frameNumber LDX #191 LK: TXA ADC frameNumber ASL ASL STA HMM1 EOR #$FF STA HMM0 STA COLUP1 STA COLUP0 STA WSYNC STA HMOVE DEX BNE LK STX ENAM1 STX ENAM0 LDX #$1E ; Waste 174 lines JMP Waste ; (Finish Screen / Overscan) ; This builds the screen for Ruffins demo: RuffinScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank lda #%10001000 ; hopefully this is mid-lum blue sta COLUP0 ; this is the temp color for the bean lda #%00110110 ; sta COLUPF ; this is the pf (platform) color lda CXP0FB ; this byte holds the collision registers for Player asl bcs joycheck ; if D7=1 there is a collision and gravity should be DEC ypos ; gravity moves the player down one scan line. joycheck LDY #$00 lda SWCHA ; load the byte that holds the joystick input bmi next ; if D7 is a 1, P0 stick doesn't point right ldy #%11110000 ; this will be a -1 movement (to the right) next rol ; shuffle the bits to the left. bmi next2 ; if D6 isn't zero, head to the next check ldy #%00010000 ; switching D7 from 1 to a 0 makes this a +1 movement next2 sty HMP0 ; store in Horizontal Movement Player Zero rol bmi next3 DEC ypos DEC ypos next3 rol bmi endofchk ; if D4 isn't latched, that's the last bit in SWCHA that INC ypos INC ypos endofchk sta WSYNC sta HMOVE LDA #0 STA CXCLR ; collison register LDY #$BF NextLine STA WSYNC LDX #$00 TYA SBC ypos ADC #$10 BCC RuffinDraw1 LDX #%10100101 RuffinDraw1 STX GRP0 LDA #$00 CPY #$60 BCS RuffinDraw2 LDA #%11111111 RuffinDraw2 STA PF1 DEY BNE NextLine STA HMCLR STY GRP0 STY PF1 LDX #$1E ; Waste 30 lines JMP Waste ; (Finish Screen / Overscan) ; This resets the Sprites demo SpritesReset LDA #$01 ; STA CTRLPF ; set background control register LDA #$43 ; STA COLUPF ; Make Playfield red LDA #$00 STA PF0 STA PF2 STA AUDV0 ; Clear audio volume LDX #$05 ; 6 sprites to init SpritesInit LDA isprvpos,x ; STA vpos,x ; Init vertical position LDA isprhpos,x ; STA hpos,x ; Init horizontal position LDA isprvmot,x ; STA sprvmot,x ; Init vertical movement LDA isprhmot,x ; STA sprhmot,x ; Init horizontal movement DEX ; BPL SpritesInit ; RTS ; This is the Sprites vertical blank SpritesVBlank JSR VBlankInit ; LDA #$38 ; STA tempVar2 ; Max vertical screen position LDX #$0B ; 12 Positions to update MoveXVertical JSR MoveX ; DEX ; CPX #$05 ; BNE MoveXVertical ; First move 6 times vertical LDA #$9C ; STA tempVar2 ; Max horizontal screen position MoveXHorizontal JSR MoveX ; TXA ; STA sprtlst,x ; Reset spritelist for sort DEX ; BPL MoveXHorizontal ; Then move 6 times horizontal STX tempVar2 ; Init TempVar2 with #FF before sort srtsprt ldx #MAXSPRITE-1 ; srtloop ldy sprtlst,x ;4 lda vpos,y ;4 ldy sprtlst+1,x ;4 cmp vpos,y ;4 bpl noswtch ;2/3 = 18/19 lda sprtlst,x ;4 sty sprtlst,x ;4 sta sprtlst+1,x ;4 noswtch dex ;2 cpx tempVar2 ; bne srtloop ;2/3 = 37/38 inc tempVar2 ; lda tempVar2 ; cmp #MAXSPRITE-1 ; bne srtsprt ;2/3 = 42/43 JSR pri0 ; JSR res0 ; JSR zrtsprt ; JMP WaitIntimReady ; Finish vertical blank ; This builds the screen for the Sprites demo: SpritesScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank ldx #$0 stx sprtptr LDX #$34 ; number of lines to draw on screen stx vline stx PF1 ; LDX #$FF ; STX TIM64T ; Init timer Loop3 STY WSYNC ; wait for horizontal sync Loop3a lda vline sta PF1 ; change a background pattern with each line ldy sprtptr lda nxtsprt,y bmi notstart tax lda xcolor,x sta curclr lda vline cmp vpos,x bne notstart lda p0count bne notstart2 sta WSYNC lda #$8 sta p0count lda hpos,x jsr calcpos sta HMP0 lda #$0 sta GRP0 iny iny iny sta WSYNC resloop0 dey bpl resloop0 sta RESP0 sta WSYNC sta HMOVE dec vline bne Loop3a notstart lda p0count notstart2 tay beq nodraw1 dec p0count lda curclr sta COLUP0 lda shape,y tay nodraw1 sta WSYNC sty GRP0 sta WSYNC jsr drawplr BNE Loop3 STA PF1 ; Clear playfield for next demo JSR WaitIntimReady ; Finish vertical blank LDX #$08 JMP Waste drawplr lda p0count tay beq nodraw LDA #$0 sta tempVar dec p0count bne ndr2 inc tempVar ndr2 lda shape,y tay nodraw sta WSYNC sty GRP0 dec vline ldx sprtptr lda tempVar beq nxt inx cpx #MAXSPRITE+1 bne ndr1 ldx #$0 ndr1 lda nxtsprt,x tay lda vline cmp vpos,y bne endraw nxt stx sprtptr endraw ldx sprtptr lda vline rts calcpos TAY ;2 INY ;2 TYA ;2 AND #$0F ;2 STA tempVar ;3 TYA ;2 LSR ;2 LSR ;2 LSR ;2 LSR ;2 TAY ;2 CLC ;2 ADC tempVar ;3 CMP #$0F ;2 BCC nextpos ;2 SBC #$0F ;2 INY ;2 nextpos EOR #$07 ;2 ASL ;2 ASL ;2 ASL ;2 ASL ;2 RTS ;6 zrtsprt ldx #$0 ldy #$0 zrtloop lda flglst,x and #$40 bne zrt1 lda sprtlst,x sta nxtsprt,y lda flglst,x ora #$80 sta flglst,x iny zrt1 lda flglst,x and #$8f sta flglst,x inx cpx #MAXSPRITE+1 bne zrtloop cpy #MAXSPRITE+1 beq zrt2 lda #$ff sta nxtsprt,y zrt2 rts res0 lda #$0 ; sta tempVar ; first conflicting sprite sta tempVar2 ; last sprite drawn ldx #MAXSPRITE ; res1 lda flglst,x ; get sprite # cmp #$20 ; check bit 5 bne res2 ; if conflict go to res2 ldy tempVar2 ; cpy #$1 ; bne res1a ; TXA ; TAY ; Copy X to Y JMP res1b ; To missuse res1a ending res1a ldy tempVar ; was there a conflict before? beq res5 ; nope get otta here ora #$40 ; sta flglst,x ; set the "don't draw" flag ldy tempVar2 ; we're at the last conflicting sprite bmi res6 ; if a sprite has been chosen, get out ldy tempVar ; get first sprite w/conflict res1b lda flglst,y ; and #$bf ; clear the "don't draw" flag sta flglst,y ; jmp res6 ; res2 ora #$40 ; sta flglst,x ; set "don't draw" flag ldy tempVar ; check to see if first conflict bne res3 ; nope, go to res3 stx tempVar ; yep, save table index in tempVar res3 and #$80 ; was it drawn? beq res4 ; nope, go to res4 lda #$1 ; sta tempVar2 ; found 1 drawn, next non-drawn is o.k. bne res5 ; res4 lda tempVar2 ; see if drawn sprite found cmp #$1 ; beq res4a ; yes bne res5 ; res4a lda flglst,x ; get sprite # and #$bf ; clear "don't draw" flag sta flglst,x ; lda #$81 ; sta tempVar2 ; bne res5 ; res6 lda #$0 ; sta tempVar ; sta tempVar2 ; res5 lda flglst,x ; and #$4f ; change to 4f sta flglst,x ; dex ; bpl res1 ; rts ; pri0 lda #$38 ; sta tempVar ; ldx #$0 ; pri1 lda sprtlst,x ; Get first sprite # tay ; lda vpos,y ; Get sprite y's vpos cmp tempVar ; Compare to current line bpl pri2 ; If there is a conflict go to pri2 sbc #$7 ; sta tempVar ; Save as next possible vpos pri5 inx ; cpx #MAXSPRITE+1 ; bne pri1 ; rts ; pri2 lda flglst,x ; get sprite # ora #$20 ; Set "conflict" flag sta flglst,x ; bne pri5 ; MoveX LDA hpos,x ; Load x or y position of sprite CLC ; ADC sprhmot,x ; move it CMP #$8 ; upper/left border reached? BEQ TurnX ; Y: Turn around CMP tempVar2 ; lower/right border reached? BNE StorePosX ; N: Store the position TurnX LDA #$0 ; SBC sprhmot,x ; STA sprhmot,x ; Swap sign of movement (+-) BNE MoveX ; Erase Move StorePosX STA hpos,x ; RTS ; shape .byte $00 ;........ .byte $81 ;x......x .byte $42 ;.x....x. .byte $24 ;..x..x.. .byte $18 ;...xx... .byte $24 ;..x..x.. .byte $42 ;.x....x. .byte $81 ;x......x .byte $00 ;........ isprhpos .byte $30,$40,$22,$28,$12,$50 isprvpos .byte $30,$32,$20,$28,$18,$10 isprhmot .byte $1,$FE,$FF,$2,$FF,$1 isprvmot .byte $ff,$1,$1,$ff,$1,$ff xcolor .byte $0e,$73,$16,$33,$22,$12 ; This is the Big Move vertical blank BigMoveVBlank JSR VBlankInit ; Joystick: LDA #$80 BIT SWCHA BEQ Right LSR BIT SWCHA BEQ Left LSR BIT SWCHA BEQ Down LSR BIT SWCHA BEQ UP JMP WaitIntimReady ; Finish vertical blank UP: LDA TopDelay BEQ U1 DEC TopDelay INC BottomDelay U1: JMP WaitIntimReady ; Finish vertical blank Down: LDA BottomDelay BEQ D1 INC TopDelay DEC BottomDelay D1: JMP WaitIntimReady ; Finish vertical blank Right: LDX MoveCount INX STX MoveCount CPX #3 BNE R2 LDX DelayPTR DEX STX DelayPTR CPX #BMData STA s1+1 STA s2+1 STA s3+1 STA s4+1 STA s5+1 STA s6+1 LDA #JNDelay STA DelayPTR+1 LDA #Graphics sta PTR18+1 sta WSYNC sta RESBL ; position ball over 1st sprite RTS ; This is the Invaders vertical blank InvadersVBlank JSR VBlankInit lda SWCHA and #%11000000 ; right & left of player0 cmp LastJoy beq JEnd sta LastJoy lda LastJoy bpl InvRight asl bpl InvLeft JEnd: jmp VblankLoop InvRight: ldx ShowCount dex bpl InvR1 jmp VblankLoop InvR1: jmp ChangeGFX InvLeft: ldx ShowCount inx cpx #18 bne ChangeGFX jmp VblankLoop ChangeGFX: stx ShowCount lda HideData1,x sta HideGFX lda HideData2,x sta HideGFX+1 lda HideData3,x sta HideGFX+2 lda HideData4,x sta HideGFX+3 lda HideData5,x sta HideGFX+4 VblankLoop: JMP WaitIntimReady ; This builds the screen for the Invaders demo: InvadersScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank lda HideGFX+2 sta PF0 tsx stx SaveStack ldx #%00000010 ; enable ball, when leftmost (18th) lda ShowCount ; sprite is invisible cmp #18 bne H0 ldx #0 H0: stx ENABL ldx HideGFX+4 txs ldy #12 sta WSYNC H1: lda (PTR18),y sta GRP0 asl ; make up for uneven sprite positioning sta GRP1 lda HideGFX+1 ldx HideGFX+3 sta RESP0 sta RESP1 sta RESP0 ; create multiple sprites by hitting RESPx sta RESP1 ; before all 3 copies have been drawn sta PF2 nop sta RESP0 ; again sta RESP1 stx PF1 nop sta RESP0 ; and again sta RESP1 tsx stx PF2 sta RESP0 ; and again sta RESP1 lda HideGFX sta.a PF1 ; absolute addressing to waste an extra cycle dey bpl H1 ldx SaveStack txs ldy #179 H2: sta WSYNC dey bne H2 lda #$02 sta VBLANK OverscanStart: lda #35 ;skip 30 lines (overscan) sta TIM64T Animate: lda AnimCount ; flip between animation frames clc ; every 32 TV frames adc #$08 sta AnimCount bne OverscanLoop lda PTR18 eor #$10 sta PTR18 OverscanLoop: JMP WaitIntimReady ; This resets the Grid demo GridReset LDX #[enddrawline - drawline] copyloop LDA drawline,X STA ramdrawline,X DEX BPL copyloop LDX #47 outergb LDY #6 innergb STY gameboard,X DEX BMI doneinitgb DEY BEQ outergb BNE innergb doneinitgb LDY #$F0 STY rndl ; Seed random number generator. LDY #$00 STY PF0 STY PF1 STY PF2 STY ENABL RTS ; This builds the screen for the Grid demo: GridScreen STA WSYNC ; Finish current line STA VBLANK ; Stop vertical blank STA gbcounter LDY #1 LDX #[squarerows * 6] scanloop STA WSYNC DEY BNE drawclrs STX rowcounter LDY gbcounter LDX gameboard,Y LDA colorchart,X STA [ramdrawline+1] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+5] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+9] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+13] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+17] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+21] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+25] INY LDX gameboard,Y LDA colorchart,X STA [ramdrawline+29] INY STY gbcounter LDY #[squarerows - 1] LDX rowcounter DEX DEX BNE scanloop JMP overscan drawclrs LDA VSYNC NOP NOP NOP JMP ramdrawline ; Go to the routine in RAM to change the background colors rdlreturn ; ramdrawline jmps here when it is done DEX BNE scanloop overscan JSR rnd48 TAY JSR rnd48 TAX JSR swap JSR rnd48 TAY JSR rnd48 TAX JSR swap JSR rnd48 TAY JSR rnd48 TAX JSR swap LDX #$20 JMP Waste ; Swap two squares in the gameboard. X and Y hold the squares that will swap. swap LDA gameboard,X STA tmp LDA gameboard,Y STA gameboard,X LDA tmp STA gameboard,Y RTS ; Generate a random number rnd LDA rndl LSR LSR SBC rndl LSR ROR rndh ROR rndl LDA rndl RTS drawline ; This routine will be copied from ROM into RAM colorcode LDA #$20 ; These numbers are meaningless since they will be overwritten in RAM STA COLUBK LDA #$40 STA COLUBK LDA #$20 STA COLUBK LDA #$40 STA COLUBK LDA #$20 STA COLUBK LDA #$40 STA COLUBK LDA #$20 STA COLUBK LDA #$40 STA COLUBK LDA #$00 STA COLUBK JMP rdlreturn enddrawline colorchart .byte black, yellow, blue, green, red, orange, purple, black ; This resets the RobField demo RobFieldReset LDA #$36 ; a nice shade of red STA COLUPF LDA #$0f STA COLUBK LDA #$f0 STA PF0Data LDA #$83 STA PF1Data LDA #$07 STA PF2Data ; set up initial playfield RTS ; This is the RobField vertical blank RobFieldVBlank JSR VBlankInit LDA PF0Data EOR #$FF AND #$F0 STA PF0Data ; reverse PF0 LDA PF1Data EOR #$FF STA PF1Data ; reverse PF1 LDA PF2Data EOR #$FF STA PF2Data ; reverse PF2 JSR RobAnimate JMP WaitIntimReady ; This builds the screen for the RobField demo: RobFieldScreen STA WSYNC ; Finish current line LDA #$00 STA CTRLPF ; set up playfield (repeat, not reflect) LDY #$BC ; let's do 190 lines of this Scanline: STA WSYNC LDA #00 STA VBLANK LDA PF0Data STA PF0 LDA PF1Data STA PF1 LDA PF2Data STA PF2 TYA AND #$1F ; XOR every 32nd line BNE DontXOR LDA PF0Data EOR #$FF AND #$F0 STA PF0Data ; reverse PF0 LDA PF1Data EOR #$FF STA PF1Data ; reverse PF1 LDA PF2Data EOR #$FF STA PF2Data ; reverse PF2 DontXOR: DEY BNE Scanline STA WSYNC LDA #$02 STA VBLANK LDA #$00 STA PF0 STA PF1 STA PF2 LDX #$21 JMP Waste ; Overscan RotateLeft: LDA PF0Data LSR ; rotate PF0 to left TAY AND #$08 BNE LCarry0 ; did we lose a bit? JMP LNoCarry0 ; if not, skip this next LCarry0: LDA PFCarry ORA #$01 ; turn on bit 0 of PFCarry STA PFCarry LNoCarry0: TYA AND #$F0 STA PF0Data LDA PF1Data CLC ASL ; rotate PF1 to left BCS LCarry1 JMP LNoCarry1 LCarry1: TAY LDA PFCarry ORA #$02 ; turn on bit 1 of PFCarry STA PFCarry TYA LNoCarry1: STA PF1Data LDA PF2Data CLC LSR ; rotate PF2 to left BCS LCarry2 JMP LNoCarry2 LCarry2: TAY LDA PFCarry ORA #$04 ; turn on bit 2 of PFCarry STA PFCarry TYA LNoCarry2: STA PF2Data LDA PFCarry AND #$02 ; mask out all but carry bit 1 (from PF1Data) ASL ASL ASL ASL ASL ASL ORA PF0Data ; add in bits from PF0Data STA PF0Data ; and put back in PF0Data LDA PFCarry AND #$04 ; mask out all but carry bit 2 (from PF2Data) LSR LSR ORA PF1Data STA PF1Data ; put into PF1Data LDA PFCarry AND #$01 ; mask out all but carry bit 0 (from PF0Data) ASL ASL ASL ASL ASL ASL ASL ORA PF2Data STA PF2Data ; put into PF2Data RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; RotateRight ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RotateRight: LDA PF0Data CLC ASL ; rotate PF0 to right BCS RCarry0 ; did we lose a bit? JMP RNoCarry0 ; if not, skip this next RCarry0: TAY LDA PFCarry ORA #$01 ; turn on bit 0 of PFCarry STA PFCarry TYA RNoCarry0: AND #$F0 STA PF0Data LDA PF1Data CLC LSR ; rotate PF1 to left BCS RCarry1 JMP RNoCarry1 RCarry1: TAY LDA PFCarry ORA #$02 ; turn on bit 1 of PFCarry STA PFCarry TYA RNoCarry1: STA PF1Data LDA PF2Data CLC ASL ; rotate PF2 to left BCS RCarry2 JMP RNoCarry2 RCarry2: TAY LDA PFCarry ORA #$04 ; turn on bit 2 of PFCarry STA PFCarry TYA RNoCarry2: STA PF2Data LDA PFCarry AND #$04 ; mask out all but carry bit 2 (from PF2Data) ASL ; need to set bit 4 of PF0 ASL ORA PF0Data ; add in bits from PF0Data STA PF0Data ; and put back in PF0Data LDA PFCarry AND #$01 ; mask out all but carry bit 0 (from PF0Data) ASL ; need to set bit 7 of PF1 ASL ASL ASL ASL ASL ASL ORA PF1Data STA PF1Data ; put into PF1Data LDA PFCarry AND #$02 ; mask out all but carry bit 1 (from PF1Data) LSR ; need to set bit 0 of PF2 ORA PF2Data STA PF2Data ; put into PF2Data RTS ORG $FF00 Graphics: .byte %00000000 .byte %00001010 .byte %00010001 .byte %00010101 .byte %00001110 .byte %00011111 .byte %00011111 .byte %00010101 .byte %00011111 .byte %00001110 .byte %00001110 .byte %00000100 .byte %00000100 .byte 0,0,0 .byte %00000000 .byte %00010101 .byte %00001010 .byte %00000100 .byte %00001010 .byte %00011111 .byte %00011111 .byte %00010101 .byte %00011111 .byte %00001110 .byte %00001110 .byte %00000100 .byte %00000100 HideData1: ; PF1 left .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111111 .byte %00111100 .byte %00110000 .byte %00000000 .byte %00000000 HideData2: ; PF2 left .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %00111111 .byte %00001111 .byte %00000011 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 HideData3: ; PF0 .byte %11110000 .byte %11110000 .byte %11110000 .byte %11110000 .byte %11110000 .byte %11110000 .byte %11110000 .byte %11110000 .byte %11110000 .byte %00110000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 HideData4: ; PF1 right .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111111 .byte %11111100 .byte %11110000 .byte %11000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 HideData5: ; PF2 right .byte %11111111 .byte %00111111 .byte %00001111 .byte %00000011 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 RobAnimate: INC CurrentFrame ; general all purpose frame counter LDA CurrentFrame AND #$01 BNE EndAnimate ; only animate every other frame LDA #$00 STA PFCarry ; start assuming we don't carry LDA CurrentFrame BMI DoRotateRight ; switch directions every 4 seconds or so DoRotateLeft: JSR RotateLeft JMP EndAnimate DoRotateRight: JSR RotateRight EndAnimate: RTS ; Generate a random number less than 48 rnd48 JSR rnd AND #$3F CMP #48 BCS rnd48 RTS ; A should now have a value from 0-47. ; Reset Vector ORG $FFFC .byte $00, $F0 .byte $00, $00