različne velikosti dreves
This commit is contained in:
@@ -52,7 +52,7 @@ class NPC {
|
|||||||
texKey
|
texKey
|
||||||
);
|
);
|
||||||
this.sprite.setOrigin(0.5, 1);
|
this.sprite.setOrigin(0.5, 1);
|
||||||
this.sprite.setScale(0.2); // Mali, detajlni sprite
|
this.sprite.setScale(0.3); // Optimized for visibility
|
||||||
|
|
||||||
// Depth sorting
|
// Depth sorting
|
||||||
this.updateDepth();
|
this.updateDepth();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class Player {
|
|||||||
texKey
|
texKey
|
||||||
);
|
);
|
||||||
this.sprite.setOrigin(0.5, 1);
|
this.sprite.setOrigin(0.5, 1);
|
||||||
this.sprite.setScale(0.2); // Mali, detajlni sprite
|
this.sprite.setScale(0.3); // Optimized for visibility
|
||||||
|
|
||||||
// Depth sorting
|
// Depth sorting
|
||||||
this.updateDepth();
|
this.updateDepth();
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ class GameScene extends Phaser.Scene {
|
|||||||
// Round pixels za crisp pixel art
|
// Round pixels za crisp pixel art
|
||||||
this.cameras.main.roundPixels = true;
|
this.cameras.main.roundPixels = true;
|
||||||
|
|
||||||
|
// Zoom out za boljši pogled (85% zoom)
|
||||||
|
this.cameras.main.setZoom(0.85);
|
||||||
|
|
||||||
// Parallax oblaki
|
// Parallax oblaki
|
||||||
this.createClouds();
|
this.createClouds();
|
||||||
|
|
||||||
|
|||||||
@@ -165,24 +165,56 @@ class UIScene extends Phaser.Scene {
|
|||||||
|
|
||||||
updateInventory(slots) {
|
updateInventory(slots) {
|
||||||
if (!this.inventorySlots) return;
|
if (!this.inventorySlots) return;
|
||||||
|
|
||||||
for (let i = 0; i < this.inventorySlots.length; i++) {
|
for (let i = 0; i < this.inventorySlots.length; i++) {
|
||||||
const slotGraphics = this.inventorySlots[i];
|
const slotGraphics = this.inventorySlots[i];
|
||||||
// Clear previous item info (we stored it in container? No, just graphics)
|
|
||||||
// Ideally slots should be containers.
|
|
||||||
// For now, let's just redraw the slot and add text on top.
|
|
||||||
// To do this cleanly, let's remove old item text/sprites if we track them.
|
|
||||||
|
|
||||||
if (slotGraphics.itemText) slotGraphics.itemText.destroy();
|
// Clean up old visual elements
|
||||||
|
if (slotGraphics.itemSprite) {
|
||||||
|
slotGraphics.itemSprite.destroy();
|
||||||
|
slotGraphics.itemSprite = null;
|
||||||
|
}
|
||||||
|
if (slotGraphics.itemText) {
|
||||||
|
slotGraphics.itemText.destroy();
|
||||||
|
slotGraphics.itemText = null;
|
||||||
|
}
|
||||||
|
if (slotGraphics.countText) {
|
||||||
|
slotGraphics.countText.destroy();
|
||||||
|
slotGraphics.countText = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (slots[i]) {
|
if (slots[i]) {
|
||||||
const { x, y, size } = slotGraphics.userData;
|
const { x, y, size } = slotGraphics.userData;
|
||||||
// Simple representation: Text
|
const type = slots[i].type;
|
||||||
const text = this.add.text(x + size / 2, y + size / 2,
|
const textureKey = `item_${type}`; // e.g., item_axe, item_wood
|
||||||
`${slots[i].type.substring(0, 2)}\n${slots[i].count}`,
|
|
||||||
{ fontSize: '10px', align: 'center', color: '#ffff00' }
|
|
||||||
).setOrigin(0.5);
|
|
||||||
|
|
||||||
slotGraphics.itemText = text;
|
// Check if texture exists
|
||||||
|
if (this.textures.exists(textureKey)) {
|
||||||
|
// Draw Sprite
|
||||||
|
const sprite = this.add.sprite(x + size / 2, y + size / 2, textureKey);
|
||||||
|
|
||||||
|
// Scale to fit slot (32px slot, maybe 24px icon)
|
||||||
|
const scale = (size - 8) / Math.max(sprite.width, sprite.height);
|
||||||
|
sprite.setScale(scale);
|
||||||
|
|
||||||
|
slotGraphics.itemSprite = sprite;
|
||||||
|
} else {
|
||||||
|
// Fallback Text
|
||||||
|
const text = this.add.text(x + size / 2, y + size / 2,
|
||||||
|
type.substring(0, 2).toUpperCase(),
|
||||||
|
{ fontSize: '12px', align: 'center', color: '#ffff00', stroke: '#000', strokeThickness: 2 }
|
||||||
|
).setOrigin(0.5);
|
||||||
|
slotGraphics.itemText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw Count (if > 1)
|
||||||
|
if (slots[i].count > 1) {
|
||||||
|
const countText = this.add.text(x + size - 2, y + size - 2,
|
||||||
|
slots[i].count.toString(),
|
||||||
|
{ fontSize: '10px', align: 'right', color: '#ffffff', stroke: '#000', strokeThickness: 2 }
|
||||||
|
).setOrigin(1, 1);
|
||||||
|
slotGraphics.countText = countText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,95 +86,71 @@ class InteractionSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Try damage decoration (fallback)
|
// 5. Try damage decoration
|
||||||
// 5. Try damage or interact decoration
|
const id = `${gridPos.x},${gridPos.y}`;
|
||||||
if (this.scene.terrainSystem) {
|
if (this.scene.terrainSystem.decorationsMap.has(id)) {
|
||||||
const id = `${gridPos.x},${gridPos.y}`;
|
const decor = this.scene.terrainSystem.decorationsMap.get(id);
|
||||||
if (this.scene.terrainSystem.decorationsMap.has(id)) {
|
|
||||||
const decor = this.scene.terrainSystem.decorationsMap.get(id);
|
|
||||||
|
|
||||||
|
// Calculate Damage based on Tool
|
||||||
|
let damage = 1; // Default hand damage
|
||||||
|
|
||||||
// Ruin Interaction - Town Restoration
|
// Tool Logic
|
||||||
if (decor.type === 'ruin' || decor.type === 'ruin_borut') {
|
if (decor.type === 'tree' && activeTool === 'axe') {
|
||||||
// Check if near
|
damage = 3; // Axe destroys tree fast
|
||||||
if (dist > 2.5) {
|
} else if ((decor.type === 'bush' || decor.type === 'stone') && activeTool === 'pickaxe') {
|
||||||
console.log('Ruin too far.');
|
damage = 3; // Pickaxe destroys stone fast
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show Project Menu
|
|
||||||
const uiScene = this.scene.scene.get('UIScene');
|
|
||||||
if (uiScene) {
|
|
||||||
// Define requirements based on ruin type
|
|
||||||
let req = { reqWood: 100, reqStone: 50, reqGold: 50 };
|
|
||||||
let ruinName = "Borut's Smithy"; // Default
|
|
||||||
let npcType = 'merchant';
|
|
||||||
|
|
||||||
if (decor.type === 'ruin') {
|
|
||||||
ruinName = "Merchant House";
|
|
||||||
req = { reqWood: 50, reqStone: 30, reqGold: 30 };
|
|
||||||
}
|
|
||||||
|
|
||||||
uiScene.showProjectMenu(req, () => {
|
|
||||||
// On Contribute Logic
|
|
||||||
if (invSys) {
|
|
||||||
const hasWood = invSys.hasItem('wood', req.reqWood);
|
|
||||||
const hasStone = invSys.hasItem('stone', req.reqStone || 0);
|
|
||||||
const hasGold = invSys.hasItem('gold', req.reqGold || 0);
|
|
||||||
|
|
||||||
// Check all requirements
|
|
||||||
if (hasWood && hasStone && hasGold) {
|
|
||||||
// Consume materials
|
|
||||||
invSys.removeItem('wood', req.reqWood);
|
|
||||||
invSys.removeItem('stone', req.reqStone);
|
|
||||||
invSys.removeItem('gold', req.reqGold);
|
|
||||||
invSys.updateUI();
|
|
||||||
|
|
||||||
console.log(`🏗️ Restoring ${ruinName}...`);
|
|
||||||
|
|
||||||
// Transform Ruin -> House
|
|
||||||
this.scene.terrainSystem.removeDecoration(gridPos.x, gridPos.y);
|
|
||||||
this.scene.terrainSystem.placeStructure(gridPos.x, gridPos.y, 'house');
|
|
||||||
|
|
||||||
// Spawn NPC nearby
|
|
||||||
const npc = new NPC(this.scene, gridPos.x + 1, gridPos.y + 1,
|
|
||||||
this.scene.terrainOffsetX, this.scene.terrainOffsetY, npcType);
|
|
||||||
this.scene.npcs.push(npc);
|
|
||||||
|
|
||||||
// Increase friendship (hearts)
|
|
||||||
if (this.scene.statsSystem) {
|
|
||||||
this.scene.statsSystem.addFriendship(npcType, 10); // +10 hearts
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`✅ ${ruinName} Restored! +10 ❤️ Friendship`);
|
|
||||||
|
|
||||||
// Play build sound
|
|
||||||
if (this.scene.soundManager) this.scene.soundManager.playBuild();
|
|
||||||
} else {
|
|
||||||
// Not enough materials
|
|
||||||
const missing = [];
|
|
||||||
if (!hasWood) missing.push(`${req.reqWood} Wood`);
|
|
||||||
if (!hasStone) missing.push(`${req.reqStone} Stone`);
|
|
||||||
if (!hasGold) missing.push(`${req.reqGold} Gold`);
|
|
||||||
|
|
||||||
console.log(`❌ Not enough materials! Need: ${missing.join(', ')}`);
|
|
||||||
alert(`Potrebuješ še: ${missing.join(', ')} da obnoviš ${ruinName}.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return; // Don't damage it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = this.scene.terrainSystem.damageDecoration(gridPos.x, gridPos.y, 1);
|
// Apply damage
|
||||||
|
const result = this.scene.terrainSystem.damageDecoration(gridPos.x, gridPos.y, damage);
|
||||||
|
|
||||||
if (result === 'destroyed') {
|
if (result === 'destroyed') {
|
||||||
// Play chop sound
|
// Play proper sound
|
||||||
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
if (decor.type === 'tree') {
|
||||||
|
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
||||||
|
} else {
|
||||||
|
// Play stone break sound (using chop for now or generic hit)
|
||||||
|
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// AUTO-LOOT directly to Inventory
|
||||||
|
let lootType = 'wood'; // Default
|
||||||
|
let lootCount = 1;
|
||||||
|
|
||||||
|
if (decor.type === 'tree') {
|
||||||
|
lootType = 'wood';
|
||||||
|
lootCount = 3 + Math.floor(Math.random() * 3); // 3-5 wood
|
||||||
|
} else if (decor.type === 'bush' || decor.type === 'stone') {
|
||||||
|
lootType = 'stone';
|
||||||
|
lootCount = 2 + Math.floor(Math.random() * 3); // 2-4 stone
|
||||||
|
} else if (decor.type === 'flower') {
|
||||||
|
lootType = 'seeds'; // Flowers drop seeds? Or flower item?
|
||||||
|
lootCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🎁 Auto-looted: ${lootCount}x ${lootType}`);
|
||||||
|
|
||||||
|
if (invSys) {
|
||||||
|
invSys.addItem(lootType, lootCount);
|
||||||
|
|
||||||
|
// Show floating text feedback " +3 Wood "
|
||||||
|
const screenPos = this.iso.toScreen(gridPos.x, gridPos.y);
|
||||||
|
const txt = this.scene.add.text(
|
||||||
|
screenPos.x + this.scene.terrainOffsetX,
|
||||||
|
screenPos.y + this.scene.terrainOffsetY - 30,
|
||||||
|
`+${lootCount} ${lootType.toUpperCase()}`,
|
||||||
|
{ fontSize: '14px', fill: '#ffff00', stroke: '#000', strokeThickness: 2 }
|
||||||
|
);
|
||||||
|
txt.setOrigin(0.5);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: txt,
|
||||||
|
y: txt.y - 40,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => txt.destroy()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Spawn loot
|
|
||||||
this.spawnLoot(gridPos.x, gridPos.y, 'wood');
|
|
||||||
} else if (result === 'hit') {
|
} else if (result === 'hit') {
|
||||||
// Play hit sound
|
// Play hit sound
|
||||||
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
||||||
@@ -182,6 +158,99 @@ class InteractionSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleDecorationClick(gridX, gridY) {
|
||||||
|
if (!this.scene.player) return;
|
||||||
|
|
||||||
|
// Check distance
|
||||||
|
const playerPos = this.scene.player.getPosition();
|
||||||
|
const dist = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, gridX, gridY);
|
||||||
|
|
||||||
|
if (dist > 3.0) { // Slightly increased radius for easier clicking
|
||||||
|
console.log('Too far:', dist.toFixed(1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Active Tool
|
||||||
|
let activeTool = null;
|
||||||
|
const uiScene = this.scene.scene.get('UIScene');
|
||||||
|
const invSys = this.scene.inventorySystem;
|
||||||
|
|
||||||
|
if (uiScene && invSys) {
|
||||||
|
const selectedIdx = uiScene.selectedSlot;
|
||||||
|
const slotData = invSys.slots[selectedIdx];
|
||||||
|
if (slotData) activeTool = slotData.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// REUSE LOGIC
|
||||||
|
const id = `${gridX},${gridY}`;
|
||||||
|
if (this.scene.terrainSystem.decorationsMap.has(id)) {
|
||||||
|
const decor = this.scene.terrainSystem.decorationsMap.get(id);
|
||||||
|
|
||||||
|
// Calculate Damage based on Tool
|
||||||
|
let damage = 1; // Default hand damage
|
||||||
|
|
||||||
|
// Tool Logic
|
||||||
|
if (decor.type === 'tree' && activeTool === 'axe') {
|
||||||
|
damage = 3; // Axe destroys tree fast
|
||||||
|
} else if ((decor.type === 'bush' || decor.type === 'stone') && activeTool === 'pickaxe') {
|
||||||
|
damage = 3; // Pickaxe destroys stone fast
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply damage
|
||||||
|
const result = this.scene.terrainSystem.damageDecoration(gridX, gridY, damage);
|
||||||
|
|
||||||
|
if (result === 'destroyed') {
|
||||||
|
// Play proper sound
|
||||||
|
if (decor.type === 'tree') {
|
||||||
|
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
||||||
|
} else {
|
||||||
|
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// AUTO-LOOT directly to Inventory
|
||||||
|
let lootType = 'wood'; // Default
|
||||||
|
let lootCount = 1;
|
||||||
|
|
||||||
|
if (decor.type === 'tree') {
|
||||||
|
lootType = 'wood';
|
||||||
|
lootCount = 3 + Math.floor(Math.random() * 3); // 3-5 wood
|
||||||
|
} else if (decor.type === 'bush' || decor.type === 'stone') {
|
||||||
|
lootType = 'stone';
|
||||||
|
lootCount = 2 + Math.floor(Math.random() * 3); // 2-4 stone
|
||||||
|
} else if (decor.type === 'flower') {
|
||||||
|
lootType = 'seeds';
|
||||||
|
lootCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🎁 Auto-looted: ${lootCount}x ${lootType}`);
|
||||||
|
|
||||||
|
if (invSys) {
|
||||||
|
invSys.addItem(lootType, lootCount);
|
||||||
|
|
||||||
|
// Show floating text feedback
|
||||||
|
const screenPos = this.iso.toScreen(gridX, gridY);
|
||||||
|
const txt = this.scene.add.text(
|
||||||
|
screenPos.x + this.scene.terrainOffsetX,
|
||||||
|
screenPos.y + this.scene.terrainOffsetY - 30,
|
||||||
|
`+${lootCount} ${lootType.toUpperCase()}`,
|
||||||
|
{ fontSize: '14px', fill: '#ffff00', stroke: '#000', strokeThickness: 2 }
|
||||||
|
);
|
||||||
|
txt.setOrigin(0.5);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: txt,
|
||||||
|
y: txt.y - 40,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => txt.destroy()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (result === 'hit') {
|
||||||
|
if (this.scene.soundManager) this.scene.soundManager.playChop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spawnLoot(gridX, gridY, type) {
|
spawnLoot(gridX, gridY, type) {
|
||||||
console.log(`🎁 Spawning ${type} at ${gridX},${gridY}`);
|
console.log(`🎁 Spawning ${type} at ${gridX},${gridY}`);
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,17 @@ class InventorySystem {
|
|||||||
this.slots = new Array(9).fill(null);
|
this.slots = new Array(9).fill(null);
|
||||||
this.maxStack = 99;
|
this.maxStack = 99;
|
||||||
|
|
||||||
// Initial test items
|
// Generate tool icons if missing
|
||||||
|
if (typeof TextureGenerator !== 'undefined') {
|
||||||
|
TextureGenerator.createToolSprites(this.scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial items
|
||||||
|
this.addItem('axe', 1); // 🪓 Sekira
|
||||||
|
this.addItem('pickaxe', 1); // ⛏️ Kramp
|
||||||
this.addItem('hoe', 1);
|
this.addItem('hoe', 1);
|
||||||
this.addItem('seeds', 10);
|
this.addItem('seeds', 5); // Zmanjšano število semen
|
||||||
this.addItem('wood', 100); // For restoration
|
// Removed default wood/stone so player has to gather them
|
||||||
this.addItem('stone', 100); // For restoration
|
|
||||||
|
|
||||||
this.gold = 0;
|
this.gold = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ class TerrainSystem {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Tipi terena z threshold vrednostmi + Y-LAYER STACKING
|
// Tipi terena z threshold vrednostmi + Y-LAYER STACKING
|
||||||
this.terrainTypes = {
|
this.terrainTypes = {
|
||||||
WATER: { threshold: 0.3, color: 0x2166aa, name: 'water', texture: 'tile_water', yLayer: -1 },
|
WATER: { threshold: 0.3, color: 0x2166aa, name: 'water', texture: 'tile_water', yLayer: -1 },
|
||||||
@@ -73,6 +72,7 @@ class TerrainSystem {
|
|||||||
DIRT: { threshold: 0.75, color: 0x8b6f47, name: 'dirt', texture: 'tile_dirt', yLayer: 2 }, // C: Full dirt
|
DIRT: { threshold: 0.75, color: 0x8b6f47, name: 'dirt', texture: 'tile_dirt', yLayer: 2 }, // C: Full dirt
|
||||||
STONE: { threshold: 1.0, color: 0x7d7d7d, name: 'stone', texture: 'tile_stone', yLayer: 3 },
|
STONE: { threshold: 1.0, color: 0x7d7d7d, name: 'stone', texture: 'tile_stone', yLayer: 3 },
|
||||||
|
|
||||||
|
PATH: { threshold: 999, color: 0x9b7653, name: 'path', texture: 'tile_path', yLayer: 0 }, // Pot/Road
|
||||||
FARMLAND: { threshold: 999, color: 0x4a3c2a, name: 'farmland', texture: 'tile_farmland', yLayer: 0 }
|
FARMLAND: { threshold: 999, color: 0x4a3c2a, name: 'farmland', texture: 'tile_farmland', yLayer: 0 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ class TerrainSystem {
|
|||||||
|
|
||||||
const tileW = this.iso.tileWidth;
|
const tileW = this.iso.tileWidth;
|
||||||
const tileH = this.iso.tileHeight;
|
const tileH = this.iso.tileHeight;
|
||||||
const thickness = 25; // Minecraft-style thickness (increased from 10)
|
const thickness = 8; // Minimal thickness - nearly 2D
|
||||||
|
|
||||||
const graphics = this.scene.make.graphics({ x: 0, y: 0, add: false });
|
const graphics = this.scene.make.graphics({ x: 0, y: 0, add: false });
|
||||||
|
|
||||||
@@ -197,6 +197,14 @@ class TerrainSystem {
|
|||||||
const py = Math.random() * tileH;
|
const py = Math.random() * tileH;
|
||||||
graphics.fillRect(px, py, 2, 1);
|
graphics.fillRect(px, py, 2, 1);
|
||||||
}
|
}
|
||||||
|
} else if (type.name === 'path') {
|
||||||
|
// Path texture: Small gravel stones
|
||||||
|
graphics.fillStyle(0x7a5e42, 0.5); // Darker brown
|
||||||
|
for (let i = 0; i < 12; i++) {
|
||||||
|
const px = Math.random() * tileW;
|
||||||
|
const py = Math.random() * tileH;
|
||||||
|
graphics.fillRect(px, py, 2, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Crisp black outline for block definition
|
// 5. Crisp black outline for block definition
|
||||||
@@ -294,6 +302,16 @@ class TerrainSystem {
|
|||||||
// Get terrain type based on BOTH noise and elevation (Y-layer)
|
// Get terrain type based on BOTH noise and elevation (Y-layer)
|
||||||
let terrainType = this.getTerrainTypeByElevation(noiseValue, elevation);
|
let terrainType = this.getTerrainTypeByElevation(noiseValue, elevation);
|
||||||
|
|
||||||
|
// === PATH GENERATION ===
|
||||||
|
// Use a separate noise layer for paths (higher frequency for winding roads)
|
||||||
|
const pathNoise = this.noise.getNormalized(x, y, 0.08, 2);
|
||||||
|
|
||||||
|
// Create minimal paths - if noise is in a very specific narrow band
|
||||||
|
// Avoid water (0.3 threshold) and edges
|
||||||
|
if (pathNoise > 0.48 && pathNoise < 0.52 && noiseValue > 0.35) {
|
||||||
|
terrainType = this.terrainTypes.PATH;
|
||||||
|
}
|
||||||
|
|
||||||
// === FLOATING ISLAND EDGE ===
|
// === FLOATING ISLAND EDGE ===
|
||||||
const edgeDistance = 2; // Tiles from edge (tighter border)
|
const edgeDistance = 2; // Tiles from edge (tighter border)
|
||||||
const isNearEdge = x < edgeDistance || x >= this.width - edgeDistance ||
|
const isNearEdge = x < edgeDistance || x >= this.width - edgeDistance ||
|
||||||
@@ -333,20 +351,20 @@ class TerrainSystem {
|
|||||||
let decorType = null;
|
let decorType = null;
|
||||||
let maxHp = 1;
|
let maxHp = 1;
|
||||||
|
|
||||||
if (terrainType.name === 'grass') {
|
if (terrainType.name.includes('grass')) { // Check ANY grass type
|
||||||
const rand = Math.random();
|
const rand = Math.random();
|
||||||
|
|
||||||
// Na hribih več kamnov
|
// Na hribih več kamnov
|
||||||
if (elevation > 0.6 && rand < 0.05) {
|
if (elevation > 0.6 && rand < 0.05) {
|
||||||
decorType = 'bush'; // Kamni (bomo kasneje naredili 'stone' tip)
|
decorType = 'bush'; // Kamni
|
||||||
maxHp = 5;
|
maxHp = 5;
|
||||||
} else if (rand < 0.01) {
|
} else if (rand < 0.025) { // Reduced to 2.5% trees (optimum balance)
|
||||||
decorType = 'tree';
|
decorType = 'tree';
|
||||||
maxHp = 5;
|
maxHp = 5;
|
||||||
} else if (rand < 0.015) {
|
} else if (rand < 0.03) {
|
||||||
decorType = 'gravestone'; // 💀 Nagrobniki
|
decorType = 'gravestone'; // 💀 Nagrobniki
|
||||||
maxHp = 10; // Težje uničiti
|
maxHp = 10; // Težje uničiti
|
||||||
} else if (rand < 0.1) {
|
} else if (rand < 0.08) {
|
||||||
decorType = 'flower';
|
decorType = 'flower';
|
||||||
maxHp = 1;
|
maxHp = 1;
|
||||||
}
|
}
|
||||||
@@ -595,7 +613,11 @@ class TerrainSystem {
|
|||||||
this.visibleTiles.set(key, sprite);
|
this.visibleTiles.set(key, sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crop Logic (render before decor or after? Same layer mostly)
|
// Elevation effect matching tile logic
|
||||||
|
const tileData = this.tiles[y][x];
|
||||||
|
const elevationOffset = tileData.elevation * -25;
|
||||||
|
|
||||||
|
// Crop Logic
|
||||||
if (this.tiles[y][x].hasCrop) {
|
if (this.tiles[y][x].hasCrop) {
|
||||||
neededCropKeys.add(key);
|
neededCropKeys.add(key);
|
||||||
if (!this.visibleCrops.has(key)) {
|
if (!this.visibleCrops.has(key)) {
|
||||||
@@ -606,7 +628,7 @@ class TerrainSystem {
|
|||||||
sprite.setTexture(`crop_stage_${cropData.stage}`);
|
sprite.setTexture(`crop_stage_${cropData.stage}`);
|
||||||
sprite.setPosition(
|
sprite.setPosition(
|
||||||
cropPos.x + this.offsetX,
|
cropPos.x + this.offsetX,
|
||||||
cropPos.y + this.offsetY + this.iso.tileHeight / 2
|
cropPos.y + this.offsetY + this.iso.tileHeight / 2 + elevationOffset
|
||||||
);
|
);
|
||||||
const depth = this.iso.getDepth(x, y);
|
const depth = this.iso.getDepth(x, y);
|
||||||
sprite.setDepth(depth + 1); // Just slightly above tile
|
sprite.setDepth(depth + 1); // Just slightly above tile
|
||||||
@@ -628,9 +650,11 @@ class TerrainSystem {
|
|||||||
const decorPos = this.iso.toScreen(x, y);
|
const decorPos = this.iso.toScreen(x, y);
|
||||||
const sprite = this.decorationPool.get();
|
const sprite = this.decorationPool.get();
|
||||||
sprite.setTexture(decor.type);
|
sprite.setTexture(decor.type);
|
||||||
|
|
||||||
|
// Apply same elevation offset as tile
|
||||||
sprite.setPosition(
|
sprite.setPosition(
|
||||||
decorPos.x + this.offsetX,
|
decorPos.x + this.offsetX,
|
||||||
decorPos.y + this.offsetY + this.iso.tileHeight / 2
|
decorPos.y + this.offsetY + this.iso.tileHeight / 2 + elevationOffset
|
||||||
);
|
);
|
||||||
|
|
||||||
const depth = this.iso.getDepth(x, y);
|
const depth = this.iso.getDepth(x, y);
|
||||||
@@ -638,6 +662,20 @@ class TerrainSystem {
|
|||||||
else sprite.setDepth(depth + 1000); // Taller objects update depth
|
else sprite.setDepth(depth + 1000); // Taller objects update depth
|
||||||
|
|
||||||
sprite.flipX = (x + y) % 2 === 0;
|
sprite.flipX = (x + y) % 2 === 0;
|
||||||
|
|
||||||
|
// INTERACTIVITY FIX: Allow clicking sprites directly
|
||||||
|
sprite.setInteractive({ pixelPerfect: true, useHandCursor: true });
|
||||||
|
|
||||||
|
// Clear old listeners
|
||||||
|
sprite.off('pointerdown');
|
||||||
|
// Add click listener
|
||||||
|
sprite.on('pointerdown', (pointer) => {
|
||||||
|
if (this.scene.interactionSystem) {
|
||||||
|
// Manually trigger interaction logic
|
||||||
|
this.scene.interactionSystem.handleDecorationClick(x, y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.visibleDecorations.set(key, sprite);
|
this.visibleDecorations.set(key, sprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -765,4 +765,70 @@ class TextureGenerator {
|
|||||||
canvas.refresh();
|
canvas.refresh();
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== ITEM ICONS ==========
|
||||||
|
|
||||||
|
static createToolSprites(scene) {
|
||||||
|
// AXE ICON
|
||||||
|
if (!scene.textures.exists('item_axe')) {
|
||||||
|
const size = 32;
|
||||||
|
const canvas = scene.textures.createCanvas('item_axe', size, size);
|
||||||
|
const ctx = canvas.getContext();
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, size, size);
|
||||||
|
|
||||||
|
// Handle
|
||||||
|
ctx.fillStyle = '#8B4513';
|
||||||
|
ctx.fillRect(14, 10, 4, 18);
|
||||||
|
|
||||||
|
// Blade (Double bit axe style)
|
||||||
|
ctx.fillStyle = '#C0C0C0'; // Silver
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(16, 12);
|
||||||
|
ctx.lineTo(6, 6); // Left Top
|
||||||
|
ctx.lineTo(6, 18); // Left Bottom
|
||||||
|
ctx.lineTo(16, 14); // Center Bottom
|
||||||
|
ctx.lineTo(26, 18); // Right Bottom
|
||||||
|
ctx.lineTo(26, 6); // Right Top
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// Edge
|
||||||
|
ctx.strokeStyle = '#FFFFFF';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
canvas.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// PICKAXE ICON
|
||||||
|
if (!scene.textures.exists('item_pickaxe')) {
|
||||||
|
const size = 32;
|
||||||
|
const canvas = scene.textures.createCanvas('item_pickaxe', size, size);
|
||||||
|
const ctx = canvas.getContext();
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, size, size);
|
||||||
|
|
||||||
|
// Handle
|
||||||
|
ctx.fillStyle = '#8B4513';
|
||||||
|
ctx.fillRect(14, 10, 4, 18);
|
||||||
|
|
||||||
|
// Head (Curved)
|
||||||
|
ctx.fillStyle = '#808080'; // Dark Grey
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(2, 12); // Left Tip
|
||||||
|
ctx.quadraticCurveTo(16, 4, 30, 12); // Curve to Right Tip
|
||||||
|
ctx.lineTo(28, 16); // Right Inner
|
||||||
|
ctx.quadraticCurveTo(16, 8, 4, 16); // Curve to Left Inner
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// Outline
|
||||||
|
ctx.strokeStyle = '#000000';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
canvas.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user