Let the horde gun keep up with the horde
The run ended on the second wave every time: the gun fired 6 flat rounds a second, hit one body each, and every shambler soaked one — while hordeGrow made each wave longer and denser. Doubled the rate and scaled it with the wave (14/s at one set banked, 21/s at four), gave a round 0.5m of extra reach, a wider cone, and enough damage to drop a shambler outright. Raised the spawn rate to match, so surviving a wave still leaves a standing crowd on your half — that pressure is the point of it. Also: he no longer carries a second racket at his hip while holding one forward (the run frames are the racket-less art), the umpire stopped talking over himself and saying "remain seated" twice, and a timed freeze now shows what it is counting down to instead of reading as dead controls. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
571cd4c399
commit
e904dfefa6
5 files changed
+47
-13
No files matched your search
@@ -416,6 +416,10 @@ function drawChar(ch) {
|
||||
if (ch.pose === 'swing') name = pre + (ch.poseT < 0.15 ? 'swing1' : 'swing2');
|
||||
if (ch.pose === 'serve') name = pre + (G.phase === 'toss' ? 'toss' : 'smash');
|
||||
if (ch.pose === 'run') p.y -= Math.floor(ch.runT * 18) % 2; // 1px run bob
|
||||
// Auto-fire: the idle sprite carries a racket at his hip AND drawMgRacket puts one in his hands —
|
||||
// two rackets. The run frames are the racket-less art, so he jogs on the spot instead.
|
||||
if (ch.side === 'P' && ch.pose === 'idle' && G.mode === 'splatter' && (G.horde || G.mgT > 0))
|
||||
name = pre + (Math.floor(G.idleT * 6) % 2 ? 'run1' : 'run2');
|
||||
const img = SPR[name];
|
||||
drawShadow(p.x, p.y, hpx * 0.22, hpx * 0.06);
|
||||
if (img) {
|
||||
@@ -450,7 +454,8 @@ function drawMgRacket() { // horde: the player braces the racket forward and up-
|
||||
ctx.strokeStyle = '#b07030'; ctx.lineWidth = 1.5; // the head, aimed forward
|
||||
ctx.beginPath(); ctx.ellipse(tip.x, tip.y, Math.max(2, tip.s * 0.14), Math.max(3, tip.s * 0.22), 0, 0, 7); ctx.stroke();
|
||||
const cool = G.horde ? G.horde.mgT : G.mgCool; // horde or GUN-tin pickup — same racket
|
||||
if (cool > 1 / TUNE.mgRate - 0.06) { // muzzle flash right after a shot
|
||||
const rate = G.horde ? G.horde.mgRate || TUNE.mgRate : TUNE.mgRate;
|
||||
if (cool > 1 / rate - 0.03) { // muzzle flash right after a shot
|
||||
ctx.fillStyle = '#fff0a0'; ctx.beginPath(); ctx.arc(tip.x, tip.y, Math.max(2, tip.s * 0.12), 0, 7); ctx.fill();
|
||||
}
|
||||
}
|
||||
@@ -805,7 +810,7 @@ export function render() {
|
||||
for (const pe of pellets) {
|
||||
const sh = proj(pe.x, 0, pe.z); drawShadow(sh.x, sh.y, Math.max(1, sh.s * 0.04), Math.max(1, sh.s * 0.02), 0.25);
|
||||
const pp = proj(pe.x, pe.y, pe.z);
|
||||
ctx.fillStyle = UI.warm; ctx.fillRect((pp.x | 0) - 1, (pp.y | 0) - 1, 2, 2);
|
||||
ctx.fillStyle = UI.warm; ctx.fillRect((pp.x | 0) - 2, (pp.y | 0) - 2, 4, 4); // fat round — it hits like one
|
||||
}
|
||||
// death, in three stages. A: you are still there, thrashing and going red as they crowd in.
|
||||
// B (from EATEN_BURST): the sprite is gone and you ARE the gore — playerGore() drops the mound.
|
||||
@@ -905,7 +910,18 @@ export function render() {
|
||||
if (G.eatenT > EATEN_RESTART) { ctx.fillStyle = UI.warm; ctx.font = F(8); ctx.fillText('TAP TO PLAY AGAIN', W / 2, H / 2 + 26); }
|
||||
ctx.restore();
|
||||
}
|
||||
if (G.phase === 'pretoss' && score.server === 'P' && G.mode !== 'eaten' && !G.horde && !(G.mgT > 0) && !G.aim) { // while pulling, the draw meter owns this slot
|
||||
// Timed freezes swallow every input until they run out, which reads as the game having hung
|
||||
// ("sometimes the controls just feel frozen"). Show the clock instead of hiding it. A modal is
|
||||
// excluded on purpose — that one waits for YOU, and says so.
|
||||
const waitT = G.modal || G.mode === 'eaten' ? 0
|
||||
: Math.max(G.changeover > 0 ? G.changeover : 0,
|
||||
G.phase === 'over' ? G.overT : 0,
|
||||
G.interlude ? G.interlude.introT : 0);
|
||||
if (waitT > 0.5) {
|
||||
ctx.font = F(7, 0); ctx.fillStyle = hexA(UI.warm, 0.8);
|
||||
ctx.fillText('RESUMING IN ' + Math.ceil(waitT), W / 2, 78); // under the flash line, clear of the court and the man
|
||||
}
|
||||
if (G.phase === 'pretoss' && score.server === 'P' && G.mode !== 'eaten' && !G.horde && !(G.mgT > 0) && !G.aim && waitT <= 0.5) { // while pulling, the draw meter owns this slot
|
||||
ctx.fillStyle = UI.warm; ctx.font = F(8);
|
||||
const touch = IS_TOUCH, switchHint = touch ? 'TAP THE RACK TO SWITCH' : '1-5 TO SWITCH';
|
||||
const sel = ['PLAIN', 'BOMB', 'TRIPLE', 'FIRE', 'GUN'][G.weapon];
|
||||
|
||||
Reference in new issue
Block a user