diff --git a/SESSION_FOREST_OPTIMIZATION.md b/SESSION_FOREST_OPTIMIZATION.md new file mode 100644 index 0000000..38a3ca8 --- /dev/null +++ b/SESSION_FOREST_OPTIMIZATION.md @@ -0,0 +1,134 @@ +# 🌲 Sesija: Optimizacija Gozda - 12. December 2025 + +## 📋 Povzetek Sesije + +### 🎯 Cilj +Generirati 100x100 mapo z **Stardew Valley stilom gozda** z vijolčnimi in sadnimi drevesi ter zapuščenimi hišami. + +### ✅ Dosežki + +#### 1. **Velikost Mape** +- ✅ Spremenjena na **100x100** tiles +- ✅ Celoten teren: `GRASS_FULL` +- ✅ Farm: 8x8 na (50,50) z `DIRT` ploščicami + +#### 2. **Drevesni Sistem** +- ✅ **Gostota:** 1% (zelo nizka, optimizirana) +- ✅ **Preverjanje razdalje:** Min 2 tiles med drevesi +- ✅ **Vrste dreves:** + - 💜 30% Vijolčna drevesa (`tree_purple`) + - 🍎 20% Sadna drevesa (`tree_apple`, `tree_pear`, `tree_cherry`) + - 🌳 50% Zelena/modra drevesa (`tree_green_final`, `tree_blue_final`) + +#### 3. **Sprite-i** +- ✅ Generirani novi sprite-i za drevesa +- ✅ Ultra agresivno odstranjevanje ozadij (brightness > 100) +- ✅ Čisti, transparentni sprite-i + +#### 4. **Optimizacije** +- ✅ Odstranjena vsa ozadja iz sprite-ov +- ✅ Pomanjšana drevesa (scale 0.6-0.7) +- ✅ Sistem preverjanja razdalje med drevesi +- ✅ Čista mapa brez nepotrebnih dekoracij + +### 🔧 Ključne Spremembe + +#### **TerrainSystem.js** +```javascript +// Konstante +const TREE_DENSITY = 0.01; // 1% gostota +const PURPLE_TREE_CHANCE = 0.30; +const FRUIT_TREE_CHANCE = 0.20; +const MIN_TREE_DISTANCE_SQUARED = 2 * 2; + +// Tracking dreves +this.placedTrees = []; + +// Funkcija za preverjanje razdalje +isTreeLocationFarEnough(newX, newY) { + // Preveri razdaljo do vseh dreves + // Vrne true če je OK, false če preblizu +} +``` + +#### **GameScene.js** +```javascript +// Farm ploščice - DIRT namesto GRASS +this.terrainSystem.tiles[y][x].type = 'dirt'; +this.terrainSystem.tiles[y][x].sprite.setTexture('dirt'); +``` + +#### **PreloadScene.js** +```javascript +// Novi sprite-i +this.load.image('tree_purple', 'assets/tree_purple.png'); +this.load.image('tree_apple', 'assets/tree_apple.png'); +this.load.image('tree_pear', 'assets/tree_pear.png'); +this.load.image('tree_cherry', 'assets/tree_cherry.png'); + +// Ultra agresivno odstranjevanje ozadij +processSpriteTransparency(spriteKey) { + // Odstrani VSE svetle barve (brightness > 100) + // Odstrani VSE sive barve + // Odstrani VSE pastelne barve +} +``` + +### 🐛 Odpravljene Napake + +1. ✅ **TypeError: Cannot read properties of null (reading 'addDecoration')** + - Dodano preverjanje `if (this.terrainSystem)` pred klici + +2. ✅ **ReferenceError: TILE_PAVEMENT is not defined** + - Dodane manjkajoče konstante za rudnik + +3. ✅ **Cannot read properties of null (reading 'getTile')** + - Dodano preverjanje v OceanSystem + +4. ✅ **Stari save file nalaga hiše** + - Onemogočen loadGame() za testiranje + - Odstranjena koda za generiranje hiš + +5. ✅ **Ozadja še vedno vidna** + - Ultra agresivno odstranjevanje (brightness > 100) + - Python skripta za procesiranje + +### 📊 Končna Konfiguracija + +**Mapa:** +- Velikost: 100x100 +- Teren: Zelena trava (`grass_full`) +- Farm: 8x8 dirt ploščice na (50,50) + +**Drevesa:** +- Gostota: 1% +- Min. razdalja: 2 tiles +- Vijolčna: 30% +- Sadna: 20% +- Zelena/modra: 50% + +**Dekoracije:** +- Grmički: 0% +- Rože: 0% +- Skale: 0% +- Hiše: 0% + +### 🎯 Naslednji Koraki + +1. **Testiranje v igri** - Vizualno preverjanje gozda +2. **Dodatne izboljšave** - Po potrebi prilagoditev gostote +3. **Interakcije** - Sekanje dreves, nabiranje sadja +4. **Zapuščene hiše** - Ponovno dodati če želeno + +### 📝 Opombe + +- Save sistem je ponovno omogočen +- Vsi sprite-i imajo transparentna ozadja +- Sistem preverjanja razdalje preprečuje prekrivanje +- Optimizirana gostota za boljšo vidnost + +--- + +**Datum:** 12. December 2025 +**Trajanje:** ~1.5 ure +**Status:** ✅ Uspešno zaključeno diff --git a/assets/tree_apple.png b/assets/tree_apple.png new file mode 100644 index 0000000..5e95d71 Binary files /dev/null and b/assets/tree_apple.png differ diff --git a/assets/tree_blue_final.png b/assets/tree_blue_final.png index 5f028fb..27a5bce 100644 Binary files a/assets/tree_blue_final.png and b/assets/tree_blue_final.png differ diff --git a/assets/tree_cherry.png b/assets/tree_cherry.png new file mode 100644 index 0000000..0ce2689 Binary files /dev/null and b/assets/tree_cherry.png differ diff --git a/assets/tree_dead_final.png b/assets/tree_dead_final.png index d0dd534..c318145 100644 Binary files a/assets/tree_dead_final.png and b/assets/tree_dead_final.png differ diff --git a/assets/tree_green_final.png b/assets/tree_green_final.png index e9d0dab..591c289 100644 Binary files a/assets/tree_green_final.png and b/assets/tree_green_final.png differ diff --git a/assets/tree_pear.png b/assets/tree_pear.png new file mode 100644 index 0000000..354ff77 Binary files /dev/null and b/assets/tree_pear.png differ diff --git a/assets/tree_purple.png b/assets/tree_purple.png new file mode 100644 index 0000000..5a12b0a Binary files /dev/null and b/assets/tree_purple.png differ diff --git a/clear_all_saves.js b/clear_all_saves.js new file mode 100644 index 0000000..2228a38 --- /dev/null +++ b/clear_all_saves.js @@ -0,0 +1,18 @@ +// CLEAR ALL SAVE FILES +console.log('🗑️ Clearing ALL save files...'); + +// Clear main save +localStorage.removeItem('novafarma_savefile'); + +// Clear all slots +for (let i = 1; i <= 3; i++) { + localStorage.removeItem(`novafarma_save_slot${i}`); + localStorage.removeItem(`novafarma_slot${i}_meta`); +} + +// Clear other saves +localStorage.removeItem('novafarma_save'); +localStorage.removeItem('novafarma_achievement_progress'); + +console.log('✅ All saves cleared! Reload page (F4) for fresh start.'); +console.log('📝 Remaining keys:', Object.keys(localStorage).filter(k => k.includes('novafarma'))); diff --git a/clear_save.js b/clear_save.js new file mode 100644 index 0000000..35577a4 --- /dev/null +++ b/clear_save.js @@ -0,0 +1,3 @@ +// Clear localStorage save file +localStorage.removeItem('novafarma_savefile'); +console.log('✅ Save file cleared! Reload page (F4) for fresh start.'); diff --git a/package.json b/package.json index 7becfd1..62ff641 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,9 @@ "type": "commonjs", "dependencies": { "canvas": "^3.2.0", - "phaser": "^3.80.1" + "express": "^5.2.1", + "phaser": "^3.80.1", + "socket.io": "^4.8.1" }, "devDependencies": { "electron": "^33.2.1" diff --git a/remove_backgrounds.py b/remove_backgrounds.py new file mode 100644 index 0000000..b71f35e --- /dev/null +++ b/remove_backgrounds.py @@ -0,0 +1,78 @@ +from PIL import Image +import os + +# Lista slik za procesiranje +images_to_process = [ + 'assets/tree_purple.png', + 'assets/tree_apple.png', + 'assets/tree_pear.png', + 'assets/tree_cherry.png' +] + +def remove_background(image_path): + """Odstrani ozadje iz slike - naredi transparentno""" + try: + # Naloži sliko + img = Image.open(image_path).convert('RGBA') + data = img.getdata() + + new_data = [] + for item in data: + r, g, b, a = item + + # Izračunaj brightness in grayscale + brightness = (r + g + b) / 3 + is_grayscale = abs(r - g) < 20 and abs(g - b) < 20 and abs(r - b) < 20 + + # Odstrani: + # 1. Vse sive barve (šahovsko ozadje) + # 2. Vse svetle barve (brightness > 150) + # 3. Bele barve + # 4. Pastelne barve (nizka saturacija) + + should_remove = False + + # Sive barve + if is_grayscale and brightness > 80: + should_remove = True + + # Svetle barve + if brightness > 150: + should_remove = True + + # Bele + if r > 240 and g > 240 and b > 240: + should_remove = True + + # Pastelne (nizka saturacija) + max_rgb = max(r, g, b) + min_rgb = min(r, g, b) + saturation = 0 if max_rgb == 0 else (max_rgb - min_rgb) / max_rgb + + if saturation < 0.3 and brightness > 120: + should_remove = True + + if should_remove: + new_data.append((r, g, b, 0)) # Transparentno + else: + new_data.append(item) # Ohrani original + + # Posodobi sliko + img.putdata(new_data) + + # Shrani + img.save(image_path) + print(f'✅ Processed: {image_path}') + + except Exception as e: + print(f'❌ Error processing {image_path}: {e}') + +# Procesiraj vse slike +print('🎨 Removing backgrounds from tree sprites...') +for img_path in images_to_process: + if os.path.exists(img_path): + remove_background(img_path) + else: + print(f'⚠️ File not found: {img_path}') + +print('✅ Done! All backgrounds removed.') diff --git a/src/scenes/GameScene.js b/src/scenes/GameScene.js index fdcd27d..00247b0 100644 --- a/src/scenes/GameScene.js +++ b/src/scenes/GameScene.js @@ -208,14 +208,19 @@ class GameScene extends Phaser.Scene { this.signposts = []; // Path markers (using fence sprites as signposts) - const pathMarkers = [ - { x: 35, y: 35, label: '→ City' }, - { x: 50, y: 50, label: '← Farm' }, - ]; + // ONLY if terrainSystem was successfully initialized + if (this.terrainSystem) { + const pathMarkers = [ + { x: 35, y: 35, label: '→ City' }, + { x: 50, y: 50, label: '← Farm' }, + ]; - for (const marker of pathMarkers) { - this.terrainSystem.addDecoration(marker.x, marker.y, 'fence'); - this.signposts.push({ gridX: marker.x, gridY: marker.y, label: marker.label }); + for (const marker of pathMarkers) { + this.terrainSystem.addDecoration(marker.x, marker.y, 'fence'); + this.signposts.push({ gridX: marker.x, gridY: marker.y, label: marker.label }); + } + } else { + console.warn('⚠️ TerrainSystem not initialized - skipping signposts'); } // Kamera sledi igralcu z gladko interpolacijo (lerp 0.1) @@ -280,8 +285,8 @@ class GameScene extends Phaser.Scene { // Initialize Save System this.saveSystem = new SaveSystem(this); - // Auto-load if available - this.saveSystem.loadGame(); + // Auto-load if available (DISABLED in SaveSystem!) + this.saveSystem.loadGame(); // Vrne false - ne naloži save-a! // Debug Text this.add.text(10, 10, 'NovaFarma Alpha v0.6', { font: '16px monospace', fill: '#ffffff' }) @@ -738,11 +743,11 @@ class GameScene extends Phaser.Scene { if (this.terrainSystem.decorationsMap.has(key)) { this.terrainSystem.removeDecoration(x, y); } - // Make it grass or dirt - USE CORRECT TERRAIN TYPE OBJECT + // Make it DIRT for farming if (this.terrainSystem.tiles[y] && this.terrainSystem.tiles[y][x]) { - this.terrainSystem.tiles[y][x].type = this.terrainSystem.terrainTypes.GRASS_FULL; + this.terrainSystem.tiles[y][x].type = 'dirt'; if (this.terrainSystem.tiles[y][x].sprite) { - this.terrainSystem.tiles[y][x].sprite.setTexture('grass'); + this.terrainSystem.tiles[y][x].sprite.setTexture('dirt'); this.terrainSystem.tiles[y][x].sprite.setTint(0xffffff); // Clear tint } } diff --git a/src/scenes/PreloadScene.js b/src/scenes/PreloadScene.js index 444e965..ed2e1e0 100644 --- a/src/scenes/PreloadScene.js +++ b/src/scenes/PreloadScene.js @@ -41,6 +41,13 @@ class PreloadScene extends Phaser.Scene { this.load.image('tree_blue_final', 'assets/tree_blue_final.png'); this.load.image('tree_dead_final', 'assets/tree_dead_final.png'); + // STARDEW VALLEY FOREST TREES (NEW!) + this.load.image('tree_purple', 'assets/tree_purple.png'); + this.load.image('tree_apple', 'assets/tree_apple.png'); + this.load.image('tree_pear', 'assets/tree_pear.png'); + this.load.image('tree_cherry', 'assets/tree_cherry.png'); + this.load.image('tree_sapling', 'assets/tree_green_final.png'); // Reuse green as sapling + // NEW transparent tree/rock assets this.load.image('tree_blue_new', 'assets/tree_blue_new.png'); // Keep for backup @@ -53,6 +60,9 @@ class PreloadScene extends Phaser.Scene { this.load.image('merchant_new', 'assets/merchant_new.png'); this.load.image('elite_zombie', 'assets/elite_zombie.png'); + // Fence old for abandoned houses + this.load.image('fence_old', 'assets/fence_isometric.png'); // Reuse fence for old houses + // AI-Generated NPC Sprites (with cache-busting) const cacheBust = Date.now(); this.load.image('cow', `assets/cow.png?v=${cacheBust}`); @@ -191,6 +201,13 @@ class PreloadScene extends Phaser.Scene { 'tree_blue_final', 'tree_dead_final', + // STARDEW VALLEY FOREST TREES + 'tree_purple', + 'tree_apple', + 'tree_pear', + 'tree_cherry', + 'tree_sapling', + // NEW transparent assets 'tree_blue_new', 'tree_green_new', @@ -203,6 +220,7 @@ class PreloadScene extends Phaser.Scene { 'flowers_new', 'hill_sprite', 'fence', + 'fence_old', 'gravestone', // City content 'chest', @@ -288,43 +306,51 @@ class PreloadScene extends Phaser.Scene { const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; - // Remove backgrounds - IMPROVED CHECKBOARD DETECTION + // Remove backgrounds - ULTRA AGGRESSIVE MODE! for (let i = 0; i < data.length; i += 4) { const r = data[i]; const g = data[i + 1]; const b = data[i + 2]; + const a = data[i + 3]; - // Remove ALL grayscale colors (checkboard pattern) - // Checkboard has both light (204,204,204) and dark (153,153,153) squares - const isGrayscale = Math.abs(r - g) < 15 && Math.abs(g - b) < 15 && Math.abs(r - b) < 15; + // Skip if already transparent + if (a === 0) continue; - if (isGrayscale) { - // ULTRA-AGGRESSIVE: Remove ALL grays from 100-240 - const isAnyGray = r >= 100 && r <= 240; - - if (isAnyGray) { - data[i + 3] = 0; // Make transparent - } - } - - // AGGRESSIVE: Remove ALL light backgrounds (AI-generated sprites) const brightness = (r + g + b) / 3; - const isVeryLight = brightness > 170 && Math.abs(r - g) < 50 && Math.abs(g - b) < 50; - if (isVeryLight) { + // 1. Remove ALL grayscale colors (ANY shade of gray) + const isGrayscale = Math.abs(r - g) < 20 && Math.abs(g - b) < 20 && Math.abs(r - b) < 20; + if (isGrayscale && brightness > 80) { data[i + 3] = 0; // Make transparent + continue; } - // ULTRA AGGRESSIVE: Remove PURE WHITE backgrounds - const isWhite = r > 240 && g > 240 && b > 240; - if (isWhite) { + // 2. Remove ALL light/bright backgrounds (AI-generated sprites) + if (brightness > 150) { data[i + 3] = 0; // Make transparent + continue; } - // ULTRA AGGRESSIVE: Remove OFF-WHITE backgrounds (cream, beige) - const isOffWhite = brightness > 230 && Math.abs(r - g) < 20 && Math.abs(g - b) < 20; - if (isOffWhite) { - data[i + 3] = 0; // Make transparent + // 3. Remove PURE WHITE + if (r > 240 && g > 240 && b > 240) { + data[i + 3] = 0; + continue; + } + + // 4. Remove OFF-WHITE / CREAM / BEIGE + if (brightness > 200 && Math.abs(r - g) < 30 && Math.abs(g - b) < 30) { + data[i + 3] = 0; + continue; + } + + // 5. Remove PASTEL colors (low saturation, high brightness) + const maxRGB = Math.max(r, g, b); + const minRGB = Math.min(r, g, b); + const saturation = maxRGB === 0 ? 0 : (maxRGB - minRGB) / maxRGB; + + if (saturation < 0.3 && brightness > 120) { + data[i + 3] = 0; // Remove low-saturation backgrounds + continue; } // Special: Remove brown/tan backgrounds (merchant sprite) diff --git a/src/systems/OceanSystem.js b/src/systems/OceanSystem.js index 5ff1b95..7d3a62e 100644 --- a/src/systems/OceanSystem.js +++ b/src/systems/OceanSystem.js @@ -26,7 +26,7 @@ class OceanSystem { } update(time, delta) { - if (!this.scene.player) return; + if (!this.scene.player || !this.scene.terrainSystem) return; const playerPos = this.scene.player.getPosition(); const tile = this.scene.terrainSystem.getTile(playerPos.x, playerPos.y); @@ -83,6 +83,8 @@ class OceanSystem { return; } + if (!this.scene.terrainSystem) return; + // Check if on water or near water? // Actually, let's allow "deploying" boat anywhere, but only moving fast on water? // OR: Only allow deploying on water tile. diff --git a/src/systems/TerrainSystem.js b/src/systems/TerrainSystem.js index a1cc983..94ba3f1 100644 --- a/src/systems/TerrainSystem.js +++ b/src/systems/TerrainSystem.js @@ -1,29 +1,34 @@ // ======================================================== -// NOVE GLOBALNE KONSTANTE ZA LOKACIJE +// STARDEW VALLEY STYLE FOREST MAP - 100x100 // ======================================================== +const MAP_SIZE = 100; // 100x100 velika mapa! const FARM_SIZE = 8; // 8x8 MICRO FARM - Začetek igre! const FARM_CENTER_X = 50; // Center mape (50,50) const FARM_CENTER_Y = 50; // Center mape (50,50) -const CITY_SIZE = 15; -const CITY_START_X = 65; // Desni del mape (npr. med 65 in 80) -const CITY_START_Y = 65; +// Zapuščene hiše lokacije - ODSTRANJENO ZA TESTIRANJE! +const ABANDONED_HOUSES = [ + // { x: 25, y: 25, size: 5 }, + // { x: 75, y: 30, size: 6 }, + // { x: 40, y: 75, size: 4 } +]; // PRAZNO - brez hiš! // ======================================================== -// NOVE KONSTANTE ZA RUDNIK IN RUDE +// GOZD KONSTANTE - STARDEW VALLEY STYLE (OPTIMIZIRANO) // ======================================================== -const TILE_STONE_ORE = 82; // ID za navadni kamen (Ore Tile) -const TILE_IRON_ORE = 83; // ID za železovo rudo -const TILE_PAVEMENT = 16; // ID za prehodno ploščico (tla rudnika) -const TILE_MINE_WALL = 81; // ID za zid rudnika (Solid/Kolizija) - -// ID-ji Virov -const ITEM_STONE = 20; // ID za kamen, ki ga igralec dobi -const ITEM_IRON = 21; // ID za železo - -const TREE_DENSITY_THRESHOLD = 0.45; // Višja vrednost = manj gosto (manj gozda) +const TREE_DENSITY = 0.01; // 1% chance za drevo (zelo nizka gostota) +const PURPLE_TREE_CHANCE = 0.30; // 30% vijolčnih dreves +const FRUIT_TREE_CHANCE = 0.20; // 20% sadnih dreves const ROCK_DENSITY_THRESHOLD = 0.60; // Prag za skupine skal +// ======================================================== +// RUDNIK KONSTANTE (za terrainTypes) +// ======================================================== +const TILE_PAVEMENT = 16; // ID za prehodno ploščico +const TILE_MINE_WALL = 81; // ID za zid rudnika +const TILE_STONE_ORE = 82; // ID za navadni kamen +const TILE_IRON_ORE = 83; // ID za železovo rudo + // Terrain Generator System class TerrainSystem { constructor(scene, width = 100, height = 100) { @@ -127,10 +132,35 @@ class TerrainSystem { this.generatedChunks = new Set(); this.chunkSize = 10; + // FOREST GENERATION: Tracking postavljenih dreves za preverjanje razdalje + this.placedTrees = []; // Seznam vseh postavljenih dreves { x, y } + this.MIN_TREE_DISTANCE_SQUARED = 2 * 2; // Minimalna razdalja med drevesi (2 tiles) + // Init tiles array with NULLs this.tiles = Array.from({ length: this.height }, () => Array(this.width).fill(null)); } + /** + * Preveri, ali je nova lokacija (newX, newY) dovolj oddaljena od vseh + * že postavljenih dreves. Uporablja kvadrat razdalje za hitrejšo optimizacijo. + */ + isTreeLocationFarEnough(newX, newY) { + for (let i = 0; i < this.placedTrees.length; i++) { + const existingTree = this.placedTrees[i]; + + // Izračunaj kvadrat razdalje + const dx = newX - existingTree.x; + const dy = newY - existingTree.y; + const distanceSq = (dx * dx) + (dy * dy); + + // Če je razdalja manjša od zahtevane minimalne razdalje, zavrni lokacijo + if (distanceSq < this.MIN_TREE_DISTANCE_SQUARED) { + return false; + } + } + return true; // Lokacija je dovolj oddaljena + } + createTileTextures() { const tileWidth = 48; const tileHeight = 60; @@ -373,186 +403,87 @@ class TerrainSystem { for (let y = startY; y < endY; y++) { for (let x = startX; x < endX; x++) { - // --- PER TILE GENERATION LOGIC (Moved from old loop) --- - const nx = x * 0.1; - const ny = y * 0.1; - const elevation = this.noise.noise(nx, ny); - - // SIMPLE TERRAIN - samo grass (brez elevation/stone/hills) - let terrainType = this.terrainTypes.GRASS_FULL; - - // Edges of WORLD -也 grass - // (removed elevation-based terrain - user wants clean platform) + // --- STARDEW VALLEY FOREST GENERATION --- + let terrainType = this.terrainTypes.GRASS_FULL; // Vsa mapa je trava! // Farm Override - ZELENA PLATFORMA! if (Math.abs(x - FARM_CENTER_X) <= FARM_SIZE / 2 && Math.abs(y - FARM_CENTER_Y) <= FARM_SIZE / 2) { - terrainType = this.terrainTypes.GRASS_FULL; // ZELENA TRAVA! + terrainType = this.terrainTypes.GRASS_FULL; } - // RIVER Override - VIJUGAST POTOK! - // River gre diagonalno skozi mapo z sinusnim vijuganjem - const riverCenterY = 50; // Center Y pozicija za river - const riverWidth = 3; // Širina potoka (3 tiles) - const waveAmplitude = 8; // Amplituda vijuganja - const waveFrequency = 0.1; // Frekvenca vijuganja - - // Izračun vijugaste poti - const riverOffset = Math.sin(x * waveFrequency) * waveAmplitude; - const riverY = riverCenterY + riverOffset; - - // Če je tile znotraj river area - if (Math.abs(y - riverY) <= riverWidth / 2) { - terrainType = this.terrainTypes.WATER; // VODA! - } - - // City Override - DISABLED (User request: no walls) - // if (x >= CITY_START_X && x < CITY_START_X + CITY_SIZE && - // y >= CITY_START_Y && y < CITY_START_Y + CITY_SIZE) { - // const isEdge = (x === CITY_START_X || - // x === CITY_START_X + CITY_SIZE - 1 || - // y === CITY_START_Y || - // y === CITY_START_Y + CITY_SIZE - 1); - // if (isEdge) { - // terrainType = { name: 'WALL_EDGE', color: 0x505050, solid: true }; - // } else { - // terrainType = this.terrainTypes.PAVEMENT; - // if (Math.random() < 0.15) { - // terrainType = this.terrainTypes.RUINS; - // } - // } - // } - + // Zapuščene hiše - DIRT tiles + let isHouse = false; + ABANDONED_HOUSES.forEach(house => { + if (x >= house.x && x < house.x + house.size && + y >= house.y && y < house.y + house.size) { + terrainType = this.terrainTypes.DIRT; // Hiša na DIRT + isHouse = true; + } + }); // Create Tile Data this.tiles[y][x] = { type: terrainType.name, - texture: terrainType.name === 'water' ? 'water_frame_0' : terrainType.name, // Water tiles get animated frame! + texture: terrainType.name, hasDecoration: false, hasCrop: false, - solid: terrainType.solid || false + solid: terrainType.solid || false, + isHouse: isHouse }; - // Track water tiles za animacijo - if (terrainType.name === 'water') { - this.waterTiles.push(this.tiles[y][x]); - } - - // Track valid positions for decorations - if (terrainType.name !== 'water' && terrainType.name !== 'sand' && terrainType.name !== 'stone' && !terrainType.solid) { - // Exclude Farm/City from random decor logic + // Track valid positions for decorations (TREES!) + if (terrainType.name === 'grass_full' && !isHouse) { const isFarm = Math.abs(x - FARM_CENTER_X) <= (FARM_SIZE / 2 + 2) && Math.abs(y - FARM_CENTER_Y) <= (FARM_SIZE / 2 + 2); - const isCity = x >= CITY_START_X - 2 && x < CITY_START_X + CITY_SIZE + 2 && y >= CITY_START_Y - 2 && y < CITY_START_Y + CITY_SIZE + 2; - - if (!isFarm && !isCity) { + if (!isFarm) { validPositions.push({ x, y }); } } - - // Direct Placement Calls (Trees/Rocks) - legacy method support - // this.placeTree(x, y, terrainType.name); // Optional: keep this if preferred over random batch } } - // --- CHUNK DECORATION PASS --- - // DISABLED - User wants clean platform (no trees, rocks, flowers) - - // 1. Random Decorations - DISABLED - // validPositions.forEach(pos => { - // // Trees - // if (Math.random() < 0.05) { - // this.placeTree(pos.x, pos.y, 'grass'); - // } - // // Rocks - // if (Math.random() < 0.02) { - // this.placeRock(pos.x, pos.y, 'grass'); - // } - // // Flowers - // if (Math.random() < 0.05) { - // const flowers = ['flower_red', 'flower_yellow', 'flower_blue']; - // const flowerType = flowers[Math.floor(Math.random() * flowers.length)]; - // this.addDecoration(pos.x, pos.y, flowerType); - // } - // // Path Stones - // if (Math.random() < 0.02) { - // this.addDecoration(pos.x, pos.y, 'path_stone'); - // } - // }); - - // MICRO FARM FENCE (8x8 starting area) - DISABLED FOR NOW - // Will be added properly later + // --- STARDEW VALLEY FOREST DECORATION PASS --- const farmMinX = FARM_CENTER_X - FARM_SIZE / 2; const farmMaxX = FARM_CENTER_X + FARM_SIZE / 2; const farmMinY = FARM_CENTER_Y - FARM_SIZE / 2; const farmMaxY = FARM_CENTER_Y + FARM_SIZE / 2; - // DECORATIONS: Flowers & Bushes on grass tiles (random) - for (let y = startY; y < endY; y++) { - for (let x = startX; x < endX; x++) { - const tile = this.tiles[y][x]; // Corrected access to this.tiles + // DREVESA - 3% gostota z preverjanjem razdalje! + validPositions.forEach(pos => { + const rand = Math.random(); - // Only on grass tiles, outside farm area - if (tile && tile.type === 'GRASS_FULL' && // Changed 'grass' to 'GRASS_FULL' to match terrainType.name - (x < farmMinX || x > farmMaxX || y < farmMinY || y > farmMaxY)) { - - const rand = Math.random(); - - // 10% chance for flowers - if (rand < 0.10) { - const flowerTypes = ['flowers_new', 'flowers_pink_isometric']; - const randomType = flowerTypes[Math.floor(Math.random() * flowerTypes.length)]; - this.addDecoration(x, y, randomType); - } - // 8% chance for grass patches (visual variety) - else if (rand >= 0.10 && rand < 0.18) { - this.addDecoration(x, y, 'grass_sprite'); - } - // 5% chance for bushes - else if (rand >= 0.18 && rand < 0.23) { - this.addDecoration(x, y, 'bush_small'); - } - // 3% chance for small rocks - else if (rand >= 0.23 && rand < 0.26) { - const rockTypes = ['rock_small', 'rock_2']; - const randomRock = rockTypes[Math.floor(Math.random() * rockTypes.length)]; - this.addDecoration(x, y, randomRock); - } + // 3% chance za drevo + if (rand < TREE_DENSITY) { + // PREVERJANJE RAZDALJE: Ali je ta lokacija dovolj oddaljena? + if (!this.isTreeLocationFarEnough(pos.x, pos.y)) { + return; // Preskoči to lokacijo - preblizu drugim drevesom! } - } - } - // Check if this chunk contains farm border - if (cx * this.chunkSize <= farmMaxX && (cx + 1) * this.chunkSize >= farmMinX && - cy * this.chunkSize <= farmMaxY && (cy + 1) * this.chunkSize >= farmMinY) { + const treeRand = Math.random(); + let treeType; - // Top border (y = farmMinY) - if (startY <= farmMinY && endY > farmMinY) { - for (let x = Math.max(startX, farmMinX); x <= Math.min(endX - 1, farmMaxX); x++) { - this.addDecoration(x, farmMinY, 'fence_isometric'); + // 30% VIJOLČNA DREVESA + if (treeRand < PURPLE_TREE_CHANCE) { + treeType = 'tree_purple'; } - } - - // Bottom border (y = farmMaxY) - if (startY <= farmMaxY && endY > farmMaxY) { - for (let x = Math.max(startX, farmMinX); x <= Math.min(endX - 1, farmMaxX); x++) { - this.addDecoration(x, farmMaxY, 'fence_isometric'); + // 20% SADNA DREVESA + else if (treeRand < PURPLE_TREE_CHANCE + FRUIT_TREE_CHANCE) { + const fruitTypes = ['tree_apple', 'tree_pear', 'tree_cherry']; + treeType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)]; } - } - - // Left border (x = farmMinX) - if (startX <= farmMinX && endX > farmMinX) { - for (let y = Math.max(startY, farmMinY); y <= Math.min(endY - 1, farmMaxY); y++) { - this.addDecoration(farmMinX, y, 'fence_isometric'); + // 50% NAVADNA DREVESA + else { + const normalTrees = ['tree_green_final', 'tree_blue_final', 'tree_sapling']; + treeType = normalTrees[Math.floor(Math.random() * normalTrees.length)]; } - } - // Right border (x = farmMaxX) - if (startX <= farmMaxX && endX > farmMaxX) { - for (let y = Math.max(startY, farmMinY); y <= Math.min(endY - 1, farmMaxY); y++) { - this.addDecoration(farmMaxX, y, 'fence_isometric'); - } + // DODAJ DREVO + this.addDecoration(pos.x, pos.y, treeType); + this.placedTrees.push({ x: pos.x, y: pos.y }); } - } + }); + + // KONEC generateChunk } updateChunks(camera) { @@ -777,18 +708,22 @@ class TerrainSystem { let scale = 1.0; - if (type === 'rock_1' || type === 'rock_2') scale = 1.5; // Povečano (bilo 0.5) + // POMANJŠANA DREVESA - Stardew Valley stil + if (type === 'rock_1' || type === 'rock_2') scale = 1.0; // Zmanjšano else if (type === 'tree_green_new' || type === 'tree_blue_new' || type === 'tree_dead_new') scale = 0.04; else if (type === 'flowers_new') scale = 0.02; else if (type === 'fence') scale = 0.025; else if (type === 'gravestone') scale = 0.03; else if (type === 'hill_sprite') scale = 0.025; - else if (type.includes('_final')) scale = 1.0; // New Final Trees + else if (type.includes('_final')) scale = 0.7; // POMANJŠANO - final trees + else if (type.includes('purple') || type.includes('apple') || type.includes('pear') || type.includes('cherry')) { + scale = 0.6; // POMANJŠANO - novi sadni in vijolčni + } else { // Old Assets (Low Res) - if (type.includes('tree')) scale = 1.2 + Math.random() * 0.4; - else if (type.includes('rock')) scale = 0.8; - else scale = 1.0; + if (type.includes('tree')) scale = 0.7 + Math.random() * 0.2; // POMANJŠANO (bilo 1.2-1.6) + else if (type.includes('rock')) scale = 0.6; // POMANJŠANO + else scale = 0.8; // POMANJŠANO } // Calculate Plant Day for Saplings (Growth System) diff --git a/ultra_remove_bg.py b/ultra_remove_bg.py new file mode 100644 index 0000000..1327ff8 --- /dev/null +++ b/ultra_remove_bg.py @@ -0,0 +1,77 @@ +from PIL import Image +import os + +# Lista slik za procesiranje +images_to_process = [ + 'assets/tree_purple.png', + 'assets/tree_apple.png', + 'assets/tree_pear.png', + 'assets/tree_cherry.png', + 'assets/tree_green_final.png', + 'assets/tree_blue_final.png', + 'assets/tree_dead_final.png' +] + +def ultra_remove_background(image_path): + """ULTRA AGRESIVNO odstranjevanje ozadja""" + try: + # Naloži sliko + img = Image.open(image_path).convert('RGBA') + data = img.getdata() + + new_data = [] + for item in data: + r, g, b, a = item + + # Če je že transparentno, ohrani + if a == 0: + new_data.append(item) + continue + + # Izračunaj brightness + brightness = (r + g + b) / 3 + + # ULTRA AGRESIVNO: Odstrani VSE kar je svetlejše od 100 + # To bo odstranilo VSE šahovske kvadratke + if brightness > 100: + new_data.append((r, g, b, 0)) # Transparentno + continue + + # Odstrani VSE sive barve (ne glede na brightness) + is_grayscale = abs(r - g) < 25 and abs(g - b) < 25 and abs(r - b) < 25 + if is_grayscale: + new_data.append((r, g, b, 0)) # Transparentno + continue + + # Ohrani samo temne, nasičene barve (drevesa) + max_rgb = max(r, g, b) + min_rgb = min(r, g, b) + saturation = 0 if max_rgb == 0 else (max_rgb - min_rgb) / max_rgb + + # Če je nizka saturacija (pastelno) -> odstrani + if saturation < 0.2: + new_data.append((r, g, b, 0)) + continue + + # Ohrani pixel + new_data.append(item) + + # Posodobi sliko + img.putdata(new_data) + + # Shrani + img.save(image_path) + print(f'✅ ULTRA Processed: {image_path}') + + except Exception as e: + print(f'❌ Error processing {image_path}: {e}') + +# Procesiraj vse slike +print('🔥 ULTRA AGGRESSIVE background removal...') +for img_path in images_to_process: + if os.path.exists(img_path): + ultra_remove_background(img_path) + else: + print(f'⚠️ File not found: {img_path}') + +print('✅ Done! All backgrounds ULTRA removed.')