Files
novafarma/old_logic/src_backup_1768938138/entities/Player.js
2026-01-21 01:08:21 +01:00

927 lines
31 KiB
JavaScript

// Player Entity
// Igralec z WASD kontrolami in isometrično podporo
class Player {
constructor(scene, gridX = 50, gridY = 50, offsetX = 0, offsetY = 0) {
this.scene = scene;
this.gridX = gridX;
this.gridY = gridY;
// Terrain offset
this.offsetX = offsetX;
this.offsetY = offsetY;
this.tileSize = (this.scene.terrainSystem && this.scene.terrainSystem.tileSize) || 48;
this.iso = new IsometricUtils(this.tileSize, this.tileSize / 2);
// 🎮 SMOOTH MOVEMENT SYSTEM (Hybrid)
this.moveSpeed = 100; // Normal speed px/s
this.sprintSpeed = 200; // Sprint speed px/s
this.acceleration = 0.15; // How fast to reach target speed
// Velocity (current movement)
this.velocity = { x: 0, y: 0 };
// Target velocity (where we want to go)
this.targetVelocity = { x: 0, y: 0 };
// Sprint system
this.sprinting = false;
this.energy = 100;
this.maxEnergy = 100;
this.energyDrain = 10; // per second while sprinting
// State
// State
this.isMoving = false;
this.isActing = false; // 🛑 Stardew Action Lock
this.direction = 'down';
this.lastDir = { x: 0, y: 1 }; // Default south
// Stats
this.hp = 100;
this.maxHp = 100;
this.isDead = false;
// Kreira sprite
this.createSprite();
// Setup kontrole
this.setupControls();
// Space za napad
this.scene.input.keyboard.on('keydown-SPACE', () => {
if (!this.isDead) this.attack();
});
// Začetna pozicija
this.updatePosition();
}
takeDamage(amount) {
if (this.isDead) return;
// GOD MODE - Invincibility
if (window.godMode) {
console.log('⚡ GOD MODE: Damage blocked!');
return;
}
this.hp -= amount;
console.log(`Player HP: ${this.hp}`);
// Visual Feedback
this.scene.cameras.main.shake(100, 0.01);
this.sprite.setTint(0xff0000);
this.scene.time.delayedCall(200, () => {
if (!this.isDead) this.sprite.clearTint();
});
// Update UI (če obstaja StatsSystem ali UI)
if (this.scene.statsSystem) {
// Scene specific stats update if linked
}
if (this.hp <= 0) {
this.die();
}
}
die() {
this.isDead = true;
this.sprite.setTint(0x555555);
this.sprite.setRotation(Math.PI / 2); // Lie down
console.log('💀 PLAYER DIED');
// Death Sound
if (this.scene.soundManager) {
this.scene.soundManager.playDeath();
}
// Show Game Over / Reload
const txt = this.scene.add.text(this.scene.cameras.main.midPoint.x, this.scene.cameras.main.midPoint.y, 'YOU DIED', {
fontSize: '64px', color: '#ff0000', fontStyle: 'bold', stroke: '#000', strokeThickness: 6
}).setOrigin(0.5).setDepth(20000);
this.scene.time.delayedCall(3000, () => {
window.location.reload();
});
}
createSprite() {
// Priority: kai_main (real sprite) > player_style32 > fallback
let texKey = 'kai_main';
if (!this.scene.textures.exists(texKey)) {
texKey = 'player_style32';
}
// Fallback to generated pink square if nothing loaded
if (!this.scene.textures.exists(texKey)) {
console.warn('⚠️ No Kai sprite found! Generating pink fallback...');
TextureGenerator.createPlayerSprite(this.scene, 'player_fallback');
texKey = 'player_fallback';
}
// Kreira sprite
// 🎨 FLAT 2D (NEW!) - Direct screen conversion
const screenPos = {
x: Math.round((this.gridX * this.tileSize) + (this.tileSize / 2)),
y: Math.round((this.gridY * this.tileSize) + (this.tileSize / 2))
};
this.sprite = this.scene.add.sprite(
screenPos.x + this.offsetX,
screenPos.y + this.offsetY,
texKey,
0 // CRITICAL: Start with frame 0 (first frame only)
);
this.sprite.setOrigin(0.5, 1.0); // Bottom center - new sprite has full character!
// Scale based on sprite type
if (texKey === 'player_protagonist') {
this.sprite.setScale(0.25); // 0.25 scale for correct size
} else {
this.sprite.setScale(0.5); // Fallback sprite
}
// --- HAND / HELD ITEM SPRITE ---
this.handSprite = this.scene.add.sprite(
screenPos.x + this.offsetX + 10,
screenPos.y + this.offsetY - 25,
'item_axe'
);
this.handSprite.setOrigin(0.5, 0.5);
this.handSprite.setScale(0.25);
this.handSprite.setVisible(false);
this.updateDepth();
}
setupControls() {
this.keys = this.scene.input.keyboard.addKeys({
// WASD
w: Phaser.Input.Keyboard.KeyCodes.W,
a: Phaser.Input.Keyboard.KeyCodes.A,
s: Phaser.Input.Keyboard.KeyCodes.S,
d: Phaser.Input.Keyboard.KeyCodes.D,
// Arrow Keys
up: Phaser.Input.Keyboard.KeyCodes.UP,
down: Phaser.Input.Keyboard.KeyCodes.DOWN,
left: Phaser.Input.Keyboard.KeyCodes.LEFT,
right: Phaser.Input.Keyboard.KeyCodes.RIGHT,
// Actions
space: Phaser.Input.Keyboard.KeyCodes.SPACE,
shift: Phaser.Input.Keyboard.KeyCodes.SHIFT,
r: Phaser.Input.Keyboard.KeyCodes.R,
x: Phaser.Input.Keyboard.KeyCodes.X, // 🪓 Chopping
c: Phaser.Input.Keyboard.KeyCodes.C // ⛏️ Mining
});
// Gamepad Events
this.scene.input.gamepad.on('connected', (pad) => {
this.setupGamepadEvents(pad);
});
if (this.scene.input.gamepad.total > 0) {
this.setupGamepadEvents(this.scene.input.gamepad.getPad(0));
}
}
setupGamepadEvents(pad) {
if (!pad) return;
console.log('🎮 Gamepad Connected:', pad.id);
pad.on('down', (index) => {
if (this.isDead) return;
// A Button (0) - Attack
if (index === 0) {
this.attack();
}
// X Button (2) - Interact (Pick/Tame)
if (index === 2) {
const targetX = this.gridX + this.lastDir.x;
const targetY = this.gridY + this.lastDir.y;
if (this.scene.interactionSystem) {
this.scene.interactionSystem.handleInteraction(targetX, targetY);
}
}
// Y Button (3) - Crafting
if (index === 3) {
// Zahteva, da UIScene posluša ta event, ali pa direktni klic
const ui = this.scene.scene.get('UIScene');
if (ui) ui.toggleCrafting();
}
// B Button (1) - Inventory
if (index === 1) {
const ui = this.scene.scene.get('UIScene');
if (ui) ui.toggleInventory();
}
});
}
attack() {
console.log('⚔️ Player Attack!');
// Attack Sound
if (this.scene.soundManager) {
this.scene.soundManager.playAttack();
}
if (this.scene.interactionSystem) {
const targetX = this.gridX + this.lastDir.x;
const targetY = this.gridY + this.lastDir.y;
this.scene.interactionSystem.handleInteraction(targetX, targetY, true); // true = attackMode
}
// Animation
this.scene.tweens.add({
targets: this.handSprite,
angle: 45, // Swing
yoyo: true,
duration: 100
});
// Player lunge
const lungeX = this.sprite.x + (this.lastDir.x * 10);
const lungeY = this.sprite.y + (this.lastDir.y * 5);
this.scene.tweens.add({
targets: this.sprite,
x: lungeX,
y: lungeY,
yoyo: true,
duration: 50
});
}
update(delta) {
// Convert delta to seconds
const dt = delta / 1000;
// 🎮 HANDLE INPUT (always check for input)
this.handleInput(dt);
// 🏃 APPLY SMOOTH MOVEMENT
// Smoothly interpolate current velocity toward target velocity
this.velocity.x = Phaser.Math.Linear(
this.velocity.x,
this.targetVelocity.x,
this.acceleration
);
this.velocity.y = Phaser.Math.Linear(
this.velocity.y,
this.targetVelocity.y,
this.acceleration
);
// Apply velocity to sprite position
this.sprite.x += this.velocity.x * dt;
this.sprite.y += this.velocity.y * dt;
// Update grid position from pixel position
const screenPos = { x: this.sprite.x - this.offsetX, y: this.sprite.y - this.offsetY };
// 🎨 FLAT 2D (NEW!) - Direct grid conversion
this.gridX = Math.floor(screenPos.x / this.tileSize);
this.gridY = Math.floor(screenPos.y / this.tileSize);
// Check if moving
const speed = Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2);
this.isMoving = speed > 5;
// 🎨 UPDATE ANIMATION
this.updateAnimation();
// 💧 ENERGY REGENERATION
if (!this.sprinting && this.energy < this.maxEnergy) {
this.energy = Math.min(this.maxEnergy, this.energy + 20 * dt);
}
// ⚡ ENERGY DRAIN WHILE SPRINTING
if (this.sprinting && this.isMoving && this.energy > 0) {
this.energy -= this.energyDrain * dt;
if (this.energy <= 0) {
this.energy = 0;
this.sprinting = false; // Can't sprint without energy
}
}
// 🔧 UPDATE HELD ITEM
this.updateHeldItem();
// 🌱 SPACE KEY - Farming Action
if (this.keys.space && Phaser.Input.Keyboard.JustDown(this.keys.space)) {
this.handleFarmingAction();
}
// 🚬 R KEY - Use Item
if (this.keys.r && Phaser.Input.Keyboard.JustDown(this.keys.r)) {
this.useSelectedItem();
}
// 🪓 X KEY - Chopping Action
if (this.keys.x && Phaser.Input.Keyboard.JustDown(this.keys.x)) {
this.handleChoppingAction();
}
// ⛏️ C KEY - Mining Action
if (this.keys.c && Phaser.Input.Keyboard.JustDown(this.keys.c)) {
this.handleMiningAction();
}
}
updateHeldItem() {
const uiScene = this.scene.scene.get('UIScene');
const invSys = this.scene.inventorySystem;
if (uiScene && invSys) {
const selectedIdx = uiScene.selectedSlot;
const slot = invSys.slots[selectedIdx];
if (slot && (slot.type === 'axe' || slot.type === 'pickaxe' || slot.type === 'hoe' || slot.type === 'sword')) {
const texKey = `item_${slot.type}`;
if (this.scene.textures.exists(texKey)) {
this.handSprite.setTexture(texKey);
this.handSprite.setVisible(true);
} else {
this.handSprite.setVisible(false);
}
} else {
this.handSprite.setVisible(false);
}
}
}
handleInput(dt) {
// 🛑 STARDEW LOGIC: Block movement if acting
if (this.isActing) {
this.velocity.x = 0;
this.velocity.y = 0;
return;
}
// 🎮 COLLECT INPUT FROM ALL SOURCES
let inputX = 0;
let inputY = 0;
// Keyboard (WASD + Arrows)
if (this.keys.up.isDown || this.keys.w.isDown) inputY -= 1;
if (this.keys.down.isDown || this.keys.s.isDown) inputY += 1;
if (this.keys.left.isDown || this.keys.a.isDown) inputX -= 1;
if (this.keys.right.isDown || this.keys.d.isDown) inputX += 1;
// Virtual Joystick (Mobile)
const ui = this.scene.scene.get('UIScene');
if (ui && ui.virtualJoystick) {
if (ui.virtualJoystick.up) inputY -= 1;
if (ui.virtualJoystick.down) inputY += 1;
if (ui.virtualJoystick.left) inputX -= 1;
if (ui.virtualJoystick.right) inputX += 1;
}
// Gamepad (Xbox Controller)
if (this.scene.input.gamepad && this.scene.input.gamepad.total > 0) {
const pad = this.scene.input.gamepad.getPad(0);
if (pad) {
const threshold = 0.2;
const stickY = pad.leftStick.y;
const stickX = pad.leftStick.x;
// Analog stick (smooth values)
if (Math.abs(stickY) > threshold) inputY += stickY;
if (Math.abs(stickX) > threshold) inputX += stickX;
// D-Pad (digital)
if (pad.up) inputY -= 1;
if (pad.down) inputY += 1;
if (pad.left) inputX -= 1;
if (pad.right) inputX += 1;
// Sprint button (B on Xbox, Circle on PS)
if (pad.B || pad.buttons[1]?.pressed) {
this.sprinting = true;
}
}
}
// 🏃 SPRINT DETECTION (Shift key)
this.sprinting = this.keys.shift?.isDown || this.sprinting;
// Normalize diagonal movement (so diagonal isn't faster)
const inputLength = Math.sqrt(inputX ** 2 + inputY ** 2);
if (inputLength > 0) {
inputX /= inputLength;
inputY /= inputLength;
}
// 🎯 DETERMINE MOVEMENT SPEED
let maxSpeed = this.moveSpeed;
if (this.sprinting && this.energy > 0) {
maxSpeed = this.sprintSpeed;
}
// 🚀 SET TARGET VELOCITY
this.targetVelocity.x = inputX * maxSpeed;
this.targetVelocity.y = inputY * maxSpeed;
// 🧭 UPDATE DIRECTION & FACING
if (inputLength > 0.1) {
// Update last direction for attacks/interactions
this.lastDir = { x: inputX, y: inputY };
// Determine animation direction (4-way)
// Isometric mapping: up/down = X axis, left/right = Y axis
let animDir = 'down';
// Prioritize primary direction (stronger input)
if (Math.abs(inputX) > Math.abs(inputY)) {
// Vertical movement (up/down in isometric)
animDir = inputX < 0 ? 'up' : 'down';
} else {
// Horizontal movement (left/right in isometric)
animDir = inputY < 0 ? 'right' : 'left';
}
this.direction = animDir;
}
}
// 🎨 UPDATE ANIMATION (called from update loop)
updateAnimation() {
if (!this.sprite.anims) return;
const speed = Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2);
try {
if (speed < 5) {
// 😴 IDLE
const idleAnim = `protagonist_idle_${this.direction}`;
if (this.scene.anims.exists(idleAnim) && !this.sprite.anims.isPlaying) {
this.sprite.play(idleAnim);
}
} else {
// 🚶 WALKING / 🏃 SPRINTING
const walkAnim = `protagonist_walk_${this.direction}`;
if (this.scene.anims.exists(walkAnim)) {
if (this.sprite.anims.currentAnim?.key !== walkAnim) {
this.sprite.play(walkAnim, true);
}
// Faster animation when sprinting
const frameRate = this.sprinting ? 12 : 8;
if (this.sprite.anims.currentAnim) {
this.sprite.anims.currentAnim.frameRate = frameRate;
}
// 🔉 PHASE 8: Footstep triggers (frames 1 and 3 are usually down-steps)
const currentFrame = this.sprite.anims.currentFrame ? this.sprite.anims.currentFrame.index : 0;
if ((currentFrame === 1 || currentFrame === 3) && this.lastFootstepFrame !== currentFrame) {
if (this.scene.soundManager) {
// Determine surface
let surface = 'grass';
if (this.scene.terrainSystem && this.scene.terrainSystem.getTile) {
const tile = this.scene.terrainSystem.getTile(this.gridX, this.gridY);
if (tile && tile.type === 'dirt') surface = 'dirt';
}
this.scene.soundManager.playFootstep(surface);
}
this.lastFootstepFrame = currentFrame;
} else if (currentFrame !== 1 && currentFrame !== 3) {
this.lastFootstepFrame = -1;
}
}
}
// Hand sprite position update
const handOffsets = {
'left': -10,
'right': 10,
'up': 0,
'down': 0
};
if (this.handSprite) {
this.handSprite.setX(this.sprite.x + (handOffsets[this.direction] || 0));
}
} catch (e) {
// Ignore animation errors
}
}
moveToGrid(targetX, targetY) {
this.isMoving = true;
this.gridX = targetX;
this.gridY = targetY;
// Footstep Sound
if (this.scene.soundManager) {
this.scene.soundManager.playFootstep();
}
const targetScreen = this.iso.toScreen(targetX, targetY);
// Play walk animation - SAFE CHECK (updated for protagonist)
const texKey = this.sprite.texture.key;
if (texKey === 'player_protagonist') {
// KRVAVA ŽETEV: Use directional animations
const walkAnim = `protagonist_walk_${this.direction}`;
if (this.scene.anims.exists(walkAnim)) {
this.sprite.play(walkAnim, true);
}
} else if (texKey === 'player_dreadlocks') {
if (this.scene.anims.exists('player_dreadlocks_walk')) {
this.sprite.play('player_dreadlocks_walk', true);
}
} else if (texKey === 'player_walk') {
if (this.scene.anims.exists('player_walk_anim')) {
this.sprite.play('player_walk_anim', true);
}
}
this.scene.tweens.add({
targets: [this.sprite, this.handSprite],
x: '+=' + (targetScreen.x + this.offsetX - this.sprite.x),
y: '+=' + (targetScreen.y + this.offsetY - this.sprite.y),
duration: this.gridMoveTime,
ease: 'Linear',
onComplete: () => {
this.isMoving = false;
this.updatePosition();
// Stop animation (updated for protagonist)
if (texKey === 'player_protagonist') {
// Play idle animation
const idleAnim = `protagonist_idle_${this.direction}`;
if (this.scene.anims.exists(idleAnim)) {
this.sprite.play(idleAnim);
} else {
this.sprite.stop();
}
} else if (texKey === 'player_dreadlocks') {
this.sprite.stop();
this.sprite.setFrame(0);
} else if (texKey === 'player_walk') {
this.sprite.stop();
this.sprite.setFrame(0);
}
}
});
// NOTE: updateDepth() disabled - using sortableObjects Z-sorting in GameScene
// this.updateDepth();
}
updatePosition() {
// 🎨 FLAT 2D POSITIONING (NEW!)
const tileSize = 48;
// Direct grid to pixel conversion (NO isometric!)
const x = Math.round((this.gridX * tileSize) + (tileSize / 2));
const y = Math.round((this.gridY * tileSize) + (tileSize / 2));
this.sprite.setPosition(x, y);
const facingRight = !this.sprite.flipX;
const handOffset = facingRight ? 10 : -10;
this.handSprite.setPosition(
Math.round(x + handOffset),
Math.round(y - 15)
);
this.updateDepth();
}
updateDepth() {
if (!this.sprite) return;
// Optimization: Create dirty check
if (this.lastDepthY === undefined || Math.abs(this.sprite.y - this.lastDepthY) > 0.1) {
// Uporabi LAYER_OBJECTS da se pravilno sortira z drevesi/kamni
const layerBase = this.iso.LAYER_OBJECTS || 200000;
const depth = layerBase + this.sprite.y;
this.sprite.setDepth(depth);
if (this.handSprite) this.handSprite.setDepth(depth + 1);
this.lastDepthY = this.sprite.y;
}
}
getPosition() {
return { x: this.gridX, y: this.gridY };
}
getScreenPosition() {
return { x: this.sprite.x, y: this.sprite.y };
}
destroy() {
if (this.sprite) this.sprite.destroy();
}
dieAnimation() {
this.sprite.setTint(0xff0000);
this.scene.tweens.add({
targets: this.sprite,
angle: 90,
duration: 500,
ease: 'Bounce.easeOut'
});
}
respawn() {
this.sprite.clearTint();
this.sprite.angle = 0;
}
handleFarmingAction() {
if (!this.scene.farmingSystem) return;
const uiScene = this.scene.scene.get('UIScene');
const invSys = this.scene.inventorySystem;
if (!uiScene || !invSys) return;
const selectedIdx = uiScene.selectedSlot;
const slot = invSys.slots[selectedIdx];
const itemType = slot ? slot.type : null;
// Get tile player is standing on
const gridX = this.gridX;
const gridY = this.gridY;
// HOE - Till soil
if (itemType === 'hoe') {
const success = this.scene.farmingSystem.tillSoil(gridX, gridY);
if (success) {
console.log('✅ Tilled soil!');
// Particle effect - soil spray
this.createSoilParticles(gridX, gridY);
// Tool swing animation
this.swingTool();
// TODO: Play dig sound
}
return;
}
// SEEDS - Plant
if (itemType === 'carrot' || itemType === 'wheat' || itemType === 'item_seeds') {
const cropType = itemType === 'item_seeds' ? 'carrot' : itemType;
const success = this.scene.farmingSystem.plantSeed(gridX, gridY, cropType);
if (success) {
invSys.removeItem(itemType, 1);
console.log('🌱 Planted seed!');
// Particle effect - seed drop
this.createSeedParticles(gridX, gridY);
// TODO: Play plant sound
}
return;
}
// EMPTY HAND - Harvest
if (!itemType) {
const success = this.scene.farmingSystem.harvestCrop(gridX, gridY);
if (success) {
console.log('🌾 Harvested crop!');
// Particle effect - harvest sparkle
this.createHarvestParticles(gridX, gridY);
// Camera shake
this.scene.cameras.main.shake(200, 0.003);
// TODO: Play harvest sound
}
return;
}
}
swingTool() {
if (!this.handSprite || !this.handSprite.visible) return;
// Save original position
const originalAngle = this.handSprite.angle;
const originalScale = this.handSprite.scaleX;
// Swing animation
this.scene.tweens.add({
targets: this.handSprite,
angle: originalAngle - 45,
scaleX: originalScale * 1.3,
scaleY: originalScale * 1.3,
duration: 100,
yoyo: true,
ease: 'Cubic.easeOut',
onComplete: () => {
this.handSprite.angle = originalAngle;
this.handSprite.scaleX = originalScale;
this.handSprite.scaleY = originalScale;
}
});
}
createSoilParticles(gridX, gridY) {
const screenPos = this.scene.iso.gridToScreen(gridX, gridY);
const x = screenPos.x + this.offsetX;
const y = screenPos.y + this.offsetY;
// Brown soil particles
for (let i = 0; i < 10; i++) {
const particle = this.scene.add.circle(x, y, 3, 0x8B4513);
this.scene.tweens.add({
targets: particle,
x: x + (Math.random() - 0.5) * 30,
y: y - Math.random() * 20,
alpha: 0,
duration: 400,
onComplete: () => particle.destroy()
});
}
}
createSeedParticles(gridX, gridY) {
const screenPos = this.scene.iso.gridToScreen(gridX, gridY);
const x = screenPos.x + this.offsetX;
const y = screenPos.y + this.offsetY;
// Green seed particles
for (let i = 0; i < 5; i++) {
const particle = this.scene.add.circle(x, y - 20, 2, 0x00ff00);
this.scene.tweens.add({
targets: particle,
y: y,
alpha: 0,
duration: 500,
ease: 'Cubic.easeIn',
onComplete: () => particle.destroy()
});
}
}
createHarvestParticles(gridX, gridY) {
const screenPos = this.scene.iso.gridToScreen(gridX, gridY);
const x = screenPos.x + this.offsetX;
const y = screenPos.y + this.offsetY;
// Golden sparkle particles
for (let i = 0; i < 15; i++) {
const particle = this.scene.add.circle(x, y, 4, 0xFFD700);
this.scene.tweens.add({
targets: particle,
x: x + (Math.random() - 0.5) * 40,
y: y - Math.random() * 40,
scaleX: 0,
scaleY: 0,
alpha: 0,
duration: 600,
ease: 'Cubic.easeOut',
onComplete: () => particle.destroy()
});
}
}
/**
* Check if player has required tool equipped/in inventory
* @param {string} toolType - Tool type (axe, pickaxe, hoe, etc.)
* @returns {boolean} - True if player has the tool
*/
hasToolEquipped(toolType) {
if (!toolType) return true; // No tool required
// Check inventory for tool
if (this.scene.inventorySystem) {
return this.scene.inventorySystem.hasItem(toolType, 1);
}
return false;
}
useSelectedItem() {
const uiScene = this.scene.scene.get('UIScene');
const invSys = this.scene.inventorySystem;
if (!uiScene || !invSys) return;
const selectedIdx = uiScene.selectedSlot;
const slot = invSys.slots[selectedIdx];
if (!slot || slot.count <= 0) return;
console.log(`🌀 Attempting to use item: ${slot.type}`);
if (slot.type === 'cannabis_buds') {
// SMOKE IT!
if (this.scene.statusEffectSystem) {
const used = this.scene.statusEffectSystem.applyEffect('high');
if (used) {
invSys.removeItem(slot.type, 1);
// Audio feedback
if (this.scene.soundManager) this.scene.soundManager.playSmokeSound();
// Visual feedback
this.createSmokeParticles(this.gridX, this.gridY);
this.scene.events.emit('show-floating-text', {
x: this.sprite.x, y: this.sprite.y - 60, text: '🚬 *puff puff*', color: '#55ff55'
});
}
}
} else if (slot.type === 'health_potion' || slot.type === 'medicine') {
// Generic healing
if (this.hp < this.maxHp) {
this.hp = Math.min(this.maxHp, this.hp + 20);
invSys.removeItem(slot.type, 1);
this.scene.events.emit('show-floating-text', {
x: this.sprite.x, y: this.sprite.y - 60, text: '💖 Recovered!', color: '#ff5555'
});
}
}
}
createSmokeParticles(gridX, gridY) {
// Reuse particle logic, or create locally
for (let i = 0; i < 10; i++) {
const smoke = this.scene.add.circle(this.sprite.x, this.sprite.y - 40, 4 + Math.random() * 4, 0xcccccc, 0.6);
this.scene.tweens.add({
targets: smoke,
x: smoke.x + (Math.random() - 0.5) * 50,
y: smoke.y - 100 - Math.random() * 50,
alpha: 0,
scale: 3,
duration: 2000 + Math.random() * 1000,
onComplete: () => smoke.destroy()
});
}
}
handleChoppingAction() {
console.log('🪓 Chopping action!');
// Check if player has axe equipped
const uiScene = this.scene.scene.get('UIScene');
const invSys = this.scene.inventorySystem;
if (!uiScene || !invSys) return;
const selectedIdx = uiScene.selectedSlot;
const slot = invSys.slots[selectedIdx];
if (!slot || slot.type !== 'axe') {
console.log('⚠️ No axe equipped!');
return;
}
// Calculate target tile in front of player
const targetX = this.gridX + Math.round(this.lastDir.x);
const targetY = this.gridY + Math.round(this.lastDir.y);
// Trigger interaction system with chopping mode
if (this.scene.interactionSystem) {
this.scene.interactionSystem.handleInteraction(targetX, targetY, true);
}
// Play chopping animation (swing tool)
this.swingTool();
// Play sound
if (this.scene.soundManager && this.scene.soundManager.playChop) {
this.scene.soundManager.playChop();
}
}
handleMiningAction() {
console.log('⛏️ Mining action!');
// Check if player has pickaxe equipped
const uiScene = this.scene.scene.get('UIScene');
const invSys = this.scene.inventorySystem;
if (!uiScene || !invSys) return;
const selectedIdx = uiScene.selectedSlot;
const slot = invSys.slots[selectedIdx];
if (!slot || slot.type !== 'pickaxe') {
console.log('⚠️ No pickaxe equipped!');
return;
}
// Calculate target tile in front of player
const targetX = this.gridX + Math.round(this.lastDir.x);
const targetY = this.gridY + Math.round(this.lastDir.y);
// Trigger interaction system with mining mode
if (this.scene.interactionSystem) {
this.scene.interactionSystem.handleInteraction(targetX, targetY, true);
}
// Play mining animation (swing tool)
this.swingTool();
// Play sound
if (this.scene.soundManager && this.scene.soundManager.playMine) {
this.scene.soundManager.playMine();
}
}
}