udomacenje zombija in uboj\

This commit is contained in:
2025-12-07 12:47:47 +01:00
parent 8e401a9d6f
commit 2404d44ef7
10 changed files with 1086 additions and 532 deletions

View File

@@ -3,315 +3,228 @@ class InteractionSystem {
this.scene = scene;
this.iso = new IsometricUtils(48, 24);
// Input listener setup (only once)
// Input listener setup
this.scene.input.on('pointerdown', (pointer) => {
if (pointer.button === 0) { // Left Click
this.handleLeftClick(pointer);
const worldX = pointer.worldX - this.scene.terrainOffsetX;
const worldY = pointer.worldY - this.scene.terrainOffsetY;
const gridPos = this.iso.toGrid(worldX, worldY);
this.handleInteraction(gridPos.x, gridPos.y, false);
}
});
// Key E listener (Easy Interaction/Tame)
this.scene.input.keyboard.on('keydown-E', () => {
this.handleInteractKey();
});
// Loot Array
this.drops = [];
}
handleLeftClick(pointer) {
if (!this.scene.player) return;
// 1. Account for camera and offset
const worldX = pointer.worldX - this.scene.terrainOffsetX;
const worldY = pointer.worldY - this.scene.terrainOffsetY;
// 2. Convert to Grid
const gridPos = this.iso.toGrid(worldX, worldY);
// 3. Check distance
handleInteractKey() {
if (!this.scene.player || !this.scene.npcs) return;
const playerPos = this.scene.player.getPosition();
const dist = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, gridPos.x, gridPos.y);
// Allow interaction within radius of 2.5 tiles
if (dist > 2.5) {
console.log('Too far:', dist.toFixed(1));
return;
}
// Find nearest NPC
let nearest = null;
let minDist = 2.5; // Interaction range
console.log(`☝️ Clicked tile: ${gridPos.x},${gridPos.y}`);
// DETERMINE TOOL / ACTION
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;
}
// 0. Build Mode Override
if (this.scene.buildingSystem && this.scene.buildingSystem.isBuildMode) {
this.scene.buildingSystem.tryBuild(gridPos.x, gridPos.y);
return; // Consume click
}
// 3.5 Check for NPC Click
if (this.scene.npcs) {
for (const npc of this.scene.npcs) {
if (Math.abs(npc.gridX - gridPos.x) < 2.5 && Math.abs(npc.gridY - gridPos.y) < 2.5) {
console.log(`🗣️ Interact with NPC: ${npc.type}`);
if (npc.type === 'zombie') {
// Taming Logic
npc.toggleState();
return; // Done
}
if (npc.type === 'merchant') {
// Open Trade Menu
if (uiScene && invSys) {
uiScene.showTradeMenu(invSys);
}
return; // Stop processing
}
return; // Stop processing other clicks (farming/terrain) if clicked NPC
}
for (const npc of this.scene.npcs) {
const d = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, npc.gridX, npc.gridY);
if (d < minDist) {
minDist = d;
nearest = npc;
}
}
// 4. Try Farming Action (Tilling, Planting, Harvesting)
if (this.scene.farmingSystem) {
const didFarm = this.scene.farmingSystem.interact(gridPos.x, gridPos.y, activeTool);
if (didFarm) {
// Animation?
return;
}
}
// 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
// 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(gridPos.x, gridPos.y, damage);
if (result === 'destroyed') {
// 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()
});
}
} else if (result === 'hit') {
// Play hit sound
if (this.scene.soundManager) this.scene.soundManager.playChop();
if (nearest) {
console.log('E Interacted with:', nearest.type);
if (nearest.type === 'zombie') {
// Always Tame on E key (Combat is Space/Click)
nearest.tame();
} else {
nearest.toggleState(); // Merchant/NPC talk
}
}
}
handleDecorationClick(gridX, gridY) {
handleInteraction(gridX, gridY, isAttack = false) {
if (!this.scene.player) return;
// Check distance
// 3. 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;
}
// Allow interaction within radius of 2.5 tiles (1.5 for attack)
const maxDist = isAttack ? 1.5 : 2.5;
if (dist > maxDist) return;
// Get Active Tool
let activeTool = null;
// DETERMINE TOOL
let activeTool = isAttack ? 'sword' : null;
const uiScene = this.scene.scene.get('UIScene');
const invSys = this.scene.inventorySystem;
if (uiScene && invSys) {
if (uiScene && invSys && !isAttack) {
const selectedIdx = uiScene.selectedSlot;
const slotData = invSys.slots[selectedIdx];
if (slotData) activeTool = slotData.type;
}
// REUSE LOGIC
if (isAttack && invSys) {
const selectedIdx = uiScene.selectedSlot;
const slotData = invSys.slots[selectedIdx];
if (slotData) activeTool = slotData.type;
}
// 0. Build Mode Override (Only click)
if (!isAttack && this.scene.buildingSystem && this.scene.buildingSystem.isBuildMode) {
this.scene.buildingSystem.tryBuild(gridX, gridY);
return;
}
// 3.5 Check for NPC Interaction
if (this.scene.npcs) {
for (const npc of this.scene.npcs) {
// Increased radius to 1.8 to catch moving NPCs easier
if (Math.abs(npc.gridX - gridX) < 1.8 && Math.abs(npc.gridY - gridY) < 1.8) {
if (npc.type === 'merchant' && !isAttack) {
if (uiScene && invSys) uiScene.showTradeMenu(invSys);
return;
}
if (npc.type === 'zombie') {
// Logic: Attack vs Tame
const isWeapon = activeTool === 'sword' || activeTool === 'axe' || activeTool === 'pickaxe';
if (isAttack || isWeapon) {
// COMBAT
let damage = 1;
if (activeTool === 'sword') damage = 5;
if (activeTool === 'axe') damage = 3;
if (activeTool === 'pickaxe') damage = 2;
if (npc.takeDamage) {
npc.takeDamage(damage);
}
return;
}
else {
// TAME ATTEMPT
console.log('🤝 Attempting to TAME zombie at', npc.gridX, npc.gridY);
npc.tame();
return;
}
}
if (!isAttack) npc.toggleState();
return;
}
}
}
// 4. Try Farming Action
if (this.scene.farmingSystem && !isAttack) {
const didFarm = this.scene.farmingSystem.interact(gridX, gridY, activeTool);
if (didFarm) return;
}
// 5. Try damage decoration
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
let damage = 1;
// 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
if (decor.type === 'tree') {
damage = (activeTool === 'axe') ? 3 : 1;
if (!isAttack && activeTool !== 'axe') return;
}
else if (decor.type === 'stone') {
damage = (activeTool === 'pickaxe') ? 3 : 1;
if (!isAttack && activeTool !== 'pickaxe') return;
}
else if (decor.type === 'bush') damage = 2;
// Apply damage
const result = this.scene.terrainSystem.damageDecoration(gridX, gridY, damage);
decor.hp -= damage;
this.showFloatingText(`${-damage}`, gridX, gridY, '#ffaaaa');
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();
if (decor.hp <= 0) {
const type = this.scene.terrainSystem.removeDecoration(gridX, gridY);
// Loot logic
let loot = 'wood';
if (type === 'stone') loot = 'stone';
if (type === 'bush') loot = 'seeds'; // Maybe berries?
if (type === 'tree') {
this.spawnLoot(gridX, gridY, 'wood');
this.spawnLoot(gridX, gridY, 'wood');
this.spawnLoot(gridX, gridY, 'wood');
}
else {
this.spawnLoot(gridX, gridY, loot);
}
// 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);
} else {
// Shake visual
const sprite = this.scene.terrainSystem.visibleDecorations.get(id);
if (sprite) {
this.scene.tweens.add({
targets: txt,
y: txt.y - 40,
alpha: 0,
duration: 1000,
onComplete: () => txt.destroy()
targets: sprite,
x: sprite.x + 2, yoyo: true, duration: 50, repeat: 2
});
sprite.setTint(0xffaaaa);
this.scene.time.delayedCall(200, () => sprite.clearTint());
}
} else if (result === 'hit') {
if (this.scene.soundManager) this.scene.soundManager.playChop();
}
}
}
showFloatingText(text, gridX, gridY, color) {
const screenPos = this.iso.toScreen(gridX, gridY);
const txt = this.scene.add.text(
screenPos.x + this.scene.terrainOffsetX,
screenPos.y + this.scene.terrainOffsetY - 30,
text,
{ fontSize: '14px', fill: color, stroke: '#000', strokeThickness: 2 }
).setOrigin(0.5);
this.scene.tweens.add({ targets: txt, y: txt.y - 40, alpha: 0, duration: 1000, onComplete: () => txt.destroy() });
}
spawnLoot(gridX, gridY, type) {
console.log(`🎁 Spawning ${type} at ${gridX},${gridY}`);
// Convert to Screen
const screenPos = this.iso.toScreen(gridX, gridY);
const x = screenPos.x + this.scene.terrainOffsetX;
const y = screenPos.y + this.scene.terrainOffsetY;
// Create simplistic item drop sprite
let symbol = '?';
if (type === 'wood') symbol = '🪵';
if (type === 'stone') symbol = '🪨';
if (type === 'seeds') symbol = '🌱';
if (type === 'wheat') symbol = '🌾';
if (type === 'hoe') symbol = '🛠️';
if (type === 'axe') symbol = '🪓';
if (type === 'item_bone') symbol = '🦴';
const drop = this.scene.add.text(x, y - 20, symbol, { fontSize: '20px' });
drop.setOrigin(0.5);
drop.setDepth(this.iso.getDepth(gridX, gridY) + 500); // above tiles
drop.setDepth(this.iso.getDepth(gridX, gridY) + 500);
// Bounce animation
this.scene.tweens.add({
targets: drop,
y: y - 40,
duration: 500,
yoyo: true,
ease: 'Sine.easeOut',
repeat: -1
targets: drop, y: y - 40, duration: 500, yoyo: true, ease: 'Sine.easeOut', repeat: -1
});
this.drops.push({
gridX,
gridY,
sprite: drop,
type: type
});
this.drops.push({ gridX, gridY, sprite: drop, type: type });
}
update() {
// Check for player pickup
if (!this.scene.player) return;
const playerPos = this.scene.player.getPosition();
// Filter drops to pick up
for (let i = this.drops.length - 1; i >= 0; i--) {
const drop = this.drops[i];
// Check if player is ON the drop tile
if (Math.abs(drop.gridX - playerPos.x) < 0.8 && Math.abs(drop.gridY - playerPos.y) < 0.8) {
// Pick up!
console.log('🎒 Picked up:', drop.type);
// Play pickup sound
if (this.scene.soundManager) this.scene.soundManager.playPickup();
// Add to inventory
if (this.scene.inventorySystem) {
this.scene.inventorySystem.addItem(drop.type, 1);
}
// Destroy visual
if (this.scene.inventorySystem) this.scene.inventorySystem.addItem(drop.type, 1);
drop.sprite.destroy();
this.drops.splice(i, 1);
}