Compare commits

...

1 Commits

Author SHA1 Message Date
177d05e942 feat(v0.97): Weather system, Master Clock save/load, Lang fix, Golden Statue 200d achievement
## 🌧️ WEATHER SYSTEM
- DayNightSystem: weather changes every morning at 06:00
- 30% chance of rain, calculated 1 day ahead
- Procedural rain visuals tied to actual weather state
- Radio [E] near tent shows tomorrow's forecast (Dark-Chibi Noir UI)

## 💧 WATER & FARMING
- WaterSystem: Rain Catcher capacity increased to 50L
- Auto-fill to 50L on rain days
- Auto-water all soilSlots on rain, auto-dry on sunny days

## 🌍 LOCALIZATION FIX
- Language button now switches instantly (no scene.restart() crash)
- All menu text (subtitle, tagline, settings) translates live
- localization.json: added menu_subtitle, menu_tagline, settings_info, settings_close for all 5 langs
- Settings button now opens real pop-up menu

## 🏆 GOLDEN STATUE (200 DAYS)
- _showAchievement() + _spawnGoldenStatue() methods
- Statue uses correct 2.5D physics: setOrigin(0.5,1.0), setDepth(y), collider
- _statueSpawned flag prevents duplicate spawns
- Post-load check: statue appears if save file has day >= 200

## 🗓️ MASTER CLOCK
- DayNightSystem: saveState()/loadState() via localStorage (key: nova_farma_time_save)
- Saves: day, year, hour, minute, todayWeather, tomorrowWeather
- Auto-save every in-game minute + on midnight + on sleep
- Year system: year increments every 120 days (Aging System hook)
- yearChanged event wired to UIScene + GrassScene

## 📊 HUD UPGRADE
- UIScene: yearText element (LETO 1) below dayText
- dayText uses i18n key, turns orange at day 190+ (pre-statue warning)
- gameState.year added

Build: v0.97 ALPHA - Master Clock Edition
2026-04-27 00:00:53 +02:00
9 changed files with 487 additions and 52 deletions

View File

@@ -5902,3 +5902,16 @@ V tej seji smo se osredotočili na popravilo in izboljšanje `GameScene.js`, pre
- **Goal:** Build the 8x8 Safe Zone foundation first. - **Goal:** Build the 8x8 Safe Zone foundation first.
- **Removed:** Duplicate documentation and obsolete backup files. - **Removed:** Duplicate documentation and obsolete backup files.
## **UPDATE 26.4.2026: DEMO MEHANIKE & DOSTOPNOST**
- **Sistemi:**
- Avtomatski "Zero-State" Tloris za 8x8 kmetijo (fiksna postavitev Šotora, Ognja in Lovilca ob zagonu).
- Pametna "Anti-Cheat" kamera z miškino drsnico (Zoom) in Lookahead zamikom.
- Day/Night cikel (20 minut na dan, temen Noir filter ponoči, močnejši zombiji in Pass Out kazen ob 02:00).
- Globalna večjezična lokalizacija (SL, EN, DE, IT, CN) v `localization.json` z avtomatsko zaznavo.
- **Dostopnost (AccessibilityManager):**
- Vgrajen 7-gumbovni UI z 2 stolpcema.
- Vizualna opozorila (Deaf Mode) - utripanje zaslona.
- Senzorni & ADHD Mode - skrivanje UI in umiritev kamere.
- Enoročni način (One-Handed) - point & click sledenje samo z miško.
- Vidne Prilagoditve - povečana pisava, Visok Kontrast in Barvna slepota (Protanopia filtri).
- **Status:** Temeljne Demo Faza 1 mehanike so združene in stabilne, UI pripravljen!

View File

@@ -1487,3 +1487,48 @@ Ali kot bi rekel Gronk, med vape puff-om:
**Status:** Session uspešno zaključen, vsi asseti commitani. **Status:** Session uspešno zaključen, vsi asseti commitani.
--- ---
## 📅 26. April 2026 - IMPLEMENTACIJA CORE MEHANIK & DOSTOPNOSTI ZA DEMO
**Datum:** 26.4.2026
**Trajanje:** Masiven All-in-One update
**Fokus:** Izboljšava kamere, Day/Night cikel, Avtomatska kmetija, Lokalizacija in Polni UI Dostopnosti
### Delo Opravljeno
**1. Vizualna Globina in Arhitektura (Y-Sorting) 🏗️**
- Popravljena sidrišča (anchors) za Kaia in vse zgradbe na (0.5, 1.0).
- Vklopljena dinamična globina (Y-sorting) za pravilen 2.5D render (Kai hodi PRED in ZA objekti).
**2. Pripravljena 8x8 "Zero-State" Kmetija 🏕️**
- Implementiran fiksni setup kmetije ob zagonu igre (šotor zgoraj levo, lovilec deževnice zgoraj desno, ogenj in skrinja v sredini).
- Pripravljena polja za sajenje pred šotorom in generiran "Fog of War" okoli baze.
**3. Pametna "Anti-Cheat" Kamera 🎥**
- Onemogočen free-roam (prosto premikanje s tipkovnico) za kamero.
- Dodan Scroll-Wheel Zoom (0.5x - 2.5x).
- Implementiran **Lookahead Offset**: kamera se gladko zamakne naprej v smeri igralčevega gibanja in vida.
**4. Sistem Dan/Noč s Kaznimi (Day/Night Cycle) 🌙**
- In-game dan nastavljen na točno 20 realnih minut.
- Uveden temno moder "Dark-Chibi Noir" nočni filter na zaslonu.
- Ponoči zombiji postanejo 2x močnejši in hitrejši + sproži se nočni spawn Rakunov.
- **Pass Out kazen**: Če igralec ne gre spati do 02:00, Kai omedli (izguba denarja in energije, respawn ob 06:00).
**5. Globalni Sistem Jezikov (Localization) 🌍**
- Ustvarjen `localization.json` s 5 jeziki (SL, EN, DE, IT, CN).
- Podpora za UTF-8 "Noto Sans" pisave (vključno s kitajskimi pismenkami).
- Zaznavanje sistemskega jezika in gumb za ročno izbiro v Meniju, ki se shrani v `localStorage`.
**6. Popoln Meni za Dostopnost (AccessibilityManager) ♿🧠**
- Implementiran celoten vmesnik in sistem z nastavitvami v 2 stolpcih (7 gumbov).
- **Deaf Mode**: Rdeči robovi ob zombijih, vijoličen zaslon pri Twin Bond, glitch efekt pri Flashbacku.
- **Autism Friendly**: Izklop tresenja kamere in mehkejši vizualni filtri.
- **ADHD/Zen Mode**: Skrivanje nepotrebnega HUD-a in osredotočen velik indikator cilja (npr. "ZALIJ PŠENICO").
- **Enoročni način (One-Handed)**: Igranje samo z miško (Kai sledi kurzorju ob držanju levega klika).
- **Vizualne nastavitve**: Povečana pisava (x1.25), Visok kontrast (CSS) in filtri za barvno slepoto (Protanopia CSS).
**7. Profesionalni UI 🎖️**
- Dodan "Trial Version" badge v zgornjem kotu in logika za takojšen odklep Faze 1 ob prehodu na "Full Game".
**Status:** Vsi temeljni sistemi za igralni Demo so sedaj stabilni in povezani med seboj!

