481 lines
14 KiB
JavaScript
481 lines
14 KiB
JavaScript
/**
|
|
* PortalRepairSystem.js
|
|
* ======================
|
|
* KRVAVA ŽETEV - Portal Repair & Construction (Phase 20)
|
|
*
|
|
* Features:
|
|
* - 18 portal locations across biomes
|
|
* - Repair mechanics with materials
|
|
* - 1-8 day construction time
|
|
* - Defend from attacks during repair
|
|
* - Lv8+ zombie builders (independent work!)
|
|
* - Portal network benefits
|
|
* - Portable Personal Portal (endgame!)
|
|
*
|
|
* @author NovaFarma Team
|
|
* @date 2025-12-23
|
|
*/
|
|
|
|
class PortalRepairSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
|
|
// Portal registry
|
|
this.portals = new Map();
|
|
|
|
// Repair progress
|
|
this.activeRepairs = new Map();
|
|
|
|
// Network status
|
|
this.networkActive = false;
|
|
this.portalsRepaired = 0;
|
|
this.totalPortals = 18;
|
|
|
|
// Personal portal (endgame unlock)
|
|
this.hasPersonalPortal = false;
|
|
|
|
console.log('🌀 PortalRepairSystem initialized');
|
|
|
|
// Register all portals
|
|
this.registerPortals();
|
|
}
|
|
|
|
/**
|
|
* Register all 18 portals
|
|
*/
|
|
registerPortals() {
|
|
const portals = [
|
|
// Tier 1 - Easy (1-2 days)
|
|
{
|
|
id: 'grassland_portal', name: 'Grassland Portal', biome: 'grassland',
|
|
materials: { stone: 100, crystal: 10 }, days: 1, difficulty: 'easy'
|
|
},
|
|
{
|
|
id: 'forest_portal', name: 'Forest Portal', biome: 'forest',
|
|
materials: { wood: 200, crystal: 15 }, days: 2, difficulty: 'easy'
|
|
},
|
|
|
|
// Tier 2 - Medium (3-4 days)
|
|
{
|
|
id: 'desert_portal', name: 'Desert Portal', biome: 'desert',
|
|
materials: { sandstone: 300, crystal: 20, gold: 10 }, days: 3, difficulty: 'medium'
|
|
},
|
|
{
|
|
id: 'swamp_portal', name: 'Swamp Portal', biome: 'swamp',
|
|
materials: { clay: 250, crystal: 25 }, days: 3, difficulty: 'medium'
|
|
},
|
|
{
|
|
id: 'beach_portal', name: 'Beach Portal', biome: 'beach',
|
|
materials: { coral: 200, crystal: 20, pearl: 5 }, days: 3, difficulty: 'medium'
|
|
},
|
|
{
|
|
id: 'mountain_portal', name: 'Mountain Portal', biome: 'mountain',
|
|
materials: { stone: 400, iron: 50, crystal: 30 }, days: 4, difficulty: 'medium'
|
|
},
|
|
|
|
// Tier 3 - Hard (5-6 days)
|
|
{
|
|
id: 'frozen_portal', name: 'Frozen Portal', biome: 'frozen',
|
|
materials: { ice: 500, crystal: 40, diamond: 5 }, days: 5, difficulty: 'hard'
|
|
},
|
|
{
|
|
id: 'volcanic_portal', name: 'Volcanic Portal', biome: 'volcanic',
|
|
materials: { obsidian: 400, crystal: 50, ruby: 10 }, days: 5, difficulty: 'hard'
|
|
},
|
|
{
|
|
id: 'wasteland_portal', name: 'Wasteland Portal', biome: 'wasteland',
|
|
materials: { scrap: 600, uranium: 20, crystal: 60 }, days: 6, difficulty: 'hard'
|
|
},
|
|
{
|
|
id: 'jungle_portal', name: 'Jungle Portal', biome: 'jungle',
|
|
materials: { vine: 300, emerald: 15, crystal: 45 }, days: 5, difficulty: 'hard'
|
|
},
|
|
|
|
// Tier 4 - Very Hard (7-8 days)
|
|
{
|
|
id: 'egypt_portal', name: 'Egypt Portal', biome: 'egypt',
|
|
materials: { sandstone: 800, gold: 100, crystal: 80 }, days: 7, difficulty: 'very_hard'
|
|
},
|
|
{
|
|
id: 'atlantis_portal', name: 'Atlantis Portal', biome: 'underwater',
|
|
materials: { orichalcum: 200, pearl: 50, crystal: 100 }, days: 8, difficulty: 'very_hard'
|
|
},
|
|
{
|
|
id: 'lochness_portal', name: 'Loch Ness Portal', biome: 'lochness',
|
|
materials: { stone: 1000, emerald: 20, crystal: 90 }, days: 7, difficulty: 'very_hard'
|
|
},
|
|
{
|
|
id: 'chernobyl_portal', name: 'Chernobyl Portal', biome: 'chernobyl',
|
|
materials: { concrete: 900, uranium: 50, crystal: 100 }, days: 8, difficulty: 'very_hard'
|
|
},
|
|
{
|
|
id: 'amazon_portal', name: 'Amazon Portal', biome: 'amazon',
|
|
materials: { wood: 1000, vine: 500, crystal: 85 }, days: 7, difficulty: 'very_hard'
|
|
},
|
|
|
|
// Tier 5 - Legendary (8 days)
|
|
{
|
|
id: 'mythical_portal', name: 'Mythical Realm Portal', biome: 'mythical',
|
|
materials: { mythril: 100, dragon_scale: 20, crystal: 150 }, days: 8, difficulty: 'legendary'
|
|
},
|
|
{
|
|
id: 'anomaly_portal', name: 'Anomalous Zone Portal', biome: 'anomaly',
|
|
materials: { artifact: 50, uranium: 100, crystal: 200 }, days: 8, difficulty: 'legendary'
|
|
},
|
|
{
|
|
id: 'void_portal', name: 'The Void Portal', biome: 'void',
|
|
materials: { void_essence: 10, cosmic_dust: 50, crystal: 250 }, days: 8, difficulty: 'legendary'
|
|
}
|
|
];
|
|
|
|
portals.forEach(portal => {
|
|
this.portals.set(portal.id, {
|
|
...portal,
|
|
isRepaired: false,
|
|
repairProgress: 0,
|
|
isUnderAttack: false,
|
|
questCompleted: false
|
|
});
|
|
});
|
|
|
|
console.log(`✅ Registered ${this.portals.size} portals`);
|
|
}
|
|
|
|
/**
|
|
* Start portal repair
|
|
*/
|
|
startRepair(portalId, zombieBuilders = []) {
|
|
const portal = this.portals.get(portalId);
|
|
if (!portal) {
|
|
console.error(`Portal ${portalId} not found!`);
|
|
return false;
|
|
}
|
|
|
|
if (portal.isRepaired) {
|
|
console.log(`${portal.name} is already repaired!`);
|
|
return false;
|
|
}
|
|
|
|
// Check if quest is completed
|
|
if (!portal.questCompleted) {
|
|
console.log(`Complete the ${portal.name} quest first!`);
|
|
return false;
|
|
}
|
|
|
|
// Check materials
|
|
if (!this.hasMaterials(portal.materials)) {
|
|
console.log(`Not enough materials for ${portal.name}!`);
|
|
return false;
|
|
}
|
|
|
|
// Consume materials
|
|
this.consumeMaterials(portal.materials);
|
|
|
|
// Calculate repair time (zombie builders reduce time)
|
|
const builderBonus = this.calculateBuilderBonus(zombieBuilders);
|
|
const repairTime = portal.days * (1 - builderBonus);
|
|
|
|
// Start repair
|
|
const repair = {
|
|
portalId: portalId,
|
|
startTime: Date.now(),
|
|
duration: repairTime * 24 * 60 * 60 * 1000, // Days to ms
|
|
builders: zombieBuilders,
|
|
defendPhase: false
|
|
};
|
|
|
|
this.activeRepairs.set(portalId, repair);
|
|
portal.repairProgress = 0;
|
|
|
|
console.log(`🌀 Started repairing ${portal.name} (${repairTime} days with ${zombieBuilders.length} workers)`);
|
|
|
|
// Start defend events
|
|
this.scheduleDefendEvents(portalId, repairTime);
|
|
|
|
this.showNotification({
|
|
title: 'Portal Repair Started!',
|
|
text: `🌀 ${portal.name} - ${repairTime.toFixed(1)} days`,
|
|
icon: '🔨'
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Calculate builder bonus
|
|
*/
|
|
calculateBuilderBonus(builders) {
|
|
if (builders.length === 0) return 0;
|
|
|
|
let bonus = 0;
|
|
builders.forEach(builder => {
|
|
// Lv8+ zombies are 50% faster
|
|
if (builder.level >= 8) {
|
|
bonus += 0.15; // 15% per Lv8+ zombie
|
|
} else {
|
|
bonus += 0.05; // 5% per lower level zombie
|
|
}
|
|
});
|
|
|
|
return Math.min(bonus, 0.6); // Max 60% reduction
|
|
}
|
|
|
|
/**
|
|
* Schedule defend events
|
|
*/
|
|
scheduleDefendEvents(portalId, repairDays) {
|
|
const portal = this.portals.get(portalId);
|
|
|
|
// Attack waves based on difficulty
|
|
const attackCount = {
|
|
easy: 1,
|
|
medium: 2,
|
|
hard: 3,
|
|
very_hard: 4,
|
|
legendary: 5
|
|
}[portal.difficulty] || 2;
|
|
|
|
// Schedule attacks at intervals
|
|
for (let i = 0; i < attackCount; i++) {
|
|
const attackTime = (repairDays / attackCount) * (i + 0.5);
|
|
|
|
setTimeout(() => {
|
|
this.triggerAttack(portalId);
|
|
}, attackTime * 24 * 60 * 60 * 1000);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger attack on portal
|
|
*/
|
|
triggerAttack(portalId) {
|
|
const portal = this.portals.get(portalId);
|
|
const repair = this.activeRepairs.get(portalId);
|
|
|
|
if (!repair) return;
|
|
|
|
portal.isUnderAttack = true;
|
|
repair.defendPhase = true;
|
|
|
|
console.log(`⚔️ ${portal.name} is under attack!`);
|
|
|
|
this.showNotification({
|
|
title: 'PORTAL UNDER ATTACK!',
|
|
text: `⚔️ Defend ${portal.name}!`,
|
|
icon: '⚠️'
|
|
});
|
|
|
|
// TODO: Spawn enemies
|
|
// Attack ends after 5 minutes or all enemies defeated
|
|
setTimeout(() => {
|
|
portal.isUnderAttack = false;
|
|
repair.defendPhase = false;
|
|
console.log(`✅ ${portal.name} defended successfully!`);
|
|
}, 5 * 60 * 1000);
|
|
}
|
|
|
|
/**
|
|
* Complete portal repair
|
|
*/
|
|
completeRepair(portalId) {
|
|
const portal = this.portals.get(portalId);
|
|
if (!portal) return;
|
|
|
|
portal.isRepaired = true;
|
|
portal.repairProgress = 100;
|
|
this.portalsRepaired++;
|
|
|
|
this.activeRepairs.delete(portalId);
|
|
|
|
console.log(`✅ ${portal.name} repaired! (${this.portalsRepaired}/${this.totalPortals})`);
|
|
|
|
// Activate portal network if this is the first portal
|
|
if (this.portalsRepaired === 1) {
|
|
this.activateNetwork();
|
|
}
|
|
|
|
// Check for personal portal unlock
|
|
if (this.portalsRepaired === this.totalPortals) {
|
|
this.unlockPersonalPortal();
|
|
}
|
|
|
|
this.showNotification({
|
|
title: 'Portal Complete!',
|
|
text: `✅ ${portal.name} is now operational!`,
|
|
icon: '🌀'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Activate portal network
|
|
*/
|
|
activateNetwork() {
|
|
this.networkActive = true;
|
|
|
|
console.log('🌐 Portal Network activated!');
|
|
|
|
this.showNotification({
|
|
title: 'PORTAL NETWORK ONLINE!',
|
|
text: '🌐 Fast travel between portals unlocked!',
|
|
icon: '✨'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Unlock personal portal
|
|
*/
|
|
unlockPersonalPortal() {
|
|
this.hasPersonalPortal = true;
|
|
|
|
console.log('👑 PERSONAL PORTAL UNLOCKED!');
|
|
|
|
this.showNotification({
|
|
title: 'PERSONAL PORTAL!',
|
|
text: '👑 Portable portal unlocked! Teleport anywhere!',
|
|
icon: '🎊'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Use portal (teleport)
|
|
*/
|
|
usePortal(fromPortalId, toPortalId) {
|
|
if (!this.networkActive) {
|
|
console.log('Portal network is not active yet!');
|
|
return false;
|
|
}
|
|
|
|
const from = this.portals.get(fromPortalId);
|
|
const to = this.portals.get(toPortalId);
|
|
|
|
if (!from || !to) {
|
|
console.error('Portal not found!');
|
|
return false;
|
|
}
|
|
|
|
if (!from.isRepaired || !to.isRepaired) {
|
|
console.log('Both portals must be repaired!');
|
|
return false;
|
|
}
|
|
|
|
console.log(`🌀 Teleporting from ${from.name} to ${to.name}!`);
|
|
|
|
// Instant teleport
|
|
// TODO: Actual player teleport
|
|
// TODO: Can bring zombies for FREE (network benefit)
|
|
|
|
this.showNotification({
|
|
title: 'Teleported!',
|
|
text: `🌀 Arrived at ${to.name}`,
|
|
icon: '✨'
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if Lv8+ zombie can work independently
|
|
*/
|
|
canWorkIndependently(zombie) {
|
|
return zombie.level >= 8;
|
|
}
|
|
|
|
/**
|
|
* Send Lv8+ zombie to repair portal alone
|
|
*/
|
|
sendIndependentBuilder(portalId, zombie) {
|
|
if (!this.canWorkIndependently(zombie)) {
|
|
console.log(`${zombie.name} must be Lv8+ to work alone!`);
|
|
return false;
|
|
}
|
|
|
|
console.log(`🤖 Sending ${zombie.name} (Lv${zombie.level}) to repair ${portalId} independently!`);
|
|
|
|
// Zombie travels, gathers materials, repairs portal autonomously!
|
|
this.startRepair(portalId, [zombie]);
|
|
|
|
this.showNotification({
|
|
title: 'Independent Builder!',
|
|
text: `🤖 ${zombie.name} will repair portal alone!`,
|
|
icon: '✨'
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check materials
|
|
*/
|
|
hasMaterials(required) {
|
|
// TODO: Check actual inventory
|
|
return true; // For now
|
|
}
|
|
|
|
/**
|
|
* Consume materials
|
|
*/
|
|
consumeMaterials(materials) {
|
|
// TODO: Remove from inventory
|
|
console.log('📦 Materials consumed:', materials);
|
|
}
|
|
|
|
/**
|
|
* Get repair progress
|
|
*/
|
|
getProgress() {
|
|
return {
|
|
repaired: this.portalsRepaired,
|
|
total: this.totalPortals,
|
|
percentage: ((this.portalsRepaired / this.totalPortals) * 100).toFixed(1),
|
|
networkActive: this.networkActive,
|
|
hasPersonalPortal: this.hasPersonalPortal
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get portal info
|
|
*/
|
|
getPortalInfo(portalId) {
|
|
return this.portals.get(portalId);
|
|
}
|
|
|
|
/**
|
|
* Get all portals
|
|
*/
|
|
getAllPortals() {
|
|
return Array.from(this.portals.values());
|
|
}
|
|
|
|
/**
|
|
* Update repair progress (called from game loop)
|
|
*/
|
|
update(delta) {
|
|
this.activeRepairs.forEach((repair, portalId) => {
|
|
const elapsed = Date.now() - repair.startTime;
|
|
const progress = (elapsed / repair.duration) * 100;
|
|
|
|
const portal = this.portals.get(portalId);
|
|
if (portal) {
|
|
portal.repairProgress = Math.min(100, progress);
|
|
}
|
|
|
|
// Check completion
|
|
if (progress >= 100) {
|
|
this.completeRepair(portalId);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Helper: Show notification
|
|
*/
|
|
showNotification(notification) {
|
|
console.log(`📢 ${notification.icon} ${notification.title}: ${notification.text}`);
|
|
|
|
const ui = this.scene.scene.get('UIScene');
|
|
if (ui && ui.showNotification) {
|
|
ui.showNotification(notification);
|
|
}
|
|
}
|
|
}
|