626879ed0c
- Add enemy freshness tracking (novelty bonus for repeated deploys) - Add freshness bar to sidepanel enemy cards with penalty indicator - Major overhaul of renderer-overlays.js (790+ lines for UI polish) - Enhanced combat log, shop overlays, and inventory UI - Improved weapon/upgrade display with partial ownership colors - Added element icons and weakness/resistance indicators to cards - Enhanced radial menu and tooltip system - Add "stale/%" penalty text when freshness depleted - Update play link to ffazeshift.net in index.html
64 lines
1.6 KiB
JavaScript
64 lines
1.6 KiB
JavaScript
// ═══ utils.js ═══
|
|
// ============================================================
|
|
// UTILS — shared pure helpers
|
|
// ============================================================
|
|
|
|
function distSq(ax, ay, bx, by) {
|
|
const dx = ax - bx;
|
|
const dy = ay - by;
|
|
return dx * dx + dy * dy;
|
|
}
|
|
|
|
function normalizeAngle(angle) {
|
|
while (angle > Math.PI) angle -= Math.PI * 2;
|
|
while (angle < -Math.PI) angle += Math.PI * 2;
|
|
return angle;
|
|
}
|
|
|
|
function shortestAngleDelta(from, to) {
|
|
return normalizeAngle(to - from);
|
|
}
|
|
|
|
function stepTowardAngle(current, desired, maxStep) {
|
|
const delta = shortestAngleDelta(current, desired);
|
|
if (Math.abs(delta) <= maxStep) return normalizeAngle(desired);
|
|
return normalizeAngle(current + Math.sign(delta) * maxStep);
|
|
}
|
|
|
|
function compactLiveArray(items, isLive) {
|
|
let write = 0;
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
if (isLive(item)) items[write++] = item;
|
|
}
|
|
items.length = write;
|
|
}
|
|
|
|
function clamp(value, min, max) {
|
|
return Math.max(min, Math.min(max, value));
|
|
}
|
|
|
|
function cheapestEnemyCost() {
|
|
const tier = G?.difficultyTier ?? 0;
|
|
const prestige = G?.prestigeLevel ?? 0;
|
|
return ENEMY_DEFS
|
|
.filter(d => (d.minTier ?? 0) <= tier && (d.minPrestige ?? 0) <= prestige)
|
|
.reduce((min, d) => Math.min(min, d.cost), Infinity);
|
|
}
|
|
|
|
function countAliveEnemies() {
|
|
let count = 0;
|
|
for (const e of G.enemies) if (e.alive) count++;
|
|
return count;
|
|
}
|
|
|
|
function getEquippedWeapons() {
|
|
return G.weapons.slice(0, G.tower.weaponSlots).filter(Boolean);
|
|
}
|
|
|
|
function findWeaponInstance(instanceId) {
|
|
for (const w of G.weapons) if (w && w.instanceId === instanceId) return w;
|
|
return null;
|
|
}
|
|
|