View File

@@ -389,6 +389,11 @@ AKT 2-4 (Faza 1+): ░░░░░░░░░░ 0% (prihodnost)
--- ---
*Posodobljeno: 2026-03-03 ob 13:19* ## 📅 UPDATE 26. April 2026 (23:25) - ZGODBA IN DOSTOPNOST
- **Twin Bond Signali:** Narejen `twinBondPulse` globalni event v `TwinBondSystem.js`. Sedaj obležijo podlago za komunikacijo! Če je vklopljen 'Deaf Mode', cel HUD zavibrira in se pobarva z *vijoličnim sijajem*. Progress 5% -> **20%**.
- **Flashback Memories:** Sprogramiran 'flashbackPulse' event v `AccessibilityManager.js`. Ob proženju se zgodi grozljiv 'Screen Glitch' (bel screen in hud Camera Shake 300ms), ki vizualno odlično ponazarja izgubo spomina (Amnezija). Progress 5% -> **15%**.
- **Pritisk Časa (Survival Lore):** Aktivirali in kalibrirali 20-minutni real-time Day/Night cikel ter 'Pass Out' kazen ob 2:00 zjutraj. Igralec končno začuti napetost noči in hudih zombijev, ki je osrčje Kaijeve situacije.
*Posodobljeno: 2026-04-26 ob 23:26*
*Za dialoge: `DEMO_FAZA1_NAPISI_DIALOGI.md`* *Za dialoge: `DEMO_FAZA1_NAPISI_DIALOGI.md`*
*Za full lore: `ZGODBA_CELOTNA.md`* *Za full lore: `ZGODBA_CELOTNA.md`*

View File

@@ -16,7 +16,11 @@
"day": "DAN", "day": "DAN",
"map": "MAPA", "map": "MAPA",
"crafting": "CRAFTING", "crafting": "CRAFTING",
"adhd_goal": "⬇️ TVOJ TRENUTNI CILJ: ZALIJ PŠENICO! ⬇️" "adhd_goal": "⬇️ TVOJ TRENUTNI CILJ: ZALIJ PŠENICO! ⬇️",
"menu_subtitle": "KRVAVA ŽETEV",
"menu_tagline": "\"Preživi. Najdi jo. Ne pozabi.\"",
"settings_info": "Nastavitve dostopnosti se nahajajo\nv sami igri (Meni gumb zgoraj desno).\n\nTukaj lahko preklapljaš samo Jezik.",
"settings_close": "ZAPRI"
}, },
"en": { "en": {
"menu_play": "PLAY", "menu_play": "PLAY",
@@ -35,7 +39,11 @@
"day": "DAY", "day": "DAY",
"map": "MAP", "map": "MAP",
"crafting": "CRAFTING", "crafting": "CRAFTING",
"adhd_goal": "⬇️ YOUR CURRENT GOAL: WATER THE WHEAT! ⬇️" "adhd_goal": "⬇️ YOUR CURRENT GOAL: WATER THE WHEAT! ⬇️",
"menu_subtitle": "BLOOD HARVEST",
"menu_tagline": "\"Survive. Find her. Don't forget.\"",
"settings_info": "Accessibility settings are located\ninside the game (Menu button top right).\n\nHere you can only change Language.",
"settings_close": "CLOSE"
}, },
"de": { "de": {
"menu_play": "SPIELEN", "menu_play": "SPIELEN",
@@ -54,7 +62,11 @@
"day": "TAG", "day": "TAG",
"map": "KARTE", "map": "KARTE",
"crafting": "HERSTELLUNG", "crafting": "HERSTELLUNG",
"adhd_goal": "⬇️ DEIN AKTUELLES ZIEL: WEIZEN GIESSEN! ⬇️" "adhd_goal": "⬇️ DEIN AKTUELLES ZIEL: WEIZEN GIESSEN! ⬇️",
"menu_subtitle": "BLUTERNTE",
"menu_tagline": "\"Überlebe. Finde sie. Vergiss nicht.\"",
"settings_info": "Barrierefreiheitseinstellungen befinden sich\nim Spiel (Menü-Taste oben rechts).\n\nHier können Sie nur die Sprache ändern.",
"settings_close": "SCHLIESSEN"
}, },
"it": { "it": {
"menu_play": "GIOCA", "menu_play": "GIOCA",
@@ -73,7 +85,11 @@
"day": "GIORNO", "day": "GIORNO",
"map": "MAPPA", "map": "MAPPA",
"crafting": "CREAZIONE", "crafting": "CREAZIONE",
"adhd_goal": "⬇️ IL TUO OBIETTIVO ATTUALE: ANNAFFIA IL GRANO! ⬇️" "adhd_goal": "⬇️ IL TUO OBIETTIVO ATTUALE: ANNAFFIA IL GRANO! ⬇️",
"menu_subtitle": "RACCOLTO DI SANGUE",
"menu_tagline": "\"Sopravvivi. Trovala. Non dimenticare.\"",
"settings_info": "Le impostazioni di accessibilità si trovano\nall'interno del gioco (tasto Menu in alto a destra).\n\nQui puoi cambiare solo la Lingua.",
"settings_close": "CHIUDI"
}, },
"cn": { "cn": {
"menu_play": "开始游戏", "menu_play": "开始游戏",
@@ -92,6 +108,10 @@
"day": "天", "day": "天",
"map": "地图", "map": "地图",
"crafting": "制作", "crafting": "制作",
"adhd_goal": "⬇️ 你当前的目标:给小麦浇水 ⬇️" "adhd_goal": "⬇️ 你当前的目标:浇灌小麦 ⬇️",
"menu_subtitle": "血腥收获",
"menu_tagline": "\"生存。找到她。别忘了。\"",
"settings_info": "无障碍设置位于\n游戏内部右上角菜单按钮。\n\n在这里你只能更改语言。",
"settings_close": "关闭"
} }
} }

