358 lines
12 KiB
JavaScript
358 lines
12 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Idle System
|
|
* Manages offline progression and idle mechanics
|
|
*/
|
|
|
|
class IdleSystem {
|
|
constructor(gameEngine) {
|
|
this.game = gameEngine;
|
|
|
|
// Idle settings
|
|
this.maxOfflineTime = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
|
|
this.lastActiveTime = Date.now();
|
|
this.accumulatedTime = 0; // Track time for resource generation
|
|
|
|
// Idle production rates
|
|
this.productionRates = {
|
|
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
|
|
};
|
|
|
|
// Offline 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
|
|
};
|
|
}
|
|
|
|
async initialize() {
|
|
// Calculate offline progress if returning
|
|
this.calculateOfflineProgress();
|
|
}
|
|
|
|
calculateOfflineProgress(offlineTime = null) {
|
|
const currentTime = Date.now();
|
|
const actualOfflineTime = offlineTime || (currentTime - this.lastActiveTime);
|
|
|
|
// Cap offline time to maximum
|
|
const cappedOfflineTime = Math.min(actualOfflineTime, this.maxOfflineTime);
|
|
|
|
if (cappedOfflineTime < 60000) { // Less than 1 minute
|
|
return;
|
|
}
|
|
|
|
// Calculate production
|
|
const totalBonus = this.getTotalBonus();
|
|
const productionSeconds = cappedOfflineTime / 1000;
|
|
|
|
this.offlineRewards = {
|
|
credits: Math.floor(this.productionRates.credits * productionSeconds * totalBonus),
|
|
experience: Math.floor(this.productionRates.experience * productionSeconds * totalBonus),
|
|
energy: Math.min(
|
|
this.game.systems.player.attributes.maxEnergy,
|
|
Math.floor(this.productionRates.energy * productionSeconds)
|
|
),
|
|
items: this.generateIdleItems(cappedOfflineTime)
|
|
};
|
|
|
|
// Update achievements
|
|
this.achievements.totalOfflineTime += cappedOfflineTime;
|
|
this.achievements.maxOfflineSession = Math.max(this.achievements.maxOfflineSession, cappedOfflineTime);
|
|
this.achievements.totalIdleCredits += this.offlineRewards.credits;
|
|
this.achievements.totalIdleExperience += this.offlineRewards.experience;
|
|
|
|
// Show offline rewards notification
|
|
this.showOfflineRewards(cappedOfflineTime);
|
|
}
|
|
|
|
getTotalBonus() {
|
|
return this.bonuses.premium * this.bonuses.guild * this.bonuses.research;
|
|
}
|
|
|
|
generateIdleItems(offlineTime) {
|
|
const items = [];
|
|
const hours = offlineTime / (1000 * 60 * 60);
|
|
|
|
// Chance to find items based on offline time
|
|
const itemChance = Math.min(0.5, hours * 0.05);
|
|
|
|
if (Math.random() < itemChance) {
|
|
const itemCount = Math.floor(hours / 2) + 1;
|
|
|
|
for (let i = 0; i < itemCount; i++) {
|
|
const rarity = this.getRandomItemRarity();
|
|
const item = this.game.systems.inventory.generateItem('consumable', rarity);
|
|
items.push(item);
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
getRandomItemRarity() {
|
|
const roll = Math.random();
|
|
if (roll < 0.05) return 'legendary';
|
|
if (roll < 0.15) return 'epic';
|
|
if (roll < 0.35) return 'rare';
|
|
if (roll < 0.65) return 'uncommon';
|
|
return 'common';
|
|
}
|
|
|
|
showOfflineRewards(offlineTime) {
|
|
const timeString = this.game.formatTime(offlineTime);
|
|
|
|
this.game.showNotification(
|
|
`Welcome back! You were offline for ${timeString}`,
|
|
'info',
|
|
5000
|
|
);
|
|
|
|
// Format rewards message
|
|
let rewardsMessage = 'Offline Rewards:\n';
|
|
if (this.offlineRewards.credits > 0) {
|
|
rewardsMessage += `+${this.game.formatNumber(this.offlineRewards.credits)} credits\n`;
|
|
}
|
|
if (this.offlineRewards.experience > 0) {
|
|
rewardsMessage += `+${this.game.formatNumber(this.offlineRewards.experience)} XP\n`;
|
|
}
|
|
if (this.offlineRewards.energy > 0) {
|
|
rewardsMessage += `+${this.game.formatNumber(this.offlineRewards.energy)} energy\n`;
|
|
}
|
|
if (this.offlineRewards.items.length > 0) {
|
|
rewardsMessage += `+${this.offlineRewards.items.length} items\n`;
|
|
}
|
|
|
|
this.game.showNotification(rewardsMessage, 'success', 5000);
|
|
}
|
|
|
|
claimOfflineRewards() {
|
|
if (this.offlineRewards.credits === 0 &&
|
|
this.offlineRewards.experience === 0 &&
|
|
this.offlineRewards.items.length === 0) {
|
|
this.game.showNotification('No offline rewards to claim', 'info', 3000);
|
|
return;
|
|
}
|
|
|
|
// Give rewards
|
|
if (this.offlineRewards.credits > 0) {
|
|
this.game.systems.economy.addCredits(this.offlineRewards.credits, 'offline');
|
|
}
|
|
|
|
if (this.offlineRewards.experience > 0) {
|
|
this.game.systems.player.addExperience(this.offlineRewards.experience);
|
|
}
|
|
|
|
if (this.offlineRewards.energy > 0) {
|
|
this.game.systems.player.restoreEnergy(this.offlineRewards.energy);
|
|
}
|
|
|
|
// Add items to inventory
|
|
if (this.offlineRewards.items.length > 0) {
|
|
const inventory = this.game.systems.inventory;
|
|
this.offlineRewards.items.forEach(item => {
|
|
inventory.addItem(item);
|
|
});
|
|
}
|
|
|
|
// Reset offline rewards
|
|
this.offlineRewards = {
|
|
credits: 0,
|
|
experience: 0,
|
|
energy: 0,
|
|
items: []
|
|
};
|
|
|
|
this.game.showNotification('Offline rewards claimed!', 'success', 3000);
|
|
}
|
|
|
|
// Active idle production
|
|
update(deltaTime) {
|
|
if (this.game.state.paused) return;
|
|
|
|
// Use real computer time delta
|
|
const seconds = deltaTime / 1000;
|
|
const totalBonus = this.getTotalBonus();
|
|
|
|
// Only add resources once per second, not every frame
|
|
this.accumulatedTime += seconds;
|
|
|
|
if (this.accumulatedTime >= 1.0) {
|
|
// Calculate active production
|
|
const activeCredits = Math.floor(this.productionRates.credits * totalBonus);
|
|
const activeExperience = Math.floor(this.productionRates.experience * totalBonus);
|
|
// const activeEnergy = this.productionRates.energy * totalBonus * 0.1; // Energy is handled differently
|
|
|
|
// Add resources
|
|
if (activeCredits > 0) {
|
|
this.game.systems.economy.addCredits(activeCredits, 'idle');
|
|
}
|
|
if (activeExperience > 0) {
|
|
this.game.systems.player.addExperience(activeExperience);
|
|
}
|
|
|
|
// Regenerate energy
|
|
this.game.systems.player.restoreEnergy(this.productionRates.energy);
|
|
|
|
// Reset accumulated time, keeping any remainder
|
|
this.accumulatedTime -= 1.0;
|
|
|
|
// Debugging: Log when resources are added
|
|
// console.debug(`[IDLE] Added ${activeCredits} credits and ${activeExperience} XP. Accumulated time: ${this.accumulatedTime.toFixed(2)}s`);
|
|
}
|
|
|
|
// Update last active time for offline calculations
|
|
this.lastActiveTime = Date.now();
|
|
}
|
|
|
|
// Upgrade production rates
|
|
upgradeProduction(type) {
|
|
const upgradeCosts = {
|
|
credits: 100,
|
|
experience: 150,
|
|
energy: 80
|
|
};
|
|
|
|
const cost = upgradeCosts[type];
|
|
if (!cost || this.game.systems.economy.credits < cost) {
|
|
return false;
|
|
}
|
|
|
|
this.game.systems.economy.removeCredits(cost);
|
|
|
|
switch (type) {
|
|
case 'credits':
|
|
this.productionRates.credits += 2;
|
|
break;
|
|
case 'experience':
|
|
this.productionRates.experience += 1;
|
|
break;
|
|
case 'energy':
|
|
this.productionRates.energy += 0.2;
|
|
break;
|
|
}
|
|
|
|
this.game.showNotification(`Production upgraded: ${type}!`, 'success', 3000);
|
|
return true;
|
|
}
|
|
|
|
// Bonus management
|
|
setBonus(type, value) {
|
|
if (this.bonuses[type] !== undefined) {
|
|
this.bonuses[type] = value;
|
|
this.game.showNotification(`${type} bonus set to ${value}x`, 'info', 3000);
|
|
}
|
|
}
|
|
|
|
// Achievement checking
|
|
checkAchievements() {
|
|
const achievements = [
|
|
{
|
|
id: 'idle_warrior',
|
|
name: 'Idle Warrior',
|
|
description: 'Earn 1,000,000 credits from idle',
|
|
condition: () => this.achievements.totalIdleCredits >= 1000000,
|
|
reward: { gems: 50, experience: 1000 }
|
|
},
|
|
{
|
|
id: 'time_master',
|
|
name: 'Time Master',
|
|
description: 'Accumulate 24 hours of offline time',
|
|
condition: () => this.achievements.totalOfflineTime >= 24 * 60 * 60 * 1000,
|
|
reward: { gems: 25, experience: 500 }
|
|
},
|
|
{
|
|
id: 'marathon_idle',
|
|
name: 'Marathon Idle',
|
|
description: 'Be offline for more than 12 hours at once',
|
|
condition: () => this.achievements.maxOfflineSession >= 12 * 60 * 60 * 1000,
|
|
reward: { gems: 100, experience: 2000 }
|
|
}
|
|
];
|
|
|
|
achievements.forEach(achievement => {
|
|
if (achievement.condition()) {
|
|
this.unlockAchievement(achievement);
|
|
}
|
|
});
|
|
}
|
|
|
|
unlockAchievement(achievement) {
|
|
this.game.showNotification(`Achievement Unlocked: ${achievement.name}!`, 'success', 5000);
|
|
this.game.showNotification(achievement.description, 'info', 3000);
|
|
|
|
// Give rewards
|
|
if (achievement.reward.gems) {
|
|
this.game.systems.economy.addGems(achievement.reward.gems, 'achievement');
|
|
}
|
|
|
|
if (achievement.reward.experience) {
|
|
this.game.systems.player.addExperience(achievement.reward.experience);
|
|
}
|
|
}
|
|
|
|
// UI updates
|
|
updateUI() {
|
|
const offlineTimeElement = document.getElementById('offlineTime');
|
|
const offlineResourcesElement = document.getElementById('offlineResources');
|
|
const claimOfflineBtn = document.getElementById('claimOfflineBtn');
|
|
|
|
if (offlineTimeElement) {
|
|
const totalRewards = this.offlineRewards.credits +
|
|
this.offlineRewards.experience +
|
|
(this.offlineRewards.items.length * 100);
|
|
offlineTimeElement.textContent = totalRewards > 0 ? 'Available' : 'None';
|
|
}
|
|
|
|
if (offlineResourcesElement) {
|
|
const totalRewards = this.offlineRewards.credits +
|
|
this.offlineRewards.experience +
|
|
(this.offlineRewards.items.length * 100);
|
|
offlineResourcesElement.textContent = this.game.formatNumber(totalRewards);
|
|
}
|
|
|
|
if (claimOfflineBtn) {
|
|
const hasRewards = this.offlineRewards.credits > 0 ||
|
|
this.offlineRewards.experience > 0 ||
|
|
this.offlineRewards.items.length > 0;
|
|
claimOfflineBtn.disabled = !hasRewards;
|
|
}
|
|
}
|
|
|
|
// Save/Load
|
|
save() {
|
|
return {
|
|
lastActiveTime: this.lastActiveTime,
|
|
productionRates: this.productionRates,
|
|
bonuses: this.bonuses,
|
|
achievements: this.achievements,
|
|
offlineRewards: this.offlineRewards
|
|
};
|
|
}
|
|
|
|
load(data) {
|
|
if (data.lastActiveTime) this.lastActiveTime = data.lastActiveTime;
|
|
if (data.productionRates) this.productionRates = { ...this.productionRates, ...data.productionRates };
|
|
if (data.bonuses) this.bonuses = { ...this.bonuses, ...data.bonuses };
|
|
if (data.achievements) this.achievements = { ...this.achievements, ...data.achievements };
|
|
if (data.offlineRewards) this.offlineRewards = data.offlineRewards;
|
|
}
|
|
}
|