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/GalaxyEventSystem.js
2026-03-10 11:20:02 -03:00

123 lines
4.2 KiB
JavaScript

/**
* Galaxy Strike Online — Galaxy Events (GDD §20.2)
* Types: Alien Invasion, Void Surge, Sector Domination, Rogue AI Fleet Boss
* Events rotate on a schedule and reward all participating players.
*/
const EVENT_TYPES = {
alien_invasion: {
name: 'Alien Invasion',
icon: '👾',
desc: 'A massive alien fleet has entered the galaxy. Coordinate with other commanders to repel the threat.',
durationHours: 24,
rewardPool: { credits: 50000, xp: 2000, darkMatter: 50 },
minParticipants: 1,
},
void_surge: {
name: 'Void Surge',
icon: '🌀',
desc: 'Dark matter concentrations spike across multiple sectors. Mine bonus Dark Matter while the surge lasts.',
durationHours: 12,
rewardPool: { credits: 20000, xp: 1000, darkMatter: 200 },
minParticipants: 1,
bonuses: { darkMatterMultiplier: 3 },
},
rogue_ai_boss: {
name: 'Rogue AI Fleet Boss',
icon: '🤖',
desc: 'The Rogue AI Collective has deployed a capital-class vessel. Destroy it for legendary loot including Dreadnought Blueprints.',
durationHours: 48,
rewardPool: { credits: 100000, xp: 5000, darkMatter: 100, loot: ['dreadnought_blueprint'] },
minParticipants: 5,
},
sector_domination: {
name: 'Sector Domination',
icon: '⚔',
desc: 'Alliance territory season is active. The alliance controlling the most sectors at the end wins exclusive skins and titles.',
durationHours: 720, // 30 days
rewardPool: { credits: 200000, exclusiveSkin: true },
minParticipants: 10,
},
};
class GalaxyEventSystem {
constructor() {
this.activeEvent = null;
this.participants = new Map(); // userId -> contribution score
this.eventHistory = [];
this._scheduleNext();
}
_scheduleNext() {
// Rotate through events every 6 hours in dev; configurable in prod
const keys = Object.keys(EVENT_TYPES);
const idx = this.eventHistory.length % keys.length;
const type = keys[idx];
const def = EVENT_TYPES[type];
const now = Date.now();
this.activeEvent = {
id: 'event_' + now,
type,
...def,
startedAt: now,
endsAt: now + def.durationHours * 3600 * 1000,
participantCount: 0,
status: 'active',
};
this.participants.clear();
// Schedule end
setTimeout(() => this._endEvent(), def.durationHours * 3600 * 1000);
console.log(`[GALAXY EVENT] Started: ${def.name} — ends in ${def.durationHours}h`);
}
_endEvent() {
if (!this.activeEvent) return;
this.activeEvent.status = 'ended';
this.eventHistory.push({ ...this.activeEvent, endedAt: Date.now() });
this.activeEvent = null;
// Schedule next after 30 min break
setTimeout(() => this._scheduleNext(), 30 * 60 * 1000);
}
participate(userId, contributionDelta = 1) {
if (!this.activeEvent || this.activeEvent.status !== 'active') return false;
const current = this.participants.get(userId) || 0;
this.participants.set(userId, current + contributionDelta);
this.activeEvent.participantCount = this.participants.size;
return true;
}
getEventData() {
if (!this.activeEvent) return { active: false };
const now = Date.now();
const remaining = Math.max(0, this.activeEvent.endsAt - now);
const h = Math.floor(remaining / 3600000);
const m = Math.floor((remaining % 3600000) / 60000);
return {
active: true,
event: {
...this.activeEvent,
remainingMs: remaining,
etaLabel: h > 0 ? `${h}h ${m}m remaining` : `${m}m remaining`,
topParticipants: [...this.participants.entries()]
.sort((a,b) => b[1]-a[1]).slice(0,10)
.map(([uid, score], i) => ({ rank: i+1, userId: uid, score })),
}
};
}
claimEventReward(playerData) {
const score = this.participants.get(playerData.userId) || 0;
if (score === 0) return { success: false, error: 'You have not participated in this event.' };
const event = this.activeEvent || {};
const pool = event.rewardPool || {};
if (pool.credits) playerData.stats.credits = (playerData.stats.credits||0) + pool.credits;
if (pool.xp) playerData.addExperience?.(pool.xp);
return { success: true, rewards: pool };
}
}
module.exports = GalaxyEventSystem;