561 lines
15 KiB
JavaScript
561 lines
15 KiB
JavaScript
/**
|
|
* PortalNetworkSystem.js
|
|
* ======================
|
|
* KRVAVA ŽETEV - Portal Network System (P15)
|
|
*
|
|
* Features:
|
|
* - 9 Portal zones with activation quests
|
|
* - Portal mechanics (swirl effects, nausea)
|
|
* - Town Portal Hub (fast travel)
|
|
* - 3 Secret portals
|
|
* - Portal upgrades
|
|
*
|
|
* @author NovaFarma Team
|
|
* @date 2025-12-23
|
|
*/
|
|
|
|
export default class PortalNetworkSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
|
|
// Portal registry
|
|
this.portals = new Map();
|
|
this.activePortals = new Set();
|
|
|
|
// Portal hub
|
|
this.hubUnlocked = false;
|
|
this.zlatnikiBalance = 0;
|
|
|
|
// Upgrades
|
|
this.hasStabilizer = false;
|
|
this.hasBeacon = false;
|
|
|
|
// Travel state
|
|
this.isInTransit = false;
|
|
this.nauseaDebuff = null;
|
|
|
|
console.log('🌀 PortalNetworkSystem initialized');
|
|
|
|
// Register all portals
|
|
this.registerPortals();
|
|
}
|
|
|
|
/**
|
|
* 15.1 - Register all portal zones
|
|
*/
|
|
registerPortals() {
|
|
const portals = [
|
|
// Main Zone Portals
|
|
{
|
|
id: 'dino_valley',
|
|
name: 'Dino Valley Portal',
|
|
zone: 'Dino Valley',
|
|
location: { x: 50, y: 400 },
|
|
activationQuest: {
|
|
name: 'Jurassic Discovery',
|
|
objective: 'Find 3 Dino Eggs',
|
|
items: ['dino_egg'],
|
|
required: 3
|
|
},
|
|
icon: '🦕'
|
|
},
|
|
{
|
|
id: 'mythical',
|
|
name: 'Mythical Realm Portal',
|
|
zone: 'Mythical Realm',
|
|
location: { x: 400, y: 50 },
|
|
activationQuest: {
|
|
name: 'Dragon Slayer',
|
|
objective: 'Slay 5 Dragons',
|
|
enemies: ['dragon'],
|
|
required: 5
|
|
},
|
|
icon: '🐉'
|
|
},
|
|
{
|
|
id: 'endless_forest',
|
|
name: 'Endless Forest Portal',
|
|
zone: 'Endless Forest',
|
|
location: { x: 350, y: 200 },
|
|
activationQuest: {
|
|
name: 'Bigfoot Hunt',
|
|
objective: 'Find Bigfoot',
|
|
npc: 'bigfoot',
|
|
required: 1
|
|
},
|
|
icon: '🌲'
|
|
},
|
|
{
|
|
id: 'loch_ness',
|
|
name: 'Loch Ness Portal',
|
|
zone: 'Loch Ness',
|
|
location: { x: 100, y: 200 },
|
|
activationQuest: {
|
|
name: 'Nessie Summoning',
|
|
objective: 'Fish all lakes, summon Nessie',
|
|
actions: ['fish_all_lakes', 'summon_nessie'],
|
|
required: 2
|
|
},
|
|
icon: '🦕'
|
|
},
|
|
{
|
|
id: 'catacombs',
|
|
name: 'Catacombs Portal',
|
|
zone: 'Ancient Catacombs',
|
|
location: { x: 300, y: 300 },
|
|
activationQuest: {
|
|
name: 'Keymaster',
|
|
objective: 'Find 9 Ancient Keys',
|
|
items: ['ancient_key'],
|
|
required: 9
|
|
},
|
|
icon: '🗝️'
|
|
},
|
|
{
|
|
id: 'egypt',
|
|
name: 'Egyptian Portal',
|
|
zone: 'Egyptian Pyramids',
|
|
location: { x: 200, y: 400 },
|
|
activationQuest: {
|
|
name: 'Hieroglyph Master',
|
|
objective: 'Solve hieroglyph puzzle',
|
|
puzzle: 'hieroglyph',
|
|
required: 1
|
|
},
|
|
icon: '🔺'
|
|
},
|
|
{
|
|
id: 'amazon',
|
|
name: 'Amazon Portal',
|
|
zone: 'Amazon Jungle',
|
|
location: { x: 300, y: 450 },
|
|
activationQuest: {
|
|
name: 'Piranha Survivor',
|
|
objective: 'Survive piranha river crossing',
|
|
survival: 'piranha_river',
|
|
required: 1
|
|
},
|
|
icon: '🌴'
|
|
},
|
|
{
|
|
id: 'atlantis',
|
|
name: 'Atlantis Portal',
|
|
zone: 'Atlantis Ruins',
|
|
location: { x: 450, y: 450 },
|
|
activationQuest: {
|
|
name: 'Crystal Collector',
|
|
objective: 'Find 7 Atlantean Crystals',
|
|
items: ['atlantean_crystal'],
|
|
required: 7
|
|
},
|
|
icon: '🔱'
|
|
},
|
|
{
|
|
id: 'chernobyl',
|
|
name: 'Chernobyl Zone',
|
|
zone: 'Chernobyl Exclusion Zone',
|
|
location: { x: 150, y: 450 },
|
|
activationQuest: {
|
|
name: 'Train Access Only',
|
|
objective: 'Unlock via train system (no portal!)',
|
|
special: 'train_only',
|
|
required: 1
|
|
},
|
|
icon: '☢️',
|
|
noPortal: true
|
|
},
|
|
|
|
// 15.4 - Secret Portals
|
|
{
|
|
id: 'developer_realm',
|
|
name: 'Developer Realm',
|
|
zone: 'Developer Secret Area',
|
|
location: { x: 1, y: 1 }, // Hidden!
|
|
activationQuest: {
|
|
name: 'Easter Egg Challenge',
|
|
objective: 'Find the secret developer egg',
|
|
secret: true,
|
|
required: 1
|
|
},
|
|
icon: '👨💻',
|
|
secret: true
|
|
},
|
|
{
|
|
id: 'time_portal',
|
|
name: 'Time Portal',
|
|
zone: 'Pre-Outbreak Lab (Flashback)',
|
|
location: { x: 250, y: 250 }, // Spawn town
|
|
activationQuest: {
|
|
name: 'Ana\'s Memories',
|
|
objective: 'Complete main quest Act 2',
|
|
quest: 'act_2_complete',
|
|
required: 1
|
|
},
|
|
icon: '⏰',
|
|
secret: true
|
|
},
|
|
{
|
|
id: 'mirror_world',
|
|
name: 'Mirror World Portal',
|
|
zone: 'Reversed Reality',
|
|
location: { x: 500, y: 500 }, // Far corner
|
|
activationQuest: {
|
|
name: 'Shatter Reality',
|
|
objective: 'Break the Mirror of Truth',
|
|
item: 'mirror_of_truth',
|
|
required: 1
|
|
},
|
|
icon: '🪞',
|
|
secret: true
|
|
}
|
|
];
|
|
|
|
portals.forEach(portal => {
|
|
this.portals.set(portal.id, portal);
|
|
});
|
|
|
|
console.log(`✅ Registered ${this.portals.size} portals (${portals.filter(p => p.secret).length} secret)`);
|
|
}
|
|
|
|
/**
|
|
* 15.1 - Activate portal
|
|
*/
|
|
activatePortal(portalId) {
|
|
const portal = this.portals.get(portalId);
|
|
if (!portal) {
|
|
console.error(`Portal ${portalId} not found!`);
|
|
return false;
|
|
}
|
|
|
|
if (this.activePortals.has(portalId)) {
|
|
console.log(`Portal ${portal.name} already active!`);
|
|
return false;
|
|
}
|
|
|
|
// Check activation quest completion
|
|
// TODO: Integrate with quest system
|
|
// For now, just activate
|
|
|
|
this.activePortals.add(portalId);
|
|
|
|
console.log(`🌀 ${portal.icon} ${portal.name} ACTIVATED!`);
|
|
|
|
// Play activation animation
|
|
this.playPortalActivationAnimation(portal);
|
|
|
|
this.showNotification({
|
|
title: 'Portal Activated!',
|
|
text: `🌀 ${portal.icon} ${portal.name} is now online!`,
|
|
icon: '✨'
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 15.2 - Portal activation animation
|
|
*/
|
|
playPortalActivationAnimation(portal) {
|
|
// TODO: Create actual portal sprite/animation
|
|
console.log(`✨ Portal activation animation for ${portal.name}`);
|
|
|
|
// Screen flash
|
|
this.scene.cameras.main.flash(1000, 100, 0, 255); // Blue flash
|
|
|
|
// Camera shake
|
|
this.scene.cameras.main.shake(500, 0.01);
|
|
}
|
|
|
|
/**
|
|
* 15.2 - Travel through portal
|
|
*/
|
|
travelThroughPortal(portalId, fromHub = false) {
|
|
const portal = this.portals.get(portalId);
|
|
if (!portal) {
|
|
console.error(`Portal ${portalId} not found!`);
|
|
return false;
|
|
}
|
|
|
|
if (!this.activePortals.has(portalId) && !fromHub) {
|
|
this.showNotification({
|
|
title: 'Portal Inactive',
|
|
text: `${portal.name} must be activated first!`,
|
|
icon: '🚫'
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Check payment if using hub
|
|
if (fromHub) {
|
|
const cost = this.calculatePortalCost(portal);
|
|
if (this.zlatnikiBalance < cost) {
|
|
this.showNotification({
|
|
title: 'Insufficient Funds',
|
|
text: `Need ${cost} Zlatniki for portal travel!`,
|
|
icon: '💰'
|
|
});
|
|
return false;
|
|
}
|
|
this.zlatnikiBalance -= cost;
|
|
}
|
|
|
|
// Start transit
|
|
this.isInTransit = true;
|
|
|
|
// Swirl effect
|
|
this.playPortalSwirlEffect();
|
|
|
|
// Loading screen (2 seconds)
|
|
setTimeout(() => {
|
|
this.completePortalTravel(portal);
|
|
}, 2000);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 15.2 - Portal swirl effect
|
|
*/
|
|
playPortalSwirlEffect() {
|
|
console.log('🌀 *SWIIIIIRL*');
|
|
|
|
// Create swirl particles
|
|
// TODO: Implement actual particle effect
|
|
|
|
// Screen spin effect
|
|
this.scene.cameras.main.rotateTo(Math.PI * 4, true, 2000);
|
|
|
|
// Fade out/in
|
|
this.scene.cameras.main.fadeOut(1000);
|
|
setTimeout(() => {
|
|
this.scene.cameras.main.fadeIn(1000);
|
|
}, 1000);
|
|
}
|
|
|
|
/**
|
|
* 15.2 - Complete portal travel
|
|
*/
|
|
completePortalTravel(portal) {
|
|
// Teleport player
|
|
if (this.scene.player) {
|
|
this.scene.player.x = portal.location.x * 48;
|
|
this.scene.player.y = portal.location.y * 48;
|
|
}
|
|
|
|
// Transit zombies
|
|
this.transitZombies(portal);
|
|
|
|
// Apply nausea debuff (unless stabilizer)
|
|
if (!this.hasStabilizer) {
|
|
this.applyNauseaDebuff();
|
|
}
|
|
|
|
this.isInTransit = false;
|
|
|
|
console.log(`🌀 Arrived at ${portal.zone}!`);
|
|
|
|
this.showNotification({
|
|
title: 'Portal Travel Complete',
|
|
text: `${portal.icon} Welcome to ${portal.zone}!`,
|
|
icon: '🌀'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 15.2 - Transit zombies through portal
|
|
*/
|
|
transitZombies(portal) {
|
|
// TODO: Move all tamed zombies to portal location
|
|
console.log('🧟 Zombies followed through portal!');
|
|
}
|
|
|
|
/**
|
|
* 15.2 - Apply nausea debuff
|
|
*/
|
|
applyNauseaDebuff() {
|
|
this.nauseaDebuff = {
|
|
duration: 5000, // 5 seconds
|
|
startTime: Date.now()
|
|
};
|
|
|
|
// Visual effect (screen wobble)
|
|
// TODO: Implement screen wobble
|
|
|
|
console.log('🤢 Nausea debuff applied (5s)');
|
|
|
|
this.showNotification({
|
|
title: 'Portal Sickness',
|
|
text: '🤢 You feel dizzy from portal travel...',
|
|
icon: '😵'
|
|
});
|
|
|
|
// Remove after duration
|
|
setTimeout(() => {
|
|
this.nauseaDebuff = null;
|
|
console.log('✅ Nausea debuff removed');
|
|
}, 5000);
|
|
}
|
|
|
|
/**
|
|
* 15.3 - Open town portal hub
|
|
*/
|
|
openPortalHub() {
|
|
if (!this.hubUnlocked) {
|
|
this.showNotification({
|
|
title: 'Hub Locked',
|
|
text: 'Build the Portal Hub building first! (After Town Hall)',
|
|
icon: '🏛️'
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Show portal hub UI
|
|
this.showPortalHubUI();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 15.3 - Portal hub UI
|
|
*/
|
|
showPortalHubUI() {
|
|
console.log('🌀 Portal Hub UI opened');
|
|
|
|
// TODO: Create actual UI
|
|
// For now, list active portals
|
|
console.log('Available Portals:');
|
|
this.activePortals.forEach(portalId => {
|
|
const portal = this.portals.get(portalId);
|
|
if (portal && !portal.noPortal) {
|
|
const cost = this.calculatePortalCost(portal);
|
|
console.log(`- ${portal.icon} ${portal.name} (${cost}Ž)`);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 15.3 - Calculate portal cost
|
|
*/
|
|
calculatePortalCost(portal) {
|
|
let cost = 5; // Base: 5 Zlatniki
|
|
|
|
// Add zombie transit cost (1Ž per zombie)
|
|
const zombieCount = this.scene.zombieSystem?.workers?.length || 0;
|
|
cost += zombieCount;
|
|
|
|
// Add animal transit cost (2Ž per animal)
|
|
const animalCount = this.scene.animalBreeding?.animals?.size || 0;
|
|
cost += animalCount * 2;
|
|
|
|
return cost;
|
|
}
|
|
|
|
/**
|
|
* 15.5 - Install portal stabilizer
|
|
*/
|
|
installStabilizer() {
|
|
// TODO: Check if player has stabilizer item
|
|
this.hasStabilizer = true;
|
|
|
|
console.log('✅ Portal Stabilizer installed!');
|
|
|
|
this.showNotification({
|
|
title: 'Stabilizer Installed',
|
|
text: '✨ Portal travel no longer causes nausea!',
|
|
icon: '🔧'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 15.5 - Install portal beacon
|
|
*/
|
|
installBeacon() {
|
|
// TODO: Check if player has beacon item
|
|
this.hasBeacon = true;
|
|
|
|
console.log('✅ Portal Beacon installed!');
|
|
|
|
this.showNotification({
|
|
title: 'Beacon Installed',
|
|
text: '💡 Portals now glow brighter and are easier to find!',
|
|
icon: '🔦'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Unlock portal hub
|
|
*/
|
|
unlockHub() {
|
|
this.hubUnlocked = true;
|
|
|
|
this.showNotification({
|
|
title: 'Portal Hub Unlocked!',
|
|
text: '🏛️ Fast travel to all active portals!',
|
|
icon: '🌀'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get portal info
|
|
*/
|
|
getPortalInfo(portalId) {
|
|
return this.portals.get(portalId);
|
|
}
|
|
|
|
/**
|
|
* Get all active portals
|
|
*/
|
|
getActivePortals() {
|
|
return Array.from(this.activePortals).map(id => this.portals.get(id));
|
|
}
|
|
|
|
/**
|
|
* Get all portals
|
|
*/
|
|
getAllPortals() {
|
|
return Array.from(this.portals.values());
|
|
}
|
|
|
|
/**
|
|
* Check if portal active
|
|
*/
|
|
isPortalActive(portalId) {
|
|
return this.activePortals.has(portalId);
|
|
}
|
|
|
|
/**
|
|
* Get secret portals
|
|
*/
|
|
getSecretPortals() {
|
|
return this.getAllPortals().filter(p => p.secret);
|
|
}
|
|
|
|
/**
|
|
* Add zlatniki
|
|
*/
|
|
addZlatniki(amount) {
|
|
this.zlatnikiBalance += amount;
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update system
|
|
*/
|
|
update(delta) {
|
|
// Update nausea debuff visual effects if active
|
|
if (this.nauseaDebuff) {
|
|
// TODO: Apply screen wobble effect
|
|
}
|
|
}
|
|
}
|