Compare commits

...

12 Commits

Author SHA1 Message Date
blondie7575 59a290a288 Known bugs update to reflect border situation 2024-02-18 19:54:13 -07:00
blondie7575 5b740be772 Disabled title screen border effect
It’s unstable on real hardware and I haven’t yet figured out why
2024-02-18 19:49:27 -07:00
blondie7575 36b0033a7d Fixed move right firing random projectile 2024-02-18 19:15:17 -07:00
blondie7575 c71534f101 Updated disk and app name 2024-02-01 10:17:14 -07:00
blondie7575 14aa945441 Update victory help 2024-02-01 09:56:28 -07:00
blondie7575 f532287345 Added victory sequence 2024-02-01 09:53:38 -07:00
blondie7575 b10eaa850f Update ReadMe 2024-01-28 20:14:28 -07:00
blondie7575 7967035cc3 Added victory screen 2024-01-28 12:12:58 -07:00
blondie7575 8362b0d4ae Fix crosshair disappearing when weapon is too expensive 2024-01-21 18:26:46 -07:00
blondie7575 30f16aaef5 Fixed memory corruption of spit damage 2024-01-21 18:21:05 -07:00
blondie7575 926e69e33d Added game controls for movement 2024-01-21 17:27:12 -07:00
blondie7575 9de1664895 Fixed fans disappearing after one turn 2024-01-21 14:01:10 -07:00
34 changed files with 315 additions and 88 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@
/FONTBANK\#060000
/Art/Generated
/fonts.lst
/catfight.lst

BIN
Art/038MoveLeft.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

BIN
Art/038MoveLeft.xcf Normal file

Binary file not shown.

BIN
Art/039MoveRight.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

BIN
Art/039MoveRight.xcf Normal file

Binary file not shown.

BIN
Art/040Pee.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

BIN
Art/040Pee.xcf Normal file

Binary file not shown.

BIN
Art/041Pee.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

BIN
Art/041Pee.xcf Normal file

Binary file not shown.

BIN
Art/042Pee.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

BIN
Art/042Pee.xcf Normal file

Binary file not shown.

BIN
Art/043Pee.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

BIN
Art/043Pee.xcf Normal file

Binary file not shown.

BIN
Art/044Pee.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

BIN
Art/044Pee.xcf Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

View File

@ -44,7 +44,7 @@
70E554C41F807ADB00F3C871 /* spritebank.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = spritebank.s; sourceTree = "<group>"; };
70E9D85F1F2BD95400555C19 /* equates.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = equates.s; sourceTree = "<group>"; };
70E9D8601F2BD95400555C19 /* graphics.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = graphics.s; sourceTree = "<group>"; };
70E9D8611F2BD95400555C19 /* gscats.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gscats.s; sourceTree = "<group>"; };
70E9D8611F2BD95400555C19 /* catfight.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = catfight.s; sourceTree = "<group>"; };
70E9D8621F2BD95400555C19 /* macros.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = macros.s; sourceTree = "<group>"; };
70E9D8631F2BD95400555C19 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
70F011D023B91B2900C8873F /* dirt.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = dirt.s; sourceTree = "<group>"; };
@ -65,7 +65,7 @@
701E708F2A69CE520030C35D /* loadingBar.s */,
701E70902A6A23800030C35D /* sharedGraphics.s */,
701E70922A6DC5910030C35D /* titleScreen.s */,
70E9D8611F2BD95400555C19 /* gscats.s */,
70E9D8611F2BD95400555C19 /* catfight.s */,
70A80FB01F43D7F200BD34C9 /* gamemanager.s */,
70E9D8601F2BD95400555C19 /* graphics.s */,
7099E3841F41022100182A82 /* gameobject.s */,

View File

