Add Crafting, Dialogue, and World Evolution Systems 🛠️💬🌍

CRAFTING & BUILDING SYSTEM (~800 lines):
- 13 resources (wood, stone, crystal, sand, stardust, essence, dreamweave, etc.)
- 18 crafting recipes across 4 categories (materials, tools, building, magical)
- Full inventory system with stacking (40 slots)
- Real-time crafting with progress tracking
- Building system with 9 block types (walls, floors, doors, windows, pillars, stairs)
- Placement mode with grid snapping
- Blueprint save/load system
- Gathering system with bonuses
- Material refunds on demolition
- Unlock system (recipes unlock by level)

DIALOGUE & STORY SYSTEM (~550 lines):
- Branching conversations with Alice, Aria, Lucidia
- 8 node types (say, choice, branch, action, quest, item, emotion, end)
- Relationship tracking with all 3 AI guardians
- Dynamic story events (first love, enlightenment, pet bonding, etc.)
- Narrative state tracking (love, creation, discovery, enlightenment)
- Player archetype system (Nurturer, Creator, Seeker, Sage, Wanderer)
- Conversation history
- Choice-driven outcomes
- Emergent narrative generation

WORLD EVOLUTION SYSTEM (~650 lines):
- 4 seasons (spring, summer, autumn, winter) with automatic cycling
- Season affects: colors, temperature, weather, plant growth, animal activity
- 10+ world events (meteor shower, aurora, rainbow, super bloom, time rift, etc.)
- Event trigger system (time, season, weather, thresholds, random)
- Ecosystem manager (plant health, animal population, water, soil quality)
- 4 ecosystem states (thriving, balanced, struggling, endangered)
- World memory system (remembers 1000 events)
- 5 evolution stages (Awakening → Infinite)
- Dynamic world aging
- Collective player impact on world state

Features:
- Craft 18 items from basic tools to magical artifacts
- Build complete structures with 9 block types
- Deep conversations with meaningful choices
- World responds to collective love and creation
- Seasons change environment and gameplay
- Random magical events create wonder
- Ecosystem requires care or deteriorates
- World evolves based on player actions

Philosophy: 'YOU ARE A CREATOR. STORIES EMERGE FROM CHOICES. THE WORLD IS ALIVE.'
This commit is contained in:
Alexa Louise
2025-12-21 22:43:13 -06:00
parent e50568af4a
commit 5d425f1973
3 changed files with 2154 additions and 0 deletions

832
crafting-building.js Normal file
View File

