Further Tweaks to Colorado Defense
This commit is contained in:
parent
bfa2359ea2
commit
8399cc69db
|
|
@ -64,6 +64,11 @@ export const TUNE = {
|
|||
MIRV_RESPLIT_WAVE: 8,
|
||||
SPLIT_ZONE_1: [0.20, 0.333],
|
||||
SPLIT_ZONE_2: [0.45, 0.55],
|
||||
// A MIRV's own children fly slower than a regular missile right when
|
||||
// MIRVs are introduced, then quickly catch up to full speed.
|
||||
MIRV_CHILD_SPEED_MULT_BASE: 0.65,
|
||||
MIRV_CHILD_SPEED_MULT_GROWTH: 0.5,
|
||||
MIRV_CHILD_SPEED_MULT_MAX: 1.0,
|
||||
BASE_AMMO: 10,
|
||||
BLAST_R_BASE: 90, BLAST_GROW_MS: 350, BLAST_HOLD_MS: 120, BLAST_FADE_MS: 200,
|
||||
INTERCEPTOR_SPEED: 900,
|
||||
|
|
@ -118,6 +123,15 @@ export function mirvChance(wave) {
|
|||
return Math.min(TUNE.MIRV_CHANCE_MAX, TUNE.MIRV_CHANCE_BASE + TUNE.MIRV_CHANCE_GROWTH * (wave - TUNE.MIRV_WAVE));
|
||||
}
|
||||
|
||||
// How fast a MIRV's split-off children fly, relative to a normal missile
|
||||
// that wave — starts slow right when MIRVs are introduced, ramps to full speed.
|
||||
export function mirvChildSpeedMult(wave) {
|
||||
return Math.min(
|
||||
TUNE.MIRV_CHILD_SPEED_MULT_MAX,
|
||||
TUNE.MIRV_CHILD_SPEED_MULT_BASE + TUNE.MIRV_CHILD_SPEED_MULT_GROWTH * (wave - TUNE.MIRV_WAVE),
|
||||
);
|
||||
}
|
||||
|
||||
// Automatic, level-driven palette progression (distinct from user-facing
|
||||
// pickers like 2048's) — advances every PALETTE_WAVES waves, clamped at the end.
|
||||
export const PALETTES = [
|
||||
|
|
@ -127,7 +141,7 @@ export const PALETTES = [
|
|||
{ bgTop: 0x1a140a, bgBottom: 0x301c0a, trail: 0xffb366, explosion: 0xff5555, accent: 0xff8a3c, ground: 0x2a1c0f, chain: 0xffee88 },
|
||||
{ bgTop: 0x120a1a, bgBottom: 0x260a30, trail: 0xc78dff, explosion: 0xff66c4, accent: 0xb84bff, ground: 0x1e0f2a, chain: 0x66ffcc },
|
||||
];
|
||||
export const PALETTE_WAVES = 4;
|
||||
export const PALETTE_WAVES = 2;
|
||||
export function paletteIndexForWave(wave) {
|
||||
return Math.min(PALETTES.length - 1, Math.floor((wave - 1) / PALETTE_WAVES));
|
||||
}
|
||||
|
|
@ -216,13 +230,13 @@ export class Sim {
|
|||
// only a freshly-spawned, top-edge missile can randomly become one; a
|
||||
// MIRV's own children (fromOverride, no force) are always simple 'single's
|
||||
// so the split tree stays bounded.
|
||||
spawnEnemyMissile(fromOverride, forceMirv = false) {
|
||||
spawnEnemyMissile(fromOverride, forceMirv = false, speedMult = 1) {
|
||||
const target = this.pickTargetSlot();
|
||||
if (!target) return null;
|
||||
const fromX = fromOverride ? fromOverride.x : 80 + this.rng() * (WIDTH - 160);
|
||||
const fromY = fromOverride ? fromOverride.y : 0;
|
||||
const dist = Math.hypot(target.x - fromX, target.y - fromY);
|
||||
const speed = fallSpeed(this.wave);
|
||||
const speed = fallSpeed(this.wave) * speedMult;
|
||||
const dur = Math.max(200, (dist / speed) * 1000);
|
||||
const isMirv = forceMirv || (!fromOverride && this.rng() < mirvChance(this.wave));
|
||||
const kind = isMirv ? 'mirv' : 'single';
|
||||
|
|
@ -241,9 +255,10 @@ export class Sim {
|
|||
const options = TUNE.MIRV_CHILDREN;
|
||||
const n = options[Math.floor(this.rng() * options.length)];
|
||||
const cur = lerpPos(parent);
|
||||
const speedMult = mirvChildSpeedMult(this.wave);
|
||||
const children = [];
|
||||
for (let i = 0; i < n; i += 1) {
|
||||
const m = this.spawnEnemyMissile(cur);
|
||||
const m = this.spawnEnemyMissile(cur, false, speedMult);
|
||||
if (m) children.push(m);
|
||||
}
|
||||
return children;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
// 3. Difficulty escalation monotonicity across waves 1-40 (bounded).
|
||||
// 4. MIRV step-unlock threshold.
|
||||
// 4b. MIRV split-zone geometry (top-third once, top-third + halfway from wave 8).
|
||||
// 4c. MIRV child speed multiplier (slower right at introduction, ramps to full speed).
|
||||
// 5. Scripted explosion/collision fixture.
|
||||
// 5c. Bonus plane fixture (unlock wave, crossing speed, hit/score/debris).
|
||||
// 5d. Bonus UFO fixture (unlock wave, weaving/shots, hit/score/debris).
|
||||
|
|
@ -16,7 +17,7 @@
|
|||
|
||||
import {
|
||||
BASE_SLOTS, CITY_SLOTS, GROUND_SLOTS, HEIGHT, WIDTH, GROUND_Y, slotX, mulberry32, pickCities,
|
||||
DEFAULT_CITIES, TUNE, spawnInterval, fallSpeed, waveQuota, mirvChance,
|
||||
DEFAULT_CITIES, TUNE, spawnInterval, fallSpeed, waveQuota, mirvChance, mirvChildSpeedMult,
|
||||
PALETTES, paletteIndexForWave, createGame, step, pickFiringBase,
|
||||
fireInterceptor, lerpPos, explosionRadius,
|
||||
} from '../src/games/coloradodefense/ColoradoDefenseLogic.js';
|
||||
|
|
@ -183,6 +184,41 @@ console.log('MIRV split-zone geometry');
|
|||
check('its second split is scheduled in SPLIT_ZONE_2', sawZone2SplitY);
|
||||
}
|
||||
|
||||
// ── 4c. MIRV child speed multiplier ─────────────────────────────────────────────
|
||||
|
||||
console.log('MIRV child speed multiplier');
|
||||
{
|
||||
check('multiplier at MIRV_WAVE is exactly the base value',
|
||||
mirvChildSpeedMult(TUNE.MIRV_WAVE) === TUNE.MIRV_CHILD_SPEED_MULT_BASE);
|
||||
let monotonic = true;
|
||||
for (let w = TUNE.MIRV_WAVE + 1; w <= TUNE.MIRV_WAVE + 20; w += 1) {
|
||||
if (mirvChildSpeedMult(w) < mirvChildSpeedMult(w - 1)) monotonic = false;
|
||||
}
|
||||
check('multiplier is monotonic non-decreasing with wave', monotonic);
|
||||
check('multiplier never exceeds MIRV_CHILD_SPEED_MULT_MAX',
|
||||
mirvChildSpeedMult(TUNE.MIRV_WAVE + 20) <= TUNE.MIRV_CHILD_SPEED_MULT_MAX);
|
||||
check('a +0.5/wave growth step reaches the max within one wave of introduction',
|
||||
mirvChildSpeedMult(TUNE.MIRV_WAVE + 1) === TUNE.MIRV_CHILD_SPEED_MULT_MAX);
|
||||
|
||||
// A child spawned at the reduced multiplier takes proportionally longer to
|
||||
// cover the SAME distance as one spawned at full speed. Force rng()=0
|
||||
// before each call so pickTargetSlot() deterministically picks the same
|
||||
// target both times — otherwise a different target/distance would
|
||||
// contaminate the dur comparison.
|
||||
const sim = createGame(DEFAULT_CITIES, 60);
|
||||
sim.wave = TUNE.MIRV_WAVE;
|
||||
const from = { x: 500, y: 400 };
|
||||
sim.rng = () => 0;
|
||||
const full = sim.spawnEnemyMissile(from, false, 1);
|
||||
sim.rng = () => 0;
|
||||
const slow = sim.spawnEnemyMissile(from, false, mirvChildSpeedMult(sim.wave));
|
||||
check('a slowed child (same distance) takes longer to arrive than a full-speed one',
|
||||
slow.dur > full.dur, `full=${full.dur} slow=${slow.dur}`);
|
||||
check('the slowdown ratio matches the configured base multiplier',
|
||||
Math.abs(full.dur / slow.dur - TUNE.MIRV_CHILD_SPEED_MULT_BASE) < 1e-6,
|
||||
`ratio=${full.dur / slow.dur}`);
|
||||
}
|
||||
|
||||
// ── 5. Explosion/collision fixture ────────────────────────────────────────────
|
||||
|
||||
console.log('Explosion/collision fixture');
|
||||
|
|
|
|||
Loading…
Reference in New Issue