View File

@@ -128,6 +128,7 @@ export default class GrassSceneClean extends Phaser.Scene {
}); });
this.load.image('rain_catcher', 'DEMO_FAZA1/Structures/rain_catcher.png'); this.load.image('rain_catcher', 'DEMO_FAZA1/Structures/rain_catcher.png');
this.load.image('foundation_concrete', 'DEMO_FAZA1/Structures/foundation_concrete.png'); this.load.image('foundation_concrete', 'DEMO_FAZA1/Structures/foundation_concrete.png');
this.load.image('golden_statue', 'DEMO_FAZA1/Structures/golden_statue.png');
// 8. Weather System // 8. Weather System
this.load.image('rain_drops', 'DEMO_FAZA1/Environment/rain_drops.png'); this.load.image('rain_drops', 'DEMO_FAZA1/Environment/rain_drops.png');
@@ -1180,7 +1181,8 @@ export default class GrassSceneClean extends Phaser.Scene {
up: Phaser.Input.Keyboard.KeyCodes.W, up: Phaser.Input.Keyboard.KeyCodes.W,
down: Phaser.Input.Keyboard.KeyCodes.S, down: Phaser.Input.Keyboard.KeyCodes.S,
left: Phaser.Input.Keyboard.KeyCodes.A, left: Phaser.Input.Keyboard.KeyCodes.A,
right: Phaser.Input.Keyboard.KeyCodes.D right: Phaser.Input.Keyboard.KeyCodes.D,
interact: Phaser.Input.Keyboard.KeyCodes.E
}); });
@@ -1343,6 +1345,7 @@ export default class GrassSceneClean extends Phaser.Scene {
this.rainScreenW = SCREEN_W; this.rainScreenW = SCREEN_W;
this.rainScreenH = SCREEN_H; this.rainScreenH = SCREEN_H;
this.isRaining = false;
console.log('🌧️ Rain system initialized (procedural canvas drops)!'); console.log('🌧️ Rain system initialized (procedural canvas drops)!');
@@ -1418,17 +1421,66 @@ export default class GrassSceneClean extends Phaser.Scene {
// === EVENT WIRE-UP === // === EVENT WIRE-UP ===
// Dan se je spremenil → farma tick // Dan se je spremenil → farma tick + Master Clock
this.events.on('dayChanged', ({ day }) => { this.events.on('dayChanged', ({ day }) => {
if (this.farmingSystem) this.farmingSystem.onNewDay(day); if (this.farmingSystem) this.farmingSystem.onNewDay(day);
console.log(`📅 Dan ${day} prišel!`); console.log(`📅 Dan ${day} prišel!`);
// 🏆 ULTIMATIVNA NAGRADA: natanko 200 dni preživetja
if (day === 200 && !this._statueSpawned) {
this._statueSpawned = true;
this._showAchievement('Trmasti Preživeli');
this._spawnGoldenStatue();
}
}); });
// Dež → Rain Catcher zbira // 🎊 NOVO LETO — trigger za prihodnji Aging System
this.events.on('rainDay', ({ day }) => { this.events.on('yearChanged', ({ year, day }) => {
console.log(`🎉 GrassScene: Novo Leto ${year} (dan ${day}) - Aging System trigger!`);
// V prihodnosti: this.agingSystem.onNewYear(year);
});
// Preveri ob nalaganju igre: Morda je save z dnevom >= 200
this.time.delayedCall(500, () => {
const dns = this.dayNightSystem;
if (dns && dns.getDay() >= 200 && !this._statueSpawned) {
this._statueSpawned = true;
// Achievement samo ob točno 200, ne ob načinu po 200
if (dns.getDay() === 200) this._showAchievement('Trmasti Preživeli');
this._spawnGoldenStatue();
}
});
// Dež → Rain Catcher zbira in avtomatsko zalije kmetijo
this.events.on('weatherChanged', (weather) => {
if (weather === 'rain') {
this.isRaining = true;
if (this.waterSystem) this.waterSystem.onRain(); if (this.waterSystem) this.waterSystem.onRain();
this.triggerRainfall(); // Vizualni dež this.triggerRainfall(); // Vizualni dež na tleh
console.log(`🌧️ Dežen dan ${day}`);
// Avtomatsko zalij vse posajene rastline!
if (this.farmingSystem && this.farmingSystem.soilSlots) {
this.farmingSystem.soilSlots.forEach(slot => {
slot.isWatered = true;
slot.tint = 0x666633; // Temnejša barva mokre zemlje
});
}
console.log(`🌧️ Vreme: DEŽ - Kmetija avtomatsko zalita!`);
} else {
this.isRaining = false;
// Vse se posuši
if (this.farmingSystem && this.farmingSystem.soilSlots) {
this.farmingSystem.soilSlots.forEach(slot => {
slot.isWatered = false;
slot.clearTint();
});
}
console.log(`☀️ Vreme: SONCE - Kmetija se je posušila.`);
}
}); });
// Jutro → Rast trave/dreves // Jutro → Rast trave/dreves
@@ -1978,6 +2030,83 @@ export default class GrassSceneClean extends Phaser.Scene {
// --- AUTO-TILING SYSTEM (REMOVED) --- // --- AUTO-TILING SYSTEM (REMOVED) ---
/* Removed for cleanup */ /* Removed for cleanup */
_showAchievement(title) {
const cx = this.cameras.main.centerX;
const cy = this.cameras.main.centerY;
const bg = this.add.rectangle(cx, cy - 200, 600, 100, 0xffd700, 0.9)
.setStrokeStyle(4, 0xffffff)
.setDepth(9999)
.setScrollFactor(0);
const txt = this.add.text(cx, cy - 200, `🏆 ACHIEVEMENT UNLOCKED 🏆\n${title}`, {
fontFamily: 'Arial Black',
fontSize: '28px',
color: '#000000',
align: 'center',
stroke: '#ffffff',
strokeThickness: 2
}).setOrigin(0.5).setDepth(10000).setScrollFactor(0);
// Animacija
bg.setScale(0);
txt.setScale(0);
this.tweens.add({
targets: [bg, txt],
scale: 1,
duration: 600,
ease: 'Back.out',
onComplete: () => {
this.time.delayedCall(5000, () => {
this.tweens.add({
targets: [bg, txt],
y: '-=50',
alpha: 0,
duration: 500,
onComplete: () => {
bg.destroy();
txt.destroy();
}
});
});
}
});
}
_spawnGoldenStatue() {
// Kip se pojavi zraven šotora
let spawnX = this.sotor ? this.sotor.x + 160 : 1500;
let spawnY = this.sotor ? this.sotor.y + 40 : 1500;
const statue = this.physics.add.image(spawnX, spawnY, 'golden_statue');
statue.setOrigin(0.5, 1.0); // Pravilno sidrišče na dno
statue.setDepth(statue.y); // Dinamična globina Y-sorting
statue.setScale(1.2); // Malo večje, da je impresivno
statue.body.setSize(100, 40);
statue.body.setOffset(statue.width/2 - 50, statue.height - 40);
statue.body.setImmovable(true);
// Trk s Kaiem
if (this.kai) {
this.physics.add.collider(this.kai, statue);
}
// Bleščanje (Pulse glow)
this.tweens.add({
targets: statue,
scaleX: 1.25,
scaleY: 1.25,
duration: 1200,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
console.log("✨ Zlati Kip za 200 dni postavljen!");
}
update(time, delta) { update(time, delta) {
if (this.kai && this.kai.active) { if (this.kai && this.kai.active) {
// --- LOOKAHEAD CAMERA OFFSET (Gledanje naprej) --- // --- LOOKAHEAD CAMERA OFFSET (Gledanje naprej) ---
@@ -2102,7 +2231,7 @@ export default class GrassSceneClean extends Phaser.Scene {
this.kai.setDepth(this.kai.y); this.kai.setDepth(this.kai.y);
// === RAIN UPDATE: Draw procedural raindrops each frame === // === RAIN UPDATE: Draw procedural raindrops each frame ===
if (this.rainGraphics && this.rainDrops) { if (this.rainGraphics && this.rainDrops && this.isRaining) {
const dt = delta / 1000; // seconds const dt = delta / 1000; // seconds
this.rainGraphics.clear(); this.rainGraphics.clear();
@@ -2131,6 +2260,20 @@ export default class GrassSceneClean extends Phaser.Scene {
); );
this.rainGraphics.strokePath(); this.rainGraphics.strokePath();
} }
} else if (this.rainGraphics) {
this.rainGraphics.clear();
}
// === RADIO INTERACTION ===
if (Phaser.Input.Keyboard.JustDown(this.keys.interact)) {
if (this.sotor) {
const distToTent = Phaser.Math.Distance.Between(this.kai.x, this.kai.y, this.sotor.x, this.sotor.y);
if (distToTent < 150) {
// Odpri radio UI
const tomorrowWeather = this.dayNightSystem ? this.dayNightSystem.getTomorrowWeather() : 'sun';
this.scene.get('UIScene').showRadioForecast(tomorrowWeather);
}
}
} }
// === WATER SYSTEM UPDATE === // === WATER SYSTEM UPDATE ===

View File

@@ -119,7 +119,7 @@ export default class MenuScene extends Phaser.Scene {
// NASLOV IGRE // NASLOV IGRE
// ───────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────
// Subtitle zgoraj // Subtitle zgoraj
this.add.text(W * 0.32, H * 0.12, 'KRVAVA ŽETEV', { this.subtitleText = this.add.text(W * 0.32, H * 0.12, this.i18n.t('menu_subtitle'), {
fontFamily: '"Georgia", serif', fontFamily: '"Georgia", serif',
fontSize: '28px', fontSize: '28px',
color: '#cc6666', color: '#cc6666',
@@ -151,7 +151,7 @@ export default class MenuScene extends Phaser.Scene {
}); });
// Tagline pod naslovom // Tagline pod naslovom
this.add.text(W * 0.32, H * 0.41, '"Preživi. Najdi jo. Ne pozabi."', { this.taglineText = this.add.text(W * 0.32, H * 0.41, this.i18n.t('menu_tagline'), {
fontFamily: '"Georgia", serif', fontFamily: '"Georgia", serif',
fontStyle: 'italic', fontStyle: 'italic',
fontSize: '22px', fontSize: '22px',
@@ -175,7 +175,7 @@ export default class MenuScene extends Phaser.Scene {
const buttons = [ const buttons = [
{ label: '▶ ' + this.i18n.t('menu_play'), id: 'play', color: '#44ffcc', hColor: '#ffffff' }, { label: '▶ ' + this.i18n.t('menu_play'), id: 'play', color: '#44ffcc', hColor: '#ffffff' },
{ label: '⚙ ' + this.i18n.t('menu_options'), id: 'settings', color: '#aabbcc', hColor: '#ffffff' }, { label: '⚙ ' + this.i18n.t('menu_options'), id: 'settings', color: '#aabbcc', hColor: '#ffffff' },
{ label: '🌍 ' + this.i18n.t('lang_btn'), id: 'lang', color: '#ccddaa', hColor: '#ffffff' }, { label: '🌍 ' + this.i18n.t('lang_btn') + ` (${this.i18n.currentLang.toUpperCase()})`, id: 'lang', color: '#ccddaa', hColor: '#ffffff' },
{ label: '✕ ' + this.i18n.t('menu_exit'), id: 'quit', color: '#cc6666', hColor: '#ff8888' }, { label: '✕ ' + this.i18n.t('menu_exit'), id: 'quit', color: '#cc6666', hColor: '#ff8888' },
]; ];
@@ -290,17 +290,30 @@ export default class MenuScene extends Phaser.Scene {
}); });
} }
else if (id === 'settings') { else if (id === 'settings') {
// TODO: SettingsScene // Prikaži nastavitve UI
this._showToast('Nastavitve kmalu! 🔧'); this._showSettingsMenu();
} }
else if (id === 'lang') { else if (id === 'lang') {
// Cycle language // Hitro zamenjaj jezik
const langs = this.i18n.supportedLangs; const langs = this.i18n.supportedLangs;
let idx = langs.indexOf(this.i18n.currentLang); let idx = langs.indexOf(this.i18n.currentLang);
idx = (idx + 1) % langs.length; idx = (idx + 1) % langs.length;
this.i18n.setLanguage(langs[idx]); this.i18n.setLanguage(langs[idx]);
// Restart scene to apply new language
this.scene.restart(); // Takoj posodobi tekste gumbov (brez scene restarta, ker je hitreje in bolj stabilno)
this._btns[0].txt.setText('▶ ' + this.i18n.t('menu_play'));
this._btns[1].txt.setText('⚙ ' + this.i18n.t('menu_options'));
this._btns[2].txt.setText('🌍 ' + this.i18n.t('lang_btn') + ` (${this.i18n.currentLang.toUpperCase()})`);
this._btns[3].txt.setText('✕ ' + this.i18n.t('menu_exit'));
// Posodobi naslovne tekste
if (this.subtitleText) this.subtitleText.setText(this.i18n.t('menu_subtitle'));
if (this.taglineText) this.taglineText.setText(this.i18n.t('menu_tagline'));
// Če je odprt meni z nastavitvami, posodobi tudi tisto
if (this.settingsTitle) this.settingsTitle.setText('⚙ ' + this.i18n.t('menu_options'));
if (this.settingsInfo) this.settingsInfo.setText(this.i18n.t('settings_info'));
if (this.settingsCloseTxt) this.settingsCloseTxt.setText(this.i18n.t('settings_close'));
} }
else if (id === 'quit') { else if (id === 'quit') {
// Electron quit // Electron quit
@@ -344,6 +357,56 @@ export default class MenuScene extends Phaser.Scene {
}); });
} }
_showSettingsMenu() {
if (this.settingsContainer) return;
const W = this.cameras.main.width;
const H = this.cameras.main.height;
this.settingsContainer = this.add.container(W / 2, H / 2).setDepth(9000);
// Temno ozadje in rob
const bg = this.add.rectangle(0, 0, 550, 320, 0x111111, 0.95).setStrokeStyle(4, 0x44ffcc);
this.settingsTitle = this.add.text(0, -110, '⚙ ' + this.i18n.t('menu_options'), {
fontFamily: this.i18n.fontFamily, fontSize: '32px', color: '#44ffcc'
}).setOrigin(0.5);
this.settingsInfo = this.add.text(0, -30, this.i18n.t('settings_info'), {
fontFamily: this.i18n.fontFamily, fontSize: '20px', color: '#aaaaaa', align: 'center'
}).setOrigin(0.5);
// Gumb Zapri
const closeBtnBg = this.add.rectangle(0, 90, 200, 50, 0xcc6666, 1).setInteractive({ useHandCursor: true });
this.settingsCloseTxt = this.add.text(0, 90, this.i18n.t('settings_close'), {
fontFamily: this.i18n.fontFamily, fontSize: '22px', color: '#ffffff', stroke: '#000000', strokeThickness: 4
}).setOrigin(0.5);
closeBtnBg.on('pointerdown', () => {
this.tweens.add({
targets: this.settingsContainer,
scale: 0,
duration: 250,
ease: 'Back.in',
onComplete: () => {
this.settingsContainer.destroy();
this.settingsContainer = null;
}
});
});
this.settingsContainer.add([bg, this.settingsTitle, this.settingsInfo, closeBtnBg, this.settingsCloseTxt]);
// Pop-up animacija
this.settingsContainer.setScale(0);
this.tweens.add({
targets: this.settingsContainer,
scale: 1,
duration: 350,
ease: 'Back.out'
});
}
// ───────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────
// UPDATE // UPDATE
// ───────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────

View File

@@ -28,6 +28,7 @@ export default class UIScene extends Phaser.Scene {
energy: 100, energy: 100,
maxEnergy: 100, maxEnergy: 100,
day: 1, day: 1,
year: 1, // 🗓️ Generacijski sistem — leto se obrne vsakih 120 dni
hour: 6, hour: 6,
minute: 0, minute: 0,
weather: 'rain', // 'sun', 'rain', 'storm', 'cloud' weather: 'rain', // 'sun', 'rain', 'storm', 'cloud'
@@ -189,15 +190,24 @@ export default class UIScene extends Phaser.Scene {
strokeThickness: 4, strokeThickness: 4,
}).setOrigin(0.5, 0.5).setDepth(1005); }).setOrigin(0.5, 0.5).setDepth(1005);
// Dan label (pod uro) // Dan + Leto (zgoraj desno, pod uro)
this.dayText = this.add.text(W - PAD - 135, PAD + 10, this.i18n.t('day') + ' 1', { this.dayText = this.add.text(W - PAD - 62, PAD + 105, this.i18n.t('day') + ' 1', {
fontFamily: this.i18n.fontFamily, fontFamily: 'Arial Black',
fontSize: '18px', fontSize: '20px',
color: '#ffdd44', color: '#ffdd44',
stroke: '#000000', stroke: '#000000',
strokeThickness: 4, strokeThickness: 4,
}).setOrigin(0.5, 0).setDepth(1005); }).setOrigin(0.5, 0).setDepth(1005);
// Leto (pod dnem)
this.yearText = this.add.text(W - PAD - 62, PAD + 133, 'LETO 1', {
fontFamily: 'Arial Black',
fontSize: '14px',
color: '#aaddff',
stroke: '#000000',
strokeThickness: 3,
}).setOrigin(0.5, 0).setDepth(1005);
// ───────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────
// BOTTOM CENTER — Hotbar (7 slotov) // BOTTOM CENTER — Hotbar (7 slotov)
// ───────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────
@@ -483,12 +493,19 @@ export default class UIScene extends Phaser.Scene {
// ── Time update iz DayNightSystem ───────────────────────────────── // ── Time update iz DayNightSystem ─────────────────────────────────
this.events.on('timeChanged', (data) => { this.events.on('timeChanged', (data) => {
if (this.timeText) { if (data.day !== undefined) this.gameState.day = data.day;
this.timeText.setText(data.timeStr || '06:00'); if (data.year !== undefined) this.gameState.year = data.year;
} if (data.hour !== undefined) this.gameState.hour = data.hour;
if (this.dayText) { if (data.minute !== undefined) this.gameState.minute = data.minute;
this.dayText.setText(`DAN ${data.day}`); this._updateTimeDisplay();
} });
// ── Year update (Generacijski Aging trigger) ────────────────────
this.events.on('yearChanged', (data) => {
this.gameState.year = data.year;
this._updateTimeDisplay();
// Tukaj v prihodnosti sproži Aging System!
console.log(`🎈 UIScene: Novo leto ${data.year} - Aging System trigger ready!`);
}); });
// ── Water update iz WaterSystem ─────────────────────────────────── // ── Water update iz WaterSystem ───────────────────────────────────
@@ -585,17 +602,28 @@ export default class UIScene extends Phaser.Scene {
} }
} }
/** Posodobi uro + dan display */ /** Posodobi uro + dan + leto display */
_updateTimeDisplay() { _updateTimeDisplay() {
const { day, hour, minute } = this.gameState; const { day, year, hour, minute } = this.gameState;
const hStr = String(hour).padStart(2, '0'); const hStr = String(hour).padStart(2, '0');
const mStr = String(minute).padStart(2, '0'); const mStr = String(minute).padStart(2, '0');
this.timeText.setText(`${hStr}:${mStr}`); this.timeText.setText(`${hStr}:${mStr}`);
this.dayText.setText(`DAN ${day}`);
// Ura barva: rdeča ponoči, rumena podnevi // Dan s i18n ključem
const dayLabel = this.i18n ? this.i18n.t('day') : 'DAN';
this.dayText.setText(`${dayLabel} ${day}`);
// Leto label
if (this.yearText) {
this.yearText.setText(`LETO ${year || 1}`);
}
// Ura barva: modra ponoči, rdeča podnevi
const isNight = hour >= 21 || hour < 5; const isNight = hour >= 21 || hour < 5;
this.timeText.setColor(isNight ? '#8899ff' : '#ff3333'); this.timeText.setColor(isNight ? '#8899ff' : '#ff3333');
// DAN se obarva rumeno, LETO svetlo modro
this.dayText.setColor(day >= 190 ? '#ff8800' : '#ffdd44'); // Oranžno bliže kipu
} }
/** Toggle Inventory popup */ /** Toggle Inventory popup */
@@ -767,6 +795,61 @@ export default class UIScene extends Phaser.Scene {
} }
} }
showRadioForecast(weather) {
if (this.radioContainer) return;
const W = this.cameras.main.width;
const H = this.cameras.main.height;
// Dark-Chibi Noir stil: črna škatla, debel rob
this.radioContainer = this.add.container(W / 2, H / 2).setDepth(8000);
const bg = this.add.rectangle(0, 0, 450, 220, 0x0a0a0d, 0.95)
.setStrokeStyle(6, 0x222222);
let forecastText = weather === 'rain' ? 'DEŽ 🌧️' : 'SONČNO ☀️';
let color = weather === 'rain' ? '#55aaff' : '#ffdd44';
const title = this.add.text(0, -60, '📻 RADIO', {
fontFamily: this.i18n.fontFamily, fontSize: '28px', color: '#aaaaaa', fontStyle: 'bold'
}).setOrigin(0.5);
const info = this.add.text(0, 0, `Napoved za jutri:\n${forecastText}`, {
fontFamily: this.i18n.fontFamily, fontSize: '36px', color: color, align: 'center', stroke: '#000000', strokeThickness: 8
}).setOrigin(0.5);
const closeHint = this.add.text(0, 80, '[ Klikni za zaprtje ]', {
fontFamily: this.i18n.fontFamily, fontSize: '18px', color: '#666666'
}).setOrigin(0.5);
this.radioContainer.add([bg, title, info, closeHint]);
// Vstopna animacija
this.radioContainer.setScale(0);
this.tweens.add({
targets: this.radioContainer,
scale: 1,
duration: 400,
ease: 'Back.out'
});
// Zapri na klik območja ekrana
const blocker = this.add.zone(W/2, H/2, W, H).setInteractive().setDepth(7999);
blocker.on('pointerdown', () => {
this.tweens.add({
targets: this.radioContainer,
scale: 0,
duration: 300,
ease: 'Back.in',
onComplete: () => {
this.radioContainer.destroy();
this.radioContainer = null;
blocker.destroy();
}
});
});
}
update(time, delta) { update(time, delta) {
if (this.accManager) { if (this.accManager) {
this.accManager.update(time, delta); this.accManager.update(time, delta);

View File

@@ -31,11 +31,19 @@ export default class DayNightSystem {
constructor(scene, options = {}) { constructor(scene, options = {}) {
this.scene = scene; this.scene = scene;
// Čas // Čas in Master Clock
this.day = 1; this.day = 1;
this.year = 1;
this.hour = 6; // Začne ob 6:00 this.hour = 6; // Začne ob 6:00
this.minute = 0; this.minute = 0;
// Vreme
this.todayWeather = 'sun';
this.tomorrowWeather = Math.random() < 0.3 ? 'rain' : 'sun';
// Poskusi naložiti stanje iz prejšnje seje (Trajno shranjevanje)
this.loadState();
// Hitrost: 1.2 igra minut = 1 real sekunda (24 ur v igri = 1200 real sekund = 20 minut) // Hitrost: 1.2 igra minut = 1 real sekunda (24 ur v igri = 1200 real sekund = 20 minut)
this.gameMinutesPerRealSecond = options.speed || 1.2; this.gameMinutesPerRealSecond = options.speed || 1.2;
@@ -131,10 +139,14 @@ export default class DayNightSystem {
// Emit UI update vsako minuto // Emit UI update vsako minuto
this.scene.events.emit('timeChanged', { this.scene.events.emit('timeChanged', {
day: this.day, day: this.day,
year: this.year,
hour: this.hour, hour: this.hour,
minute: this.minute, minute: this.minute,
timeStr: this._timeStr(), timeStr: this._timeStr(),
}); });
// Avtomatsko trajno shranjevanje ure in dneva vsako in-game minuto
this.saveState();
} }
// ───────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────
@@ -149,9 +161,18 @@ export default class DayNightSystem {
// Posebni uri: // Posebni uri:
if (this.hour === 6) { if (this.hour === 6) {
// Jutro! // Jutro - Menjava vremena!
this.scene.events.emit('morningArrived', { day: this.day }); this.todayWeather = this.tomorrowWeather;
console.log(`🌅 Jutro! Dan ${this.day}, 06:00`); this.tomorrowWeather = Math.random() < 0.3 ? 'rain' : 'sun';
// Posodobimo globalno stanje, če obstaja
if (this.scene.gameState) {
this.scene.gameState.weather = this.todayWeather;
}
this.scene.events.emit('morningArrived', { day: this.day, weather: this.todayWeather });
this.scene.events.emit('weatherChanged', this.todayWeather);
console.log(`🌅 Jutro! Dan ${this.day}, 06:00. Današnje vreme: ${this.todayWeather}, Jutri: ${this.tomorrowWeather}`);
} }
if (this.hour === 20) { if (this.hour === 20) {
// Večer // Večer
@@ -166,19 +187,24 @@ export default class DayNightSystem {
} }
// ───────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────
// HOOK — Polnoč → Nov dan // HOOK — Polnoč → Nov dan in Leto
// ───────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────
_onMidnight() { _onMidnight() {
this.day++; this.day++;
console.log(`🌙 Polnoč → Dan ${this.day}!`); console.log(`🌙 Polnoč → Dan ${this.day}!`);
// Generacijski sistem (Staranje): Leto se obrne vsakih 120 dni
if (this.day % 120 === 1 && this.day > 1) {
this.year++;
console.log(`🎉 SREČNO NOVO LETO! Leto ${this.year} se je začelo!`);
this.scene.events.emit('yearChanged', { year: this.year, day: this.day });
}
// Shranimo takoj na polnoč
this.saveState();
// ── Farming tick ── // ── Farming tick ──
this.scene.events.emit('dayChanged', { day: this.day }); this.scene.events.emit('dayChanged', { day: this.day });
// ── Rain check (30% chance) ──
if (Math.random() < 0.3) {
this.scene.events.emit('rainDay', { day: this.day });
}
} }
// ───────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────
@@ -213,7 +239,7 @@ export default class DayNightSystem {
this.minute = 0; this.minute = 0;
// Emit morning events // Emit morning events
this.scene.events.emit('morningArrived', { day: this.day }); this.scene.events.emit('morningArrived', { day: this.day, weather: this.todayWeather });
this.scene.events.emit('timeChanged', { this.scene.events.emit('timeChanged', {
day: this.day, hour: 6, minute: 0, timeStr: '06:00' day: this.day, hour: 6, minute: 0, timeStr: '06:00'
}); });
@@ -270,7 +296,7 @@ export default class DayNightSystem {
} }
// Emit morning events // Emit morning events
this.scene.events.emit('morningArrived', { day: this.day }); this.scene.events.emit('morningArrived', { day: this.day, weather: this.todayWeather });
this.scene.events.emit('timeChanged', { this.scene.events.emit('timeChanged', {
day: this.day, hour: 6, minute: 0, timeStr: '06:00' day: this.day, hour: 6, minute: 0, timeStr: '06:00'
}); });
@@ -482,15 +508,52 @@ export default class DayNightSystem {
// ───────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────
getTimeStr() { return this._timeStr(); } getTimeStr() { return this._timeStr(); }
getDay() { return this.day; } getDay() { return this.day; }
getYear() { return this.year; }
getHour() { return this.hour; } getHour() { return this.hour; }
isNight() { return this.hour >= 22 || this.hour < 6; } isNight() { return this.hour >= 22 || this.hour < 6; }
isDay() { return this.hour >= 6 && this.hour < 20; } isDay() { return this.hour >= 6 && this.hour < 20; }
getTomorrowWeather() { return this.tomorrowWeather; }
getTodayWeather() { return this.todayWeather; }
/** Nastavi čas (za debug/testing) */ /** Nastavi čas (za debug/testing) */
setTime(hour, minute = 0) { setTime(hour, minute = 0) {
this.hour = hour; this.hour = hour;
this.minute = minute; this.minute = minute;
console.log(`⏰ Čas nastavljen: ${this._timeStr()}`); console.log(`⏰ Čas nastavljen: ${this._timeStr()}`);
this.saveState();
}
// ─────────────────────────────────────────────────────────────────────────
// TRAJNO SHRANJEVANJE (LOCALSTORAGE)
// ─────────────────────────────────────────────────────────────────────────
saveState() {
const state = {
day: this.day,
year: this.year,
hour: this.hour,
minute: this.minute,
todayWeather: this.todayWeather,
tomorrowWeather: this.tomorrowWeather
};
localStorage.setItem('nova_farma_time_save', JSON.stringify(state));
}
loadState() {
const saved = localStorage.getItem('nova_farma_time_save');
if (saved) {
try {
const data = JSON.parse(saved);
this.day = data.day || 1;
this.year = data.year || 1;
this.hour = data.hour !== undefined ? data.hour : 6;
this.minute = data.minute || 0;
this.todayWeather = data.todayWeather || 'sun';
this.tomorrowWeather = data.tomorrowWeather || 'sun';
console.log(`💾 Čas uspešno naložen! Dan: ${this.day}, Leto: ${this.year}, Ura: ${this._timeStr()}`);
} catch (e) {
console.warn("⚠️ Napaka pri branju časa iz LocalStorage", e);
}
}
} }
destroy() { destroy() {

View File

@@ -83,7 +83,7 @@ export default class WaterSystem {
sprite, sprite,
label, label,
current: 0, current: 0,
max: 20, max: 50,
}; };
this.rainCatchers.push(rc); this.rainCatchers.push(rc);
@@ -187,15 +187,15 @@ export default class WaterSystem {
onRain() { onRain() {
let total = 0; let total = 0;
for (const rc of this.rainCatchers) { for (const rc of this.rainCatchers) {
const collected = Math.min(this.rainCollectRate, rc.max - rc.current); const collected = rc.max - rc.current; // Napolni do 50L
rc.current += collected; rc.current = rc.max;
total += collected; total += collected;
this._updateLabel(rc); this._updateLabel(rc);
// Ripple animacija na RC // Ripple animacija na RC
this._rainRipple(rc.x, rc.y - 40); this._rainRipple(rc.x, rc.y - 40);
} }
if (total > 0) { if (total > 0) {
console.log(`🌧️ Dež zbral ${total}L v Rain Catcher-jih`); console.log(`🌧️ Dež napolnil Lovilec deževnice na polno (50L)!`);
} }
this.scene.events.emit('waterChanged', { this.scene.events.emit('waterChanged', {
can: this.canCurrent, can: this.canCurrent,