refactor starcontrol weapons and improve road visibility
- Rewrite Kohr-Ah guidedBlades: one-shot-per-press with blades that fly straight while held, then slow and become homing mines near enemies; blades persist indefinitely and cap at 8 live (oldest recycled) - Add bladeFireHeld tracking and canFire/tick hooks for blade cooldown - Update AI to tap fire for Kohr-Ah blades instead of holding - Reduce PLANET_GRAVITY from 1.6e6 to 1.1e6 for better slingshot physics - Add dark outline pass under road/rail lines in Civilization map for better visibility against light terrain
This commit is contained in:
parent
237a024f80
commit
2a08df9cd8
|
|
@ -344,7 +344,7 @@ export class CivilizationMapView {
|
|||
if (bits & (IMP.ROAD | IMP.RAILROAD)) {
|
||||
g.clear();
|
||||
const rail = !!(bits & IMP.RAILROAD);
|
||||
let drewAny = false;
|
||||
const segments = [];
|
||||
for (let dy = -1; dy <= 1; dy += 1) {
|
||||
for (let dx = -1; dx <= 1; dx += 1) {
|
||||
if (dx === 0 && dy === 0) continue;
|
||||
|
|
@ -355,21 +355,24 @@ export class CivilizationMapView {
|
|||
if (!(nBits & (IMP.ROAD | IMP.RAILROAD))) continue;
|
||||
const ex = (this.isoX(nc, nr) - this.isoX(c, r)) / 2;
|
||||
const ey = (this.isoY(nc, nr) - this.isoY(c, r)) / 2;
|
||||
g.lineStyle(rail ? 4 : 3, rail ? 0x4a4038 : 0x8a6f4d, 0.9);
|
||||
g.beginPath();
|
||||
g.moveTo(0, cy);
|
||||
g.lineTo(ex, cy + ey);
|
||||
g.strokePath();
|
||||
drewAny = true;
|
||||
segments.push([ex, cy + ey]);
|
||||
}
|
||||
}
|
||||
if (!drewAny && !hasCity) {
|
||||
g.lineStyle(3, 0x8a6f4d, 0.9);
|
||||
g.beginPath();
|
||||
g.moveTo(-14, cy);
|
||||
g.lineTo(14, cy);
|
||||
g.strokePath();
|
||||
}
|
||||
if (!segments.length && !hasCity) segments.push([-14, cy], [14, cy]);
|
||||
// A dark outline pass under the road/rail colour itself makes the line
|
||||
// read clearly against any terrain, instead of blending in on lighter
|
||||
// ground like desert/plains.
|
||||
const strokeAll = (width, color, alpha) => {
|
||||
g.lineStyle(width, color, alpha);
|
||||
for (const [ex, ey] of segments) {
|
||||
g.beginPath();
|
||||
g.moveTo(0, cy);
|
||||
g.lineTo(ex, ey);
|
||||
g.strokePath();
|
||||
}
|
||||
};
|
||||
strokeAll(rail ? 7 : 6, 0x000000, 0.4);
|
||||
strokeAll(rail ? 4 : 3, rail ? 0x4a4038 : 0x8a6f4d, 1);
|
||||
this.drawStampAt(g, x, y);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -340,6 +340,11 @@ export function updateAI(ai, state, dtMs) {
|
|||
&& !(enemy.fx.cloaked && dist > 900)) {
|
||||
input.fire = true;
|
||||
}
|
||||
// Kohr-Ah blades are one-shot-per-press: the ship must let go of the
|
||||
// button before it can launch another, so tap it instead of holding it.
|
||||
if (ship.def.primary.type === 'guidedBlades' && ship.fx.bladeFireHeld) {
|
||||
input.fire = false;
|
||||
}
|
||||
// Charge weapons (Melnorme pump-up): keep pumping while far or unaimed,
|
||||
// release once the shot is charged and the nose is on target.
|
||||
if (ship.fx.pump) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export const FACING_STEP = (Math.PI * 2) / FACINGS;
|
|||
export const TUNE = {
|
||||
MAX_FRAMES_PER_STEP: 6, // spiral-of-death cap after tab suspend
|
||||
PLANET_RADIUS: 220, // world units (UQM planet ~29 display px)
|
||||
PLANET_GRAVITY: 1.6e6, // accel = G / r^2 (world units / frame^2)
|
||||
PLANET_GRAVITY: 1.1e6, // accel = G / r^2 (world units / frame^2)
|
||||
PLANET_GRAVITY_MIN_R: 420, // clamp radius so slingshots stay sane
|
||||
PLANET_CREW_DAMAGE: 3, // crew lost on planet impact
|
||||
PLANET_DAMAGE_COOLDOWN: 24, // frames between crew-damaging planet hits
|
||||
|
|
|
|||
|
|
@ -318,23 +318,56 @@ export const PRIMARIES = {
|
|||
},
|
||||
},
|
||||
|
||||
// Kohr-Ah spinning blades: launched forward, then steered toward wherever
|
||||
// the Marauder points while the button is held.
|
||||
// Kohr-Ah spinning blades: one shot per button press (the button must be
|
||||
// released before another blade can launch), launched dead ahead and left
|
||||
// flying straight while the button stays held. Releasing lets a blade
|
||||
// coast to a stop and then drift as a slow homing mine toward any enemy
|
||||
// that strays close, otherwise it just sits there as a trap. Blades never
|
||||
// expire on their own — only dying to a ship, asteroid, planet or another
|
||||
// blade — but only maxCount (default 8) may be live at once; launching
|
||||
// past that cap pops the oldest.
|
||||
guidedBlades: {
|
||||
fire(state, ship, def) {
|
||||
ship.fx.bladeFireHeld = true;
|
||||
const m = muzzle(ship, (def.muzzleDist ?? 9) * 4, 0);
|
||||
spawnProjectile(state, ship, {
|
||||
const blade = spawnProjectile(state, ship, {
|
||||
type: 'blade',
|
||||
x: m.x, y: m.y, angle: m.angle,
|
||||
speed: def.speed,
|
||||
damage: def.damage, hp: def.hp ?? 10, life: def.lifeFrames,
|
||||
damage: def.damage, hp: def.hp ?? 10, life: Infinity,
|
||||
radius: def.radius ?? 30,
|
||||
data: { trackRange: (def.trackRange ?? 224) * 4, wait: 0 },
|
||||
behavior(st, p) {
|
||||
const owner = st.ships[p.owner];
|
||||
if (!owner.alive || !owner.input.fire) return;
|
||||
steerProjectile(p, facingToRad(quantizeFacing(owner.facing)), FACING_STEP / 2, def.speed);
|
||||
if (owner.alive && owner.input.fire) return;
|
||||
if (Math.abs(p.vx) > 1 || Math.abs(p.vy) > 1) {
|
||||
p.vx *= 0.5; p.vy *= 0.5;
|
||||
return;
|
||||
}
|
||||
p.vx = 0; p.vy = 0;
|
||||
if (p.data.wait > 0) { p.data.wait -= 1; return; }
|
||||
p.data.wait = 4;
|
||||
const enemy = enemyOf(st, owner);
|
||||
if (!enemy.alive || tdist(p.x, p.y, enemy.x, enemy.y) > p.data.trackRange) return;
|
||||
const a = bearingTo(p, enemy);
|
||||
p.vx = Math.cos(a) * 8; p.vy = Math.sin(a) * 8;
|
||||
},
|
||||
});
|
||||
const blades = (ship.fx.blades ?? []).filter((b) => b.alive);
|
||||
blades.push(blade);
|
||||
const max = def.maxCount ?? 8;
|
||||
while (blades.length > max) {
|
||||
const oldest = blades.shift();
|
||||
oldest.alive = false;
|
||||
emit(state, { t: 'shotHit', x: oldest.x, y: oldest.y, kind: 'blade' });
|
||||
}
|
||||
ship.fx.blades = blades;
|
||||
},
|
||||
canFire(state, ship) {
|
||||
return !ship.fx.bladeFireHeld;
|
||||
},
|
||||
tick(state, ship) {
|
||||
if (!ship.input.fire) ship.fx.bladeFireHeld = false;
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue