360 lines
11 KiB
JavaScript
360 lines
11 KiB
JavaScript
/**
|
||
* CENTRAL POPUP SYSTEM
|
||
* Displays important messages, quests, and dialogs in center of screen
|
||
* Always appears in front of player for easy reading
|
||
*/
|
||
class CentralPopupSystem {
|
||
constructor(scene) {
|
||
this.scene = scene;
|
||
this.enabled = true;
|
||
|
||
// Current popup
|
||
this.currentPopup = null;
|
||
this.popupQueue = [];
|
||
this.isShowing = false;
|
||
|
||
// Settings
|
||
this.settings = {
|
||
enabled: true,
|
||
autoClose: true,
|
||
autoCloseDelay: 5000, // 5 seconds
|
||
pauseGameOnPopup: true,
|
||
soundOnPopup: true
|
||
};
|
||
|
||
this.loadSettings();
|
||
console.log('✅ Central Popup System initialized');
|
||
}
|
||
|
||
/**
|
||
* Show popup in center of screen
|
||
*/
|
||
showPopup(config) {
|
||
const popup = {
|
||
title: config.title || 'Notification',
|
||
message: config.message || '',
|
||
type: config.type || 'info', // info, quest, warning, success, story
|
||
icon: config.icon || '📋',
|
||
buttons: config.buttons || [{ text: 'OK', action: 'close' }],
|
||
image: config.image || null,
|
||
autoClose: config.autoClose !== undefined ? config.autoClose : this.settings.autoClose,
|
||
onClose: config.onClose || null,
|
||
priority: config.priority || 'normal' // low, normal, high, critical
|
||
};
|
||
|
||
// Add to queue
|
||
this.popupQueue.push(popup);
|
||
|
||
// Show if not already showing
|
||
if (!this.isShowing) {
|
||
this.displayNextPopup();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Display next popup from queue
|
||
*/
|
||
displayNextPopup() {
|
||
if (this.popupQueue.length === 0) {
|
||
this.isShowing = false;
|
||
return;
|
||
}
|
||
|
||
this.isShowing = true;
|
||
const popup = this.popupQueue.shift();
|
||
|
||
// Get UIScene
|
||
const uiScene = this.scene.scene.get('UIScene');
|
||
if (!uiScene) return;
|
||
|
||
// Pause game if needed
|
||
if (this.settings.pauseGameOnPopup) {
|
||
this.scene.physics.pause();
|
||
}
|
||
|
||
// Create popup container
|
||
const centerX = uiScene.scale.width / 2;
|
||
const centerY = uiScene.scale.height / 2;
|
||
|
||
this.currentPopup = uiScene.add.container(centerX, centerY);
|
||
this.currentPopup.setDepth(10000); // Always on top
|
||
this.currentPopup.setScrollFactor(0);
|
||
|
||
// Popup size based on type
|
||
const width = popup.type === 'story' ? 600 : 500;
|
||
const height = popup.type === 'story' ? 400 : 300;
|
||
|
||
// Background overlay (darken screen)
|
||
const overlay = uiScene.add.rectangle(0, 0, uiScene.scale.width * 2, uiScene.scale.height * 2, 0x000000, 0.7);
|
||
overlay.setOrigin(0.5);
|
||
this.currentPopup.add(overlay);
|
||
|
||
// Main popup background
|
||
const bg = uiScene.add.graphics();
|
||
|
||
// Color based on type
|
||
let bgColor = 0x2a2a3e;
|
||
let borderColor = 0x4e4e6e;
|
||
|
||
if (popup.type === 'quest') {
|
||
bgColor = 0x3a2a1e;
|
||
borderColor = 0xFFD700;
|
||
} else if (popup.type === 'warning') {
|
||
bgColor = 0x3e2a2a;
|
||
borderColor = 0xff4444;
|
||
} else if (popup.type === 'success') {
|
||
bgColor = 0x2a3e2a;
|
||
borderColor = 0x44ff44;
|
||
} else if (popup.type === 'story') {
|
||
bgColor = 0x1a1a2e;
|
||
borderColor = 0x8888ff;
|
||
}
|
||
|
||
// Draw background with rounded corners
|
||
bg.fillStyle(bgColor, 0.95);
|
||
bg.fillRoundedRect(-width / 2, -height / 2, width, height, 16);
|
||
bg.lineStyle(4, borderColor, 1);
|
||
bg.strokeRoundedRect(-width / 2, -height / 2, width, height, 16);
|
||
this.currentPopup.add(bg);
|
||
|
||
// Icon
|
||
const iconText = uiScene.add.text(-width / 2 + 30, -height / 2 + 30, popup.icon, {
|
||
fontSize: '48px'
|
||
});
|
||
this.currentPopup.add(iconText);
|
||
|
||
// Title
|
||
const title = uiScene.add.text(0, -height / 2 + 50, popup.title, {
|
||
fontSize: '28px',
|
||
fontFamily: 'Arial',
|
||
fill: '#ffffff',
|
||
fontStyle: 'bold',
|
||
align: 'center'
|
||
}).setOrigin(0.5);
|
||
this.currentPopup.add(title);
|
||
|
||
// Separator line
|
||
const separator = uiScene.add.graphics();
|
||
separator.lineStyle(2, borderColor, 0.5);
|
||
separator.lineBetween(-width / 2 + 20, -height / 2 + 90, width / 2 - 20, -height / 2 + 90);
|
||
this.currentPopup.add(separator);
|
||
|
||
// Message
|
||
const message = uiScene.add.text(0, -height / 2 + 150, popup.message, {
|
||
fontSize: '18px',
|
||
fontFamily: 'Arial',
|
||
fill: '#dddddd',
|
||
align: 'center',
|
||
wordWrap: { width: width - 80 }
|
||
}).setOrigin(0.5, 0);
|
||
this.currentPopup.add(message);
|
||
|
||
// Image (if provided)
|
||
if (popup.image) {
|
||
const img = uiScene.add.image(0, -height / 2 + 120, popup.image);
|
||
img.setScale(0.5);
|
||
this.currentPopup.add(img);
|
||
}
|
||
|
||
// Buttons
|
||
const buttonY = height / 2 - 50;
|
||
const buttonSpacing = 150;
|
||
const buttonStartX = -(popup.buttons.length - 1) * buttonSpacing / 2;
|
||
|
||
popup.buttons.forEach((btn, index) => {
|
||
const btnX = buttonStartX + index * buttonSpacing;
|
||
|
||
// Button background
|
||
const btnBg = uiScene.add.graphics();
|
||
btnBg.fillStyle(0x4a4a6e, 1);
|
||
btnBg.fillRoundedRect(btnX - 60, buttonY - 20, 120, 40, 8);
|
||
btnBg.lineStyle(2, borderColor, 1);
|
||
btnBg.strokeRoundedRect(btnX - 60, buttonY - 20, 120, 40, 8);
|
||
btnBg.setInteractive(
|
||
new Phaser.Geom.Rectangle(btnX - 60, buttonY - 20, 120, 40),
|
||
Phaser.Geom.Rectangle.Contains
|
||
);
|
||
|
||
// Hover effect
|
||
btnBg.on('pointerover', () => {
|
||
btnBg.clear();
|
||
btnBg.fillStyle(0x6a6a8e, 1);
|
||
btnBg.fillRoundedRect(btnX - 60, buttonY - 20, 120, 40, 8);
|
||
btnBg.lineStyle(2, borderColor, 1);
|
||
btnBg.strokeRoundedRect(btnX - 60, buttonY - 20, 120, 40, 8);
|
||
});
|
||
|
||
btnBg.on('pointerout', () => {
|
||
btnBg.clear();
|
||
btnBg.fillStyle(0x4a4a6e, 1);
|
||
btnBg.fillRoundedRect(btnX - 60, buttonY - 20, 120, 40, 8);
|
||
btnBg.lineStyle(2, borderColor, 1);
|
||
btnBg.strokeRoundedRect(btnX - 60, buttonY - 20, 120, 40, 8);
|
||
});
|
||
|
||
// Click handler
|
||
btnBg.on('pointerdown', () => {
|
||
if (btn.action === 'close') {
|
||
this.closePopup(popup);
|
||
} else if (btn.callback) {
|
||
btn.callback();
|
||
this.closePopup(popup);
|
||
}
|
||
});
|
||
|
||
this.currentPopup.add(btnBg);
|
||
|
||
// Button text
|
||
const btnText = uiScene.add.text(btnX, buttonY, btn.text, {
|
||
fontSize: '18px',
|
||
fontFamily: 'Arial',
|
||
fill: '#ffffff',
|
||
fontStyle: 'bold'
|
||
}).setOrigin(0.5);
|
||
this.currentPopup.add(btnText);
|
||
});
|
||
|
||
// Auto-close timer
|
||
if (popup.autoClose && this.settings.autoClose) {
|
||
uiScene.time.delayedCall(this.settings.autoCloseDelay, () => {
|
||
this.closePopup(popup);
|
||
});
|
||
}
|
||
|
||
// Play sound
|
||
if (this.settings.soundOnPopup && this.scene.soundManager) {
|
||
this.scene.soundManager.beepPickup();
|
||
}
|
||
|
||
// Animate in
|
||
this.currentPopup.setScale(0.8);
|
||
this.currentPopup.setAlpha(0);
|
||
uiScene.tweens.add({
|
||
targets: this.currentPopup,
|
||
scale: 1,
|
||
alpha: 1,
|
||
duration: 300,
|
||
ease: 'Back.easeOut'
|
||
});
|
||
|
||
console.log(`📋 Popup shown: ${popup.title}`);
|
||
}
|
||
|
||
/**
|
||
* Close current popup
|
||
*/
|
||
closePopup(popup) {
|
||
if (!this.currentPopup) return;
|
||
|
||
const uiScene = this.scene.scene.get('UIScene');
|
||
if (!uiScene) return;
|
||
|
||
// Animate out
|
||
uiScene.tweens.add({
|
||
targets: this.currentPopup,
|
||
scale: 0.8,
|
||
alpha: 0,
|
||
duration: 200,
|
||
ease: 'Power2',
|
||
onComplete: () => {
|
||
this.currentPopup.destroy();
|
||
this.currentPopup = null;
|
||
|
||
// Resume game
|
||
if (this.settings.pauseGameOnPopup) {
|
||
this.scene.physics.resume();
|
||
}
|
||
|
||
// Call onClose callback
|
||
if (popup.onClose) {
|
||
popup.onClose();
|
||
}
|
||
|
||
// Show next popup
|
||
this.displayNextPopup();
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Show quest popup
|
||
*/
|
||
showQuest(title, description, objectives) {
|
||
this.showPopup({
|
||
title: title,
|
||
message: description + '\n\nObjectives:\n' + objectives.map((obj, i) => `${i + 1}. ${obj}`).join('\n'),
|
||
type: 'quest',
|
||
icon: '📜',
|
||
buttons: [
|
||
{ text: 'Accept', action: 'close' },
|
||
{ text: 'Decline', action: 'close' }
|
||
],
|
||
autoClose: false
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Show story popup
|
||
*/
|
||
showStory(title, text, image = null) {
|
||
this.showPopup({
|
||
title: title,
|
||
message: text,
|
||
type: 'story',
|
||
icon: '📖',
|
||
image: image,
|
||
buttons: [{ text: 'Continue', action: 'close' }],
|
||
autoClose: false
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Show notification
|
||
*/
|
||
showNotification(message, type = 'info') {
|
||
const icons = {
|
||
'info': 'ℹ️',
|
||
'success': '✅',
|
||
'warning': '⚠️',
|
||
'error': '❌'
|
||
};
|
||
|
||
this.showPopup({
|
||
title: type.charAt(0).toUpperCase() + type.slice(1),
|
||
message: message,
|
||
type: type,
|
||
icon: icons[type] || 'ℹ️',
|
||
buttons: [{ text: 'OK', action: 'close' }],
|
||
autoClose: true
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Save settings
|
||
*/
|
||
saveSettings() {
|
||
localStorage.setItem('novafarma_popup_settings', JSON.stringify(this.settings));
|
||
}
|
||
|
||
/**
|
||
* Load settings
|
||
*/
|
||
loadSettings() {
|
||
const saved = localStorage.getItem('novafarma_popup_settings');
|
||
if (saved) {
|
||
this.settings = { ...this.settings, ...JSON.parse(saved) };
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Destroy system
|
||
*/
|
||
destroy() {
|
||
if (this.currentPopup) {
|
||
this.currentPopup.destroy();
|
||
}
|
||
this.popupQueue = [];
|
||
console.log('📋 Central Popup System destroyed');
|
||
}
|
||
}
|