Keep the wounded walking, and make the steward worth his size
A wound skin was a single still, so anything hurt froze on one frame and slid across the court. Every skin has its …b twin now — the stride swapped, stepped off the same clock as the healthy walk — for both shamblers, both racket-zombie stages, and the steward, who had no wounded state at all. The steward also died like a shambler at 3 hp, which made a bigger body read as decoration. Five now, with a wound skin to show the second half of that. hpMax is recorded on every body that has hp, so "hurt = show the wound" is one rule instead of a per-variant constant to remember. First pass at the wound frames was rejected on sight and deserved it: the generator drew small figures with fine pixels on a GRADIENT background, and a nearest-neighbour downscale to sprite height shredded the outlines. Regenerated two at a time, drawn large, chunky pixels, flat background, hard black outline — then fitted per channel onto each frame's own healthy twin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No files matched your search
|
After Width: | Height: | Size: 306 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 362 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -205,8 +205,9 @@ export const TUNE = {
|
||||
runnerSpeed: 3.2, // runner ('f') speed multiplier over the shamble
|
||||
runnerVMax: 4.2, // hard runner speed cap — the late-game ramp must stay humanly reactable
|
||||
shamblerHp: 2, // splat-quality hits a classic shambler ('a'/'b') soaks before it dies — only the runner ('f') is still one-shot glass
|
||||
stewardHp: 3, // the steward ('d'): one hit tougher than the crowd he walks in. Deliberately NOT
|
||||
// a brute — no wound skins, no special rule, just a bigger body that takes one more
|
||||
stewardHp: 5, // the steward ('d'). Was 3 and died like a shambler, which made a bigger body read
|
||||
// as decoration; at 5 he is a brute's worth of hp on a faster, ordinary-looking
|
||||
// walker, and he has a wound skin (z_dw) so the second half of that shows
|
||||
hordeSteward: 0.2, // share of horde spawns that come out as stewards (from game 4)
|
||||
// fire: the flame ball no longer just kills what it touches, it starts an epidemic.
|
||||
burnTime: 3.0, // s a body burns before the fire goes out
|
||||
|
||||
@@ -97,6 +97,6 @@
|
||||
<p id="build"></p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="main.js?v=59"></script>
|
||||
<script type="module" src="main.js?v=60"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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 = 53; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
|
||||
const SPRV = 55; // 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',
|
||||
@@ -170,6 +170,7 @@ for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','
|
||||
'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',
|
||||
'z_d1','z_d2','z_d3','z_d4', // the steward: bigger body, hi-vis vest, 4-frame walk
|
||||
'z_awb','z_bwb','z_cw1b','z_cw2b','z_dw','z_dwb', // ...and every wound skin's second frame: wounded bodies walk too
|
||||
'z_f1','z_f2','z_f3','z_f4','z_g1','z_g2','z_g3','z_g4','z_gw','z_s1','z_s2','z_s3',
|
||||
'z_cw1','z_cw2','z_aw','z_bw', // wounded skins for multi-hit enemies (racket boss, brute, and now the classic shamblers)
|
||||
'w_ball','w_bomb','w_triple','w_fire','w_gun', // weapon-rack icons
|
||||
@@ -316,7 +317,13 @@ function drawZombie(zb) {
|
||||
h *= SPR[stage].height / SPRITE_H; // height ALWAYS off the A frame, or the size pops each step
|
||||
} else if (SPR.z_gw) name = 'z_gw'; // a missing asset degrades to the last skin that loaded
|
||||
}
|
||||
else if ((zb.variant === 'a' || zb.variant === 'b') && zb.hp < TUNE.shamblerHp && SPR['z_' + zb.variant + 'w']) name = 'z_' + zb.variant + 'w'; // gashed shambler
|
||||
else if ('abd'.includes(zb.variant) && zb.hp < (zb.hpMax || 0) && SPR['z_' + zb.variant + 'w']) {
|
||||
// A wounded body used to freeze on ONE frame and slide across the court — the wound skins were
|
||||
// single stills. Every skin has its …b twin now (the stride swapped), stepped off the same clock
|
||||
// as the healthy walk, so losing an arm changes how he walks and not whether he walks.
|
||||
const w = 'z_' + zb.variant + 'w';
|
||||
name = SPR[w + 'b'] && stepFrame(zb.walkT * 2.6, 2) ? w + 'b' : w; // gashed shambler, still lurching
|
||||
}
|
||||
// The boss's damage is read as a FRACTION of full health — his hp scales with the run
|
||||
// (TUNE.racketHpPerGame), so the old `hp === 2` / `hp <= 1` thresholds would have left a late-run
|
||||
// boss looking untouched until the killing blow. Keep these in step with bleed()'s anchors.
|
||||
@@ -324,6 +331,8 @@ function drawZombie(zb) {
|
||||
const f = zb.hp / (zb.hpMax || TUNE.racketHp);
|
||||
if (f <= 0.34 && SPR.z_cw2) { name = 'z_cw2'; h = 1.52; } // headless: a head shorter, so the shoulders land where a whole zombie's do
|
||||
else if (f <= 0.67 && SPR.z_cw1) name = 'z_cw1';
|
||||
const b = name + 'b'; // ...and he limps through his wounds too, instead of gliding
|
||||
if (name !== 'z_' + v + frame && SPR[b] && stepFrame(zb.walkT * 2.6, 2)) name = b;
|
||||
}
|
||||
// The chapter boss comes apart through the SAME fraction-of-hpMax rule as the racket zombie, over
|
||||
// three stages, so a 34 hp chapter-4 boss visibly degrades all the way down: arm off, then ribs
|
||||
|
||||
@@ -33,7 +33,11 @@ export function spawnZombie(x, z, variant) {
|
||||
if (variant === 'f') { zb.v = Math.min(TUNE.runnerVMax, zb.v * TUNE.runnerSpeed); shriek(); } // shriek = the fairness contract; capped so late runners stay reactable
|
||||
if (variant === 'a' || variant === 'b') zb.hp = TUNE.shamblerHp; // classic shamblers take a wound before they drop — only the runner is one-shot glass
|
||||
if (variant === 'g') { zb.v *= 0.55; zb.hp = TUNE.bruteHp; } // slow, but soaks hits
|
||||
if (variant === 'd') { zb.v *= 0.8; zb.hp = TUNE.stewardHp; } // the steward: a head taller and a hit tougher than the crowd, nothing more exotic than that
|
||||
if (variant === 'd') { zb.v *= 0.8; zb.hp = TUNE.stewardHp; } // the steward: a head taller and several hits tougher than the crowd, nothing more exotic than that
|
||||
// Every body with hp remembers its FULL hp. The wound skins used to compare against the variant's
|
||||
// TUNE constant, which meant every new body needed its own branch to look hurt; one field here and
|
||||
// the rule is "hp below full = show the wound", for anything that has a wound skin.
|
||||
if (zb.hp) zb.hpMax = zb.hp;
|
||||
if (variant === 's') zb.shieldT = 0; // chair up; > 0 = seconds of stagger left
|
||||
if ('fgsd'.includes(variant) && !G.seen['v' + variant]) { G.seen['v' + variant] = true; aside('ump_dress_code', 0.8); }
|
||||
if (variant === 'm') { // the rogue ball machine: furniture, not a body. It does not walk at all.
|
||||
|
||||