Raise online play to 16-player lobbies and 8-player games

Lobbies hold 16 players and the sandbox 16 fighters, games up to 8. The arena
gets spawns 5-8 (outer ledges and middle platforms) and the race start eight
places. The sandbox adds eight more spawns, each the open spot farthest from
the rest. Rival cards wrap into rows of four, the lobby's player list goes to
two tiny columns when crowded, and the server keeps frame packets to one
datagram. Formatted with clang-format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shweetandClaude Opus 5.5 committed 2026-11-08 02:33:20 -05:00
1 parent 56af1c357c
commit 6003175173
19 files changed
+247 -140

No files matched your search

+48 -47
View File
@@ -336,8 +336,7 @@ std::vector<Vec2> lash_get(Attack& attack)
static bool is_hostile(Sim& sim, int owner, int target)
{
Match& match = sim.match;
return match.state != MATCH_PRACTICE ||
(sim.fighters[owner].isPvp && sim.fighters[target].isPvp);
return match.state != MATCH_PRACTICE || (sim.fighters[owner].isPvp && sim.fighters[target].isPvp);
}
static bool is_target(Sim& sim, int target, int owner)
@@ -760,7 +759,8 @@ bool Weapons::is_spawned(Sim& sim, Fighter& fighter, Shot shot)
if (weapon.flash > 0)
sim.cues->flash_spawn(muzzle, vec2_angle(aim), weapon.flash, fighter.index);
if (weapon.isEjecting)
sim.cues->burst_spawn(CASING_BURST, attack.origin, vec2_angle(aim) - side * (PI / 2 + CASING_BACK), fighter.index);
sim.cues->burst_spawn(CASING_BURST, attack.origin, vec2_angle(aim) - side * (PI / 2 + CASING_BACK),
fighter.index);
if (isCharged)
sim.cues->shake_add(def.shake * FIRE_SHAKE);
@@ -1051,7 +1051,8 @@ void Weapons::attack_move(Sim& sim, Attack& attack)
break;
}
attack.position = next;
sim.cues->burst_spawn(SMOKE_BURST, attack.position - vec2_polar(attack.angle, ROCKET_TAIL), attack.angle + PI, attack.owner);
sim.cues->burst_spawn(SMOKE_BURST, attack.position - vec2_polar(attack.angle, ROCKET_TAIL),
attack.angle + PI, attack.owner);
bool isSpent = attack.time > ROCKET_LIFETIME || vec2_length(attack.position - attack.origin) > range;
if (sim.world.is_blocking_at(attack.position) || isSpent)
@@ -1370,15 +1371,15 @@ void Weapons::contact_update(Sim& sim, Fighter& fighter)
(std::max(box.y, other.y) + std::min(box.y + box.h, other.y + other.h)) / 2};
damage_deal(
sim, {
.point = point,
.source = fighter.center_get(),
.hitstop = damage >= HITSTOP_MIN_DAMAGE ? std::min(HITSTOP_MAX, damage * HITSTOP_PER_DAMAGE) : 0,
.knock = CONTACT_KNOCK,
.amount = damage,
.owner = fighter.index,
.target = target,
.sound = hit_sound_get(HIT_BLUNT, damage >= HEAVY_DAMAGE),
});
.point = point,
.source = fighter.center_get(),
.hitstop = damage >= HITSTOP_MIN_DAMAGE ? std::min(HITSTOP_MAX, damage * HITSTOP_PER_DAMAGE) : 0,
.knock = CONTACT_KNOCK,
.amount = damage,
.owner = fighter.index,
.target = target,
.sound = hit_sound_get(HIT_BLUNT, damage >= HEAVY_DAMAGE),
});
fighter.contactCooldown = CONTACT_INTERVAL;
return;
}
@@ -1507,15 +1508,15 @@ void Weapons::teleport_move(Sim& sim, Attack& attack)
sim.cues->shake_add(attack.def()->shake);
}
blast_spawn(sim, {
.position = spot,
.area = attack.stats.area * attack.scale,
.damage = attack.stats.damage,
.owner = attack.owner,
.sound = SOUND_TELEPORT,
.weapon = attack.weapon,
.isGentle = true,
.isSecondary = attack.isSecondary,
});
.position = spot,
.area = attack.stats.area * attack.scale,
.damage = attack.stats.damage,
.owner = attack.owner,
.sound = SOUND_TELEPORT,
.weapon = attack.weapon,
.isGentle = true,
.isSecondary = attack.isSecondary,
});
}
// Tesla Coil: a web of lightning between every weapon the fighter has out in the world (anything but explosions).
@@ -1579,12 +1580,12 @@ void Weapons::tesla_update(Sim& sim)
continue;
shock = TESLA_INTERVAL;
damage_deal(sim, {.point = point,
.source = fighter.center_get(),
.knock = KNOCK_SLIGHT,
.amount = (int)damage,
.owner = i,
.target = target,
.sound = SOUND_ZAP});
.source = fighter.center_get(),
.knock = KNOCK_SLIGHT,
.amount = (int)damage,
.owner = i,
.target = target,
.sound = SOUND_ZAP});
}
}
}
@@ -1695,17 +1696,17 @@ void Weapons::piece_launch(Sim& sim, Attack& piece)
Vec2 lash = piece.tip - piece.origin;
if (!piece.isCopy && vec2_length(lash) < piece.stats.range - RAY_STEP)
sim.fighters[piece.owner].impulse_add(vec2_normalize(lash) * WHIP_PULL *
sim.fighters[piece.owner].trinket_get(TRINKET_ABSORBER, 1));
sim.fighters[piece.owner].trinket_get(TRINKET_ABSORBER, 1));
if (piece.isCharged)
blast_spawn(sim, {
.position = piece.tip,
.area = piece.stats.area * piece.scale / piece.stats.scale,
.damage = piece.stats.damage,
.owner = piece.owner,
.sound = SOUND_NONE, // the charged crack already carries it
.weapon = piece.weapon,
.isSecondary = piece.isSecondary,
});
.position = piece.tip,
.area = piece.stats.area * piece.scale / piece.stats.scale,
.damage = piece.stats.damage,
.owner = piece.owner,
.sound = SOUND_NONE, // the charged crack already carries it
.weapon = piece.weapon,
.isSecondary = piece.isSecondary,
});
}
if (piece.def()->kind == ATTACK_BEAM)
@@ -1752,16 +1753,16 @@ void Weapons::attack_explode(Sim& sim, Attack& attack)
attack.isDead = true;
attack.hitsLeft = 0;
blast_spawn(sim, {
.position = attack.position,
.area = blast_area_get(attack),
.bonus = strength_get(attack, attack.position),
.damage = attack.stats.damage * multiplier_get(attack, attack.position),
.owner = attack.owner,
.sound = SOUND_EXPLOSION,
.weapon = attack.weapon,
.isPushing = true,
.isSecondary = attack.isSecondary,
});
.position = attack.position,
.area = blast_area_get(attack),
.bonus = strength_get(attack, attack.position),
.damage = attack.stats.damage * multiplier_get(attack, attack.position),
.owner = attack.owner,
.sound = SOUND_EXPLOSION,
.weapon = attack.weapon,
.isPushing = true,
.isSecondary = attack.isSecondary,
});
}
// Queues an explosion that hits everything inside it next tick, weaker toward its edge. Pushing blasts fling every