popravki
This commit is contained in:
@@ -57,6 +57,9 @@ Pripravi se... NOČ PRIHAJA.`;
|
||||
fontSize: '16px', fill: '#666'
|
||||
}).setOrigin(1);
|
||||
|
||||
// LANGUAGE SELECTOR
|
||||
this.createLanguageSelector(width, height);
|
||||
|
||||
// Input to skip
|
||||
this.input.keyboard.on('keydown-SPACE', () => {
|
||||
this.scene.start('GameScene');
|
||||
@@ -66,4 +69,80 @@ Pripravi se... NOČ PRIHAJA.`;
|
||||
this.scene.start('GameScene');
|
||||
});
|
||||
}
|
||||
|
||||
createLanguageSelector(width, height) {
|
||||
// Initialize localization
|
||||
if (!window.i18n) {
|
||||
window.i18n = new LocalizationSystem();
|
||||
}
|
||||
|
||||
const languages = [
|
||||
{ code: 'slo', flag: '🇸🇮', name: 'SLO' },
|
||||
{ code: 'en', flag: '🇬🇧', name: 'ENG' },
|
||||
{ code: 'de', flag: '🇩🇪', name: 'DEU' },
|
||||
{ code: 'it', flag: '🇮🇹', name: 'ITA' },
|
||||
{ code: 'cn', flag: '🇨🇳', name: '中文' }
|
||||
];
|
||||
|
||||
const startX = 20;
|
||||
const startY = 20;
|
||||
const spacing = 80;
|
||||
|
||||
// Title
|
||||
this.add.text(startX, startY, '🌍 Language:', {
|
||||
fontSize: '18px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Courier New'
|
||||
});
|
||||
|
||||
// Language buttons
|
||||
languages.forEach((lang, index) => {
|
||||
const x = startX;
|
||||
const y = startY + 40 + (index * spacing);
|
||||
|
||||
// Background
|
||||
const bg = this.add.rectangle(x, y, 200, 60, 0x333333, 0.8);
|
||||
bg.setOrigin(0, 0);
|
||||
|
||||
// Flag + Name
|
||||
const text = this.add.text(x + 100, y + 30, `${lang.flag} ${lang.name}`, {
|
||||
fontSize: '24px',
|
||||
fill: window.i18n.getCurrentLanguage() === lang.code ? '#00ff41' : '#ffffff',
|
||||
fontFamily: 'Courier New'
|
||||
}).setOrigin(0.5);
|
||||
|
||||
// Make interactive
|
||||
bg.setInteractive({ useHandCursor: true });
|
||||
bg.on('pointerover', () => {
|
||||
bg.setFillStyle(0x555555, 0.9);
|
||||
text.setScale(1.1);
|
||||
});
|
||||
bg.on('pointerout', () => {
|
||||
bg.setFillStyle(0x333333, 0.8);
|
||||
text.setScale(1.0);
|
||||
});
|
||||
bg.on('pointerdown', () => {
|
||||
// Set language
|
||||
window.i18n.setLanguage(lang.code);
|
||||
|
||||
// Update all text colors
|
||||
languages.forEach((l, i) => {
|
||||
const langText = this.children.list.find(child =>
|
||||
child.text && child.text.includes(l.flag)
|
||||
);
|
||||
if (langText) {
|
||||
langText.setColor(window.i18n.getCurrentLanguage() === l.code ? '#00ff41' : '#ffffff');
|
||||
}
|
||||
});
|
||||
|
||||
// Visual feedback
|
||||
this.tweens.add({
|
||||
targets: bg,
|
||||
alpha: 0.5,
|
||||
yoyo: true,
|
||||
duration: 100
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1541,4 +1541,177 @@ class UIScene extends Phaser.Scene {
|
||||
onComplete: () => text.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
createSettingsButton() {
|
||||
// Settings gear icon (top-right corner)
|
||||
const settingsBtn = this.add.text(this.cameras.main.width - 60, 20, '⚙️', {
|
||||
fontSize: '32px',
|
||||
color: '#ffffff'
|
||||
});
|
||||
settingsBtn.setScrollFactor(0);
|
||||
settingsBtn.setDepth(9999);
|
||||
settingsBtn.setInteractive({ useHandCursor: true });
|
||||
|
||||
settingsBtn.on('pointerover', () => {
|
||||
settingsBtn.setScale(1.2);
|
||||
});
|
||||
settingsBtn.on('pointerout', () => {
|
||||
settingsBtn.setScale(1.0);
|
||||
});
|
||||
settingsBtn.on('pointerdown', () => {
|
||||
this.toggleSettingsMenu();
|
||||
});
|
||||
}
|
||||
|
||||
toggleSettingsMenu() {
|
||||
if (this.settingsContainer) {
|
||||
// Close existing menu
|
||||
this.settingsContainer.destroy();
|
||||
this.settingsContainer = null;
|
||||
// Resume game
|
||||
if (this.gameScene) {
|
||||
this.gameScene.physics.resume();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Pause game
|
||||
if (this.gameScene) {
|
||||
this.gameScene.physics.pause();
|
||||
}
|
||||
|
||||
// Create settings menu
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
this.settingsContainer = this.add.container(0, 0);
|
||||
this.settingsContainer.setScrollFactor(0);
|
||||
this.settingsContainer.setDepth(10000);
|
||||
|
||||
// Semi-transparent background
|
||||
const bg = this.add.rectangle(0, 0, width, height, 0x000000, 0.8);
|
||||
bg.setOrigin(0);
|
||||
this.settingsContainer.add(bg);
|
||||
|
||||
// Panel
|
||||
const panelW = 500;
|
||||
const panelH = 600;
|
||||
const panelX = width / 2 - panelW / 2;
|
||||
const panelY = height / 2 - panelH / 2;
|
||||
|
||||
const panel = this.add.rectangle(panelX, panelY, panelW, panelH, 0x1a1a2e, 1);
|
||||
panel.setOrigin(0);
|
||||
panel.setStrokeStyle(4, 0x00ff41);
|
||||
this.settingsContainer.add(panel);
|
||||
|
||||
// Title
|
||||
const title = this.add.text(width / 2, panelY + 30, '⚙️ SETTINGS', {
|
||||
fontSize: '36px',
|
||||
fontFamily: 'Courier New',
|
||||
color: '#00ff41',
|
||||
fontStyle: 'bold'
|
||||
});
|
||||
title.setOrigin(0.5, 0);
|
||||
this.settingsContainer.add(title);
|
||||
|
||||
// Language Section
|
||||
this.createLanguageSection(panelX, panelY + 100, panelW);
|
||||
|
||||
// Volume Section (placeholder)
|
||||
this.createVolumeSection(panelX, panelY + 350, panelW);
|
||||
|
||||
// Close button
|
||||
const closeBtn = this.add.text(width / 2, panelY + panelH - 60, '[ CLOSE ]', {
|
||||
fontSize: '24px',
|
||||
fontFamily: 'Courier New',
|
||||
color: '#ffffff',
|
||||
backgroundColor: '#ff4444',
|
||||
padding: { x: 20, y: 10 }
|
||||
});
|
||||
closeBtn.setOrigin(0.5);
|
||||
closeBtn.setInteractive({ useHandCursor: true });
|
||||
closeBtn.on('pointerover', () => closeBtn.setScale(1.1));
|
||||
closeBtn.on('pointerout', () => closeBtn.setScale(1.0));
|
||||
closeBtn.on('pointerdown', () => this.toggleSettingsMenu());
|
||||
this.settingsContainer.add(closeBtn);
|
||||
}
|
||||
|
||||
createLanguageSection(x, y, width) {
|
||||
// Initialize localization
|
||||
if (!window.i18n) {
|
||||
window.i18n = new LocalizationSystem();
|
||||
}
|
||||
|
||||
const sectionTitle = this.add.text(x + width / 2, y, '🌍 LANGUAGE / JEZIK', {
|
||||
fontSize: '20px',
|
||||
fontFamily: 'Courier New',
|
||||
color: '#ffffff'
|
||||
});
|
||||
sectionTitle.setOrigin(0.5, 0);
|
||||
this.settingsContainer.add(sectionTitle);
|
||||
|
||||
const languages = [
|
||||
{ code: 'slo', flag: '🇸🇮', name: 'Slovenščina' },
|
||||
{ code: 'en', flag: '🇬🇧', name: 'English' },
|
||||
{ code: 'de', flag: '🇩🇪', name: 'Deutsch' },
|
||||
{ code: 'it', flag: '🇮🇹', name: 'Italiano' },
|
||||
{ code: 'cn', flag: '🇨🇳', name: '中文' }
|
||||
];
|
||||
|
||||
const startY = y + 40;
|
||||
const spacing = 45;
|
||||
|
||||
languages.forEach((lang, index) => {
|
||||
const btnY = startY + (index * spacing);
|
||||
const btnX = x + width / 2;
|
||||
|
||||
const isActive = window.i18n.getCurrentLanguage() === lang.code;
|
||||
|
||||
const btn = this.add.text(btnX, btnY, `${lang.flag} ${lang.name}`, {
|
||||
fontSize: '18px',
|
||||
fontFamily: 'Courier New',
|
||||
color: isActive ? '#00ff41' : '#ffffff',
|
||||
backgroundColor: isActive ? '#333333' : '#222222',
|
||||
padding: { x: 15, y: 8 }
|
||||
});
|
||||
btn.setOrigin(0.5);
|
||||
btn.setInteractive({ useHandCursor: true });
|
||||
|
||||
btn.on('pointerover', () => {
|
||||
btn.setScale(1.05);
|
||||
if (!isActive) btn.setBackgroundColor('#444444');
|
||||
});
|
||||
btn.on('pointerout', () => {
|
||||
btn.setScale(1.0);
|
||||
if (!isActive) btn.setBackgroundColor('#222222');
|
||||
});
|
||||
btn.on('pointerdown', () => {
|
||||
window.i18n.setLanguage(lang.code);
|
||||
// Refresh settings menu to update colors
|
||||
this.toggleSettingsMenu();
|
||||
this.toggleSettingsMenu();
|
||||
});
|
||||
|
||||
this.settingsContainer.add(btn);
|
||||
});
|
||||
}
|
||||
|
||||
createVolumeSection(x, y, width) {
|
||||
const sectionTitle = this.add.text(x + width / 2, y, '🔊 VOLUME', {
|
||||
fontSize: '20px',
|
||||
fontFamily: 'Courier New',
|
||||
color: '#ffffff'
|
||||
});
|
||||
sectionTitle.setOrigin(0.5, 0);
|
||||
this.settingsContainer.add(sectionTitle);
|
||||
|
||||
// Placeholder text
|
||||
const placeholder = this.add.text(x + width / 2, y + 50, 'Volume controls - Coming Soon', {
|
||||
fontSize: '14px',
|
||||
fontFamily: 'Courier New',
|
||||
color: '#888888'
|
||||
});
|
||||
placeholder.setOrigin(0.5, 0);
|
||||
this.settingsContainer.add(placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,10 @@ class CollectionSystem {
|
||||
color: '#FFD700'
|
||||
});
|
||||
|
||||
if (this.scene.soundManager) {
|
||||
this.scene.soundManager.playSuccess(); // Reuse success sound
|
||||
if (this.scene.soundManager && typeof this.scene.soundManager.playSuccess === 'function') {
|
||||
this.scene.soundManager.playSuccess();
|
||||
} else if (this.scene.soundManager && typeof this.scene.soundManager.playHarvest === 'function') {
|
||||
this.scene.soundManager.playHarvest(); // Fallback to harvest sound
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
176
src/systems/LocalizationSystem.js
Normal file
176
src/systems/LocalizationSystem.js
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* LOCALIZATION SYSTEM
|
||||
* Multi-language support with JSON translation files
|
||||
*/
|
||||
class LocalizationSystem {
|
||||
constructor() {
|
||||
this.currentLang = 'en'; // Default language
|
||||
this.translations = {};
|
||||
this.supportedLanguages = ['slo', 'en', 'de', 'it', 'cn'];
|
||||
|
||||
// Load from localStorage
|
||||
const savedLang = localStorage.getItem('novafarma_language');
|
||||
if (savedLang && this.supportedLanguages.includes(savedLang)) {
|
||||
this.currentLang = savedLang;
|
||||
}
|
||||
|
||||
this.loadTranslations();
|
||||
}
|
||||
|
||||
loadTranslations() {
|
||||
// Embedded translations (inline for simplicity)
|
||||
this.translations = {
|
||||
'slo': {
|
||||
// UI
|
||||
'ui.inventory': 'Inventar',
|
||||
'ui.crafting': 'Izdelovanje',
|
||||
'ui.health': 'Zdravje',
|
||||
'ui.hunger': 'Lakota',
|
||||
'ui.oxygen': 'Kisik',
|
||||
'ui.day': 'Dan',
|
||||
'ui.season': 'Letni čas',
|
||||
|
||||
// Items
|
||||
'item.wood': 'Les',
|
||||
'item.stone': 'Kamen',
|
||||
'item.seeds': 'Semena',
|
||||
'item.wheat': 'Pšenica',
|
||||
'item.corn': 'Koruza',
|
||||
|
||||
// Actions
|
||||
'action.plant': 'Posadi',
|
||||
'action.harvest': 'Požanji',
|
||||
'action.craft': 'Izdelaj',
|
||||
'action.build': 'Zgradi',
|
||||
|
||||
// Seasons
|
||||
'season.spring': 'Pomlad',
|
||||
'season.summer': 'Poletje',
|
||||
'season.autumn': 'Jesen',
|
||||
'season.winter': 'Zima',
|
||||
|
||||
// Messages
|
||||
'msg.demo_end': 'Demo končan! Hvala za igranje.',
|
||||
'msg.freezing': '❄️ Zmrzuješ!',
|
||||
'msg.overheating': '🔥 Pregrevanje!'
|
||||
},
|
||||
'en': {
|
||||
// UI
|
||||
'ui.inventory': 'Inventory',
|
||||
'ui.crafting': 'Crafting',
|
||||
'ui.health': 'Health',
|
||||
'ui.hunger': 'Hunger',
|
||||
'ui.oxygen': 'Oxygen',
|
||||
'ui.day': 'Day',
|
||||
'ui.season': 'Season',
|
||||
|
||||
// Items
|
||||
'item.wood': 'Wood',
|
||||
'item.stone': 'Stone',
|
||||
'item.seeds': 'Seeds',
|
||||
'item.wheat': 'Wheat',
|
||||
'item.corn': 'Corn',
|
||||
|
||||
// Actions
|
||||
'action.plant': 'Plant',
|
||||
'action.harvest': 'Harvest',
|
||||
'action.craft': 'Craft',
|
||||
'action.build': 'Build',
|
||||
|
||||
// Seasons
|
||||
'season.spring': 'Spring',
|
||||
'season.summer': 'Summer',
|
||||
'season.autumn': 'Autumn',
|
||||
'season.winter': 'Winter',
|
||||
|
||||
// Messages
|
||||
'msg.demo_end': 'Demo Ended! Thanks for playing.',
|
||||
'msg.freezing': '❄️ Freezing!',
|
||||
'msg.overheating': '🔥 Overheating!'
|
||||
},
|
||||
'de': {
|
||||
'ui.inventory': 'Inventar',
|
||||
'ui.crafting': 'Handwerk',
|
||||
'ui.health': 'Gesundheit',
|
||||
'season.spring': 'Frühling',
|
||||
'season.summer': 'Sommer',
|
||||
'season.autumn': 'Herbst',
|
||||
'season.winter': 'Winter'
|
||||
},
|
||||
'it': {
|
||||
'ui.inventory': 'Inventario',
|
||||
'ui.crafting': 'Artigianato',
|
||||
'season.spring': 'Primavera',
|
||||
'season.summer': 'Estate',
|
||||
'season.autumn': 'Autunno',
|
||||
'season.winter': 'Inverno'
|
||||
},
|
||||
'cn': {
|
||||
'ui.inventory': '库存',
|
||||
'ui.crafting': '制作',
|
||||
'season.spring': '春天',
|
||||
'season.summer': '夏天',
|
||||
'season.autumn': '秋天',
|
||||
'season.winter': '冬天'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translated string
|
||||
* @param {string} key - Translation key (e.g. 'ui.inventory')
|
||||
* @param {string} fallback - Fallback text if translation missing
|
||||
*/
|
||||
t(key, fallback = key) {
|
||||
const lang = this.translations[this.currentLang];
|
||||
if (lang && lang[key]) {
|
||||
return lang[key];
|
||||
}
|
||||
|
||||
// Fallback to English
|
||||
const enLang = this.translations['en'];
|
||||
if (enLang && enLang[key]) {
|
||||
return enLang[key];
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current language
|
||||
*/
|
||||
setLanguage(langCode) {
|
||||
if (this.supportedLanguages.includes(langCode)) {
|
||||
this.currentLang = langCode;
|
||||
localStorage.setItem('novafarma_language', langCode);
|
||||
console.log(`🌍 Language changed to: ${langCode}`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getCurrentLanguage() {
|
||||
return this.currentLang;
|
||||
}
|
||||
|
||||
getSupportedLanguages() {
|
||||
return this.supportedLanguages.map(code => ({
|
||||
code,
|
||||
name: this.getLanguageName(code)
|
||||
}));
|
||||
}
|
||||
|
||||
getLanguageName(code) {
|
||||
const names = {
|
||||
'slo': 'Slovenščina',
|
||||
'en': 'English',
|
||||
'de': 'Deutsch',
|
||||
'it': 'Italiano',
|
||||
'cn': '中文'
|
||||
};
|
||||
return names[code] || code;
|
||||
}
|
||||
}
|
||||
|
||||
// Global instance
|
||||
window.LocalizationSystem = LocalizationSystem;
|
||||
141
src/systems/PlaytimeTrackerSystem.js
Normal file
141
src/systems/PlaytimeTrackerSystem.js
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* PLAYTIME TRACKER SYSTEM
|
||||
* Tracks persistent stats: playtime, deaths, harvests, etc.
|
||||
*/
|
||||
class PlaytimeTrackerSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// Initialize stats
|
||||
this.stats = {
|
||||
playtimeSeconds: 0,
|
||||
deaths: 0,
|
||||
kills: 0,
|
||||
harvests: 0,
|
||||
plantings: 0,
|
||||
distanceTraveled: 0,
|
||||
moneyEarned: 0,
|
||||
itemsCrafted: 0,
|
||||
blocksPlaced: 0,
|
||||
sessionStart: Date.now()
|
||||
};
|
||||
|
||||
// Load from save
|
||||
this.load();
|
||||
|
||||
// Update timer
|
||||
this.updateTimer = 0;
|
||||
this.saveInterval = 10000; // Save every 10 seconds
|
||||
}
|
||||
|
||||
update(delta) {
|
||||
// Increment playtime
|
||||
this.stats.playtimeSeconds += delta / 1000;
|
||||
|
||||
// Periodic save
|
||||
this.updateTimer += delta;
|
||||
if (this.updateTimer >= this.saveInterval) {
|
||||
this.updateTimer = 0;
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
// Stat tracking methods
|
||||
recordDeath() {
|
||||
this.stats.deaths++;
|
||||
this.save();
|
||||
}
|
||||
|
||||
recordKill() {
|
||||
this.stats.kills++;
|
||||
}
|
||||
|
||||
recordHarvest() {
|
||||
this.stats.harvests++;
|
||||
}
|
||||
|
||||
recordPlanting() {
|
||||
this.stats.plantings++;
|
||||
}
|
||||
|
||||
recordDistance(distance) {
|
||||
this.stats.distanceTraveled += distance;
|
||||
}
|
||||
|
||||
recordMoneyEarned(amount) {
|
||||
this.stats.moneyEarned += amount;
|
||||
}
|
||||
|
||||
recordCraft() {
|
||||
this.stats.itemsCrafted++;
|
||||
}
|
||||
|
||||
recordBlockPlaced() {
|
||||
this.stats.blocksPlaced++;
|
||||
}
|
||||
|
||||
// Formatted playtime
|
||||
getPlaytimeFormatted() {
|
||||
const hours = Math.floor(this.stats.playtimeSeconds / 3600);
|
||||
const minutes = Math.floor((this.stats.playtimeSeconds % 3600) / 60);
|
||||
const seconds = Math.floor(this.stats.playtimeSeconds % 60);
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}m ${seconds}s`;
|
||||
} else {
|
||||
return `${seconds}s`;
|
||||
}
|
||||
}
|
||||
|
||||
// Session duration
|
||||
getSessionDuration() {
|
||||
const sessionMs = Date.now() - this.stats.sessionStart;
|
||||
const sessionSec = Math.floor(sessionMs / 1000);
|
||||
return sessionSec;
|
||||
}
|
||||
|
||||
// Save/Load
|
||||
save() {
|
||||
localStorage.setItem('novafarma_stats', JSON.stringify(this.stats));
|
||||
}
|
||||
|
||||
load() {
|
||||
const saved = localStorage.getItem('novafarma_stats');
|
||||
if (saved) {
|
||||
try {
|
||||
const data = JSON.parse(saved);
|
||||
this.stats = { ...this.stats, ...data };
|
||||
this.stats.sessionStart = Date.now(); // Reset session timer
|
||||
} catch (e) {
|
||||
console.error('Failed to load stats:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.stats = {
|
||||
playtimeSeconds: 0,
|
||||
deaths: 0,
|
||||
kills: 0,
|
||||
harvests: 0,
|
||||
plantings: 0,
|
||||
distanceTraveled: 0,
|
||||
moneyEarned: 0,
|
||||
itemsCrafted: 0,
|
||||
blocksPlaced: 0,
|
||||
sessionStart: Date.now()
|
||||
};
|
||||
this.save();
|
||||
}
|
||||
|
||||
// Get all stats
|
||||
getStats() {
|
||||
return {
|
||||
...this.stats,
|
||||
playtimeFormatted: this.getPlaytimeFormatted(),
|
||||
sessionDuration: this.getSessionDuration()
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user