shweet 7b98ff1d6b Everything ricochets, desync resync, aim previews that fall, and suffocation
- 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!"
2026-11-11 00:56:16 -05:00
2026-11-08 01:30:33 -05:00
2026-11-08 17:09:11 -05:00
2026-11-08 01:30:33 -05:00
2026-11-08 01:30:33 -05:00

Smack a Brother

1

2

3

4

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:47800
  • SAB_NET_LAG: add this many milliseconds of lag
  • SAB_NET_LOSS: drop this percent of input packets
  • SAB_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.

S
Description
No description provided
Readme CC0-1.0
2.6 MiB
0 Stars 1 Watchers 0 Forks
Languages
C++ 99%
CMake 0.8%