Tomatoes, match tabs, shared pings, and a round of fixes

- On the results, everyone but the winner splats tomatoes where they
  click (bots aim at the winner), with a new splat sound.
- During a match the menu has the item tabs (choosing when the
  countdown allows, and otherwise levelling the sandbox's levels for
  when you're back), Play (the game's rules) and Settings.
- Pings are shared through the server (protocol 4), so other players'
  connection bars show over their heads and on their windows.
- PvP comes into lobbies with your profile and is saved.
- The choice menu opens by itself however the countdown began.
- Knocked-out fighters keep their buttons current, so Ready on the
  results toggles once per press.
- The weapon wheel wraps both ways. Readying with empty slots plays
  the equip sound for your own fighter.
- Shock Absorber: up to 50% less weapon movement and 33% less
  knockback. Only the catalog previews the next level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shweetandClaude Opus 5.5 committed 2026-11-08 18:11:06 -05:00
1 parent cdb0845da2
commit 9a41474069
29 files changed
+295 -79

No files matched your search

+13 -6
View File
@@ -69,6 +69,7 @@ constexpr float WHIP_INNER = 2;
constexpr float WHIP_JITTER = 0.5f;
constexpr float WHIP_OUTER = 5;
constexpr float WISP_FRAME_STAGGER = 0.3f;
constexpr Burst TOMATO_BURST = {.gravity = 400, .life = 0.5f, .size = 2, .speed = 140, .spread = 1.2f, .count = 12};
// A random offset for an empowered attack or fighter to shake by, wider the more its colour fills in, like a damage
// number.
@@ -390,16 +391,22 @@ void Scene::match_start()
game.menu.isOpen = false;
}
void Scene::choice_open()
// A tomato thrown on the results: a splat in the thrower's colour where it landed, spraying juice.
void Scene::tomato_splat(Vec2 position, int owner)
{
if (game.local_count() == 1)
game.menu.choice_open(game);
if (isMuted)
return;
Color color = game.color_get(owner, true);
game.effects.splat_spawn(position, color);
game.effects.burst(TOMATO_BURST, position, -PI / 2, color);
game.audio.play(SOUND_SPLAT);
}
void Scene::choice_close()
// Readying with empty slots dealt them: this screen's own fighters hear the items go in.
void Scene::deal_play(int fighter)
{
if (game.local_count() > 0)
game.menu.isOpen = false;
if (!isMuted && game.is_local(fighter))
game.audio.play(SOUND_EQUIP);
}
void Scene::sandbox_return()