SEG zeropageSegment introDestPtr WORD SEG programSegment introreset SUBROUTINE jsr multicolorOff jsr clearScreen ; Set screen colors lda #0 sta $d020 ; overscan sta $d021 ; center lda #14 sta introYscroll ; for "GLGPROGRAMS" at the beginning ldx #$78 stx introDestPtr ldy #$04 sty introDestPtr + 1 ; GLGPROGRAMS color ldy #$00 lda #$02 .colorLoop: sta $d800,y sta $d900,y sta $da00,y sta $db00,y dey bne .colorLoop ; first raster interrupt line, for moustaches lda #68+18 sta moustacheLine rts statusIntro0 SUBROUTINE ; arrives raster interrupt, move moustache one line below inc moustacheLine lda $d011 ; load current vertical offset from VIC-II and #$07 cmp #$07 beq .nextline ; if 7, then it is next text line inc $d011 ; else setup moustache interrupt to trigger next raster line... jsr setupMoustacheInterrupt rts ; ...and return: my job here is done .nextline: lda $d011 ; reset raster offset to 0... and #$f8 sta $d011 MOV_WORD_MEM dstPointer, introDestPtr MEMSET "D", #$80, #40 clc ; ... move introDestPtr to next text line ... lda introDestPtr adc #40 sta introDestPtr lda introDestPtr + 1 adc #0 sta introDestPtr + 1 MOV_WORD_MEM dstPointer, introDestPtr MEMCPY "D", #GLGProgramsText, #200 ; ... and copy "GLG Programs" text to next text line dec introYscroll ; remember that we are one line below beq .next ; if we reached the end of the vertical scroll, advance status jsr setupMoustacheInterrupt ; else just continue with the moustache rts .next: lda #ST_INTRO1 sta status rts setupMoustacheInterrupt SUBROUTINE ; Store in $314 address of our custom interrupt handler ldx #<.moustacheInterruptH ldy #>.moustacheInterruptH stx $314 sty $315 ; Set raster beam to trigger interrupt at row lda moustacheLine sta $d012 rts .moustacheInterruptH: ; "higher" moustache interrupt (on the right of the screen) ; +36 dec $d019 ; +42, EOI lda #$02 ; +44, color sta $d020 ; +48, color nop ; +50, timing nop ; +52, timing nop ; +54, timing bit $02 ; +57, timing lda #$00 ; +59, color sta $d020 ; +63, color ; second line, +0 inc $0800 ; + 6, timing inc $0800 ; +12, timing inc $0800 ; +18, timing inc $0800 ; +24, timing inc $0800 ; +30, timing inc $0800 ; +36, timing inc $0800 ; +42, timing lda #$02 ; +44, color sta $d020 ; +48, color inc $0800 ; +54, timing bit $02 ; +57, timing lda #$00 ; +59, color sta $d020 ; +63, color ; set raster beam low ldx #<.moustacheInterruptL ldy #>.moustacheInterruptL stx $314 sty $315 clc lda moustacheLine adc #23 ; "lower" moustache is 23 raster lines below higher one sta $d012 jmp $ea31 .moustacheInterruptL: ; "lower" moustache interrupt (on the left of the screen) ; +36 dec $d019 ; +42, EOI inc $0800 ; +48, timing inc $0800 ; +54, timing lda #$02 ; +56, color bit $0800 ; +60, timing bit $02 ; +63, timing ; newline sta $d020 ; + 4, color lda #$00 ; + 6, timing inc $0800 ; +12, timing inc $0800 ; +18, timing nop ; +20, timing sta $d020 ; +24, color lda #$02 ; +26, color bit $0800 ; +30, timing inc $0800 ; +36, timing inc $0800 ; +42, timing inc $0800 ; +48, timing inc $0800 ; +54, timing inc $0800 ; +60, timing bit $02 ; +63, timing ; newline sta $d020 ; + 4, color lda #$00 ; + 6, color inc $0800 ; +12, timing inc $0800 ; +18, timing sta $d020 ; +22, color ldx #irq stx $314 sty $315 lda #$00 sta $d012 jmp $ea31 GLGProgramsText: ; fancy PETSCII-looking brand name BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f0,#$f4,#$80,#$80,#$80,#$f0,#$f4,#$80,#$80,#$f0,#$f4,#$f1,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80 BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f5,#$80,#$80,#$f5,#$80,#$f5,#$80,#$80,#$80,#$f5,#$80,#$f5,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f1,#$80,#$80,#$80,#$f0,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4 BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f5,#$80,#$f5,#$f5,#$80,#$f5,#$80,#$f5,#$80,#$fd,#$f4,#$f3,#$f0,#$f0,#$f1,#$f0,#$f1,#$f0,#$f0,#$fc,#$f0,#$fb,#$f1,#$f2,#$f1,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80 BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f2,#$f4,#$fc,#$f2,#$f4,#$f2,#$f4,#$fc,#$80,#$f5,#$80,#$80,#$f5,#$f2,#$f3,#$f2,#$fc,#$f5,#$f2,#$f3,#$f5,#$f5,#$f5,#$f4,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80 BYTE #$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$fa,#$f4,#$f4,#$f4,#$f4,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80 statusIntro1 SUBROUTINE ; continue moving moustaches down, up to 4 raster lines (middle of text) lda $d011 and #$07 cmp #$04 beq .next ; if interrupt is in the middle, don't move it anymore, and... inc $d011 inc moustacheLine jsr setupMoustacheInterrupt rts .next: jsr setupMoustacheInterrupt ; ... always remember to display moustache, anyhow ... lda counter ; wait for song synchronization up to interrupt $0080 cmp #$80 bne .end lda counter + 1 cmp #$00 bne .end ldy #$0 lda #$07 .colorLoop: sta $d940,y iny cpy #200 bne .colorLoop lda #ST_INTRO2 sta status .end: rts statusIntro2 SUBROUTINE jsr setupMoustacheInterrupt ; "RETROFFICINA" lda #introStringA1 sta srcStringPointer + 1 lda #$48 sta dstScreenPointer lda #$05 sta dstScreenPointer + 1 jsr printString lda counter cmp #$08 bne .end lda counter + 1 cmp #$01 bne .end lda #ST_INTRO3 sta status .end: rts statusIntro3 SUBROUTINE jsr setupMoustacheInterrupt ; "AND" lda #introStringA2 sta srcStringPointer + 1 lda #$a5 sta dstScreenPointer lda #$05 sta dstScreenPointer + 1 jsr printString lda counter cmp #$86 bne .end lda counter + 1 cmp #$01 bne .end lda #ST_INTRO4 sta status .end: rts statusIntro4 SUBROUTINE jsr setupMoustacheInterrupt ; "GIOMBA" lda #introStringA3 sta srcStringPointer + 1 lda #$f9 sta dstScreenPointer lda #$05 sta dstScreenPointer + 1 jsr printString lda counter cmp #$08 bne .end lda counter + 1 cmp #$02 bne .end MEMSET #$540, #$80, #200 lda #ST_INTRO5 sta status .end: rts statusIntro5 SUBROUTINE jsr setupMoustacheInterrupt ; "PRESENT" lda #introStringA4 sta srcStringPointer + 1 lda #$50 sta dstScreenPointer lda #$05 sta dstScreenPointer + 1 jsr printString lda counter cmp #$80 bne .end lda counter + 1 cmp #$02 bne .end lda #ST_INTRO6 sta status .end: rts statusIntro6 SUBROUTINE jsr setupMoustacheInterrupt ; "A COMMODORE 64" lda #introStringA5 sta srcStringPointer + 1 lda #$9d sta dstScreenPointer lda #$05 sta dstScreenPointer + 1 jsr printString lda counter cmp #$08 bne .end lda counter + 1 cmp #$03 bne .end lda #ST_INTRO7 sta status .end: rts statusIntro7 SUBROUTINE jsr setupMoustacheInterrupt ; "VIDEOGAME" lda #introStringA6 sta srcStringPointer + 1 lda #$ef sta dstScreenPointer lda #$05 sta dstScreenPointer + 1 jsr printString lda counter cmp #$80 bne .end lda counter + 1 cmp #$03 bne .end lda #ST_INTRO8 sta status .end: rts statusIntro8 SUBROUTINE jsr setupMoustacheInterrupt ; blank wait lda counter cmp #$16 bne .end lda counter + 1 cmp #$04 bne .end lda #ST_MENURESET sta status .end: rts statusMenuReset SUBROUTINE lda #$05 ldy #$0 .lastlineColorLoop: sta $db98,y iny cpy #80 bne .lastlineColorLoop ; Print Game Title: big "SNAKE" MEMSET #$d800, #$02, #280 ; color MEMCPY #$400, #SnakeText, #280 ; text ; Print PETSCII GLG Programs MEMSET #($6a8 + $d800 - $400), #$02, #200 ; color MEMCPY #$6a8, #GLGProgramsText, #200 ; text ; Print website lda #intro2string ; do the same for msb of string address sta srcStringPointer + 1 ; put into msb of source pointer lda #$9e ; this is lsb of address of 23th line sta dstScreenPointer ; put into lsb of dest pointer lda #$07 ; do the same for msb of adress of 20th line sta dstScreenPointer + 1 ; put into msb of dest pointer jsr printString ; print ; Print Copyright lda #intro3string ; and line (24th line) sta srcStringPointer + 1 lda #$ce sta dstScreenPointer lda #$07 sta dstScreenPointer + 1 jsr printString ; boat-shaped horizontal line (rounded edges toward the top) ; this overwrites the "present" word from the intro lda #$f2 ; 3rd quadrant sta $540 lda #$f3 ; 4th quadrant sta $567 lda #$07 ; color for edges sta $540+$d800-$400 sta $567+$d800-$400 ldy #$1 .boatLineLoop: lda #$f4 ; horizontal line sta $540,y lda #$07 sta $540+$d800-$400,y iny cpy #39 bne .boatLineLoop lda #$05 sta XCharOffset jsr setupMoustacheInterrupt ; never forget the magic moustaches lda #ST_MENU sta status rts SnakeText: HEX 80 80 80 80 80 80 80 80 f6 a0 a0 f9 80 f7 80 80 f6 80 f6 a0 a0 f7 80 f7 80 80 80 f6 a0 a0 f9 80 80 80 80 80 80 80 80 80 HEX 80 80 80 80 80 80 80 80 a0 80 80 80 80 a0 f7 80 a0 80 a0 80 80 a0 80 a0 f6 f7 80 a0 80 80 80 80 80 80 80 80 80 80 80 80 HEX 80 80 80 80 80 80 80 80 a0 80 80 80 80 a0 a0 f7 a0 80 a0 80 80 a0 80 a0 a0 f9 80 a0 80 80 80 80 80 80 80 80 80 80 80 80 HEX 80 80 80 80 80 80 80 80 f8 a0 a0 f7 80 a0 f8 a0 a0 80 a0 a0 a0 a0 80 a0 f9 80 80 a0 a0 80 80 80 80 80 80 80 80 80 80 80 HEX 80 80 80 80 80 80 80 80 80 80 80 a0 80 a0 80 f8 a0 80 a0 80 80 a0 80 a0 f7 80 80 a0 80 80 80 80 80 80 80 80 80 80 80 80 HEX 80 80 80 80 80 80 80 80 80 80 80 a0 80 a0 80 80 a0 80 a0 80 80 a0 80 a0 a0 f7 80 a0 80 80 80 80 80 80 80 80 80 80 80 80 HEX 80 80 80 80 80 80 80 80 f6 a0 a0 f9 80 f8 80 80 f8 80 f9 80 80 f8 80 a0 f8 f9 80 f8 a0 a0 f7 80 80 80 80 80 80 80 80 80 ;ParabolicSpaceChars: ; HEX 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ;ParabolicSpaceScroll: ; HEX 00 01 01 01 01 01 01 01 02 02 02 03 03 04 04 05 06 06 07 00 00 01 02 03 04 05 06 07 00 01 02 04 05 06 00 01 02 04 05 07 00 02 04 05 07 00 01 03 04 06 00 01 03 04 06 07 00 02 03 04 06 07 00 01 02 03 04 05 06 07 00 01 02 02 03 04 04 05 05 06 06 06 07 06 07 07 07 07 07 07 07 setupXScrollInterrupt SUBROUTINE ldx #XScrollInterruptH stx $314 sty $315 ; Set raster beam to trigger interrupt at row lda #42 sta $d012 rts XScrollInterruptH SUBROUTINE lda $d016 and #$f8 ora XScrollOffset sta $d016 dec $d019 ldx #XScrollInterruptL stx $314 sty $315 lda #110 sta $d012 jmp $ea31 XScrollInterruptL SUBROUTINE lda $d016 and #$f8 sta $d016 dec $d019 ldx #XScrollInterruptMoveAll stx $314 sty $315 lda #120 sta $d012 jmp $ea31 XScrollInterruptMoveAll SUBROUTINE dec $d019 ; EOI tsx dex lda XCharOffset asl asl asl sta $100,x lda $d016 and #$07 ora $100,x inx txs cmp #78 bcs .isEdge cmp #3 bcc .isEdge cmp #70 bcs .isMiddle cmp #10 bcc .isMiddle jmp .enter .isMiddle: lda counter and #$01 beq .enter jmp .next .isEdge: lda counter and #$03 beq .enter ; ah, some good spaghetti code to accomodate for far branch jmp .next ; bounce slower .isCenter: .enter: lda XScrollDirection and #$01 bne .goRight .goLeft: dec XScrollOffset lda XScrollOffset and #$07 cmp #$07 beq .continue1 jmp .next .continue1: lda #$07 sta XScrollOffset .moveEverythingLeft: dec XCharOffset ldy #0 .loop1: lda $401,y sta $400,y lda $429,y sta $428,y lda $451,y sta $450,y lda $479,y sta $478,y lda $4a1,y sta $4a0,y lda $4c9,y sta $4c8,y lda $4f1,y sta $4f0,y iny cpy #38 bne .loop1 lda XCharOffset cmp #0 bne .next lda #$01 sta XScrollDirection jmp .next .goRight: inc XScrollOffset lda XScrollOffset and #$07 cmp #$00 bne .next lda #$00 sta XScrollOffset .moveEverythingRight: inc XCharOffset ldy #38 .loop2: lda $400,y sta $401,y lda $428,y sta $429,y lda $450,y sta $451,y lda $478,y sta $479,y lda $4a0,y sta $4a1,y lda $4c8,y sta $4c9,y lda $4f0,y sta $4f1,y dey bne .loop2 lda XCharOffset cmp #10 bne .next lda #$00 sta XScrollOffset lda #$00 sta XScrollDirection .next: jsr setupMoustacheInterrupt jmp $ea31 statusMenu SUBROUTINE jsr setupXScrollInterrupt rts