Files
siege-protocol/js/defs.js
T
44r0n7 626879ed0c Add freshness bar, enhance overlays and renderers
- 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
2026-06-17 11:58:17 -04:00

658 lines
35 KiB
JavaScript

// ═══ defs.js ═══
// ============================================================
// DEFINITIONS — elements, enemies, weapons, upgrades
// ============================================================
// ── ELEMENTS ─────────────────────────────────────────────────
const ELEMENTS = {
fire: { name: 'Fire', color: '#ff6b35', glow: '#ff3300', icon: '🔥' },
ice: { name: 'Ice', color: '#7ecfff', glow: '#00cfff', icon: '❄️' },
lightning: { name: 'Lightning', color: '#ffe033', glow: '#ffcc00', icon: '⚡' },
poison: { name: 'Poison', color: '#7fff4f', glow: '#44ff00', icon: '☠️' },
void: { name: 'Void', color: '#c77dff', glow: '#9900ff', icon: '🌀' },
arcane: { name: 'Arcane', color: '#ff77e9', glow: '#ff00cc', icon: '✨' },
physical: { name: 'Physical', color: '#c8c8c8', glow: '#ffffff', icon: '💢' },
};
// ── DIFFICULTY TIERS ──────────────────────────────────────────
const DIFFICULTY_TIERS = [
{ id: 0, name: 'NORMAL', unlockCost: 0, hpMult: 1.00, speedMult: 1.00, armorMult: 1.00, rewardMult: 1.00 },
{ id: 1, name: 'SKIRMISH', unlockCost: 500, hpMult: 1.25, speedMult: 1.15, armorMult: 1.20, rewardMult: 1.40 },
{ id: 2, name: 'ASSAULT', unlockCost: 2000, hpMult: 1.60, speedMult: 1.30, armorMult: 1.50, rewardMult: 1.90 },
{ id: 3, name: 'SIEGE', unlockCost: 6000, hpMult: 2.10, speedMult: 1.50, armorMult: 2.00, rewardMult: 2.50 },
{ id: 4, name: 'ONSLAUGHT', unlockCost: 15000, hpMult: 2.85, speedMult: 1.75, armorMult: 2.80, rewardMult: 3.50 },
{ id: 5, name: 'CATACLYSM', unlockCost: 40000, hpMult: 3.80, speedMult: 2.00, armorMult: 4.00, rewardMult: 4.70 },
];
// ── ENEMY TYPES ───────────────────────────────────────────────
const ENEMY_DEFS = [
{
id: 'grunt',
name: 'GRUNT',
desc: 'Basic foot soldier. No special traits.',
hp: 8, speed: 0.72, radius: 7, armor: 0,
color: '#aaaaaa', glowColor: '#ffffff',
cost: 20, reward: 30,
resistances: {},
weaknesses: { poison: 1.3 },
element: null,
count: 1,
},
{
id: 'runner',
name: 'RUNNER',
desc: 'Very fast, low HP. Hard to track.',
hp: 5, speed: 1.88, radius: 5, armor: 0,
color: '#00ff88', glowColor: '#00ff88',
cost: 30, reward: 44,
resistances: {},
weaknesses: { lightning: 1.5, poison: 1.3 },
element: null,
count: 1,
},
{
id: 'brute',
name: 'BRUTE',
desc: 'High HP and armor. Slow mover.',
hp: 35, speed: 0.42, radius: 13, armor: 3,
color: '#ff7043', glowColor: '#ff3300',
cost: 80, reward: 112,
resistances: { physical: 0.5 },
weaknesses: { void: 1.8, fire: 1.4, poison: 1.3 },
element: null,
count: 1,
},
{
id: 'swarm',
name: 'SWARM',
desc: 'Spawns 6 tiny units at once.',
hp: 3, speed: 1.48, radius: 4, armor: 0,
color: '#ce93d8', glowColor: '#cc00ff',
cost: 60, reward: 84,
resistances: {},
weaknesses: { fire: 1.4, lightning: 1.4 },
element: null,
count: 6,
},
{
id: 'phantom',
name: 'PHANTOM',
desc: '40% dodge. Void-touched.',
hp: 6, speed: 1.36, radius: 7, armor: 0,
color: '#c77dff', glowColor: '#9900ff',
cost: 100, reward: 138,
evasion: 0.3,
resistances: { void: 0.3, arcane: 0.5 },
weaknesses: { fire: 1.5 },
element: 'void',
count: 1,
},
{
id: 'iceling',
name: 'ICELING',
desc: 'Ice elemental. Slows bullets on contact.',
hp: 12, speed: 0.70, radius: 9, armor: 1,
color: '#7ecfff', glowColor: '#00cfff',
cost: 90, reward: 125,
resistances: { ice: 0.0 },
weaknesses: { fire: 1.6, lightning: 1.3 },
element: 'ice',
count: 1,
},
{
id: 'sparkling',
name: 'SPARKLING',
desc: 'Lightning elemental. Fast and electric.',
hp: 7, speed: 1.68, radius: 6, armor: 0,
color: '#ffe033', glowColor: '#ffcc00',
cost: 110, reward: 148,
resistances: { lightning: 0.0 },
weaknesses: { ice: 1.5, void: 1.3 },
element: 'lightning',
count: 1,
},
{
id: 'venom',
name: 'VENOM',
desc: 'Poison elemental. Immune to DoT.',
hp: 14, speed: 0.77, radius: 10, armor: 0,
color: '#7fff4f', glowColor: '#44ff00',
cost: 120, reward: 160,
resistances: { poison: 0.0, fire: 0.6 },
weaknesses: { ice: 1.4, arcane: 1.6 },
element: 'poison',
count: 1,
},
{
id: 'titan',
name: 'TITAN',
desc: 'Massive HP, heavy armor, very slow.',
hp: 120, speed: 0.25, radius: 20, armor: 8,
color: '#ff1744', glowColor: '#ff0000',
cost: 350, reward: 465,
resistances: { physical: 0.4, fire: 0.7 },
weaknesses: { void: 2.0, arcane: 1.5 },
element: null,
count: 1,
},
{
id: 'wraith',
name: 'WRAITH',
desc: 'Void entity. Ignores 80% of armor.',
hp: 18, speed: 1.10, radius: 9, armor: 0,
color: '#9900ff', glowColor: '#6600cc',
cost: 200, reward: 265,
armorPen: 0.8,
resistances: { void: 0.2, poison: 0.5 },
weaknesses: { arcane: 2.0 },
element: 'void',
count: 1,
},
{
id: 'commander', name: 'COMMANDER',
desc: 'Aura: nearby enemies AND self gain +30% damage resistance. Weak to arcane.',
hp: 160, speed: 0.60, radius: 11, armor: 2,
color: '#ffc107', glowColor: '#ff8f00',
cost: 220, reward: 280,
resistances: {}, weaknesses: { arcane: 2.0 },
element: null, count: 1, minTier: 3,
},
{
id: 'juggernaut', name: 'JUGGERNAUT',
desc: 'Max 12 damage per hit. Immune to freeze. Lightning partially bypasses cap.',
hp: 280, speed: 0.32, radius: 16, armor: 4,
color: '#bf360c', glowColor: '#ff3d00',
cost: 400, reward: 600,
resistances: {}, weaknesses: { lightning: 1.6 },
element: null, count: 1, minTier: 4,
damageCapPerHit: 12, immuneToFreeze: true,
},
{
id: 'siegebreaker', name: 'SIEGE BREAKER',
desc: 'Regenerates 5 HP/sec. Immune to poison/freeze. Void pauses regen 3s.',
hp: 400, speed: 0.22, radius: 22, armor: 6,
color: '#880e4f', glowColor: '#ff0077',
cost: 500, reward: 900,
resistances: { poison: 0.0 }, weaknesses: {},
element: null, count: 1, minTier: 5,
hpRegenPerSec: 5, immuneToFreeze: true,
},
{
id: 'echo', name: 'ECHO',
desc: 'Splits into 2 copies on single-hit damage >30. Each copy earns a reward.',
hp: 100, speed: 0.96, radius: 8, armor: 0,
color: '#29b6f6', glowColor: '#0288d1',
cost: 180, reward: 250, echoReward: 120,
resistances: {}, weaknesses: { fire: 1.4 },
element: null, count: 1, minPrestige: 1,
},
{
id: 'voidherald', name: 'VOID HERALD',
desc: 'Shield absorbs 60% dmg when 3+ weapons hit per frame. Deploy in crowds.',
hp: 200, speed: 0.68, radius: 12, armor: 0,
color: '#7c4dff', glowColor: '#651fff',
cost: 300, reward: 480,
resistances: {}, weaknesses: { void: 1.5 },
element: 'void', count: 1, minPrestige: 2,
},
];
// ── WEAPON DEFINITIONS ────────────────────────────────────────
const WEAPON_DEFS = [
{
id: 'cannon',
name: 'CANNON',
desc: 'Standard projectile. Reliable, upgradeable.',
icon: '💣',
cost: 100,
defaultElement: 'physical',
targeting: 'nearest',
fireRate: 72, // frames between shots
damage: 4,
projectileSpeed: 4.2,
projectileRadius: 4,
range: 310,
color: '#c8c8c8',
type: 'projectile',
},
{
id: 'flamethrower',
name: 'FLAMETHROWER',
desc: 'Continuous cone of fire. Medium range, applies burn.',
icon: '🔥',
cost: 800,
defaultElement: 'fire',
targeting: 'nearest',
fireRate: 8,
damage: 1,
range: 230,
coneAngle: 0.35,
color: '#ff6b35',
type: 'cone',
},
{
id: 'chainlightning',
name: 'CHAIN LIGHTNING',
desc: 'Arcs between up to 3 enemies.',
icon: '⚡',
cost: 1200,
defaultElement: 'lightning',
targeting: 'nearest',
fireRate: 70,
damage: 4,
chains: 3,
chainRange: 120,
range: 340,
color: '#ffe033',
type: 'chain',
},
{
id: 'mortar',
name: 'MORTAR',
desc: 'Lobbed shell with AoE explosion. Slow reload.',
icon: '💥',
cost: 1500,
defaultElement: 'physical',
targeting: 'group',
fireRate: 180,
damage: 12,
aoeRadius: 60,
projectileSpeed: 2.8,
range: 480,
color: '#ff7043',
type: 'mortar',
},
{
id: 'laser',
name: 'LASER',
desc: 'Continuous beam piercing all enemies in a line.',
icon: '🔴',
cost: 2000,
defaultElement: 'arcane',
targeting: 'furthest',
fireRate: 10,
damage: 1,
range: 390,
color: '#ff77e9',
type: 'beam',
},
{
id: 'freezebomb',
name: 'FREEZE BOMB',
desc: 'AoE ice explosion. Freezes enemies solid briefly.',
icon: '❄️',
cost: 1800,
defaultElement: 'ice',
targeting: 'group',
fireRate: 150,
damage: 5,
aoeRadius: 75,
freezeDuration: 180,
projectileSpeed: 2.4,
range: 400,
color: '#7ecfff',
type: 'mortar',
},
{
id: 'voidcannon',
name: 'VOID CANNON',
desc: 'Massive slow projectile. Strips armor, bypasses resistance.',
icon: '🌀',
cost: 2000,
defaultElement: 'void',
targeting: 'strongest',
fireRate: 240,
damage: 20,
armorShred: 5,
projectileSpeed: 1.8,
projectileRadius: 12,
range: 360,
color: '#c77dff',
type: 'projectile',
},
{
id: 'missilepod',
name: 'MISSILE POD',
desc: 'Fires homing AoE missiles at 3 targets simultaneously.',
icon: '🚀',
cost: 2400,
defaultElement: 'fire',
targeting: 'group',
fireRate: 120,
damage: 8,
targets: 3,
aoeRadius: 36,
projectileSpeed: 3.6,
range: 450,
color: '#ff4500',
type: 'multi',
},
{
id: 'arcaneturret',
name: 'ARCANE TURRET',
desc: 'Rapid magic bolts. Applies Amplify debuff (+25% dmg taken).',
icon: '✨',
cost: 2200,
defaultElement: 'arcane',
targeting: 'nearest',
fireRate: 20,
damage: 2,
amplify: 0.25,
projectileSpeed: 5.8,
range: 280,
color: '#ff77e9',
type: 'projectile',
},
{
id: 'poisoncloud',
name: 'POISON CLOUD',
desc: 'Launches a lingering poison gas cloud.',
icon: '☠️',
cost: 1600,
defaultElement: 'poison',
targeting: 'group',
fireRate: 130,
damage: 2,
dotDamage: 1,
dotInterval: 30,
dotDuration: 180,
aoeRadius: 55,
projectileSpeed: 2.2,
range: 350,
color: '#7fff4f',
type: 'mortar',
},
];
const MAX_WEAPONS_PER_TYPE = 8;
// ── UPGRADE TREES ─────────────────────────────────────────────
// Tower general upgrades
const TOWER_UPGRADE_TREE = [
{
id: 'hp1', label: 'Reinforced Hull I', desc: '+5 Max HP',
cost: 100, requires: [], effect: { maxHp: 5 },
},
{
id: 'hp2', label: 'Reinforced Hull II', desc: '+10 Max HP',
cost: 250, requires: ['hp1'], effect: { maxHp: 10 },
},
{
id: 'hp3', label: 'Reinforced Hull III', desc: '+20 Max HP',
cost: 600, requires: ['hp2'], effect: { maxHp: 20 },
},
{
id: 'hp4', label: 'Reinforced Hull IV', desc: '+35 Max HP',
cost: 1400, requires: ['hp3'], effect: { maxHp: 35 },
},
{
id: 'hp5', label: 'Reinforced Hull V', desc: '+60 Max HP',
cost: 3000, requires: ['hp4'], effect: { maxHp: 60 },
},
{
id: 'armor1', label: 'Plating I', desc: '+1 Armor',
cost: 150, requires: [], effect: { armor: 1 },
},
{
id: 'armor2', label: 'Plating II', desc: '+2 Armor',
cost: 400, requires: ['armor1'], effect: { armor: 2 },
},
{
id: 'armor3', label: 'Plating III', desc: '+3 Armor',
cost: 900, requires: ['armor2'], effect: { armor: 3 },
},
{
id: 'armor4', label: 'Plating IV', desc: '+4 Armor',
cost: 2000, requires: ['armor3'], effect: { armor: 4 },
},
{
id: 'armor5', label: 'Plating V', desc: '+6 Armor',
cost: 4500, requires: ['armor4'], effect: { armor: 6 },
},
{
id: 'aim1', label: 'Servo Motors I', desc: '+0.015 Aim Speed',
cost: 100, requires: [], effect: { aimSpeed: 0.015 },
},
{
id: 'aim2', label: 'Servo Motors II', desc: '+0.02 Aim Speed',
cost: 200, requires: ['aim1'], effect: { aimSpeed: 0.02 },
},
{
id: 'aim3', label: 'Servo Motors III', desc: '+0.025 Aim Speed',
cost: 350, requires: ['aim2'], effect: { aimSpeed: 0.025 },
},
{
id: 'aim4', label: 'Servo Motors IV', desc: '+0.035 Aim Speed',
cost: 600, requires: ['aim3'], effect: { aimSpeed: 0.035 },
},
{
id: 'aim5', label: 'Servo Motors V', desc: '+0.05 Aim Speed',
cost: 1200, requires: ['aim4'], effect: { aimSpeed: 0.05 },
},
{
id: 'aim6', label: 'Servo Motors VI', desc: '+0.07 Aim Speed — Near instant',
cost: 2500, requires: ['aim5'], effect: { aimSpeed: 0.07 },
},
{
id: 'repair1', label: 'Field Repair', desc: 'Restore 5 HP',
cost: 80, requires: [], effect: { repair: 5 }, repeatable: true,
},
{
id: 'slot2', label: 'Weapon Slot II', desc: 'Unlock 2nd weapon slot',
cost: 500, requires: [], effect: { weaponSlot: 2 },
},
{
id: 'slot3', label: 'Weapon Slot III', desc: 'Unlock 3rd weapon slot',
cost: 1500, requires: ['slot2'], effect: { weaponSlot: 3 },
},
{
id: 'slot4', label: 'Weapon Slot IV', desc: 'Unlock 4th weapon slot',
cost: 3500, requires: ['slot3'], effect: { weaponSlot: 4 },
},
{
id: 'slot5', label: 'Weapon Slot V', desc: 'Unlock 5th weapon slot',
cost: 7000, requires: ['slot4'], effect: { weaponSlot: 5 }, minTier: 1,
},
{
id: 'slot6', label: 'Weapon Slot VI', desc: 'Unlock 6th weapon slot',
cost: 12000, requires: ['slot5'], effect: { weaponSlot: 6 }, minTier: 2,
},
{
id: 'slot7', label: 'Weapon Slot VII', desc: 'Unlock 7th weapon slot',
cost: 20000, requires: ['slot6'], effect: { weaponSlot: 7 }, minTier: 3,
},
{
id: 'slot8', label: 'Weapon Slot VIII', desc: 'Unlock 8th weapon slot',
cost: 30000, requires: ['slot7'], effect: { weaponSlot: 8 }, minTier: 4,
},
{
id: 'shield_dome', label: 'Dome Shield', desc: 'Buy dome shield system',
cost: 800, requires: [], effect: { shield: 'dome' },
},
{
id: 'shield_dir', label: 'Directional Shield', desc: 'Buy directional shield',
cost: 600, requires: [], effect: { shield: 'directional' },
},
];
// Per-weapon upgrade trees — each node has a `category` for grouped display
const WEAPON_UPGRADE_TREES = {
cannon: [
// Damage
{ id: 'dmg1', label: 'Damage I', desc: '+2 damage', cost: 80, requires: [], effect: { damage: 2 }, category: 'Damage' },
{ id: 'dmg2', label: 'Damage II', desc: '+3 damage', cost: 200, requires: ['dmg1'], effect: { damage: 3 }, category: 'Damage' },
{ id: 'dmg3', label: 'Damage III', desc: '+5 damage', cost: 450, requires: ['dmg2'], effect: { damage: 5 }, category: 'Damage' },
{ id: 'dmg4', label: 'Damage IV', desc: '+8 damage', cost: 900, requires: ['dmg3'], effect: { damage: 8 }, category: 'Damage' },
// Fire Rate
{ id: 'rate1', label: 'Fire Rate I', desc: '-15 frames', cost: 100, requires: [], effect: { fireRate: -15 }, category: 'Fire Rate' },
{ id: 'rate2', label: 'Fire Rate II', desc: '-20 frames', cost: 250, requires: ['rate1'], effect: { fireRate: -20 }, category: 'Fire Rate' },
{ id: 'rate3', label: 'Fire Rate III',desc: '-25 frames', cost: 550, requires: ['rate2'], effect: { fireRate: -25 }, category: 'Fire Rate' },
// Velocity
{ id: 'speed1', label: 'Velocity I', desc: '+3 proj speed', cost: 90, requires: [], effect: { projectileSpeed: 3 }, category: 'Velocity' },
{ id: 'speed2', label: 'Velocity II', desc: '+4 proj speed', cost: 220, requires: ['speed1'], effect: { projectileSpeed: 4 }, category: 'Velocity' },
{ id: 'speed3', label: 'Velocity III',desc: '+5 proj speed', cost: 500, requires: ['speed2'], effect: { projectileSpeed: 5 }, category: 'Velocity' },
// Special
{ id: 'pierce1', label: 'Piercing I', desc: 'Pierce 1 extra', cost: 200, requires: ['dmg1'], effect: { pierce: 1 }, category: 'Special' },
{ id: 'pierce2', label: 'Piercing II', desc: 'Pierce 2 extra', cost: 500, requires: ['pierce1'], effect: { pierce: 1 }, category: 'Special' },
{ id: 'pierce3', label: 'Piercing III', desc: 'Pierce 3 extra', cost: 1100, requires: ['pierce2'], effect: { pierce: 1 }, category: 'Special' },
{ id: 'pierce4', label: 'Piercing IV', desc: 'Pierce 4 extra', cost: 2400, requires: ['pierce3'], effect: { pierce: 1 }, category: 'Special' },
{ id: 'pierce5', label: 'Piercing V', desc: 'Pierce 5 extra', cost: 5000, requires: ['pierce4'], effect: { pierce: 1 }, category: 'Special' },
{ id: 'crit1', label: 'Crit I', desc: '+10% crit', cost: 180, requires: ['dmg1'], effect: { critChance: 0.10 }, category: 'Special' },
{ id: 'crit2', label: 'Crit II', desc: '+15% crit', cost: 400, requires: ['crit1'], effect: { critChance: 0.15 }, category: 'Special' },
{ id: 'crit3', label: 'Crit III', desc: '+20% crit', cost: 900, requires: ['crit2'], effect: { critChance: 0.20 }, category: 'Special' },
// Elements
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
{ id: 'el3', label: 'Infuse: Slot 3', desc: 'Unlock 3rd element slot', cost: 2000, requires: ['el2'], effect: { canInfuse3: true }, category: 'Elements' },
// Range
{ id: 'range1', label: 'Barrel Ext I', desc: '+50 range', cost: 200, requires: [], effect: { range: 50 }, category: 'Range' },
{ id: 'range2', label: 'Barrel Ext II', desc: '+80 range', cost: 550, requires: ['range1'], effect: { range: 80 }, category: 'Range' },
{ id: 'range3', label: 'Barrel Ext III', desc: '+110 range', cost: 1400, requires: ['range2'], effect: { range: 110 }, category: 'Range' },
],
flamethrower: [
{ id: 'dmg1', label: 'Heat I', desc: '+1 dmg/tick', cost: 120, requires: [], effect: { damage: 1 }, category: 'Damage' },
{ id: 'dmg2', label: 'Heat II', desc: '+2 dmg/tick', cost: 300, requires: ['dmg1'], effect: { damage: 2 }, category: 'Damage' },
{ id: 'dmg3', label: 'Heat III', desc: '+3 dmg/tick', cost: 700, requires: ['dmg2'], effect: { damage: 3 }, category: 'Damage' },
{ id: 'range1', label: 'Range I', desc: '+40 range', cost: 150, requires: [], effect: { range: 40 }, category: 'Range' },
{ id: 'range2', label: 'Range II', desc: '+60 range', cost: 350, requires: ['range1'], effect: { range: 60 }, category: 'Range' },
{ id: 'range3', label: 'Range III',desc: '+80 range', cost: 800, requires: ['range2'], effect: { range: 80 }, category: 'Range' },
{ id: 'cone1', label: 'Wide Cone I', desc: '+15° angle', cost: 200, requires: [], effect: { coneAngle: 0.07 }, category: 'Cone' },
{ id: 'cone2', label: 'Wide Cone II', desc: '+20° angle', cost: 500, requires: ['cone1'], effect: { coneAngle: 0.10 }, category: 'Cone' },
{ id: 'burn1', label: 'Burn I', desc: '+60 burn frames', cost: 180, requires: ['dmg1'], effect: { dotDuration: 60 }, category: 'Special' },
{ id: 'burn2', label: 'Burn II', desc: '+90 burn frames', cost: 400, requires: ['burn1'], effect: { dotDuration: 90 }, category: 'Special' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
],
chainlightning: [
{ id: 'dmg1', label: 'Voltage I', desc: '+2 damage', cost: 150, requires: [], effect: { damage: 2 }, category: 'Damage' },
{ id: 'dmg2', label: 'Voltage II', desc: '+4 damage', cost: 380, requires: ['dmg1'], effect: { damage: 4 }, category: 'Damage' },
{ id: 'dmg3', label: 'Voltage III',desc: '+6 damage', cost: 900, requires: ['dmg2'], effect: { damage: 6 }, category: 'Damage' },
{ id: 'chains1', label: 'Chain +1', desc: '+1 arc target', cost: 300, requires: [], effect: { chains: 1 }, category: 'Chains' },
{ id: 'chains2', label: 'Chain +2', desc: '+2 arc targets', cost: 700, requires: ['chains1'], effect: { chains: 2 }, category: 'Chains' },
{ id: 'chains3', label: 'Chain +3', desc: '+3 arc targets', cost: 1600, requires: ['chains2'],effect: { chains: 3 }, category: 'Chains' },
{ id: 'range1', label: 'Arc Range I', desc: '+50 chain range', cost: 200, requires: [], effect: { chainRange: 50 }, category: 'Range' },
{ id: 'range2', label: 'Arc Range II', desc: '+80 chain range', cost: 500, requires: ['range1'], effect: { chainRange: 80 }, category: 'Range' },
{ id: 'rate1', label: 'Frequency I', desc: '-15 frames', cost: 150, requires: [], effect: { fireRate: -15 }, category: 'Fire Rate' },
{ id: 'rate2', label: 'Frequency II', desc: '-20 frames', cost: 400, requires: ['rate1'], effect: { fireRate: -20 }, category: 'Fire Rate' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
],
mortar: [
{ id: 'dmg1', label: 'Payload I', desc: '+5 damage', cost: 200, requires: [], effect: { damage: 5 }, category: 'Damage' },
{ id: 'dmg2', label: 'Payload II', desc: '+8 damage', cost: 500, requires: ['dmg1'], effect: { damage: 8 }, category: 'Damage' },
{ id: 'dmg3', label: 'Payload III',desc: '+12 damage',cost: 1100, requires: ['dmg2'],effect: { damage: 12}, category: 'Damage' },
{ id: 'aoe1', label: 'Blast Radius I', desc: '+20 AoE', cost: 180, requires: [], effect: { aoeRadius: 20 }, category: 'Blast' },
{ id: 'aoe2', label: 'Blast Radius II', desc: '+30 AoE', cost: 450, requires: ['aoe1'], effect: { aoeRadius: 30 }, category: 'Blast' },
{ id: 'aoe3', label: 'Blast Radius III',desc: '+40 AoE', cost: 950, requires: ['aoe2'], effect: { aoeRadius: 40 }, category: 'Blast' },
{ id: 'rate1', label: 'Reload I', desc: '-40 frames', cost: 250, requires: [], effect: { fireRate: -40 }, category: 'Fire Rate' },
{ id: 'rate2', label: 'Reload II', desc: '-50 frames', cost: 600, requires: ['rate1'], effect: { fireRate: -50 }, category: 'Fire Rate' },
{ id: 'speed1', label: 'Velocity I', desc: '+1.5 proj spd', cost: 200, requires: [], effect: { projectileSpeed: 1.5 }, category: 'Velocity' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
{ id: 'el3', label: 'Infuse: Slot 3', desc: 'Unlock 3rd element slot', cost: 2000, requires: ['el2'], effect: { canInfuse3: true }, category: 'Elements' },
],
laser: [
{ id: 'dmg1', label: 'Focus I', desc: '+1 dmg/tick', cost: 180, requires: [], effect: { damage: 1 }, category: 'Damage' },
{ id: 'dmg2', label: 'Focus II', desc: '+2 dmg/tick', cost: 450, requires: ['dmg1'], effect: { damage: 2 }, category: 'Damage' },
{ id: 'dmg3', label: 'Focus III',desc: '+3 dmg/tick', cost: 1000, requires: ['dmg2'],effect: { damage: 3 }, category: 'Damage' },
{ id: 'rate1', label: 'Frequency I', desc: '-2 tick frames', cost: 200, requires: [], effect: { fireRate: -2 }, category: 'Fire Rate' },
{ id: 'rate2', label: 'Frequency II', desc: '-2 tick frames', cost: 500, requires: ['rate1'], effect: { fireRate: -2 }, category: 'Fire Rate' },
{ id: 'rate3', label: 'Frequency III',desc: '-2 tick frames', cost: 1200, requires: ['rate2'],effect: { fireRate: -2 }, category: 'Fire Rate' },
{ id: 'width1', label: 'Wide Beam I', desc: '+6 hit radius', cost: 300, requires: [], effect: { projectileRadius: 6 }, category: 'Width' },
{ id: 'width2', label: 'Wide Beam II', desc: '+8 hit radius', cost: 700, requires: ['width1'], effect: { projectileRadius: 8 }, category: 'Width' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
// Range
{ id: 'range1', label: 'Focal Lens I', desc: '+60 range', cost: 250, requires: [], effect: { range: 60 }, category: 'Range' },
{ id: 'range2', label: 'Focal Lens II', desc: '+100 range', cost: 750, requires: ['range1'], effect: { range: 100 }, category: 'Range' },
{ id: 'range3', label: 'Focal Lens III', desc: '+140 range', cost: 1800, requires: ['range2'], effect: { range: 140 }, category: 'Range' },
],
freezebomb: [
{ id: 'dmg1', label: 'Cold I', desc: '+3 damage', cost: 200, requires: [], effect: { damage: 3 }, category: 'Damage' },
{ id: 'dmg2', label: 'Cold II', desc: '+5 damage', cost: 500, requires: ['dmg1'], effect: { damage: 5 }, category: 'Damage' },
{ id: 'aoe1', label: 'Blast I', desc: '+25 AoE', cost: 220, requires: [], effect: { aoeRadius: 25 }, category: 'Blast' },
{ id: 'aoe2', label: 'Blast II', desc: '+35 AoE', cost: 550, requires: ['aoe1'], effect: { aoeRadius: 35 }, category: 'Blast' },
{ id: 'freeze1', label: 'Deep Freeze I', desc: '+60 freeze frames', cost: 280, requires: [], effect: { freezeDuration: 60 }, category: 'Freeze' },
{ id: 'freeze2', label: 'Deep Freeze II', desc: '+90 freeze frames', cost: 600, requires: ['freeze1'], effect: { freezeDuration: 90 }, category: 'Freeze' },
{ id: 'freeze3', label: 'Deep Freeze III',desc: '+120 freeze frames', cost: 1300, requires: ['freeze2'], effect: { freezeDuration: 120}, category: 'Freeze' },
{ id: 'rate1', label: 'Reload I', desc: '-40 frames', cost: 300, requires: [], effect: { fireRate: -40 }, category: 'Fire Rate' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
],
voidcannon: [
{ id: 'dmg1', label: 'Singularity I', desc: '+8 damage', cost: 300, requires: [], effect: { damage: 8 }, category: 'Damage' },
{ id: 'dmg2', label: 'Singularity II', desc: '+15 damage', cost: 750, requires: ['dmg1'], effect: { damage: 15 }, category: 'Damage' },
{ id: 'dmg3', label: 'Singularity III',desc: '+25 damage', cost: 1600, requires: ['dmg2'],effect: { damage: 25 }, category: 'Damage' },
{ id: 'shred1', label: 'Armor Shred I', desc: '+3 armor shred', cost: 400, requires: [], effect: { armorShred: 3 }, category: 'Special' },
{ id: 'shred2', label: 'Armor Shred II', desc: '+5 armor shred', cost: 900, requires: ['shred1'], effect: { armorShred: 5 }, category: 'Special' },
{ id: 'speed1', label: 'Velocity I', desc: '+1.5 proj spd', cost: 350, requires: [], effect: { projectileSpeed: 1.5 }, category: 'Velocity' },
{ id: 'speed2', label: 'Velocity II', desc: '+2 proj spd', cost: 800, requires: ['speed1'], effect: { projectileSpeed: 2 }, category: 'Velocity' },
{ id: 'size1', label: 'Projectile Size I', desc: '+4 proj radius', cost: 400, requires: [], effect: { projectileRadius: 4 }, category: 'Size' },
{ id: 'rate1', label: 'Reload I', desc: '-50 frames', cost: 500, requires: [], effect: { fireRate: -50 }, category: 'Fire Rate' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
{ id: 'el3', label: 'Infuse: Slot 3', desc: 'Unlock 3rd element slot', cost: 2000, requires: ['el2'], effect: { canInfuse3: true }, category: 'Elements' },
],
missilepod: [
{ id: 'dmg1', label: 'Warhead I', desc: '+4 damage', cost: 250, requires: [], effect: { damage: 4 }, category: 'Damage' },
{ id: 'dmg2', label: 'Warhead II', desc: '+6 damage', cost: 600, requires: ['dmg1'], effect: { damage: 6 }, category: 'Damage' },
{ id: 'dmg3', label: 'Warhead III',desc: '+10 damage',cost: 1400, requires: ['dmg2'],effect: { damage: 10}, category: 'Damage' },
{ id: 'targets1', label: '+1 Target', desc: 'Fire at 1 more', cost: 500, requires: [], effect: { targets: 1 }, category: 'Targets' },
{ id: 'targets2', label: '+2 Targets',desc: 'Fire at 2 more', cost: 1200, requires: ['targets1'], effect: { targets: 2 }, category: 'Targets', minTier: 2 },
{ id: 'targets3', label: '+3 Targets',desc: 'Fire at 3 more', cost: 2800, requires: ['targets2'], effect: { targets: 3 }, category: 'Targets', minTier: 2 },
{ id: 'rate1', label: 'Reload I', desc: '-30 frames', cost: 300, requires: [], effect: { fireRate: -30 }, category: 'Fire Rate' },
{ id: 'rate2', label: 'Reload II', desc: '-40 frames', cost: 700, requires: ['rate1'], effect: { fireRate: -40 }, category: 'Fire Rate' },
{ id: 'speed1', label: 'Velocity I', desc: '+2 proj spd', cost: 300, requires: [], effect: { projectileSpeed: 2 }, category: 'Velocity' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
],
arcaneturret: [
{ id: 'dmg1', label: 'Potency I', desc: '+1 damage', cost: 120, requires: [], effect: { damage: 1 }, category: 'Damage' },
{ id: 'dmg2', label: 'Potency II', desc: '+2 damage', cost: 300, requires: ['dmg1'], effect: { damage: 2 }, category: 'Damage' },
{ id: 'dmg3', label: 'Potency III',desc: '+3 damage', cost: 700, requires: ['dmg2'], effect: { damage: 3 }, category: 'Damage', minTier: 2 },
{ id: 'rate1', label: 'Frequency I', desc: '-5 frames', cost: 150, requires: [], effect: { fireRate: -5 }, category: 'Fire Rate' },
{ id: 'rate2', label: 'Frequency II', desc: '-5 frames', cost: 380, requires: ['rate1'], effect: { fireRate: -5 }, category: 'Fire Rate' },
{ id: 'rate3', label: 'Frequency III',desc: '-4 frames', cost: 850, requires: ['rate2'], effect: { fireRate: -4 }, category: 'Fire Rate', minTier: 2 },
{ id: 'amp1', label: 'Amplify I', desc: '+10% amp', cost: 300, requires: ['dmg1'], effect: { amplify: 0.10 }, category: 'Special' },
{ id: 'amp2', label: 'Amplify II', desc: '+15% amp', cost: 700, requires: ['amp1'], effect: { amplify: 0.15 }, category: 'Special', minTier: 2 },
{ id: 'speed1',label: 'Velocity I', desc: '+3 proj spd',cost: 200, requires: [], effect: { projectileSpeed: 3 }, category: 'Velocity' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
],
poisoncloud: [
{ id: 'dmg1', label: 'Toxin I', desc: '+1 dot dmg', cost: 150, requires: [], effect: { dotDamage: 1 }, category: 'Damage' },
{ id: 'dmg2', label: 'Toxin II', desc: '+2 dot dmg', cost: 380, requires: ['dmg1'], effect: { dotDamage: 2 }, category: 'Damage' },
{ id: 'dmg3', label: 'Toxin III',desc: '+3 dot dmg', cost: 850, requires: ['dmg2'], effect: { dotDamage: 3 }, category: 'Damage' },
{ id: 'dur1', label: 'Duration I', desc: '+60 cloud frames', cost: 180, requires: [], effect: { dotDuration: 60 }, category: 'Duration' },
{ id: 'dur2', label: 'Duration II', desc: '+90 cloud frames', cost: 450, requires: ['dur1'], effect: { dotDuration: 90 }, category: 'Duration' },
{ id: 'dur3', label: 'Duration III',desc: '+120 cloud frames', cost: 1000, requires: ['dur2'], effect: { dotDuration: 120}, category: 'Duration' },
{ id: 'aoe1', label: 'Cloud I', desc: '+20 AoE', cost: 200, requires: [], effect: { aoeRadius: 20 }, category: 'Blast' },
{ id: 'aoe2', label: 'Cloud II', desc: '+30 AoE', cost: 500, requires: ['aoe1'], effect: { aoeRadius: 30 }, category: 'Blast' },
{ id: 'rate1', label: 'Reload I', desc: '-30 frames', cost: 250, requires: [], effect: { fireRate: -30 }, category: 'Fire Rate' },
{ id: 'el1', label: 'Infuse: Slot 1', desc: 'Unlock 1st element slot', cost: 300, requires: [], effect: { canInfuse: true }, category: 'Elements' },
{ id: 'el2', label: 'Infuse: Slot 2', desc: 'Unlock 2nd element slot', cost: 800, requires: ['el1'], effect: { canInfuse2: true }, category: 'Elements' },
],
};
// Shield upgrade trees
const SHIELD_UPGRADE_TREES = {
dome: [
{ id: 'cap1', label: 'Capacity I', desc: '+5 shield HP', cost: 200, requires: [], effect: { capacity: 5 } },
{ id: 'cap2', label: 'Capacity II', desc: '+10 shield HP', cost: 500, requires: ['cap1'], effect: { capacity: 10 } },
{ id: 'cap3', label: 'Capacity III', desc: '+20 shield HP', cost: 1100, requires: ['cap2'], effect: { capacity: 20 } },
{ id: 'regen1', label: 'Recharge I', desc: '-30 frames recharge', cost: 300, requires: [], effect: { rechargeDelay: -30 } },
{ id: 'regen2', label: 'Recharge II', desc: '-60 frames recharge', cost: 700, requires: ['regen1'], effect: { rechargeDelay: -60 } },
{ id: 'reflect1', label: 'Reflect', desc: 'Reflect 20% dmg back', cost: 1500, requires: ['cap2'], effect: { reflect: 0.2 } },
],
directional: [
{ id: 'arc1', label: 'Wide Arc I', desc: '+20° arc width', cost: 200, requires: [], effect: { arcWidth: 0.35 } },
{ id: 'arc2', label: 'Wide Arc II', desc: '+30° arc width', cost: 500, requires: ['arc1'], effect: { arcWidth: 0.52 } },
{ id: 'cap1', label: 'Capacity I', desc: '+8 shield HP', cost: 250, requires: [], effect: { capacity: 8 } },
{ id: 'cap2', label: 'Capacity II', desc: '+15 shield HP', cost: 600, requires: ['cap1'], effect: { capacity: 15 } },
{ id: 'speed1', label: 'Track Speed I', desc: '+50% shield rotation', cost: 300, requires: [], effect: { trackSpeed: 0.03 } },
{ id: 'speed2', label: 'Track Speed II', desc: '+100% shield rotation', cost: 700, requires: ['speed1'], effect: { trackSpeed: 0.06 } },
{ id: 'absorb1', label: 'Absorption I', desc: 'Block 25% more damage', cost: 400, requires: ['cap1'], effect: { absorption: 0.25 } },
],
};