Let the ball machine roll, dent, and blow up
It was furniture in the most literal sense: bolted to one spot, three hits from scrap, and when it died it bled and a ball boy came out to mop it. - It trundles to a new spot every seven seconds or so, and CANNOT fire while it rolls. That is honest (a rolling cart cannot aim) and it is the window you use to close on it — but it also means it stops being a landmark you can ignore. - Six hits, not three, and it wears them: dented at two thirds, split open and sparking at one third, smoking where it stands once it is that far gone. - It comes apart as MACHINERY. No blood decal, no gore mound, no mop boy — a flash, sparks, torn metal and a column of dark smoke over a scorch mark. Smoke is a new particle flavour that rises and spreads instead of falling. Damaged sheets keep the healthy cart's footprint: the generator drew the smoke plume into the sprite, which would have shrunk the cart as it took damage, so the plume is cropped off and the smoke is drawn procedurally where it can move. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1168e9ee5b
commit
661ad90be5
7 files changed
+70
-11
No files matched your search
@@ -155,7 +155,7 @@ export function proj(x, y, z) {
|
||||
|
||||
// ---------------------------------------------------------------- sprites ----
|
||||
// assets/<name>.png; game falls back to code-drawn figures until sprites load.
|
||||
const SPRV = 55; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
|
||||
const SPRV = 56; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
|
||||
const SPR = {};
|
||||
for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_run3','p_run4','p_swing1','p_swing2',
|
||||
'o_idle1','o_idle2','o_bounce','o_bounce2','o_toss','o_smash','o_run1','o_run2','o_swing1','o_swing2',
|
||||
@@ -165,7 +165,7 @@ for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','
|
||||
'z_gw2','z_gw3','z_gw4','z_gwb','z_gw2b','z_gw3b','z_gw4b', // the brute comes apart in stages (4/5 hp = z_gw .. 1/5 = z_gw4), each with a 2-frame lurch (…b)
|
||||
'z_boss1','z_boss2','z_bossw1','z_bossw2','z_bossw3', // the CHAPTER BOSS: 2-frame stride + three wound stages (arm off -> ribs out -> headless)
|
||||
'z_bosst0','z_bosst1','z_bosst2','z_bosst3', // ...and each of those four states mid-THROW (windT)
|
||||
'z_mach1','z_mach2', // the ball machine: idle, and firing with a muzzle flash
|
||||
'z_mach1','z_mach2','z_machw1','z_machw2', // the ball machine: idle, firing, dented, split open
|
||||
'z_judge1','z_judge2','z_judgew','z_judget','z_judgewt', // boss design 2 (chapter 2, 5, ...)
|
||||
'z_chair1','z_chair2','z_chairw','z_chairt','z_chairwt', // boss design 3 (chapter 3, 6, ...)
|
||||
'z_a1','z_a2','z_a3','z_a4','z_b1','z_b2','z_b3','z_b4','z_c1','z_c2',
|
||||
@@ -271,7 +271,12 @@ const ZFRAMES = { a: 4, b: 4, f: 4, d: 4, g: 4 }; // 4-frame walk cycles where s
|
||||
// player has to recognise and prioritise.
|
||||
function drawMachine(zb) {
|
||||
const firing = zb.windT > 0;
|
||||
const name = firing && SPR.z_mach2 ? 'z_mach2' : 'z_mach1';
|
||||
// It wears its damage like every other multi-hit body on court: dented at two thirds, split open
|
||||
// and sparking at one. The healthy sheet keeps the muzzle-flash frame; a damaged machine flashes
|
||||
// procedurally instead of needing a firing frame per stage.
|
||||
const f = zb.hp / (zb.hpMax || TUNE.machHp);
|
||||
const dmg = f <= 0.34 ? 'z_machw2' : f <= 0.67 ? 'z_machw1' : null;
|
||||
const name = dmg && SPR[dmg] ? dmg : firing && SPR.z_mach2 ? 'z_mach2' : 'z_mach1';
|
||||
const img = SPR[name];
|
||||
if (!img) return; // sheet not loaded yet: draw nothing, not a box
|
||||
const h = MACH_H * (img.height / SPRITE_H);
|
||||
@@ -846,9 +851,15 @@ export function render() {
|
||||
ctx.fillStyle = UI.ball;
|
||||
ctx.beginPath(); ctx.arc(Math.round(sp.x), Math.round(sp.y), r, 0, 7); ctx.fill();
|
||||
}
|
||||
// splatter particles (fire embers ride the same array)
|
||||
// splatter particles (fire embers and machine smoke ride the same array)
|
||||
for (const pt of parts) {
|
||||
const pp = proj(pt.x, pt.y, pt.z);
|
||||
if (pt.smoke) { // a broken machine's smoke: dark, soft-edged, growing and thinning as it climbs
|
||||
const age = Math.min(1, pt.t / 1.8), r = Math.max(2, pp.s * 0.09 * (2 - age));
|
||||
ctx.fillStyle = `rgba(46,44,48,${0.62 * age})`;
|
||||
ctx.beginPath(); ctx.arc(pp.x | 0, pp.y | 0, r, 0, 7); ctx.fill();
|
||||
continue;
|
||||
}
|
||||
ctx.fillStyle = pt.fire ? (pt.t > 0.12 ? '#ffc030' : '#ff8010')
|
||||
: pt.dark ? 'rgba(96,14,14,0.9)' : 'rgba(170,22,22,0.9)';
|
||||
ctx.fillRect(pp.x | 0, pp.y | 0, 2, 2);
|
||||
|
||||
Reference in new issue
Block a user