Weapons built from traits, fashion, Hourglass, About tab, and Ithaca

- Every attack is now assembled from traits on its definition instead
  of per-weapon code: an anchor and path (thrusts, out-and-back, arcs),
  shared flight physics (gravity, drag, acceleration, homing, and one
  wall response: end, burst, stick, crawl, bounce, stop, pass, return,
  latch), and flags like bouncy, drifting, tethered, orbiting, instant
  and arming. Melee are projectiles too.
- Shots have a lifetime and a fade (when damage bottoms out). Range is
  speed times lifetime. Ricochets and the Vacuum wind lifetime back.
- The Vacuum pulls anyone's shots, and its airblast flips them out
  along the aim, claiming enemies' (fading into your colour).
- New trinket: Hourglass, longer projectile lifetime and range. Ropes
  and chains lengthen with it and the Accelerator.
- Fashion: 23 items worn on the head, face or torso, chosen in Profile.
- Flamethrower flames hit continuously, the whip coils and sweeps,
  bouncing shots roll over ramps, and Ricochet relights grenade fuses.
- Profile tab, colour tooltips, option hints on every setting, an
  About tab with credits and links, and the Ithaca font.
- Loadouts lock once readied, tomatoes clear with the match, and the
  round-over pause is 4 seconds.
- CC0 license. Tools and CLAUDE.md are no longer tracked, and the web
  shell moves to web/.
This commit is contained in:
shweet committed 2026-11-10 15:27:12 -05:00
1 parent e55596b276
commit e9d8cac926
101 files changed
+5787 -7148

No files matched your search

+12 -7
View File
@@ -60,6 +60,7 @@ void game_tick(Game& game)
match.isSandboxRequested =
game.menu.isLeaving || (!game.menu.isOpen && input.is_pad_tapped(SDL_GAMEPAD_BUTTON_EAST));
match.colorWanted = game.settings.color_get();
match.fashionWanted = game.settings.fashion;
game.sim.tick();
input.tick_end();
}
@@ -122,9 +123,8 @@ struct FrameClock
static Game game;
static FrameClock frameClock;
// One frame: input, as many fixed ticks as the time since the last frame allows, then drawing (unless it's not to be
// drawn). Returns whether to keep going.
static bool frame_run(bool isDrawn = true)
// One frame's input and as many fixed ticks as the time since the last frame allows.
static void frame_step()
{
Uint64 now = SDL_GetPerformanceCounter();
frameClock.accumulator +=
@@ -143,7 +143,7 @@ static bool frame_run(bool isDrawn = true)
if (session.is_wanted(game))
{
Fighter& own = game.local_get();
bool isHeld = game.menu.isOpen || game.chat.isOpen || session.is_watching();
bool isHeld = game.menu.isOpen || game.chat.isOpen || session.is_watching(game);
Controls controls = game.input.controls_get(DEVICE_KEYBOARD, game.camera, own, isHeld);
session.update(game, controls);
game.input.tick_end();
@@ -167,8 +167,13 @@ static bool frame_run(bool isDrawn = true)
}
game.settings.update(game);
game.alpha = frameClock.accumulator / TICK;
if (isDrawn)
game_draw(game);
}
// One frame, stepped and drawn. Returns whether to keep going.
static bool frame_run()
{
frame_step();
game_draw(game);
return !game.input.isQuit;
}
@@ -184,7 +189,7 @@ static void frame_callback()
extern "C" EMSCRIPTEN_KEEPALIVE void frame_hidden()
{
if (game.session.is_wanted(game))
frame_run(false);
frame_step();
}
#endif