This commit is contained in:
2025-12-07 21:31:44 +01:00
parent 4a0ca267ea
commit 974141c08c
52 changed files with 2485 additions and 397 deletions

View File

@@ -51,8 +51,15 @@ class GameScene extends Phaser.Scene {
this.terrainSystem.updateCulling(this.cameras.main);
// FAZA 14: Spawn Ruin (Town Project) at fixed location near player
console.log('🏚️ Spawning Ruin...');
console.log('🏚️ Spawning Ruin & Arena...');
this.terrainSystem.placeStructure(55, 55, 'ruin');
this.terrainSystem.placeStructure(75, 75, 'arena');
// Initialize Pathfinding (Worker)
console.log('🗺️ Initializing Pathfinding...');
this.pathfinding = new PathfindingSystem(this);
this.pathfinding.updateGrid();
} catch (e) {
console.error("Terrain system failed:", e);
}
@@ -61,8 +68,6 @@ class GameScene extends Phaser.Scene {
console.log('👤 Initializing player...');
this.player = new Player(this, 50, 50, this.terrainOffsetX, this.terrainOffsetY);
// Dodaj 3 NPCje
console.log('🧟 Initializing NPCs...');
// Dodaj 3 NPCje (Mixed)
console.log('🧟 Initializing NPCs...');
const npcTypes = ['zombie', 'villager', 'merchant'];
@@ -81,8 +86,8 @@ class GameScene extends Phaser.Scene {
this.npcs.push(zombie);
}
// Kamera sledi igralcu z izboljšanimi nastavitvami
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0); // Instant follow (was 0.1)
// Kamera sledi igralcu
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0);
// Nastavi deadzone (100px border)
this.cameras.main.setDeadzone(100, 100);
@@ -99,11 +104,10 @@ class GameScene extends Phaser.Scene {
// Kamera kontrole
this.setupCamera();
// Initialize Time & Stats
// Initialize Weather System (Unified: Time + DayNight + Weather)
// Initialize Systems
console.log('🌦️ Initializing Unified Weather System...');
this.weatherSystem = new WeatherSystem(this);
this.timeSystem = this.weatherSystem; // Alias for compatibility with other systems (e.g. UIScene, Farming)
this.timeSystem = this.weatherSystem; // Alias
this.statsSystem = new StatsSystem(this);
this.inventorySystem = new InventorySystem(this);
@@ -111,17 +115,24 @@ class GameScene extends Phaser.Scene {
this.interactionSystem = new InteractionSystem(this);
this.farmingSystem = new FarmingSystem(this);
this.buildingSystem = new BuildingSystem(this);
// DayNightSystem removed (merged into WeatherSystem)
this.pathfinding = new Pathfinding(this);
this.questSystem = new QuestSystem(this);
this.multiplayerSystem = new MultiplayerSystem(this);
// Initialize Sound Manager
console.log('🎵 Initializing Sound Manager...');
this.soundManager = new SoundManager(this);
this.soundManager.startMusic();
// Initialize Parallax System
console.log('🌄 Initializing Parallax System...');
this.parallaxSystem = new ParallaxSystem(this);
// Initialize Particle Effects
console.log('✨ Initializing Particle Effects...');
this.particleEffects = new ParticleEffects(this);
this.particleEffects.createFallingLeaves();
// Generate Item Sprites for UI
TextureGenerator.createItemSprites(this);
@@ -135,7 +146,11 @@ class GameScene extends Phaser.Scene {
// Auto-load if available
this.saveSystem.loadGame();
console.log('✅ GameScene ready - FAZA 18 (Crafting & AI)!');
// Debug Text
this.add.text(10, 10, 'NovaFarma Alpha v0.6', { font: '16px monospace', fill: '#ffffff' })
.setScrollFactor(0).setDepth(10000);
console.log('✅ GameScene ready - FAZA 20 (Full Features)!');
}
setupCamera() {
@@ -159,21 +174,11 @@ class GameScene extends Phaser.Scene {
});
// Save/Load Keys
this.input.keyboard.on('keydown-F8', () => {
// Save
if (this.saveSystem) {
this.saveSystem.saveGame();
console.log('💾 Game Saved! (F8)');
}
});
this.input.keyboard.on('keydown-F8', () => this.saveGame());
this.input.keyboard.on('keydown-F9', () => this.loadGame());
this.input.keyboard.on('keydown-F9', () => {
// Load
if (this.saveSystem) {
this.saveSystem.loadGame();
console.log('📂 Game Loaded! (F9)');
}
});
// Spawn Boss (Debug)
this.input.keyboard.on('keydown-K', () => this.spawnBoss());
// Build Mode Keys
this.input.keyboard.on('keydown-B', () => {
@@ -184,41 +189,73 @@ class GameScene extends Phaser.Scene {
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('fence');
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(0);
});
this.input.keyboard.on('keydown-TWO', () => {
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('wall');
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(1);
});
this.input.keyboard.on('keydown-THREE', () => {
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('house');
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(2);
});
// Soft Reset (F4) - Force Reload Page
this.input.keyboard.on('keydown-F4', () => {
console.log('🔄 Soft Reset Initiated (Force Reload)...');
window.location.reload();
});
// Soft Reset (F4)
this.input.keyboard.on('keydown-F4', () => window.location.reload());
// Mute Toggle (M key)
this.input.keyboard.on('keydown-M', () => {
if (this.soundManager) {
this.soundManager.toggleMute();
}
if (this.soundManager) this.soundManager.toggleMute();
});
}
update(time, delta) {
if (this.player) this.player.update(delta);
// Update Systems
// TimeSystem update removed (handled by WeatherSystem)
if (this.statsSystem) this.statsSystem.update(delta);
if (this.lootSystem) this.lootSystem.update(delta); // Loot System Update
if (this.lootSystem) this.lootSystem.update(delta);
if (this.interactionSystem) this.interactionSystem.update(delta);
if (this.farmingSystem) this.farmingSystem.update(delta);
// DayNight update removed (handled by WeatherSystem)
if (this.weatherSystem) this.weatherSystem.update(delta);
if (this.questSystem) this.questSystem.update(delta);
if (this.multiplayerSystem) this.multiplayerSystem.update(delta);
// Update Parallax (foreground grass fading)
if (this.weatherSystem) {
this.weatherSystem.update(delta);
// Night Logic
if (this.weatherSystem.isNight()) {
const isHorde = this.weatherSystem.isHordeNight();
const spawnInterval = isHorde ? 2000 : 10000;
// Check for Horde Start Warning
if (isHorde && !this.hordeWarningShown) {
this.showHordeWarning();
this.hordeWarningShown = true;
}
if (!this.nightSpawnTimer) this.nightSpawnTimer = 0;
this.nightSpawnTimer += delta;
if (this.nightSpawnTimer > spawnInterval) {
this.nightSpawnTimer = 0;
this.spawnNightZombie();
if (isHorde) {
this.spawnNightZombie();
this.spawnNightZombie();
}
}
} else {
this.hordeWarningShown = false;
}
}
// NPC Update
for (const npc of this.npcs) {
npc.update(delta);
}
// Parallax
if (this.parallaxSystem && this.player) {
const playerPos = this.player.getPosition();
const screenPos = this.iso.toScreen(playerPos.x, playerPos.y);
@@ -228,45 +265,34 @@ class GameScene extends Phaser.Scene {
);
}
// Update player
if (this.player) {
this.player.update(delta);
}
// Update NPCs
for (const npc of this.npcs) {
npc.update(delta);
}
// Update Terrain Culling
// Terrain Culling
if (this.terrainSystem) {
this.terrainSystem.updateCulling(this.cameras.main);
}
// Update clouds
// Clouds
if (this.clouds) {
for (const cloud of this.clouds) {
cloud.sprite.x += cloud.speed * (delta / 1000);
if (cloud.sprite.x > this.terrainOffsetX + 2000) { // Reset far right
if (cloud.sprite.x > this.terrainOffsetX + 2000) {
cloud.sprite.x = this.terrainOffsetX - 2000;
cloud.sprite.y = Phaser.Math.Between(0, 1000);
}
}
}
// Send debug info to UI Scene
// Debug Info
if (this.player) {
const playerPos = this.player.getPosition();
const cam = this.cameras.main;
const uiScene = this.scene.get('UIScene');
if (uiScene && uiScene.debugText) {
const activeCrops = this.terrainSystem && this.terrainSystem.cropsMap ? this.terrainSystem.cropsMap.size : 0;
const dropsCount = this.lootSystem ? this.lootSystem.drops.length : 0;
const conn = this.multiplayerSystem && this.multiplayerSystem.isConnected ? '🟢 Online' : '🔴 Offline';
uiScene.debugText.setText(
`FAZA 11 - Building\n` +
`[F5] Save | [F9] Load | [B] Build Mode\n` +
`NovaFarma v0.6 [${conn}]\n` +
`[F5] Save | [F9] Load | [K] Boss\n` +
`Time: ${this.timeSystem ? this.timeSystem.gameTime.toFixed(1) : '?'}h\n` +
`Active Crops: ${activeCrops}\n` +
`Loot Drops: ${dropsCount}\n` +
@@ -276,25 +302,76 @@ class GameScene extends Phaser.Scene {
}
}
spawnNightZombie() {
if (!this.player || this.npcs.length > 50) return;
const playerPos = this.player.getPosition();
const angle = Math.random() * Math.PI * 2;
const distance = Phaser.Math.Between(15, 25);
const spawnX = Math.floor(playerPos.x + Math.cos(angle) * distance);
const spawnY = Math.floor(playerPos.y + Math.sin(angle) * distance);
if (spawnX < 0 || spawnX >= 100 || spawnY < 0 || spawnY >= 100) return;
if (Phaser.Math.Distance.Between(spawnX, spawnY, 20, 20) < 15) return;
const tile = this.terrainSystem.getTile(spawnX, spawnY);
if (tile && tile.type !== 'water') {
console.log(`🌑 Night Spawn: Zombie at ${spawnX},${spawnY}`);
const zombie = new NPC(this, spawnX, spawnY, this.terrainOffsetX, this.terrainOffsetY, 'zombie');
zombie.state = 'CHASE';
this.npcs.push(zombie);
}
}
showHordeWarning() {
console.log('🩸 BLOOD MOON RISING!');
if (this.soundManager) this.soundManager.playDeath();
const width = this.cameras.main.width;
const height = this.cameras.main.height;
const text = this.add.text(width / 2, height / 3, 'THE HORDE IS APPROACHING...', {
fontSize: '40px', fontFamily: 'Courier New', fill: '#ff0000', fontStyle: 'bold', stroke: '#000000', strokeThickness: 6
}).setOrigin(0.5).setScrollFactor(0).setDepth(10000);
this.tweens.add({
targets: text, scale: 1.2, duration: 500, yoyo: true, repeat: 5,
onComplete: () => {
this.tweens.add({
targets: text, alpha: 0, duration: 2000,
onComplete: () => text.destroy()
});
}
});
}
createClouds() {
if (!this.textures.exists('cloud')) TextureGenerator.createCloudSprite(this, 'cloud');
this.clouds = [];
console.log('☁️ Creating parallax clouds...');
for (let i = 0; i < 8; i++) {
const x = Phaser.Math.Between(-1000, 3000);
const y = Phaser.Math.Between(-500, 1500);
const cloud = this.add.sprite(x, y, 'cloud');
cloud.setAlpha(0.4);
cloud.setScrollFactor(0.2); // Parallax effect
cloud.setDepth(2000); // Nad vsem
cloud.setScale(Phaser.Math.FloatBetween(2, 4)); // Veliki oblaki
cloud.setAlpha(0.4).setScrollFactor(0.2).setDepth(2000).setScale(Phaser.Math.FloatBetween(2, 4));
this.clouds.push({ sprite: cloud, speed: Phaser.Math.FloatBetween(10, 30) });
}
}
spawnBoss() {
if (!this.player) return;
console.log('👑 SPANWING ZOMBIE KING!');
const playerPos = this.player.getPosition();
const spawnX = Math.floor(playerPos.x + 8);
const spawnY = Math.floor(playerPos.y + 8);
const boss = new Boss(this, spawnX, spawnY);
boss.state = 'CHASE';
this.npcs.push(boss);
this.showHordeWarning();
this.events.emit('show-floating-text', { x: this.player.x, y: this.player.y - 100, text: "THE KING HAS ARRIVED!", color: '#AA00FF' });
}
saveGame() {
if (this.saveSystem) this.saveSystem.saveGame();
}

View File

@@ -7,6 +7,8 @@ class PreloadScene extends Phaser.Scene {
preload() {
console.log('⏳ PreloadScene: Loading assets...');
this.createLoadingBar();
// Load ALL custom sprites
this.load.image('player_sprite', 'assets/player_sprite.png');
this.load.image('zombie_sprite', 'assets/zombie_sprite.png');
@@ -27,6 +29,30 @@ class PreloadScene extends Phaser.Scene {
this.load.image('objects_pack2', 'assets/objects_pack2.png');
this.load.image('trees_vegetation', 'assets/trees_vegetation.png');
// User-uploaded pixel art assets (original)
this.load.image('flowers', 'assets/flowers.png');
this.load.image('tree_green', 'assets/tree_green.png');
this.load.image('tree_blue', 'assets/tree_blue.png');
this.load.image('tree_dead', 'assets/tree_dead.png');
this.load.image('rock_asset', 'assets/rock_asset.png');
// NEW transparent tree/rock assets
this.load.image('tree_blue_new', 'assets/tree_blue_new.png');
this.load.image('tree_green_new', 'assets/tree_green_new.png');
this.load.image('rock_1', 'assets/rock_1.png');
this.load.image('rock_2', 'assets/rock_2.png');
this.load.image('tree_dead_new', 'assets/tree_dead_new.png');
this.load.image('flowers_new', 'assets/flowers_new.png');
this.load.image('hill_sprite', 'assets/hill_sprite.png');
this.load.image('fence', 'assets/fence.png');
this.load.image('gravestone', 'assets/gravestone.png');
// Voxel stil asset-i (2.5D)
this.load.image('tree_voxel_green', 'assets/tree_voxel_green.png');
this.load.image('tree_voxel_blue', 'assets/tree_voxel_blue.png');
this.load.image('tree_voxel_dead', 'assets/tree_voxel_dead.png');
this.load.image('rock_voxel', 'assets/rock_voxel.png');
// Wait for load completion then process transparency
this.load.once('complete', () => {
this.processAllTransparency();
@@ -69,7 +95,28 @@ class PreloadScene extends Phaser.Scene {
'grass_sprite',
'leaf_sprite',
'wheat_sprite',
'stone_texture'
'stone_texture',
// New pixel art assets
'flowers',
'tree_green',
'tree_blue',
'tree_dead',
'rock_asset',
// NEW transparent assets
'tree_blue_new',
'tree_green_new',
'rock_1',
'rock_2',
'tree_dead_new',
'flowers_new',
'hill_sprite',
'fence',
'gravestone',
// Voxel stil
'tree_voxel_green',
'tree_voxel_blue',
'tree_voxel_dead',
'rock_voxel'
];
spritesToProcess.forEach(spriteKey => {
@@ -127,6 +174,42 @@ class PreloadScene extends Phaser.Scene {
this.textures.addCanvas(spriteKey, canvas);
}
createLoadingBar() {
const width = this.cameras.main.width;
const height = this.cameras.main.height;
const progressBar = this.add.graphics();
const progressBox = this.add.graphics();
progressBox.fillStyle(0x222222, 0.8);
progressBox.fillRect(width / 2 - 160, height / 2 - 25, 320, 50);
const loadingText = this.add.text(width / 2, height / 2 - 50, 'Loading NovaFarma...', {
font: '20px Courier New',
fill: '#ffffff'
});
loadingText.setOrigin(0.5, 0.5);
const percentText = this.add.text(width / 2, height / 2, '0%', {
font: '18px Courier New',
fill: '#ffffff'
});
percentText.setOrigin(0.5, 0.5);
this.load.on('progress', (value) => {
percentText.setText(parseInt(value * 100) + '%');
progressBar.clear();
progressBar.fillStyle(0x00ff00, 1); // Matrix Green
progressBar.fillRect(width / 2 - 150, height / 2 - 15, 300 * value, 30);
});
this.load.on('complete', () => {
progressBar.destroy();
progressBox.destroy();
loadingText.destroy();
percentText.destroy();
});
}
create() {
console.log('✅ PreloadScene: Assets loaded!');
window.gameState.currentScene = 'PreloadScene';

View File

@@ -11,32 +11,31 @@ class StoryScene extends Phaser.Scene {
this.add.rectangle(0, 0, width, height, 0x000000).setOrigin(0);
const storyText =
`Leto 2084.
Svet, kot smo ga poznali, je izginil.
`LETO 2084.
SVET JE PADEL V TEMO.
Virus "Zmaj-Volka" je spremenil človeštvo.
Mesta so ruševine. Narava je divja.
Virus je večino spremenil v pošasti.
Mesta so grobnice.
Toda ti si drugačen.
Preživel si napad. Okužen, a imun.
Si HIBRID.
Zombiji te ne napadajo... čutijo te.
Zanje si ALFA.
Toda našel si upanje.
Zapuščeno kmetijo na robu divjine.
Zadnje varno zatočišče.
Tvoja naloga:
1. Najdi izgubljeno sestro.
2. Maščuj starše.
3. Obnovi civilizacijo iz pepela.
1. Obnovi kmetijo in preživi.
2. Zgradi obrambo pred hordo.
3. Najdi zdravilo in reši svet.
Dobrodošel v KRVAVI ŽETVI.`;
Pripravi se... NOČ PRIHAJA.`;
const textObj = this.add.text(width / 2, height + 100, storyText, {
const textObj = this.add.text(width / 2, height, storyText, {
fontFamily: 'Courier New',
fontSize: '24px',
fontSize: '28px',
fill: '#00ff41',
align: 'center',
lineSpacing: 10
lineSpacing: 15,
stroke: '#000000',
strokeThickness: 4
});
textObj.setOrigin(0.5, 0);
@@ -44,7 +43,7 @@ Dobrodošel v KRVAVI ŽETVI.`;
this.tweens.add({
targets: textObj,
y: 50,
duration: 10000, // 10s scroll
duration: 15000, // 15s scroll
ease: 'Linear',
onComplete: () => {
this.time.delayedCall(2000, () => {

View File

@@ -18,6 +18,7 @@ class UIScene extends Phaser.Scene {
this.createStatusBars();
this.createInventoryBar();
this.createGoldDisplay();
this.createVirtualJoystick();
this.createClock();
// this.createDebugInfo();
this.createSettingsButton();
@@ -471,7 +472,20 @@ class UIScene extends Phaser.Scene {
if (!this.buildMenuContainer) {
this.createBuildMenuInfo();
}
this.buildMenuContainer.setVisible(isVisible);
if (isVisible) {
this.buildMenuContainer.setVisible(true);
this.buildMenuContainer.y = -100; // Start off-screen
this.tweens.add({
targets: this.buildMenuContainer,
y: 100, // Target pos
duration: 300,
ease: 'Back.easeOut'
});
} else {
// Slide out (optional) or just hide
this.buildMenuContainer.setVisible(false);
}
}
createBuildMenuInfo() {
@@ -778,4 +792,168 @@ class UIScene extends Phaser.Scene {
});
this.settingsContainer.add(hitArea);
}
updateQuestTracker(quest) {
if (!this.questContainer) {
this.createQuestTracker();
}
if (!quest) {
this.questContainer.setVisible(false);
return;
}
this.questContainer.setVisible(true);
this.questTitle.setText(quest.title.toUpperCase());
let objText = '';
quest.objectives.forEach(obj => {
const status = obj.done ? '✅' : '⬜';
let desc = '';
if (obj.type === 'collect') desc = `${obj.item}: ${obj.current}/${obj.amount}`;
else if (obj.type === 'action') desc = `${obj.action}: ${obj.current}/${obj.amount}`;
else if (obj.type === 'kill') desc = `Slay ${obj.target}: ${obj.current}/${obj.amount}`;
objText += `${status} ${desc}\n`;
});
this.questObjectives.setText(objText);
}
createQuestTracker() {
const x = this.width - 240;
const y = 20;
this.questContainer = this.add.container(x, y);
// BG
const bg = this.add.graphics();
bg.fillStyle(0x000000, 0.6);
bg.fillRect(0, 0, 220, 100);
bg.lineStyle(2, 0xffaa00, 0.8);
bg.strokeRect(0, 0, 220, 100);
this.questContainer.add(bg);
this.questTrackerBg = bg; // ref to resize later if needed
// Title Header
const header = this.add.text(10, 5, 'CURRENT QUEST', { fontSize: '10px', fill: '#aaaaaa' });
this.questContainer.add(header);
// Title
this.questTitle = this.add.text(10, 20, 'Quest Title', {
fontSize: '16px', fill: '#ffaa00', fontStyle: 'bold'
});
this.questContainer.add(this.questTitle);
// Objectives
this.questObjectives = this.add.text(10, 45, 'Objectives...', {
fontSize: '14px', fill: '#ffffff', lineSpacing: 5
});
this.questContainer.add(this.questObjectives);
}
createVirtualJoystick() {
const x = 120;
const y = this.height - 120;
// Warning: this.height might not be updated on resize? Use this.scale.height or just initial.
// UIScene is usually overlay, so simple coords ok. But resize needs handling.
const r = 60;
// Visuals
this.joyBase = this.add.circle(x, y, r, 0xffffff, 0.1).setScrollFactor(0).setDepth(2000).setInteractive();
this.joyStick = this.add.circle(x, y, r / 2, 0xffffff, 0.5).setScrollFactor(0).setDepth(2001);
this.virtualJoystick = { up: false, down: false, left: false, right: false };
this.joyDragging = false;
// Events
this.input.on('pointermove', (pointer) => {
if (!this.joyDragging) return;
this.updateJoystick(pointer.x, pointer.y, x, y, r);
});
this.input.on('pointerup', () => {
if (this.joyDragging) {
this.joyDragging = false;
this.joyStick.setPosition(x, y);
this.virtualJoystick = { up: false, down: false, left: false, right: false };
}
});
this.joyBase.on('pointerdown', (pointer) => {
this.joyDragging = true;
this.updateJoystick(pointer.x, pointer.y, x, y, r);
});
}
updateJoystick(px, py, cx, cy, r) {
const angle = Phaser.Math.Angle.Between(cx, cy, px, py);
const dist = Math.min(r, Phaser.Math.Distance.Between(cx, cy, px, py));
const sx = cx + Math.cos(angle) * dist;
const sy = cy + Math.sin(angle) * dist;
this.joyStick.setPosition(sx, sy);
// Normalize angle to degrees
let deg = Phaser.Math.RadToDeg(angle);
this.virtualJoystick = { up: false, down: false, left: false, right: false };
// Mapping to Isometric direction keys
// UP Key (Top-Left on screen) -> Angle -135 (-180 to -90)
// RIGHT Key (Top-Right on screen) -> Angle -45 (-90 to 0)
// DOWN Key (Bottom-Right on screen) -> Angle 45 (0 to 90)
// LEFT Key (Bottom-Left on screen) -> Angle 135 (90 to 180)
if (deg > -170 && deg <= -80) this.virtualJoystick.up = true; // Tuned slightly
else if (deg > -80 && deg <= 10) this.virtualJoystick.right = true;
else if (deg > 10 && deg <= 100) this.virtualJoystick.down = true;
else this.virtualJoystick.left = true;
}
showQuestDialog(quest, onAccept) {
const width = 400;
const height = 250;
const x = this.cameras.main.centerX;
const y = this.cameras.main.centerY;
const container = this.add.container(x, y);
container.setDepth(5000);
const bg = this.add.rectangle(0, 0, width, height, 0x222222, 0.95);
bg.setStrokeStyle(4, 0x444444);
const title = this.add.text(0, -90, quest.title.toUpperCase(), { fontSize: '24px', fontStyle: 'bold', color: '#ffcc00' }).setOrigin(0.5);
const desc = this.add.text(0, -30, quest.description, { fontSize: '16px', color: '#dddddd', align: 'center', wordWrap: { width: width - 60 } }).setOrigin(0.5);
let rText = "Reward: ";
if (quest.reward.gold) rText += `${quest.reward.gold} G `;
if (quest.reward.item) rText += `+ ${quest.reward.amount || 1} ${quest.reward.item}`;
const reward = this.add.text(0, 40, rText, { fontSize: '16px', color: '#00ff00', fontStyle: 'italic' }).setOrigin(0.5);
// Buttons
const btnAccept = this.add.rectangle(-70, 90, 120, 40, 0x228B22).setInteractive({ useHandCursor: true });
const txtAccept = this.add.text(-70, 90, 'ACCEPT', { fontSize: '18px', fontStyle: 'bold' }).setOrigin(0.5);
const btnClose = this.add.rectangle(70, 90, 120, 40, 0x8B0000).setInteractive({ useHandCursor: true });
const txtClose = this.add.text(70, 90, 'DECLINE', { fontSize: '18px', fontStyle: 'bold' }).setOrigin(0.5);
btnAccept.on('pointerdown', () => {
onAccept();
container.destroy();
});
btnClose.on('pointerdown', () => {
container.destroy();
});
container.add([bg, title, desc, reward, btnAccept, txtAccept, btnClose, txtClose]);
// Appear anim
container.setScale(0);
this.tweens.add({ targets: container, scale: 1, duration: 200, ease: 'Back.out' });
}
}