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:
BIN
assets/.DS_Store
vendored
BIN
assets/.DS_Store
vendored
Binary file not shown.
BIN
assets/DEMO_FAZA1/.DS_Store
vendored
BIN
assets/DEMO_FAZA1/.DS_Store
vendored
Binary file not shown.
BIN
nova farma TRAE/assets/DEMO_FAZA1/Buildings/chest_closed.png
Normal file
BIN
nova farma TRAE/assets/DEMO_FAZA1/Buildings/chest_closed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 472 KiB |
BIN
nova farma TRAE/assets/DEMO_FAZA1/Buildings/wooden_fence.png
Normal file
BIN
nova farma TRAE/assets/DEMO_FAZA1/Buildings/wooden_fence.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 298 KiB |
25
nova farma TRAE/remove_bg.py
Normal file
25
nova farma TRAE/remove_bg.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import sys
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
def process_image(input_path, output_path):
|
||||||
|
img = Image.open(input_path).convert("RGBA")
|
||||||
|
datas = img.getdata()
|
||||||
|
|
||||||
|
newData = []
|
||||||
|
# Convert white background to transparent
|
||||||
|
for item in datas:
|
||||||
|
# Check if the pixel color is white or close to white (tolerance)
|
||||||
|
if item[0] >= 240 and item[1] >= 240 and item[2] >= 240:
|
||||||
|
newData.append((255, 255, 255, 0)) # Replace with transparent
|
||||||
|
else:
|
||||||
|
newData.append(item)
|
||||||
|
|
||||||
|
img.putdata(newData)
|
||||||
|
img.save(output_path, "PNG")
|
||||||
|
print(f"Saved {output_path}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print("Usage: python remove_bg.py <input> <output>")
|
||||||
|
else:
|
||||||
|
process_image(sys.argv[1], sys.argv[2])
|
||||||
@@ -4,6 +4,8 @@ import WaterSystem from '../systems/WaterSystem.js';
|
|||||||
import DayNightSystem from '../systems/DayNightSystem.js';
|
import DayNightSystem from '../systems/DayNightSystem.js';
|
||||||
import InventorySystem from '../systems/InventorySystem.js';
|
import InventorySystem from '../systems/InventorySystem.js';
|
||||||
import ZombieSystem from '../systems/ZombieSystem.js';
|
import ZombieSystem from '../systems/ZombieSystem.js';
|
||||||
|
import TwinBondSystem from '../systems/TwinBondSystem.js';
|
||||||
|
import JournalSystem from '../systems/JournalSystem.js';
|
||||||
|
|
||||||
export default class GrassSceneClean extends Phaser.Scene {
|
export default class GrassSceneClean extends Phaser.Scene {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -117,6 +119,7 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
this.load.image('campfire', 'DEMO_FAZA1/Environment/taborni_ogenj.png');
|
this.load.image('campfire', 'DEMO_FAZA1/Environment/taborni_ogenj.png');
|
||||||
this.load.image('tent', 'DEMO_FAZA1/Environment/sotor.png');
|
this.load.image('tent', 'DEMO_FAZA1/Environment/sotor.png');
|
||||||
this.load.image('sleeping_bag', 'DEMO_FAZA1/Items/spalna_vreca.png');
|
this.load.image('sleeping_bag', 'DEMO_FAZA1/Items/spalna_vreca.png');
|
||||||
|
this.load.image('chest_closed', 'DEMO_FAZA1/Buildings/chest_closed.png');
|
||||||
|
|
||||||
// 7. NEW: Gronk & Structures
|
// 7. NEW: Gronk & Structures
|
||||||
this.load.spritesheet('gronk', 'DEMO_FAZA1/Characters/gronk_walk_sheet.png', {
|
this.load.spritesheet('gronk', 'DEMO_FAZA1/Characters/gronk_walk_sheet.png', {
|
||||||
@@ -137,6 +140,9 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
|
|
||||||
// 11. Zombie System Assets
|
// 11. Zombie System Assets
|
||||||
ZombieSystem.preload(this);
|
ZombieSystem.preload(this);
|
||||||
|
|
||||||
|
// 12. Building System Assets
|
||||||
|
this.load.image('wooden_fence', 'DEMO_FAZA1/Buildings/wooden_fence.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
@@ -202,6 +208,35 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
// SMOOTH RENDERING: Linear filter (no pixelation)
|
// SMOOTH RENDERING: Linear filter (no pixelation)
|
||||||
sprite.texture.setFilter(Phaser.Textures.FilterMode.LINEAR);
|
sprite.texture.setFilter(Phaser.Textures.FilterMode.LINEAR);
|
||||||
|
|
||||||
|
// PHYSICS & INTERACTION
|
||||||
|
this.physics.add.existing(sprite, true); // true = static body
|
||||||
|
if (sprite.body) {
|
||||||
|
// Trunk size roughly matching the visual base
|
||||||
|
sprite.body.setSize(sprite.width * scale * 0.4, 40);
|
||||||
|
sprite.body.setOffset(sprite.width * 0.3, sprite.height - 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite.health = 3;
|
||||||
|
sprite.isChopping = false;
|
||||||
|
sprite.setInteractive({ useHandCursor: true });
|
||||||
|
sprite.on('pointerdown', () => {
|
||||||
|
const dist = Phaser.Math.Distance.Between(this.scene?.kai?.x || this.kai?.x, this.scene?.kai?.y || this.kai?.y, sprite.x, sprite.y);
|
||||||
|
|
||||||
|
if (dist < 150) {
|
||||||
|
// Preveri če ima igralec izbrano sekiro v rokah
|
||||||
|
const activeItemKey = this.inventorySystem?.hotbar[this.inventorySystem?.activeSlot];
|
||||||
|
const activeItemDef = activeItemKey ? this.inventorySystem?.ITEM_DEFS[activeItemKey] : null;
|
||||||
|
|
||||||
|
if (activeItemDef && activeItemDef.tool === 'axe') {
|
||||||
|
this.chopTree(sprite);
|
||||||
|
} else {
|
||||||
|
if (this.inventorySystem) {
|
||||||
|
this.inventorySystem._showMsg('Rabiš Sekiro v rokah!', '#ff4444');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,17 +392,13 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
|
|
||||||
// FAILSAFE 2: Use simple Rectangles instead of TileSprites/Textures to STOP OOM.
|
// FAILSAFE 2: Use simple Rectangles instead of TileSprites/Textures to STOP OOM.
|
||||||
// We will add waves later if stability allows.
|
// We will add waves later if stability allows.
|
||||||
const viewW = this.scale.width || 1280;
|
// Ustvarimo dva velika modra pravokotnika kot 'bazen', v katerem je otok
|
||||||
const viewH = this.scale.height || 720;
|
this.oceanLayer1 = this.add.rectangle(WORLD_W / 2, WORLD_H / 2, WORLD_W + 2000, WORLD_H + 2000, 0x004488)
|
||||||
|
|
||||||
this.oceanLayer1 = this.add.rectangle(viewW / 2, viewH / 2, viewW + 100, viewH + 100, 0x004488)
|
|
||||||
.setScrollFactor(0)
|
|
||||||
.setDepth(-290)
|
.setDepth(-290)
|
||||||
.setAlpha(0.5);
|
.setAlpha(0.5);
|
||||||
|
|
||||||
// Optional: Second layer for depth effect
|
// Optional: Second layer for depth effect
|
||||||
this.oceanLayer2 = this.add.rectangle(viewW / 2, viewH / 2, viewW + 100, viewH + 100, 0x002244)
|
this.oceanLayer2 = this.add.rectangle(WORLD_W / 2, WORLD_H / 2, WORLD_W + 2000, WORLD_H + 2000, 0x002244)
|
||||||
.setScrollFactor(0)
|
|
||||||
.setDepth(-295) // Behind
|
.setDepth(-295) // Behind
|
||||||
.setAlpha(1.0);
|
.setAlpha(1.0);
|
||||||
|
|
||||||
@@ -960,34 +991,95 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
this.physics.add.overlap(this.kai, this.sleepingBag, () => {
|
this.physics.add.overlap(this.kai, this.sleepingBag, () => {
|
||||||
if (this.lastCheckpointTime && this.time.now - this.lastCheckpointTime < 5000) return;
|
if (this.lastCheckpointTime && this.time.now - this.lastCheckpointTime < 5000) return;
|
||||||
|
|
||||||
this.saveCheckpoint(this.sleepingBag.x, this.sleepingBag.y);
|
|
||||||
this.lastCheckpointTime = this.time.now;
|
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
console.log('SPALNA VREČA ODSTRANJENA');
|
// ─── SPALNA VREČA & STARTER CHEST (Kišta) ────────────────────────
|
||||||
|
this.sleepingBag = this.physics.add.image(SPAWN_X + 150, 5600, 'sleeping_bag');
|
||||||
|
this.sleepingBag.setOrigin(0.5, 1.0);
|
||||||
|
this.sleepingBag.setScale(0.3);
|
||||||
|
this.sleepingBag.setDepth(this.sleepingBag.y);
|
||||||
|
|
||||||
// ===================================================================
|
this.starterChest = this.physics.add.image(SPAWN_X - 100, 5600, 'chest_closed');
|
||||||
// TEST: AUTO-LOADER DEMO
|
this.starterChest.setOrigin(0.5, 1.0);
|
||||||
// ===================================================================
|
this.starterChest.setScale(0.18);
|
||||||
// Place test vegetation and tree to verify grounding system
|
this.starterChest.setDepth(5600);
|
||||||
|
this.starterChest.body.setSize(this.starterChest.width * 0.18, this.starterChest.height * 0.18);
|
||||||
|
this.starterChest.body.setImmovable(true);
|
||||||
|
this.starterChest.opened = false;
|
||||||
|
|
||||||
const testTileBottom = SPAWN_Y + 200; // Tile bottom Y position
|
let chestText = this.add.text(SPAWN_X - 100, 5600 - 100, '[E] Odpri Kišto', { fontFamily: 'Arial Black', fontSize: '13px', color: '#ffdd00', stroke: '#000', strokeThickness: 4, align: 'center' }).setOrigin(0.5, 0.5);
|
||||||
|
chestText.setDepth(9999);
|
||||||
|
|
||||||
// TEST 1: Vegetation (28px height, 4px burial)
|
this.input.keyboard.on('keydown-E', () => {
|
||||||
this.testGrass = this.loadVegetation(
|
if (this.starterChest.opened) return;
|
||||||
SPAWN_X - 100, // Left of Kai
|
const dist = Phaser.Math.Distance.Between(this.kai.x, this.kai.y, this.starterChest.x, this.starterChest.y);
|
||||||
testTileBottom,
|
if (dist < 150) {
|
||||||
'grass_ref_1'
|
this.starterChest.opened = true;
|
||||||
);
|
chestText.setText('📦 Prazno\n(Vse pobrano)');
|
||||||
console.log('🌿 TEST: Grass loaded at 28px with 4px burial');
|
chestText.setColor('#888888');
|
||||||
|
|
||||||
// TEST 2: Tree (160px height, 8px burial)
|
this.tweens.add({
|
||||||
this.testTree = this.loadTree(
|
targets: this.starterChest,
|
||||||
SPAWN_X + 100, // Right of Kai
|
y: this.starterChest.y - 20,
|
||||||
testTileBottom,
|
yoyo: true,
|
||||||
'tree_adult_0'
|
duration: 150,
|
||||||
);
|
onComplete: () => {
|
||||||
console.log('🌳 TEST: Oak loaded at 160px with 8px burial');
|
this.starterChest.setTint(0x888888);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add items directly to Inventory
|
||||||
|
this.inventorySystem.addItem('axe', 1);
|
||||||
|
this.inventorySystem.addItem('hoe', 1);
|
||||||
|
this.inventorySystem.addItem('watering_can', 1);
|
||||||
|
this.inventorySystem.addItem('wheat_seed', 5);
|
||||||
|
this.inventorySystem.addItem('carrot_seed', 5);
|
||||||
|
|
||||||
|
// UI Message
|
||||||
|
this.inventorySystem._showMsg('Pobral si Orodje in Semena!', '#44ff44');
|
||||||
|
if (this.journalSystem) this.journalSystem.unlockEntry('start');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// ─────────────────────────────────────────────────────────────────
|
||||||
|
// === RANDOM TREE GENERATION (AUTO-LOADER) ===
|
||||||
|
this.treesGroup = this.physics.add.staticGroup();
|
||||||
|
|
||||||
|
const treeKeys = ['tree_adult_0', 'tree_adult_1', 'tree_adult_2', 'tree_adult_3', 'tree_adult_4', 'tree_adult_5'];
|
||||||
|
const TREE_COUNT = 40;
|
||||||
|
|
||||||
|
for (let i = 0; i < TREE_COUNT; i++) {
|
||||||
|
// Place on random edge to keep center farming area free
|
||||||
|
const edge = Math.floor(Math.random() * 4);
|
||||||
|
let tx, ty;
|
||||||
|
const PADDING = 200;
|
||||||
|
|
||||||
|
switch (edge) {
|
||||||
|
case 0: // Top
|
||||||
|
tx = this.islandX + Math.random() * this.islandWidth;
|
||||||
|
ty = this.islandY + PADDING + Math.random() * 300;
|
||||||
|
break;
|
||||||
|
case 1: // Right
|
||||||
|
tx = this.islandX + this.islandWidth - PADDING - Math.random() * 300;
|
||||||
|
ty = this.islandY + Math.random() * this.islandHeight;
|
||||||
|
break;
|
||||||
|
case 2: // Bottom
|
||||||
|
tx = this.islandX + Math.random() * this.islandWidth;
|
||||||
|
ty = this.islandY + this.islandHeight - PADDING - Math.random() * 300;
|
||||||
|
break;
|
||||||
|
case 3: // Left
|
||||||
|
tx = this.islandX + PADDING + Math.random() * 300;
|
||||||
|
ty = this.islandY + Math.random() * this.islandHeight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tKey = Phaser.Utils.Array.GetRandom(treeKeys);
|
||||||
|
let t = this.loadTree(tx, ty, tKey);
|
||||||
|
t.setMask(this.islandMask);
|
||||||
|
this.treesGroup.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add solid collision against trees!
|
||||||
|
this.physics.add.collider(this.kai, this.treesGroup);
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
// Adjust Physics Body for larger size
|
// Adjust Physics Body for larger size
|
||||||
@@ -1105,6 +1197,9 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
|
|
||||||
console.log('🏗️ Building System initialized — press [B] to open build mode');
|
console.log('🏗️ Building System initialized — press [B] to open build mode');
|
||||||
|
|
||||||
|
// === JOURNAL SYSTEM (Kaijev Dnevnik) ===
|
||||||
|
this.journalSystem = new JournalSystem(this);
|
||||||
|
|
||||||
// === ZAŽENIMO UIScene kot overlay (HUD sloj) ===
|
// === ZAŽENIMO UIScene kot overlay (HUD sloj) ===
|
||||||
if (!this.scene.isActive('UIScene')) {
|
if (!this.scene.isActive('UIScene')) {
|
||||||
this.scene.launch('UIScene');
|
this.scene.launch('UIScene');
|
||||||
@@ -1309,11 +1404,8 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Registriraj spalno vrečo kot sleep objekt
|
// Registriraj dejansko spalno vrečo
|
||||||
// (spawn point je center otoka)
|
this.dayNightSystem.registerSleepObject(this.sleepingBag.x, this.sleepingBag.y, this.sleepingBag, 'sleeping_bag');
|
||||||
const sleepX = this.islandX + this.islandWidth / 2;
|
|
||||||
const sleepY = this.islandY + this.islandHeight / 2;
|
|
||||||
this.dayNightSystem.registerSleepObject(sleepX, sleepY, null, 'sleeping_bag');
|
|
||||||
|
|
||||||
console.log('✅ DayNightSystem ready — [Z] za spanje, 1 min/s!');
|
console.log('✅ DayNightSystem ready — [Z] za spanje, 1 min/s!');
|
||||||
|
|
||||||
@@ -1346,6 +1438,10 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
});
|
});
|
||||||
this.zombieSystem.createAnimations();
|
this.zombieSystem.createAnimations();
|
||||||
|
|
||||||
|
// ─── TWIN BOND (Telepathy) SYSTEM ─────────────────────────
|
||||||
|
this.twinBondSystem = new TwinBondSystem(this);
|
||||||
|
console.log('✅ TwinBondSystem ready!');
|
||||||
|
|
||||||
// Noč → Začni spawnat
|
// Noč → Začni spawnat
|
||||||
this.events.on('nightArrived', () => {
|
this.events.on('nightArrived', () => {
|
||||||
this.zombieSystem.startNightSpawning();
|
this.zombieSystem.startNightSpawning();
|
||||||
@@ -1434,6 +1530,42 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
|
|
||||||
tree.destroy();
|
tree.destroy();
|
||||||
|
|
||||||
|
// Odkleni dnevniski vnos ob prvem podrtju drevesa
|
||||||
|
if (this.journalSystem && !this._firstTreeFelled) {
|
||||||
|
this._firstTreeFelled = true;
|
||||||
|
this.time.delayedCall(800, () => {
|
||||||
|
this.journalSystem.unlockEntry('first_tree');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop wood visual (3 pieces)
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
let wx = tx + (Math.random() - 0.5) * 100;
|
||||||
|
let wy = ty - 50 + (Math.random() - 0.5) * 50;
|
||||||
|
let w = this.add.text(wx, wy, '🪵', { fontSize: '35px' }).setOrigin(0.5);
|
||||||
|
w.setDepth(wy); // y-sorting
|
||||||
|
this.physics.add.existing(w);
|
||||||
|
w.body.setSize(40, 40);
|
||||||
|
|
||||||
|
// Simple jump/pop animation for the drop
|
||||||
|
this.tweens.add({
|
||||||
|
targets: w,
|
||||||
|
y: wy - 40,
|
||||||
|
duration: 200,
|
||||||
|
yoyo: true,
|
||||||
|
ease: 'Quad.easeOut'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add collision to collect it
|
||||||
|
this.physics.add.overlap(this.kai, w, () => {
|
||||||
|
w.destroy();
|
||||||
|
if (this.inventorySystem) {
|
||||||
|
this.inventorySystem.addItem('wood', 1);
|
||||||
|
this.inventorySystem._showMsg('+1 Les', '#ddaa00');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 3. AUTO-REPLANT (Spawn Grass Clump)
|
// 3. AUTO-REPLANT (Spawn Grass Clump)
|
||||||
this.spawnReplant(tx, ty); // Use generic regrowth for consistency if desired, or keep as specialized spawn
|
this.spawnReplant(tx, ty); // Use generic regrowth for consistency if desired, or keep as specialized spawn
|
||||||
}
|
}
|
||||||
@@ -1795,6 +1927,10 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// --- PLAYER MOVEMENT (SMOOTHENED) ---
|
// --- PLAYER MOVEMENT (SMOOTHENED) ---
|
||||||
|
if (this.kai.canMove === false) {
|
||||||
|
this.kai.setVelocity(0, 0);
|
||||||
|
this.kai.anims.stop();
|
||||||
|
} else {
|
||||||
const speed = 500;
|
const speed = 500;
|
||||||
const velocity = new Phaser.Math.Vector2(0, 0);
|
const velocity = new Phaser.Math.Vector2(0, 0);
|
||||||
|
|
||||||
@@ -1825,6 +1961,7 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
this.kai.setVelocity(0, 0);
|
this.kai.setVelocity(0, 0);
|
||||||
this.kai.anims.stop();
|
this.kai.anims.stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// === ULTRA CLEAN: Only Kai depth sorting ===
|
// === ULTRA CLEAN: Only Kai depth sorting ===
|
||||||
@@ -1877,6 +2014,11 @@ export default class GrassSceneClean extends Phaser.Scene {
|
|||||||
this.zombieSystem.update(this.kai, delta);
|
this.zombieSystem.update(this.kai, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === TWIN BOND SYSTEM UPDATE ===
|
||||||
|
if (this.twinBondSystem) {
|
||||||
|
this.twinBondSystem.update(time, delta);
|
||||||
|
}
|
||||||
|
|
||||||
// === FARMING SYSTEM UPDATE ===
|
// === FARMING SYSTEM UPDATE ===
|
||||||
if (this.farmingSystem) {
|
if (this.farmingSystem) {
|
||||||
this.farmingSystem.update(this.kai, time);
|
this.farmingSystem.update(this.kai, time);
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ export default class BuildingSystem {
|
|||||||
|
|
||||||
// Katalog stavb — tukaj dodajamo nove
|
// Katalog stavb — tukaj dodajamo nove
|
||||||
this.catalogue = [
|
this.catalogue = [
|
||||||
|
{
|
||||||
|
key: 'wooden_fence',
|
||||||
|
label: 'Lesena Barikada',
|
||||||
|
scale: 0.5,
|
||||||
|
colliderW: 80,
|
||||||
|
colliderH: 20,
|
||||||
|
colliderOffsetX: -5,
|
||||||
|
colliderOffsetY: 0,
|
||||||
|
cost: { item: 'wood', amount: 2 }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'sotor',
|
key: 'sotor',
|
||||||
label: 'Šotor',
|
label: 'Šotor',
|
||||||
@@ -48,24 +58,6 @@ export default class BuildingSystem {
|
|||||||
colliderOffsetX: -25,
|
colliderOffsetX: -25,
|
||||||
colliderOffsetY: -20,
|
colliderOffsetY: -20,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'rain_catcher',
|
|
||||||
label: 'Zbirač dežja',
|
|
||||||
scale: 2.0,
|
|
||||||
colliderW: 140,
|
|
||||||
colliderH: 40,
|
|
||||||
colliderOffsetX: -70,
|
|
||||||
colliderOffsetY: -40,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'foundation_concrete',
|
|
||||||
label: 'Betonski temelj',
|
|
||||||
scale: 2.0,
|
|
||||||
colliderW: 120,
|
|
||||||
colliderH: 20,
|
|
||||||
colliderOffsetX: -60,
|
|
||||||
colliderOffsetY: -20,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
this._setupInput();
|
this._setupInput();
|
||||||
@@ -99,7 +91,7 @@ export default class BuildingSystem {
|
|||||||
if (!this._modeTip) {
|
if (!this._modeTip) {
|
||||||
this._modeTip = this.scene.add.text(
|
this._modeTip = this.scene.add.text(
|
||||||
this.scene.cameras.main.width / 2, 20,
|
this.scene.cameras.main.width / 2, 20,
|
||||||
'🏗️ NAČIN GRADNJE | Klik = postavi | B / Esc = izhod',
|
'🏗️ NAČIN GRADNJE | 🖱️ postavi | B / Esc izhod | R rotacija',
|
||||||
{
|
{
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: '#44ffaa',
|
color: '#44ffaa',
|
||||||
@@ -164,12 +156,30 @@ export default class BuildingSystem {
|
|||||||
|
|
||||||
const wx = pointer.worldX;
|
const wx = pointer.worldX;
|
||||||
const wy = pointer.worldY;
|
const wy = pointer.worldY;
|
||||||
this.ghost.setPosition(wx, wy);
|
|
||||||
|
|
||||||
// Zelena = na otoku, Rdeča = zunaj
|
// Snapping na grid 32px
|
||||||
|
const grid = 32;
|
||||||
|
const finalX = Math.round(wx / grid) * grid;
|
||||||
|
const finalY = Math.round(wy / grid) * grid;
|
||||||
|
|
||||||
|
this.ghost.setPosition(finalX, finalY);
|
||||||
|
|
||||||
|
// Preveri surovine in lokacijo
|
||||||
|
const def = this.catalogue.find(c => c.key === this.selectedKey);
|
||||||
|
let ok = true;
|
||||||
|
|
||||||
const b = this.scene.physics.world.bounds;
|
const b = this.scene.physics.world.bounds;
|
||||||
const ok = wx > b.x && wx < b.x + b.width &&
|
if (finalX <= b.x || finalX >= b.x + b.width || finalY <= b.y || finalY >= b.y + b.height) {
|
||||||
wy > b.y && wy < b.y + b.height;
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def && def.cost && this.scene.inventorySystem) {
|
||||||
|
const item = this.scene.inventorySystem.items[def.cost.item];
|
||||||
|
if (!item || item.count < def.cost.amount) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.ghost.setTint(ok ? 0x44ffaa : 0xff4444);
|
this.ghost.setTint(ok ? 0x44ffaa : 0xff4444);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,28 +187,31 @@ export default class BuildingSystem {
|
|||||||
// PLACE BUILDING (ob kliku)
|
// PLACE BUILDING (ob kliku)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
placeBuilding(worldX, worldY) {
|
placeBuilding(worldX, worldY) {
|
||||||
if (!this.active || !this.selectedKey) return;
|
if (!this.active || !this.selectedKey || !this.ghost) return;
|
||||||
|
|
||||||
const def = this.catalogue.find(c => c.key === this.selectedKey);
|
const def = this.catalogue.find(c => c.key === this.selectedKey);
|
||||||
if (!def) return;
|
if (!def) return;
|
||||||
|
|
||||||
|
const finalX = this.ghost.x;
|
||||||
|
const finalY = this.ghost.y;
|
||||||
|
|
||||||
// Validacija — mora biti na otoku
|
// Validacija — mora biti na otoku
|
||||||
const b = this.scene.physics.world.bounds;
|
const b = this.scene.physics.world.bounds;
|
||||||
if (worldX <= b.x || worldX >= b.x + b.width ||
|
if (finalX <= b.x || finalX >= b.x + b.width || finalY <= b.y || finalY >= b.y + b.height) {
|
||||||
worldY <= b.y || worldY >= b.y + b.height) {
|
this._flashGhost();
|
||||||
// Flash rdeče
|
|
||||||
if (this.ghost) {
|
|
||||||
this.scene.tweens.add({
|
|
||||||
targets: this.ghost,
|
|
||||||
alpha: { from: 0.9, to: 0.2 },
|
|
||||||
duration: 80,
|
|
||||||
yoyo: true,
|
|
||||||
repeat: 2,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validacija surovin
|
||||||
|
if (def.cost && this.scene.inventorySystem) {
|
||||||
|
const item = this.scene.inventorySystem.items[def.cost.item];
|
||||||
|
if (!this.scene.inventorySystem.deductItem(def.cost.item, def.cost.amount)) {
|
||||||
|
this._flashGhost();
|
||||||
|
this.scene.inventorySystem._showMsg(`Premalo ${def.cost.item}!`, '#ff4444');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Izračun scale
|
// Izračun scale
|
||||||
const KAI_H = 64;
|
const KAI_H = 64;
|
||||||
const targetH = KAI_H * def.scale;
|
const targetH = KAI_H * def.scale;
|
||||||
@@ -207,18 +220,18 @@ export default class BuildingSystem {
|
|||||||
const scale = targetH / srcH;
|
const scale = targetH / srcH;
|
||||||
|
|
||||||
// Ustvari static physics image
|
// Ustvari static physics image
|
||||||
const building = this.scene.physics.add.staticImage(worldX, worldY, this.selectedKey)
|
const building = this.scene.physics.add.staticImage(finalX, finalY, this.selectedKey)
|
||||||
.setScale(scale)
|
.setScale(scale)
|
||||||
.setOrigin(0.5, 1.0)
|
.setOrigin(0.5, 1.0)
|
||||||
.setDepth(worldY);
|
.setDepth(finalY);
|
||||||
|
|
||||||
// Physics collider body (samo baza stavbe)
|
// Physics collider body (samo baza stavbe)
|
||||||
building.body.setSize(def.colliderW, def.colliderH);
|
building.body.setSize(def.colliderW, def.colliderH);
|
||||||
building.body.setOffset(
|
building.body.setOffset(
|
||||||
(texture.getSourceImage().width * scale) / 2 + def.colliderOffsetX,
|
def.colliderOffsetX || 0,
|
||||||
srcH * scale + def.colliderOffsetY
|
def.colliderOffsetY || 0
|
||||||
);
|
);
|
||||||
building.body.reset(worldX, worldY);
|
building.body.reset(finalX, finalY);
|
||||||
|
|
||||||
// Collider med Kai in stavbo
|
// Collider med Kai in stavbo
|
||||||
this.buildingsGroup.add(building, true);
|
this.buildingsGroup.add(building, true);
|
||||||
@@ -234,7 +247,7 @@ export default class BuildingSystem {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Flash feedback
|
// Flash feedback
|
||||||
const flash = this.scene.add.rectangle(worldX, worldY - targetH * 0.5, 80, 80, 0x44ffaa, 0.6)
|
const flash = this.scene.add.rectangle(finalX, finalY - targetH * 0.5, 80, 80, 0x44ffaa, 0.6)
|
||||||
.setDepth(99998);
|
.setDepth(99998);
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: flash,
|
targets: flash,
|
||||||
@@ -243,12 +256,20 @@ export default class BuildingSystem {
|
|||||||
onComplete: () => flash.destroy(),
|
onComplete: () => flash.destroy(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Shrani referenco za Y-sort v update()
|
this.placed.push({ key: this.selectedKey, x: finalX, y: finalY });
|
||||||
this.scene._buildingSprites = this.scene._buildingSprites || [];
|
|
||||||
this.scene._buildingSprites.push(building);
|
|
||||||
|
|
||||||
this.placed.push({ key: this.selectedKey, x: worldX, y: worldY });
|
console.log(`🏗️ Placed: ${this.selectedKey} @ (${Math.round(finalX)}, ${Math.round(finalY)})`);
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`🏗️ Placed: ${this.selectedKey} @ (${Math.round(worldX)}, ${Math.round(worldY)})`);
|
_flashGhost() {
|
||||||
|
if (this.ghost) {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.ghost,
|
||||||
|
alpha: { from: 0.9, to: 0.2 },
|
||||||
|
duration: 80,
|
||||||
|
yoyo: true,
|
||||||
|
repeat: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,8 @@ export default class DayNightSystem {
|
|||||||
// Input [Z] za spanje
|
// Input [Z] za spanje
|
||||||
this.keyZ = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z);
|
this.keyZ = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z);
|
||||||
|
|
||||||
// Ambient Graphics (overlay za noč)
|
// Ambient Graphics (overlay za noč) - Pokriva celoten svet!
|
||||||
this.ambientOverlay = scene.add.graphics()
|
this.ambientOverlay = scene.add.graphics()
|
||||||
.setScrollFactor(0)
|
|
||||||
.setDepth(4500); // Pod UIScene (depth 5000+), nad svetom
|
.setDepth(4500); // Pod UIScene (depth 5000+), nad svetom
|
||||||
|
|
||||||
// Star particles za noč
|
// Star particles za noč
|
||||||
@@ -273,7 +272,10 @@ export default class DayNightSystem {
|
|||||||
(r << 16) | (g << 8) | b,
|
(r << 16) | (g << 8) | b,
|
||||||
alpha
|
alpha
|
||||||
);
|
);
|
||||||
this.ambientOverlay.fillRect(0, 0, W, H);
|
// Ker imava izklopljen GPU, .setScrollFactor(0) včasih povzroča
|
||||||
|
// težave pri zoomu. Zato je NAJSIGURNEJE preprosto narisati čez celoten 'svet' (10000x10000)
|
||||||
|
// Tako bo "celoten otok" vedno pokrit, neglede na kamero in pozicijo!
|
||||||
|
this.ambientOverlay.fillRect(-2000, -2000, 15000, 15000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,15 +284,14 @@ export default class DayNightSystem {
|
|||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
_initStars() {
|
_initStars() {
|
||||||
const W = this.scene.cameras.main.width;
|
const W = this.scene.cameras.main.width;
|
||||||
const H = this.scene.cameras.main.height;
|
|
||||||
this.starGfx = this.scene.add.graphics()
|
this.starGfx = this.scene.add.graphics()
|
||||||
.setScrollFactor(0)
|
|
||||||
.setDepth(4499);
|
.setDepth(4499);
|
||||||
|
|
||||||
for (let i = 0; i < 80; i++) {
|
// Zvezde raztrosimo čez celoten svet (zgoraj)
|
||||||
|
for (let i = 0; i < 400; i++) {
|
||||||
this.stars.push({
|
this.stars.push({
|
||||||
x: Math.random() * W,
|
x: -2000 + Math.random() * 12000,
|
||||||
y: Math.random() * H * 0.6, // Samo zgoraj
|
y: -2000 + Math.random() * 8000,
|
||||||
size: 0.5 + Math.random() * 1.5,
|
size: 0.5 + Math.random() * 1.5,
|
||||||
twinkle: Math.random() * Math.PI * 2,
|
twinkle: Math.random() * Math.PI * 2,
|
||||||
speed: 0.5 + Math.random() * 1.5,
|
speed: 0.5 + Math.random() * 1.5,
|
||||||
|
|||||||
@@ -323,6 +323,12 @@ export default class FarmingSystem {
|
|||||||
|
|
||||||
this._showFloatingText(plot.x, plot.y - 30, `🌱 ${cropKey}!`, '#88ff88', 18);
|
this._showFloatingText(plot.x, plot.y - 30, `🌱 ${cropKey}!`, '#88ff88', 18);
|
||||||
console.log(`🌱 Posajeno: ${cropKey} @ day ${this.currentDay}`);
|
console.log(`🌱 Posajeno: ${cropKey} @ day ${this.currentDay}`);
|
||||||
|
|
||||||
|
// Odkleni dnevniški vnos ob prvem sajenju
|
||||||
|
if (!this._firstPlant && this.scene.journalSystem) {
|
||||||
|
this._firstPlant = true;
|
||||||
|
this.scene.journalSystem.unlockEntry('first_plant');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
@@ -421,6 +427,14 @@ export default class FarmingSystem {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log(`🌾 Harvest: ${def.harvestItem} ×${count} = ${value}g`);
|
console.log(`🌾 Harvest: ${def.harvestItem} ×${count} = ${value}g`);
|
||||||
|
|
||||||
|
// Odkleni dnevniški vnos ob prvi žetvi
|
||||||
|
if (!this._firstHarvest && this.scene.journalSystem) {
|
||||||
|
this._firstHarvest = true;
|
||||||
|
this.scene.time.delayedCall(500, () => {
|
||||||
|
this.scene.journalSystem.unlockEntry('first_harvest');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -29,17 +29,17 @@ export default class InventorySystem {
|
|||||||
this.items = {};
|
this.items = {};
|
||||||
// Format: { 'wheat_seed': { name, icon, count, type, tool/seed } }
|
// Format: { 'wheat_seed': { name, icon, count, type, tool/seed } }
|
||||||
|
|
||||||
// Hotbar = 7 slotov, vsak kaže na item key ali null
|
// Hotbar = 7 slotov, vsak kaže na item key ali null (začenjamo prazni!)
|
||||||
this.hotbar = [
|
this.hotbar = [
|
||||||
'hoe',
|
null,
|
||||||
'watering_can',
|
null,
|
||||||
'wheat_seed',
|
null,
|
||||||
'carrot_seed',
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
];
|
];
|
||||||
this.activeSlot = 0; // Slot 1 = Motika
|
this.activeSlot = 0; // Slot 1
|
||||||
|
|
||||||
// Item definicije
|
// Item definicije
|
||||||
this.ITEM_DEFS = {
|
this.ITEM_DEFS = {
|
||||||
@@ -61,6 +61,15 @@ export default class InventorySystem {
|
|||||||
count: 1,
|
count: 1,
|
||||||
desc: '[E] Zalij rastlino',
|
desc: '[E] Zalij rastlino',
|
||||||
},
|
},
|
||||||
|
axe: {
|
||||||
|
name: 'Sekira',
|
||||||
|
icon: '🪓',
|
||||||
|
type: 'tool',
|
||||||
|
tool: 'axe',
|
||||||
|
stackable: false,
|
||||||
|
count: 1,
|
||||||
|
desc: '[M1] Podri drevo',
|
||||||
|
},
|
||||||
wheat_seed: {
|
wheat_seed: {
|
||||||
name: 'Pšenica',
|
name: 'Pšenica',
|
||||||
icon: '🌾',
|
icon: '🌾',
|
||||||
@@ -88,8 +97,9 @@ export default class InventorySystem {
|
|||||||
seed: 'cannabis',
|
seed: 'cannabis',
|
||||||
stackable: true,
|
stackable: true,
|
||||||
count: 0,
|
count: 0,
|
||||||
desc: '7 dni • 200g/harvest',
|
desc: '[E] Posadi na preorano',
|
||||||
color: '#88cc44',
|
color: '#88cc44',
|
||||||
|
value: 50,
|
||||||
},
|
},
|
||||||
// Harvested items
|
// Harvested items
|
||||||
wheat: {
|
wheat: {
|
||||||
@@ -116,6 +126,14 @@ export default class InventorySystem {
|
|||||||
count: 0,
|
count: 0,
|
||||||
value: 200,
|
value: 200,
|
||||||
},
|
},
|
||||||
|
wood: {
|
||||||
|
name: 'Les',
|
||||||
|
icon: '🪵',
|
||||||
|
type: 'resource',
|
||||||
|
stackable: true,
|
||||||
|
count: 0,
|
||||||
|
value: 10,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inicializiraj items iz ITEM_DEFS (samo tiste s count > 0)
|
// Inicializiraj items iz ITEM_DEFS (samo tiste s count > 0)
|
||||||
@@ -169,9 +187,9 @@ export default class InventorySystem {
|
|||||||
}
|
}
|
||||||
this.items[key].count += count;
|
this.items[key].count += count;
|
||||||
|
|
||||||
// Dodaj v hotbar če je prazen slot + seme/resource
|
// Dodaj v hotbar če je prazen slot in item še ni v hotbaru
|
||||||
const def = this.ITEM_DEFS[key];
|
const def = this.ITEM_DEFS[key];
|
||||||
if (def && def.stackable && !this.hotbar.includes(key)) {
|
if (def && !this.hotbar.includes(key)) {
|
||||||
const emptySlot = this.hotbar.findIndex(s => s === null);
|
const emptySlot = this.hotbar.findIndex(s => s === null);
|
||||||
if (emptySlot !== -1) this.hotbar[emptySlot] = key;
|
if (emptySlot !== -1) this.hotbar[emptySlot] = key;
|
||||||
}
|
}
|
||||||
@@ -186,6 +204,23 @@ export default class InventorySystem {
|
|||||||
console.log(`💰 +${amount}g (skupaj: ${this.gold}g)`);
|
console.log(`💰 +${amount}g (skupaj: ${this.gold}g)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deductItem(key, amount) {
|
||||||
|
if (!this.items[key] || this.items[key].count < amount) return false;
|
||||||
|
|
||||||
|
this.items[key].count -= amount;
|
||||||
|
|
||||||
|
// Če je stackable in gre na 0, odstrani tudi iz hotbara
|
||||||
|
if (this.items[key].count <= 0 && this.items[key].stackable) {
|
||||||
|
const index = this.hotbar.indexOf(key);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.hotbar[index] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._notifyUI();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
// PORABI ITEM (semena pri sajenju)
|
// PORABI ITEM (semena pri sajenju)
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
334
nova farma TRAE/src/systems/JournalSystem.js
Normal file
334
nova farma TRAE/src/systems/JournalSystem.js
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
/**
|
||||||
|
* ============================================================
|
||||||
|
* JournalSystem.js — Kaijev Dnevnik (Nova Farma)
|
||||||
|
* ============================================================
|
||||||
|
* [J] = odpri / zapri dnevnik
|
||||||
|
* Entries se odklenejo ob napredku (ob klicu unlockEntry(id))
|
||||||
|
* Stil: Temni gotski dnevnik z rumenimi robovi
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
export default class JournalSystem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Phaser.Scene} scene - GrassSceneClean instanca
|
||||||
|
*/
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.isOpen = false;
|
||||||
|
this.container = null;
|
||||||
|
this.currentPage = 0;
|
||||||
|
|
||||||
|
// ── Vse Vnosi (se odklenejo z unlockEntry) ──────────────────────
|
||||||
|
this.entries = [
|
||||||
|
{
|
||||||
|
id: 'start',
|
||||||
|
title: 'Dan 1 — Začetek',
|
||||||
|
text: [
|
||||||
|
'Prebudil sem se na otoku.',
|
||||||
|
'Nič se ne spomnim. Samo glas v glavi:',
|
||||||
|
'"Preživi. Posadi. Gradi."',
|
||||||
|
'',
|
||||||
|
'Poleg mene je bila skrinja. V njej orodja.',
|
||||||
|
'Začenjam.',
|
||||||
|
],
|
||||||
|
icon: '📖',
|
||||||
|
unlocked: true, // Startni vnos je vedno aktiven
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'first_tree',
|
||||||
|
title: 'Les z Gozda',
|
||||||
|
text: [
|
||||||
|
'Sekira se je dobro obnesla.',
|
||||||
|
'Drevo je padlo, les se je zvril na tla.',
|
||||||
|
'S tem lesom bom zgradil prve barikade.',
|
||||||
|
'',
|
||||||
|
'Noč se bliža. Slutim, da bo grdo.',
|
||||||
|
],
|
||||||
|
icon: '🪓',
|
||||||
|
unlocked: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'first_plant',
|
||||||
|
title: 'Prve Sadike',
|
||||||
|
text: [
|
||||||
|
'Zemlja je rjava in mokra.',
|
||||||
|
'Prekopal sem jo z motiko, posadil pšenico.',
|
||||||
|
'Vsako jutro jo moram zaliti.',
|
||||||
|
'',
|
||||||
|
'Upam, da bo rasla hitro. Hrane je vedno manj.',
|
||||||
|
],
|
||||||
|
icon: '🌱',
|
||||||
|
unlocked: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'first_night',
|
||||||
|
title: 'Prva Noč',
|
||||||
|
text: [
|
||||||
|
'Slišim jih.',
|
||||||
|
'Ropot v temi, stokanje. Hodijo počasi.',
|
||||||
|
'',
|
||||||
|
'Barikade so zdržale to noč.',
|
||||||
|
'A koliko noči jih je še pred mano?',
|
||||||
|
],
|
||||||
|
icon: '🌙',
|
||||||
|
unlocked: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'first_harvest',
|
||||||
|
title: 'Žetev',
|
||||||
|
text: [
|
||||||
|
'Pšenica je zrasla!',
|
||||||
|
'Tri klasje. Malo, a dovolj za začetek.',
|
||||||
|
'',
|
||||||
|
'Zemlja tukaj je rodovitna kljub vsemu.',
|
||||||
|
'Morda je to kraj, kjer se da preživeti.',
|
||||||
|
],
|
||||||
|
icon: '🌾',
|
||||||
|
unlocked: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mystery',
|
||||||
|
title: '???',
|
||||||
|
text: [
|
||||||
|
'???',
|
||||||
|
],
|
||||||
|
icon: '❓',
|
||||||
|
unlocked: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// ── UI Setup ──────────────────────────────────────────────────────
|
||||||
|
this._buildUI();
|
||||||
|
|
||||||
|
// ── Tipka [J] ─────────────────────────────────────────────────────
|
||||||
|
this.keyJ = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.J);
|
||||||
|
this.keyJ.on('down', this.toggle, this);
|
||||||
|
|
||||||
|
// ── Zapri z [Esc] ─────────────────────────────────────────────────
|
||||||
|
scene.input.keyboard.on('keydown-ESC', () => {
|
||||||
|
if (this.isOpen) this.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('📖 JournalSystem initialized — [J] za dnevnik');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
// BUILD UI
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
_buildUI() {
|
||||||
|
const { width, height } = this.scene.cameras.main;
|
||||||
|
const W = Math.min(660, width - 60);
|
||||||
|
const H = Math.min(460, height - 60);
|
||||||
|
const cx = width / 2;
|
||||||
|
const cy = height / 2;
|
||||||
|
|
||||||
|
// ── Wrapper (ScrollFactor 0 = fiksno na ekranu) ──
|
||||||
|
this.container = this.scene.add.container(cx, cy).setScrollFactor(0).setDepth(25000).setVisible(false);
|
||||||
|
|
||||||
|
// Temni tančati overlay
|
||||||
|
this.overlay = this.scene.add.rectangle(0, 0, width * 2, height * 2, 0x000000, 0.7)
|
||||||
|
.setScrollFactor(0).setDepth(24999).setVisible(false);
|
||||||
|
|
||||||
|
// ── Ozadje dnevnika (pergament) ──
|
||||||
|
const bg = this.scene.add.graphics();
|
||||||
|
// Senčni okvir
|
||||||
|
bg.fillStyle(0x1a0f00, 1);
|
||||||
|
bg.fillRoundedRect(-W / 2 + 5, -H / 2 + 5, W, H, 12);
|
||||||
|
// Pergament
|
||||||
|
bg.fillStyle(0x2a1a08, 1);
|
||||||
|
bg.fillRoundedRect(-W / 2, -H / 2, W, H, 10);
|
||||||
|
// Zlat rob
|
||||||
|
bg.lineStyle(3, 0xc8a040, 1);
|
||||||
|
bg.strokeRoundedRect(-W / 2, -H / 2, W, H, 10);
|
||||||
|
// Notranji rob
|
||||||
|
bg.lineStyle(1, 0x7a5020, 0.6);
|
||||||
|
bg.strokeRoundedRect(-W / 2 + 8, -H / 2 + 8, W - 16, H - 16, 8);
|
||||||
|
this.container.add(bg);
|
||||||
|
|
||||||
|
// ── Naslov ──
|
||||||
|
const title = this.scene.add.text(0, -H / 2 + 28, '📖 Kaijev Dnevnik', {
|
||||||
|
fontFamily: '"Cinzel", "Georgia", serif',
|
||||||
|
fontSize: '22px',
|
||||||
|
color: '#f0c060',
|
||||||
|
stroke: '#3a1a00',
|
||||||
|
strokeThickness: 4,
|
||||||
|
}).setOrigin(0.5, 0.5);
|
||||||
|
this.container.add(title);
|
||||||
|
|
||||||
|
// ── Razdelilna črta pod naslovom ──
|
||||||
|
const divider = this.scene.add.graphics();
|
||||||
|
divider.lineStyle(1, 0xc8a040, 0.6);
|
||||||
|
divider.lineBetween(-W / 2 + 20, -H / 2 + 50, W / 2 - 20, -H / 2 + 50);
|
||||||
|
this.container.add(divider);
|
||||||
|
|
||||||
|
// ── Leva stran: seznam vnosov ──
|
||||||
|
const listX = -W / 2 + 20;
|
||||||
|
this.entryButtons = [];
|
||||||
|
this._entryListY0 = -H / 2 + 65;
|
||||||
|
this._listStartX = listX;
|
||||||
|
this._panelW = W;
|
||||||
|
this._panelH = H;
|
||||||
|
|
||||||
|
// Placeholder za vnose (izgradujemo dinamično v refresh)
|
||||||
|
this._entryListContainer = this.scene.add.container(0, 0);
|
||||||
|
this.container.add(this._entryListContainer);
|
||||||
|
|
||||||
|
// ── Desna stran: vsebina ──
|
||||||
|
this._contentX = -W / 2 + W * 0.42;
|
||||||
|
this._contentY = -H / 2 + 65;
|
||||||
|
this._contentW = W * 0.57;
|
||||||
|
this._contentH = H - 90;
|
||||||
|
|
||||||
|
// Ločevalna črta med levo in desno
|
||||||
|
const div2 = this.scene.add.graphics();
|
||||||
|
div2.lineStyle(1, 0x7a5020, 0.5);
|
||||||
|
div2.lineBetween(-W / 2 + W * 0.41, -H / 2 + 55, -W / 2 + W * 0.41, H / 2 - 15);
|
||||||
|
this.container.add(div2);
|
||||||
|
|
||||||
|
// Vsebinski tekst (začasni, bo refreshan)
|
||||||
|
this._contentTitle = this.scene.add.text(this._contentX + 8, this._contentY + 10, '', {
|
||||||
|
fontFamily: '"Georgia", serif',
|
||||||
|
fontSize: '16px',
|
||||||
|
color: '#f0c060',
|
||||||
|
wordWrap: { width: this._contentW - 20 },
|
||||||
|
}).setOrigin(0, 0);
|
||||||
|
this.container.add(this._contentTitle);
|
||||||
|
|
||||||
|
this._contentBody = this.scene.add.text(this._contentX + 8, this._contentY + 40, '', {
|
||||||
|
fontFamily: '"Georgia", serif',
|
||||||
|
fontSize: '13px',
|
||||||
|
color: '#d4b872',
|
||||||
|
wordWrap: { width: this._contentW - 20 },
|
||||||
|
lineSpacing: 5,
|
||||||
|
}).setOrigin(0, 0);
|
||||||
|
this.container.add(this._contentBody);
|
||||||
|
|
||||||
|
// ── Gumb ZAPRI ──
|
||||||
|
const closeBtn = this.scene.add.text(W / 2 - 15, -H / 2 + 15, '✕', {
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: '18px',
|
||||||
|
color: '#c87050',
|
||||||
|
}).setOrigin(0.5, 0.5).setInteractive({ useHandCursor: true });
|
||||||
|
closeBtn.on('pointerdown', this.close, this);
|
||||||
|
closeBtn.on('pointerover', () => closeBtn.setColor('#ff7744'));
|
||||||
|
closeBtn.on('pointerout', () => closeBtn.setColor('#c87050'));
|
||||||
|
this.container.add(closeBtn);
|
||||||
|
|
||||||
|
// ── Navodila (spodaj) ──
|
||||||
|
const hint = this.scene.add.text(0, H / 2 - 15, '[J] Zapri | ←→ Strani', {
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: '11px',
|
||||||
|
color: '#7a5030',
|
||||||
|
}).setOrigin(0.5, 1);
|
||||||
|
this.container.add(hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
// REFRESH: Posodobi seznam vnosov in vsebino
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
_refresh() {
|
||||||
|
// Počisti stari seznam
|
||||||
|
this._entryListContainer.removeAll(true);
|
||||||
|
|
||||||
|
const unlocked = this.entries.filter(e => e.unlocked);
|
||||||
|
this.currentPage = Math.max(0, Math.min(this.currentPage, unlocked.length - 1));
|
||||||
|
|
||||||
|
unlocked.forEach((entry, i) => {
|
||||||
|
const yOff = this._entryListY0 + i * 38;
|
||||||
|
const isActive = i === this.currentPage;
|
||||||
|
|
||||||
|
// Ozadje za aktivni vnos
|
||||||
|
if (isActive) {
|
||||||
|
const hl = this.scene.add.graphics();
|
||||||
|
hl.fillStyle(0x3a2010, 1);
|
||||||
|
hl.fillRoundedRect(this._listStartX, yOff - 14, this._panelW * 0.39, 32, 6);
|
||||||
|
hl.lineStyle(1, 0xc8a040, 0.7);
|
||||||
|
hl.strokeRoundedRect(this._listStartX, yOff - 14, this._panelW * 0.39, 32, 6);
|
||||||
|
this._entryListContainer.add(hl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = this.scene.add.text(this._listStartX + 10, yOff, `${entry.icon} ${entry.title}`, {
|
||||||
|
fontFamily: '"Georgia", serif',
|
||||||
|
fontSize: '13px',
|
||||||
|
color: isActive ? '#f0c060' : '#a08040',
|
||||||
|
}).setOrigin(0, 0.5).setInteractive({ useHandCursor: true });
|
||||||
|
|
||||||
|
row.on('pointerdown', () => {
|
||||||
|
this.currentPage = i;
|
||||||
|
this._refresh();
|
||||||
|
});
|
||||||
|
row.on('pointerover', () => row.setColor('#ffe080'));
|
||||||
|
row.on('pointerout', () => row.setColor(isActive ? '#f0c060' : '#a08040'));
|
||||||
|
|
||||||
|
this._entryListContainer.add(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prikaži vsebino aktivnega vnosa
|
||||||
|
const active = unlocked[this.currentPage];
|
||||||
|
if (active) {
|
||||||
|
this._contentTitle.setText(`${active.icon} ${active.title}`);
|
||||||
|
this._contentBody.setText(active.text.join('\n'));
|
||||||
|
} else {
|
||||||
|
this._contentTitle.setText('');
|
||||||
|
this._contentBody.setText('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
// TOGGLE / OPEN / CLOSE
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
toggle() {
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.close();
|
||||||
|
} else {
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
this.isOpen = true;
|
||||||
|
this._refresh();
|
||||||
|
this.container.setVisible(true);
|
||||||
|
this.overlay.setVisible(true);
|
||||||
|
|
||||||
|
// Pojavi se animacija
|
||||||
|
this.container.setScale(0.85);
|
||||||
|
this.container.setAlpha(0);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.container,
|
||||||
|
scaleX: 1, scaleY: 1, alpha: 1,
|
||||||
|
duration: 220,
|
||||||
|
ease: 'Back.easeOut',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.container,
|
||||||
|
scaleX: 0.9, scaleY: 0.9, alpha: 0,
|
||||||
|
duration: 150,
|
||||||
|
ease: 'Sine.easeIn',
|
||||||
|
onComplete: () => {
|
||||||
|
this.container.setVisible(false);
|
||||||
|
this.overlay.setVisible(false);
|
||||||
|
this.isOpen = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
// UNLOCK ENTRY (kliči od drugod: this.journalSystem.unlockEntry('first_tree'))
|
||||||
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
|
unlockEntry(id) {
|
||||||
|
const entry = this.entries.find(e => e.id === id);
|
||||||
|
if (!entry || entry.unlocked) return;
|
||||||
|
|
||||||
|
entry.unlocked = true;
|
||||||
|
console.log(`📖 Dnevnik odklenjen: "${entry.title}"`);
|
||||||
|
|
||||||
|
// Toast obvestilo
|
||||||
|
if (this.scene.inventorySystem) {
|
||||||
|
this.scene.inventorySystem._showMsg(`📖 Nov vnos: "${entry.title}"`, '#f0c060');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
nova farma TRAE/src/systems/TwinBondSystem.js
Normal file
137
nova farma TRAE/src/systems/TwinBondSystem.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,12 +27,13 @@ export default class ZombieSystem {
|
|||||||
this.islandH = options.islandH || 6400;
|
this.islandH = options.islandH || 6400;
|
||||||
|
|
||||||
// Zombi parametri
|
// Zombi parametri
|
||||||
this.maxZombies = 3;
|
this.maxZombies = 2; // Začne z 2, raste po dnevih
|
||||||
this.spawnAtNight = true;
|
this.spawnAtNight = true;
|
||||||
this.zombieSpeed = 35; // px/s — počasi šambers
|
this.zombieSpeed = 35; // px/s — počasi šambers
|
||||||
this.detectionRange = 600; // Kai zazna zombija → prikaže opozorilo
|
this.detectionRange = 600; // Kai zazna zombija → prikaže opozorilo
|
||||||
this.alfaRange = 120; // Razdalja za Alfa Moč [SPACE]
|
this.alfaRange = 120; // Razdalja za Alfa Moč [SPACE]
|
||||||
this.tamingTime = 2000; // ms za udomačitev (drži [SPACE])
|
this.tamingTime = 2000; // ms za udomačitev (drži [SPACE])
|
||||||
|
this._nightCount = 0; // Koliko noči je minilo
|
||||||
|
|
||||||
// Aktivni zombiji
|
// Aktivni zombiji
|
||||||
this.zombies = [];
|
this.zombies = [];
|
||||||
@@ -94,8 +95,18 @@ export default class ZombieSystem {
|
|||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
startNightSpawning() {
|
startNightSpawning() {
|
||||||
if (this.spawnTimer) return;
|
if (this.spawnTimer) return;
|
||||||
|
|
||||||
|
this._nightCount++;
|
||||||
|
|
||||||
|
// Stopnjevanje tezje po vsaki noci
|
||||||
|
this.maxZombies = Math.min(2 + this._nightCount, 8);
|
||||||
|
const spawnDelay = Math.max(6000, 14000 - this._nightCount * 1000);
|
||||||
|
this.zombieSpeed = Math.min(35 + this._nightCount * 3, 65);
|
||||||
|
|
||||||
|
console.log(`🌙 Noč ${this._nightCount}: max=${this.maxZombies}, delay=${spawnDelay}ms, speed=${this.zombieSpeed}px/s`);
|
||||||
|
|
||||||
this.spawnTimer = this.scene.time.addEvent({
|
this.spawnTimer = this.scene.time.addEvent({
|
||||||
delay: 12000, // Vsakih 12s poskusi spawnat (ponoči)
|
delay: spawnDelay,
|
||||||
loop: true,
|
loop: true,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
if (this.zombies.length < this.maxZombies) {
|
if (this.zombies.length < this.maxZombies) {
|
||||||
@@ -103,10 +114,19 @@ export default class ZombieSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Takoj spawni prvega
|
// Takoj spawni prvega
|
||||||
this.scene.time.delayedCall(2000, () => {
|
this.scene.time.delayedCall(2000, () => {
|
||||||
if (this.zombies.length < this.maxZombies) this.spawnZombie();
|
if (this.zombies.length < this.maxZombies) this.spawnZombie();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Journal unlock ob prvi noči
|
||||||
|
if (this._nightCount === 1 && this.scene.journalSystem) {
|
||||||
|
this.scene.time.delayedCall(3000, () => {
|
||||||
|
this.scene.journalSystem.unlockEntry('first_night');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
console.log('🌙 Zombiji se začnejo spawnat!');
|
console.log('🌙 Zombiji se začnejo spawnat!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user