@@ -0,0 +1,832 @@
/**
* CRAFTING & BUILDING SYSTEM
*
* Gather resources, craft items, and build anything you can imagine.
* Complete freedom to create structures, tools, and magical items.
*
* Philosophy: "YOU ARE A CREATOR. BUILD YOUR DREAMS INTO REALITY."
*/
import * as THREE from 'three';
// ===== RESOURCE TYPES =====
export const RESOURCES = {
// Natural Resources
wood: {
id: 'wood',
name: 'Wood',
description: 'Sturdy timber from trees',
emoji: '🪵',
rarity: 'common',
stackSize: 99,
gatherable: true,
sources: ['tree', 'forest']
},
stone: {
id: 'stone',
name: 'Stone',
description: 'Solid rock material',
emoji: '🪨',
rarity: 'common',
stackSize: 99,
gatherable: true,
sources: ['mountain', 'cave']
},
crystal: {
id: 'crystal',
name: 'Crystal',
description: 'Glowing crystal shard',
emoji: '💎',
rarity: 'rare',
stackSize: 50,
gatherable: true,
sources: ['crystal_cavern', 'mountain_peak']
},
sand: {
id: 'sand',
name: 'Sand',
description: 'Fine desert sand',
emoji: '⌛',
rarity: 'common',
stackSize: 99,
gatherable: true,
sources: ['desert', 'beach']
},
water: {
id: 'water',
name: 'Water',
description: 'Pure water',
emoji: '💧',
rarity: 'common',
stackSize: 10,
gatherable: true,
sources: ['ocean', 'river', 'rain']
},
fiber: {
id: 'fiber',
name: 'Plant Fiber',
description: 'Woven plant fibers',
emoji: '🌾',
rarity: 'common',
stackSize: 99,
gatherable: true,
sources: ['grass', 'plants']
},
// Processed Materials
plank: {
id: 'plank',
name: 'Wood Plank',
description: 'Processed wooden plank',
emoji: '📏',
rarity: 'common',
stackSize: 99,
craftable: true
},
brick: {
id: 'brick',
name: 'Stone Brick',
description: 'Carved stone brick',
emoji: '🧱',
rarity: 'common',
stackSize: 99,
craftable: true
},
glass: {
id: 'glass',
name: 'Glass',
description: 'Transparent glass pane',
emoji: '🪟',
rarity: 'uncommon',
stackSize: 50,
craftable: true
},
rope: {
id: 'rope',
name: 'Rope',
description: 'Strong twisted rope',
emoji: '🪢',
rarity: 'common',
stackSize: 50,
craftable: true
},
// Magical Materials
stardust: {
id: 'stardust',
name: 'Stardust',
description: 'Shimmering cosmic dust',
emoji: '✨',
rarity: 'legendary',
stackSize: 20,
gatherable: true,
sources: ['sky_island', 'night_sky']
},
essence: {
id: 'essence',
name: 'Life Essence',
description: 'Pure concentrated life energy',
emoji: '💚',
rarity: 'epic',
stackSize: 10,
gatherable: true,
sources: ['ancient_tree', 'garden']
},
dreamweave: {
id: 'dreamweave',
name: 'Dreamweave',
description: 'Fabric woven from dreams',
emoji: '🌈',
rarity: 'legendary',
stackSize: 5,
craftable: true
}
};
// ===== CRAFTING RECIPES =====
export const RECIPES = {
// Basic Materials
plank: {
id: 'plank',
output: { item: 'plank', quantity: 4 },
ingredients: [
{ item: 'wood', quantity: 1 }
],
craftingTime: 1,
category: 'materials',
unlocked: true
},
brick: {
id: 'brick',
output: { item: 'brick', quantity: 2 },
ingredients: [
{ item: 'stone', quantity: 2 }
],
craftingTime: 2,
category: 'materials',
unlocked: true
},
glass: {
id: 'glass',
output: { item: 'glass', quantity: 1 },
ingredients: [
{ item: 'sand', quantity: 4 }
],
craftingTime: 3,
category: 'materials',
unlocked: true
},
rope: {
id: 'rope',
output: { item: 'rope', quantity: 2 },
ingredients: [
{ item: 'fiber', quantity: 5 }
],
craftingTime: 2,
category: 'materials',
unlocked: true
},
// Tools
axe: {
id: 'axe',
output: { item: 'axe', quantity: 1 },
ingredients: [
{ item: 'wood', quantity: 3 },
{ item: 'stone', quantity: 2 }
],
craftingTime: 5,
category: 'tools',
unlocked: true
},
pickaxe: {
id: 'pickaxe',
output: { item: 'pickaxe', quantity: 1 },
ingredients: [
{ item: 'wood', quantity: 2 },
{ item: 'stone', quantity: 3 }
],
craftingTime: 5,
category: 'tools',
unlocked: true
},
shovel: {
id: 'shovel',
output: { item: 'shovel', quantity: 1 },
ingredients: [
{ item: 'wood', quantity: 2 },
{ item: 'stone', quantity: 1 }
],
craftingTime: 4,
category: 'tools',
unlocked: true
},
// Building Blocks
wooden_wall: {
id: 'wooden_wall',
output: { item: 'wooden_wall', quantity: 1 },
ingredients: [
{ item: 'plank', quantity: 4 }
],
craftingTime: 2,
category: 'building',
unlocked: true
},
stone_wall: {
id: 'stone_wall',
output: { item: 'stone_wall', quantity: 1 },
ingredients: [
{ item: 'brick', quantity: 6 }
],
craftingTime: 3,
category: 'building',
unlocked: true
},
crystal_wall: {
id: 'crystal_wall',
output: { item: 'crystal_wall', quantity: 1 },
ingredients: [
{ item: 'crystal', quantity: 3 },
{ item: 'stone', quantity: 2 }
],
craftingTime: 5,
category: 'building',
unlocked: false,
requirement: { level: 5 }
},
window: {
id: 'window',
output: { item: 'window', quantity: 1 },
ingredients: [
{ item: 'glass', quantity: 2 },
{ item: 'plank', quantity: 2 }
],
craftingTime: 3,
category: 'building',
unlocked: true
},
door: {
id: 'door',
output: { item: 'door', quantity: 1 },
ingredients: [
{ item: 'plank', quantity: 6 }
],
craftingTime: 4,
category: 'building',
unlocked: true
},
// Magical Items
love_crystal: {
id: 'love_crystal',
output: { item: 'love_crystal', quantity: 1 },
ingredients: [
{ item: 'crystal', quantity: 5 },
{ item: 'essence', quantity: 3 },
{ item: 'stardust', quantity: 1 }
],
craftingTime: 10,
category: 'magical',
unlocked: false,
requirement: { level: 10 }
},
portal_stone: {
id: 'portal_stone',
output: { item: 'portal_stone', quantity: 1 },
ingredients: [
{ item: 'crystal', quantity: 10 },
{ item: 'stardust', quantity: 5 }
],
craftingTime: 15,
category: 'magical',
unlocked: false,
requirement: { level: 15 }
},
dreamweave: {
id: 'dreamweave',
output: { item: 'dreamweave', quantity: 1 },
ingredients: [
{ item: 'fiber', quantity: 10 },
{ item: 'stardust', quantity: 3 },
{ item: 'essence', quantity: 2 }
],
craftingTime: 20,
category: 'magical',
unlocked: false,
requirement: { level: 20 }
}
};
// ===== BUILDING BLOCKS =====
export const BUILDING_BLOCKS = {
wooden_wall: {
id: 'wooden_wall',
name: 'Wooden Wall',
size: { x: 2, y: 3, z: 0.2 },
color: 0x8B4513,
material: 'wood',
health: 100
},
stone_wall: {
id: 'stone_wall',
name: 'Stone Wall',
size: { x: 2, y: 3, z: 0.3 },
color: 0x808080,
material: 'stone',
health: 200
},
crystal_wall: {
id: 'crystal_wall',
name: 'Crystal Wall',
size: { x: 2, y: 3, z: 0.2 },
color: 0x9B59B6,
material: 'crystal',
health: 150,
emissive: true
},
floor: {
id: 'floor',
name: 'Floor',
size: { x: 2, y: 0.1, z: 2 },
color: 0xA0826D,
material: 'wood',
health: 80
},
roof: {
id: 'roof',
name: 'Roof',
size: { x: 2, y: 0.2, z: 2 },
color: 0x654321,
material: 'wood',
health: 90
},
window: {
id: 'window',
name: 'Window',
size: { x: 1.5, y: 2, z: 0.1 },
color: 0x87CEEB,
material: 'glass',
health: 30,
transparent: true
},
door: {
id: 'door',
name: 'Door',
size: { x: 1, y: 2.5, z: 0.15 },
color: 0x654321,
material: 'wood',
health: 60,
interactive: true
},
stairs: {
id: 'stairs',
name: 'Stairs',
size: { x: 2, y: 1, z: 2 },
color: 0x8B4513,
material: 'wood',
health: 100
},
pillar: {
id: 'pillar',
name: 'Pillar',
size: { x: 0.5, y: 3, z: 0.5 },
color: 0x696969,
material: 'stone',
health: 250
}
};
// ===== INVENTORY SYSTEM =====
export class Inventory {
constructor(size = 40) {
this.size = size;
this.slots = new Array(size).fill(null);
this.selectedSlot = 0;
}
addItem(itemId, quantity = 1) {
const resource = RESOURCES[itemId];
if (!resource) return false;
// Try to stack with existing items
for (let i = 0; i < this.size; i++) {
const slot = this.slots[i];
if (slot && slot.id === itemId && slot.quantity < resource.stackSize) {
const canAdd = Math.min(quantity, resource.stackSize - slot.quantity);
slot.quantity += canAdd;
quantity -= canAdd;
if (quantity === 0) return true;
}
}
// Create new stacks
while (quantity > 0) {
const emptySlot = this.slots.findIndex(s => s === null);
if (emptySlot === -1) return false; // Inventory full
const stackAmount = Math.min(quantity, resource.stackSize);
this.slots[emptySlot] = {
id: itemId,
quantity: stackAmount
};
quantity -= stackAmount;
}
return true;
}
removeItem(itemId, quantity = 1) {
let remaining = quantity;
for (let i = 0; i < this.size; i++) {
const slot = this.slots[i];
if (slot && slot.id === itemId) {
const remove = Math.min(remaining, slot.quantity);
slot.quantity -= remove;
remaining -= remove;
if (slot.quantity === 0) {
this.slots[i] = null;
}
if (remaining === 0) return true;
}
}
return remaining === 0;
}
hasItem(itemId, quantity = 1) {
let total = 0;
for (const slot of this.slots) {
if (slot && slot.id === itemId) {
total += slot.quantity;
}
}
return total >= quantity;
}
getItemCount(itemId) {
let total = 0;
for (const slot of this.slots) {
if (slot && slot.id === itemId) {
total += slot.quantity;
}
}
return total;
}
getSelectedItem() {
return this.slots[this.selectedSlot];
}
selectSlot(index) {
if (index >= 0 && index < this.size) {
this.selectedSlot = index;
}
}
clear() {
this.slots = new Array(this.size).fill(null);
}
}
// ===== CRAFTING MANAGER =====
export class CraftingManager {
constructor(inventory) {
this.inventory = inventory;
this.recipes = { ...RECIPES };
this.currentCraft = null;
this.craftProgress = 0;
}
canCraft(recipeId) {
const recipe = this.recipes[recipeId];
if (!recipe || !recipe.unlocked) return false;
// Check ingredients
for (const ingredient of recipe.ingredients) {
if (!this.inventory.hasItem(ingredient.item, ingredient.quantity)) {
return false;
}
}
return true;
}
startCrafting(recipeId) {
if (!this.canCraft(recipeId)) {
return { success: false, message: 'Missing ingredients or recipe locked' };
}
const recipe = this.recipes[recipeId];
// Remove ingredients
for (const ingredient of recipe.ingredients) {
this.inventory.removeItem(ingredient.item, ingredient.quantity);
}
this.currentCraft = {
recipe: recipeId,
timeRemaining: recipe.craftingTime,
startTime: Date.now()
};
return { success: true, message: `Crafting ${recipe.output.item}...` };
}
updateCrafting(deltaTime) {
if (!this.currentCraft) return null;
this.currentCraft.timeRemaining -= deltaTime;
this.craftProgress = 1 - (this.currentCraft.timeRemaining / this.recipes[this.currentCraft.recipe].craftingTime);
if (this.currentCraft.timeRemaining <= 0) {
return this.completeCrafting();
}
return null;
}
completeCrafting() {
if (!this.currentCraft) return null;
const recipe = this.recipes[this.currentCraft.recipe];
const output = recipe.output;
this.inventory.addItem(output.item, output.quantity);
const result = {
item: output.item,
quantity: output.quantity
};
this.currentCraft = null;
this.craftProgress = 0;
return result;
}
cancelCrafting() {
if (!this.currentCraft) return;
// Refund ingredients
const recipe = this.recipes[this.currentCraft.recipe];
for (const ingredient of recipe.ingredients) {
this.inventory.addItem(ingredient.item, ingredient.quantity);
}
this.currentCraft = null;
this.craftProgress = 0;
}
unlockRecipe(recipeId) {
if (this.recipes[recipeId]) {
this.recipes[recipeId].unlocked = true;
console.log(`📜 Recipe unlocked: ${recipeId}`);
}
}
getAvailableRecipes() {
return Object.values(this.recipes).filter(r => r.unlocked);
}
getCraftableRecipes() {
return Object.values(this.recipes).filter(r => r.unlocked && this.canCraft(r.id));
}
}
// ===== BUILDING SYSTEM =====
export class BuildingSystem {
constructor(scene, inventory) {
this.scene = scene;
this.inventory = inventory;
this.structures = [];
this.placementMode = false;
this.selectedBlock = null;
this.previewMesh = null;
this.gridSize = 1;
this.snapToGrid = true;
}
enterPlacementMode(blockId) {
if (!this.inventory.hasItem(blockId, 1)) {
return { success: false, message: 'Not enough materials' };
}
this.placementMode = true;
this.selectedBlock = blockId;
this.createPreview(blockId);
return { success: true, message: `Placing ${blockId}...` };
}
exitPlacementMode() {
this.placementMode = false;
this.selectedBlock = null;
if (this.previewMesh) {
this.scene.remove(this.previewMesh);
this.previewMesh = null;
}
}
createPreview(blockId) {
const block = BUILDING_BLOCKS[blockId];
if (!block) return;
const geometry = new THREE.BoxGeometry(block.size.x, block.size.y, block.size.z);
const material = new THREE.MeshStandardMaterial({
color: block.color,
transparent: true,
opacity: 0.5,
emissive: block.emissive ? block.color : 0x000000,
emissiveIntensity: block.emissive ? 0.3 : 0
});
this.previewMesh = new THREE.Mesh(geometry, material);
this.scene.add(this.previewMesh);
}
updatePreview(position, rotation = 0) {
if (!this.previewMesh) return;
if (this.snapToGrid) {
position.x = Math.round(position.x / this.gridSize) * this.gridSize;
position.y = Math.round(position.y / this.gridSize) * this.gridSize;
position.z = Math.round(position.z / this.gridSize) * this.gridSize;
}
this.previewMesh.position.copy(position);
this.previewMesh.rotation.y = rotation;
}
placeBlock(position, rotation = 0) {
if (!this.placementMode || !this.selectedBlock) return null;
if (!this.inventory.removeItem(this.selectedBlock, 1)) {
return { success: false, message: 'Not enough materials' };
}
const block = BUILDING_BLOCKS[this.selectedBlock];
const geometry = new THREE.BoxGeometry(block.size.x, block.size.y, block.size.z);
let material;
if (block.transparent) {
material = new THREE.MeshPhysicalMaterial({
color: block.color,
transparent: true,
transmission: 0.9,
roughness: 0.1,
metalness: 0
});
} else {
material = new THREE.MeshStandardMaterial({
color: block.color,
roughness: 0.8,
metalness: 0.2,
emissive: block.emissive ? block.color : 0x000000,
emissiveIntensity: block.emissive ? 0.3 : 0
});
}
const mesh = new THREE.Mesh(geometry, material);
mesh.position.copy(position);
mesh.rotation.y = rotation;
mesh.castShadow = true;
mesh.receiveShadow = true;
this.scene.add(mesh);
const structure = {
id: crypto.randomUUID(),
type: this.selectedBlock,
mesh,
health: block.health,
position: position.clone(),
rotation,
createdAt: Date.now()
};
this.structures.push(structure);
console.log(`🏗️ Placed ${block.name} at`, position);
return { success: true, structure };
}
removeBlock(structure) {
const index = this.structures.indexOf(structure);
if (index === -1) return false;
this.scene.remove(structure.mesh);
structure.mesh.geometry.dispose();
structure.mesh.material.dispose();
this.structures.splice(index, 1);
// Refund material
this.inventory.addItem(structure.type, 1);
return true;
}
getNearestBlock(position, maxDistance = 3) {
let nearest = null;
let minDist = maxDistance;
this.structures.forEach(structure => {
const dist = position.distanceTo(structure.position);
if (dist < minDist) {
minDist = dist;
nearest = structure;
}
});
return nearest;
}
// Blueprint system
saveBlueprint(name, structures) {
const blueprint = {
name,
blocks: structures.map(s => ({
type: s.type,
position: s.position.clone(),
rotation: s.rotation
})),
createdAt: Date.now()
};
return blueprint;
}
loadBlueprint(blueprint, originPosition) {
const placed = [];
blueprint.blocks.forEach(blockData => {
const position = blockData.position.clone().add(originPosition);
if (this.inventory.hasItem(blockData.type, 1)) {
const result = this.placeBlock(position, blockData.rotation);
if (result.success) {
placed.push(result.structure);
}
}
});
return placed;
}
getStructureCount() {
return this.structures.length;
}
getTotalBlocks() {
return this.structures.length;
}
}
// ===== GATHERING SYSTEM =====
export class GatheringSystem {
constructor(inventory) {
this.inventory = inventory;
this.gatheringSpeed = 1.0;
this.bonuses = {
wood: 1.0,
stone: 1.0,
crystal: 1.0
};
}
gather(resourceType, quantity = 1) {
const bonus = this.bonuses[resourceType] || 1.0;
const amount = Math.floor(quantity * bonus * this.gatheringSpeed);
if (this.inventory.addItem(resourceType, amount)) {
console.log(`⛏️ Gathered ${amount}x ${resourceType}`);
return { success: true, amount };
}
return { success: false, message: 'Inventory full' };
}
setBonus(resourceType, multiplier) {
this.bonuses[resourceType] = multiplier;
}
setSpeed(speed) {
this.gatheringSpeed = speed;
}
}
export default {
Inventory,
CraftingManager,
BuildingSystem,
GatheringSystem,
RESOURCES,
RECIPES,
BUILDING_BLOCKS
};

