MICRO FARM SYSTEM (8x8): - Initial 8x8 farm boundary (center spawn) - White boundary visualization - Corner markers for clear boundaries - Locked tile tracking (Set-based) VISUAL FEEDBACK: - Locked tile overlay (30% black) - Clear visual distinction (farm vs locked) - Dynamic rendering (15 tile radius) - Depth-sorted overlays FARMING RESTRICTIONS: - Block tilling outside farm boundary - Error messages (floating text) - Farm boundary validation - FarmingSystem integration EXPANSION SYSTEM: - 4-direction unlock buttons (N/S/E/W) - Cost system (50 gold per expansion) - 2x2 tile unlock increments - Visual updates (boundaries + overlay) UI INTEGRATION: - Interactive expansion buttons - Hover effects (color + scale) - Cost labels (gold display) - Success/error feedback MINIMAP INTEGRATION: - Farm boundary in minimap - White box indicator - Player-relative rendering - Fixed terrain system compatibility TECHNICAL FIXES: - Added decorationsMap to Flat2DTerrainSystem - Fixed variable scope issues - UIScene minimap compatibility - TerrainSystem.getTile() integration FILES CREATED/MODIFIED: - src/systems/MicroFarmSystem.js (NEW!) - src/systems/FarmingSystem.js - src/systems/Flat2DTerrainSystem.js - src/scenes/GameScene.js - src/scenes/UIScene.js - index.html Session: 1h (00:50-01:19) Date: 15.12.2024 Status: PHASE 37 COMPLETE!
332 lines
11 KiB
JavaScript
332 lines
11 KiB
JavaScript
// 🌱 MICRO FARM SYSTEM - Phase 37
|
|
// Začetna 8x8 parcela z postopno širitvijo
|
|
|
|
class MicroFarmSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
|
|
// MICRO FARM CONFIG
|
|
this.farmCenterX = 50; // Center of 100x100 map
|
|
this.farmCenterY = 50;
|
|
this.farmSize = 8; // 8x8 tiles (initial)
|
|
|
|
// EXPANSION SYSTEM
|
|
this.unlockedTiles = new Set(); // Tracks unlocked tiles
|
|
this.expansionCost = 50; // Gold per 2x2 expansion
|
|
|
|
// LAND TYPES
|
|
this.landTypes = {
|
|
GRASS: 'grass', // Free to use
|
|
FOREST: 'forest', // Needs clearing (trees)
|
|
ROCKY: 'rocky', // Needs mining (rocks)
|
|
SWAMP: 'swamp' // Needs drainage (water)
|
|
};
|
|
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
console.log('🌱 MicroFarmSystem initialized');
|
|
|
|
// Unlock initial 8x8 farm
|
|
this.unlockInitialFarm();
|
|
|
|
// Create visual boundaries
|
|
this.createFarmBoundaries();
|
|
|
|
// Render locked tile overlay
|
|
this.renderLockedTileOverlay();
|
|
|
|
// Create expansion UI buttons
|
|
this.createExpansionUI();
|
|
}
|
|
|
|
createExpansionUI() {
|
|
// Create UI buttons for farm expansion
|
|
const uiScene = this.scene.scene.get('UIScene');
|
|
if (!uiScene) {
|
|
console.warn('⚠️ UIScene not found - cannot create expansion UI');
|
|
return;
|
|
}
|
|
|
|
// Store reference
|
|
this.uiScene = uiScene;
|
|
this.expansionButtons = [];
|
|
|
|
const buttonSize = 40;
|
|
const buttonColor = 0x8B4513; // Brown
|
|
const buttonHoverColor = 0xD2691E;
|
|
const expandCost = this.expansionCost;
|
|
|
|
// Button positions relative to farm center
|
|
const farmWorldX = this.farmCenterX * 48;
|
|
const farmWorldY = this.farmCenterY * 48;
|
|
const farmPixelSize = this.farmSize * 48;
|
|
const halfSize = farmPixelSize / 2;
|
|
|
|
const buttons = [
|
|
{ dir: 'north', x: farmWorldX, y: farmWorldY - halfSize - 60, icon: '⬆️' },
|
|
{ dir: 'south', x: farmWorldX, y: farmWorldY + halfSize + 60, icon: '⬇️' },
|
|
{ dir: 'east', x: farmWorldX + halfSize + 60, y: farmWorldY, icon: '➡️' },
|
|
{ dir: 'west', x: farmWorldX - halfSize - 60, y: farmWorldY, icon: '⬅️' }
|
|
];
|
|
|
|
buttons.forEach(btn => {
|
|
// Button background
|
|
const bg = this.scene.add.rectangle(btn.x, btn.y, buttonSize, buttonSize, buttonColor);
|
|
bg.setStrokeStyle(2, 0xFFFFFF);
|
|
bg.setDepth(10);
|
|
bg.setInteractive({ useHandCursor: true });
|
|
|
|
// Button text
|
|
const text = this.scene.add.text(btn.x, btn.y, btn.icon, {
|
|
fontSize: '20px',
|
|
color: '#ffffff'
|
|
}).setOrigin(0.5);
|
|
text.setDepth(11);
|
|
|
|
// Cost label
|
|
const costLabel = this.scene.add.text(btn.x, btn.y + 30, `${expandCost}g`, {
|
|
fontSize: '12px',
|
|
color: '#FFD700',
|
|
fontStyle: 'bold'
|
|
}).setOrigin(0.5);
|
|
costLabel.setDepth(11);
|
|
|
|
// Hover effects
|
|
bg.on('pointerover', () => {
|
|
bg.setFillStyle(buttonHoverColor);
|
|
bg.setScale(1.1);
|
|
});
|
|
|
|
bg.on('pointerout', () => {
|
|
bg.setFillStyle(buttonColor);
|
|
bg.setScale(1.0);
|
|
});
|
|
|
|
// Click handler
|
|
bg.on('pointerdown', () => {
|
|
this.tryExpandFarm(btn.dir);
|
|
});
|
|
|
|
this.expansionButtons.push({ bg, text, costLabel, dir: btn.dir });
|
|
});
|
|
|
|
console.log('✅ Expansion UI created!');
|
|
}
|
|
|
|
tryExpandFarm(direction) {
|
|
// Check if player has enough gold
|
|
const inv = this.scene.inventorySystem;
|
|
if (!inv || inv.gold < this.expansionCost) {
|
|
console.log(`❌ Not enough gold! Need ${this.expansionCost}g`);
|
|
|
|
if (this.scene.events) {
|
|
this.scene.events.emit('show-floating-text', {
|
|
x: this.scene.cameras.main.width / 2,
|
|
y: 100,
|
|
text: `Need ${this.expansionCost} gold!`,
|
|
color: '#ff0000'
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Deduct gold
|
|
inv.gold -= this.expansionCost;
|
|
|
|
// Expand farm
|
|
this.expandFarm(direction);
|
|
|
|
// Success feedback
|
|
if (this.scene.events) {
|
|
this.scene.events.emit('show-floating-text', {
|
|
x: this.scene.cameras.main.width / 2,
|
|
y: 100,
|
|
text: `✅ Farm expanded ${direction.toUpperCase()}!`,
|
|
color: '#00ff00'
|
|
});
|
|
}
|
|
|
|
console.log(`✅ Farm expanded ${direction}! (-${this.expansionCost}g)`);
|
|
}
|
|
|
|
unlockInitialFarm() {
|
|
// Unlock central 8x8 tiles
|
|
const halfSize = Math.floor(this.farmSize / 2);
|
|
|
|
for (let y = this.farmCenterY - halfSize; y < this.farmCenterY + halfSize; y++) {
|
|
for (let x = this.farmCenterX - halfSize; x < this.farmCenterX + halfSize; x++) {
|
|
const tileKey = `${x},${y}`;
|
|
this.unlockedTiles.add(tileKey);
|
|
}
|
|
}
|
|
|
|
console.log(`✅ Unlocked ${this.unlockedTiles.size} tiles (8x8 micro farm)`);
|
|
}
|
|
|
|
createFarmBoundaries() {
|
|
// Visual indicator of farm boundaries
|
|
const graphics = this.scene.add.graphics();
|
|
const halfSize = Math.floor(this.farmSize / 2);
|
|
|
|
const startX = (this.farmCenterX - halfSize) * 48;
|
|
const startY = (this.farmCenterY - halfSize) * 48;
|
|
const width = this.farmSize * 48;
|
|
const height = this.farmSize * 48;
|
|
|
|
// Farm border (white dashed line)
|
|
graphics.lineStyle(3, 0xFFFFFF, 0.8);
|
|
graphics.strokeRect(startX, startY, width, height);
|
|
|
|
// Corner markers
|
|
graphics.fillStyle(0xFFFFFF, 0.9);
|
|
const markerSize = 8;
|
|
graphics.fillRect(startX - markerSize / 2, startY - markerSize / 2, markerSize, markerSize);
|
|
graphics.fillRect(startX + width - markerSize / 2, startY - markerSize / 2, markerSize, markerSize);
|
|
graphics.fillRect(startX - markerSize / 2, startY + height - markerSize / 2, markerSize, markerSize);
|
|
graphics.fillRect(startX + width - markerSize / 2, startY + height - markerSize / 2, markerSize, markerSize);
|
|
|
|
graphics.setDepth(5); // Above ground, below player
|
|
|
|
// Store graphics for later updates
|
|
this.boundaryGraphics = graphics;
|
|
}
|
|
|
|
renderLockedTileOverlay() {
|
|
// Render dark overlay on locked tiles
|
|
if (!this.scene || !this.lockedOverlayGraphics) {
|
|
// Create overlay graphics if not exists
|
|
this.lockedOverlayGraphics = this.scene.add.graphics();
|
|
this.lockedOverlayGraphics.setDepth(4); // Above ground, below boundaries
|
|
}
|
|
|
|
this.lockedOverlayGraphics.clear();
|
|
|
|
// Darken all tiles that are NOT unlocked
|
|
const halfSize = Math.floor(this.farmSize / 2);
|
|
const farmStartX = this.farmCenterX - halfSize;
|
|
const farmEndX = this.farmCenterX + halfSize;
|
|
const farmStartY = this.farmCenterY - halfSize;
|
|
const farmEndY = this.farmCenterY + halfSize;
|
|
|
|
// Render grid of locked tiles
|
|
const viewRange = 15; // Show some area around farm
|
|
for (let y = this.farmCenterY - viewRange; y < this.farmCenterY + viewRange; y++) {
|
|
for (let x = this.farmCenterX - viewRange; x < this.farmCenterX + viewRange; x++) {
|
|
// Skip if within farm boundaries
|
|
if (x >= farmStartX && x < farmEndX && y >= farmStartY && y < farmEndY) {
|
|
continue;
|
|
}
|
|
|
|
// Draw dark overlay (lighter)
|
|
const worldX = x * 48;
|
|
const worldY = y * 48;
|
|
this.lockedOverlayGraphics.fillStyle(0x000000, 0.3); // 0.5 -> 0.3
|
|
this.lockedOverlayGraphics.fillRect(worldX, worldY, 48, 48);
|
|
}
|
|
}
|
|
|
|
console.log('🔒 Locked tile overlay rendered!');
|
|
}
|
|
|
|
isTileUnlocked(tileX, tileY) {
|
|
const tileKey = `${tileX},${tileY}`;
|
|
return this.unlockedTiles.has(tileKey);
|
|
}
|
|
|
|
canExpand(direction) {
|
|
// Check if expansion in direction is possible
|
|
// direction: 'north', 'south', 'east', 'west'
|
|
// TODO: Implement expansion logic
|
|
return true;
|
|
}
|
|
|
|
expandFarm(direction) {
|
|
// Unlock 2x2 tiles in specified direction
|
|
const halfSize = Math.floor(this.farmSize / 2);
|
|
const expansionSize = 2; // Unlock 2x2 tiles at a time
|
|
|
|
let newTiles = [];
|
|
|
|
switch (direction) {
|
|
case 'north':
|
|
for (let y = this.farmCenterY - halfSize - expansionSize; y < this.farmCenterY - halfSize; y++) {
|
|
for (let x = this.farmCenterX - halfSize; x < this.farmCenterX + halfSize; x++) {
|
|
newTiles.push({ x, y });
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'south':
|
|
for (let y = this.farmCenterY + halfSize; y < this.farmCenterY + halfSize + expansionSize; y++) {
|
|
for (let x = this.farmCenterX - halfSize; x < this.farmCenterX + halfSize; x++) {
|
|
newTiles.push({ x, y });
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'east':
|
|
for (let y = this.farmCenterY - halfSize; y < this.farmCenterY + halfSize; y++) {
|
|
for (let x = this.farmCenterX + halfSize; x < this.farmCenterX + halfSize + expansionSize; x++) {
|
|
newTiles.push({ x, y });
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'west':
|
|
for (let y = this.farmCenterY - halfSize; y < this.farmCenterY + halfSize; y++) {
|
|
for (let x = this.farmCenterX - halfSize - expansionSize; x < this.farmCenterX - halfSize; x++) {
|
|
newTiles.push({ x, y });
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Unlock the tiles
|
|
newTiles.forEach(tile => {
|
|
const tileKey = `${tile.x},${tile.y}`;
|
|
this.unlockedTiles.add(tileKey);
|
|
});
|
|
|
|
// Update farm size
|
|
if (direction === 'north' || direction === 'south') {
|
|
this.farmSize += expansionSize;
|
|
} else {
|
|
this.farmSize += expansionSize;
|
|
}
|
|
|
|
// Update visuals
|
|
this.createFarmBoundaries(); // Redraw boundaries
|
|
this.renderLockedTileOverlay(); // Update overlay
|
|
|
|
console.log(`🔓 Expanded farm ${direction}! +${newTiles.length} tiles. Total: ${this.unlockedTiles.size}`);
|
|
}
|
|
|
|
getLandType(tileX, tileY) {
|
|
// Determine land type based on tile position
|
|
// TODO: Use terrain system data
|
|
|
|
// For now, return grass for unlocked tiles
|
|
if (this.isTileUnlocked(tileX, tileY)) {
|
|
return this.landTypes.GRASS;
|
|
}
|
|
|
|
// Surrounding areas have different types
|
|
const distFromCenter = Math.sqrt(
|
|
Math.pow(tileX - this.farmCenterX, 2) +
|
|
Math.pow(tileY - this.farmCenterY, 2)
|
|
);
|
|
|
|
if (distFromCenter < 10) return this.landTypes.GRASS;
|
|
if (distFromCenter < 15) return this.landTypes.FOREST;
|
|
if (distFromCenter < 20) return this.landTypes.ROCKY;
|
|
return this.landTypes.SWAMP;
|
|
}
|
|
|
|
destroy() {
|
|
// Cleanup
|
|
this.unlockedTiles.clear();
|
|
}
|
|
}
|