This repository has been archived on 2026-05-04. You can view files and clone it, but cannot push or open issues or pull requests.
Galaxy-Strike-Online/GameServer/systems/ResearchSystem.js
2026-03-11 00:32:45 -03:00

159 lines
13 KiB
JavaScript

/**
* Galaxy Strike Online — Research System (GDD §16)
* Tech tree: Engineering · Propulsion · Weapons · Science
* Effects are accumulated in playerData.research.effects and applied by:
* - ResourceSystem (miningBonus, buildTimeReduction)
* - MissionSystem (travelSpeed)
* - _simulatePvpBattle in server.js (weaponDamage, armorBonus, hullBonus)
* - GalaxySystem (sensorRange)
* - CraftingSystem (craftingSpeed)
*/
const RESEARCH_TREE = {
// ── Weapons ───────────────────────────────────────────────────────────────
basic_lasers: { id:'basic_lasers', name:'Basic Lasers', branch:'weapons', tier:1, cost:{credits:500, gems:0 }, time:60, effects:{ weaponDamage:10 }, requires:[] },
pulse_lasers: { id:'pulse_lasers', name:'Pulse Lasers', branch:'weapons', tier:2, cost:{credits:1200, gems:0 }, time:180, effects:{ weaponDamage:25 }, requires:['basic_lasers'] },
advanced_lasers: { id:'advanced_lasers', name:'Advanced Lasers', branch:'weapons', tier:3, cost:{credits:3000, gems:5 }, time:600, effects:{ weaponDamage:50 }, requires:['pulse_lasers'] },
railgun_tech: { id:'railgun_tech', name:'Railgun Tech', branch:'weapons', tier:2, cost:{credits:2000, gems:0 }, time:240, effects:{ armorPierce:20 }, requires:['basic_lasers'] },
smart_warheads: { id:'smart_warheads', name:'Smart Warheads', branch:'weapons', tier:4, cost:{credits:9000, gems:10}, time:1200, effects:{ weaponDamage:30, armorPierce:15 }, requires:['railgun_tech'] },
emp_technology: { id:'emp_technology', name:'EMP Technology', branch:'weapons', tier:3, cost:{credits:4000, gems:5 }, time:720, effects:{ empChance:15 }, requires:['pulse_lasers'] },
quantum_torpedoes: { id:'quantum_torpedoes', name:'Quantum Torpedoes', branch:'weapons', tier:5, cost:{credits:18000, gems:20}, time:2400, effects:{ weaponDamage:80, critChanceBonus:10 }, requires:['smart_warheads','emp_technology'] },
// ── Engineering ───────────────────────────────────────────────────────────
structural_analysis:{ id:'structural_analysis', name:'Structural Analysis', branch:'engineering', tier:1, cost:{credits:400, gems:0 }, time:60, effects:{ hullBonus:10 }, requires:[] },
nano_composites: { id:'nano_composites', name:'Nano-Composites', branch:'engineering', tier:2, cost:{credits:1000, gems:0 }, time:180, effects:{ hullBonus:25 }, requires:['structural_analysis'] },
reactive_armor: { id:'reactive_armor', name:'Reactive Armor', branch:'engineering', tier:3, cost:{credits:3500, gems:5 }, time:600, effects:{ armorBonus:40 }, requires:['nano_composites'] },
construction_eff: { id:'construction_eff', name:'Construction Efficiency',branch:'engineering',tier:1, cost:{credits:350, gems:0 }, time:60, effects:{ buildTimeReduction:10 }, requires:[] },
mass_production: { id:'mass_production', name:'Mass Production', branch:'engineering', tier:3, cost:{credits:5000, gems:5 }, time:900, effects:{ buildTimeReduction:25 }, requires:['construction_eff'] },
megastructure_eng: { id:'megastructure_eng', name:'Megastructure Engineering',branch:'engineering',tier:5,cost:{credits:22000,gems:25},time:3600, effects:{ buildTimeReduction:40, hullBonus:30 }, requires:['mass_production','reactive_armor'] },
shield_matrix: { id:'shield_matrix', name:'Shield Matrix', branch:'engineering', tier:2, cost:{credits:1200, gems:0 }, time:180, effects:{ shieldRegen:50 }, requires:[] },
heavy_armor_plating:{ id:'heavy_armor_plating', name:'Heavy Armor Plating', branch:'engineering', tier:4, cost:{credits:12000, gems:15}, time:1800, effects:{ armorBonus:80 }, requires:['reactive_armor'] },
auto_repair: { id:'auto_repair', name:'Auto-Repair Drones', branch:'engineering', tier:3, cost:{credits:4000, gems:5 }, time:720, effects:{ hullRegen:2 }, requires:['shield_matrix'] },
// ── Propulsion ────────────────────────────────────────────────────────────
improved_engines: { id:'improved_engines', name:'Improved Engines', branch:'propulsion', tier:1, cost:{credits:300, gems:0 }, time:60, effects:{ travelSpeed:10 }, requires:[] },
afterburners: { id:'afterburners', name:'Afterburners', branch:'propulsion', tier:2, cost:{credits:800, gems:0 }, time:150, effects:{ travelSpeed:20 }, requires:['improved_engines'] },
ion_drives: { id:'ion_drives', name:'Ion Drives', branch:'propulsion', tier:3, cost:{credits:2500, gems:5 }, time:480, effects:{ travelSpeed:35, fuelEfficiency:15 }, requires:['afterburners'] },
warp_drive: { id:'warp_drive', name:'Warp Drive', branch:'propulsion', tier:4, cost:{credits:8000, gems:10}, time:1200, effects:{ travelSpeed:60 }, requires:['ion_drives'] },
quantum_slip: { id:'quantum_slip', name:'Quantum Slipstream', branch:'propulsion', tier:5, cost:{credits:20000, gems:20}, time:3600, effects:{ travelSpeed:100, fuelEfficiency:30 }, requires:['warp_drive'] },
long_range_sensors: { id:'long_range_sensors', name:'Long Range Sensors', branch:'propulsion', tier:1, cost:{credits:300, gems:0 }, time:60, effects:{ sensorRange:2 }, requires:[] },
deep_space_nav: { id:'deep_space_nav', name:'Deep Space Navigation', branch:'propulsion', tier:3, cost:{credits:4000, gems:5 }, time:720, effects:{ sensorRange:3, travelSpeed:15 }, requires:['long_range_sensors','ion_drives'] },
wormhole_nav: { id:'wormhole_nav', name:'Wormhole Navigation', branch:'propulsion', tier:4, cost:{credits:8000, gems:15}, time:1200, effects:{ warpCooldown:50, sensorRange:2 }, requires:['deep_space_nav'] },
// ── Science ───────────────────────────────────────────────────────────────
enhanced_mining: { id:'enhanced_mining', name:'Enhanced Mining', branch:'science', tier:1, cost:{credits:200, gems:0 }, time:60, effects:{ miningBonus:15 }, requires:[] },
deep_core_drills: { id:'deep_core_drills', name:'Deep-Core Drills', branch:'science', tier:3, cost:{credits:2500, gems:5 }, time:600, effects:{ miningBonus:35 }, requires:['enhanced_mining'] },
trade_protocols: { id:'trade_protocols', name:'Trade Protocols', branch:'science', tier:2, cost:{credits:600, gems:0 }, time:120, effects:{ tradeFeeReduction:10 }, requires:[] },
advanced_alchemy: { id:'advanced_alchemy', name:'Advanced Alchemy', branch:'science', tier:2, cost:{credits:700, gems:0 }, time:150, effects:{ craftingSpeed:15 }, requires:[] },
nano_fabrication: { id:'nano_fabrication', name:'Nano-Fabrication', branch:'science', tier:3, cost:{credits:3000, gems:5 }, time:600, effects:{ craftingSpeed:30, miningBonus:10 }, requires:['advanced_alchemy'] },
xenobiology: { id:'xenobiology', name:'Xenobiology', branch:'science', tier:2, cost:{credits:900, gems:0 }, time:180, effects:{ xpBonus:10 }, requires:[] },
consciousness_uplink:{ id:'consciousness_uplink',name:'Consciousness Uplink', branch:'science', tier:4, cost:{credits:10000, gems:10}, time:1800, effects:{ xpBonus:25, craftingSpeed:20 }, requires:['xenobiology','nano_fabrication'] },
dark_matter_theory: { id:'dark_matter_theory', name:'Dark Matter Theory', branch:'science', tier:4, cost:{credits:12000, gems:15}, time:2100, effects:{ miningBonus:50, darkMatterBonus:25 }, requires:['deep_core_drills'] },
omega_synthesis: { id:'omega_synthesis', name:'Omega Synthesis', branch:'science', tier:5, cost:{credits:25000, gems:30}, time:4800, effects:{ craftingSpeed:50, miningBonus:30, xpBonus:20 }, requires:['dark_matter_theory','consciousness_uplink'] },
};
class ResearchSystem {
constructor() { this.tree = RESEARCH_TREE; }
getTree() { return Object.values(this.tree); }
getBranches() {
const branches = {};
for (const tech of Object.values(this.tree)) {
if (!branches[tech.branch]) branches[tech.branch] = [];
branches[tech.branch].push(tech);
}
// Sort each branch by tier
for (const b of Object.values(branches)) b.sort((a, z) => a.tier - z.tier);
return branches;
}
/** Return full tree annotated with per-player status */
getAvailableResearch(playerData) {
const completed = new Set(playerData.research?.completed || []);
const inProgress = playerData.research?.inProgress || null;
return Object.values(this.tree).map(tech => ({
...tech,
status:
completed.has(tech.id) ? 'completed' :
inProgress?.techId === tech.id ? 'in_progress' :
tech.requires.every(r => completed.has(r)) ? 'available' : 'locked',
progressPercent: inProgress?.techId === tech.id
? Math.min(100, Math.floor(((Date.now() - inProgress.startedAt) / (tech.time * 1000)) * 100))
: 0,
}));
}
/** Start researching a technology — deducts credits/gems, sets inProgress */
startResearch(playerData, techId) {
const tech = this.tree[techId];
if (!tech) throw new Error('Unknown technology: ' + techId);
const completed = new Set(playerData.research?.completed || []);
if (completed.has(techId)) throw new Error('Already researched');
if (playerData.research?.inProgress) throw new Error('Research already in progress');
if (!tech.requires.every(r => completed.has(r))) throw new Error('Prerequisites not met');
const stats = playerData.stats || {};
if ((stats.credits || 0) < tech.cost.credits) throw new Error(`Need ${tech.cost.credits} credits`);
if ((stats.gems || 0) < tech.cost.gems) throw new Error(`Need ${tech.cost.gems} gems`);
// Apply research lab speed bonus (GDD §16)
const labLevel = playerData.buildings?.research_lab?.level || 0;
const labBonus = labLevel * 0.08; // 8% per level
const effectTime = Math.max(10, Math.floor(tech.time * (1 - labBonus)));
stats.credits = (stats.credits || 0) - tech.cost.credits;
stats.gems = (stats.gems || 0) - tech.cost.gems;
playerData.stats = stats;
playerData.research = playerData.research || { completed: [], inProgress: null, effects: {} };
playerData.research.inProgress = {
techId,
startedAt: Date.now(),
completesAt: Date.now() + effectTime * 1000,
};
return { tech, completesAt: playerData.research.inProgress.completesAt };
}
/** Check and resolve completed research — call on tick or on request */
checkCompletion(playerData) {
const ip = playerData.research?.inProgress;
if (!ip || Date.now() < ip.completesAt) return null;
const tech = this.tree[ip.techId];
if (!tech) { playerData.research.inProgress = null; return null; }
playerData.research.completed = playerData.research.completed || [];
playerData.research.completed.push(ip.techId);
playerData.research.inProgress = null;
// Accumulate effects
playerData.research.effects = playerData.research.effects || {};
for (const [k, v] of Object.entries(tech.effects || {})) {
playerData.research.effects[k] = (playerData.research.effects[k] || 0) + v;
}
return tech;
}
/** Cancel in-progress research — 75% credit/gem refund */
cancelResearch(playerData) {
const ip = playerData.research?.inProgress;
if (!ip) throw new Error('No research in progress');
const tech = this.tree[ip.techId];
playerData.stats.credits = (playerData.stats.credits || 0) + Math.floor(tech.cost.credits * 0.75);
playerData.stats.gems = (playerData.stats.gems || 0) + Math.floor(tech.cost.gems * 0.75);
playerData.research.inProgress = null;
return tech;
}
/** Return a human-readable summary of a player's accumulated research effects */
getEffectsSummary(playerData) {
const e = playerData.research?.effects || {};
return Object.entries(e)
.filter(([, v]) => v !== 0)
.map(([k, v]) => ({ effect: k, value: v }));
}
}
module.exports = { ResearchSystem, RESEARCH_TREE };