feat: Faza 1 Gameplay Loop - Kista, Sekanje, Gradnja, Kmetovanje, Dnevnik, Zombiji

- Starter Chest (Kista): Nov sprite asset (chest_closed.png), zamenjal rectangles z dejansko sliko, dodal axe reward ob odprtju
- Sekanje dreves: Zahteva Sekiro v rokah, padec drevesa odvrze 3 kose lesa (pickup sistem), unlock dnevniska vnosa
- Gradnja Barikad [B]: Nov wooden_fence.png asset, BuildingSystem posodobljen z leseno barikado (cena: 2 les), ghost preview z grid snappingom, deductItem() API
- Farming zanka: Popravljen seed property v InventorySystem, unlock ob prvem sajenju in zetvi
- Kaijev Dnevnik [J]: Novi JournalSystem.js s 6 vnosi, gotski UI z zlatimi okviri, animirano odpiranje, odklepanje ob napredku
- Zombie nochni napadi: Stopnjevano po nochih (max 8, hitrost do 65px/s, krajsi spawn delay), unlock dnevnika ob prvi nochi
- InventorySystem: Popravljen bug kjer tools niso bili dodani v hotbar, dodan axe in wood v ITEM_DEFS, nova deductItem() funkcija
- Pomoznna remove_bg.py skripta za odstranjevanje belega ozadja assetov
This commit is contained in:
2026-03-13 20:11:46 +01:00
parent 188bd769cf
commit b660429e3c
13 changed files with 860 additions and 131 deletions

View File

@@ -0,0 +1,137 @@
/**
* TwinBondSystem.js
*
* Sistem, ki občasno pošlje srhljiv telepatski signal (spomin/klic) od Ane.
* Ekran naključno utripne vijolično in se izpiše skrit tekst v glavi Kaja.
*/
export default class TwinBondSystem {
constructor(scene) {
this.scene = scene;
this.isActive = false;
// Overlay za vijoličen blisk
this.flashOverlay = scene.add.graphics()
.setDepth(9999)
.setScrollFactor(0);
// Tekst na sredini zaslona
const cx = scene.cameras.main.width / 2;
const cy = scene.cameras.main.height / 2;
this.messageText = scene.add.text(cx, cy - 100, '', {
fontFamily: 'Courier New',
fontSize: '42px',
color: '#ff99ff',
stroke: '#2b002b',
strokeThickness: 8,
align: 'center',
fontStyle: 'bold'
})
.setOrigin(0.5, 0.5)
.setDepth(10000)
.setScrollFactor(0)
.setAlpha(0);
// Nabor Aninih sporočil
this.messages = [
"K a i . . . n a j d i m e . . .",
"T u k a j d o l j e t e m a . . .",
"N e o b u p a j . . . T w i n B o n d d e l u j e .",
"K a i . . . b o l i m e . . .",
"P a z i s e n o č i . . ."
];
// Tipka za testiranje (tipka T)
this.keyT = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.T);
}
update(time, delta) {
// Testni sprožilec
if (Phaser.Input.Keyboard.JustDown(this.keyT) && !this.isActive) {
this.triggerBond();
}
// Naključno sprožanje (zelo majhna možnost ob igranju)
// 1 na 10,000 frejmov (~ vsake 3-5 minut)
if (Math.random() < 0.0001 && !this.isActive) {
// Samo če je zunaj spanja
this.triggerBond();
}
}
triggerBond() {
this.isActive = true;
// Zaustavi Kaja za kratek čas (šok)
if (this.scene.kai) {
this.scene.kai.canMove = false;
this.scene.kai.setVelocity(0, 0);
}
// 1. Zvok (Web Audio API srhljiv glitch freq)
this._playGlitchSound();
// 2. Narisemo purple flash, ki pokrije zaslon
const W = this.scene.cameras.main.width;
const H = this.scene.cameras.main.height;
this.flashOverlay.clear();
this.flashOverlay.fillStyle(0x3a0055, 0.85); // Temno vijolična
this.flashOverlay.fillRect(0, 0, W, H);
// Skrijemo čez 0.15s
this.scene.time.delayedCall(150, () => {
this.flashOverlay.clear();
});
// 3. Izberi random text in naredi typewriter
const text = Phaser.Utils.Array.GetRandom(this.messages);
this.messageText.setText('');
this.messageText.setAlpha(1);
let index = 0;
const typeTimer = this.scene.time.addEvent({
delay: 80,
repeat: text.length - 1,
callback: () => {
this.messageText.setText(text.substring(0, index + 1));
index++;
}
});
// 4. Fade out text in enable movement po 3 sekundah
this.scene.time.delayedCall(3000, () => {
this.scene.tweens.add({
targets: this.messageText,
alpha: 0,
duration: 1000,
onComplete: () => {
this.isActive = false;
if (this.scene.kai) {
this.scene.kai.canMove = true;
}
}
});
});
}
_playGlitchSound() {
if (!this.scene.sound.context) return;
const ctx = this.scene.sound.context;
const osc = ctx.createOscillator();
const gain = ctx.createGain();
// Srhljiv nizek zvok s frekvenčno modulacijo
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(120, ctx.currentTime);
osc.frequency.linearRampToValueAtTime(40, ctx.currentTime + 1.5);
gain.gain.setValueAtTime(0.3, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 1.5);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 1.5);
}
}