A 4-player fighting game for the Atari 2600, built with batariBASIC targeting the 64kiB EF + SuperChip cartridge format.
ChaosFight uses a dual-context execution model: Admin Mode (title screens, menus) and Game Mode (gameplay). The game runs on a multisprite kernel, requiring 4-player sprite support while maintaining 60fps performance through careful frame budgeting.
- ConvertToBCD routine: Optimized binary-to-BCD conversion algorithm by Thomas Jentsch (used with permission)
Standard RAM (74 bytes total):
a-z: 26 bytes (built-in and user variables)var0-var47: 48 bytes ($A4-$D3)
SuperChip RAM (SCRAM) (128 bytes):
- Read ports:
r000-r127($F080-$F0FF) - Write ports:
w000-w127($F000-$F07F) - Critical: SCRAM has separate read/write ports mapping to the same physical RAM. Always use
_Rsuffix for reads,_Wfor writes (e.g.,selectedArena_W,selectedArena_R).
Memory Contexts:
- Admin Mode (GameModes 0-5, 7): Title, preambles, character select, arena select, winner screen
- Game Mode (GameMode 6): Active gameplay
- Variables can be redimmed between contexts (see
Source/Common/Variables.basfor allocations)
- Zero-page (Standard RAM): Frame-critical variables (physics, positions, state)
- SCRAM: Less-frequent variables (animation counters, timers, menu state)
See Source/Common/Variables.bas for complete memory layout.
Music/Sound Assets:
- Bank 1: Character theme songs (IDs 6-28) - Bolero, LowRes, RoboTito, SongOfTheBear, DucksAway, Character16-30 themes
- Bank 15: Sound effects + character theme songs (IDs 0-5) - Bernie, OCascadia, Revontuli, EXO, Grizzards, MagicalFairyForce
Character Art Assets:
- Bank 2: Character sprites (0-7) - Bernie, Curler, DragonOfStorms, ZoeRyen, FatTony, Megax, Harpy, KnightGuy
- Bank 3: Character sprites (8-15) - Frooty, Nefertem, NinjishGuy, PorkChop, RadishGoblin, RoboTito, Ursulo, Shamone
- Bank 4: Character sprites (16-23) - Character16-23 (placeholders)
- Bank 5: Character sprites (24-31) - Character24-30, MethHound
- Bank 6: Character selection (main/render)
- Bank 7: Missile system (tables, physics, collision) + combat system
- Bank 8: Physics system (gravity, movement, special abilities) + screen layout + health bars + main loop dispatcher
- Bank 10: Sprite rendering (character art loader, player rendering, elimination) + character attacks system
- Bank 11: Gameplay loop (init/main/collision resolution/animation) + attack support data
- Bank 12: Character data system + Titlescreen system (definitions, cycles, falling animation, titlescreen graphics/kernel)
- Bank 13: Input system (movement, player input, guard effects)
- Bank 14: Console handling (detection, controllers, game mode transitions, character controls)
- Bank 9: Winner/data tables
- Bank 16: Arenas + drawscreen (main loop, arena data/loader, special sprites, numbers font, font rendering)
Central dispatcher that routes to mode-specific handlers:
MainLoop
if switchreset then gosub bank11 WarmStart : goto MainLoopContinue
if gameMode = 0 then gosub bank9 PublisherPreambleMain : goto MainLoopContinue
if gameMode = 1 then gosub bank9 AuthorPreamble : goto MainLoopContinue
...Game Modes:
0: Publisher Prelude1: Author Prelude2: Title Screen3: Character Select4: Falling Animation5: Arena Select6: Gameplay (dispatches toGameMainLoopin Bank 11)7: Winner Announcement
Per-frame sequence:
- Console switches (pause, reset)
- Player input (with Quadtari multiplexing)
- Animation updates (10fps)
- Movement/physics
- Collisions (players, missiles, playfield)
- Combat/damage
- Sprite rendering
- Health bar updates
- Screen draw
Frame budgeting distributes expensive operations (health bars, multi-player collisions) across multiple frames.
The game supports these sprite configurations per player:
- P0 (Player 1):
character|? - P1 (Player 2):
character|CPU|No|? - P2 (Player 3):
character|No|? - P3 (Player 4):
character|No|? - P4 (Arena Select):
digit|blank - P5 (Arena Select):
digit|?
Notes:
character: Full character sprite with animations?: Question mark glyph spriteCPU: CPU indicator sprite (Player 2 only)No: "No" text sprite (Players 2-4, not Player 1)digit: Numeric digits for arena selectionblank: Empty/cleared sprite- P4 and P5 are used only during arena selection
- Auto-detects: CX-40, Genesis 3-button, Joy2B+, Quadtari
- Quadtari: Frame multiplexing (even=P1/P2, odd=P3/P4)
- Enhanced controllers: Additional button mappings via INPT0-5
- Data-driven via
on-gotodispatch (O(1) lookups) - Character properties: Weight, missile types, special abilities
- Sprite loading:
SpriteLoader.bas→ bank-specific assembly routines
- Supports up to 4 active missiles
- Physics: Gravity, bounce, friction (character-specific)
- Collision: AABB detection vs players, playfield
- Gravity and momentum handling (
Source/Routines/PlayerPhysicsGravity.bas, bank 8) - Boundary wrap and screen clamp logic (
Source/Routines/PlayerBoundaryCollisions.bas, bank 10) - Playfield collision sampling (
Source/Routines/PlayerPlayfieldCollisions.bas, bank 10) - Weight-based jump height, fall damage mitigation, knockback resistance, and recovery frames
- 8 frames × 16 actions per character
- 10fps update rate (spread across frames)
- Character-specific attack dispatches to individual attack routines (BernieAttack.bas, HarpyAttack.bas, etc.)
Source Format: Source/Art/CharacterName.xcf (GIMP)
Pipeline:
# XCF → PNG (automatic via Makefile)
make Source/Art/CharacterName.png
# PNG → batariBASIC data (automatic)
make Source/Generated/CharacterName.bas
# Generate all characters
make charactersGenerated Output (Source/Generated/CharacterName.bas):
data CharacterNameFrames: Deduplicated sprite frame datadata CharacterNameFrameMap: Indirection table (action × frame → frame index)
Bank Allocation:
- Bank 2: Characters 0-7
- Bank 3: Characters 8-15
- Bank 4: Characters 16-23 (placeholders)
- Bank 5: Characters 24-31
Sprite Loading: Source/Routines/SpriteLoader.bas dispatches to bank-specific assembly routines (CharacterArtBank*.s).
- Bitmaps (48×42px):
Source/Art/BitmapName.xcf→Source/Generated/Art.BitmapName.s - Music:
Source/Art/SongName.mscz→Source/Generated/Song.SongName.{NTSC,PAL,SECAM}.bas - Sounds:
Source/Art/SoundName.wav→Source/Generated/Sound.SoundName.{NTSC,PAL,SECAM}.bas - Fonts:
Source/Art/FontName.png→Source/Generated/FontName.bas
All asset compilation handled by SkylineTool (included submodule).
- batariBASIC (included in
Tools/) - DASM assembler (included)
- SBCL + Common Lisp (for SkylineTool)
- GIMP (for XCF→PNG export)
- MuseScore (optional, for music)
# Build all ROMs (NTSC, PAL, SECAM)
make all
# Build ROMs only
make game
# Build documentation
make doc
# Generate all character sprites
make characters
# Test in Stella emulator
make emuDist/ChaosFight26.{NTSC,PAL,SECAM}.a26- ROM filesDist/ChaosFight26.{sym,lst,pro}- Debug symbols/listingsDist/ChaosFight26.{pdf,html}- Game manual
- Preprocess batariBASIC (C preprocessor with
-traditionalflag) - Compile to assembly via batariBASIC
- Assemble via DASM with bank switching
- Link and generate ROM
- Built-ins:
lowercase(temp1,joy0fire) - User variables:
camelCase(playerX,gameState) - Constants:
PascalCase(MaxCharacter,ColBlue(14)) - Routines/Labels:
PascalCase(LoadCharacterSprite,HandleInput) - SCRAM variables:
camelCase_R/camelCase_W(separate read/write)
- One subroutine per file for large/complex routines
- Group related subroutines when tightly coupled
- Files in
Source/Routines/, included by bank files inSource/Banks/
All subroutines must include header comments:
LoadCharacterSprite
rem Load sprite data for character
rem Input: temp1 = character index, temp2 = frame
rem Output: Sprite loaded into player registerSee Source/StyleGuide.md for complete coding standards.
# Install dependencies (Fedora/RHEL)
sudo dnf install gcc make gimp sbcl texlive texinfo
# Initialize submodules
git submodule update --init --recursive
# Build tools
make bin/skyline-tool bin/zx7mini
# Build game
make allSource/Routines/MainLoop.bas- Main execution dispatcherSource/Routines/GameLoopMain.bas- Gameplay per-frame loopSource/Common/Variables.bas- Memory layout and variable declarationsSource/Common/CharacterDefinitions.bas- Character data tablesSource/Routines/ControllerDetection.bas- Controller auto-detectionSource/Routines/MissileSystem.bas- Projectile managementSource/Routines/SpriteLoader.bas- Character sprite loadingSource/Banks/Banks.bas- Bank organization and includesMakefile- Build configuration and asset pipeline
ChaosFight - Copyright 2025 Bruce-Robert Pocock