BomberTalk Alpha

I got the first alpha of BomberTalk working today. It's a networked Bomberman clone for Classic Macintosh. I just played a game across a Mac SE, a Performa 6200, and a Performa 6400. Hardware from 1987, 1994, and 1995, all on the same LAN.

There are no sprites yet. Players are coloured blocks, bombs are smaller blocks, and explosions just flash the tiles where the fire goes. It's rough, but the networking works. All three machines find each other, connect, and stay in sync.

#The stack

BomberTalk sits on top of a dependency chain I've been building up over the past few months. Each layer is its own project and its own repo. Nothing moved up the stack until the layer below it worked on all three machines.

BomberTalk Networked Bomberman for Classic Mac C89 · QuickDraw · GWorld double-buffering PeerTalk UDP discovery · TCP mesh · chunked messaging clog Structured logging with network sink Retro68 GCC cross-compiler for 68k and PPC

clog is a small logging library. About 480 lines of C89. It writes timestamped messages to a file and can also broadcast them over UDP, which is the bit I actually care about. On a Mac SE that might crash at any moment, I want to be watching the logs from my Linux box, not trying to read them off the dead machine afterwards. I run socat UDP-RECV:7355 - and see every log line from all three Macs as it happens.

PeerTalk is a networking SDK. About 4,100 lines of C89. It does peer discovery over UDP broadcast, reliable messaging over TCP, and fast positional updates over UDP. It has three completely different backends under the same API: POSIX (BSD sockets), MacTCP (for the Mac SE and 6200), and Open Transport (for the 6400).

BomberTalk sits on top of both. It registers seven message types with PeerTalk at startup and from there it's a standard game loop: poll for input, poll the network, update state, draw.

#How the pieces fit together

All three machines connect in a peer-to-peer mesh. There's no server. Every machine talks directly to every other machine.

Mac SE 68000 · 8 MHz · System 6.0.8 PeerTalk MacTCP clog Performa 6200 PPC 603 · 75 MHz · System 7.5.3 PeerTalk MacTCP clog Performa 6400 PPC 603e · 200 MHz · System 7.6.1 PeerTalk Open Transport clog TCP/UDP TCP/UDP TCP/UDP UDP log broadcast (port 7355) Linux box socat log monitor Game traffic (TCP + UDP) Log broadcast (UDP)

Player positions go over UDP because speed matters more than guaranteed delivery. Bomb placements, explosions, block destruction, and kills go over TCP because those have to arrive. Player IDs are assigned by sorting everyone's IP address, so every machine works out the same answer independently without any negotiation.

#The lobby

PeerTalk broadcasts a UDP discovery packet every two seconds. As peers turn up, they appear in the lobby. Here's all three machines in the lobby, each showing they've found the other two:

Mac SE running BomberTalk lobby showing two discovered peers
Mac SE (System 6.0.8) - lobby with two peers found
Performa 6400 running BomberTalk lobby showing two discovered peers
Performa 6400 (System 7.6.1) - lobby with two peers found
Performa 6200 running BomberTalk lobby showing two discovered peers
Performa 6200 (System 7.5.3) - lobby with two peers found

Any player can press Return to start. PeerTalk sorts out the TCP mesh and then you're in.

#The game

It's Bomberman. You walk around a 15x13 grid, place bombs, blow up destructible blocks, and try to be the last one standing. The game runs tick-based rather than frame-based, which matters because the Mac SE gets about 15 fps on a quiet board but drops to around 8 as gameplay picks up, while the 6400 does around 24. If I'd tied game speed to frame rate, the machines would play at completely different speeds.

Performa 6400 running BomberTalk in-game showing coloured player blocks on a grid
Performa 6400 - three players on the grid
Performa 6200 running BomberTalk in-game
Performa 6200 - same game, same positions
Mac SE running BomberTalk in monochrome
Mac SE - monochrome, 16x16 tiles instead of 32x32
Close-up of BomberTalk gameplay showing player blocks and grid
Close-up of the 6400 - three player blocks in their starting positions
Mac SE running BomberTalk showing monochrome game grid with two player blocks
Mac SE - two players on the monochrome grid

Everything you see is plain QuickDraw. Coloured rectangles for players, coloured tiles for the grid. Bombs flash when they go off. Sprites are next once I've done another round of optimisation.

The rendering is GWorld double-buffered with dirty rectangle tracking. Only tiles that actually changed get redrawn each frame. If more than half the grid is dirty it just blits the whole screen instead of iterating tile by tile. The Mac SE has a 68000 at 8 MHz, 4 MB of RAM, and no Colour QuickDraw, so it gets a separate rendering path using plain BitMap operations on its 1-bit monochrome display. The game uses 16x16 tiles on the SE instead of 32x32 so the play area fits the 512x342 screen. All memory is pre-allocated at startup. No malloc during gameplay.

The SE's networking goes through MacTCP, same as the 6200, while the 6400 uses the newer Open Transport API. PeerTalk deals with all of that. BomberTalk just calls the same functions regardless of which machine it's running on.

#What's next

Sprites. The coloured blocks are fine for testing the networking and game logic, but I want PICT resources loaded from the resource fork. Colour sprites for the PPC machines, monochrome ones for the SE. The renderer already checks for PICTs at startup and drops back to rectangles if they're missing, which is what's happening now.

After that, more optimisation. The Mac SE is playable but tight. 8 MHz doesn't leave much room.

The code is at github.com/matthewdeaves/BomberTalk. The full stack: clog (logging) → PeerTalk (networking) → BomberTalk (game).