različne velikosti dreves

This commit is contained in:
2025-12-07 03:40:50 +01:00
parent 9eb57ed117
commit 521468c797
8 changed files with 323 additions and 109 deletions

View File

@@ -86,95 +86,71 @@ class InteractionSystem {
}
}
// 5. Try damage decoration (fallback)
// 5. Try damage or interact decoration
if (this.scene.terrainSystem) {
const id = `${gridPos.x},${gridPos.y}`;
if (this.scene.terrainSystem.decorationsMap.has(id)) {
const decor = this.scene.terrainSystem.decorationsMap.get(id);
// 5. Try damage decoration
const id = `${gridPos.x},${gridPos.y}`;
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
if (decor.type === 'ruin' || decor.type === 'ruin_borut') {
// Check if near
if (dist > 2.5) {
console.log('Ruin too far.');
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
}
// 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
}
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') {
// Play chop sound
if (this.scene.soundManager) this.scene.soundManager.playChop();
// Play proper sound
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') {
// Play hit sound
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) {
console.log(`🎁 Spawning ${type} at ${gridX},${gridY}`);

View File

@@ -7,11 +7,17 @@ class InventorySystem {
this.slots = new Array(9).fill(null);
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('seeds', 10);
this.addItem('wood', 100); // For restoration
this.addItem('stone', 100); // For restoration
this.addItem('seeds', 5); // Zmanjšano število semen
// Removed default wood/stone so player has to gather them
this.gold = 0;
}

View File

@@ -61,7 +61,6 @@ class TerrainSystem {
}
);
// Tipi terena z threshold vrednostmi + Y-LAYER STACKING
this.terrainTypes = {
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
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 }
};
}
@@ -115,7 +115,7 @@ class TerrainSystem {
const tileW = this.iso.tileWidth;
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 });
@@ -197,6 +197,14 @@ class TerrainSystem {
const py = Math.random() * tileH;
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
@@ -294,6 +302,16 @@ class TerrainSystem {
// Get terrain type based on BOTH noise and elevation (Y-layer)
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 ===
const edgeDistance = 2; // Tiles from edge (tighter border)
const isNearEdge = x < edgeDistance || x >= this.width - edgeDistance ||
@@ -333,20 +351,20 @@ class TerrainSystem {
let decorType = null;
let maxHp = 1;
if (terrainType.name === 'grass') {
if (terrainType.name.includes('grass')) { // Check ANY grass type
const rand = Math.random();
// Na hribih več kamnov
if (elevation > 0.6 && rand < 0.05) {
decorType = 'bush'; // Kamni (bomo kasneje naredili 'stone' tip)
decorType = 'bush'; // Kamni
maxHp = 5;
} else if (rand < 0.01) {
} else if (rand < 0.025) { // Reduced to 2.5% trees (optimum balance)
decorType = 'tree';
maxHp = 5;
} else if (rand < 0.015) {
} else if (rand < 0.03) {
decorType = 'gravestone'; // 💀 Nagrobniki
maxHp = 10; // Težje uničiti
} else if (rand < 0.1) {
} else if (rand < 0.08) {
decorType = 'flower';
maxHp = 1;
}
@@ -595,7 +613,11 @@ class TerrainSystem {
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) {
neededCropKeys.add(key);
if (!this.visibleCrops.has(key)) {
@@ -606,7 +628,7 @@ class TerrainSystem {
sprite.setTexture(`crop_stage_${cropData.stage}`);
sprite.setPosition(
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);
sprite.setDepth(depth + 1); // Just slightly above tile
@@ -628,9 +650,11 @@ class TerrainSystem {
const decorPos = this.iso.toScreen(x, y);
const sprite = this.decorationPool.get();
sprite.setTexture(decor.type);
// Apply same elevation offset as tile
sprite.setPosition(
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);
@@ -638,6 +662,20 @@ class TerrainSystem {
else sprite.setDepth(depth + 1000); // Taller objects update depth
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);
}
}