@ -10,7 +10,7 @@
CL65=cl65
CAD=./cadius
VOLNAME=GSAPP
VOLNAME=CATFIGHT
IMG=DiskImageParts
EMU=/Applications/GSplus.app/Contents/MacOS/gsplus
ADDR=0800
@ -20,7 +20,7 @@ EXEC=$(PGM)\#06$(ADDR)
SOUNDBANK=SOUNDBANK\#060000
FONTBANK=FONTBANK\#060000
TITLESCREEN=TITLE\#060000
PGM=gscats
PGM=catfight
MRSPRITE=../MrSprite/mrsprite
GENART=Art/Generated

View File

@ -1,10 +1,18 @@
# GSCats
# Cat Fight
## Introduction
This is a simple game in the style of Apple II Artilley, Scorched Earth, or Worms but with cats and nobody gets hurt.
This is a simple game in the style of Apple II Artilley, Scorched Earth, or Worms but with cats and nobody gets hurt. The goal is simply to make the other cat so angry that they pee themselves (based on the true story of Tinker and Sprocket's first encounter).
This was written as an exercise for me to learn the fundamentals of Apple IIgs game programming, and I certainly won't claim there's anything special here technically. The neatest part is probably the terrain, which is deformable and scrolls at 60fps on stock hardware. Well, sometimes it does, anyway, depending on how you hold your nose. The GS is hard. Also it no longer does it at 60fps since I built a whole game on top of that engine. It was neat for a while, okay? I did a whole KansasFest presentation about it. There's a video. Google it yourself. I'm not your mother.
If nothing else, I do think this project serves as a solid starting point for anyone interested in writing GS games. The basics are all here- an art pipeline with compiled sprites, a VBL-synced game loop, input handling, fonts, animation system, and sound. All the things you need on a GS, and all things that are hard on the GS. I'll describe these systems in more detail below.
## Running The Game
The included 800k disk image should load fine in any emulator or on real hardware. It should run on any GS with 512k or more of RAM, and no acceleration is required. The game runs of ProDOS 8 and can in theory be copied to a hard drive, but at the moment the volume name is hardcoded in the loader. Sorry, it's lame, I know. The image boots Bitsy Bye, and the game is called CATFIGHT. Run that and enjoy spitting at your opponent all the live long day.
This was written as an exercise for me to learn the fundamentals of Apple IIgs game programming, and I certainly won't claim there's anything special here technically. The neatest part is probably the terrain, which is deformable and scrolls at 60fps on stock hardware. Well, sometimes it does, anyway, depending on how you hold your nose. The GS is hard.
## Acknowledgements
@ -12,13 +20,90 @@ I'm writing this game now because I'm learning all the things I wished I could k
- John Brooks, who has forgotten more about the GS than I will ever know.
- Rebecca Heineman, who wrote every good game on the platform that you probably played except the ones John wrote
- Jeremy Rand, who is inspiring to me with his prolific retro programming endeavours and humble spirit. Not to mention I learned a lot from reading his code for BuGS.
- Jeremy Rand, who is inspiring to me with his prolific retro programming endeavours and humble spirit. Not to mention I learned a lot from reading his code for [BuGS](https://github.com/jeremysrand/BuGS).
- Brutal Deluxe, who have made so many great GS tools, including [Mr. Sprite](http://www.brutaldeluxe.fr/products/crossdevtools/mrsprite/index.html) and Cadius, upon which this game depends. I doubt you could find anyone more consistently devoted to the platform than these guys. Mr. Sprite's Tech Page is probably the greatest single treatise ever written on how to do fast Apple IIgs graphics.
- Dagen Brock, for tirelessly maintaining the last remaining (as of this writing) good GS emulator, GSPlus. Without good emulators, retro-development dies, so thank you for fighting the good fight, Dagen. Emulating the GS is a thankless job for a platform almost nobody cares about.
- Dagen Brock and Kent Dickey, for tirelessly maintaining [GSPlus](https://apple2.gs/plus/) and [KEGS](https://kegs.sourceforge.net) respectively. Without good emulators, retro-development dies, so thank you for fighting the good fight, gents. Emulating the GS is a thankless job for a platform almost nobody cares about.
- All of the KansasFest and Apple II community on Slack and elsewhere
## Memory map
The GS's memory banks in Cat Fight are allocated as follows:
- Bank $00 : *Loader*
- Bank $02 : *Code*. Most of this 64k bank is filled with the game code
- Bank $03 : *Sprites*. This bank holds all compiled sprite rendering code
- Bank $04 : *Sound*. The bank of audio samples to be loaded into Ensoniq live here
- Bank $05 : *Fonts*. The game uses three compiled fonts, and the rendering code lives here
- Bank $06 : *Title Screen*. Loaded here for copying into VRAM as needed
This means Cat Fight requires a minimum of 512k of RAM. I've never seen a GS with less than 1.25MB of RAM in the wild, but I suppose they exist. The very earliest machines shipped with 256k, so it's possible. Those people can't play my game. You're not missing much.
## The Loader
Cat Fight is a little too big to be a trivial "let ProDOS load it and run" game, so it needed a loader. However the loader is very silly and slow. I made no effort to make this clever. I steal as much memory as I can from bank $00 without stepping on ProDOS 8 to use as a loading buffer. Chunks are loaded from disk into this buffer, then copied into the banks where they need to live. If the bank is full (64k) then I have to do this in two steps since I obviously can't load a full 64k into bank $00 without stepping on something important. Nothing is compressed, which is admittedly lame. At least I made a pretty loading bar for you to look at. Once loaded, however, the game is fully RAM resident so you can play all day with no more loading.
Why on earth did I use ProDOS 8, you might ask? A very reasonable question. The truth is, because it's simple, easy, and still reasonably compatible with solid state devices, hard drives, and GS/OS. It's a clean ProDOS 8 app that plays nice with quitting and such. GS/OS is such a beast and I don't want to deal with it. I did my time on that back in the day. Writing a custom RWTS loader is neat, but not compatible with anything else. ProDOS 8 is a nice middle ground. Hey, if it's good enough for Wil Harvey (Zany Golf, The Immortal) it's sure as hell good enough for me. He didn't even use a *current* ProDOS 8. At least I'm using John Brooks' cool new one. The only weirdness comes from the fact that ProDOS 8 is 8-bit and doesn't know about the IIgs. This means you have to run ProDOS 8 calls in emulation, then go native to copy the data into other banks. ProDOS 8 can't load into other banks because it doesn't know that a universe can have more than 64k in it, and wouldn't believe you if you told it.
## The Sprite Engine
Cat Fight's sprites are rendered in a typical Apple IIgs way, which is to say a very strange way to anyone who doesn't know this platform. Bank $01/E1 memory shadowing is enabled, the stack is placed at $2000 in bank $01, then pixels are drawn by pushing on to the stack. Because all writes to the super hi-res video buffer on the GS are forced to 1MHz, this stack relocation trick allows us to render as quickly as possible. With stack pushing, you get cheap memory writes (no separate load and store) and you get pointer incrementing for free. When rendering constant values, it's possible to exceed one pixel per clock cycle. It's still 1MHz, but at least it's as few of those slow cycles as possible. To render sprites this way, you need a sprite compiler. If you want a lot more technical detail on how GS sprite compiling works, check out the Mr. Sprite link above. The gist is that it generates code that pushes constant values for all the pixels in your sprite to the stack. If you set up the stack to point at the video buffer before calling it, your sprite will be drawn. There are a huge number of devils in the details, but the basic idea is as simple as that.
## The Art Pipeline
All the artwork is done in GIF format via GIMP, since the GS uses indexed colour. GIF is an easy format to work in for indexed colour. These images are fed to the Brutal Deluxe tool called Mr. Sprite which generates blocks of code for rendering those sprites. One of the great things about the GS is that it has 16-bit index registers. That means you can reference every pixel on the screen with offset addressing modes. No fancy math or lookup tables required to calculate rendering positions. This makes sprite compiling really easy because you can assume the VRAM position to render at is stored in X, and the compiled sprite code can be general, while still compact and fast. The Makefile produces the compiled sprite code into a bank called SPRITEBANK when you `make art`. This Sprite Bank file is loaded into Bank 3 for use as indicated in the memory map above.
## The Font Compiler
Fonts on the GS are best rendered in a similar way to sprites- as compiled entities. I tried to use Mr. Sprite for this as I did the sprites, but the truth is Mr. Sprite is a little buggy. It's a fantastic tool and I have the utmost respect for Brutal Deluxe for writing it. I am forever endebted to them. However the specific bugs that it has are around quick colour transitions in small sprites, exactly what a font tends to do a lot of. I worked around the bugs for my main sprites, but for the fonts, I couldn't. I set out to write a subset of Mr. Sprite in Python, but I couldn't stop and ended up replicating about 99% of its features. My next game will probably use only this new Python implementation. You'l find it here as "CompileFont". The nice thing about it is that it's a modern Python implementation so it's completely portable to whatever your modern cross-development system is.
## The Terrain Engine
Rendering fast on the GS is all about compiling your pixel writes. This usually means sprite compiling, which is where you use an offline tool to convert your sprite art into code that renders those sprites directly, as explained above. For the terrain engine in Cat Fight, this means taking a 2D height map and compiling it into a series of stack push instructions to render as quickly as possible. It's similar to sprite compiling, but this has to be done on the fly. The way I did this was by limiting the terrain to a single colour. This means I only need four bit patterns to represent all possible terrain pixel patterns (since the GS has 4 pixels per word). We can store four bit patterns in four registers that can all be pushed- the accumulator, index X, index Y, and the Direct Page register. This means the terrain compiler generates a huge block of PHA, PHX, PHY, and PHD instructions to render the terrain. We're not done though, because the terrain needs to be deformable to make it a true artillery style game. To do this, sections of the terrain can be recompiled as needed to modify it. Compiling the entire map would be slow (and is only done once) but recompiling small "dirty rectangles" is so fast you don't notice it. Furthermore, the terrain has to scroll, which means we render an arbitrary 320 pixel wide section of it. To do this, the compiled terrain code is "clipped" by inserting a column of JMP instructions at the left edge of the virtual screen's location. Each row of terrain is rendered by jumping to the right edge entry point, then bouncing back at the left edge off the return JMP. When the terrain scrolls, that column of JMP instructions is replaced with the terrain data that was there. The column of terrain we overwrite to do this is saved in a little mini stack. To save and restore this data very quickly, I use the amazing GS trick of relocating the GS stack. I can push and pop this data to save/restore it very quickly into a little buffer than I hide in an unused area of bank $E0.
All of this is a little mind-bending because stack-based rendering means you do everything backwards. Sprites are rendered from bottom right to top left, and my terrain is rendered right-to-left on each row, and bottom to top overall.
## The Build Pipeline
The build is done with a makefile. The steps are:
1) A blank formatted disk image is created from scratch using Cadius
2) A functional ProDOS 8 disk is created by copying critical SYSTEM files to it
3) John Brooks' Bitsy Bye is copied over as a quick launcher
4) The fonts are compiled into a FONTBANK file, which is copied to the disk image
5) The titlescreen bitmap is copied to the disk image
6) The game code is assembled with ca65 into a CODEBANK file and copied to the disk image
7) The compiled sprite code (SPRITEBANK) is copied to the disk image
8) The sound data (SOUNDBANK) is copied to the disk image
9) The loader code is assembled with ca65, a ProDOS 8 executable is made, and copied to the disk image
10) An instance of the emulator GSPlus is launched with the disk image as the boot volume
All of that is fast enough to be done every time. The sprite compiling is only done when you manually `make art`. This generates the SPRITEBANK file copied in step 7 above. Similarly, the SOUNDBANK is only produced with a manual `make sound`.
## The Sound System
The sound bank (SOUNDBANK) is a 64k file that is already in the internal format expected by the Ensoniq for its sound ram. This file is generated from WAV files using a Python script GenerateSoundBank. These WAVs are converted into the very low fidelity format needed to fit in the Ensoniq, converted to the signed 8 bit format it expects, then packed together and padded out to the Ensoniq's 4k wavetable boundaries. Playing sound on the GS is quite easy. Getting audio files into the expected wavetable format is not, and I am especially indebted to Jeremy Rand for this step. At load time, the 64k bank is copied directly into Ensoniq instrument RAM and sounds are played from there. Cat Fight doesn't do any audio streaming, I just kept the sound minimal enough to fit in 64k.
### Sound Credits:
- Cat noise compilation, by Counter-gamer. Used with permission under CC3.0 license. [https://freesound.org/s/213889/](url)
- Cat Howl, by InspectorJ. Used with permission under CC4.0 license. [https://freesound.org/s/415209/](url)
## Known Bugs
I did my best to make this sufficiently bug free to play. I'm not aware of any open bugs. If there are any, they will mostly likely be rendering artifacts. For example, you might see half a floating cat head or a stray crosshair when the map scrolls. That sort of thing. The sprite rendering is admitedly not very robust, and doesn't handle overlaps well. I fixed all the cases I could find, but I would not be surprised if there are others.
There was originally a nifty border effect on the title screen where the terrain extends into the border. This works perfectly on all emulators but is horribly unstable on real hardware for reasons I have not yet figured out. It's disabled in the current version until I figure it out. Just imagine how cool it is, and wonder with me about why GS emulators are all so approximate.
The game may or may not actually be fun. It has had no playtesting or balancing work done. After seven years of working on this, I decided I just needed to finish it and it is what it is. It will not start some new revolution of retro-gaming enthusiasm on the GS.
The game has been tested on:
- The GSPlus emulator (v0.14)
- The KEGS emulator (v1.34) Works, except sound is playing too slowly, which is a KEGS bug
- A ROM01 GS at 2.8MHz
- A ROM01 GS with Transwarp at 7MHz

Binary file not shown.

View File

@ -154,6 +154,16 @@ renderAnimationLoop:
jsr delayMedium
; On last frame, freeze if needed
lda renderAnimationFreezeFrame
beq renderAnimationContinue
inx
cpx PARAML0
beq renderAnimationDone
dex
renderAnimationContinue:
; Restore background
phx
ldy SCRATCHL2
@ -168,12 +178,36 @@ renderAnimationLoop:
bne renderAnimationLoop
renderAnimationDone:
stz renderAnimationFreezeFrame
rts
renderAnimationSkip:
plx
bra renderAnimationDone
renderAnimationFreezeFrame:
.word 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; renderAnimationFreeze
;
; Plays an entire animation statelessly, and freezes on the last frame
;
; Y = Base sprite index
; X = Number of frames
; A = Animation size (use constants above)
; PARAML0 = Pointer to X,Y (16 bits each, Y is bottom relative)
;
; Trashes A,X,Y,PARAML0,PARAML1,PARAML2,SCRATCHL2
;
renderAnimationFreeze:
pha
lda #1
sta renderAnimationFreezeFrame
pla
jmp renderAnimation
; Jump tables for various animation sizes
protectionRoutines:

BIN
catfight.2mg Normal file

Binary file not shown.

2
fan.s
View File

@ -7,7 +7,7 @@
FANRANGE = 100 ; In pixels
FANMAGNITUDE = $20 ; 12.4 fixed point speed delta, in pixels
FAN_AGE = 4
FAN_AGE = 10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; deployFan

90
fonts.s
View File

@ -6420,156 +6420,156 @@ font16char32:
font16char33:
tya
tcs
; Line 15, Pixel values: 2222 2000 0000 0000
; Line 15, Pixel values: faaa a000 0000 0000
tsc
sec
sbc #6
tcs
pea $2222
pea $aafa
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 14, Pixel values: 2222 2000 0000 0000
; Line 14, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $2222
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 13, Pixel values: 2222 2000 0000 0000
; Line 13, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $2222
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 12, Pixel values: 2222 2000 0000 0000
; Line 12, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $2222
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 11, Pixel values: 2222 2000 0000 0000
; Line 11, Pixel values: ffff f000 0000 0000
tsc
sec
sbc #158
tcs
pea $2222
pea $ffff
lda 3,S
and #$ff0f
ora #$0020
ora #$00f0
sta 3,S
; Line 10, Pixel values: 0000 0000 0000 0000
; Line 9, Pixel values: 2222 2000 0000 0000
; Line 9, Pixel values: faaa a000 0000 0000
tsc
sec
sbc #318
tcs
pea $2222
pea $aafa
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 8, Pixel values: 2222 2000 0000 0000
; Line 8, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $2222
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 7, Pixel values: 8222 2000 0000 0000
; Line 7, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $2282
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 6, Pixel values: 8822 2000 0000 0000
; Line 6, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $2288
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 5, Pixel values: 8882 2000 0000 0000
; Line 5, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $8288
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 4, Pixel values: 8888 2000 0000 0000
; Line 4, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $8888
pea $bbfb
lda 3,S
and #$ff0f
ora #$0020
ora #$00a0
sta 3,S
; Line 3, Pixel values: 8888 8000 0000 0000
; Line 3, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $8888
pea $bbfb
lda 3,S
and #$ff0f
ora #$0080
ora #$00a0
sta 3,S
; Line 2, Pixel values: 8888 8000 0000 0000
; Line 2, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $8888
pea $bbfb
lda 3,S
and #$ff0f
ora #$0080
ora #$00a0
sta 3,S
; Line 1, Pixel values: 8888 8000 0000 0000
; Line 1, Pixel values: fbbb a000 0000 0000
tsc
sec
sbc #158
tcs
pea $8888
pea $bbfb
lda 3,S
and #$ff0f
ora #$0080
ora #$00a0
sta 3,S
; Line 0, Pixel values: 8888 8000 0000 0000
; Line 0, Pixel values: ffff f000 0000 0000
tsc
sec
sbc #158
tcs
pea $8888
pea $ffff
lda 3,S
and #$ff0f
ora #$0080
ora #$00f0
sta 3,S
jmp renderCharJumpReturn_font16

View File

@ -33,6 +33,7 @@ beginGameplay:
; Generate, compile, and clip terrain
stz mapScrollPos
stz leftScreenEdge
stz mapScrollRequested
lda #160-GAMEOBJECTWIDTH/4-2
sta rightScreenEdge
jsr generateTerrain
@ -331,13 +332,54 @@ endTurnWrap:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; endGame
;
; Handles someone winning
; Handles someone winning. Assumes "someone" is current player
;
endGame:
SAVE_AXY
lda currentPlayer
beq endGame0
lda #victoryText1
bra endGameRender
endGame0:
lda #victoryText0
endGameRender:
sta PARAML0
ldy #$48b7
lda #2
jsl renderStringFar
; Play pee animation under loser (non-current player)
lda currentPlayer
eor #1
tay
PLAYERPTR_Y
lda playerData+GO_POSX,y
sta endGamePeePos
lda playerData+GO_POSY,y
dec
dec
sta endGamePeePos+2
lda #endGamePeePos
sta PARAML0
ldy #40
ldx #5
lda #ANIMATION_SIZE_16x16
jsr renderAnimationFreeze
; Wait for keypress
jsr kbdWaitForAnyKey
lda #1
sta quitRequested
RESTORE_AXY
rts
endGamePeePos:
.word 0,0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; scrollMap
@ -535,3 +577,7 @@ mapScrollPos:
rightScreenEdge: ; Right edge minus one game object width, for easy render clipping
.word 160-GAMEOBJECTWIDTH/4-2
victoryText0:
pstring "SPROCKET WINS!"
victoryText1:
pstring " TINKER WINS!"

View File

@ -109,10 +109,10 @@ kbdScanGameplay:
beq kbdScanPeriod
cmp #(' ' + $80)
beq kbdScanSpace
cmp #(';' + $80)
beq kbdScanSemiColon
cmp #(39 + $80)
beq kbdScanApostrophe
; cmp #(';' + $80) ; For debugging cat movement
; beq kbdScanSemiColon ;
; cmp #(39 + $80) ;
; beq kbdScanApostrophe ;
cmp #(9 + $80)
bne kbdScanDebugPiggyback
jmp kbdScanTab

View File

@ -6,7 +6,7 @@
;
INVENTORY_ITEMS = 3
INVENTORY_ITEMS = 5
ITEM_WIDTH = 16 ; In pixels
ITEM_HEIGHT = 16 ; In pixels
ICON_WIDTH = 8 ; In pixels

View File

@ -434,15 +434,15 @@ fileOpenTitle:
.byte 0 ; Padding
codePath:
pstring "/GSAPP/CODEBANK"
pstring "/CATFIGHT/CODEBANK"
spritePath:
pstring "/GSAPP/SPRITEBANK"
pstring "/CATFIGHT/SPRITEBANK"
soundPath:
pstring "/GSAPP/SOUNDBANK"
pstring "/CATFIGHT/SOUNDBANK"
fontPath:
pstring "/GSAPP/FONTBANK"
pstring "/CATFIGHT/FONTBANK"
titlePath:
pstring "/GSAPP/TITLE"
pstring "/CATFIGHT/TITLE"
.include "sharedGraphics.s"
.include "loaderGraphics.s"

View File

@ -24,7 +24,7 @@ playerData:
.word 0 ; Anger
.byte 8,"SPROCKET " ; Name
.word 29 ; Base Sprite
.word 0,5,7,0,0,0,0,0 ; Prices
.word 0,5,7,1,1,0,0,0 ; Prices
.word 0 ; Current weapon
.word 0 ; Treats
.repeat 86
@ -45,7 +45,7 @@ playerData:
.word 0 ; Anger
.byte 8,"TINKER " ; Name
.word 20 ; Base Sprite
.word 0,5,7,0,0,0,0,0 ; Prices
.word 0,5,7,1,1,0,0,0 ; Prices
.word 0 ; Current weapon
.word 0 ; Treats
@ -132,9 +132,8 @@ playerCreateInit:
sta playerData+PD_POWER,y
lda #START_TREATS
sta playerData+PD_TREATS,y
lda #MAX_ANGER
sta playerData+PD_ANGER,y
lda #0
sta playerData+PD_ANGER,y
sta playerData+PD_CURRWEAPON,y
lda #1
sta playersDirty
@ -246,6 +245,13 @@ playerFire:
sbc SCRATCHL
sta playerData+PD_TREATS,y
; Check for movement
lda playerData+PD_CURRWEAPON,y
cmp #PT_MOVELEFT
beq playerFireMoveLeft
cmp #PT_MOVERIGHT
beq playerFireMoveRight
; Animate the shooting
phy
ldy SCRATCHL2
@ -271,8 +277,19 @@ playerFire_done:
playerFire_abort:
pla ; Balance stack
jsr renderCrosshair ; Keep crosshair from disappearing on abort. Kinda hacky
bra playerFire_done
playerFireMoveLeft:
lda #-2
sta playerMoveRequested
bra playerFire_abort
playerFireMoveRight:
lda #2
sta playerMoveRequested
bra playerFire_abort
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; playerIntersectRect
@ -527,9 +544,7 @@ syncPlayerHeader:
PLAYERPTR_Y
; Convert anger to progress bar value
sec
lda #MAX_ANGER
sbc playerData+PD_ANGER,y
lda playerData+PD_ANGER,y
lsr
lsr
jsr setProgressBar

View File

@ -92,6 +92,8 @@ projectileTypes:
PT_SPIT = 0
PT_BOMB = 1
PT_FAN = 2
PT_MOVELEFT = 3
PT_MOVERIGHT = 4
; Spit
.word 4 ; Damage
@ -151,6 +153,46 @@ projectileTypes:
.byte 0 ; Padding to 32-byte boundary
.endrepeat
; Move Left
.word 0 ; Damage
.word 0 ; Crater radius
.word 0 ; Frame 0
.word 38 ; Frame 1
.word 0 ; Frame 2
.addr 0 ; Deploy
.addr 0 ; Update
.addr 0 ; Render
.addr 0 ; Unrender
.addr 0 ; Protect
.addr 0 ; Cleanup
.word 0 ; Directional
.word 0 ; Mining
.repeat 6
.byte 0 ; Padding to 32-byte boundary
.endrepeat
; Move Right
.word 0 ; Damage
.word 0 ; Crater radius
.word 0 ; Frame 0
.word 39 ; Frame 1
.word 0 ; Frame 2
.addr 0 ; Deploy
.addr 0 ; Update
.addr 0 ; Render
.addr 0 ; Unrender
.addr 0 ; Protect
.addr 0 ; Cleanup
.word 0 ; Directional
.word 0 ; Mining
.repeat 6
.byte 0 ; Padding to 32-byte boundary
.endrepeat
PT_DAMAGE = 0 ; Byte offsets into projectile type data structure
PT_RADIUS = 2
@ -638,6 +680,7 @@ endProjectile:
; Trashes A
;
deleteProjectile:
phx
lda projectileData+GO_POSX,y
bmi deleteProjectileDone ; Already deleted
@ -654,6 +697,7 @@ deleteProjectile:
JSRA
deleteProjectileDone:
plx
rts
@ -669,7 +713,7 @@ deleteAllProjectilesLoop:
PROJECTILEPTR_Y
jsr deleteProjectile
inx
cpx #4
cpx #3
bne deleteAllProjectilesLoop
RESTORE_AXY
@ -922,12 +966,12 @@ processPlayerImpact:
; Apply damage
lda playerData+PD_ANGER,x
sec
sbc projectileTypes+PT_DAMAGE,y
clc
adc projectileTypes+PT_DAMAGE,y
; Check for death
beq processPlayerImpactDeath
bmi processPlayerImpactDeath
cmp #MAX_ANGER
bcs processPlayerImpactDeath
sta playerData+PD_ANGER,x
rts

View File

@ -2,24 +2,26 @@
DrawSpriteBank :
ASL ; A=Sprite Number ($0000-$0025)
ASL ; A=Sprite Number ($0000-$002C)
TAX ; Y=Target Screen Address ($2000-$9D00)
LDA SpriteBankNum,X ; Relative Sprite Number Table
JMP (SpriteBankBank,X) ; Bank Number Table
SpriteBankNum :
.dbyt $0C00,$0B00,$1E00,$1700,$1800,$1D00,$2400,$2200
.dbyt $1B00,$1C00,$2100,$2500,$1100,$1500,$1600,$2300
.dbyt $2000,$1F00,$1A00,$1900,$0D00,$1200,$0600,$0000
.dbyt $0300,$0400,$1000,$1300,$0E00,$0900,$0800,$0700
.dbyt $0200,$0100,$0500,$0F00,$1400,$0A00
.dbyt $0D00,$0900,$2000,$1800,$1A00,$1F00,$2600,$2400
.dbyt $1D00,$1E00,$2300,$2C00,$1100,$1500,$1600,$2500
.dbyt $2200,$2100,$1C00,$1B00,$0E00,$1200,$0600,$0000
.dbyt $0300,$0400,$1000,$1300,$0C00,$0B00,$0A00,$0700
.dbyt $0100,$0200,$0500,$0F00,$1400,$0800,$1900,$1700
.dbyt $2B00,$2A00,$2900,$2800,$2700
SpriteBankBank :
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
.addr SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00,SpriteBankBank00
SpriteBankBank00 :
JSL $AA0000

View File

@ -51,7 +51,7 @@ titleScreenCopyLoop:
; Render menu text
jsr titleScreenRenderMenu
jsr setBorderAtScanLine
; jsr setBorderAtScanLine
; Fade in
lda #titlePalette
@ -420,7 +420,7 @@ helpText0:
helpText1:
pstring "YOUR GOAL IS TO ANGER THE OTHER CAT"
helpText2:
pstring "SO MUCH THAT SHE PEES AND RUNS OFF."
pstring "SO MUCH THAT SHE PEES."
helpText3:
pstring "_^ AIM"
helpText4: