- Ricochet now bounces every attack that moves. Swings sweep back, the uppercut bounces its fighter, punches and Lance pokes come loose and thrust again from the wall, then a held Lance turns and flies home. A whip lash's crack glances the reach a wall cut off as a strand. Vacuum cones glance into further cones that suck around corners. Bolts, grapple hooks and charged cracks bounce, and so do shots heading home (boomerangs, flail balls, hooks). - Every ricochet plays its sound (flames too), adds its damage (the charged crack's blast too), and gives the attack its hits back. With bounces left, a bouncing shot hops off anything it touches, even at rest, until they're spent. Rays fired from inside a wall back out first instead of bouncing on the spot. - Aim previews: falling shots arc at their real speed, instants (beams, cracks) take their real path and full range per bounce, Vacuum cones show their glances, and every cone draws at its spread width. - A client out of step with the server asks for its room again and resyncs. The checksum covers much more of the match. Protocol 12. - Fighters stuck inside solid ground slowly suffocate (not in the sandbox or races). - Sword slashes smaller (basic 25%, charged slash scales halved). The Good Stuff: "Aye, me bottle o'scrumpy!"
Smack a Brother
Online platform fighter. Lobbies of up to 16 players, games of up to 8. Play it in the browser here.
Clarification
This application was developed with the assistance of a large language model.
Build
After cloning and entering the repository's directory, make sure to initialize the submodules:
git submodule update --init --recursive
Everything (SDL, libdatachannel, simdjson) is built statically from the submodules. The game's resources are in resources/ and get linked next to the executable.
Linux
Needs OpenSSL, plus the X11/Wayland and audio headers SDL builds against.
mkdir build
cd build
cmake ..
make
Web
Needs the Emscripten SDK.
emcmake cmake -B build-web -DCMAKE_BUILD_TYPE=Release
cmake --build build-web
This makes smack-a-brother.html, .js, .wasm and .data. Rename the .html to index.html and serve all four.
Server
The server builds on its own, without SDL. It needs OpenSSL (libssl-dev on Debian).
cmake -S server -B build-server -DCMAKE_BUILD_TYPE=Release
cmake --build build-server
Run it with:
smack-a-brother-server [port] [first UDP port] [last UDP port]
Defaults are 47800, 47810 and 47899. It only listens on 127.0.0.1, so put it behind a reverse proxy that handles TLS. For nginx:
location /smack-a-brother/ws {
proxy_pass http://127.0.0.1:47800;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 120s;
}
Open the UDP range in the firewall (e.g. ufw allow 47810:47899/udp).
Netcode
- The server runs every lobby: a sandbox everyone in the lobby shares, plus the games queued in it. Each is its own simulation. All of them run on one thread, at 60 ticks a second.
- Clients send their inputs ahead of time. Each tick the server takes what has arrived (repeating a player's last inputs if they're late), steps the simulation, and sends everyone the inputs it used. Every 60 ticks it also sends a checksum.
- Clients run the same simulation about 3 ticks ahead of the server, guessing other players' inputs. When the server's inputs differ from the guess, the client rolls back and replays.
- The simulation is deterministic on every platform (strict floating point, own math functions), so desktop and web play together.
- Clients connect over a WebSocket first (lobbies, chat, WebRTC signaling). Then they open a WebRTC connection to the server with two data channels: a reliable one, and an unreliable one for inputs and frames. If WebRTC can't connect, everything stays on the WebSocket.
- STUN:
stun.l.google.com:19302. - The server address is set in Settings. Default:
wss://shweetz.net/smack-a-brother/ws.
Joining a lobby directly
- Desktop:
smack-a-brother --join CODE - Web:
https://shweetz.net/smack-a-brother/?lobby=CODE
Environment variables
SAB_SERVER_URL: use a different server, e.g.ws://127.0.0.1:47800SAB_NET_LAG: add this many milliseconds of lagSAB_NET_LOSS: drop this percent of input packetsSAB_NET_STATS: log how the client is keeping up with the server
License
The game's code and art are released into the public domain under CC0 1.0. Not covered by that: the Ithaca font (SIL Open Font License, see resources/font/LICENSE.txt), the sound effects cut from the Sound Ideas libraries (see resources/sfx/SOURCES.md), and the libraries in external/, each under its own license.



