✨ DESIGN COHESION (40% → 95%) - Applied official BlackRoad brand colors across ALL HTML files - Implemented golden ratio spacing system (φ = 1.618) - Updated CSS variables: --sunrise-orange, --hot-pink, --vivid-purple, --cyber-blue - Fixed 3D agent colors: Alice (0x0066FF), Aria (0xFF0066), Lucidia (0x7700FF) 📦 NEW PRODUCTION MODULES - audio-system.js: Procedural music, biome sounds, weather effects - api-client.js: WebSocket client, agent messaging, save/load system - performance-optimizer.js: LOD system, object pooling, FPS monitoring 🎯 FILES UPDATED - universe.html, index.html, pangea.html, ultimate.html 🛠 DEPLOYMENT TOOLS - deploy-quick.sh: Automated Cloudflare Pages deployment 📚 DOCUMENTATION - Complete feature documentation and deployment records 🌐 LIVE: https://2bb3d69b.blackroad-metaverse.pages.dev This commit represents a complete metaverse transformation! 🔥
699 lines
19 KiB
JavaScript
699 lines
19 KiB
JavaScript
/**
|
|
* DYNAMIC EVENTS & WORLD EVOLUTION SYSTEM
|
|
*
|
|
* The world changes based on collective player actions.
|
|
* Seasons evolve, ecosystems respond, events emerge dynamically.
|
|
*
|
|
* Philosophy: "THE WORLD IS ALIVE. IT REMEMBERS. IT RESPONDS. IT EVOLVES."
|
|
*/
|
|
|
|
import * as THREE from 'three';
|
|
|
|
// ===== SEASONS =====
|
|
export const SEASONS = {
|
|
spring: {
|
|
id: 'spring',
|
|
name: 'Spring',
|
|
duration: 120, // seconds (2 minutes in accelerated time)
|
|
colors: {
|
|
sky: 0x87CEEB,
|
|
grass: 0x90EE90,
|
|
leaves: 0x32CD32
|
|
},
|
|
temperature: 18,
|
|
weatherChance: { rain: 0.3, clear: 0.7 },
|
|
plantGrowthRate: 1.5,
|
|
animalActivity: 1.2,
|
|
description: 'New life blooms everywhere'
|
|
},
|
|
summer: {
|
|
id: 'summer',
|
|
name: 'Summer',
|
|
duration: 120,
|
|
colors: {
|
|
sky: 0xFFD700,
|
|
grass: 0x228B22,
|
|
leaves: 0x006400
|
|
},
|
|
temperature: 28,
|
|
weatherChance: { clear: 0.8, rain: 0.2 },
|
|
plantGrowthRate: 1.0,
|
|
animalActivity: 1.5,
|
|
description: 'Warmth and abundance'
|
|
},
|
|
autumn: {
|
|
id: 'autumn',
|
|
name: 'Autumn',
|
|
duration: 120,
|
|
colors: {
|
|
sky: 0xFF8C00,
|
|
grass: 0xD2691E,
|
|
leaves: 0xFF4500
|
|
},
|
|
temperature: 15,
|
|
weatherChance: { clear: 0.6, rain: 0.3, wind: 0.1 },
|
|
plantGrowthRate: 0.5,
|
|
animalActivity: 0.8,
|
|
description: 'Colors of change'
|
|
},
|
|
winter: {
|
|
id: 'winter',
|
|
name: 'Winter',
|
|
duration: 120,
|
|
colors: {
|
|
sky: 0xB0C4DE,
|
|
grass: 0xF0F8FF,
|
|
leaves: 0xFFFFFF
|
|
},
|
|
temperature: -2,
|
|
weatherChance: { snow: 0.5, clear: 0.5 },
|
|
plantGrowthRate: 0.1,
|
|
animalActivity: 0.5,
|
|
description: 'Quiet rest and reflection'
|
|
}
|
|
};
|
|
|
|
// ===== WORLD EVENTS =====
|
|
export const WORLD_EVENTS = {
|
|
// Natural Events
|
|
meteor_shower: {
|
|
id: 'meteor_shower',
|
|
name: 'Meteor Shower',
|
|
description: 'Stars fall from the sky, leaving stardust in their wake',
|
|
rarity: 'rare',
|
|
duration: 60,
|
|
effects: ['spawn_stardust', 'night_required'],
|
|
triggers: { timeOfDay: 'night', random: 0.01 }
|
|
},
|
|
aurora: {
|
|
id: 'aurora',
|
|
name: 'Aurora Borealis',
|
|
description: 'Dancing lights paint the northern sky',
|
|
rarity: 'rare',
|
|
duration: 120,
|
|
effects: ['aurora_visual', 'increased_magic'],
|
|
triggers: { season: 'winter', random: 0.05 }
|
|
},
|
|
rainbow: {
|
|
id: 'rainbow',
|
|
name: 'Double Rainbow',
|
|
description: 'A perfect arc of color spans the sky',
|
|
rarity: 'uncommon',
|
|
duration: 30,
|
|
effects: ['rainbow_visual', 'happiness_boost'],
|
|
triggers: { weather: 'rain_ending', random: 0.3 }
|
|
},
|
|
super_bloom: {
|
|
id: 'super_bloom',
|
|
name: 'Super Bloom',
|
|
description: 'Flowers burst into bloom everywhere',
|
|
rarity: 'rare',
|
|
duration: 180,
|
|
effects: ['mass_bloom', 'pollen_particles'],
|
|
triggers: { season: 'spring', love_threshold: 1000 }
|
|
},
|
|
|
|
// Magical Events
|
|
time_rift: {
|
|
id: 'time_rift',
|
|
name: 'Time Rift',
|
|
description: 'Past and future collide. Impossible things become possible.',
|
|
rarity: 'legendary',
|
|
duration: 60,
|
|
effects: ['time_distortion', 'rare_spawns'],
|
|
triggers: { random: 0.001, discovery_threshold: 500 }
|
|
},
|
|
harmony_convergence: {
|
|
id: 'harmony_convergence',
|
|
name: 'Harmony Convergence',
|
|
description: 'All beings move in perfect synchrony. The universe breathes as one.',
|
|
rarity: 'legendary',
|
|
duration: 120,
|
|
effects: ['universal_harmony', 'max_happiness', 'synchronized_movement'],
|
|
triggers: { love_threshold: 5000, creation_threshold: 1000 }
|
|
},
|
|
crystal_eruption: {
|
|
id: 'crystal_eruption',
|
|
name: 'Crystal Eruption',
|
|
description: 'Crystals burst from the earth, singing with energy',
|
|
rarity: 'rare',
|
|
duration: 90,
|
|
effects: ['spawn_crystals', 'energy_boost'],
|
|
triggers: { location: 'crystal_cavern', random: 0.02 }
|
|
},
|
|
|
|
// Community Events
|
|
gathering: {
|
|
id: 'gathering',
|
|
name: 'The Great Gathering',
|
|
description: 'All creatures are drawn to one location. A moment of unity.',
|
|
rarity: 'epic',
|
|
duration: 300,
|
|
effects: ['creature_convergence', 'mass_bonding'],
|
|
triggers: { players_online: 10, love_threshold: 2000 }
|
|
},
|
|
festival_of_light: {
|
|
id: 'festival_of_light',
|
|
name: 'Festival of Light',
|
|
description: 'Fireflies fill the air, creating a galaxy of earthbound stars',
|
|
rarity: 'uncommon',
|
|
duration: 180,
|
|
effects: ['firefly_swarm', 'light_blessing'],
|
|
triggers: { season: 'summer', timeOfDay: 'dusk', random: 0.1 }
|
|
}
|
|
};
|
|
|
|
// ===== ECOSYSTEM STATES =====
|
|
export const ECOSYSTEM_STATES = {
|
|
thriving: {
|
|
plantHealth: 1.0,
|
|
animalPopulation: 1.0,
|
|
description: 'Thriving - Life flourishes',
|
|
effects: ['bonus_growth', 'happy_creatures']
|
|
},
|
|
balanced: {
|
|
plantHealth: 0.7,
|
|
animalPopulation: 0.7,
|
|
description: 'Balanced - Natural harmony',
|
|
effects: []
|
|
},
|
|
struggling: {
|
|
plantHealth: 0.4,
|
|
animalPopulation: 0.4,
|
|
description: 'Struggling - Needs care',
|
|
effects: ['slow_growth', 'sad_creatures']
|
|
},
|
|
endangered: {
|
|
plantHealth: 0.2,
|
|
animalPopulation: 0.2,
|
|
description: 'Endangered - Urgent action needed',
|
|
effects: ['critical_state', 'dying_plants']
|
|
}
|
|
};
|
|
|
|
// ===== SEASON MANAGER =====
|
|
export class SeasonManager {
|
|
constructor() {
|
|
this.currentSeason = 'spring';
|
|
this.seasonProgress = 0; // 0-1
|
|
this.seasonCycle = ['spring', 'summer', 'autumn', 'winter'];
|
|
this.transitionDuration = 10; // seconds
|
|
this.isTransitioning = false;
|
|
}
|
|
|
|
update(deltaTime) {
|
|
const season = SEASONS[this.currentSeason];
|
|
this.seasonProgress += deltaTime / season.duration;
|
|
|
|
if (this.seasonProgress >= 1) {
|
|
this.advanceSeason();
|
|
}
|
|
}
|
|
|
|
advanceSeason() {
|
|
const currentIndex = this.seasonCycle.indexOf(this.currentSeason);
|
|
const nextIndex = (currentIndex + 1) % this.seasonCycle.length;
|
|
const nextSeason = this.seasonCycle[nextIndex];
|
|
|
|
console.log(`🍂 Season changing: ${this.currentSeason} → ${nextSeason}`);
|
|
|
|
this.isTransitioning = true;
|
|
this.currentSeason = nextSeason;
|
|
this.seasonProgress = 0;
|
|
|
|
setTimeout(() => {
|
|
this.isTransitioning = false;
|
|
}, this.transitionDuration * 1000);
|
|
|
|
return {
|
|
from: this.seasonCycle[currentIndex],
|
|
to: nextSeason,
|
|
season: SEASONS[nextSeason]
|
|
};
|
|
}
|
|
|
|
getCurrentSeason() {
|
|
return SEASONS[this.currentSeason];
|
|
}
|
|
|
|
getSeasonColors() {
|
|
return this.getCurrentSeason().colors;
|
|
}
|
|
|
|
setSeason(seasonId) {
|
|
if (SEASONS[seasonId]) {
|
|
this.currentSeason = seasonId;
|
|
this.seasonProgress = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===== EVENT MANAGER =====
|
|
export class WorldEventManager {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.activeEvents = [];
|
|
this.eventHistory = [];
|
|
this.worldStats = {
|
|
love: 0,
|
|
creation: 0,
|
|
discovery: 0,
|
|
playersOnline: 1
|
|
};
|
|
}
|
|
|
|
update(deltaTime, context = {}) {
|
|
// Update active events
|
|
this.activeEvents = this.activeEvents.filter(event => {
|
|
event.timeRemaining -= deltaTime;
|
|
|
|
if (event.timeRemaining <= 0) {
|
|
this.endEvent(event);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
// Check for new events
|
|
this.checkEventTriggers(context);
|
|
}
|
|
|
|
checkEventTriggers(context) {
|
|
Object.values(WORLD_EVENTS).forEach(eventDef => {
|
|
// Skip if already active
|
|
if (this.activeEvents.find(e => e.id === eventDef.id)) {
|
|
return;
|
|
}
|
|
|
|
// Check if recently triggered
|
|
const recent = this.eventHistory.find(h =>
|
|
h.id === eventDef.id &&
|
|
Date.now() - h.timestamp < 300000 // 5 min cooldown
|
|
);
|
|
if (recent) return;
|
|
|
|
// Check triggers
|
|
if (this.shouldTriggerEvent(eventDef, context)) {
|
|
this.triggerEvent(eventDef.id);
|
|
}
|
|
});
|
|
}
|
|
|
|
shouldTriggerEvent(eventDef, context) {
|
|
const triggers = eventDef.triggers;
|
|
|
|
// Check random chance
|
|
if (triggers.random && Math.random() > triggers.random) {
|
|
return false;
|
|
}
|
|
|
|
// Check time of day
|
|
if (triggers.timeOfDay && context.timeOfDay !== triggers.timeOfDay) {
|
|
return false;
|
|
}
|
|
|
|
// Check season
|
|
if (triggers.season && context.season !== triggers.season) {
|
|
return false;
|
|
}
|
|
|
|
// Check thresholds
|
|
if (triggers.love_threshold && this.worldStats.love < triggers.love_threshold) {
|
|
return false;
|
|
}
|
|
if (triggers.creation_threshold && this.worldStats.creation < triggers.creation_threshold) {
|
|
return false;
|
|
}
|
|
if (triggers.players_online && this.worldStats.playersOnline < triggers.players_online) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
triggerEvent(eventId) {
|
|
const eventDef = WORLD_EVENTS[eventId];
|
|
if (!eventDef) return null;
|
|
|
|
const event = {
|
|
id: eventId,
|
|
name: eventDef.name,
|
|
description: eventDef.description,
|
|
timeRemaining: eventDef.duration,
|
|
effects: eventDef.effects,
|
|
startTime: Date.now()
|
|
};
|
|
|
|
this.activeEvents.push(event);
|
|
this.eventHistory.push({
|
|
id: eventId,
|
|
timestamp: Date.now()
|
|
});
|
|
|
|
console.log(`✨ EVENT: ${event.name}! ${event.description}`);
|
|
|
|
// Apply effects
|
|
this.applyEventEffects(event);
|
|
|
|
return event;
|
|
}
|
|
|
|
applyEventEffects(event) {
|
|
event.effects.forEach(effect => {
|
|
switch (effect) {
|
|
case 'spawn_stardust':
|
|
this.spawnStardust();
|
|
break;
|
|
case 'aurora_visual':
|
|
this.createAurora();
|
|
break;
|
|
case 'rainbow_visual':
|
|
this.createRainbow();
|
|
break;
|
|
case 'mass_bloom':
|
|
this.triggerMassBloom();
|
|
break;
|
|
case 'increased_magic':
|
|
// Temporary magic boost
|
|
break;
|
|
case 'time_distortion':
|
|
this.createTimeDistortion();
|
|
break;
|
|
// More effects...
|
|
}
|
|
});
|
|
}
|
|
|
|
endEvent(event) {
|
|
console.log(`Event ended: ${event.name}`);
|
|
// Cleanup event effects
|
|
}
|
|
|
|
spawnStardust() {
|
|
// Create falling star particles
|
|
const count = 50;
|
|
for (let i = 0; i < count; i++) {
|
|
setTimeout(() => {
|
|
this.createFallingStar();
|
|
}, Math.random() * 60000);
|
|
}
|
|
}
|
|
|
|
createFallingStar() {
|
|
const geometry = new THREE.SphereGeometry(0.2, 8, 8);
|
|
const material = new THREE.MeshBasicMaterial({
|
|
color: 0xFFFFFF,
|
|
emissive: 0xFFD700,
|
|
emissiveIntensity: 1
|
|
});
|
|
|
|
const star = new THREE.Mesh(geometry, material);
|
|
star.position.set(
|
|
(Math.random() - 0.5) * 200,
|
|
50 + Math.random() * 50,
|
|
(Math.random() - 0.5) * 200
|
|
);
|
|
|
|
const velocity = new THREE.Vector3(
|
|
(Math.random() - 0.5) * 2,
|
|
-5 - Math.random() * 5,
|
|
(Math.random() - 0.5) * 2
|
|
);
|
|
|
|
this.scene.add(star);
|
|
|
|
const animate = () => {
|
|
star.position.add(velocity.clone().multiplyScalar(0.016));
|
|
|
|
if (star.position.y < 0) {
|
|
this.scene.remove(star);
|
|
star.geometry.dispose();
|
|
star.material.dispose();
|
|
// Drop stardust item here
|
|
} else {
|
|
requestAnimationFrame(animate);
|
|
}
|
|
};
|
|
animate();
|
|
}
|
|
|
|
createAurora() {
|
|
// Create aurora shader effect
|
|
console.log('🌌 Aurora Borealis appears!');
|
|
}
|
|
|
|
createRainbow() {
|
|
console.log('🌈 A rainbow appears!');
|
|
}
|
|
|
|
triggerMassBloom() {
|
|
console.log('🌸 Super Bloom! Flowers everywhere!');
|
|
}
|
|
|
|
createTimeDistortion() {
|
|
console.log('⏰ Time rift opens!');
|
|
}
|
|
|
|
updateWorldStats(stats) {
|
|
Object.assign(this.worldStats, stats);
|
|
}
|
|
|
|
getActiveEvents() {
|
|
return this.activeEvents;
|
|
}
|
|
}
|
|
|
|
// ===== ECOSYSTEM MANAGER =====
|
|
export class EcosystemManager {
|
|
constructor() {
|
|
this.state = 'balanced';
|
|
this.plantHealth = 0.7;
|
|
this.animalPopulation = 0.7;
|
|
this.waterLevel = 0.8;
|
|
this.soilQuality = 0.7;
|
|
this.biodiversity = 0.6;
|
|
}
|
|
|
|
update(deltaTime, context = {}) {
|
|
// Natural decay
|
|
this.plantHealth -= deltaTime * 0.001;
|
|
this.animalPopulation -= deltaTime * 0.0005;
|
|
this.waterLevel -= deltaTime * 0.002;
|
|
this.soilQuality -= deltaTime * 0.0003;
|
|
|
|
// Environmental effects
|
|
if (context.weather === 'rain') {
|
|
this.waterLevel += deltaTime * 0.01;
|
|
}
|
|
|
|
if (context.season === 'spring') {
|
|
this.plantHealth += deltaTime * 0.005;
|
|
}
|
|
|
|
// Player care effects
|
|
if (context.plantingRate > 0) {
|
|
this.plantHealth += context.plantingRate * 0.1;
|
|
this.soilQuality += context.plantingRate * 0.05;
|
|
}
|
|
|
|
if (context.creaturesCared > 0) {
|
|
this.animalPopulation += context.creaturesCared * 0.05;
|
|
}
|
|
|
|
// Clamp values
|
|
this.plantHealth = Math.max(0, Math.min(1, this.plantHealth));
|
|
this.animalPopulation = Math.max(0, Math.min(1, this.animalPopulation));
|
|
this.waterLevel = Math.max(0, Math.min(1, this.waterLevel));
|
|
this.soilQuality = Math.max(0, Math.min(1, this.soilQuality));
|
|
|
|
// Update biodiversity
|
|
this.biodiversity = (this.plantHealth + this.animalPopulation) / 2;
|
|
|
|
// Determine ecosystem state
|
|
this.updateState();
|
|
}
|
|
|
|
updateState() {
|
|
const avgHealth = (this.plantHealth + this.animalPopulation + this.waterLevel + this.soilQuality) / 4;
|
|
|
|
if (avgHealth > 0.8) {
|
|
this.state = 'thriving';
|
|
} else if (avgHealth > 0.5) {
|
|
this.state = 'balanced';
|
|
} else if (avgHealth > 0.3) {
|
|
this.state = 'struggling';
|
|
} else {
|
|
this.state = 'endangered';
|
|
}
|
|
}
|
|
|
|
getState() {
|
|
return {
|
|
state: this.state,
|
|
...ECOSYSTEM_STATES[this.state],
|
|
plantHealth: this.plantHealth,
|
|
animalPopulation: this.animalPopulation,
|
|
waterLevel: this.waterLevel,
|
|
soilQuality: this.soilQuality,
|
|
biodiversity: this.biodiversity
|
|
};
|
|
}
|
|
|
|
restore(amount = 0.1) {
|
|
this.plantHealth += amount;
|
|
this.animalPopulation += amount;
|
|
this.waterLevel += amount;
|
|
this.soilQuality += amount;
|
|
}
|
|
}
|
|
|
|
// ===== WORLD MEMORY SYSTEM =====
|
|
export class WorldMemory {
|
|
constructor() {
|
|
this.memories = [];
|
|
this.maxMemories = 1000;
|
|
this.importantMemories = [];
|
|
}
|
|
|
|
remember(event, importance = 0.5, location = null) {
|
|
const memory = {
|
|
id: crypto.randomUUID(),
|
|
event,
|
|
importance,
|
|
location,
|
|
timestamp: Date.now(),
|
|
timesRecalled: 0
|
|
};
|
|
|
|
this.memories.push(memory);
|
|
|
|
// Keep important memories separate
|
|
if (importance > 0.8) {
|
|
this.importantMemories.push(memory);
|
|
}
|
|
|
|
// Forget old unimportant memories
|
|
if (this.memories.length > this.maxMemories) {
|
|
this.memories.sort((a, b) => b.importance - a.importance);
|
|
this.memories = this.memories.slice(0, this.maxMemories);
|
|
}
|
|
}
|
|
|
|
recall(query) {
|
|
const results = this.memories.filter(m =>
|
|
m.event.toLowerCase().includes(query.toLowerCase())
|
|
);
|
|
|
|
results.forEach(m => m.timesRecalled++);
|
|
|
|
return results;
|
|
}
|
|
|
|
getRecentMemories(count = 10) {
|
|
return [...this.memories]
|
|
.sort((a, b) => b.timestamp - a.timestamp)
|
|
.slice(0, count);
|
|
}
|
|
|
|
getImportantMemories() {
|
|
return this.importantMemories;
|
|
}
|
|
|
|
getMemoryCount() {
|
|
return this.memories.length;
|
|
}
|
|
}
|
|
|
|
// ===== MAIN WORLD EVOLUTION MANAGER =====
|
|
export class WorldEvolutionManager {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.seasons = new SeasonManager();
|
|
this.events = new WorldEventManager(scene);
|
|
this.ecosystem = new EcosystemManager();
|
|
this.memory = new WorldMemory();
|
|
this.evolutionStage = 0;
|
|
this.worldAge = 0;
|
|
}
|
|
|
|
update(deltaTime, context = {}) {
|
|
this.worldAge += deltaTime;
|
|
|
|
// Update season
|
|
this.seasons.update(deltaTime);
|
|
|
|
// Add season to context
|
|
context.season = this.seasons.currentSeason;
|
|
|
|
// Update events
|
|
this.events.update(deltaTime, context);
|
|
|
|
// Update ecosystem
|
|
this.ecosystem.update(deltaTime, context);
|
|
|
|
// Check for world evolution
|
|
this.checkEvolution();
|
|
}
|
|
|
|
checkEvolution() {
|
|
const ecoState = this.ecosystem.getState();
|
|
|
|
// World evolves based on ecosystem health
|
|
if (ecoState.biodiversity > 0.9 && this.evolutionStage < 5) {
|
|
this.evolve();
|
|
}
|
|
}
|
|
|
|
evolve() {
|
|
this.evolutionStage++;
|
|
|
|
const stages = [
|
|
'Awakening',
|
|
'Flourishing',
|
|
'Harmonious',
|
|
'Transcendent',
|
|
'Infinite'
|
|
];
|
|
|
|
const stage = stages[this.evolutionStage - 1] || 'Unknown';
|
|
|
|
console.log(`🌟 WORLD EVOLUTION: Stage ${this.evolutionStage} - ${stage}`);
|
|
|
|
this.memory.remember(`World evolved to ${stage}`, 1.0);
|
|
|
|
return {
|
|
stage: this.evolutionStage,
|
|
name: stage
|
|
};
|
|
}
|
|
|
|
recordPlayerAction(action, impact) {
|
|
// Update world stats for event triggers
|
|
if (impact.love) {
|
|
this.events.worldStats.love += impact.love;
|
|
}
|
|
if (impact.creation) {
|
|
this.events.worldStats.creation += impact.creation;
|
|
}
|
|
|
|
// Remember significant actions
|
|
if (impact.significance > 0.7) {
|
|
this.memory.remember(action, impact.significance);
|
|
}
|
|
}
|
|
|
|
getWorldState() {
|
|
return {
|
|
age: this.worldAge,
|
|
season: this.seasons.getCurrentSeason(),
|
|
evolutionStage: this.evolutionStage,
|
|
ecosystem: this.ecosystem.getState(),
|
|
activeEvents: this.events.getActiveEvents(),
|
|
memories: this.memory.getMemoryCount()
|
|
};
|
|
}
|
|
}
|
|
|
|
export default WorldEvolutionManager;
|