diff --git a/Art/Assets/TitleScreen.gif b/Art/Assets/TitleScreen.gif new file mode 100644 index 0000000..410e1a0 Binary files /dev/null and b/Art/Assets/TitleScreen.gif differ diff --git a/Art/Assets/TitleScreen.xcf b/Art/Assets/TitleScreen.xcf new file mode 100644 index 0000000..39ada7d Binary files /dev/null and b/Art/Assets/TitleScreen.xcf differ diff --git a/GSCats.xcodeproj/project.pbxproj b/GSCats.xcodeproj/project.pbxproj index c8a454a..04f1f3a 100644 --- a/GSCats.xcodeproj/project.pbxproj +++ b/GSCats.xcodeproj/project.pbxproj @@ -18,6 +18,8 @@ 701E708E2A67844B0030C35D /* loaderGraphics.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = loaderGraphics.s; sourceTree = ""; }; 701E708F2A69CE520030C35D /* loadingBar.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = loadingBar.s; sourceTree = ""; }; 701E70902A6A23800030C35D /* sharedGraphics.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = sharedGraphics.s; sourceTree = ""; }; + 701E70912A6DA4D80030C35D /* GenerateRawImage.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateRawImage.py; sourceTree = ""; }; + 701E70922A6DC5910030C35D /* titleScreen.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = titleScreen.s; sourceTree = ""; }; 705456862A43E03B00A2B866 /* GeneratePixelCircle.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GeneratePixelCircle.py; sourceTree = ""; }; 705456882A4D336200A2B866 /* animation.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = animation.s; sourceTree = ""; }; 7059502B1F37A0BE00BBE90F /* GenerateVRAMTable.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = GenerateVRAMTable.py; sourceTree = ""; }; @@ -64,9 +66,10 @@ 701E708E2A67844B0030C35D /* loaderGraphics.s */, 701E708F2A69CE520030C35D /* loadingBar.s */, 701E70902A6A23800030C35D /* sharedGraphics.s */, - 70E9D8601F2BD95400555C19 /* graphics.s */, + 701E70922A6DC5910030C35D /* titleScreen.s */, 70E9D8611F2BD95400555C19 /* gscats.s */, 70A80FB01F43D7F200BD34C9 /* gamemanager.s */, + 70E9D8601F2BD95400555C19 /* graphics.s */, 7099E3841F41022100182A82 /* gameobject.s */, 70F011D123B989B800C8873F /* random.s */, 706DF1651F2D4A8100AA6680 /* terrain.s */, @@ -95,6 +98,7 @@ 7076E9222A57AED90006E295 /* CompileFont.py */, 70FE79D21F8814A600E0095C /* MerlinToCA65.sh */, 700F72872112428D00225B17 /* RenumberSpriteFiles.sh */, + 701E70912A6DA4D80030C35D /* GenerateRawImage.py */, 7088096D1F2ECE8D00D4C950 /* GenerateRenderSpans.py */, 7059502B1F37A0BE00BBE90F /* GenerateVRAMTable.py */, 7099E3851F4107B100182A82 /* GenerateVRAMYOffset.py */, diff --git a/GenerateRawImage.py b/GenerateRawImage.py new file mode 100755 index 0000000..5978eb1 --- /dev/null +++ b/GenerateRawImage.py @@ -0,0 +1,24 @@ +#!/usr/bin/python3 + +import sys +import PIL +from PIL import Image +from numpy import asarray + +def main(argv): + image = Image.open(argv[0]) + outputFilename = argv[1] + pixels = asarray(image) + + with open(outputFilename, 'bw') as output: + for y in range(0,image.size[1]): + for x in range(0,image.size[0],2): + highPixel = pixels[y][x] << 4 + lowPixel = pixels[y][x+1] + byte = highPixel | lowPixel + output.write(bytes([byte])) + +if __name__ == "__main__": + main(sys.argv[1:]) + + diff --git a/Makefile b/Makefile index 0c9d905..ca7ec31 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ CODEBANK=CODEBANK\#060000 EXEC=$(PGM)\#06$(ADDR) SOUNDBANK=SOUNDBANK\#060000 FONTBANK=FONTBANK\#060000 +TITLESCREEN=TITLE\#060000 PGM=gscats MRSPRITE=../MrSprite/mrsprite @@ -31,7 +32,7 @@ SPRITEBANK=$(SPRITES)\#060000 FLIPLIST=$(wildcard Art/*Fan.gif) $(wildcard Art/*Spit*.gif) REMOTESYMBOLS= # -Wl $(shell ./ParseMapFile.py *.map) <- Use this to share symbols across code banks -all: clean diskimage fonts $(PGM) loader emulate +all: clean diskimage fonts titlescreen $(PGM) loader emulate emulate: # Leading hypen needed because GSPlus maddeningly returns code 1 (error) always and for no reason @@ -51,8 +52,10 @@ $(PGM): $(CAD) ADDFILE $(PGM).2mg /$(VOLNAME) $(SPRITEBANK) $(CAD) ADDFILE $(PGM).2mg /$(VOLNAME) $(SOUNDBANK) $(CAD) ADDFILE $(PGM).2mg /$(VOLNAME) $(FONTBANK) + $(CAD) ADDFILE $(PGM).2mg /$(VOLNAME) $(TITLESCREEN) rm -f $(CODEBANK) rm -f $(FONTBANK) + rm -f $(TITLESCREEN) rm -f $(PGM).o loader: @@ -62,16 +65,23 @@ loader: rm -f loader.o fonts: - rm -rf $(FONTBANK) + rm -f $(FONTBANK) ./CompileFont.py 4 5 48 0 "tinyNum" "Art/Assets/TinyNumbers.gif" > fonts.s ./CompileFont.py 8 8 32 0 "font8" "Art/Assets/Font8x8.gif" >> fonts.s # ./CompileFont.py 16 16 32 14 "font16" "Art/Assets/Font16x16.gif" > font16x16.s @PATH=$(PATH):/usr/local/bin; $(CL65) -t apple2enh -C linkerConfig --cpu 65816 --start-addr 0000 -lfontEngine.lst fontEngine.s -o $(FONTBANK) rm -f fontEngine.o +titlescreen: + rm -f $(TITLESCREEN) + ./GenerateRawImage.py "Art/Assets/TitleScreen.gif" "$(TITLESCREEN)" + clean: rm -f $(PGM) rm -f $(PGM).o + rm -f $(CODEBANK) + rm -f $(FONTBANK) + rm -f $(TITLESCREEN) rm -f loader rm -f loader.o rm -f Art/*m.gif diff --git a/gamemanager.s b/gamemanager.s index 9d36973..9f0942d 100644 --- a/gamemanager.s +++ b/gamemanager.s @@ -13,15 +13,6 @@ beginGameplay: lda #1 jsr seedRandom - ; Set up sprite rendering - BITS8 - lda #3 - sta SpriteBankBank00+3 ; Tell compiled sprites what bank they are in - BITS16 - - ; Set up audio - jsr initSoundSystem - ; Erase the screen ldx #$0000 ldy #200 diff --git a/gscats.s b/gscats.s index 405fca7..a1864d5 100644 --- a/gscats.s +++ b/gscats.s @@ -22,7 +22,7 @@ mainBank2: sta TEXTCOLOR BITS16 - jmp beginGameplay + jmp titleScreen quitGame: NORMALMEMORY @@ -49,6 +49,7 @@ quitGame: .include "dirt.s" .include "crosshair.s" .include "progressBar.s" +.include "titleScreen.s" endMainBank2: diff --git a/input.s b/input.s index c2673e1..54e4179 100644 --- a/input.s +++ b/input.s @@ -5,9 +5,44 @@ ; Created by Quinn Dunki on 8/15/17 ; + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; kbdScanTitle +; Processes keyboard input for title screen +; +; Trashes A +; + +kbdScanTitle: + BITS8 + lda KBD + bpl kbdScanTitleDone + sta KBDSTROBE + + cmp #(8 + $80) + beq kbdScanLeftArrowTitle + +kbdScanTitleDone: + BITS16 + rts + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Title Screen Key Handlers +; + +kbdScanLeftArrowTitle: + BITS16 + lda #1 + sta menuActionRequested + rts + + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; kbdScanGameplay/Debug -; Processes keyboard input +; Processes keyboard input for gameplay ; ; Trashes A ; @@ -58,6 +93,9 @@ kbdScanDebugPiggyback: bra kbdScanDone +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Gameplay Key Handlers +; kbdScanRightArrow: BITS16 diff --git a/loader.s b/loader.s index 0b4ed7a..fa377c4 100644 --- a/loader.s +++ b/loader.s @@ -12,8 +12,8 @@ .include "equates.s" .include "macros.s" -LOADBUFFER = $1000 ; Clear of this loader code -BUFFERSIZE = $8200 ; About max size we can fit between buffer and this loader code +LOADBUFFER = $1100 ; Clear of this loader code +BUFFERSIZE = $8000 ; About max size we can fit between buffer and this loader code MAINENTRY = $020000 .org $800 @@ -240,7 +240,7 @@ mainContinue2: addProgress LOADSTEP -; EMULATION + EMULATION ; Load rest of font data into bank 0 (needed if font size exceeds BUFFERSIZE) ; jsr PRODOS @@ -249,9 +249,9 @@ mainContinue2: ; bne ioErrorJmp ; Close the file -; jsr PRODOS -; .byte $cc -; .addr fileClose + jsr PRODOS + .byte $cc + .addr fileClose ; NATIVE @@ -262,6 +262,50 @@ mainContinue2: ; ldy #BUFFERSIZE ; jsr copyBytes + bra mainContinue3 + +ioErrorJmp: + jmp ioError + +mainContinue3: + +; EMULATION + + ; Open the title screen file + jsr PRODOS + .byte $c8 + .addr fileOpenTitle + bne ioErrorJmp + + NATIVE + addProgress LOADSTEP + EMULATION + + ; Load the title screen data into bank 0 + jsr PRODOS + .byte $ca + .addr fileRead + bne ioErrorJmp + + NATIVE + addProgress LOADSTEP + + ; Copy title screen data into bank 6 + ldx fileReadLen + lda #6 + ldy #0 + jsr copyBytes + + EMULATION + + ; Close the file + jsr PRODOS + .byte $cc + .addr fileClose + + NATIVE + addProgress LOADSTEP + ; Set up a long jump into bank 2, and ; a way for game code to get back here to exit ; properly to ProDOS 8 @@ -287,9 +331,6 @@ returnToProDOS: sta TEXTCOLOR rts -ioErrorJmp: - jmp ioError - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -385,6 +426,13 @@ fileOpenFonts: .byte 0 ; Result (file handle) .byte 0 ; Padding +fileOpenTitle: + .byte 3 + .addr titlePath + .addr $9200 ; 1k below BASIC.SYSTEM + .byte 0 ; Result (file handle) + .byte 0 ; Padding + codePath: pstring "/GSAPP/CODEBANK" spritePath: @@ -393,6 +441,8 @@ soundPath: pstring "/GSAPP/SOUNDBANK" fontPath: pstring "/GSAPP/FONTBANK" +titlePath: + pstring "/GSAPP/TITLE" .include "sharedGraphics.s" .include "loaderGraphics.s" diff --git a/loadingBar.s b/loadingBar.s index 7f5d1eb..7bfcb5a 100644 --- a/loadingBar.s +++ b/loadingBar.s @@ -134,7 +134,7 @@ CBR_VRAM = 6 currentLoadingBar: .word 0 ; Active .word 0 ; Current progress in bytes - .word 57 ; Final progress in bytes + .word 66 ; Final progress in bytes .word $5eb4 ; VRAM position (top left) diff --git a/titleScreen.s b/titleScreen.s new file mode 100644 index 0000000..78247cb --- /dev/null +++ b/titleScreen.s @@ -0,0 +1,129 @@ +; +; titleScreen +; A friendly place to start the game +; +; Created by Quinn Dunki on 7/23/23 +; + +.a16 +.i16 + +titlePalette: + .word $06af,$0072,$0072,$0861,$0c93,$0eb4,$0d66,$0f9a,$0777,$0d00,$0bbb,$ddd,$007b,$0a5b,$0000,$0fff + +TITLE_ANIMATION_FRAMES = 5 +CAT_DELAY = 300 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; titleScreen +; +; Shows the title screen and main game menu +; +titleScreen: + + lda #%10000000 ; Set all SCBs to 320, no interrupts, palette 0 + jsr initSCBs + + ; Copy title screen art from where it was loaded in bank 6 + ; This isn't fast, but doesn't need to be + ldx #0 + +titleScreenCopyLoop: + lda $060000,x + sta VRAM,x + inx + inx + cpx #$7d00 + bne titleScreenCopyLoop + + ; Set up sprite rendering + BITS8 + lda #3 + sta SpriteBankBank00+3 ; Tell compiled sprites what bank they are in + BITS16 + + ; Set up audio + jsr initSoundSystem + + ; Fade in + lda #titlePalette + sta PARAML2 + jsr paletteFade + +titleScreenMainLoop: + + ; Track animations + jsr nextVBL + lda titleAnimationCounter + inc + cmp TITLE_ANIMATION_FRAMES + jsr titleScreenResetAnimation + + ; Time animations of cats + lda animationDelay0 + dec + bne titleScreenStillCat + lda #CAT_DELAY + sta animationDelay0 + + ; Render next frame of cats + lda #titleAnimationPos0 + sta PARAML0 + ldx #TITLE_ANIMATION_FRAMES + ldy #30 + lda #ANIMATION_SIZE_16x32 + jsr renderAnimation + bra titleScreenNextCat + +titleScreenStillCat: + sta animationDelay0 + ldy #$5d79 + lda #29 + jsr drawSpriteBankSafe + +titleScreenNextCat: + lda animationDelay1 + dec + bne titleScreenStillCat2 + lda #CAT_DELAY + sta animationDelay1 + + lda #titleAnimationPos1 + sta PARAML0 + ldx #TITLE_ANIMATION_FRAMES + ldy #21 + lda #ANIMATION_SIZE_16x32 + jsr renderAnimation + bra titleScreenKeyboard + +titleScreenStillCat2: + sta animationDelay1 + ldy #$5da0 + lda #20 + jsr drawSpriteBankSafe + +titleScreenKeyboard: + ; Check for selection + jsr kbdScanTitle + lda menuActionRequested + beq titleScreenMainLoop + + jmp beginGameplay + +titleScreenResetAnimation: + stz titleAnimationCounter + rts + +titleAnimationCounter: + .word 0 +titleAnimationPos0: + .word 130,120 +titleAnimationPos1: + .word 208,120 +animationDelay0: + .word CAT_DELAY/2 +animationDelay1: + .word CAT_DELAY +menuActionRequested: + .word 0