273 lines
9.0 KiB
JavaScript
273 lines
9.0 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Server Idle System
|
|
* Manages offline progression and idle mechanics
|
|
*/
|
|
|
|
class IdleSystem {
|
|
constructor() {
|
|
// Idle settings
|
|
this.maxOfflineTime = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
|
|
this.playerLastActive = new Map(); // userId -> last active timestamp
|
|
this.playerProductionRates = new Map(); // userId -> production rates
|
|
|
|
// Default production rates
|
|
this.defaultProductionRates = {
|
|
credits: 10, // credits per second (increased for better gameplay)
|
|
experience: 1, // experience per second (increased for better progression)
|
|
energy: 0.5 // energy regeneration per second
|
|
};
|
|
|
|
// Idle rewards
|
|
this.offlineRewards = {
|
|
credits: 0,
|
|
experience: 0,
|
|
energy: 0,
|
|
items: []
|
|
};
|
|
|
|
// Idle bonuses
|
|
this.bonuses = {
|
|
premium: 1.0,
|
|
guild: 1.0,
|
|
research: 1.0
|
|
};
|
|
|
|
// Idle achievements
|
|
this.achievements = {
|
|
totalOfflineTime: 0,
|
|
maxOfflineSession: 0,
|
|
totalIdleCredits: 0,
|
|
totalIdleExperience: 0
|
|
};
|
|
}
|
|
|
|
initializePlayerData(userId) {
|
|
if (!this.playerLastActive.has(userId)) {
|
|
this.playerLastActive.set(userId, Date.now());
|
|
this.playerProductionRates.set(userId, { ...this.defaultProductionRates });
|
|
this.playerAchievements.set(userId, {
|
|
totalOfflineTime: 0,
|
|
maxOfflineSession: 0,
|
|
totalIdleCredits: 0,
|
|
totalIdleExperience: 0
|
|
});
|
|
}
|
|
}
|
|
|
|
updateLastActive(userId) {
|
|
this.playerLastActive.set(userId, Date.now());
|
|
}
|
|
|
|
updateProductionRates(userId, rates) {
|
|
this.playerProductionRates.set(userId, {
|
|
...this.defaultProductionRates,
|
|
...rates
|
|
});
|
|
}
|
|
|
|
calculateOfflineProgress(userId) {
|
|
this.initializePlayerData(userId);
|
|
|
|
const lastActive = this.playerLastActive.get(userId);
|
|
const currentTime = Date.now();
|
|
const offlineTime = currentTime - lastActive;
|
|
|
|
// Cap offline time to maximum
|
|
const cappedOfflineTime = Math.min(offlineTime, this.maxOfflineTime);
|
|
|
|
if (cappedOfflineTime <= 0) {
|
|
return {
|
|
offlineTime: 0,
|
|
rewards: {
|
|
credits: 0,
|
|
experience: 0,
|
|
energy: 0,
|
|
items: []
|
|
}
|
|
};
|
|
}
|
|
|
|
const productionRates = this.playerProductionRates.get(userId);
|
|
const achievements = this.playerAchievements.get(userId);
|
|
|
|
// Calculate offline rewards
|
|
const offlineSeconds = Math.floor(cappedOfflineTime / 1000);
|
|
const rewards = {
|
|
credits: Math.floor(productionRates.credits * offlineSeconds),
|
|
experience: Math.floor(productionRates.experience * offlineSeconds),
|
|
energy: Math.floor(productionRates.energy * offlineSeconds),
|
|
items: []
|
|
};
|
|
|
|
// Update achievements
|
|
achievements.totalOfflineTime += cappedOfflineTime;
|
|
achievements.maxOfflineSession = Math.max(achievements.maxOfflineSession, cappedOfflineTime);
|
|
achievements.totalIdleCredits += rewards.credits;
|
|
achievements.totalIdleExperience += rewards.experience;
|
|
|
|
// Update last active time
|
|
this.playerLastActive.set(userId, currentTime);
|
|
|
|
return {
|
|
offlineTime: cappedOfflineTime,
|
|
offlineSeconds,
|
|
rewards,
|
|
productionRates
|
|
};
|
|
}
|
|
|
|
applyIdleRewards(userId, playerData) {
|
|
const progress = this.calculateOfflineProgress(userId);
|
|
|
|
if (progress.offlineTime > 0) {
|
|
// Apply rewards to player data
|
|
if (playerData.stats) {
|
|
playerData.stats.credits = (playerData.stats.credits || 0) + progress.rewards.credits;
|
|
playerData.stats.experience = (playerData.stats.experience || 0) + progress.rewards.experience;
|
|
}
|
|
|
|
if (playerData.resources) {
|
|
playerData.resources.energy = (playerData.resources.energy || 0) + progress.rewards.energy;
|
|
}
|
|
|
|
// Add items if any
|
|
if (progress.rewards.items && progress.rewards.items.length > 0) {
|
|
if (!playerData.inventory) {
|
|
playerData.inventory = [];
|
|
}
|
|
playerData.inventory.push(...progress.rewards.items);
|
|
}
|
|
}
|
|
|
|
return progress;
|
|
}
|
|
|
|
getProductionRates(userId) {
|
|
this.initializePlayerData(userId);
|
|
return this.playerProductionRates.get(userId);
|
|
}
|
|
|
|
updateBonuses(userId, bonuses) {
|
|
this.initializePlayerData(userId);
|
|
const currentRates = this.playerProductionRates.get(userId);
|
|
|
|
// Apply bonuses to production rates
|
|
const bonusMultiplier =
|
|
(bonuses.premium || this.defaultBonuses.premium) *
|
|
(bonuses.guild || this.defaultBonuses.guild) *
|
|
(bonuses.research || this.defaultBonuses.research);
|
|
|
|
const updatedRates = {};
|
|
for (const [resource, baseRate] of Object.entries(this.defaultProductionRates)) {
|
|
updatedRates[resource] = Math.floor(baseRate * bonusMultiplier);
|
|
}
|
|
|
|
this.playerProductionRates.set(userId, updatedRates);
|
|
return updatedRates;
|
|
}
|
|
|
|
getAchievements(userId) {
|
|
this.initializePlayerData(userId);
|
|
return this.playerAchievements.get(userId);
|
|
}
|
|
|
|
getIdleStats(userId) {
|
|
this.initializePlayerData(userId);
|
|
const achievements = this.playerAchievements.get(userId);
|
|
const productionRates = this.playerProductionRates.get(userId);
|
|
|
|
return {
|
|
lastActive: this.playerLastActive.get(userId),
|
|
productionRates,
|
|
achievements,
|
|
maxOfflineTime: this.maxOfflineTime,
|
|
currentOfflineTime: Date.now() - this.playerLastActive.get(userId)
|
|
};
|
|
}
|
|
|
|
// Calculate idle income for a specific time period
|
|
calculateIncomeForTime(userId, timeInSeconds) {
|
|
this.initializePlayerData(userId);
|
|
const productionRates = this.playerProductionRates.get(userId);
|
|
|
|
return {
|
|
credits: Math.floor(productionRates.credits * timeInSeconds),
|
|
experience: Math.floor(productionRates.experience * timeInSeconds),
|
|
energy: Math.floor(productionRates.energy * timeInSeconds)
|
|
};
|
|
}
|
|
|
|
// Get time until next milestone
|
|
getTimeUntilMilestone(userId, targetCredits = 10000) {
|
|
this.initializePlayerData(userId);
|
|
const productionRates = this.playerProductionRates.get(userId);
|
|
const currentOfflineTime = Date.now() - this.playerLastActive.get(userId);
|
|
|
|
if (productionRates.credits <= 0) {
|
|
return { seconds: Infinity, hours: Infinity };
|
|
}
|
|
|
|
const creditsPerSecond = productionRates.credits;
|
|
const secondsNeeded = Math.ceil(targetCredits / creditsPerSecond);
|
|
|
|
return {
|
|
seconds: secondsNeeded,
|
|
minutes: Math.ceil(secondsNeeded / 60),
|
|
hours: Math.ceil(secondsNeeded / 3600)
|
|
};
|
|
}
|
|
|
|
// Process idle rewards for multiple users (batch processing)
|
|
processBatchIdleRewards(userIds) {
|
|
const results = new Map();
|
|
|
|
for (const userId of userIds) {
|
|
try {
|
|
const progress = this.calculateOfflineProgress(userId);
|
|
results.set(userId, {
|
|
success: true,
|
|
progress
|
|
});
|
|
} catch (error) {
|
|
results.set(userId, {
|
|
success: false,
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
// Reset idle data for a user
|
|
resetPlayerData(userId) {
|
|
this.playerLastActive.delete(userId);
|
|
this.playerProductionRates.delete(userId);
|
|
this.playerAchievements.delete(userId);
|
|
}
|
|
|
|
// Get global idle statistics
|
|
getGlobalStats() {
|
|
const totalPlayers = this.playerLastActive.size;
|
|
let totalOfflineTime = 0;
|
|
let totalIdleCredits = 0;
|
|
let totalIdleExperience = 0;
|
|
|
|
for (const achievements of this.playerAchievements.values()) {
|
|
totalOfflineTime += achievements.totalOfflineTime;
|
|
totalIdleCredits += achievements.totalIdleCredits;
|
|
totalIdleExperience += achievements.totalIdleExperience;
|
|
}
|
|
|
|
return {
|
|
totalPlayers,
|
|
totalOfflineTime,
|
|
totalIdleCredits,
|
|
totalIdleExperience,
|
|
averageOfflineTime: totalPlayers > 0 ? totalOfflineTime / totalPlayers : 0
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = IdleSystem;
|