499 lines
16 KiB
JavaScript
499 lines
16 KiB
JavaScript
// BiomeSystem - Manages world biomes and generation
|
|
class BiomeSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
|
|
// World size
|
|
this.worldWidth = 500;
|
|
this.worldHeight = 500;
|
|
|
|
// Biome map (500x500 grid of biome IDs)
|
|
this.biomeMap = [];
|
|
|
|
// Biome definitions
|
|
this.biomes = {
|
|
grassland: {
|
|
id: 'grassland',
|
|
name: 'Grassland',
|
|
color: 0x4a9d5f,
|
|
tileColor: '#4a9d5f',
|
|
features: {
|
|
trees: 0.05,
|
|
rocks: 0.02,
|
|
flowers: 0.15
|
|
},
|
|
weather: 'normal',
|
|
temperature: 20
|
|
},
|
|
forest: {
|
|
id: 'forest',
|
|
name: 'Forest',
|
|
color: 0x2d5016,
|
|
tileColor: '#2d5016',
|
|
features: {
|
|
trees: 0.60,
|
|
rocks: 0.05,
|
|
bushes: 0.20,
|
|
mushrooms: 0.10
|
|
},
|
|
weather: 'rainy',
|
|
temperature: 15
|
|
},
|
|
desert: {
|
|
id: 'desert',
|
|
name: 'Desert',
|
|
color: 0xd4c4a1,
|
|
tileColor: '#d4c4a1',
|
|
features: {
|
|
cacti: 0.08,
|
|
rocks: 0.15,
|
|
deadTrees: 0.03
|
|
},
|
|
weather: 'hot',
|
|
temperature: 35
|
|
},
|
|
mountain: {
|
|
id: 'mountain',
|
|
name: 'Mountain',
|
|
color: 0x808080,
|
|
tileColor: '#808080',
|
|
features: {
|
|
rocks: 0.40,
|
|
largeRocks: 0.20,
|
|
snow: 0.10
|
|
},
|
|
weather: 'cold',
|
|
temperature: -5
|
|
},
|
|
swamp: {
|
|
id: 'swamp',
|
|
name: 'Swamp',
|
|
color: 0x3d5a3d,
|
|
tileColor: '#3d5a3d',
|
|
features: {
|
|
water: 0.30,
|
|
deadTrees: 0.25,
|
|
vines: 0.15,
|
|
fog: true
|
|
},
|
|
weather: 'foggy',
|
|
temperature: 18
|
|
},
|
|
// ===== NEW BIOMES - NORMAL (4) =====
|
|
snow: {
|
|
id: 'snow',
|
|
name: 'Frozen Tundra',
|
|
color: 0xE0F7FA,
|
|
tileColor: '#E0F7FA',
|
|
features: {
|
|
ice: 0.40,
|
|
frozenTrees: 0.15,
|
|
snowDrifts: 0.25,
|
|
icicles: 0.10
|
|
},
|
|
weather: 'blizzard',
|
|
temperature: -20
|
|
},
|
|
wasteland: {
|
|
id: 'wasteland',
|
|
name: 'Wasteland',
|
|
color: 0x4a4a4a,
|
|
tileColor: '#4a4a4a',
|
|
features: {
|
|
ruins: 0.30,
|
|
rubble: 0.40,
|
|
scrapMetal: 0.20,
|
|
brokenMachinery: 0.15
|
|
},
|
|
weather: 'dusty',
|
|
temperature: 25
|
|
},
|
|
tropical: {
|
|
id: 'tropical',
|
|
name: 'Tropical Beach',
|
|
color: 0xFFE082,
|
|
tileColor: '#FFE082',
|
|
features: {
|
|
palmTrees: 0.25,
|
|
coconuts: 0.15,
|
|
shells: 0.20,
|
|
water: 0.40
|
|
},
|
|
weather: 'sunny',
|
|
temperature: 30
|
|
},
|
|
radioactive: {
|
|
id: 'radioactive',
|
|
name: 'Radioactive Zone',
|
|
color: 0x39FF14,
|
|
tileColor: '#39FF14',
|
|
features: {
|
|
glowingRocks: 0.30,
|
|
mutantPlants: 0.25,
|
|
radioactiveBarrels: 0.15,
|
|
toxicPuddles: 0.20,
|
|
glow: true
|
|
},
|
|
weather: 'toxic',
|
|
temperature: 28
|
|
},
|
|
// ===== NEW BIOMES - ANOMALOUS (9) =====
|
|
dino_valley: {
|
|
id: 'dino_valley',
|
|
name: 'Dino Valley',
|
|
color: 0x6B8E23,
|
|
tileColor: '#6B8E23',
|
|
features: {
|
|
prehistoricTrees: 0.45,
|
|
largeFerns: 0.35,
|
|
dinoFootprints: 0.20,
|
|
fossils: 0.10,
|
|
eggs: 0.05
|
|
},
|
|
weather: 'humid',
|
|
temperature: 32,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_dino'
|
|
},
|
|
mythical: {
|
|
id: 'mythical',
|
|
name: 'Mythical Highlands',
|
|
color: 0xB39DDB,
|
|
tileColor: '#B39DDB',
|
|
features: {
|
|
magicalTrees: 0.30,
|
|
crystals: 0.25,
|
|
floatingRocks: 0.20,
|
|
rainbows: 0.10,
|
|
magicAura: true
|
|
},
|
|
weather: 'magical',
|
|
temperature: 18,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_mythical'
|
|
},
|
|
endless_forest: {
|
|
id: 'endless_forest',
|
|
name: 'Endless Forest',
|
|
color: 0x1B5E20,
|
|
tileColor: '#1B5E20',
|
|
features: {
|
|
ancientTrees: 0.80,
|
|
mysteryFog: 0.30,
|
|
strangeFootprints: 0.15,
|
|
hiddenPaths: 0.20
|
|
},
|
|
weather: 'misty',
|
|
temperature: 12,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_endless_forest'
|
|
},
|
|
loch_ness: {
|
|
id: 'loch_ness',
|
|
name: 'Loch Ness',
|
|
color: 0x546E7A,
|
|
tileColor: '#546E7A',
|
|
features: {
|
|
scottishPines: 0.35,
|
|
heather: 0.25,
|
|
lochWater: 0.40,
|
|
castleRuins: 0.10
|
|
},
|
|
weather: 'rainy',
|
|
temperature: 10,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_scotland'
|
|
},
|
|
catacombs: {
|
|
id: 'catacombs',
|
|
name: 'Catacombs',
|
|
color: 0x3E2723,
|
|
tileColor: '#3E2723',
|
|
features: {
|
|
bones: 0.50,
|
|
tombs: 0.30,
|
|
skulls: 0.25,
|
|
ancientUrns: 0.15,
|
|
darkness: true
|
|
},
|
|
weather: 'underground',
|
|
temperature: 15,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_catacombs'
|
|
},
|
|
egyptian_desert: {
|
|
id: 'egyptian_desert',
|
|
name: 'Egyptian Desert',
|
|
color: 0xFFD54F,
|
|
tileColor: '#FFD54F',
|
|
features: {
|
|
pyramids: 0.05,
|
|
sandDunes: 0.60,
|
|
hieroglyphs: 0.15,
|
|
scarabs: 0.20,
|
|
sphinx: 0.01
|
|
},
|
|
weather: 'scorching',
|
|
temperature: 45,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_egypt'
|
|
},
|
|
amazon: {
|
|
id: 'amazon',
|
|
name: 'Amazon Rainforest',
|
|
color: 0x1B5E20,
|
|
tileColor: '#1B5E20',
|
|
features: {
|
|
jungleTrees: 0.75,
|
|
vines: 0.40,
|
|
exoticFlowers: 0.30,
|
|
tribalTotems: 0.10,
|
|
piranhaRivers: 0.15
|
|
},
|
|
weather: 'monsoon',
|
|
temperature: 35,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_amazon'
|
|
},
|
|
atlantis: {
|
|
id: 'atlantis',
|
|
name: 'Atlantis',
|
|
color: 0x00BCD4,
|
|
tileColor: '#00BCD4',
|
|
features: {
|
|
coralReefs: 0.40,
|
|
underwaterRuins: 0.35,
|
|
pearls: 0.15,
|
|
seaweed: 0.30,
|
|
bubbles: true,
|
|
underwater: true
|
|
},
|
|
weather: 'underwater',
|
|
temperature: 20,
|
|
anomalous: true,
|
|
unlockRequirement: 'portal_atlantis'
|
|
},
|
|
chernobyl: {
|
|
id: 'chernobyl',
|
|
name: 'Chernobyl',
|
|
color: 0x757575,
|
|
tileColor: '#757575',
|
|
features: {
|
|
reactorRuins: 0.20,
|
|
abandonedBuildings: 0.40,
|
|
radioactiveBarrels: 0.25,
|
|
sovietRelics: 0.20,
|
|
hazmatSigns: 0.15,
|
|
radiation: true
|
|
},
|
|
weather: 'nuclear',
|
|
temperature: 22,
|
|
anomalous: true,
|
|
isFinalZone: true,
|
|
unlockRequirement: 'train_to_chernobyl'
|
|
}
|
|
};
|
|
|
|
console.log('🌍 BiomeSystem initialized (500x500 world)');
|
|
}
|
|
|
|
// Generate biome map using Perlin-like noise
|
|
generateBiomeMap() {
|
|
console.log('🌍 Generating biome map...');
|
|
|
|
this.biomeMap = [];
|
|
|
|
// Initialize empty map
|
|
for (let y = 0; y < this.worldHeight; y++) {
|
|
this.biomeMap[y] = [];
|
|
for (let x = 0; x < this.worldWidth; x++) {
|
|
this.biomeMap[y][x] = null;
|
|
}
|
|
}
|
|
|
|
// Center is always grassland (farm area)
|
|
const centerX = Math.floor(this.worldWidth / 2);
|
|
const centerY = Math.floor(this.worldHeight / 2);
|
|
const farmRadius = 50; // 100x100 farm area
|
|
|
|
// Define biome centers (for now, simple regions)
|
|
const biomeRegions = [
|
|
{ biome: 'grassland', centerX: 250, centerY: 250, radius: 80 }, // Center (FARM)
|
|
{ biome: 'forest', centerX: 150, centerY: 150, radius: 100 }, // Northwest
|
|
{ biome: 'forest', centerX: 350, centerY: 150, radius: 80 }, // Northeast
|
|
{ biome: 'desert', centerX: 400, centerY: 350, radius: 90 }, // Southeast
|
|
{ biome: 'mountain', centerX: 100, centerY: 100, radius: 70 }, // Far northwest
|
|
{ biome: 'swamp', centerX: 100, centerY: 400, radius: 80 } // Southwest
|
|
];
|
|
|
|
// Fill biomes based on distance to region centers
|
|
for (let y = 0; y < this.worldHeight; y++) {
|
|
for (let x = 0; x < this.worldWidth; x++) {
|
|
// Find closest biome region
|
|
let closestBiome = 'grassland'; // Default
|
|
let minDistance = Infinity;
|
|
|
|
for (const region of biomeRegions) {
|
|
const dx = x - region.centerX;
|
|
const dy = y - region.centerY;
|
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
if (distance < minDistance) {
|
|
minDistance = distance;
|
|
closestBiome = region.biome;
|
|
}
|
|
}
|
|
|
|
this.biomeMap[y][x] = closestBiome;
|
|
}
|
|
}
|
|
|
|
console.log('✅ Biome map generated!');
|
|
}
|
|
|
|
// Get biome at specific coordinates
|
|
getBiomeAt(x, y) {
|
|
if (x < 0 || x >= this.worldWidth || y < 0 || y >= this.worldHeight) {
|
|
return 'grassland'; // Default outside bounds
|
|
}
|
|
|
|
return this.biomeMap[y][x] || 'grassland';
|
|
}
|
|
|
|
// Get biome data
|
|
getBiomeData(biomeId) {
|
|
return this.biomes[biomeId] || this.biomes.grassland;
|
|
}
|
|
|
|
// Check if feature should spawn at location
|
|
shouldSpawnFeature(x, y, featureType) {
|
|
const biomeId = this.getBiomeAt(x, y);
|
|
const biomeData = this.getBiomeData(biomeId);
|
|
|
|
if (!biomeData.features[featureType]) return false;
|
|
|
|
const chance = biomeData.features[featureType];
|
|
return Math.random() < chance;
|
|
}
|
|
|
|
// Get tile color for biome
|
|
getTileColor(x, y) {
|
|
const biomeId = this.getBiomeAt(x, y);
|
|
const biomeData = this.getBiomeData(biomeId);
|
|
return biomeData.tileColor;
|
|
}
|
|
|
|
// Apply biome-specific features during world generation
|
|
applyBiomeFeatures(x, y) {
|
|
const biomeId = this.getBiomeAt(x, y);
|
|
const biomeData = this.getBiomeData(biomeId);
|
|
|
|
const features = [];
|
|
|
|
// Trees
|
|
if (this.shouldSpawnFeature(x, y, 'trees')) {
|
|
features.push({ type: 'tree', variant: Math.floor(Math.random() * 3) });
|
|
}
|
|
|
|
// Rocks
|
|
if (this.shouldSpawnFeature(x, y, 'rocks')) {
|
|
features.push({ type: 'rock', size: Math.random() > 0.7 ? 'large' : 'small' });
|
|
}
|
|
|
|
// Biome-specific features
|
|
if (biomeId === 'forest') {
|
|
if (this.shouldSpawnFeature(x, y, 'bushes')) {
|
|
features.push({ type: 'bush' });
|
|
}
|
|
if (this.shouldSpawnFeature(x, y, 'mushrooms')) {
|
|
features.push({ type: 'mushroom' });
|
|
}
|
|
} else if (biomeId === 'desert') {
|
|
if (this.shouldSpawnFeature(x, y, 'cacti')) {
|
|
features.push({ type: 'cactus' });
|
|
}
|
|
if (this.shouldSpawnFeature(x, y, 'deadTrees')) {
|
|
features.push({ type: 'deadTree' });
|
|
}
|
|
} else if (biomeId === 'mountain') {
|
|
if (this.shouldSpawnFeature(x, y, 'largeRocks')) {
|
|
features.push({ type: 'boulder' });
|
|
}
|
|
} else if (biomeId === 'swamp') {
|
|
if (this.shouldSpawnFeature(x, y, 'deadTrees')) {
|
|
features.push({ type: 'deadTree' });
|
|
}
|
|
if (this.shouldSpawnFeature(x, y, 'vines')) {
|
|
features.push({ type: 'vine' });
|
|
}
|
|
}
|
|
|
|
return features;
|
|
}
|
|
|
|
// Get biome transitions (blend zones)
|
|
getBiomeBlend(x, y, radius = 3) {
|
|
// Check surrounding tiles for different biomes
|
|
const centerBiome = this.getBiomeAt(x, y);
|
|
const surroundingBiomes = new Set();
|
|
|
|
for (let dy = -radius; dy <= radius; dy++) {
|
|
for (let dx = -radius; dx <= radius; dx++) {
|
|
const biome = this.getBiomeAt(x + dx, y + dy);
|
|
if (biome !== centerBiome) {
|
|
surroundingBiomes.add(biome);
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
isTransition: surroundingBiomes.size > 0,
|
|
mainBiome: centerBiome,
|
|
nearbyBiomes: Array.from(surroundingBiomes)
|
|
};
|
|
}
|
|
|
|
// Get biome statistics (for debugging/UI)
|
|
getBiomeStats() {
|
|
const stats = {};
|
|
|
|
for (const biomeId in this.biomes) {
|
|
stats[biomeId] = 0;
|
|
}
|
|
|
|
for (let y = 0; y < this.worldHeight; y++) {
|
|
for (let x = 0; x < this.worldWidth; x++) {
|
|
const biome = this.getBiomeAt(x, y);
|
|
stats[biome] = (stats[biome] || 0) + 1;
|
|
}
|
|
}
|
|
|
|
// Convert to percentages
|
|
const total = this.worldWidth * this.worldHeight;
|
|
for (const biomeId in stats) {
|
|
stats[biomeId] = {
|
|
tiles: stats[biomeId],
|
|
percentage: ((stats[biomeId] / total) * 100).toFixed(1)
|
|
};
|
|
}
|
|
|
|
return stats;
|
|
}
|
|
|
|
// Export biome map for debugging/visualization
|
|
exportBiomeMap() {
|
|
return {
|
|
width: this.worldWidth,
|
|
height: this.worldHeight,
|
|
biomes: this.biomes,
|
|
map: this.biomeMap
|
|
};
|
|
}
|
|
|
|
// Destroy
|
|
destroy() {
|
|
this.biomeMap = [];
|
|
console.log('🌍 BiomeSystem destroyed');
|
|
}
|
|
}
|