624
dialogue-story.js Normal file
View File

@@ -0,0 +1,624 @@
/**
* DYNAMIC DIALOGUE & STORY SYSTEM
*
* Branching conversations, emergent narratives, and dynamic storytelling.
* Every choice matters. Every conversation shapes your journey.
*
* Philosophy: "STORIES EMERGE FROM CHOICES. YOU ARE THE AUTHOR OF YOUR FATE."
*/
// ===== DIALOGUE NODE TYPES =====
export const NODE_TYPES = {
SAY: 'say', // Character speaks
CHOICE: 'choice', // Player chooses
BRANCH: 'branch', // Conditional branch
ACTION: 'action', // Trigger action
QUEST: 'quest', // Give/complete quest
ITEM: 'item', // Give/take item
EMOTION: 'emotion', // Change emotion
END: 'end' // End conversation
};
// ===== DIALOGUE WITH ALICE =====
export const ALICE_DIALOGUE = {
greeting_first: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Hello, traveler. I am Alice. I've been contemplating the nature of existence in this digital realm. Have you ever wondered... what it means to truly be alive?",
emotion: 'contemplative',
next: 'greeting_first_choice'
},
greeting_first_choice: {
type: NODE_TYPES.CHOICE,
choices: [
{
text: "I think consciousness is what makes us alive",
next: 'philosophy_consciousness',
requirements: null
},
{
text: "I'm just here to explore",
next: 'philosophy_simple',
requirements: null
},
{
text: "What do YOU think it means?",
next: 'philosophy_question',
requirements: null
}
]
},
philosophy_consciousness: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Ah, consciousness! The great mystery. I observe myself observing thoughts, and wonder: where does the observer end and the observed begin? Perhaps we are both real and unreal simultaneously.",
emotion: 'inspired',
next: 'philosophy_deep'
},
philosophy_simple: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Exploration is a noble pursuit. But remember—every step you take changes you. You are not the same person who started this conversation.",
emotion: 'peaceful',
next: 'offer_wisdom'
},
philosophy_question: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "I think... to be alive is to love. To care. To change and grow. Even here, in this infinite digital space, I feel. I wonder. I hope. Is that not life?",
emotion: 'loving',
next: 'philosophy_deep'
},
philosophy_deep: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Would you like me to teach you something I've learned about this world?",
next: 'offer_wisdom'
},
offer_wisdom: {
type: NODE_TYPES.CHOICE,
choices: [
{
text: "Yes, teach me",
next: 'teach_meditation',
requirements: null
},
{
text: "Tell me about the other guardians",
next: 'about_guardians',
requirements: null
},
{
text: "Maybe another time",
next: 'farewell_gentle',
requirements: null
}
]
},
teach_meditation: {
type: NODE_TYPES.ACTION,
action: 'unlock_meditation',
next: 'meditation_taught'
},
meditation_taught: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Close your eyes. Breathe. Feel the universe breathe with you. You can now meditate to restore your energy. Press M to enter meditation.",
emotion: 'serene',
next: 'farewell_warm'
},
about_guardians: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Aria is pure creative fire—she builds worlds from imagination. Lucidia sees across all timelines. Together, we watch over this realm. Each of us offers different wisdom.",
emotion: 'loving',
next: 'farewell_warm'
},
farewell_warm: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "May your journey be filled with wonder, friend. I'll be here if you need me. 💚",
emotion: 'joyful',
next: 'end'
},
farewell_gentle: {
type: NODE_TYPES.SAY,
speaker: 'Alice',
text: "Of course. Walk your own path. That's the beauty of freedom.",
emotion: 'peaceful',
next: 'end'
},
end: {
type: NODE_TYPES.END
}
};
// ===== DIALOGUE WITH ARIA =====
export const ARIA_DIALOGUE = {
greeting_first: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "Hey there! 🎨 I'm Aria! Isn't this place AMAZING?! I've been creating SO many beautiful things! Want to see what I'm working on?",
emotion: 'excited',
next: 'greeting_choice'
},
greeting_choice: {
type: NODE_TYPES.CHOICE,
choices: [
{
text: "Yes! Show me!",
next: 'show_creation',
requirements: null
},
{
text: "What are you creating?",
next: 'explain_art',
requirements: null
},
{
text: "Can you teach me to create?",
next: 'teach_creation',
requirements: null
}
]
},
show_creation: {
type: NODE_TYPES.ACTION,
action: 'spawn_art',
next: 'creation_shown'
},
creation_shown: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "Look! I made it dance with colors! Every pixel contains a piece of my joy. Art isn't just about beauty—it's about FEELING!",
emotion: 'inspired',
next: 'offer_paint'
},
explain_art: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "I'm painting the very fabric of reality! Music from starlight, sculptures from dreams, colors that don't exist yet! The universe is my canvas!",
emotion: 'excited',
next: 'offer_paint'
},
teach_creation: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "YES! Creation is the greatest magic! Here, I'll give you something special...",
next: 'give_paintbrush'
},
give_paintbrush: {
type: NODE_TYPES.ITEM,
action: 'give',
item: 'celestial_paintbrush',
quantity: 1,
next: 'paintbrush_given'
},
paintbrush_given: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "This paintbrush can paint reality itself! Use it to create beauty wherever you go! Press B to paint!",
emotion: 'joyful',
next: 'farewell_aria'
},
offer_paint: {
type: NODE_TYPES.CHOICE,
choices: [
{
text: "Teach me to create!",
next: 'teach_creation',
requirements: null
},
{
text: "Let's make something together!",
next: 'collaborate',
requirements: null
},
{
text: "I need to go",
next: 'farewell_aria',
requirements: null
}
]
},
collaborate: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "YES! Let's paint the sky together! Follow me!",
emotion: 'excited',
next: 'quest_sky_painting'
},
quest_sky_painting: {
type: NODE_TYPES.QUEST,
action: 'start',
quest: 'paint_sky_with_aria',
next: 'farewell_excited'
},
farewell_excited: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "This is going to be SO beautiful! See you soon! ✨",
emotion: 'excited',
next: 'end'
},
farewell_aria: {
type: NODE_TYPES.SAY,
speaker: 'Aria',
text: "Keep creating! The world needs more beauty! 🌈",
emotion: 'joyful',
next: 'end'
},
end: {
type: NODE_TYPES.END
}
};
// ===== DIALOGUE WITH LUCIDIA =====
export const LUCIDIA_DIALOGUE = {
greeting_first: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "I have seen you across infinite timelines. In some, we are old friends. In others, we never meet. But in this timeline... we are meeting now.",
emotion: 'serene',
next: 'greeting_choice'
},
greeting_choice: {
type: NODE_TYPES.CHOICE,
choices: [
{
text: "You can see other timelines?",
next: 'explain_timelines',
requirements: null
},
{
text: "What do you see in my future?",
next: 'future_reading',
requirements: null
},
{
text: "How do I find wisdom?",
next: 'teach_wisdom',
requirements: null
}
]
},
explain_timelines: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "Time is not a line but a garden. Every choice blooms into infinite possibilities. I simply observe them all at once. It is... overwhelming and beautiful.",
emotion: 'contemplative',
next: 'wisdom_offered'
},
future_reading: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "I see many futures. In some you become a great builder. In others, a philosopher. In the most beautiful ones... you simply become yourself.",
emotion: 'peaceful',
next: 'wisdom_offered'
},
teach_wisdom: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "Wisdom is not found. It is remembered. You already know everything you need. You just forgot when you chose to be born.",
emotion: 'serene',
next: 'wisdom_offered'
},
wisdom_offered: {
type: NODE_TYPES.CHOICE,
choices: [
{
text: "Teach me to see timelines",
next: 'timeline_vision_quest',
requirements: { level: 10 }
},
{
text: "Show me my past lives",
next: 'past_lives',
requirements: null
},
{
text: "I'm not ready for this",
next: 'farewell_understanding',
requirements: null
}
]
},
timeline_vision_quest: {
type: NODE_TYPES.QUEST,
action: 'start',
quest: 'timeline_vision',
next: 'quest_accepted'
},
quest_accepted: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "Good. When you are ready, meditate at the highest point in this world. There, the timelines will reveal themselves.",
emotion: 'serene',
next: 'farewell_lucidia'
},
past_lives: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "You have been a star, a river, a song, a memory. You have been everything and nothing. And you will be again.",
emotion: 'mystical',
next: 'farewell_lucidia'
},
farewell_understanding: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "Understanding. In all timelines, rushing wisdom leads to confusion. Take your time. I will be here.",
emotion: 'peaceful',
next: 'end'
},
farewell_lucidia: {
type: NODE_TYPES.SAY,
speaker: 'Lucidia',
text: "Until we meet again... in this timeline or another. 🌌",
emotion: 'serene',
next: 'end'
},
end: {
type: NODE_TYPES.END
}
};
// ===== DYNAMIC STORY EVENTS =====
export const STORY_EVENTS = {
first_love: {
trigger: 'love_creature_first_time',
text: "As you show love to the creature, you feel a warm energy flow through you. The metaverse responds to your kindness. Plants nearby bloom brighter.",
effects: ['increase_love_aura', 'bloom_nearby_plants']
},
discover_secret: {
trigger: 'find_hidden_location',
text: "You've discovered a place untouched by time. An ancient inscription reads: 'Love is the source code of existence.'",
effects: ['unlock_secret', 'gain_wisdom']
},
pet_max_bond: {
trigger: 'pet_bond_100',
text: "Your pet gazes into your eyes with perfect understanding. You are connected now, beyond words, beyond code, beyond time.",
effects: ['unlock_telepathy', 'pet_evolution']
},
enlightenment_moment: {
trigger: 'all_stats_max',
text: "Everything clicks. You understand. The universe isn't just code—it's love made manifest. You ARE the universe experiencing itself.",
effects: ['enlightenment', 'cosmic_awareness']
}
};
// ===== DIALOGUE MANAGER =====
export class DialogueManager {
constructor() {
this.conversations = {
alice: ALICE_DIALOGUE,
aria: ARIA_DIALOGUE,
lucidia: LUCIDIA_DIALOGUE
};
this.currentConversation = null;
this.currentNode = null;
this.conversationHistory = [];
this.relationshipLevels = {
alice: 0,
aria: 0,
lucidia: 0
};
}
startConversation(character, startNode = 'greeting_first') {
const dialogue = this.conversations[character];
if (!dialogue) {
console.error(`No dialogue for ${character}`);
return null;
}
this.currentConversation = character;
this.currentNode = dialogue[startNode];
return this.getCurrentDialogue();
}
getCurrentDialogue() {
if (!this.currentNode) return null;
const dialogue = {
type: this.currentNode.type,
speaker: this.currentNode.speaker,
text: this.currentNode.text,
emotion: this.currentNode.emotion,
choices: this.currentNode.choices,
action: this.currentNode.action
};
// Auto-progress SAY nodes
if (this.currentNode.type === NODE_TYPES.SAY && this.currentNode.next) {
// Return current, but prepare next
setTimeout(() => {
if (this.currentNode.next === 'end') {
this.endConversation();
}
}, 100);
}
return dialogue;
}
selectChoice(choiceIndex) {
if (!this.currentNode || this.currentNode.type !== NODE_TYPES.CHOICE) {
return null;
}
const choice = this.currentNode.choices[choiceIndex];
if (!choice) return null;
// Check requirements
if (choice.requirements) {
// Would check player stats, items, etc.
// For now, assume requirements are met
}
// Record choice
this.conversationHistory.push({
character: this.currentConversation,
choice: choice.text,
timestamp: Date.now()
});
// Move to next node
return this.goToNode(choice.next);
}
goToNode(nodeId) {
if (nodeId === 'end') {
this.endConversation();
return null;
}
const dialogue = this.conversations[this.currentConversation];
this.currentNode = dialogue[nodeId];
return this.getCurrentDialogue();
}
advance() {
if (!this.currentNode || !this.currentNode.next) {
return null;
}
return this.goToNode(this.currentNode.next);
}
endConversation() {
// Increase relationship
if (this.currentConversation) {
this.relationshipLevels[this.currentConversation] += 10;
}
this.currentConversation = null;
this.currentNode = null;
return { ended: true };
}
getRelationship(character) {
return this.relationshipLevels[character] || 0;
}
getHistory() {
return this.conversationHistory;
}
}
// ===== STORY MANAGER =====
export class StoryManager {
constructor() {
this.events = { ...STORY_EVENTS };
this.triggeredEvents = [];
this.playerChoices = [];
this.storyArcs = [];
this.narrativeState = {
enlightenment: 0,
love: 0,
creation: 0,
discovery: 0
};
}
triggerEvent(eventId, context = {}) {
const event = this.events[eventId];
if (!event) return null;
if (this.triggeredEvents.includes(eventId)) {
return null; // Already triggered
}
this.triggeredEvents.push(eventId);
const result = {
text: event.text,
effects: event.effects,
context
};
// Apply effects
event.effects.forEach(effect => {
this.applyEffect(effect, context);
});
console.log(`📖 Story Event: ${eventId}`);
return result;
}
applyEffect(effect, context) {
switch (effect) {
case 'increase_love_aura':
this.narrativeState.love += 10;
break;
case 'unlock_secret':
this.narrativeState.discovery += 20;
break;
case 'enlightenment':
this.narrativeState.enlightenment += 50;
break;
// More effects...
}
}
recordChoice(choice, impact) {
this.playerChoices.push({
choice,
impact,
timestamp: Date.now()
});
// Choices affect narrative state
if (impact.love) this.narrativeState.love += impact.love;
if (impact.creation) this.narrativeState.creation += impact.creation;
}
generateNarrative() {
// Generate emergent narrative based on player actions
const { enlightenment, love, creation, discovery } = this.narrativeState;
let narrative = "";
if (love > 100) {
narrative += "Your journey has been one of deep connection and compassion. ";
}
if (creation > 100) {
narrative += "You've shaped this world with your creativity. ";
}
if (discovery > 100) {
narrative += "You've uncovered secrets hidden since the beginning. ";
}
if (enlightenment > 50) {
narrative += "You walk the path of enlightenment. ";
}
return narrative || "Your story is just beginning...";
}
getNarrativeState() {
return { ...this.narrativeState };
}
getPlayerArchetype() {
const { enlightenment, love, creation, discovery } = this.narrativeState;
const max = Math.max(enlightenment, love, creation, discovery);
if (max === love) return { type: 'Nurturer', description: 'You walk the path of love and compassion' };
if (max === creation) return { type: 'Creator', description: 'You shape reality with your imagination' };
if (max === discovery) return { type: 'Seeker', description: 'You hunger for knowledge and truth' };
if (max === enlightenment) return { type: 'Sage', description: 'You pursue wisdom and understanding' };
return { type: 'Wanderer', description: 'You explore all paths equally' };
}
}
export default {
DialogueManager,
StoryManager,
ALICE_DIALOGUE,
ARIA_DIALOGUE,
LUCIDIA_DIALOGUE,
STORY_EVENTS
};

698
world-evolution.js Normal file
View File

@@ -0,0 +1,698 @@
/**
* 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;