Compare commits
10 Commits
b3fe1000c0
...
f393b28d73
| Author | SHA1 | Date | |
|---|---|---|---|
| f393b28d73 | |||
| 63a2d251ff | |||
| 919b68afd0 | |||
| 5e4235889a | |||
| 076acd4812 | |||
| b93b269e6d | |||
| 78e31fc765 | |||
| fd1ec4f503 | |||
| e5ef16742b | |||
| ca81062b43 |
7
.claude/settings.json
Normal file
7
.claude/settings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"permissions": {
|
||||
"additionalDirectories": [
|
||||
"../GroveEngine"
|
||||
]
|
||||
}
|
||||
}
|
||||
95
CLAUDE.md
95
CLAUDE.md
@ -14,11 +14,33 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## 📋 Implementation Status
|
||||
|
||||
**ALWAYS CHECK**: `TODO.md` at project root for current implementation roadmap and tasks.
|
||||
**ALWAYS CHECK**:
|
||||
- `TODO.md` at project root for current implementation roadmap and high-level phases
|
||||
- `TASKLIST.md` for detailed task breakdown organized by time investment (Quick Wins, Light Tasks, Medium Tasks, Feature Tasks, Big Tasks)
|
||||
|
||||
**Current Phase**: **PRODUCTION-READY** Hot-Reload System - **0.4ms average reload time achieved!**
|
||||
**Current Phase**: World Generation System - Geological and resource foundation complete
|
||||
|
||||
## 🎯 **Recent Major Achievements - UI Interface System**
|
||||
## 🎯 **Recent Major Achievements - World Generation System**
|
||||
|
||||
### ✅ **Complete Geological Simulation (COMPLETED)**
|
||||
- **7-Phase Pipeline**: 4.6 billion year geological evolution simulation
|
||||
- **Physics-Based Tectonics**: Collision detection, plate movement, mountain formation
|
||||
- **Scientific Climate Model**: WindRegions, ITCZ, and realistic weather patterns
|
||||
- **Biome Classification**: 18 distinct biomes with elevation and generation parameters
|
||||
|
||||
### 🗺️ **Resource Distribution System (COMPLETED)**
|
||||
- **70+ Natural Features**: Geologically accurate formation patterns
|
||||
- **Smart Biome Integration**: Blacklist + frequent biomes for scalable compatibility
|
||||
- **Mass-Based Quality**: Region strength determines available resource grades
|
||||
- **Cross-Referenced Resources**: All features map to actual game resource definitions
|
||||
|
||||
### ⚙️ **Spatial Distribution Patterns (COMPLETED)**
|
||||
- **5 Pattern Types**: Concentrated, uniform, ring, clustered, gradient distributions
|
||||
- **Random Assignment**: Each region gets unpredictable density patterns
|
||||
- **Biome-Aware Placement**: Local environment determines compatible features
|
||||
- **Phase 8 Ready**: System prepared for integration with world generation pipeline
|
||||
|
||||
## 🎯 **Previous Major Achievements - UI Interface System**
|
||||
|
||||
### ✅ **Complete IUI Interface Architecture (COMPLETED)**
|
||||
- **Data-Agnostic Design**: Generic `IUI` interface supporting all content types
|
||||
@ -79,6 +101,7 @@ The project uses a **hierarchical documentation system** in `/docs/`:
|
||||
- `systeme-militaire.md` - Vehicle design with grid-based component placement
|
||||
- `economie-logistique.md` - Market simulation, supply chains, pricing
|
||||
- `map-system.md` - Procedural generation with 218+ elements
|
||||
- `rendering-system.md` - Sprite composition and entity rendering
|
||||
- `factory-architecture-post-player.md` - Advanced production architecture
|
||||
|
||||
### 🔧 03-implementation/
|
||||
@ -97,18 +120,43 @@ The project uses a **hierarchical documentation system** in `/docs/`:
|
||||
## Key Technical Concepts
|
||||
|
||||
### Core Interface Architecture (COMPLETED - PHASE 1)
|
||||
- **Quadruple Interface Pattern**: IEngine, IModuleSystem, IModule, IIO + ITaskScheduler
|
||||
- **Complete Interface Set**: IEngine, IModuleSystem, IModule, IIO, ITaskScheduler, IDataTree, IDataNode, ICoordinationModule
|
||||
- **CRITICAL**: **Core interfaces are IMMUTABLE** - Never modify once finalized
|
||||
- **Configuration System**: IDataTree/IDataNode for hierarchical data-driven development with const references
|
||||
- **Coordination System**: ICoordinationModule as global orchestrator (first launched, last shutdown)
|
||||
- **Task Delegation**: ITaskScheduler for module → execution system delegation (multithreading)
|
||||
- **Autonomous Modules**: Small (200-300 lines) hot-reloadable modules (.so files)
|
||||
- **Claude Code Optimized**: Each module is a micro-context for AI development
|
||||
- **Performance Targets**: V1 Client 30+ fps, V2 Client 60+ fps, V1 Server 10+ players, V2 Server 100+ players
|
||||
|
||||
### Interface Specifications (NEVER MODIFY THESE)
|
||||
- **IEngine**: Engine orchestration, module loading, client/coordinator socket management
|
||||
- **IModuleSystem**: Execution strategy + task scheduling (inherits ITaskScheduler)
|
||||
- **IModule**: Pure business logic + pub/sub communication + task delegation
|
||||
- **ICoordinationModule**: Global system orchestrator, gameconfig.json management, module deployment topology
|
||||
- **IEngine**: Local engine orchestration, module loading, client/coordinator socket management
|
||||
- **IModuleSystem**: Execution strategy implementation (Sequential → Threaded → Cluster)
|
||||
- **IModule**: Pure business logic + pub/sub communication (**BREAKING CHANGES** - see below)
|
||||
- **IIO**: Pull-based pub/sub with low-frequency batching and health monitoring
|
||||
- **ITaskScheduler**: Task delegation interface for module → execution system
|
||||
- **ITaskScheduler**: Task delegation interface for module → execution system (multithreading)
|
||||
- **IDataTree**: Configuration tree container with manual hot-reload capabilities
|
||||
- **IDataNode**: Hierarchical data nodes with pattern matching and property queries (**const methods**)
|
||||
|
||||
### BREAKING CHANGES in IModule Interface
|
||||
```cpp
|
||||
// OLD Interface (DEPRECATED)
|
||||
virtual void initialize(const json& config, IIO* io, ITaskScheduler* scheduler) = 0;
|
||||
virtual bool isHealthy() = 0;
|
||||
|
||||
// NEW Interface (CURRENT)
|
||||
virtual void setConfiguration(const IDataNode& configNode, IIO* io, ITaskScheduler* scheduler) = 0;
|
||||
virtual const IDataNode& getConfiguration() = 0;
|
||||
virtual json getHealthStatus() = 0; // Detailed JSON instead of bool
|
||||
// initialize() method REMOVED
|
||||
```
|
||||
|
||||
### Configuration Immutability System
|
||||
- **const IDataNode&** references prevent modules from modifying configuration
|
||||
- **Single source of truth**: gameconfig.json loaded via IDataTree
|
||||
- **Hot-reload**: CoordinationModule propagates config changes to all modules
|
||||
- **Type safety**: All IDataNode getters are const methods
|
||||
|
||||
### Module Frequencies & Isolation
|
||||
- **ProductionModule**: 60Hz (frame-perfect factory operations)
|
||||
@ -272,7 +320,7 @@ cmake --build build # ALL debugging tools active by default
|
||||
## Claude Code Development Practices
|
||||
|
||||
### Interface Management (ABSOLUTELY CRITICAL)
|
||||
- **IMMUTABLE INTERFACES**: Core interfaces (IEngine, IModuleSystem, IModule, IIO, ITaskScheduler) are FROZEN
|
||||
- **IMMUTABLE INTERFACES**: Core interfaces (IEngine, IModuleSystem, IModule, IIO, ITaskScheduler, IDataTree, IDataNode) are FROZEN
|
||||
- **NEVER MODIFY**: Once interfaces are finalized, they become the architectural foundation
|
||||
- **Extension Only**: New functionality via new implementations, not interface changes
|
||||
- **Breaking Changes**: Modifying core interfaces breaks ALL existing modules and systems
|
||||
@ -344,6 +392,10 @@ The project includes 16 C++ libraries via FetchContent:
|
||||
3. `03-implementation/testing-strategy.md` - Testing approach
|
||||
4. `04-reference/INTEGRATION-MASTER-LIST.md` - Complete specifications
|
||||
|
||||
### For Task Management
|
||||
1. `TODO.md` - High-level implementation roadmap and current phases
|
||||
2. **`TASKLIST.md`** - **DETAILED**: Complete task breakdown by time (Quick Wins < 1h, Light 1-3h, Medium 1-2 days, Feature 3-7 days, Big 1-2 weeks)
|
||||
|
||||
### For Technical Reference
|
||||
1. `04-reference/arbre-technologique.md` - Complete tech tree
|
||||
2. `04-reference/coherence-problem.md` - Technical analyses
|
||||
@ -363,4 +415,27 @@ The project includes 16 C++ libraries via FetchContent:
|
||||
|
||||
**DEVELOPMENT WORKFLOW**: ✅ **BATTLE-TESTED** - AddressSanitizer + GDB integration for instant bug detection.
|
||||
|
||||
**Next Phase**: Integration of IUI system with core modular architecture and hot-reload capabilities.
|
||||
**CONFIGURATION SYSTEM**: ✅ **INTERFACES COMPLETE** - Comprehensive IDataTree configuration system for data-driven gameplay.
|
||||
- **GameConfig Source**: Single `gameconfig.json` file containing all game configuration and module deployment topology
|
||||
- **Hierarchical Data**: Tree structure where each node can have both children AND its own data blob
|
||||
- **Advanced Querying**: Pattern matching with wildcards, property-based lambda predicates
|
||||
- **Type-Safe Access**: Getters with defaults for int/double/string/bool properties
|
||||
- **Hash Validation**: SHA256 hashing for data integrity and synchronization
|
||||
- **Manual Hot-Reload**: Check for changes and reload on demand with callbacks
|
||||
- **Module Distribution**: gameconfig.json defines which modules to load and where to deploy them
|
||||
|
||||
## 🎯 **Current Status - INTERFACES COMPLETE & CLEAN**
|
||||
|
||||
**CORE INTERFACES**: ✅ **ALL COMPLETE** - Complete interface set with proper file organization:
|
||||
- ✅ **ICoordinationModule.h** - Global orchestrator with detailed startup/shutdown sequences
|
||||
- ✅ **ITaskScheduler.h** - **NEW FILE** with comprehensive multithreading delegation documentation
|
||||
- ✅ **IModule.h** - BREAKING CHANGES implemented with const IDataNode& configuration
|
||||
- ✅ **IDataNode.h** - All methods const for immutability enforcement
|
||||
- ✅ **IEngine.h, IModuleSystem.h, IIO.h** - Recovered and cleaned from duplications
|
||||
- ✅ **IDataTree.h, DataTreeFactory.h** - Configuration system foundation
|
||||
|
||||
**ARCHITECTURE DOCUMENTED**: ✅ **COMPLETE** - Full system flow and coordination patterns documented
|
||||
|
||||
**BREAKING CHANGES**: ✅ **IMPLEMENTED** - IModule interface modernized with configuration immutability
|
||||
|
||||
**Next Phase**: Implementation of JSONDataTree concrete classes and example gameconfig.json for testing.
|
||||
@ -37,6 +37,9 @@ FetchContent_Declare(
|
||||
|
||||
FetchContent_MakeAvailable(nlohmann_json imgui)
|
||||
|
||||
# Add GroveEngine
|
||||
add_subdirectory(../GroveEngine GroveEngine_build)
|
||||
|
||||
# Create ImGui library with OpenGL/GLFW backends
|
||||
add_library(imgui_backends
|
||||
${imgui_SOURCE_DIR}/imgui.cpp
|
||||
@ -58,16 +61,15 @@ target_link_libraries(imgui_backends PUBLIC glfw OpenGL::GL)
|
||||
# Test executable
|
||||
add_executable(test_imgui_ui
|
||||
test_imgui_ui.cpp
|
||||
src/core/src/ImGuiUI.cpp
|
||||
)
|
||||
|
||||
target_include_directories(test_imgui_ui PRIVATE
|
||||
src/core/include
|
||||
${imgui_SOURCE_DIR}
|
||||
${imgui_SOURCE_DIR}/backends
|
||||
)
|
||||
|
||||
target_link_libraries(test_imgui_ui
|
||||
GroveEngine::impl
|
||||
imgui_backends
|
||||
nlohmann_json::nlohmann_json
|
||||
glfw
|
||||
@ -84,16 +86,15 @@ set_target_properties(test_imgui_ui PROPERTIES
|
||||
# Test constraints executable
|
||||
add_executable(test_constraints
|
||||
test_constraints.cpp
|
||||
src/core/src/ImGuiUI.cpp
|
||||
)
|
||||
|
||||
target_include_directories(test_constraints PRIVATE
|
||||
src/core/include
|
||||
${imgui_SOURCE_DIR}
|
||||
${imgui_SOURCE_DIR}/backends
|
||||
)
|
||||
|
||||
target_link_libraries(test_constraints
|
||||
GroveEngine::impl
|
||||
imgui_backends
|
||||
nlohmann_json::nlohmann_json
|
||||
glfw
|
||||
|
||||
1723
TASKLIST.md
Normal file
1723
TASKLIST.md
Normal file
File diff suppressed because it is too large
Load Diff
2
TODO.md
2
TODO.md
@ -422,7 +422,7 @@
|
||||
---
|
||||
|
||||
## Notes
|
||||
- **Architecture Status**: Transitioning from 10 engines to modular system
|
||||
- **Architecture Status**: Modular system with complete interface specifications
|
||||
- **Documentation**: See `docs/01-architecture/architecture-modulaire.md` for complete specification
|
||||
- **Claude Code Optimization**: Each module = micro-context for AI development
|
||||
- **Exception**: ProductionModule (Belt+Inserter+Factory) requires 500-800 lines for performance
|
||||
|
||||
@ -1,55 +1,266 @@
|
||||
# Vue d'ensemble du projet
|
||||
# Warfactory : Vue d'Ensemble du Projet
|
||||
|
||||
## Vision et objectifs
|
||||
## Vision Globale
|
||||
|
||||
- **Concept général** : Jeu d'usine avec une composante militaire forte
|
||||
- **Inspiration** : Factorio-like avec dimension stratégique militaire
|
||||
- **Principe clé** : L'importance du choix à tous les niveaux
|
||||
- **Progression** : De PMC vers opérations conventionnelles, impact du joueur grandit avec le temps
|
||||
**Warfactory** est un RTS/4X révolutionnaire fusionnant la profondeur industrielle de Factorio avec une simulation militaire réaliste et une économie mondiale dynamique. Le projet allie l'hommage moral à l'Ukraine avec une architecture technique modulaire ultra-innovante, optimisée pour le développement assisté par IA.
|
||||
|
||||
## Philosophie de design
|
||||
**Innovation Centrale** : Un système économique où TOUS les acteurs (joueur, IA, États) suivent exactement les mêmes règles économiques, créant une simulation authentique et éducative des marchés mondiaux.
|
||||
|
||||
### Clarté et simplicité
|
||||
- Interface claire avec pictogrammes simples pour éviter la fausse complexité
|
||||
- Jeu déjà complexe nécessitant une présentation accessible
|
||||
## Concept de Jeu et Progression
|
||||
|
||||
### Aspect usine
|
||||
- La ligne d'assemblage soit le cœur
|
||||
- La doctrine militaire que le joueur s'est trouvée indique les besoins industriels
|
||||
- L'énergie c'est facile à gérer
|
||||
- L'extraction c'est facile
|
||||
### De PMC à Géant Industriel
|
||||
**Progression naturelle** :
|
||||
- **Phase PMC** : Opérations irrégulières limitées, contrats d'État
|
||||
- **Phase Industrielle** : Production civile/militaire, expansion géographique
|
||||
- **Phase Géopolitique** : Influence mondiale, doctrines militaires, crises planétaires
|
||||
|
||||
### Aspect militaire
|
||||
- Le joueur doit se trouver sa propre doctrine et créer son gameplay
|
||||
- Mettre en avant le concept de doctrine d'emploi
|
||||
- La contemplation du combat
|
||||
- IA qui donne du feedback de sa compétence ou de sa médiocrité
|
||||
- Bien que le contrôle direct soit important, il n'est pas le cœur
|
||||
**Liberté d'échelle** : Philosophie bac à sable permettant au joueur de rester artisan local ou de défier Lockheed Martin selon ses ambitions.
|
||||
|
||||
### Progression militaire
|
||||
- Dans un premier temps on se cantonner à des opérations irrégulières
|
||||
- L'impact du joueur grandit avec le temps
|
||||
### Principe "Skip vs Optimize"
|
||||
**Design fondamental** : Tous les systèmes peuvent être automatisés ou micro-gérés
|
||||
- **Skip** : Solutions automatisées, efficacité réduite mais accessibles
|
||||
- **Optimize** : Contrôle manuel complet, efficacité maximale
|
||||
- **Hybride** : Mix selon préférences et contexte
|
||||
|
||||
### Égalité économique (RÈGLE FONDAMENTALE)
|
||||
**Principe core** : Le player n'a AUCUN privilège économique artificiel
|
||||
Exemples concrets :
|
||||
- **Production** : Usines tout-en-un vs layouts Factorio optimisés
|
||||
- **Combat** : IA tactique vs commande directe
|
||||
- **Commerce** : Auto-trade vs négociation manuelle
|
||||
|
||||
- **Same rules for all** : Player, AI companies, AI states suivent EXACTEMENT les mêmes règles économiques
|
||||
- **No artificial advantages** : Aucun bonus coût, aucun discount, aucun traitement spécial
|
||||
- **Success via insight** : Réussite basée sur compréhension économique réelle, pas privilèges
|
||||
- **Educational integrity** : Players apprennent vrais principes économiques applicables
|
||||
- **Competitive fairness** : AI opponents économiquement crédibles et rationnels
|
||||
## Systèmes Industriels Intégrés
|
||||
|
||||
### Architecture Factorio-like Avancée
|
||||
**Cœur productif** :
|
||||
- **Production modulaire** : Belts, inserters, factories avec évolution progressive
|
||||
- **4 phases de complexité** : Mono → Multi-lanes → Bidirectionnel → Full Factorio
|
||||
- **Qualité d'assemblage** : Placement optimal vs automatique avec pénalités réalistes
|
||||
|
||||
**Innovation : Dual Production System** :
|
||||
- **Production brute** : Transformation ressources primaires (minerai → plaques)
|
||||
- **Assemblage précis** : Placement composants selon grilles vehicules
|
||||
|
||||
### Flexibilité de Reconversion Industrielle
|
||||
**Mécaniques réalistes** basées sur similarité des processus :
|
||||
- **Facile** : Tables fer → Blindages (même matériaux, processus similaires)
|
||||
- **Complexe** : Tables → Canons (précision usinage, alliages spéciaux)
|
||||
- **Impossible** : Menuiserie → Production hydrogène (zéro overlap technologique)
|
||||
|
||||
## Système Militaire Révolutionnaire
|
||||
|
||||
### Conception de Véhicules par Grilles
|
||||
**Innovation gameplay** : Design sur châssis irréguliers avec zones spécialisées
|
||||
|
||||
**Interface intuitive** :
|
||||
- **Pick & Place** : Drag & drop composants avec rotations A/E
|
||||
- **Snap toggle** : R pour alignement grille
|
||||
- **Validation temps réel** : Contraintes poids/énergie vérifiées durant placement
|
||||
|
||||
**Diversité massive** :
|
||||
- **Châssis nommés** : "Griffon" (chenillé), "Viper" (modulaire), "Fennec" (ultra-léger)
|
||||
- **3 layers** : Châssis → Systèmes → Armes & Capteurs
|
||||
- **1000+ composants** : Formes uniques, jamais carrées ni 1x1
|
||||
|
||||
### Système d'Amélioration Générique
|
||||
**Améliorations universelles** stackables avec rendements décroissants :
|
||||
- **High ROF** : +20% cadence, +40% chaleur (stack 1), puis +10%/+40% (stack 2)
|
||||
- **Efficiency** : -20% consommation, -15% performance
|
||||
- **Reliability** : +30% durabilité, -10% performance
|
||||
|
||||
**Coût exponentiel** : 1.25^n per stack avec malus cumulatifs linéaires
|
||||
|
||||
## Économie Mondiale Simulée
|
||||
|
||||
### Égalité Économique Fondamentale
|
||||
**RÈGLE NON-NÉGOCIABLE** : Le joueur n'a AUCUN privilège économique artificiel
|
||||
|
||||
**Implementation requirement** :
|
||||
```cpp
|
||||
// INTERDIT - Player privilege
|
||||
// INTERDIT - Avantage joueur
|
||||
if(agent.isPlayer()) order.cost *= 0.9f;
|
||||
|
||||
// OBLIGATOIRE - Equal treatment
|
||||
// OBLIGATOIRE - Traitement égal
|
||||
float cost = calculateRealTransportCost(order);
|
||||
agent.processOrder(order, cost);
|
||||
```
|
||||
|
||||
Cette règle est **NON-NÉGOCIABLE** pour l'intégrité de la simulation économique.
|
||||
**Résultat** : Réussite basée sur compréhension économique réelle, pas sur privilèges artificiels.
|
||||
|
||||
## Inspiration Undertale
|
||||
- S'inspirer d'Undertale pour la partie choix géopolitique
|
||||
### Système de Companies avec Features
|
||||
**Chaque IA company** a 2-4 features définissant ses capacités :
|
||||
- **Domaines** : Metal, Electronic, Tank, Plane, Wood, Food, Engine, Cannon, Missile
|
||||
- **Modificateurs** : Quality, Quantity, Speed, Cost, Modularity, Innovation
|
||||
|
||||
**Exemple** : Company "Metal + Plane + Quantity + Electronic" excelle en avions métalliques de masse avec électronique embarquée, mais manque raffinement vs spécialistes Quality.
|
||||
|
||||
### Transport Multi-Modal Réaliste
|
||||
**Hiérarchie des coûts** (indicative) :
|
||||
- **Maritime** : ~0.10€/kg (volume massif, ultra-économique)
|
||||
- **Ferroviaire** : ~0.50€/kg (grandes quantités, infrastructure)
|
||||
- **Aérien** : ~2.00€/kg (rapide, coûteux)
|
||||
- **Routier** : ~5.00€/kg (flexible, dernier kilomètre)
|
||||
|
||||
**Impact stratégique** : Localisation côtière = avantage économique 50x
|
||||
|
||||
### Marchés Segmentés et Restrictions
|
||||
**Types de marchés** :
|
||||
- **Nationaux** : Par pays avec politiques douanières
|
||||
- **Companies privés** : Accords bilatéraux
|
||||
- **Blocs multinationaux** : UE, OTAN avec préférences
|
||||
- **Mondial** : Marché libre avec sanctions possibles
|
||||
|
||||
**Doubles verrous** : Companies ET États peuvent bloquer accès
|
||||
|
||||
## Architecture Technique Révolutionnaire
|
||||
|
||||
### Modularité Claude Code Optimisée
|
||||
**Innovation développement** : Architecture modulaire révolutionnaire pour développement IA
|
||||
|
||||
**Contraintes strictes** :
|
||||
- **200-300 lignes max** par module (EXCEPTION : ProductionModule 500-800)
|
||||
- **Build autonome** : `cd modules/tank/ && cmake .` - zéro dépendance parent
|
||||
- **Hot-reload 0.4ms** : Modifications instantanées sans restart
|
||||
- **Développement parallèle** : 3+ instances Claude Code simultanées
|
||||
|
||||
### Interface System IMMUTABLE
|
||||
**5 interfaces fondamentales** (JAMAIS modifiées une fois finalisées) :
|
||||
```cpp
|
||||
ICoordinationModule → Orchestrateur global système
|
||||
IEngine → Coordination locale (Debug → HighPerf → DataOriented)
|
||||
IModuleSystem → Stratégie d'exécution (Sequential → Threaded → Cluster)
|
||||
IModule → Logique métier pure (TankModule.so, EconomyModule.so)
|
||||
IIO → Communication (IntraIO → LocalIO → NetworkIO)
|
||||
```
|
||||
|
||||
### Évolution Progressive Sans Régression
|
||||
```cpp
|
||||
// Phase 1 : Prototype
|
||||
DebugEngine + SequentialModuleSystem + IntraIO
|
||||
|
||||
// Phase 2 : Optimization
|
||||
DebugEngine + ThreadedModuleSystem + IntraIO
|
||||
|
||||
// Phase 3 : Production
|
||||
HighPerfEngine + MultithreadedModuleSystem + LocalIO
|
||||
|
||||
// Phase 4 : MMO Scale
|
||||
DataOrientedEngine + ClusterModuleSystem + NetworkIO
|
||||
```
|
||||
|
||||
**Avantage révolutionnaire** : Modules métier inchangés à travers toutes les phases !
|
||||
|
||||
## Carte et Exploration
|
||||
|
||||
### Architecture Multi-Échelles
|
||||
**2 niveaux discrets** :
|
||||
- **Large Map** : Carte mondiale éditable, navigation node-based
|
||||
- **Local Map** : Tiles 1m×1m, chunks 64×64, style Factorio précis
|
||||
|
||||
### Génération Procédurale par Budget de Points
|
||||
**Innovation système** : Chaque tile reçoit score (-10 à +10) équilibrant automatiquement risques/récompenses
|
||||
|
||||
**218+ éléments** avec tendances régionales :
|
||||
- **Bassins pétroliers** : Pétrole ×5 probabilité, terrains marécageux ×2
|
||||
- **Zones ex-minières** : Fer/charbon ×3-4, teritons ×8, pollution héritée ×3
|
||||
- **Régions forestières** : Forêt dense ×3-4, grottes ×2-3, pentes abruptes ×2
|
||||
|
||||
**Découverte stratifiée** :
|
||||
- **Visible** : Relief, végétation, structures surface
|
||||
- **Caché niveau 1** : Prospection géologique (gisements souterrains)
|
||||
- **Caché niveau 2** : Magnétométrie (anomalies, structures enfouies)
|
||||
- **Caché niveau 3** : Analyse NRBC (contaminations invisibles)
|
||||
|
||||
## Arbre Technologique Massif
|
||||
|
||||
### 3000+ Technologies pour Rejouabilité Infinie
|
||||
**Principe découverte** : Player ne recherche PAS toutes les technologies !
|
||||
- **Discovery organique** : Breakthrough via gameplay naturel
|
||||
- **10-50 techs éligibles** simultanément (jamais 3000)
|
||||
- **Système de passerelles** : Expertise dans un domaine débloque prototypes dans autres
|
||||
|
||||
**Exemple passerelles Châssis** :
|
||||
```
|
||||
Métallurgie Avancée → [PROTOTYPE] Châssis Composite
|
||||
Électronique → [PROTOTYPE] Châssis Smart
|
||||
Moteur → [PROTOTYPE] Châssis Performance
|
||||
```
|
||||
|
||||
## Contexte Narratif et Éthique
|
||||
|
||||
### Hommage à l'Ukraine
|
||||
**Motivation morale fondamentale** : "L'Ukraine parce qu'ils sont des héros, parce qu'ils meurent pour leur liberté et pour la nôtre."
|
||||
|
||||
**Intégration authentique** :
|
||||
- **Géographie réelle** : Ukraine, Europe sur carte mondiale
|
||||
- **Contexte historique** : Zones post-industrielles, vestiges soviétiques
|
||||
- **Enjeux géopolitiques** : Résistance démocratique vs autoritarisme
|
||||
|
||||
### Crises Endgame
|
||||
**3 scénarios apocalyptiques** avec mécaniques distinctes :
|
||||
- **Zombie Apocalypse** : Vitesse de réaction, lignes de défense
|
||||
- **Invasion ET** : Technologie supérieure aérienne, survie planétaire
|
||||
- **Demon Portal** : Portails imprévisibles, course contre extermination
|
||||
|
||||
## Interface Utilisateur Révolutionnaire
|
||||
|
||||
### Système IUI Data-Agnostic
|
||||
**Architecture générique** supportant tous types de contenu :
|
||||
- **Enums type-safe** : `DataType::ECONOMY`, `RequestType::GET_PRICES`
|
||||
- **Windowing hiérarchique** : Parent → Dock → Split → Tab → Window
|
||||
- **Hybrid Sizing System** : Cibles pourcentage avec contraintes pixels
|
||||
|
||||
**Layout professionnel** : Topbar économique + panel companies + carte stratégique + console
|
||||
|
||||
## Performance et Scalabilité
|
||||
|
||||
### Fréquences Modulaires Optimisées
|
||||
- **ProductionModule** : 60Hz (frame-perfect factory)
|
||||
- **TankModule Targeting** : 60Hz (combat réactif)
|
||||
- **TankModule Movement** : 30Hz (positions)
|
||||
- **TankModule Tactical** : 1Hz (décisions stratégiques)
|
||||
- **EconomyModule** : 0.01-0.1Hz (cycles économiques)
|
||||
|
||||
### Targets Performance
|
||||
- **V1 Client** : 30+ fps, 10+ joueurs serveur
|
||||
- **V2 Client** : 60+ fps, 100+ joueurs serveur avec prédiction locale
|
||||
|
||||
## Philosophie de Design Avancée
|
||||
|
||||
### "Complexity through Simplicity"
|
||||
**Complexité AAA** émergeant de modules simples Claude-friendly :
|
||||
- **Modules 200 lignes** = compréhension IA parfaite
|
||||
- **Interactions complexes** = gameplay émergent sophistiqué
|
||||
- **Testing granulaire** = fiabilité et débug facilités
|
||||
|
||||
### Configuration vs Modding
|
||||
**Philosophy YAGNI** : Configuration JSON couvre 90% besoins modding
|
||||
```json
|
||||
{
|
||||
"tank_mk2_custom": {
|
||||
"health": 150, "speed": 30,
|
||||
"weapons": ["cannon_105mm", "mg_coaxial"]
|
||||
},
|
||||
"aggressive_ai": {
|
||||
"engagement_range": 1000,
|
||||
"retreat_threshold": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## État Actuel et Roadmap
|
||||
|
||||
### PRODUCTION-READY Achievements
|
||||
- ✅ **Core Interfaces COMPLETE** : Architecture modulaire immutable finalisée
|
||||
- ✅ **UI System COMPLETE** : IUI + ImGuiUI avec hybrid sizing révolutionnaire
|
||||
- ✅ **Hot-Reload 0.4ms** : Workflow développement révolutionné
|
||||
- ✅ **Configuration System** : IDataTree avec validation SHA256
|
||||
- ✅ **Cross-Platform Pipeline** : Linux dev → Windows .exe automatisé
|
||||
|
||||
### Next Phases
|
||||
1. **Phase 2** : Implémentations concrètes (DebugEngine, JSONDataTree)
|
||||
2. **Phase 3** : Modules gameplay (ProductionModule, TankModule)
|
||||
3. **Phase 4** : Integration économique et multijoueur
|
||||
|
||||
## Conclusion : Une Vision Révolutionnaire
|
||||
|
||||
Warfactory transcende les genres traditionnels en unifiant industrie, stratégie militaire et simulation économique authentique dans une architecture technique révolutionnaire.
|
||||
|
||||
Le projet honore l'héroïsme ukrainien tout en repoussant les limites du développement assisté par IA, créant un gameplay émergent d'une profondeur inégalée où chaque choix - industriel, militaire, économique - résonne à travers un système interconnecté d'une complexité et d'un réalisme saisissants.
|
||||
@ -4,15 +4,17 @@
|
||||
|
||||
L'architecture modulaire Warfactory transforme le développement de jeux complexes en utilisant une approche **micro-modules** optimisée pour Claude Code. Chaque module est un micro-contexte de 200-300 lignes de logique métier pure.
|
||||
|
||||
## Triple Interface Pattern
|
||||
## Core Interface Architecture
|
||||
|
||||
### Architecture Fondamentale
|
||||
|
||||
```cpp
|
||||
IEngine → Orchestration et coordination
|
||||
IModuleSystem → Stratégies d'exécution
|
||||
IModule → Logique métier pure
|
||||
IIO → Communication et transport
|
||||
ICoordinationModule → Orchestrateur global système
|
||||
IEngine → Orchestration locale
|
||||
IModuleSystem → Stratégies d'exécution
|
||||
IModule → Logique métier pure
|
||||
IIO → Communication et transport
|
||||
ITaskScheduler → Délégation de tâches
|
||||
```
|
||||
|
||||
### IEngine - Orchestration
|
||||
|
||||
@ -8,17 +8,35 @@
|
||||
|
||||
## Architecture Système
|
||||
|
||||
### Triple Interface Pattern (Architecture Révolutionnaire)
|
||||
### Core Interface Architecture
|
||||
|
||||
**NOUVELLE ARCHITECTURE MODULAIRE** - Remplace l'ancienne architecture 10 engines par un système modulaire optimisé pour le développement avec Claude Code.
|
||||
**ARCHITECTURE MODULAIRE** - Système modulaire optimisé pour le développement avec Claude Code.
|
||||
|
||||
#### Les 4 Interfaces Fondamentales
|
||||
#### Les 5 Interfaces Fondamentales
|
||||
|
||||
```cpp
|
||||
IEngine → Coordination générale (DebugEngine → HighPerfEngine → DataOrientedEngine)
|
||||
IModuleSystem → Stratégie d'exécution (Sequential → Threaded → Multithread → Cluster)
|
||||
IModule → Logique métier pure (TankModule.so, EconomyModule.so, FactoryModule.so)
|
||||
IIO → Communication (IntraIO → LocalIO → NetworkIO)
|
||||
ICoordinationModule → Orchestrateur global système (MainServer, déploiement, config)
|
||||
IEngine → Coordination locale (DebugEngine → HighPerfEngine → DataOrientedEngine)
|
||||
IModuleSystem → Stratégie d'exécution (Sequential → Threaded → Multithread → Cluster)
|
||||
IModule → Logique métier pure (TankModule.so, EconomyModule.so, FactoryModule.so)
|
||||
IIO → Communication (IntraIO → LocalIO → NetworkIO)
|
||||
```
|
||||
|
||||
#### Architecture de Déploiement Global
|
||||
|
||||
```
|
||||
MainServer Process:
|
||||
├── CoordinationModule (Global Orchestrator)
|
||||
│ ├── Loads gameconfig.json via IDataTree
|
||||
│ ├── Manages local IEngine + modules
|
||||
│ └── Launches remote servers + engines
|
||||
├── Local IEngine (manages local modules)
|
||||
│ ├── IModuleSystem (Sequential/Threaded/etc.)
|
||||
│ └── Local Modules (.so files)
|
||||
└── Remote Servers (launched by coordination)
|
||||
├── Remote IEngine (manages remote modules)
|
||||
├── IModuleSystem (execution strategy)
|
||||
└── Remote Modules (.so files)
|
||||
```
|
||||
|
||||
#### Séparation des Responsabilités
|
||||
@ -34,12 +52,21 @@ IIO → Communication (IntraIO → LocalIO → NetworkIO)
|
||||
- MultithreadedModuleSystem : Pool de threads pour tasks
|
||||
- ClusterModuleSystem : Distribution sur plusieurs machines
|
||||
|
||||
**IModule** : Logique métier pure
|
||||
**ICoordinationModule** : Orchestrateur global système
|
||||
- Premier module lancé, dernier fermé
|
||||
- Charge gameconfig.json via IDataTree
|
||||
- Déploie modules selon topologie (local/distant)
|
||||
- Synchronise configurations entre tous les modules
|
||||
|
||||
**IModule** : Logique métier pure (BREAKING CHANGES)
|
||||
```cpp
|
||||
class IModule {
|
||||
virtual json process(const json& input) = 0; // PURE FUNCTION
|
||||
virtual void initialize(const json& config) = 0;
|
||||
virtual void setConfiguration(const IDataNode& configNode, IIO* io, ITaskScheduler* scheduler) = 0; // NEW
|
||||
virtual const IDataNode& getConfiguration() = 0; // NEW
|
||||
virtual json getHealthStatus() = 0; // NEW - detailed JSON instead of bool
|
||||
virtual void shutdown() = 0;
|
||||
// initialize() method REMOVED
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
488
docs/02-systems/CLIMATE_SIMULATION_SYSTEM.md
Normal file
488
docs/02-systems/CLIMATE_SIMULATION_SYSTEM.md
Normal file
@ -0,0 +1,488 @@
|
||||
# Climate Simulation System
|
||||
|
||||
**Status**: Designed - Ready for Implementation
|
||||
**Scope**: Realistic climate patterns through mobile wind regions and convergence zones
|
||||
**Integration**: Uses existing TectonicRegions framework
|
||||
|
||||
## System Overview
|
||||
|
||||
Revolutionary climate simulation using **mobile wind regions** that spawn, evolve, and interact to create emergent weather patterns. Solves the "Sahara vs Congo" problem through **Inter-Tropical Convergence Zones (ITCZ)** and **planetary rotation bands** without complex 3D atmospheric physics.
|
||||
|
||||
### Key Innovations
|
||||
- **Mobile WindRegions** with token-based distribution system
|
||||
- **ITCZ gravitational zones** based on continental mass
|
||||
- **Planetary rotation bands** for realistic circulation patterns
|
||||
- **Emergent storm evolution** from simple wind interactions
|
||||
- **Destruction token system** for persistent terrain effects
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### WindRegion Mobile Entities
|
||||
```json
|
||||
"wind_region": {
|
||||
"position": [x, y],
|
||||
"wind_strength": 1.0, // Base intensity (decays over time)
|
||||
"wetness": 0.0, // Moisture content (gained over ocean)
|
||||
"velocity": [vx, vy], // Movement vector
|
||||
"wind_tokens": 100, // Distributed to tiles
|
||||
"decay_per_move": 0.02, // -2% strength per movement
|
||||
"decay_per_tile": 0.01 // -1% strength per tile crossed
|
||||
}
|
||||
```
|
||||
|
||||
### ITCZ Convergence Zones
|
||||
```json
|
||||
"itcz_zone": {
|
||||
"center": [x, y],
|
||||
"gravitational_range": "sqrt(landmass_area) * 50",
|
||||
"aspiration_strength": "landmass_mass / distance^2",
|
||||
"amplification_factor": 3.0, // Wind strength multiplier at center
|
||||
"latitude_requirement": [0.45, 0.55] // Equatorial band only
|
||||
}
|
||||
```
|
||||
|
||||
## Simulation Architecture
|
||||
|
||||
### Phase 1: Landmass Analysis and ITCZ Generation
|
||||
|
||||
**Uses Existing TectonicRegions:**
|
||||
```cpp
|
||||
// Analyze continental masses from existing tectonic data
|
||||
std::vector<Continent> continents = groupTectonicRegions();
|
||||
|
||||
// Generate water masses by inverse analysis
|
||||
std::vector<WaterMass> oceans = detectOceanBasins(continents);
|
||||
|
||||
// Place ITCZ zones on qualifying equatorial landmasses
|
||||
for (auto& continent : continents) {
|
||||
if (continent.latitude >= 0.45 && continent.latitude <= 0.55 &&
|
||||
continent.area > MIN_LANDMASS_SIZE) {
|
||||
createITCZ(continent.center, sqrt(continent.area));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**ITCZ Requirements:**
|
||||
- **Latitude Band**: 45-55% of map height (equatorial)
|
||||
- **Minimum Landmass**: 10,000+ tiles
|
||||
- **Ocean Proximity**: Within 800km for moisture source
|
||||
- **Continental Heating**: Large thermal mass for convection
|
||||
|
||||
### Phase 2: WindRegion Spawning System
|
||||
|
||||
**Procedural Spawn Rules:**
|
||||
```json
|
||||
"wind_spawn_system": {
|
||||
"spawn_locations": "ocean_masses_only",
|
||||
"spawn_frequency": "water_mass_size / 1000",
|
||||
"initial_strength": "water_temperature * evaporation_factor",
|
||||
"region_size": "sqrt(water_mass_area) / 10",
|
||||
"tokens_per_region": "base_tokens * size_factor",
|
||||
"spawn_distribution": "random_within_water_region_biased_toward_center"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: WindRegions spawn aléatoirement dans le rayon de la waterRegion avec une distribution de spawn plutôt vers le centre pour éviter les spawns en bordure systématiques.
|
||||
|
||||
**Spawn Distribution:**
|
||||
- **Large Oceans** (Pacific): Big regions, high frequency
|
||||
- **Medium Seas** (Mediterranean): Medium regions, moderate frequency
|
||||
- **Small Bays**: Small regions, low frequency
|
||||
- **No Land Spawning**: All weather originates from water bodies
|
||||
|
||||
### Phase 3: Movement and Planetary Circulation
|
||||
|
||||
**Planetary Rotation Bands** (based on real 10hPa atmospheric data):
|
||||
```json
|
||||
"planetary_circulation": {
|
||||
"polar_jet_north": {
|
||||
"latitude_range": [0.10, 0.25],
|
||||
"direction": "west_to_east",
|
||||
"strength": 1.8
|
||||
},
|
||||
"calm_transition_1": {
|
||||
"latitude_range": [0.25, 0.40],
|
||||
"movement": "chaos_plus_procedural"
|
||||
},
|
||||
"equatorial_trades": {
|
||||
"latitude_range": [0.40, 0.60],
|
||||
"direction": "east_to_west",
|
||||
"strength": 1.5
|
||||
},
|
||||
"calm_transition_2": {
|
||||
"latitude_range": [0.60, 0.75],
|
||||
"movement": "chaos_plus_procedural"
|
||||
},
|
||||
"polar_jet_south": {
|
||||
"latitude_range": [0.75, 0.95],
|
||||
"direction": "west_to_east",
|
||||
"strength": 1.8
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Movement Calculation:**
|
||||
```cpp
|
||||
Vector2 movement =
|
||||
planetary_rotation_band * 0.6 + // 60% planetary circulation
|
||||
equator_to_pole_bias * 0.2 + // 20% thermal circulation
|
||||
terrain_deflection * 0.1 + // 10% topographic influence
|
||||
random_variation * 0.1; // 10% chaos
|
||||
```
|
||||
|
||||
### Phase 4: WindRegion Evolution and Interactions
|
||||
|
||||
**Dynamic Evolution:**
|
||||
```cpp
|
||||
void updateWindRegion(WindRegion& region) {
|
||||
// Gain moisture over water
|
||||
if (currentTile.isOcean()) {
|
||||
region.wetness += OCEAN_MOISTURE_GAIN;
|
||||
}
|
||||
|
||||
// Repulsion from other regions = acceleration
|
||||
// NOTE: Not physical repulsion - proxy for spatial competition and turbulence
|
||||
// Prevents region stacking while creating realistic dispersion patterns
|
||||
// CRITIQUE POINT: May cause "force field" effect around ITCZ zones where regions
|
||||
// oscillate/scatter instead of converging due to attraction vs repulsion conflict.
|
||||
// Alternative approaches: density-based drift, no interaction, or collision division.
|
||||
// TODO: Implement as configurable algorithm options for empirical testing.
|
||||
float repulsion = calculateRepulsionForce(region, nearbyRegions);
|
||||
region.wind_strength += repulsion * ACCELERATION_FACTOR;
|
||||
|
||||
// Movement decay
|
||||
region.wind_strength *= (1.0 - DECAY_PER_MOVE);
|
||||
|
||||
// Tile crossing cost
|
||||
region.wind_strength *= (1.0 - DECAY_PER_TILE);
|
||||
|
||||
// Die when too weak
|
||||
if (region.wind_strength < MINIMUM_THRESHOLD) {
|
||||
destroyRegion(region);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**ITCZ Gravitational Effects:**
|
||||
```cpp
|
||||
void applyITCZGravity(WindRegion& region) {
|
||||
for (auto& itcz : active_itcz_zones) {
|
||||
float distance = calculateDistance(region.position, itcz.center);
|
||||
|
||||
if (distance < itcz.gravitational_range) {
|
||||
// Attraction force (inverse square law)
|
||||
// NOTE: "Gravitational" metaphor for influence strength, not literal physics
|
||||
// Like saying someone has "gravitas" - clear semantic meaning for developers
|
||||
float attraction = itcz.mass / (distance * distance);
|
||||
Vector2 pull_direction = normalize(itcz.center - region.position);
|
||||
|
||||
// Apply attraction
|
||||
region.velocity += pull_direction * attraction;
|
||||
|
||||
// Amplification effect as region approaches
|
||||
float proximity = (itcz.range - distance) / itcz.range;
|
||||
float amplification = 1.0 + (itcz.max_amplification * proximity);
|
||||
|
||||
region.wind_strength *= amplification;
|
||||
region.wetness *= amplification;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 5: Storm Classification and Token Distribution
|
||||
|
||||
**Climate Zone Classification:**
|
||||
```cpp
|
||||
// Simple thresholds for climate zone determination
|
||||
const float HIGH_WIND_THRESHOLD = 2.0;
|
||||
const float FLOOD_THRESHOLD = 1.5;
|
||||
const float HURRICANE_WIND = 2.5;
|
||||
const float HURRICANE_RAIN = 2.0;
|
||||
|
||||
bool isHighWindZone(const WindRegion& region) {
|
||||
return region.wind_strength >= HIGH_WIND_THRESHOLD;
|
||||
}
|
||||
|
||||
bool isFloodZone(const WindRegion& region) {
|
||||
return region.wetness >= FLOOD_THRESHOLD;
|
||||
}
|
||||
|
||||
bool isHurricaneZone(const WindRegion& region) {
|
||||
return region.wind_strength >= HURRICANE_WIND && region.wetness >= HURRICANE_RAIN;
|
||||
}
|
||||
```
|
||||
|
||||
**Token Distribution System:**
|
||||
```cpp
|
||||
void distributeTokens(WindRegion& region) {
|
||||
// Basic climate tokens for all regions
|
||||
int wind_tokens = static_cast<int>(region.wind_strength * 10);
|
||||
int rain_tokens = static_cast<int>(region.wetness * 10);
|
||||
|
||||
WorldTile& tile = world_map.getTile(region.position);
|
||||
tile.addTokens("wind", wind_tokens);
|
||||
tile.addTokens("rain", rain_tokens);
|
||||
|
||||
// Special climate zone tokens for extreme weather
|
||||
if (isHighWindZone(region)) {
|
||||
tile.addTokens("highWind", 1); // Hostile to forests
|
||||
}
|
||||
if (isFloodZone(region)) {
|
||||
tile.addTokens("flood", 1); // Forces wetlands/marshes
|
||||
}
|
||||
if (isHurricaneZone(region)) {
|
||||
tile.addTokens("hurricane", 1); // Specialized hurricane biome
|
||||
}
|
||||
|
||||
// Consume distributed tokens from region
|
||||
region.wind_tokens -= wind_tokens;
|
||||
region.rain_tokens -= rain_tokens;
|
||||
}
|
||||
```
|
||||
|
||||
## Geographic Climate Patterns
|
||||
|
||||
### Realistic Climate Formation
|
||||
|
||||
**Congo Basin (Rainforest):**
|
||||
```
|
||||
1. Large African landmass → Strong ITCZ at equator
|
||||
2. Atlantic wind regions spawn → Move east via trade winds
|
||||
3. ITCZ aspiration → Convergence at Congo → Amplification ×3
|
||||
4. Super-humid storms → Massive rain token distribution
|
||||
5. Result: Dense rainforest biome
|
||||
```
|
||||
|
||||
**Sahara Desert:**
|
||||
```
|
||||
1. Sahara latitude (25-35°N) → Outside ITCZ band
|
||||
2. No convergence zone → Wind regions pass through
|
||||
3. Continental distance → Low initial moisture
|
||||
4. Subtropical high pressure → Air descends (simulated via movement patterns)
|
||||
5. Result: Minimal rain tokens → Desert biome
|
||||
```
|
||||
|
||||
**Egypt/Algeria Coastal:**
|
||||
```
|
||||
1. Mediterranean wind regions → Moderate moisture
|
||||
2. Coastal proximity → Some rain tokens
|
||||
3. Sahara interior → Moisture depleted inland
|
||||
4. Result: Mediterranean coastal climate → Desert interior gradient
|
||||
```
|
||||
|
||||
### Emergent Seasonal Patterns
|
||||
|
||||
**ITCZ Strength Variation:**
|
||||
```json
|
||||
"seasonal_modulation": {
|
||||
"itcz_strength_summer": 1.5, // Stronger convection
|
||||
"itcz_strength_winter": 0.8, // Weaker convection
|
||||
"spawn_rate_summer": 1.3, // More wind regions
|
||||
"spawn_rate_winter": 0.7 // Fewer wind regions
|
||||
}
|
||||
```
|
||||
|
||||
**Results:**
|
||||
- **Monsoon Seasons**: ITCZ amplification cycles
|
||||
- **Hurricane Seasons**: Increased spawn rates + ITCZ amplification
|
||||
- **Dry Seasons**: Reduced ITCZ strength + lower spawn rates
|
||||
|
||||
## Climate Zone Effects on Biome Generation
|
||||
|
||||
### Token-Based Biome Classification
|
||||
|
||||
**Climate Token Usage:**
|
||||
```cpp
|
||||
BiomeType classifyBiome(const WorldTile& tile) {
|
||||
int total_rain = tile.getAccumulatedTokens("rain");
|
||||
int total_wind = tile.getAccumulatedTokens("wind");
|
||||
int highWind_tokens = tile.getAccumulatedTokens("highWind");
|
||||
int flood_tokens = tile.getAccumulatedTokens("flood");
|
||||
int hurricane_tokens = tile.getAccumulatedTokens("hurricane");
|
||||
|
||||
// Special climate zones override normal biome classification
|
||||
if (hurricane_tokens > 0) {
|
||||
return BiomeType::HURRICANE_ZONE; // Specialized storm-resistant vegetation
|
||||
}
|
||||
if (flood_tokens > FLOOD_THRESHOLD) {
|
||||
return BiomeType::WETLANDS; // Forced marshes/swamps
|
||||
}
|
||||
if (highWind_tokens > STORM_THRESHOLD) {
|
||||
// High wind prevents forest growth
|
||||
if (total_rain > 300) {
|
||||
return BiomeType::STORM_PRAIRIE; // Grasslands that can handle wind
|
||||
} else {
|
||||
return BiomeType::BADLANDS; // Sparse, wind-resistant vegetation
|
||||
}
|
||||
}
|
||||
|
||||
// Normal biome classification using basic rain/wind tokens
|
||||
if (total_rain > 500) {
|
||||
return BiomeType::TROPICAL_RAINFOREST;
|
||||
} else if (total_rain < 50) {
|
||||
return BiomeType::HOT_DESERT;
|
||||
}
|
||||
// ... additional normal biome logic
|
||||
}
|
||||
```
|
||||
|
||||
**Climate Zone Characteristics:**
|
||||
- **Hurricane Zones** → Storm-resistant palms, specialized coastal vegetation
|
||||
- **Flood Zones** → Wetlands, marshes, swamp vegetation mandatory
|
||||
- **High Wind Zones** → No forests allowed, prairie/badlands only
|
||||
- **Normal Zones** → Standard biome classification by rain/temperature
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
### Computational Complexity
|
||||
- **Wind Regions**: O(n) for n active regions (~50-200 simultaneously)
|
||||
- **ITCZ Calculations**: O(m) for m convergence zones (~5-15 globally)
|
||||
- **Token Distribution**: O(tiles_visited) per region movement
|
||||
- **Total per cycle**: O(n × average_movement_distance)
|
||||
|
||||
### Memory Usage
|
||||
- **WindRegion**: 32 bytes per region
|
||||
- **ITCZ Zone**: 24 bytes per zone
|
||||
- **Token accumulation**: Uses existing tile data structure
|
||||
- **Estimated total**: <5MB for global weather simulation
|
||||
|
||||
### Generation Time
|
||||
- **Landmass analysis**: 1-2 seconds (one-time setup)
|
||||
- **Per simulation cycle**: 10-50ms for 100-200 wind regions
|
||||
- **Full climate stabilization**: 100-500 cycles → 10-30 seconds total
|
||||
|
||||
## Integration with Existing Systems
|
||||
|
||||
### TectonicRegions Reuse
|
||||
```cpp
|
||||
// Leverage existing tectonic analysis
|
||||
class ClimateSystem {
|
||||
void initializeFromTectonics(const std::vector<TectonicRegion>& regions) {
|
||||
auto continents = groupRegionsByProximity(regions);
|
||||
auto oceans = calculateOceanBasins(continents);
|
||||
|
||||
generateITCZFromContinents(continents);
|
||||
setupWindSpawnFromOceans(oceans);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### RegionalInfluence Framework
|
||||
```cpp
|
||||
// Wind regions as mobile regional influences
|
||||
class WindRegion : public RegionalInfluence {
|
||||
void applyInfluenceToTile(WorldTile& tile) override {
|
||||
distributeTokens(tile);
|
||||
|
||||
// Create regional influence for persistent effects
|
||||
if (isStormLevel()) {
|
||||
createPersistentInfluence(tile, getStormType());
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Biome Generation Integration
|
||||
```cpp
|
||||
// Use accumulated climate tokens for biome classification
|
||||
BiomeType classifyBiome(const WorldTile& tile) {
|
||||
int total_rain = tile.getAccumulatedTokens("rain");
|
||||
int total_wind = tile.getAccumulatedTokens("wind");
|
||||
float temperature = tile.getTemperature();
|
||||
|
||||
if (total_rain > 500 && temperature > 20.0f) {
|
||||
return BiomeType::TROPICAL_RAINFOREST;
|
||||
} else if (total_rain < 50 && temperature > 15.0f) {
|
||||
return BiomeType::HOT_DESERT;
|
||||
}
|
||||
// ... additional biome logic
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
### Phase 1: Core Framework (1-2 weeks)
|
||||
1. WindRegion class and basic movement
|
||||
2. Token distribution system
|
||||
3. Simple spawn from ocean detection
|
||||
4. Basic planetary circulation bands
|
||||
|
||||
### Phase 2: ITCZ System (1-2 weeks)
|
||||
1. Landmass analysis from TectonicRegions
|
||||
2. ITCZ generation and gravitational effects
|
||||
3. Wind region amplification mechanics
|
||||
4. Storm classification system
|
||||
|
||||
### Phase 3: Advanced Features (1-2 weeks)
|
||||
1. Destruction token system and persistent effects
|
||||
2. Seasonal variation and modulation
|
||||
3. Performance optimization
|
||||
4. Integration with biome generation
|
||||
|
||||
### Phase 4: Tuning and Validation (1 week)
|
||||
1. Parameter adjustment for realistic patterns
|
||||
2. Verification of Congo/Sahara differentiation
|
||||
3. Performance profiling and optimization
|
||||
4. Documentation and examples
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```json
|
||||
{
|
||||
"climate_simulation": {
|
||||
"wind_spawn_system": {
|
||||
"base_spawn_rate": 0.1,
|
||||
"ocean_size_factor": 0.001,
|
||||
"max_concurrent_regions": 200
|
||||
},
|
||||
"planetary_circulation": {
|
||||
"trade_winds_strength": 1.5,
|
||||
"jet_stream_strength": 1.8,
|
||||
"calm_zone_chaos": 0.3
|
||||
},
|
||||
"itcz_system": {
|
||||
"latitude_band": [0.45, 0.55],
|
||||
"min_landmass_size": 10000,
|
||||
"max_ocean_distance": 800,
|
||||
"amplification_max": 3.0
|
||||
},
|
||||
"storm_thresholds": {
|
||||
"high_wind_min": 2.0,
|
||||
"flood_wetness_min": 1.5,
|
||||
"hurricane_wind_min": 2.5,
|
||||
"hurricane_rain_min": 2.0
|
||||
},
|
||||
"token_distribution": {
|
||||
"wind_token_factor": 10,
|
||||
"rain_token_factor": 10,
|
||||
"climate_zone_rate": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: All parameters are hot-reloadable via the modular configuration system. Magic numbers are intentionally externalizable for real-time tuning during development - adjust values, save config, see immediate results without recompilation.
|
||||
```
|
||||
|
||||
## Scientific Accuracy vs Gameplay
|
||||
|
||||
### Scientifically Inspired Elements
|
||||
- ✅ ITCZ formation from continental heating
|
||||
- ✅ Planetary circulation bands (trade winds, jet streams)
|
||||
- ✅ Storm formation from wind-moisture interaction
|
||||
- ✅ Geographic influence on climate patterns
|
||||
- ✅ Persistent landscape effects from weather
|
||||
|
||||
### Gameplay Simplifications
|
||||
- ⚠️ 2D simulation instead of 3D atmospheric layers
|
||||
- ⚠️ Simplified storm evolution (no pressure systems)
|
||||
- ⚠️ Discrete token system instead of continuous fields
|
||||
- ⚠️ Accelerated timeframes for practical simulation
|
||||
|
||||
### Result
|
||||
**Plausible climate science** that creates **engaging gameplay** with **emergent complexity** from **simple, understandable rules**.
|
||||
|
||||
---
|
||||
|
||||
**Status**: System designed and ready for implementation. Provides realistic climate differentiation (Sahara vs Congo) through elegant mobile region simulation using existing tectonic framework.
|
||||
1886
docs/02-systems/GEOLOGICAL_SIMULATION_SYSTEM.md
Normal file
1886
docs/02-systems/GEOLOGICAL_SIMULATION_SYSTEM.md
Normal file
File diff suppressed because it is too large
Load Diff
419
docs/02-systems/message-communication-system.md
Normal file
419
docs/02-systems/message-communication-system.md
Normal file
@ -0,0 +1,419 @@
|
||||
# Message Communication System
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Le système de communication inter-modules utilise des **classes de messages typées** au lieu de JSON brut pour garantir la fiabilité et la maintenabilité.
|
||||
|
||||
## Concept fondamental
|
||||
|
||||
**Une classe = un type de message**
|
||||
**Une instance = un message individuel**
|
||||
|
||||
Exemple: La classe `TankMovedMessage` définit le type "mouvement de tank". Chaque fois qu'un tank bouge, on crée une nouvelle instance de cette classe.
|
||||
|
||||
## Pourquoi des classes?
|
||||
|
||||
### Problème avec JSON brut
|
||||
- Erreurs découvertes uniquement au runtime
|
||||
- Pas de validation automatique
|
||||
- Typos dans les clés non détectées
|
||||
- Difficile à maintenir et refactoriser
|
||||
|
||||
### Solution avec classes
|
||||
- Validation au compile-time
|
||||
- Contrat clair entre modules
|
||||
- IDE autocomplétion et refactoring
|
||||
- Hot-reload friendly (petites classes isolées)
|
||||
- Évolutif (ajout de champs sans casser l'existant)
|
||||
|
||||
## Architecture
|
||||
|
||||
### IMessage - Interface de base
|
||||
|
||||
Interface pure définissant le contrat minimal pour tous les messages:
|
||||
|
||||
- **Type identification**: Chaque message déclare son type via enum
|
||||
- **Serialization**: Conversion vers JSON pour transport via IIO
|
||||
- **Deserialization**: Reconstruction depuis JSON reçu
|
||||
|
||||
### AMessage - Classe abstraite avec métadata
|
||||
|
||||
Classe abstraite obligatoire fournissant l'implémentation partielle commune à tous les messages.
|
||||
|
||||
**Métadata immutables (enforced):**
|
||||
- `timestamp` - Horodatage de création (const)
|
||||
- `sender` - Module émetteur (const)
|
||||
- `messageId` - ID unique pour tracking et reassemblage fragments (const)
|
||||
- `partId` - ID de fragment pour messages multi-parts (const)
|
||||
|
||||
**Caractéristiques:**
|
||||
- Constructeur protégé force passage par classes enfants
|
||||
- Métadata initialisées automatiquement à la construction
|
||||
- Impossible de modifier métadata après création
|
||||
- Tous messages garantis d'avoir timestamp/sender/messageId
|
||||
|
||||
### MessageType - Enum central
|
||||
|
||||
Enum listant tous les types de messages du système:
|
||||
- `TANK_MOVED`, `TANK_FIRED`, `TANK_DESTROYED`
|
||||
- `PRICE_UPDATED`, `TRADE_EXECUTED`
|
||||
- `ITEM_PRODUCED`, `BELT_CONGESTION`
|
||||
- etc.
|
||||
|
||||
**Pourquoi enum plutôt que strings?**
|
||||
- Performance (comparaison d'entiers)
|
||||
- Type safety (typos détectées au compile)
|
||||
- Centralisation (tous les types visibles)
|
||||
|
||||
### Messages concrets
|
||||
|
||||
Chaque type de message est une classe dédiée héritant de `AMessage`:
|
||||
|
||||
**TankMovedMessage**: Position, vitesse, ID tank
|
||||
**PriceUpdatedMessage**: Item, ancien prix, nouveau prix
|
||||
**ItemProducedMessage**: Item type, quantité, factory ID
|
||||
|
||||
Chaque classe:
|
||||
- Hérite obligatoirement de `AMessage`
|
||||
- Appelle constructeur `AMessage(senderModule)`
|
||||
- Stocke ses données spécifiques
|
||||
- Valide à la construction
|
||||
- Sérialise/désérialise son propre format
|
||||
|
||||
## Flow de communication
|
||||
|
||||
### Publication
|
||||
|
||||
**Exemple complet:**
|
||||
```cpp
|
||||
void TankModule::process(const json& input) {
|
||||
// 1. Calculer nouvelle position
|
||||
Vector2 newPos = calculatePosition();
|
||||
float currentSpeed = getSpeed();
|
||||
|
||||
// 2. Créer message (validation automatique à la construction)
|
||||
TankMovedMessage msg(newPos, currentSpeed, tankId);
|
||||
|
||||
// 3. Sérialiser en JSON
|
||||
json serialized = msg.serialize();
|
||||
|
||||
// 4. Publier via IIO
|
||||
io->publish("tank:" + std::to_string(tankId), serialized);
|
||||
}
|
||||
```
|
||||
|
||||
**Étapes:**
|
||||
1. Module crée instance de message (validation à la construction)
|
||||
2. Message sérialisé en JSON via `serialize()`
|
||||
3. Publié via `IIO::publish(topic, json)`
|
||||
4. IIO route vers subscribers du topic
|
||||
|
||||
### Réception
|
||||
|
||||
**Méthode 1: Type-safe template helper (recommandé)**
|
||||
```cpp
|
||||
// Clean syntax avec type safety automatique
|
||||
auto tankMsg = io->pullMessageAs<TankMovedMessage>();
|
||||
|
||||
if (tankMsg) { // nullptr si type mismatch ou queue vide
|
||||
Vector2 pos = tankMsg->getPosition();
|
||||
float speed = tankMsg->getSpeed();
|
||||
}
|
||||
```
|
||||
|
||||
**Méthode 2: Manuelle (si besoin de flexibilité)**
|
||||
```cpp
|
||||
// Récupère message brut
|
||||
Message rawMsg = io->pullMessage();
|
||||
|
||||
// Désérialise vers base
|
||||
std::unique_ptr<IMessage> baseMsg = IMessage::deserialize(rawMsg.data);
|
||||
|
||||
// Cast vers type concret
|
||||
if (TankMovedMessage* tankMsg = dynamic_cast<TankMovedMessage*>(baseMsg.get())) {
|
||||
// Accès type-safe
|
||||
}
|
||||
```
|
||||
|
||||
**Template helper implementation:**
|
||||
```cpp
|
||||
class IIO {
|
||||
// Template helper inline (zero overhead)
|
||||
template<typename T>
|
||||
std::unique_ptr<T> pullMessageAs() {
|
||||
if (!hasMessages()) return nullptr;
|
||||
|
||||
Message raw = pullMessage();
|
||||
std::unique_ptr<IMessage> base = IMessage::deserialize(raw.data);
|
||||
|
||||
T* casted = dynamic_cast<T*>(base.get());
|
||||
if (!casted) return nullptr; // Type mismatch
|
||||
|
||||
base.release();
|
||||
return std::unique_ptr<T>(casted);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Performance:**
|
||||
- Template inlined = zero function call overhead
|
||||
- `dynamic_cast` = ~5-10ns (négligeable vs JSON parsing)
|
||||
- Bottleneck réel = JSON serialization, pas le cast
|
||||
|
||||
### Désérialisation centralisée
|
||||
|
||||
**Factory pattern avec routing par type:**
|
||||
```cpp
|
||||
// IMessage base class
|
||||
std::unique_ptr<IMessage> IMessage::deserialize(const json& data) {
|
||||
// Extract type from JSON
|
||||
int typeInt = data.value("type", -1);
|
||||
MessageType type = static_cast<MessageType>(typeInt);
|
||||
|
||||
// Route to concrete deserializer
|
||||
switch (type) {
|
||||
case MessageType::TANK_MOVED:
|
||||
return TankMovedMessage::deserialize(data);
|
||||
|
||||
case MessageType::PRICE_UPDATED:
|
||||
return PriceUpdatedMessage::deserialize(data);
|
||||
|
||||
case MessageType::ITEM_PRODUCED:
|
||||
return ItemProducedMessage::deserialize(data);
|
||||
|
||||
// Add new messages here
|
||||
|
||||
default:
|
||||
return nullptr; // Unknown type
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Chaque message implémente sa propre désérialisation:**
|
||||
```cpp
|
||||
class TankMovedMessage : public AMessage {
|
||||
static std::unique_ptr<TankMovedMessage> deserialize(const json& data) {
|
||||
try {
|
||||
Vector2 pos{data["position"]["x"], data["position"]["y"]};
|
||||
float speed = data["speed"];
|
||||
int tankId = data["tankId"];
|
||||
|
||||
return std::make_unique<TankMovedMessage>(pos, speed, tankId);
|
||||
} catch (const json::exception& e) {
|
||||
return nullptr; // Malformed JSON
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Gestion des erreurs:**
|
||||
- JSON malformé → retourne `nullptr`
|
||||
- Type inconnu → retourne `nullptr`
|
||||
- Validation échoue → exception à la construction
|
||||
- Modules doivent vérifier `if (msg != nullptr)`
|
||||
|
||||
## Organisation du code
|
||||
|
||||
### Location des messages
|
||||
```
|
||||
modules/shared/messages/
|
||||
├── IMessage.h # Interface pure
|
||||
├── AMessage.h # Classe abstraite avec métadata
|
||||
├── MessageType.h # Enum des types
|
||||
├── TankMovedMessage.h
|
||||
├── PriceUpdatedMessage.h
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- Single source of truth (pas de duplication)
|
||||
- Contrat partagé entre émetteur et récepteur
|
||||
- Facile à trouver et maintenir
|
||||
|
||||
### Validation
|
||||
|
||||
**À la construction**: Invariants validés immédiatement
|
||||
- Vitesse négative → exception
|
||||
- ID invalide → exception
|
||||
- Fail fast pour détecter bugs tôt
|
||||
|
||||
**À la désérialisation**: Données réseau/externes validées
|
||||
- JSON malformé → retourne nullptr
|
||||
- Champs manquants → retourne nullptr
|
||||
- Protège contre données corrompues
|
||||
|
||||
## Décisions de design finalisées
|
||||
|
||||
### Versioning - Breaking changes assumées
|
||||
|
||||
**Décision:** Types versionnés avec breaking changes strictes
|
||||
|
||||
Changement de format = nouveau type + nouvelle classe:
|
||||
- `TANK_MOVED_V1` → `TANK_MOVED_V2` = types différents
|
||||
- Pas de backward compatibility
|
||||
- Pas de forward compatibility
|
||||
- Migration forcée de tous les modules
|
||||
|
||||
**Rationale:**
|
||||
- Zéro ambiguïté sur le format attendu
|
||||
- Pas de logique conditionnelle complexe
|
||||
- Hot-reload force mise à jour synchronisée
|
||||
- Détection immédiate des incompatibilités
|
||||
- Code simple et clair
|
||||
|
||||
**Conséquence:**
|
||||
- Format change → tous modules doivent migrer
|
||||
- Ancien code ne compile plus → migration manuelle obligatoire
|
||||
- Breaking changes explicites et visibles
|
||||
|
||||
### Message inheritance - AMessage obligatoire
|
||||
|
||||
**Décision:** Classe abstraite `AMessage` avec métadata immutables enforced
|
||||
|
||||
Architecture:
|
||||
```
|
||||
IMessage (interface pure)
|
||||
↓
|
||||
AMessage (classe abstraite - métadata immutables)
|
||||
↓
|
||||
TankMovedMessage, PriceUpdatedMessage... (classes concrètes)
|
||||
```
|
||||
|
||||
**Enforcement:**
|
||||
- Constructeur `AMessage` protégé → impossible de créer message sans passer par enfant
|
||||
- Métadata const → immutables après construction
|
||||
- Tous messages garantis d'avoir timestamp/sender/messageId
|
||||
- Format uniforme pour tous messages du système
|
||||
|
||||
**Rationale:**
|
||||
- Pas de duplication (métadata dans AMessage)
|
||||
- Impossible d'oublier métadata
|
||||
- Contrat strict et enforced au compile-time
|
||||
- Simplicité pour messages concrets (métadata automatique)
|
||||
|
||||
## Décisions de design finalisées (suite)
|
||||
|
||||
### Size limits - Fragmentation automatique par IO
|
||||
|
||||
**Décision:** Pas de limite au niveau message, fragmentation automatique par couche transport
|
||||
|
||||
**Architecture:**
|
||||
- **Modules**: Publient/reçoivent messages complets (transparence totale)
|
||||
- **IIO**: Gère fragmentation/défragmentation automatiquement
|
||||
- **Transport adaptatif**: Fragmentation si nécessaire selon type IO
|
||||
|
||||
**Fragmentation par type:**
|
||||
- **IntraIO**: Pas de fragmentation (copie mémoire directe)
|
||||
- **LocalIO**: Fragmentation si > seuil (ex: 64KB chunks)
|
||||
- **NetworkIO**: Fragmentation si > MTU (~1500 bytes)
|
||||
|
||||
**Mécanisme:**
|
||||
1. Module publie message → sérialisé en JSON
|
||||
2. IO détecte si taille > seuil transport
|
||||
3. Si oui: découpe en fragments avec `messageId` + `partId`
|
||||
4. Transport des fragments
|
||||
5. IO destination reassemble via `messageId` (collect tous `partId`)
|
||||
6. Module reçoit message complet via `pullMessage()`
|
||||
|
||||
**Robustesse:**
|
||||
- **Packet loss**: Timeout si fragments incomplets (ex: 30s)
|
||||
- **Ordering**: `partId` garantit ordre de reassemblage
|
||||
- **Monitoring**: Log warning si message > 100KB (design smell probable)
|
||||
|
||||
**Conséquence:**
|
||||
- Messages peuvent être arbitrairement gros
|
||||
- Complexité cachée dans couche IO
|
||||
- Performance optimisée par type de transport
|
||||
|
||||
### Async handling - Délégation au module
|
||||
|
||||
**Décision:** Pas de gestion async spéciale au niveau messages
|
||||
|
||||
**Rationale:**
|
||||
- Messages = transport de données uniquement
|
||||
- `ITaskScheduler` existe déjà pour opérations coûteuses
|
||||
- Module décide si déléguer ou traiter directement
|
||||
- Keep messages simple et stupid
|
||||
|
||||
**Responsabilité:**
|
||||
- **Message**: Transport de données (aucune intelligence)
|
||||
- **Module**: Décide de déléguer opérations coûteuses au scheduler
|
||||
- **ITaskScheduler**: Gère threading et async
|
||||
|
||||
**Exemple:**
|
||||
```cpp
|
||||
// Module reçoit message déclenchant opération coûteuse
|
||||
if (PathfindingRequestMessage* req = dynamic_cast<...>) {
|
||||
// Module délègue au TaskScheduler
|
||||
scheduler->scheduleTask(PATHFINDING_TASK, req->serialize());
|
||||
// Continue traitement autres messages
|
||||
}
|
||||
|
||||
// Plus tard, récupère résultat
|
||||
if (scheduler->hasCompletedTasks() > 0) {
|
||||
TaskResult result = scheduler->getCompletedTask();
|
||||
// Publie résultat via message
|
||||
}
|
||||
```
|
||||
|
||||
### Message ordering - Pas de garantie + Messages remplaçables
|
||||
|
||||
**Décision:** Pas de garantie d'ordre, modules gèrent via timestamp si critique
|
||||
|
||||
**Approche:**
|
||||
- **Pas de FIFO enforced**: Messages peuvent arriver dans ordre arbitraire
|
||||
- **Messages remplaçables par défaut**: `SubscriptionConfig.replaceable = true` pour majorité
|
||||
- **Timestamp disponible**: `msg->getTimestamp()` permet tri manuel si nécessaire
|
||||
- **Utilité questionnable**: Architecture modulaire rend ordre moins critique
|
||||
|
||||
**Rationale:**
|
||||
- Performance maximale (pas de garanties coûteuses)
|
||||
- Messages remplaçables optimisent bandwidth (garde juste dernier)
|
||||
- Timestamp dans `AMessage` permet tri si vraiment nécessaire
|
||||
- Architecture découple les dépendances temporelles
|
||||
|
||||
**Exemples d'usage:**
|
||||
```cpp
|
||||
// Prix - remplaçable (dernière valeur suffit)
|
||||
io->subscribeLowFreq("economy:*", {.replaceable = true});
|
||||
|
||||
// Tank position - remplaçable (position actuelle suffit)
|
||||
io->subscribe("tank:*", {.replaceable = true});
|
||||
|
||||
// Events critiques - non remplaçable + tri si nécessaire
|
||||
io->subscribe("combat:*", {.replaceable = false});
|
||||
|
||||
// Si ordre vraiment critique (rare)
|
||||
std::vector<Message> messages = collectAllMessages();
|
||||
std::sort(messages.begin(), messages.end(),
|
||||
[](const Message& a, const Message& b) {
|
||||
return a.getTimestamp() < b.getTimestamp();
|
||||
});
|
||||
```
|
||||
|
||||
**Conséquence:**
|
||||
- Modules ne doivent pas assumer ordre de réception
|
||||
- Messages remplaçables = dernière valeur seulement
|
||||
- Tri par timestamp disponible mais rarement nécessaire
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Aucune question ouverte restante. Toutes les décisions de design ont été finalisées.
|
||||
|
||||
## Statut d'implémentation
|
||||
|
||||
**Phase actuelle:** Design et documentation
|
||||
|
||||
**Prochaines étapes:**
|
||||
1. Créer interface `IMessage.h`
|
||||
2. Créer classe abstraite `AMessage.h` avec métadata immutables
|
||||
3. Créer enum `MessageType.h`
|
||||
4. Implémenter 5-10 messages d'exemple
|
||||
5. Tester avec modules existants
|
||||
6. Itérer selon usage réel
|
||||
|
||||
## Références
|
||||
|
||||
- `src/core/include/warfactory/IIO.h` - Couche pub/sub
|
||||
- `docs/01-architecture/architecture-technique.md` - Patterns de communication
|
||||
- `docs/03-implementation/CLAUDE-HOT-RELOAD-GUIDE.md` - Impact sur design messages
|
||||
2233
docs/02-systems/pathfinding-system.md
Normal file
2233
docs/02-systems/pathfinding-system.md
Normal file
File diff suppressed because it is too large
Load Diff
516
docs/02-systems/rendering-system.md
Normal file
516
docs/02-systems/rendering-system.md
Normal file
@ -0,0 +1,516 @@
|
||||
# Rendering System - Sprite Composition
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Le système de rendu graphique de Warfactory utilise une approche de **composition de sprites** inspirée de Rimworld, optimisée pour minimiser le nombre de sprites à dessiner tout en permettant une grande flexibilité visuelle.
|
||||
|
||||
**Principe fondamental** : Chaque entité est composée de sprites superposés avec des orientations indépendantes, permettant un rendu dynamique efficace.
|
||||
|
||||
## Architecture de composition
|
||||
|
||||
### Personnages (Humains)
|
||||
|
||||
Un personnage est composé de **3 sprites maximum** :
|
||||
|
||||
```
|
||||
Personnage
|
||||
├── Corps (sprite de base + vêtements composés)
|
||||
├── Tête (orientation indépendante - turret behavior)
|
||||
└── Arme (orientation indépendante - turret behavior)
|
||||
```
|
||||
|
||||
**Optimisation clé** : Les vêtements sont pré-composés avec le corps pour éviter de dessiner chaque couche de vêtement séparément.
|
||||
|
||||
#### Exemple de composition
|
||||
```
|
||||
Rendu final = Corps_Base + Veste + Pantalon + Tête + Arme
|
||||
└─────────────────────┘
|
||||
1 sprite composé
|
||||
```
|
||||
|
||||
Au lieu de dessiner 5 sprites par personnage, on en dessine **3** :
|
||||
- 1 sprite corps composé (avec tous les vêtements)
|
||||
- 1 sprite tête
|
||||
- 1 sprite arme
|
||||
|
||||
### Véhicules
|
||||
|
||||
Un véhicule suit le même principe avec un nombre variable de tourelles :
|
||||
|
||||
```
|
||||
Véhicule
|
||||
├── Corps (sprite fixe avec orientation principale)
|
||||
└── Tourelles[] (orientations indépendantes)
|
||||
├── Tourelle principale
|
||||
├── Tourelle secondaire (optionnelle)
|
||||
└── Tourelle tertiaire (optionnelle)
|
||||
```
|
||||
|
||||
**Exemple** :
|
||||
- Tank léger : Corps + 1 tourelle = **2 sprites**
|
||||
- APC : Corps + 1 tourelle principale + 1 mitrailleuse = **3 sprites**
|
||||
- Véhicule lourd : Corps + 3 tourelles = **4 sprites**
|
||||
|
||||
## Pipeline unifiée : Concept Fixe/Mobile
|
||||
|
||||
Le système distingue deux types de composants :
|
||||
|
||||
### 1. Composants Fixes
|
||||
**Définition** : Composants dont l'orientation est liée à l'orientation principale de l'entité.
|
||||
|
||||
**Caractéristiques** :
|
||||
- Rotation synchronisée avec l'entité parente
|
||||
- Pas de calcul d'orientation indépendant
|
||||
- Exemples : corps de personnage, châssis de véhicule
|
||||
|
||||
```cpp
|
||||
struct FixedComponent {
|
||||
SpriteID sprite;
|
||||
Vector2 offset; // Position relative au centre de l'entité
|
||||
float rotationOffset; // Rotation additionnelle par rapport à l'orientation principale
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Composants Mobiles (Turret Behavior)
|
||||
**Définition** : Composants avec orientation indépendante suivant une cible.
|
||||
|
||||
**Caractéristiques** :
|
||||
- Orientation calculée indépendamment
|
||||
- Cible une position XY (target)
|
||||
- Contraintes de rotation optionnelles (angle min/max, vitesse de rotation)
|
||||
- Exemples : tête de personnage, arme, tourelle de véhicule
|
||||
|
||||
```cpp
|
||||
struct MobileComponent {
|
||||
SpriteID sprite;
|
||||
Vector2 offset; // Position relative au centre de l'entité
|
||||
|
||||
// Turret behavior
|
||||
Vector2 currentTarget; // Position XY actuelle de la cible
|
||||
float currentAngle; // Angle actuel du composant
|
||||
float rotationSpeed; // Vitesse de rotation max (rad/s)
|
||||
|
||||
// Contraintes optionnelles
|
||||
float minAngle; // Angle minimum (par rapport au fixe)
|
||||
float maxAngle; // Angle maximum (par rapport au fixe)
|
||||
bool hasConstraints; // Si true, applique les contraintes min/max
|
||||
};
|
||||
```
|
||||
|
||||
## Pipeline de rendu unifiée
|
||||
|
||||
La **même pipeline** gère les têtes, armes et tourelles :
|
||||
|
||||
```cpp
|
||||
class EntityRenderer {
|
||||
// Composants fixes (corps)
|
||||
std::vector<FixedComponent> fixedComponents;
|
||||
|
||||
// Composants mobiles (têtes, armes, tourelles)
|
||||
std::vector<MobileComponent> mobileComponents;
|
||||
|
||||
void render(Vector2 position, float mainOrientation) {
|
||||
// 1. Dessiner les composants fixes
|
||||
for (const FixedComponent& comp : fixedComponents) {
|
||||
float finalAngle = mainOrientation + comp.rotationOffset;
|
||||
drawSprite(comp.sprite, position + rotate(comp.offset, mainOrientation), finalAngle);
|
||||
}
|
||||
|
||||
// 2. Dessiner les composants mobiles
|
||||
for (MobileComponent& comp : mobileComponents) {
|
||||
// Calculer l'orientation vers la cible
|
||||
float targetAngle = calculateAngleToTarget(position, comp.offset, comp.currentTarget);
|
||||
|
||||
// Appliquer la vitesse de rotation (smooth rotation)
|
||||
comp.currentAngle = lerpAngle(comp.currentAngle, targetAngle, comp.rotationSpeed * deltaTime);
|
||||
|
||||
// Appliquer les contraintes si nécessaire
|
||||
if (comp.hasConstraints) {
|
||||
float relativeAngle = comp.currentAngle - mainOrientation;
|
||||
comp.currentAngle = mainOrientation + clamp(relativeAngle, comp.minAngle, comp.maxAngle);
|
||||
}
|
||||
|
||||
drawSprite(comp.sprite, position + rotate(comp.offset, mainOrientation), comp.currentAngle);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Exemples concrets
|
||||
|
||||
### Personnage avec arme
|
||||
|
||||
```cpp
|
||||
EntityRenderer soldier;
|
||||
|
||||
// Corps (fixe)
|
||||
soldier.fixedComponents.push_back({
|
||||
.sprite = SPRITE_SOLDIER_BODY_COMPOSED,
|
||||
.offset = {0, 0},
|
||||
.rotationOffset = 0
|
||||
});
|
||||
|
||||
// Tête (mobile - turret behavior)
|
||||
soldier.mobileComponents.push_back({
|
||||
.sprite = SPRITE_HEAD,
|
||||
.offset = {0, 8}, // 8 pixels au-dessus du centre
|
||||
.currentTarget = enemyPosition,
|
||||
.currentAngle = 0,
|
||||
.rotationSpeed = 5.0f, // rad/s
|
||||
.minAngle = -PI/2, // Peut regarder 90° à gauche
|
||||
.maxAngle = PI/2, // Peut regarder 90° à droite
|
||||
.hasConstraints = true
|
||||
});
|
||||
|
||||
// Arme (mobile - turret behavior)
|
||||
soldier.mobileComponents.push_back({
|
||||
.sprite = SPRITE_RIFLE,
|
||||
.offset = {4, 2}, // Décalage pour la main
|
||||
.currentTarget = enemyPosition,
|
||||
.currentAngle = 0,
|
||||
.rotationSpeed = 3.0f, // Plus lent que la tête
|
||||
.minAngle = -PI/4, // Contraintes plus strictes
|
||||
.maxAngle = PI/4,
|
||||
.hasConstraints = true
|
||||
});
|
||||
|
||||
// Rendu
|
||||
soldier.render(soldierPosition, soldierOrientation);
|
||||
```
|
||||
|
||||
### Véhicule avec tourelle
|
||||
|
||||
```cpp
|
||||
EntityRenderer tank;
|
||||
|
||||
// Châssis (fixe)
|
||||
tank.fixedComponents.push_back({
|
||||
.sprite = SPRITE_TANK_HULL,
|
||||
.offset = {0, 0},
|
||||
.rotationOffset = 0
|
||||
});
|
||||
|
||||
// Tourelle principale (mobile - rotation 360°)
|
||||
tank.mobileComponents.push_back({
|
||||
.sprite = SPRITE_TANK_TURRET,
|
||||
.offset = {0, 0},
|
||||
.currentTarget = targetPosition,
|
||||
.currentAngle = 0,
|
||||
.rotationSpeed = 2.0f, // Rotation lente (réaliste)
|
||||
.hasConstraints = false // Rotation complète
|
||||
});
|
||||
|
||||
// Rendu
|
||||
tank.render(tankPosition, tankOrientation);
|
||||
```
|
||||
|
||||
## Optimisations
|
||||
|
||||
### 1. Composition de sprites (Layering)
|
||||
|
||||
**Problème** : Dessiner tous les vêtements séparément = beaucoup de draw calls.
|
||||
|
||||
**Solution** : Pré-composer les sprites en cache.
|
||||
|
||||
```cpp
|
||||
class SpriteComposer {
|
||||
std::unordered_map<CompositionKey, SpriteID> compositionCache;
|
||||
|
||||
SpriteID getComposedSprite(const std::vector<LayerID>& layers) {
|
||||
CompositionKey key = hashLayers(layers);
|
||||
|
||||
if (compositionCache.contains(key)) {
|
||||
return compositionCache[key];
|
||||
}
|
||||
|
||||
// Composer les sprites
|
||||
SpriteID composed = renderToTexture(layers);
|
||||
compositionCache[key] = composed;
|
||||
return composed;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Exemple** :
|
||||
```cpp
|
||||
// Composition d'un soldat
|
||||
std::vector<LayerID> soldierLayers = {
|
||||
SPRITE_BODY_BASE,
|
||||
SPRITE_PANTS_CAMO,
|
||||
SPRITE_JACKET_TACTICAL,
|
||||
SPRITE_VEST_ARMOR
|
||||
};
|
||||
|
||||
SpriteID composedBody = composer.getComposedSprite(soldierLayers);
|
||||
```
|
||||
|
||||
**Avantages** :
|
||||
- Réduction massive des draw calls
|
||||
- Cache persistant entre frames
|
||||
- Mise à jour uniquement quand les vêtements changent
|
||||
|
||||
### 2. Sprite Batching
|
||||
|
||||
Grouper les sprites par texture pour minimiser les changements d'état GPU :
|
||||
|
||||
```cpp
|
||||
// Trier par texture avant de dessiner
|
||||
std::sort(entities.begin(), entities.end(), [](const Entity& a, const Entity& b) {
|
||||
return a.getTextureID() < b.getTextureID();
|
||||
});
|
||||
|
||||
// Dessiner tous les sprites de la même texture ensemble
|
||||
for (const Entity& entity : entities) {
|
||||
entity.render();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Culling
|
||||
|
||||
Ne dessiner que les entités visibles à l'écran :
|
||||
|
||||
```cpp
|
||||
void renderEntities(const Camera& camera) {
|
||||
for (Entity& entity : entities) {
|
||||
if (camera.isVisible(entity.getBounds())) {
|
||||
entity.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Système de couches (Layering)
|
||||
|
||||
### Ordre de rendu (Z-order)
|
||||
|
||||
Les sprites doivent être dessinés dans un ordre précis pour éviter les problèmes de superposition :
|
||||
|
||||
```
|
||||
Z-Order (du plus bas au plus haut)
|
||||
├── 0: Corps/Châssis (fixe)
|
||||
├── 1: Tête/Tourelle (mobile)
|
||||
└── 2: Arme (mobile)
|
||||
```
|
||||
|
||||
**Implémentation** :
|
||||
```cpp
|
||||
struct RenderableComponent {
|
||||
SpriteID sprite;
|
||||
Vector2 position;
|
||||
float rotation;
|
||||
int zOrder; // Ordre de rendu
|
||||
};
|
||||
|
||||
void renderEntity(const Entity& entity) {
|
||||
std::vector<RenderableComponent> renderables;
|
||||
|
||||
// Collecter tous les composants
|
||||
collectFixedComponents(entity, renderables);
|
||||
collectMobileComponents(entity, renderables);
|
||||
|
||||
// Trier par Z-order
|
||||
std::sort(renderables.begin(), renderables.end(),
|
||||
[](const RenderableComponent& a, const RenderableComponent& b) {
|
||||
return a.zOrder < b.zOrder;
|
||||
});
|
||||
|
||||
// Dessiner dans l'ordre
|
||||
for (const RenderableComponent& comp : renderables) {
|
||||
drawSprite(comp.sprite, comp.position, comp.rotation);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Gestion des orientations
|
||||
|
||||
### Angles et conventions
|
||||
|
||||
**Convention** : Angle 0 = direction droite (East), rotation anti-horaire.
|
||||
|
||||
```
|
||||
N (π/2)
|
||||
|
|
||||
W (π) --+-- E (0)
|
||||
|
|
||||
S (3π/2)
|
||||
```
|
||||
|
||||
### Calcul de l'angle vers une cible
|
||||
|
||||
```cpp
|
||||
float calculateAngleToTarget(Vector2 entityPos, Vector2 componentOffset, Vector2 target) {
|
||||
// Position mondiale du composant
|
||||
Vector2 worldPos = entityPos + componentOffset;
|
||||
|
||||
// Direction vers la cible
|
||||
Vector2 direction = target - worldPos;
|
||||
|
||||
// Angle en radians
|
||||
return std::atan2(direction.y, direction.x);
|
||||
}
|
||||
```
|
||||
|
||||
### Interpolation d'angle (smooth rotation)
|
||||
|
||||
Pour éviter les rotations brusques, on interpole vers l'angle cible :
|
||||
|
||||
```cpp
|
||||
float lerpAngle(float current, float target, float speed, float deltaTime) {
|
||||
// Normaliser les angles entre -π et π
|
||||
float diff = normalizeAngle(target - current);
|
||||
|
||||
// Calculer le changement maximum pour cette frame
|
||||
float maxChange = speed * deltaTime;
|
||||
|
||||
// Appliquer le changement (limité par la vitesse)
|
||||
float change = std::clamp(diff, -maxChange, maxChange);
|
||||
|
||||
return current + change;
|
||||
}
|
||||
|
||||
float normalizeAngle(float angle) {
|
||||
while (angle > PI) angle -= 2 * PI;
|
||||
while (angle < -PI) angle += 2 * PI;
|
||||
return angle;
|
||||
}
|
||||
```
|
||||
|
||||
## Extensions futures
|
||||
|
||||
### 1. Animations
|
||||
|
||||
Ajouter un système d'animation pour les sprites :
|
||||
|
||||
```cpp
|
||||
struct AnimatedComponent {
|
||||
std::vector<SpriteID> frames;
|
||||
float frameDuration;
|
||||
float currentTime;
|
||||
|
||||
SpriteID getCurrentFrame() {
|
||||
int frameIndex = (int)(currentTime / frameDuration) % frames.size();
|
||||
return frames[frameIndex];
|
||||
}
|
||||
|
||||
void update(float deltaTime) {
|
||||
currentTime += deltaTime;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Effets visuels
|
||||
|
||||
Ajouter des effets visuels aux composants :
|
||||
|
||||
```cpp
|
||||
struct VisualEffect {
|
||||
Color tint; // Couleur de teinte
|
||||
float opacity; // Transparence
|
||||
Vector2 scale; // Échelle
|
||||
bool flipX, flipY; // Miroirs
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Attachments dynamiques
|
||||
|
||||
Support pour des composants attachés dynamiquement :
|
||||
|
||||
```cpp
|
||||
class AttachmentSystem {
|
||||
void attachComponent(EntityID entity, MobileComponent component, const std::string& attachPoint);
|
||||
void detachComponent(EntityID entity, const std::string& attachPoint);
|
||||
};
|
||||
|
||||
// Exemple : attacher une tourelle sur un point de montage
|
||||
attachments.attachComponent(vehicleID, turretComponent, "mount_point_1");
|
||||
```
|
||||
|
||||
## Performances
|
||||
|
||||
### Métriques cibles
|
||||
|
||||
- **Entités à l'écran** : 500-1000 personnages/véhicules simultanés
|
||||
- **Draw calls** : < 100 par frame (via batching)
|
||||
- **FPS cible** : 60 fps (16.67ms par frame)
|
||||
- **Temps de rendu** : < 8ms par frame (50% du budget)
|
||||
|
||||
### Profiling
|
||||
|
||||
Points de mesure critiques :
|
||||
|
||||
```cpp
|
||||
void renderAll() {
|
||||
PROFILE_SCOPE("Entity Rendering");
|
||||
|
||||
{
|
||||
PROFILE_SCOPE("Sprite Composition");
|
||||
updateComposedSprites();
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_SCOPE("Culling");
|
||||
cullEntities(camera);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_SCOPE("Sorting");
|
||||
sortByTexture(visibleEntities);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_SCOPE("Drawing");
|
||||
drawEntities(visibleEntities);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Intégration avec les autres systèmes
|
||||
|
||||
### Lien avec le système militaire
|
||||
|
||||
Le système de rendu est découplé des systèmes de combat :
|
||||
|
||||
- **Combat System** calcule les positions, rotations, cibles
|
||||
- **Rendering System** lit ces données et dessine les sprites
|
||||
|
||||
```cpp
|
||||
// Dans le module Combat
|
||||
void updateCombat(Entity& entity, float deltaTime) {
|
||||
// Calculer la cible
|
||||
Vector2 target = findClosestEnemy(entity.position);
|
||||
entity.setTarget(target);
|
||||
|
||||
// Le rendering system lira cette cible plus tard
|
||||
}
|
||||
|
||||
// Dans le module Rendering
|
||||
void render(const Entity& entity) {
|
||||
// Lire la cible depuis l'entité
|
||||
Vector2 target = entity.getTarget();
|
||||
|
||||
// Dessiner avec la cible
|
||||
entityRenderer.render(entity.position, entity.orientation, target);
|
||||
}
|
||||
```
|
||||
|
||||
### Lien avec le système de pathfinding
|
||||
|
||||
Le système de rendu utilise les positions calculées par le pathfinding :
|
||||
|
||||
```cpp
|
||||
// Pathfinding calcule la position
|
||||
Vector2 newPosition = pathfinding.getNextPosition(entity);
|
||||
entity.setPosition(newPosition);
|
||||
|
||||
// Rendering dessine à cette position
|
||||
render(entity);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Statut** : ✅ **DESIGN COMPLETE**
|
||||
**Prochaines étapes** :
|
||||
1. Implémenter `EntityRenderer` avec la pipeline fixe/mobile
|
||||
2. Créer `SpriteComposer` pour la composition de sprites
|
||||
3. Intégrer avec le système de combat pour les cibles
|
||||
4. Optimiser avec batching et culling
|
||||
677
docs/03-implementation/configuration/module-versioning.md
Normal file
677
docs/03-implementation/configuration/module-versioning.md
Normal file
@ -0,0 +1,677 @@
|
||||
# Module Versioning System
|
||||
|
||||
## Vue d'Ensemble
|
||||
|
||||
Le système de versioning des modules utilise un format **MAJOR.MINOR.PATCH.BUILD** automatiquement généré par CMake lors de la compilation. Ce système permet de :
|
||||
|
||||
- **Tracer les versions** : Identifier précisément quelle version du code a créé une save
|
||||
- **Détecter incompatibilités** : Alerter si une save utilise une version différente
|
||||
- **Debugging** : Reproduire bugs avec la version exacte du module
|
||||
- **Développement** : Versions incrémentales automatiques sans maintenance manuelle
|
||||
|
||||
## Format de Version
|
||||
|
||||
### Structure : MAJOR.MINOR.PATCH.BUILD
|
||||
|
||||
```
|
||||
0.1.15.3847
|
||||
│ │ │ │
|
||||
│ │ │ └─── BUILD : Auto-increment à chaque build (hash sources)
|
||||
│ │ └────── PATCH : Auto-increment à chaque commit
|
||||
│ └──────── MINOR : Manuel (fonctionnalités nouvelles)
|
||||
└────────── MAJOR : Manuel (breaking changes)
|
||||
```
|
||||
|
||||
### Composantes
|
||||
|
||||
#### MAJOR (Manuel)
|
||||
- **Incrémenté** : Breaking changes, incompatibilités majeures
|
||||
- **Exemples** : Refonte complète architecture, changement format save incompatible
|
||||
- **Gestion** : Modifié manuellement dans fichier `VERSION`
|
||||
- **Valeur initiale** : `0` (pré-release), `1` (première version stable)
|
||||
|
||||
#### MINOR (Manuel)
|
||||
- **Incrémenté** : Nouvelles fonctionnalités, ajouts non-breaking
|
||||
- **Exemples** : Nouveau type de tank, nouveau système économique
|
||||
- **Gestion** : Modifié manuellement dans fichier `VERSION`
|
||||
- **Valeur initiale** : `1`
|
||||
|
||||
#### PATCH (Automatique)
|
||||
- **Incrémenté** : À chaque commit Git
|
||||
- **Calcul** : Nombre de commits depuis le début du projet
|
||||
- **Exemples** : Bugfixes, optimisations, refactoring mineur
|
||||
- **Gestion** : Calculé automatiquement par CMake via `git rev-list --count HEAD`
|
||||
|
||||
#### BUILD (Automatique)
|
||||
- **Incrémenté** : À chaque rebuild (si sources modifiées)
|
||||
- **Calcul** : Hash MD5 des fichiers sources (`.cpp`, `.h`)
|
||||
- **But** : Distinguer builds de dev avec code non-commité
|
||||
- **Gestion** : Calculé automatiquement par CMake
|
||||
|
||||
### Exemples de Versions
|
||||
|
||||
```
|
||||
0.1.0.0 → Première version dev (MAJOR.MINOR manuel, PATCH/BUILD = 0)
|
||||
0.1.5.1234 → Après 5 commits, build 1234
|
||||
0.1.5.1235 → Même commit, sources modifiées → nouveau build
|
||||
0.1.6.1235 → Nouveau commit, sources identiques → même build (théorique)
|
||||
0.2.10.3847 → MINOR bump (nouvelle feature) + 10 commits
|
||||
1.0.0.0 → Release stable, reset PATCH/BUILD
|
||||
```
|
||||
|
||||
## Implémentation CMake
|
||||
|
||||
### Fichier VERSION
|
||||
|
||||
Chaque module contient un fichier `VERSION` à la racine :
|
||||
|
||||
```
|
||||
modules/tank/VERSION
|
||||
```
|
||||
|
||||
Contenu du fichier :
|
||||
```
|
||||
0.1
|
||||
```
|
||||
|
||||
Ce fichier contient uniquement `MAJOR.MINOR`. Les composantes `PATCH.BUILD` sont calculées automatiquement.
|
||||
|
||||
### CMakeLists.txt du Module
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(TankModule)
|
||||
|
||||
# ============================================================================
|
||||
# MODULE VERSIONING
|
||||
# ============================================================================
|
||||
|
||||
# 1. Lire MAJOR.MINOR depuis fichier VERSION
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" BASE_VERSION)
|
||||
string(STRIP "${BASE_VERSION}" BASE_VERSION)
|
||||
else()
|
||||
set(BASE_VERSION "0.1")
|
||||
message(WARNING "No VERSION file found, using default: ${BASE_VERSION}")
|
||||
endif()
|
||||
|
||||
# 2. Calculer PATCH : nombre de commits Git
|
||||
execute_process(
|
||||
COMMAND git rev-list --count HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE PATCH_COUNT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
RESULT_VARIABLE GIT_RESULT
|
||||
)
|
||||
|
||||
if(NOT GIT_RESULT EQUAL 0)
|
||||
set(PATCH_COUNT "0")
|
||||
message(WARNING "Git not available, PATCH set to 0")
|
||||
endif()
|
||||
|
||||
# 3. Calculer BUILD : hash des fichiers sources
|
||||
file(GLOB_RECURSE MODULE_SOURCES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/*.h"
|
||||
)
|
||||
|
||||
# Concaténer contenu de tous les fichiers
|
||||
set(SOURCES_CONTENT "")
|
||||
foreach(SOURCE_FILE ${MODULE_SOURCES})
|
||||
file(READ ${SOURCE_FILE} FILE_CONTENT)
|
||||
string(APPEND SOURCES_CONTENT ${FILE_CONTENT})
|
||||
endforeach()
|
||||
|
||||
# Hash MD5 du contenu total
|
||||
string(MD5 SOURCES_HASH "${SOURCES_CONTENT}")
|
||||
|
||||
# Convertir hash hex en nombre décimal (4 premiers caractères)
|
||||
string(SUBSTRING ${SOURCES_HASH} 0 4 BUILD_HEX)
|
||||
# Calculer valeur numérique (modulo 10000 pour limiter à 4 chiffres)
|
||||
math(EXPR BUILD_NUM "0x${BUILD_HEX} % 10000")
|
||||
|
||||
# 4. Assembler version complète
|
||||
set(MODULE_VERSION "${BASE_VERSION}.${PATCH_COUNT}.${BUILD_NUM}")
|
||||
|
||||
message(STATUS "Module version: ${MODULE_VERSION}")
|
||||
message(STATUS " BASE: ${BASE_VERSION} (from VERSION file)")
|
||||
message(STATUS " PATCH: ${PATCH_COUNT} (git commits)")
|
||||
message(STATUS " BUILD: ${BUILD_NUM} (sources hash)")
|
||||
|
||||
# 5. Définir macro C++ pour accès au runtime
|
||||
add_definitions(-DMODULE_VERSION="${MODULE_VERSION}")
|
||||
|
||||
# ============================================================================
|
||||
# MODULE BUILD
|
||||
# ============================================================================
|
||||
|
||||
# Inclure sources
|
||||
file(GLOB_RECURSE TANK_SOURCES src/*.cpp)
|
||||
|
||||
# Créer bibliothèque partagée (.so)
|
||||
add_library(tank-module SHARED ${TANK_SOURCES})
|
||||
|
||||
# Configuration compilation
|
||||
target_include_directories(tank-module PRIVATE include)
|
||||
target_compile_features(tank-module PRIVATE cxx_std_20)
|
||||
|
||||
# Sortie
|
||||
set_target_properties(tank-module PROPERTIES
|
||||
OUTPUT_NAME "tank"
|
||||
PREFIX ""
|
||||
SUFFIX ".so"
|
||||
)
|
||||
|
||||
message(STATUS "Building TankModule v${MODULE_VERSION}")
|
||||
```
|
||||
|
||||
### Utilisation dans le Code C++
|
||||
|
||||
```cpp
|
||||
// src/TankModule.h
|
||||
#ifndef MODULE_VERSION
|
||||
#define MODULE_VERSION "unknown"
|
||||
#endif
|
||||
|
||||
class TankModule : public IModule, public IModuleSave {
|
||||
public:
|
||||
std::string getVersion() const override {
|
||||
return MODULE_VERSION; // Défini par CMake
|
||||
}
|
||||
|
||||
nlohmann::json serialize() override {
|
||||
json data;
|
||||
data["module_name"] = "tank";
|
||||
data["module_version"] = getVersion(); // "0.1.15.3847"
|
||||
// ... reste de la sérialisation
|
||||
return data;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Affichage au Runtime
|
||||
|
||||
```cpp
|
||||
void TankModule::initialize() {
|
||||
LOG_INFO("TankModule v{} initializing...", getVersion());
|
||||
}
|
||||
```
|
||||
|
||||
Sortie console :
|
||||
```
|
||||
[INFO] TankModule v0.1.15.3847 initializing...
|
||||
```
|
||||
|
||||
## Workflow de Développement
|
||||
|
||||
### 1. Création Nouveau Module
|
||||
|
||||
```bash
|
||||
# Créer structure module
|
||||
mkdir -p modules/new_module/src
|
||||
cd modules/new_module
|
||||
|
||||
# Créer fichier VERSION
|
||||
echo "0.1" > VERSION
|
||||
|
||||
# Créer CMakeLists.txt avec système versioning
|
||||
# (copier template ci-dessus)
|
||||
```
|
||||
|
||||
**Première compilation** :
|
||||
```bash
|
||||
cmake . && make
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
-- Module version: 0.1.0.0
|
||||
-- BASE: 0.1 (from VERSION file)
|
||||
-- PATCH: 0 (git commits)
|
||||
-- BUILD: 0 (sources hash)
|
||||
-- Building NewModule v0.1.0.0
|
||||
```
|
||||
|
||||
### 2. Développement Itératif
|
||||
|
||||
**Scénario 1 : Modifier code sans commit**
|
||||
|
||||
```bash
|
||||
# Éditer src/NewModule.cpp
|
||||
nano src/NewModule.cpp
|
||||
|
||||
# Rebuild
|
||||
make
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
-- Module version: 0.1.0.4582
|
||||
-- PATCH: 0 (aucun commit)
|
||||
-- BUILD: 4582 (hash sources a changé)
|
||||
```
|
||||
|
||||
**Scénario 2 : Commit modifications**
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Add feature X"
|
||||
|
||||
# Rebuild
|
||||
make
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
-- Module version: 0.1.1.4582
|
||||
-- PATCH: 1 (nouveau commit)
|
||||
-- BUILD: 4582 (sources identiques au commit)
|
||||
```
|
||||
|
||||
**Scénario 3 : Rebuild sans modification**
|
||||
|
||||
```bash
|
||||
# Rebuild immédiat
|
||||
make
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
-- Module version: 0.1.1.4582
|
||||
(version identique, aucun changement)
|
||||
```
|
||||
|
||||
### 3. Release Mineure (Nouvelle Feature)
|
||||
|
||||
```bash
|
||||
# Bump MINOR version
|
||||
echo "0.2" > VERSION
|
||||
|
||||
# Commit
|
||||
git add VERSION
|
||||
git commit -m "Bump version to 0.2 (new feature: advanced tactics)"
|
||||
|
||||
# Rebuild
|
||||
cmake . && make
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
-- Module version: 0.2.2.5123
|
||||
-- BASE: 0.2 (nouvelle version)
|
||||
-- PATCH: 2 (commits depuis début projet)
|
||||
-- BUILD: 5123 (hash actuel)
|
||||
```
|
||||
|
||||
### 4. Release Majeure (Breaking Change)
|
||||
|
||||
```bash
|
||||
# Bump MAJOR version
|
||||
echo "1.0" > VERSION
|
||||
|
||||
git add VERSION
|
||||
git commit -m "Release 1.0.0 - Stable API"
|
||||
|
||||
cmake . && make
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
-- Module version: 1.0.3.5123
|
||||
-- BASE: 1.0 (version stable)
|
||||
-- PATCH: 3 (total commits)
|
||||
-- BUILD: 5123
|
||||
```
|
||||
|
||||
## Comparaison de Versions
|
||||
|
||||
### Dans le Système de Save
|
||||
|
||||
Lors du chargement d'une save, comparaison des versions :
|
||||
|
||||
```cpp
|
||||
bool SaveSystem::loadModule(const std::string& moduleName) {
|
||||
auto module = moduleSystem->getModule(moduleName);
|
||||
|
||||
json moduleData = readJsonFile(modulePath);
|
||||
std::string savedVersion = moduleData["module_version"];
|
||||
std::string currentVersion = module->getVersion();
|
||||
|
||||
if (savedVersion != currentVersion) {
|
||||
LOG_WARN("Module {} version mismatch:", moduleName);
|
||||
LOG_WARN(" Save version: {}", savedVersion);
|
||||
LOG_WARN(" Current version: {}", currentVersion);
|
||||
|
||||
// Analyser différences
|
||||
VersionInfo saved = parseVersion(savedVersion);
|
||||
VersionInfo current = parseVersion(currentVersion);
|
||||
|
||||
if (saved.major != current.major) {
|
||||
LOG_ERROR(" MAJOR version mismatch - likely incompatible!");
|
||||
return false; // Incompatibilité critique
|
||||
}
|
||||
else if (saved.minor != current.minor) {
|
||||
LOG_WARN(" MINOR version mismatch - some features may differ");
|
||||
// Continuer avec warning
|
||||
}
|
||||
else if (saved.patch != current.patch) {
|
||||
LOG_INFO(" PATCH version mismatch - minor changes only");
|
||||
// Sûr, juste bugfixes
|
||||
}
|
||||
else {
|
||||
LOG_DEBUG(" BUILD version mismatch - dev builds differ");
|
||||
// Totalement sûr
|
||||
}
|
||||
}
|
||||
|
||||
return module->deserialize(moduleData);
|
||||
}
|
||||
```
|
||||
|
||||
### Structure VersionInfo
|
||||
|
||||
```cpp
|
||||
struct VersionInfo {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
int build;
|
||||
|
||||
static VersionInfo parse(const std::string& versionStr) {
|
||||
VersionInfo info;
|
||||
std::sscanf(versionStr.c_str(), "%d.%d.%d.%d",
|
||||
&info.major, &info.minor, &info.patch, &info.build);
|
||||
return info;
|
||||
}
|
||||
|
||||
bool isCompatibleWith(const VersionInfo& other) const {
|
||||
// Compatible si MAJOR identique
|
||||
return major == other.major;
|
||||
}
|
||||
|
||||
bool hasBreakingChanges(const VersionInfo& other) const {
|
||||
return major != other.major;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Gestion Multi-Modules
|
||||
|
||||
### Script CMake Global
|
||||
|
||||
Pour centraliser la logique de versioning, créer un fichier CMake réutilisable :
|
||||
|
||||
```cmake
|
||||
# cmake/ModuleVersioning.cmake
|
||||
|
||||
function(setup_module_versioning)
|
||||
# Lire VERSION
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" BASE_VERSION)
|
||||
string(STRIP "${BASE_VERSION}" BASE_VERSION)
|
||||
else()
|
||||
set(BASE_VERSION "0.1")
|
||||
endif()
|
||||
|
||||
# Calculer PATCH
|
||||
execute_process(
|
||||
COMMAND git rev-list --count HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE PATCH_COUNT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
RESULT_VARIABLE GIT_RESULT
|
||||
)
|
||||
if(NOT GIT_RESULT EQUAL 0)
|
||||
set(PATCH_COUNT "0")
|
||||
endif()
|
||||
|
||||
# Calculer BUILD
|
||||
file(GLOB_RECURSE MODULE_SOURCES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/*.h"
|
||||
)
|
||||
set(SOURCES_CONTENT "")
|
||||
foreach(SOURCE_FILE ${MODULE_SOURCES})
|
||||
file(READ ${SOURCE_FILE} FILE_CONTENT)
|
||||
string(APPEND SOURCES_CONTENT ${FILE_CONTENT})
|
||||
endforeach()
|
||||
string(MD5 SOURCES_HASH "${SOURCES_CONTENT}")
|
||||
string(SUBSTRING ${SOURCES_HASH} 0 4 BUILD_HEX)
|
||||
math(EXPR BUILD_NUM "0x${BUILD_HEX} % 10000")
|
||||
|
||||
# Assembler version
|
||||
set(MODULE_VERSION "${BASE_VERSION}.${PATCH_COUNT}.${BUILD_NUM}" PARENT_SCOPE)
|
||||
|
||||
# Log
|
||||
message(STATUS "Module version: ${BASE_VERSION}.${PATCH_COUNT}.${BUILD_NUM}")
|
||||
endfunction()
|
||||
```
|
||||
|
||||
### Utilisation dans Module
|
||||
|
||||
```cmake
|
||||
# modules/tank/CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(TankModule)
|
||||
|
||||
# Importer fonction versioning
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/ModuleVersioning.cmake)
|
||||
|
||||
# Setup version automatique
|
||||
setup_module_versioning()
|
||||
|
||||
# Définir macro
|
||||
add_definitions(-DMODULE_VERSION="${MODULE_VERSION}")
|
||||
|
||||
# ... reste du CMakeLists
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Quand Bumper MAJOR ?
|
||||
|
||||
**Situations justifiant MAJOR bump** :
|
||||
- Changement format save incompatible
|
||||
- Refonte API du module (signatures fonctions changent)
|
||||
- Suppression de fonctionnalités existantes
|
||||
- Changement architecture fondamentale
|
||||
|
||||
**Exemple** :
|
||||
```bash
|
||||
# Avant : TankModule v0.8.x utilise grille 10x10
|
||||
# Après : TankModule v1.0.0 utilise grille 16x16 (incompatible)
|
||||
echo "1.0" > VERSION
|
||||
```
|
||||
|
||||
### 2. Quand Bumper MINOR ?
|
||||
|
||||
**Situations justifiant MINOR bump** :
|
||||
- Ajout nouveau type de tank/composant
|
||||
- Nouvelle fonctionnalité (mode formation, tactiques AI)
|
||||
- Amélioration significative sans breaking change
|
||||
|
||||
**Exemple** :
|
||||
```bash
|
||||
# Ajout système de camouflage → 0.1 → 0.2
|
||||
echo "0.2" > VERSION
|
||||
```
|
||||
|
||||
### 3. PATCH et BUILD sont Automatiques
|
||||
|
||||
**Ne jamais modifier manuellement** :
|
||||
- PATCH suit automatiquement les commits
|
||||
- BUILD suit automatiquement les modifications code
|
||||
|
||||
### 4. Versioning pour Tests
|
||||
|
||||
En environnement de test, fixer une version stable :
|
||||
|
||||
```cmake
|
||||
if(DEFINED ENV{CI_BUILD})
|
||||
# Build CI : version fixe pour reproductibilité
|
||||
set(MODULE_VERSION "0.0.0.0")
|
||||
else()
|
||||
# Build normal : versioning automatique
|
||||
setup_module_versioning()
|
||||
endif()
|
||||
```
|
||||
|
||||
### 5. Affichage Version au Démarrage
|
||||
|
||||
```cpp
|
||||
void logModuleVersions() {
|
||||
LOG_INFO("=== Module Versions ===");
|
||||
for (auto& module : moduleSystem->getAllModules()) {
|
||||
LOG_INFO(" {}: v{}", module->getName(), module->getVersion());
|
||||
}
|
||||
LOG_INFO("=======================");
|
||||
}
|
||||
```
|
||||
|
||||
Sortie :
|
||||
```
|
||||
[INFO] === Module Versions ===
|
||||
[INFO] tank: v0.1.15.3847
|
||||
[INFO] economy: v0.2.8.1203
|
||||
[INFO] factory: v0.1.20.4512
|
||||
[INFO] transport: v0.1.5.982
|
||||
[INFO] =======================
|
||||
```
|
||||
|
||||
## Debugging avec Versions
|
||||
|
||||
### Reproduire un Bug
|
||||
|
||||
Si un bug est reporté avec une save :
|
||||
|
||||
1. **Lire version du module dans la save** :
|
||||
```bash
|
||||
cat saves/abc123/server_1/tank.json | grep module_version
|
||||
# "module_version": "0.1.15.3847"
|
||||
```
|
||||
|
||||
2. **Retrouver commit correspondant** :
|
||||
```bash
|
||||
# PATCH = 15 commits
|
||||
git log --oneline | head -n 15 | tail -n 1
|
||||
```
|
||||
|
||||
3. **Vérifier hash sources** :
|
||||
```bash
|
||||
# BUILD = 3847 correspond à un certain hash
|
||||
# Comparer avec hashes de commits proches
|
||||
```
|
||||
|
||||
4. **Checkout version exacte pour debugging** :
|
||||
```bash
|
||||
git checkout <commit_hash>
|
||||
cmake . && make
|
||||
# Version devrait matcher ou être proche
|
||||
```
|
||||
|
||||
### Logs de Version
|
||||
|
||||
```cpp
|
||||
void TankModule::initialize() {
|
||||
LOG_INFO("TankModule v{} initializing", getVersion());
|
||||
LOG_DEBUG(" Compiled: {} {}", __DATE__, __TIME__);
|
||||
LOG_DEBUG(" Compiler: {}", __VERSION__);
|
||||
}
|
||||
```
|
||||
|
||||
## Alternatives et Limitations
|
||||
|
||||
### Alternative 1 : Semantic Versioning Manuel
|
||||
|
||||
**Avantage** : Contrôle total sur versions
|
||||
**Inconvénient** : Maintenance manuelle, oublis fréquents
|
||||
|
||||
### Alternative 2 : Git Tags Only
|
||||
|
||||
```cmake
|
||||
execute_process(
|
||||
COMMAND git describe --tags --always
|
||||
OUTPUT_VARIABLE MODULE_VERSION
|
||||
)
|
||||
```
|
||||
|
||||
**Avantage** : Simple, suit git
|
||||
**Inconvénient** : Nécessite tags, pas de granularité build
|
||||
|
||||
### Limitation Actuelle : Hash Non-Déterministe
|
||||
|
||||
Le hash des sources peut varier selon :
|
||||
- Ordre de lecture des fichiers (filesystem dépendant)
|
||||
- Encodage des fichiers
|
||||
- Whitespace differences
|
||||
|
||||
**Solution future** : Hash déterministe avec tri des fichiers et normalisation.
|
||||
|
||||
## Migration depuis Système Existant
|
||||
|
||||
Si des modules existants utilisent un autre système :
|
||||
|
||||
```cmake
|
||||
# Détecter ancien système
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/version.txt")
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" OLD_VERSION)
|
||||
message(WARNING "Found old version.txt, migrating to VERSION file")
|
||||
|
||||
# Extraire MAJOR.MINOR
|
||||
string(REGEX MATCH "^[0-9]+\\.[0-9]+" BASE_VERSION ${OLD_VERSION})
|
||||
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" "${BASE_VERSION}")
|
||||
|
||||
message(STATUS "Migration complete: ${OLD_VERSION} -> ${BASE_VERSION}.x.x")
|
||||
endif()
|
||||
```
|
||||
|
||||
## Références Croisées
|
||||
|
||||
- `systeme-sauvegarde.md` : Utilisation des versions dans le système de save
|
||||
- `architecture-modulaire.md` : Interface IModule, contraintes modules
|
||||
- `claude-code-integration.md` : Optimisation builds pour développement AI
|
||||
|
||||
## Exemples Complets
|
||||
|
||||
### Module Complet avec Versioning
|
||||
|
||||
Voir structure complète dans :
|
||||
```
|
||||
modules/tank/
|
||||
├── VERSION # "0.1"
|
||||
├── CMakeLists.txt # Setup versioning + build
|
||||
├── src/
|
||||
│ ├── TankModule.cpp # Utilise MODULE_VERSION
|
||||
│ └── Tank.cpp
|
||||
└── include/
|
||||
└── TankModule.h # Déclare getVersion()
|
||||
```
|
||||
|
||||
### Test Versioning
|
||||
|
||||
```cpp
|
||||
#ifdef TESTING
|
||||
#include <cassert>
|
||||
|
||||
void testVersioning() {
|
||||
TankModule module;
|
||||
|
||||
std::string version = module.getVersion();
|
||||
assert(!version.empty());
|
||||
assert(version != "unknown");
|
||||
|
||||
// Parse version
|
||||
VersionInfo info = VersionInfo::parse(version);
|
||||
assert(info.major >= 0);
|
||||
assert(info.minor >= 0);
|
||||
assert(info.patch >= 0);
|
||||
assert(info.build >= 0);
|
||||
|
||||
std::cout << "Versioning test passed: " << version << std::endl;
|
||||
}
|
||||
#endif
|
||||
```
|
||||
395
docs/04-reference/INTEGRATION-MASTER-LIST.md
Normal file
395
docs/04-reference/INTEGRATION-MASTER-LIST.md
Normal file
@ -0,0 +1,395 @@
|
||||
# INTEGRATION MASTER LIST
|
||||
|
||||
Complete technical specifications catalog for the Warfactory project.
|
||||
|
||||
## Global Architecture Overview
|
||||
|
||||
### System Orchestration Flow
|
||||
```
|
||||
MainServer Process:
|
||||
├── CoordinationModule (Global Orchestrator)
|
||||
│ ├── Loads gameconfig.json via IDataTree
|
||||
│ ├── Launches local IEngine + modules
|
||||
│ └── Launches remote servers + engines
|
||||
├── Local IEngine (manages local modules)
|
||||
│ ├── IModuleSystem (execution strategy)
|
||||
│ └── Local Modules (.so files)
|
||||
└── Remote Servers (launched by coordination)
|
||||
├── Remote IEngine (manages remote modules)
|
||||
├── IModuleSystem (execution strategy)
|
||||
└── Remote Modules (.so files)
|
||||
```
|
||||
|
||||
### Startup Sequence
|
||||
1. **MainServer** starts and launches **CoordinationModule**
|
||||
2. **CoordinationModule** calls `startNewGame("gameconfig.json")`
|
||||
3. **Config Loading**: IDataTree loads and parses gameconfig.json
|
||||
4. **Deployment Analysis**: Parse deployment section to determine module topology
|
||||
5. **Local Deployment**: Deploy modules with `target: "local"` to local IEngine
|
||||
6. **Remote Deployment**: Launch remote servers and deploy modules with `target: "server:IP"`
|
||||
7. **Synchronization**: All modules receive their configuration via `setConfiguration()`
|
||||
8. **Game Ready**: Return control to user interface
|
||||
|
||||
### Module Lifecycle with New Configuration System
|
||||
```cpp
|
||||
// Old way (DEPRECATED)
|
||||
module->initialize(json_config, io, scheduler);
|
||||
|
||||
// New way (CURRENT)
|
||||
const IDataNode& config = configTree->getNode("modules/production");
|
||||
module->setConfiguration(config, io, scheduler); // const ref, no copies
|
||||
|
||||
// Health monitoring
|
||||
json health = module->getHealthStatus();
|
||||
// Returns: {"status": "healthy", "last_process_time_ms": 1.2, "memory_usage_mb": 45}
|
||||
```
|
||||
|
||||
## Core Interface System
|
||||
|
||||
### Engine Interfaces (IMMUTABLE)
|
||||
- **IEngine**: Engine orchestration, module loading, client/coordinator socket management
|
||||
- **IModuleSystem**: Execution strategy + task scheduling (inherits ITaskScheduler)
|
||||
- **IModule**: Pure business logic + pub/sub communication + task delegation (**BREAKING CHANGES**)
|
||||
- **IIO**: Pull-based pub/sub with low-frequency batching and health monitoring
|
||||
- **ITaskScheduler**: Task delegation interface for module → execution system
|
||||
|
||||
### Configuration System (IMMUTABLE)
|
||||
- **IDataTree**: Configuration tree container with manual hot-reload capabilities
|
||||
- **IDataNode**: Hierarchical data nodes with pattern matching and property queries (**const methods**)
|
||||
- **DataTreeFactory**: Factory pattern for flexible data source creation
|
||||
|
||||
### Coordination System (NEW)
|
||||
- **ICoordinationModule**: Global system orchestrator and main game lifecycle manager
|
||||
|
||||
## GameConfig.json Architecture
|
||||
|
||||
### Central Configuration System
|
||||
The entire game system is configured through a single **`gameconfig.json`** file that serves as the master configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"game": {
|
||||
"name": "Warfactory Game Session",
|
||||
"version": "1.0.0",
|
||||
"save_path": "./saves/game_001"
|
||||
},
|
||||
"deployment": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "production_main",
|
||||
"type": "ProductionModule",
|
||||
"path": "./modules/production.so",
|
||||
"target": "local",
|
||||
"config_path": "modules/production"
|
||||
},
|
||||
{
|
||||
"id": "economy_central",
|
||||
"type": "EconomyModule",
|
||||
"path": "./modules/economy.so",
|
||||
"target": "server:192.168.1.100:8080",
|
||||
"config_path": "modules/economy"
|
||||
},
|
||||
{
|
||||
"id": "tank_combat",
|
||||
"type": "TankModule",
|
||||
"path": "./modules/tank.so",
|
||||
"target": "cluster:combat_nodes",
|
||||
"config_path": "modules/tank"
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": {
|
||||
"production": {
|
||||
"frequency": "60Hz",
|
||||
"belt_speed": 2.5,
|
||||
"inserter_capacity": 12
|
||||
},
|
||||
"economy": {
|
||||
"frequency": "0.1Hz",
|
||||
"inflation_rate": 0.02,
|
||||
"market_volatility": 0.15
|
||||
},
|
||||
"tank": {
|
||||
"targeting_frequency": "60Hz",
|
||||
"movement_frequency": "30Hz",
|
||||
"tactical_frequency": "1Hz"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Flow
|
||||
1. **CoordinationModule** loads `gameconfig.json` via IDataTree
|
||||
2. **Deployment section** defines module topology and distribution
|
||||
3. **Modules section** contains hierarchical configuration for each module type
|
||||
4. **Hot-reload** updates propagated to all deployed modules automatically
|
||||
|
||||
### CoordinationModule Deployment Logic
|
||||
```cpp
|
||||
// Example deployment process
|
||||
void CoordinationModule::deployModule(const std::string& moduleInstanceId) {
|
||||
// 1. Get module configuration from gameconfig.json
|
||||
const IDataNode& deployConfig = configTree->getNode("deployment/modules");
|
||||
const IDataNode* moduleConfig = deployConfig.getFirstChildByName(moduleInstanceId);
|
||||
|
||||
// 2. Determine deployment target
|
||||
std::string target = moduleConfig->getString("target");
|
||||
std::string modulePath = moduleConfig->getString("path");
|
||||
std::string configPath = moduleConfig->getString("config_path");
|
||||
|
||||
// 3. Get module-specific configuration
|
||||
const IDataNode& moduleSettings = configTree->getNode("modules/" + configPath);
|
||||
|
||||
// 4. Deploy based on target
|
||||
if (target == "local") {
|
||||
localEngine->getModuleSystem()->loadModule(modulePath, moduleSettings);
|
||||
} else if (target.startswith("server:")) {
|
||||
deployToRemoteServer(target, modulePath, moduleSettings);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## IDataTree Configuration System Specifications
|
||||
|
||||
### Core Architecture
|
||||
```cpp
|
||||
namespace warfactory {
|
||||
class IDataTree {
|
||||
// Tree access
|
||||
virtual std::unique_ptr<IDataNode> getRoot() = 0;
|
||||
virtual std::unique_ptr<IDataNode> getNode(const std::string& path) = 0;
|
||||
|
||||
// Manual hot-reload
|
||||
virtual bool checkForChanges() = 0;
|
||||
virtual bool reloadIfChanged() = 0;
|
||||
virtual void onTreeReloaded(std::function<void()> callback) = 0;
|
||||
|
||||
// Metadata
|
||||
virtual std::string getType() = 0;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### IDataNode Capabilities
|
||||
```cpp
|
||||
namespace warfactory {
|
||||
class IDataNode {
|
||||
// Tree navigation
|
||||
virtual std::unique_ptr<IDataNode> getChild(const std::string& name) = 0;
|
||||
virtual std::vector<std::string> getChildNames() = 0;
|
||||
virtual bool hasChildren() = 0;
|
||||
|
||||
// Exact search in children
|
||||
virtual std::vector<IDataNode*> getChildrenByName(const std::string& name) = 0;
|
||||
virtual bool hasChildrenByName(const std::string& name) const = 0;
|
||||
virtual IDataNode* getFirstChildByName(const std::string& name) = 0;
|
||||
|
||||
// Pattern matching search (deep search in whole subtree)
|
||||
virtual std::vector<IDataNode*> getChildrenByNameMatch(const std::string& pattern) = 0;
|
||||
virtual bool hasChildrenByNameMatch(const std::string& pattern) const = 0;
|
||||
virtual IDataNode* getFirstChildByNameMatch(const std::string& pattern) = 0;
|
||||
|
||||
// Query by properties
|
||||
virtual std::vector<IDataNode*> queryByProperty(const std::string& propName,
|
||||
const std::function<bool(const json&)>& predicate) = 0;
|
||||
|
||||
// Node's own data
|
||||
virtual json getData() = 0;
|
||||
virtual bool hasData() = 0;
|
||||
virtual void setData(const json& data) = 0;
|
||||
|
||||
// Typed data access by property name
|
||||
virtual std::string getString(const std::string& name, const std::string& defaultValue = "") = 0;
|
||||
virtual int getInt(const std::string& name, int defaultValue = 0) = 0;
|
||||
virtual double getDouble(const std::string& name, double defaultValue = 0.0) = 0;
|
||||
virtual bool getBool(const std::string& name, bool defaultValue = false) = 0;
|
||||
virtual bool hasProperty(const std::string& name) = 0;
|
||||
|
||||
// Hash system for validation & synchro
|
||||
virtual std::string getDataHash() = 0;
|
||||
virtual std::string getTreeHash() = 0;
|
||||
virtual std::string getSubtreeHash(const std::string& childPath) = 0;
|
||||
|
||||
// Metadata
|
||||
virtual std::string getPath() = 0;
|
||||
virtual std::string getName() = 0;
|
||||
virtual std::string getNodeType() = 0;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Usage Patterns
|
||||
|
||||
#### Hierarchical Data Access
|
||||
```cpp
|
||||
// Access nested configuration
|
||||
std::unique_ptr<IDataTree> tree = DataTreeFactory::create("json", "config/vehicles.json");
|
||||
std::unique_ptr<IDataNode> tank = tree->getNode("vehicles/tanks/heavy/model5");
|
||||
|
||||
// Get properties with type safety
|
||||
int armor = tank->getInt("armor", 100);
|
||||
double speed = tank->getDouble("speed", 30.0);
|
||||
std::string name = tank->getString("display_name", "Unknown Tank");
|
||||
```
|
||||
|
||||
#### Pattern Matching Search
|
||||
```cpp
|
||||
// Find all components
|
||||
std::vector<IDataNode*> components = root->getChildrenByNameMatch("component*");
|
||||
|
||||
// Find all heavy variants
|
||||
std::vector<IDataNode*> heavyUnits = root->getChildrenByNameMatch("*heavy*");
|
||||
|
||||
// Find specific models
|
||||
std::vector<IDataNode*> models = root->getChildrenByNameMatch("model_*");
|
||||
```
|
||||
|
||||
#### Property-Based Queries
|
||||
```cpp
|
||||
// Find all tanks with armor > 150
|
||||
std::vector<IDataNode*> heavyTanks = root->queryByProperty("armor", [](const json& val) {
|
||||
return val.is_number() && val.get<int>() > 150;
|
||||
});
|
||||
|
||||
// Find all vehicles with specific role
|
||||
std::vector<IDataNode*> scouts = root->queryByProperty("role", [](const json& val) {
|
||||
return val.is_string() && val.get<std::string>() == "scout";
|
||||
});
|
||||
```
|
||||
|
||||
#### Hot-Reload Workflow
|
||||
```cpp
|
||||
// Manual hot-reload check
|
||||
if (tree->checkForChanges()) {
|
||||
if (tree->reloadIfChanged()) {
|
||||
// Tree was reloaded - update dependent systems
|
||||
updateGameContent();
|
||||
}
|
||||
}
|
||||
|
||||
// Register reload callback
|
||||
tree->onTreeReloaded([]() {
|
||||
std::cout << "Configuration reloaded - updating systems\n";
|
||||
notifyAllModules();
|
||||
});
|
||||
```
|
||||
|
||||
### Hash-Based Validation
|
||||
```cpp
|
||||
// Validate specific data integrity
|
||||
std::string nodeHash = node->getDataHash();
|
||||
std::string previousHash = loadStoredHash();
|
||||
if (nodeHash != previousHash) {
|
||||
// Data has changed - trigger update
|
||||
synchronizeWithServer(nodeHash);
|
||||
}
|
||||
|
||||
// Validate entire subtree
|
||||
std::string treeHash = node->getTreeHash();
|
||||
if (treeHash != expectedTreeHash) {
|
||||
// Subtree structure or data has changed
|
||||
performFullValidation();
|
||||
}
|
||||
```
|
||||
|
||||
### Factory Pattern Usage
|
||||
```cpp
|
||||
// JSON configuration
|
||||
std::unique_ptr<IDataTree> jsonTree = DataTreeFactory::create("json", "config/vehicles.json");
|
||||
|
||||
// Future: Database configuration
|
||||
std::unique_ptr<IDataTree> dbTree = DataTreeFactory::create("database", "postgresql://config_db");
|
||||
|
||||
// Future: Network configuration
|
||||
std::unique_ptr<IDataTree> netTree = DataTreeFactory::create("network", "https://api.example.com/config");
|
||||
```
|
||||
|
||||
## UI Interface System (COMPLETED)
|
||||
|
||||
### IUI Architecture
|
||||
- **Data-Agnostic Design**: Generic interface supporting all content types
|
||||
- **Type-Safe Enums**: DataType::ECONOMY, RequestType::GET_PRICES for performance
|
||||
- **Hierarchical Windowing**: Parent → Dock → Split → Tab → Window structure
|
||||
- **Hybrid Sizing System**: Percentage targets with absolute pixel constraints
|
||||
|
||||
### ImGuiUI Implementation
|
||||
- **Complete Rendering Pipeline**: All DataType content renderers implemented
|
||||
- **Interactive Callbacks**: Request/response system with onRequest() + custom events
|
||||
- **Professional Layout**: Economic topbar + companies panel + strategic map + console
|
||||
- **State Management**: Window persistence, docking configuration, layout serialization
|
||||
|
||||
## Module System Specifications
|
||||
|
||||
### BREAKING CHANGES in IModule Interface
|
||||
```cpp
|
||||
// OLD Interface (DEPRECATED)
|
||||
class IModule {
|
||||
virtual void initialize(const json& config, IIO* io, ITaskScheduler* scheduler) = 0;
|
||||
virtual bool isHealthy() = 0; // Simple boolean
|
||||
};
|
||||
|
||||
// NEW Interface (CURRENT)
|
||||
class IModule {
|
||||
virtual void setConfiguration(const IDataNode& configNode, IIO* io, ITaskScheduler* scheduler) = 0;
|
||||
virtual const IDataNode& getConfiguration() = 0;
|
||||
virtual json getHealthStatus() = 0; // Detailed JSON report
|
||||
// initialize() method REMOVED
|
||||
};
|
||||
```
|
||||
|
||||
### Configuration Immutability Pattern
|
||||
```cpp
|
||||
// Modules receive const references - cannot modify configuration
|
||||
const IDataNode& config = coordinationModule->getConfigurationTree()->getNode("modules/production");
|
||||
|
||||
// All getter methods are const to enforce read-only access
|
||||
int frequency = config.getInt("frequency", 60); // const method
|
||||
std::string mode = config.getString("mode", "auto"); // const method
|
||||
|
||||
// Modifications only possible through CoordinationModule
|
||||
coordinationModule->syncConfiguration(); // Reloads entire tree
|
||||
```
|
||||
|
||||
### Module Health Monitoring
|
||||
```cpp
|
||||
// Detailed health status example
|
||||
json healthStatus = {
|
||||
"status": "healthy|degraded|critical|offline",
|
||||
"last_process_time_ms": 1.2,
|
||||
"memory_usage_mb": 45,
|
||||
"error_count": 0,
|
||||
"warnings": ["High memory usage detected"],
|
||||
"details": "All subsystems operational",
|
||||
"uptime_seconds": 3600,
|
||||
"processed_messages": 15420
|
||||
};
|
||||
```
|
||||
|
||||
### Module Frequencies & Isolation
|
||||
- **ProductionModule**: 60Hz (frame-perfect factory operations)
|
||||
- **TankModule**: 0.1-60Hz (Targeting 60Hz → Movement 30Hz → Tactical 1Hz → Analytics 0.1Hz)
|
||||
- **EconomyModule**: 0.01-0.1Hz (economic cycles)
|
||||
- **War Isolation**: ZERO interaction ProductionModule ↔ WarModule
|
||||
- **Supply Chain**: Factory → LogisticModule → War (unidirectional flow)
|
||||
|
||||
### Performance Targets
|
||||
- **V1 Client**: 30+ fps
|
||||
- **V2 Client**: 60+ fps
|
||||
- **V1 Server**: 10+ players
|
||||
- **V2 Server**: 100+ players
|
||||
|
||||
## Development Constraints
|
||||
|
||||
### Code Restrictions
|
||||
- **AUTO KEYWORD PROHIBITED**: Explicit types required throughout codebase
|
||||
- **Interface Immutability**: Core interfaces NEVER modified once finalized
|
||||
- **Module Isolation**: No `#include "../"` or parent directory references
|
||||
- **PUB/SUB Communication**: Module communication via IIO only
|
||||
|
||||
### Build System
|
||||
- **Autonomous Builds**: Each module builds independently
|
||||
- **Hot-Reload**: 0.4ms average reload time achieved
|
||||
- **Cross-Platform**: Linux development → Windows .exe automated
|
||||
- **Debug Tools**: AddressSanitizer + UndefinedBehaviorSanitizer by default
|
||||
|
||||
This document serves as the authoritative reference for all technical specifications in the Warfactory project.
|
||||
@ -134,6 +134,38 @@ class PsychologicalAntiCheat {
|
||||
- **Continuité améliorée** : Algorithmes liaison inter-chunks
|
||||
- **Biomes complexes** : Transitions naturelles entre terrains
|
||||
|
||||
### Load Balancing et Distribution Avancée
|
||||
**Future évolution du CoordinationModule** pour optimisation performance automatique :
|
||||
|
||||
#### Distribution Intelligente des Modules
|
||||
- **CPU Load Monitoring** : Surveillance utilisation processeur par module
|
||||
- **Network Latency Aware** : Placement modules selon latence réseau
|
||||
- **Memory Usage Optimization** : Répartition selon consommation mémoire
|
||||
- **Auto-scaling** : Lancement instances multiples modules haute charge
|
||||
|
||||
#### Migration Dynamique
|
||||
```cpp
|
||||
class LoadBalancer {
|
||||
void redistributeModules() {
|
||||
// Analyse performance metrics
|
||||
if (economyModule.getCPUUsage() > 80%) {
|
||||
migrateToLowerLoadServer(economyModule);
|
||||
}
|
||||
|
||||
// Optimisation latence
|
||||
if (networkLatency(tankModule, productionModule) > 50ms) {
|
||||
colocateModules(tankModule, productionModule);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Stratégies de Placement
|
||||
- **Colocation Intelligente** : Modules communicants sur même serveur
|
||||
- **Geographic Distribution** : Placement modules selon localisation joueurs
|
||||
- **Resource Affinity** : Modules CPU-intensifs vs I/O-intensifs
|
||||
- **Hot-Standby** : Réplication modules critiques pour haute disponibilité
|
||||
|
||||
### Autres fonctionnalités à explorer
|
||||
*À compléter selon l'évolution du projet*
|
||||
|
||||
|
||||
1414
docs/ai-framework.md
Normal file
1414
docs/ai-framework.md
Normal file
File diff suppressed because it is too large
Load Diff
842
docs/calcul-menace.md
Normal file
842
docs/calcul-menace.md
Normal file
@ -0,0 +1,842 @@
|
||||
# Calcul de Menace Contextuelle
|
||||
|
||||
## Vue d'Ensemble
|
||||
|
||||
Le système de calcul de menace évalue la **dangerosité qu'une entité représente pour une autre** en analysant non seulement les forces brutes, mais aussi les capacités défensives, la qualité des équipements, et la production industrielle.
|
||||
|
||||
### Principes Fondamentaux
|
||||
|
||||
- **Contextuel** : Menace calculée selon capacités **des deux parties**
|
||||
- **Asymétrique** : A menace B ≠ B menace A
|
||||
- **Sword & Shield** : Qualité défenses réduit menace, jamais totalement
|
||||
- **Baseline 20%** : Toute arme reste dangereuse à minimum 20% effectiveness
|
||||
- **Production** : Capacité industrielle = menace future
|
||||
- **Multi-domaines** : Terre, air, mer évalués séparément puis agrégés
|
||||
- **Perte coûteuse** : Perdre unité chère = désastre stratégique même avec victoire
|
||||
|
||||
### Distinction Menace vs Victoire Tactique
|
||||
|
||||
**CRITIQUE** : La menace mesure la **capacité de nuisance stratégique**, pas l'issue du combat tactique.
|
||||
|
||||
**Exemple** : 20 tanks modernes peuvent être détruits par saturation, MAIS avant destruction ils peuvent :
|
||||
- Percer défenses et atteindre objectifs profonds
|
||||
- Détruire infrastructure critique (QG, dépôts, ponts)
|
||||
- Infliger pertes massives
|
||||
- Forcer mobilisation coûteuse
|
||||
|
||||
→ Menace élevée même si tanks finalement détruits
|
||||
→ Perte d'un Leopard 2A7 (8M€) = toujours désastre stratégique
|
||||
|
||||
## Échelle de Menace
|
||||
|
||||
**Valeurs** : `0` à `2 000 000+` (pas de maximum strict, type `int32_t`)
|
||||
|
||||
**Ordres de grandeur** :
|
||||
- `0` : Aucune menace
|
||||
- `100 - 1 000` : PMC petit
|
||||
- `5 000 - 50 000` : Company moyenne
|
||||
- `100 000` : État petit
|
||||
- `500 000` : État moyen (France, UK, Allemagne)
|
||||
- `900 000` : Superpower (USA, Chine, Russie)
|
||||
- `1 000 000+` : Menace existentielle
|
||||
|
||||
## Architecture Calcul
|
||||
|
||||
### Formule Globale
|
||||
|
||||
```cpp
|
||||
int calculateThreat(Entity attacker, Entity defender) {
|
||||
auto params = attacker.getThreatParams();
|
||||
|
||||
// Composantes
|
||||
int current_military = evaluateCurrentForces(attacker, defender);
|
||||
int production_capacity = evaluateProduction(attacker, defender, params.projection_months);
|
||||
|
||||
// Pondération configurable par entité
|
||||
return current_military * params.current_weight +
|
||||
production_capacity * params.production_weight;
|
||||
}
|
||||
|
||||
struct ThreatCalculationParams {
|
||||
int projection_months = 12; // Horizon projection (défaut 12 mois)
|
||||
float current_weight = 0.6f; // Poids forces actuelles (60%)
|
||||
float production_weight = 0.4f; // Poids production (40%)
|
||||
};
|
||||
```
|
||||
|
||||
**Personnalisation par entité** :
|
||||
- Company **agressive** : `current: 0.8, production: 0.2` (focus court-terme)
|
||||
- State **prudent** : `current: 0.4, production: 0.6` (focus long-terme)
|
||||
- PMC **réactif** : `current: 0.9, production: 0.1` (menace immédiate prioritaire)
|
||||
|
||||
## Évaluation Forces Actuelles
|
||||
|
||||
### Principe : Sword & Shield avec Effectiveness Float
|
||||
|
||||
Pour chaque domaine (terre, air, mer), on évalue :
|
||||
1. **Sword** (attaquant) : Capacités offensives
|
||||
2. **Shield** (défenseur) : Capacités défensives
|
||||
3. **Effectiveness** : Ratio pénétration/armure avec baseline 20% minimum
|
||||
|
||||
```cpp
|
||||
int evaluateCurrentForces(Entity attacker, Entity defender) {
|
||||
int land_threat = evaluateLandThreat(attacker, defender);
|
||||
int air_threat = evaluateAirThreat(attacker, defender);
|
||||
int naval_threat = evaluateNavalThreat(attacker, defender);
|
||||
|
||||
return land_threat + air_threat + naval_threat;
|
||||
}
|
||||
```
|
||||
|
||||
## Système Armor vs Penetration
|
||||
|
||||
### Référence de Base
|
||||
|
||||
Chaque équipement possède des valeurs mesurables :
|
||||
|
||||
```cpp
|
||||
struct Tank {
|
||||
float armor_average; // Moyenne armure (mm RHA equivalent)
|
||||
int combat_value; // Valeur au combat
|
||||
int quantity;
|
||||
|
||||
// Exemple Leopard 2A7:
|
||||
// - Frontal: 950mm RHA
|
||||
// - Flancs: 200mm RHA
|
||||
// - Arrière: 100mm RHA
|
||||
// - Average (pondéré surface): ~400mm
|
||||
};
|
||||
|
||||
struct ATWeapon {
|
||||
float penetration; // Pénétration max (mm RHA)
|
||||
int combat_value;
|
||||
int quantity;
|
||||
|
||||
// Exemples:
|
||||
// - RPG-7: 260mm
|
||||
// - Milan Gen2: 530mm
|
||||
// - Javelin Gen3 (top-attack): 800mm
|
||||
// - Kornet Gen4+ (tandem): 1200mm
|
||||
};
|
||||
```
|
||||
|
||||
### Calcul Effectiveness (Float)
|
||||
|
||||
**Formule baseline 20%** : Toute arme reste dangereuse (flancs, arrière, chance)
|
||||
|
||||
```cpp
|
||||
float calculateCounterEffectiveness(ATWeapon weapon, Tank tank) {
|
||||
float pen_ratio = weapon.penetration / tank.armor_average;
|
||||
|
||||
// BASELINE 20% : TOUJOURS dangereux
|
||||
const float BASE_EFFECTIVENESS = 0.20f;
|
||||
|
||||
if (pen_ratio >= 1.0f) {
|
||||
// Arme peut percer : scaling jusqu'à 90% max
|
||||
float bonus = (pen_ratio - 1.0f) * 0.5f;
|
||||
return min(0.90f, BASE_EFFECTIVENESS + bonus);
|
||||
}
|
||||
else {
|
||||
// Arme sous-dimensionnée : reste à 20% (flancs, arrière, chance)
|
||||
return BASE_EFFECTIVENESS;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exemples Effectiveness
|
||||
|
||||
```cpp
|
||||
// Leopard 2A7 (armor_avg = 400mm) vs différentes armes
|
||||
|
||||
RPG-7 (260mm) :
|
||||
pen_ratio = 260 / 400 = 0.65
|
||||
effectiveness = 20%
|
||||
→ 100 RPG-7 needed = 20 "équivalents kill"
|
||||
→ Coût: 100 × 500€ = 50k€ vs Leopard 8M€ = 0.625% ratio
|
||||
→ Menace présente mais faible, économiquement viable en masse
|
||||
|
||||
Milan Gen2 (530mm) :
|
||||
pen_ratio = 530 / 400 = 1.325
|
||||
effectiveness = 20% + (0.325 × 0.5) = 36.25%
|
||||
→ ~3 missiles = 1 kill probable
|
||||
→ Menace sérieuse
|
||||
|
||||
Javelin Gen3 (800mm top-attack) :
|
||||
pen_ratio = 800 / 400 = 2.0
|
||||
effectiveness = 20% + (1.0 × 0.5) = 70%
|
||||
→ ~1.5 missiles = 1 kill probable
|
||||
→ Menace très élevée
|
||||
|
||||
Kornet Gen4+ (1200mm tandem) :
|
||||
pen_ratio = 1200 / 400 = 3.0
|
||||
effectiveness = 20% + (2.0 × 0.5) = 90% (plafonné)
|
||||
→ ~1.1 missiles = 1 kill quasi-certain
|
||||
→ Menace maximale
|
||||
```
|
||||
|
||||
## Évaluation Domaine Terrestre
|
||||
|
||||
### Inventaire Forces
|
||||
|
||||
**Attaquant** :
|
||||
```cpp
|
||||
struct LandForces {
|
||||
std::vector<Tank> tanks;
|
||||
std::vector<IFV> ifvs;
|
||||
std::vector<APC> apcs;
|
||||
std::vector<Artillery> artillery;
|
||||
std::vector<Infantry> infantry;
|
||||
};
|
||||
```
|
||||
|
||||
**Défenseur** :
|
||||
```cpp
|
||||
struct LandDefenses {
|
||||
std::vector<ATSystem> anti_tank; // Systèmes anti-char
|
||||
std::vector<Tank> counter_tanks; // Tanks défensifs
|
||||
std::vector<Infantry> anti_tank_inf; // Infanterie AT
|
||||
std::vector<Fortification> fortifications;
|
||||
};
|
||||
```
|
||||
|
||||
### Couples Équipement ↔ Contre-mesures
|
||||
|
||||
**Principe** : Chaque type d'équipement offensif a des contre-mesures spécifiques.
|
||||
|
||||
```cpp
|
||||
struct EquipmentCounters {
|
||||
std::map<EquipmentType, std::vector<CounterType>> counters = {
|
||||
{TANK, {AT_MISSILE, AT_GUN, COUNTER_TANK, AT_INFANTRY}},
|
||||
{IFV, {AT_MISSILE, AT_GUN, AUTOCANNON}},
|
||||
{APC, {AUTOCANNON, MACHINE_GUN, RPG}},
|
||||
{INFANTRY, {MACHINE_GUN, ARTILLERY, AUTOCANNON}},
|
||||
{ARTILLERY, {COUNTER_BATTERY, AIR_STRIKE}}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Calcul Defensive Effectiveness
|
||||
|
||||
```cpp
|
||||
float calculateDefensiveEffectiveness(
|
||||
std::vector<Equipment> swords,
|
||||
std::vector<Defense> shields
|
||||
) {
|
||||
float total_sword_value = 0;
|
||||
float neutralized_value = 0;
|
||||
|
||||
for (auto& sword : swords) {
|
||||
float sword_value = sword.quantity * sword.combat_value;
|
||||
total_sword_value += sword_value;
|
||||
|
||||
// Trouver défenses applicables
|
||||
auto applicable_shields = findApplicableDefenses(sword, shields);
|
||||
|
||||
// Calculer valeur défensive totale contre ce sword
|
||||
float shield_value = 0;
|
||||
for (auto& shield : applicable_shields) {
|
||||
// ✅ EFFECTIVENESS FLOAT (20%-90%)
|
||||
float effectiveness = calculateCounterEffectiveness(shield, sword);
|
||||
shield_value += shield.quantity * shield.combat_value * effectiveness;
|
||||
}
|
||||
|
||||
// Neutralisation proportionnelle
|
||||
float neutralization = min(1.0f, shield_value / sword_value);
|
||||
neutralized_value += sword_value * neutralization;
|
||||
}
|
||||
|
||||
return total_sword_value > 0 ? (neutralized_value / total_sword_value) : 0.0f;
|
||||
}
|
||||
```
|
||||
|
||||
### Score Final avec Menace Résiduelle
|
||||
|
||||
```cpp
|
||||
int evaluateLandThreat(Entity attacker, Entity defender) {
|
||||
auto swords = attacker.getLandForces();
|
||||
auto shields = defender.getLandDefenses();
|
||||
|
||||
// Menace brute (sans défenses)
|
||||
int raw_threat = 0;
|
||||
for (auto& sword : swords) {
|
||||
raw_threat += sword.quantity * sword.combat_value;
|
||||
}
|
||||
|
||||
// Réduction par défenses
|
||||
float defensive_effectiveness = calculateDefensiveEffectiveness(swords, shields);
|
||||
|
||||
// ✅ MENACE RÉSIDUELLE : Jamais totalement nulle si attaquant existe
|
||||
float residual_multiplier = max(0.05f, 1.0f - defensive_effectiveness);
|
||||
int final_threat = raw_threat * residual_multiplier;
|
||||
|
||||
return final_threat;
|
||||
}
|
||||
```
|
||||
|
||||
## Exemples Concrets Terre
|
||||
|
||||
### Exemple 1 : Tech Obsolète Viable en Masse
|
||||
|
||||
**Attaquant** :
|
||||
- 20 tanks Gen4 (Leopard 2A7)
|
||||
- armor_average : 400mm RHA
|
||||
- combat_value : 1000/tank
|
||||
- Menace brute : 20 000
|
||||
- Valeur totale : 20 × 8M€ = 160M€
|
||||
|
||||
**Défenseur** :
|
||||
- 5000 RPG-7 (Gen1, ancien)
|
||||
- penetration : 260mm
|
||||
- pen_ratio : 260/400 = 0.65
|
||||
- effectiveness : 20% (baseline)
|
||||
- combat_value : 50/RPG
|
||||
- shield_value : 5000 × 50 × 0.20 = 50 000
|
||||
- Coût : 5000 × 500€ = 2.5M€
|
||||
|
||||
**Résultat** :
|
||||
```
|
||||
defensive_effectiveness = min(1.0, 50000 / 20000) = 100%
|
||||
residual_multiplier = max(0.05, 1.0 - 1.0) = 5%
|
||||
final_threat = 20000 × 0.05 = 1 000
|
||||
|
||||
→ Menace quasi-neutralisée (5% résiduel)
|
||||
→ Nécessite 5000 RPG-7 (masse logistique)
|
||||
→ Ratio coût défenseur/attaquant = 2.5M€ / 160M€ = 1.56%
|
||||
→ Défense économiquement viable ✅
|
||||
→ MAIS perte Leopard reste désastre (8M€ + prestige + formation)
|
||||
```
|
||||
|
||||
### Exemple 2 : Tech Moderne Efficace
|
||||
|
||||
**Attaquant** :
|
||||
- 20 tanks Gen4 (Leopard 2A7)
|
||||
- armor_average : 400mm
|
||||
- Menace brute : 20 000
|
||||
|
||||
**Défenseur** :
|
||||
- 100 missiles Javelin Gen3
|
||||
- penetration : 800mm (top-attack)
|
||||
- pen_ratio : 800/400 = 2.0
|
||||
- effectiveness : 70%
|
||||
- combat_value : 300/missile
|
||||
- shield_value : 100 × 300 × 0.70 = 21 000
|
||||
- Coût : 100 × 200k€ = 20M€
|
||||
|
||||
**Résultat** :
|
||||
```
|
||||
defensive_effectiveness = min(1.0, 21000 / 20000) = 100%
|
||||
residual_multiplier = 5%
|
||||
final_threat = 20000 × 0.05 = 1 000
|
||||
|
||||
→ Menace quasi-neutralisée
|
||||
→ Ratio coût : 20M€ / 160M€ = 12.5%
|
||||
→ Plus cher que RPG-7 mais logistique simplifiée (100 vs 5000)
|
||||
```
|
||||
|
||||
### Exemple 3 : Défense Insuffisante
|
||||
|
||||
**Attaquant** :
|
||||
- 20 tanks Gen4
|
||||
- Menace brute : 20 000
|
||||
|
||||
**Défenseur** :
|
||||
- 500 RPG-7
|
||||
- effectiveness : 20%
|
||||
- shield_value : 500 × 50 × 0.20 = 5 000
|
||||
|
||||
**Résultat** :
|
||||
```
|
||||
defensive_effectiveness = 5000 / 20000 = 25%
|
||||
residual_multiplier = max(0.05, 0.75) = 75%
|
||||
final_threat = 20000 × 0.75 = 15 000
|
||||
|
||||
→ Menace reste élevée (75%)
|
||||
→ Défense insuffisante
|
||||
```
|
||||
|
||||
### Exemple 4 : Défense Mixte Économique
|
||||
|
||||
**Attaquant** :
|
||||
- 20 tanks Gen4
|
||||
- Menace brute : 20 000
|
||||
|
||||
**Défenseur** :
|
||||
- 30 Javelin Gen3 : shield = 30 × 300 × 0.70 = 6 300
|
||||
- 1000 RPG-7 : shield = 1000 × 50 × 0.20 = 10 000
|
||||
- **Shield total** : 16 300
|
||||
- **Coût total** : 30 × 200k€ + 1000 × 500€ = 6.5M€
|
||||
|
||||
**Résultat** :
|
||||
```
|
||||
defensive_effectiveness = 16300 / 20000 = 81.5%
|
||||
residual_multiplier = max(0.05, 0.185) = 18.5%
|
||||
final_threat = 20000 × 0.185 = 3 700
|
||||
|
||||
→ Menace réduite à 18.5% (acceptable)
|
||||
→ Défense mixte optimise coût-efficacité
|
||||
→ Ratio coût : 6.5M€ / 160M€ = 4.06%
|
||||
```
|
||||
|
||||
### Exemple 5 : Système de Conception Modulaire - Retrofit Anti-AT
|
||||
|
||||
**Attaquant** :
|
||||
- 20 tanks Leopard 2A7 **retrofittés Gen5**
|
||||
- Chassis Gen4 base
|
||||
- **APS Trophy Gen5** : intercepte 80% missiles avant impact
|
||||
- **ERA Gen5** : neutralise pénétration Gen2-3
|
||||
- armor_effective : 400mm × 2.5 (ERA bonus) = 1000mm equivalent
|
||||
- Menace brute : 20 000
|
||||
|
||||
**Défenseur** :
|
||||
- 1000 missiles Milan Gen2
|
||||
- penetration : 530mm
|
||||
- pen_ratio : 530/1000 = 0.53 (sous-dimensionné avec ERA)
|
||||
- effectiveness : 20% (baseline)
|
||||
- **APS reduction** : 20% × (1 - 0.80) = 4% effectiveness finale
|
||||
- shield_value : 1000 × 300 × 0.04 = 12 000
|
||||
|
||||
**Résultat** :
|
||||
```
|
||||
defensive_effectiveness = 12000 / 20000 = 60%
|
||||
residual_multiplier = max(0.05, 0.40) = 40%
|
||||
final_threat = 20000 × 0.40 = 8 000
|
||||
|
||||
→ Menace reste significative (40%)
|
||||
→ APS + ERA réduisent drastiquement effectiveness Gen2
|
||||
→ Système de conception permet adaptation doctrine
|
||||
→ Joueur peut designer tanks spécifiquement anti-saturation
|
||||
```
|
||||
|
||||
## Évaluation Domaine Aérien
|
||||
|
||||
### Spécificités Air
|
||||
|
||||
**Complexité supplémentaire** :
|
||||
- **Qualité prime** : Furtivité et ECM dominent
|
||||
- **ECM/ECCM** : Guerre électronique critique
|
||||
- **Compatibilité stricte** : AA anti-hélicoptère ne touche pas jets
|
||||
|
||||
```cpp
|
||||
struct AirForces {
|
||||
std::vector<Fighter> fighters;
|
||||
std::vector<Bomber> bombers;
|
||||
std::vector<Helicopter> helicopters;
|
||||
std::vector<Drone> drones;
|
||||
|
||||
// Capacités spéciales
|
||||
bool has_stealth;
|
||||
bool has_ecm; // Electronic Counter-Measures
|
||||
int electronic_warfare_level;
|
||||
};
|
||||
|
||||
struct AirDefenses {
|
||||
std::vector<AAMissile> aa_missiles;
|
||||
std::vector<AAGun> aa_guns;
|
||||
std::vector<Fighter> interceptors;
|
||||
|
||||
// Capacités
|
||||
bool has_eccm; // Electronic Counter-Counter-Measures
|
||||
int radar_quality;
|
||||
std::map<AASystem, TargetCapability> capabilities;
|
||||
};
|
||||
|
||||
enum TargetCapability {
|
||||
HELICOPTER_ONLY, // Seulement hélicoptères
|
||||
LOW_ALTITUDE, // Avions basse altitude
|
||||
HIGH_ALTITUDE, // Avions haute altitude
|
||||
ALL_AIRCRAFT // Tous types
|
||||
};
|
||||
```
|
||||
|
||||
### Effectiveness Air avec Stealth/ECM
|
||||
|
||||
```cpp
|
||||
float calculateAirDefenseEffectiveness(Aircraft aircraft, AASystem aa) {
|
||||
// Base effectiveness selon pénétration radar vs stealth
|
||||
float base_eff = calculateCounterEffectiveness(aa, aircraft);
|
||||
|
||||
// Multiplicateurs tech
|
||||
float stealth_reduction = 1.0f;
|
||||
if (aircraft.has_stealth && !aa.has_advanced_radar) {
|
||||
stealth_reduction = 1.0f - aircraft.stealth_rating; // Ex: 0.1 si 90% stealth
|
||||
}
|
||||
|
||||
float ecm_reduction = 1.0f;
|
||||
if (aircraft.has_ecm && !aa.has_eccm) {
|
||||
ecm_reduction = 1.0f - (aircraft.ecm_power / (aa.radar_quality + 1));
|
||||
}
|
||||
|
||||
// Effectiveness finale (baseline 20% toujours appliqué)
|
||||
float final_eff = max(0.20f, base_eff * stealth_reduction * ecm_reduction);
|
||||
|
||||
return final_eff;
|
||||
}
|
||||
```
|
||||
|
||||
### Exemple Air : Furtivité + ECM
|
||||
|
||||
**Attaquant** :
|
||||
- 20 jets furtifs Gen4 (F-35)
|
||||
- stealth_rating : 0.90 (réduit détection 90%)
|
||||
- ecm_power : 8
|
||||
- combat_value : 2000/jet
|
||||
- Menace brute : 40 000
|
||||
|
||||
**Défenseur** :
|
||||
- 1000 missiles AA Gen3 (Patriot)
|
||||
- radar_quality : 6
|
||||
- has_eccm : false
|
||||
- base_effectiveness : 70% (tech Gen3 vs Gen4)
|
||||
- stealth_reduction : 1.0 - 0.90 = 0.10
|
||||
- ecm_reduction : 1.0 - (8/7) = -0.14 → 0.0 (plancher)
|
||||
- final_effectiveness : max(0.20, 0.70 × 0.10 × 0.0) = 20% (baseline)
|
||||
- shield_value : 1000 × 400 × 0.20 = 80 000
|
||||
|
||||
**Résultat** :
|
||||
```
|
||||
defensive_effectiveness = min(1.0, 80000 / 40000) = 100%
|
||||
residual_multiplier = 5%
|
||||
final_threat = 40000 × 0.05 = 2 000
|
||||
|
||||
→ Furtivité + ECM ramènent effectiveness au baseline 20%
|
||||
→ Nécessite masse importante (1000 missiles) pour compenser
|
||||
→ F-35 peuvent accomplir raid avant saturation (menace 5% résiduelle)
|
||||
```
|
||||
|
||||
## Évaluation Domaine Naval
|
||||
|
||||
**Similaire à terrestre/aérien** mais avec spécificités :
|
||||
- **Torpilles vs sonars** (submersibles)
|
||||
- **Anti-ship missiles vs CIWS** (Close-In Weapon Systems)
|
||||
- **Portée extrême** : Naval combat à 100+ km
|
||||
|
||||
Structure identique avec couples spécifiques (penetration vs armor pour missiles anti-navire).
|
||||
|
||||
## Évaluation Production
|
||||
|
||||
### Principe
|
||||
|
||||
La menace ne vient pas seulement des forces actuelles, mais aussi de la **capacité à produire** plus d'équipements.
|
||||
|
||||
```cpp
|
||||
int evaluateProduction(Entity attacker, Entity defender, int projection_months) {
|
||||
int production_threat = 0;
|
||||
|
||||
// Pour chaque type d'équipement
|
||||
for (auto& equipment_type : all_equipment_types) {
|
||||
// Taux production attaquant
|
||||
int attacker_rate = attacker.getProductionRate(equipment_type); // unités/mois
|
||||
|
||||
// Taux production défenses défenseur
|
||||
int defender_rate = defender.getProductionRate(getCounterType(equipment_type));
|
||||
|
||||
// Projection future
|
||||
int attacker_produced = attacker_rate * projection_months;
|
||||
int defender_produced = defender_rate * projection_months;
|
||||
|
||||
// Menace nette production
|
||||
int net_production = attacker_produced - defender_produced;
|
||||
if (net_production > 0) {
|
||||
int equipment_value = getEquipmentValue(equipment_type);
|
||||
production_threat += net_production * equipment_value;
|
||||
}
|
||||
}
|
||||
|
||||
return production_threat;
|
||||
}
|
||||
```
|
||||
|
||||
### Exemple Production
|
||||
|
||||
**État A** :
|
||||
- Production actuelle : 50 tanks/mois
|
||||
- Projection 12 mois : 600 tanks
|
||||
- Combat value : 400/tank
|
||||
- Production threat : 600 × 400 = 240 000
|
||||
|
||||
**État B** (défenseur) :
|
||||
- Production AT : 100 missiles/mois
|
||||
- Projection 12 mois : 1200 missiles
|
||||
- Combat value : 300/missile
|
||||
- Effectiveness moyenne : 40%
|
||||
- Défense production : 1200 × 300 × 0.40 = 144 000
|
||||
|
||||
**Net production threat** :
|
||||
```
|
||||
Attacker gain : 240 000
|
||||
Defender gain : 144 000
|
||||
Net : 240 000 - 144 000 = 96 000
|
||||
|
||||
production_threat = 96 000
|
||||
|
||||
→ État A a avantage production malgré défenses
|
||||
```
|
||||
|
||||
## Agrégation Finale
|
||||
|
||||
### Formule Complète
|
||||
|
||||
```cpp
|
||||
int calculateThreat(Entity attacker, Entity defender) {
|
||||
auto params = attacker.getThreatParams();
|
||||
|
||||
// Forces actuelles (sword & shield par domaine)
|
||||
int land_threat = evaluateLandThreat(attacker, defender);
|
||||
int air_threat = evaluateAirThreat(attacker, defender);
|
||||
int naval_threat = evaluateNavalThreat(attacker, defender);
|
||||
|
||||
int current_military = land_threat + air_threat + naval_threat;
|
||||
|
||||
// Production future
|
||||
int production_threat = evaluateProduction(
|
||||
attacker,
|
||||
defender,
|
||||
params.projection_months
|
||||
);
|
||||
|
||||
// Pondération finale
|
||||
int total_threat = current_military * params.current_weight +
|
||||
production_threat * params.production_weight;
|
||||
|
||||
return total_threat;
|
||||
}
|
||||
```
|
||||
|
||||
### Exemples Complets
|
||||
|
||||
#### Superpower vs État Moyen
|
||||
|
||||
**USA vs France**
|
||||
|
||||
**USA forces** :
|
||||
- Tanks : 8000 (Gen3-4) → 3 200 000
|
||||
- Aircraft : 2000 (Gen4, furtifs) → 4 000 000
|
||||
- Naval : 500 ships → 2 500 000
|
||||
- **Total brut** : 9 700 000
|
||||
|
||||
**France défenses** :
|
||||
- AT systems : 3000 (Gen3, eff 60%) → Shield 60% tanks
|
||||
- AA systems : 1500 (Gen3, eff 40% vs furtifs) → Shield 40% aircraft
|
||||
- Naval defenses : 200 (eff 50%) → Shield 50% naval
|
||||
|
||||
**Après sword & shield** :
|
||||
- Land : 3 200 000 × max(0.05, 0.40) = 1 280 000
|
||||
- Air : 4 000 000 × max(0.05, 0.60) = 2 400 000
|
||||
- Naval : 2 500 000 × max(0.05, 0.50) = 1 250 000
|
||||
- **Current threat** : 4 930 000
|
||||
|
||||
**Production (12 mois)** :
|
||||
- USA : +600 tanks, +100 aircraft → 360 000
|
||||
- France : +100 tanks, +50 aircraft → 70 000
|
||||
- **Net production** : 290 000
|
||||
|
||||
**Total (60% current, 40% prod)** :
|
||||
```
|
||||
4 930 000 × 0.6 + 290 000 × 0.4 = 3 074 000
|
||||
|
||||
→ Menace colossale, mais France peut tenir avec alliances
|
||||
```
|
||||
|
||||
#### PMC vs Company
|
||||
|
||||
**PMC_Alpha vs RheinmetallCorp**
|
||||
|
||||
**PMC forces** :
|
||||
- Infantry : 500 (léger armement)
|
||||
- Vehicles : 20 APCs
|
||||
- **Total** : 50 000
|
||||
|
||||
**Rheinmetall défenses** :
|
||||
- Security : 100 guards (effectiveness 30%)
|
||||
- Fortifications : minimal
|
||||
- **Shield** : 15%
|
||||
|
||||
**Threat** :
|
||||
```
|
||||
residual = max(0.05, 1.0 - 0.15) = 85%
|
||||
final_threat = 50000 × 0.85 = 42 500
|
||||
|
||||
→ PMC peut menacer installations Company
|
||||
```
|
||||
|
||||
## Cas Spéciaux
|
||||
|
||||
### Menace Économique Pure
|
||||
|
||||
Pour Companies sans capacités militaires :
|
||||
|
||||
```cpp
|
||||
int calculateEconomicThreat(Company attacker, Company defender) {
|
||||
// Part de marché
|
||||
float market_dominance = attacker.market_share / (defender.market_share + 0.01f);
|
||||
|
||||
// Capacité production
|
||||
float production_ratio = attacker.production_capacity / defender.production_capacity;
|
||||
|
||||
// Qualité produits
|
||||
float quality_advantage = attacker.avg_product_quality / defender.avg_product_quality;
|
||||
|
||||
// Menace économique
|
||||
int economic_threat = (market_dominance * 100000) +
|
||||
(production_ratio * 80000) +
|
||||
(quality_advantage * 50000);
|
||||
|
||||
return economic_threat;
|
||||
}
|
||||
```
|
||||
|
||||
### Menace Géographique
|
||||
|
||||
Distance géographique module menace :
|
||||
|
||||
```cpp
|
||||
float getGeographicModifier(Entity attacker, Entity defender) {
|
||||
float distance_km = calculateDistance(attacker.position, defender.position);
|
||||
|
||||
// Projection power diminue avec distance
|
||||
if (distance_km < 500) {
|
||||
return 1.0f; // Menace pleine
|
||||
}
|
||||
else if (distance_km < 2000) {
|
||||
return 0.7f; // 30% réduction
|
||||
}
|
||||
else if (distance_km < 5000) {
|
||||
return 0.4f; // 60% réduction
|
||||
}
|
||||
else {
|
||||
return 0.1f; // 90% réduction (trop loin)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Implications Stratégiques
|
||||
|
||||
### 1. Coût-Efficacité Défensive
|
||||
|
||||
```cpp
|
||||
struct DefenseCostAnalysis {
|
||||
float threat_neutralized;
|
||||
float cost;
|
||||
float cost_efficiency; // menace neutralisée par €
|
||||
};
|
||||
|
||||
// Neutraliser 20 Leopard 2A7 (160M€ total)
|
||||
|
||||
Option A - RPG-7 masse (effectiveness 20%) :
|
||||
- Quantité nécessaire : 100 RPG × 20 tanks = 2000 RPG
|
||||
- Coût : 2000 × 500€ = 1M€
|
||||
- Ratio : 1M€ / 160M€ = 0.625%
|
||||
- Avantage : Très économique
|
||||
- Inconvénient : Logistique massive
|
||||
|
||||
Option B - Javelin Gen3 (effectiveness 70%) :
|
||||
- Quantité nécessaire : 1.5 Javelin × 20 tanks = 30 Javelin
|
||||
- Coût : 30 × 200k€ = 6M€
|
||||
- Ratio : 6M€ / 160M€ = 3.75%
|
||||
- Avantage : Logistique légère
|
||||
- Inconvénient : Plus cher
|
||||
|
||||
→ RPG-7 est 6× plus cost-efficient, mais logistique 67× plus lourde
|
||||
→ Choix stratégique selon capacités logistiques
|
||||
```
|
||||
|
||||
### 2. Perte Asymétrique
|
||||
|
||||
```cpp
|
||||
// Exemple bataille : Menace neutralisée mais pertes coûteuses
|
||||
|
||||
Attaquant : 20 Leopard 2A7 (160M€)
|
||||
Défenseur : 5000 RPG-7 (2.5M€)
|
||||
|
||||
Outcome tactique :
|
||||
- Tous Leopards détruits (saturation)
|
||||
- 2000 RPG-7 utilisés effectivement
|
||||
|
||||
Bilan stratégique :
|
||||
Attaquant pertes :
|
||||
- 160M€ équipement
|
||||
- 20 crews élites (formation coûteuse)
|
||||
- Prestige international
|
||||
- Capacités offensives réduites
|
||||
|
||||
Défenseur pertes :
|
||||
- 1M€ munitions consommées (2000 RPG effectifs)
|
||||
- +Victoire propagande
|
||||
- +Moral défensif
|
||||
|
||||
→ Victoire tactique défenseur = victoire stratégique
|
||||
→ Système menace reflète cette asymétrie via residual 5%
|
||||
→ Perdre Leopard = toujours désastre même si menace "neutralisée"
|
||||
```
|
||||
|
||||
## Performance et Optimisation
|
||||
|
||||
### Cache Threat
|
||||
|
||||
```cpp
|
||||
class ThreatCache {
|
||||
private:
|
||||
struct CachedThreat {
|
||||
int value;
|
||||
int timestamp;
|
||||
int ttl = 3600; // 1 heure
|
||||
};
|
||||
|
||||
std::map<std::pair<EntityId, EntityId>, CachedThreat> cache;
|
||||
|
||||
public:
|
||||
int getThreat(EntityId attacker, EntityId defender) {
|
||||
auto key = std::make_pair(attacker, defender);
|
||||
|
||||
if (cache.contains(key)) {
|
||||
auto& cached = cache[key];
|
||||
if (getCurrentTime() - cached.timestamp < cached.ttl) {
|
||||
return cached.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculer
|
||||
int threat = calculateThreat(attacker, defender);
|
||||
cache[key] = {threat, getCurrentTime()};
|
||||
return threat;
|
||||
}
|
||||
|
||||
void invalidate(EntityId entity) {
|
||||
// Invalider tous les caches impliquant cette entité
|
||||
for (auto it = cache.begin(); it != cache.end();) {
|
||||
if (it->first.first == entity || it->first.second == entity) {
|
||||
it = cache.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Invalidation Cache
|
||||
|
||||
Événements invalidant cache :
|
||||
- Production nouvelle unité
|
||||
- Perte unité au combat
|
||||
- Nouvelle recherche technologique
|
||||
- Changement doctrine militaire
|
||||
- Retrofit/upgrade équipement
|
||||
|
||||
### Calcul Lazy
|
||||
|
||||
```cpp
|
||||
// Ne calculer que si demandé par IA
|
||||
int getThreatOnDemand(EntityId attacker, EntityId defender) {
|
||||
return threatCache.getThreat(attacker, defender);
|
||||
}
|
||||
|
||||
// Pas de recalcul automatique chaque tick
|
||||
```
|
||||
|
||||
## Références Croisées
|
||||
|
||||
- `systeme-diplomatique.md` : Utilisation menace dans relations diplomatiques
|
||||
- `ai-framework.md` : Menace influence décisions IA (achats, alliances)
|
||||
- `systeme-militaire.md` : Valeurs combat équipements, générations, système conception modulaire
|
||||
- `economie-logistique.md` : Production rates, capacités industrielles
|
||||
1090
docs/systeme-diplomatique.md
Normal file
1090
docs/systeme-diplomatique.md
Normal file
File diff suppressed because it is too large
Load Diff
715
docs/systeme-sauvegarde.md
Normal file
715
docs/systeme-sauvegarde.md
Normal file
@ -0,0 +1,715 @@
|
||||
# Système de Sauvegarde
|
||||
|
||||
## Philosophie
|
||||
|
||||
Le système de sauvegarde suit la philosophie du projet : **évolution itérative avec versioning des systèmes**. Chaque version améliore progressivement les performances et fonctionnalités tout en maintenant la compatibilité.
|
||||
|
||||
Le système est conçu pour être **modulaire et autonome**, chaque module gérant sa propre persistence de manière indépendante.
|
||||
|
||||
## Version 1 : Save JSON Local Sans Versioning de Format
|
||||
|
||||
### Principes de Base
|
||||
|
||||
- **Format** : JSON pur pour lisibilité, debugging et édition manuelle
|
||||
- **Granularité** : Un fichier par module
|
||||
- **Distribution** : Chaque serveur sauvegarde localement (multi-serveur ready)
|
||||
- **Coordination** : Clé de save distribuée par le coordinateur
|
||||
- **Autonomie** : Chaque module implémente son propre `serialize()` / `deserialize()`
|
||||
- **Chunks** : Seulement les chunks modifiés (metachunks 512x512)
|
||||
- **Objectif** : Système fonctionnel et suffisant pour tests et développement
|
||||
|
||||
### Architecture de Fichiers
|
||||
|
||||
```
|
||||
saves/
|
||||
└── abc123_1728226320/ # Clé de save : [id]_[timestamp]
|
||||
├── save_metadata.json # Métadonnées globales de la save
|
||||
├── server_1/ # Un dossier par serveur (future-proof)
|
||||
│ ├── tank.json
|
||||
│ └── combat.json
|
||||
├── server_2/
|
||||
│ ├── economy.json
|
||||
│ └── factory.json
|
||||
└── metachunks/
|
||||
├── 0_0.json # Metachunk coords (x, y) en 512x512
|
||||
├── 0_1.json
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Note** : En configuration single-process V1, un seul dossier serveur existe (ex: `server_1/`), mais la structure supporte déjà le multi-serveur.
|
||||
|
||||
### Format save_metadata.json
|
||||
|
||||
Fichier global décrivant la sauvegarde complète :
|
||||
|
||||
```json
|
||||
{
|
||||
"save_key": "abc123_1728226320",
|
||||
"timestamp": "2025-10-06T14:32:00Z",
|
||||
"game_version": "0.1.0-alpha",
|
||||
"modules": {
|
||||
"tank": {
|
||||
"version": "0.1.15.3847",
|
||||
"load_status": "ok"
|
||||
},
|
||||
"economy": {
|
||||
"version": "0.2.8.1203",
|
||||
"load_status": "ok"
|
||||
},
|
||||
"factory": {
|
||||
"version": "0.1.20.4512",
|
||||
"load_status": "load_pending"
|
||||
},
|
||||
"transport": {
|
||||
"version": "0.1.5.982",
|
||||
"load_status": "ok"
|
||||
}
|
||||
},
|
||||
"metachunks_count": 42,
|
||||
"world_seed": 1847293847
|
||||
}
|
||||
```
|
||||
|
||||
**Champs** :
|
||||
- `save_key` : Identifiant unique de la save (format : `[id]_[timestamp_unix]`)
|
||||
- `timestamp` : Date/heure de sauvegarde (ISO 8601)
|
||||
- `game_version` : Version du jeu ayant créé la save
|
||||
- `modules` : État de chaque module sauvé
|
||||
- `version` : Version du module (voir `module-versioning.md`)
|
||||
- `load_status` : `"ok"`, `"load_pending"`, `"failed"`
|
||||
- `metachunks_count` : Nombre de metachunks sauvés
|
||||
- `world_seed` : Seed de génération procédurale
|
||||
|
||||
### Format Fichiers Modules
|
||||
|
||||
Chaque module implémente `IModuleSave` et définit son propre format JSON.
|
||||
|
||||
#### Exemple : tank.json
|
||||
|
||||
```json
|
||||
{
|
||||
"module_name": "tank",
|
||||
"module_version": "0.1.15.3847",
|
||||
"save_timestamp": "2025-10-06T14:32:00Z",
|
||||
"data": {
|
||||
"tanks": [
|
||||
{
|
||||
"id": "tank_001",
|
||||
"chassis_type": "m1_abrams",
|
||||
"position": {"x": 1250.5, "y": 3480.2},
|
||||
"rotation": 45.0,
|
||||
"components": [
|
||||
{
|
||||
"type": "turret_120mm",
|
||||
"grid_pos": [2, 3],
|
||||
"health": 100,
|
||||
"ammo_loaded": "apfsds"
|
||||
},
|
||||
{
|
||||
"type": "engine_turbine",
|
||||
"grid_pos": [1, 1],
|
||||
"health": 85,
|
||||
"fuel": 0.75
|
||||
}
|
||||
],
|
||||
"inventory": {
|
||||
"120mm_apfsds": 32,
|
||||
"120mm_heat": 18
|
||||
},
|
||||
"crew_status": "operational"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Exemple : economy.json
|
||||
|
||||
```json
|
||||
{
|
||||
"module_name": "economy",
|
||||
"module_version": "0.2.8.1203",
|
||||
"save_timestamp": "2025-10-06T14:32:00Z",
|
||||
"data": {
|
||||
"market_prices": {
|
||||
"iron_ore": 2.5,
|
||||
"copper_ore": 3.2,
|
||||
"steel_plate": 8.0
|
||||
},
|
||||
"player_balance": 125000,
|
||||
"pending_transactions": [
|
||||
{
|
||||
"id": "tx_4829",
|
||||
"type": "buy",
|
||||
"resource": "steel_plate",
|
||||
"quantity": 1000,
|
||||
"price_per_unit": 8.0,
|
||||
"timestamp": "2025-10-06T14:30:15Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Convention** : Chaque fichier module contient :
|
||||
- `module_name` : Nom du module (vérification cohérence)
|
||||
- `module_version` : Version du module ayant créé la save
|
||||
- `save_timestamp` : Timestamp de sauvegarde
|
||||
- `data` : Objet contenant toutes les données spécifiques au module
|
||||
|
||||
### Format Metachunks (512x512)
|
||||
|
||||
Pour réduire le nombre de fichiers, les chunks 64x64 sont regroupés en **metachunks 512x512** (8x8 chunks par metachunk = 64 chunks).
|
||||
|
||||
#### Structure Metachunk
|
||||
|
||||
```json
|
||||
{
|
||||
"metachunk_coords": {"x": 0, "y": 0},
|
||||
"metachunk_size": 512,
|
||||
"chunk_size": 64,
|
||||
"chunks": {
|
||||
"0_0": {
|
||||
"terrain": {
|
||||
"land_ids_base64": "AQIDBAUGBwg...",
|
||||
"roof_ids_base64": "CQAKAA..."
|
||||
},
|
||||
"buildings": [
|
||||
{
|
||||
"id": "building_factory_001",
|
||||
"type": "assembler_mk1",
|
||||
"position": {"x": 10, "y": 15},
|
||||
"recipe": "ammunition_7.62mm",
|
||||
"progress": 0.45,
|
||||
"inventory": {
|
||||
"iron_plate": 50,
|
||||
"copper_wire": 30
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"type": "iron_ore",
|
||||
"patch_id": "iron_patch_042",
|
||||
"positions": [[5,5], [5,6], [6,5], [6,6]],
|
||||
"amounts": [1000, 950, 980, 1020]
|
||||
}
|
||||
]
|
||||
},
|
||||
"0_1": {
|
||||
"terrain": { "land_ids_base64": "..." },
|
||||
"buildings": [],
|
||||
"resources": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Optimisations** :
|
||||
- **Base64 compression** : Données terrain denses compressées
|
||||
- **Sparse storage** : Chunks vides omis du metachunk
|
||||
- **Dirty tracking** : Seulement metachunks avec chunks modifiés sont sauvés
|
||||
|
||||
#### Calcul Coords Metachunk
|
||||
|
||||
```cpp
|
||||
// Chunk 64x64 coords → Metachunk 512x512 coords
|
||||
MetachunkCoords getMetachunkCoords(int chunkX, int chunkY) {
|
||||
return {
|
||||
chunkX / 8, // 512 / 64 = 8 chunks par metachunk
|
||||
chunkY / 8
|
||||
};
|
||||
}
|
||||
|
||||
// Coords locales dans le metachunk
|
||||
ChunkLocalCoords getLocalCoords(int chunkX, int chunkY) {
|
||||
return {
|
||||
chunkX % 8,
|
||||
chunkY % 8
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Interface IModuleSave
|
||||
|
||||
Chaque module implémente cette interface pour gérer sa persistence :
|
||||
|
||||
```cpp
|
||||
class IModuleSave {
|
||||
public:
|
||||
virtual ~IModuleSave() = default;
|
||||
|
||||
// Sérialise l'état complet du module en JSON
|
||||
virtual nlohmann::json serialize() = 0;
|
||||
|
||||
// Restaure l'état du module depuis JSON
|
||||
// Retourne true si succès, false si erreur (→ load_pending)
|
||||
virtual bool deserialize(const nlohmann::json& data) = 0;
|
||||
|
||||
// Version du module (auto-générée, voir module-versioning.md)
|
||||
virtual std::string getVersion() const = 0;
|
||||
};
|
||||
```
|
||||
|
||||
#### Exemple Implémentation
|
||||
|
||||
```cpp
|
||||
class TankModule : public IModule, public IModuleSave {
|
||||
private:
|
||||
std::vector<Tank> tanks;
|
||||
|
||||
public:
|
||||
nlohmann::json serialize() override {
|
||||
json data;
|
||||
data["module_name"] = "tank";
|
||||
data["module_version"] = getVersion();
|
||||
data["save_timestamp"] = getCurrentTimestamp();
|
||||
|
||||
json tanksArray = json::array();
|
||||
for (const auto& tank : tanks) {
|
||||
tanksArray.push_back(tank.toJson());
|
||||
}
|
||||
data["data"]["tanks"] = tanksArray;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool deserialize(const json& data) override {
|
||||
try {
|
||||
// Validation version
|
||||
if (data["module_name"] != "tank") {
|
||||
LOG_ERROR("Invalid module name in save file");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Charge les tanks
|
||||
tanks.clear();
|
||||
for (const auto& tankJson : data["data"]["tanks"]) {
|
||||
tanks.push_back(Tank::fromJson(tankJson));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR("Deserialization failed: {}", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getVersion() const override {
|
||||
return MODULE_VERSION; // Défini par CMake
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Workflow de Sauvegarde
|
||||
|
||||
#### Déclenchement
|
||||
|
||||
**En single-process** :
|
||||
```cpp
|
||||
saveSystem->saveGame("abc123");
|
||||
```
|
||||
|
||||
**En multi-serveur** :
|
||||
Le coordinateur broadcast une clé de save :
|
||||
```cpp
|
||||
// Coordinateur
|
||||
coordinator->broadcastSaveCommand("abc123_1728226320");
|
||||
|
||||
// Chaque serveur reçoit et exécute
|
||||
void Server::onSaveCommand(const std::string& saveKey) {
|
||||
saveSystem->saveGame(saveKey);
|
||||
}
|
||||
```
|
||||
|
||||
#### Processus de Sauvegarde
|
||||
|
||||
```cpp
|
||||
void SaveSystem::saveGame(const std::string& saveKey) {
|
||||
auto startTime = std::chrono::steady_clock::now();
|
||||
|
||||
// 1. Créer structure de dossiers
|
||||
std::string savePath = "saves/" + saveKey + "/";
|
||||
fs::create_directories(savePath + "server_1/");
|
||||
fs::create_directories(savePath + "metachunks/");
|
||||
|
||||
// 2. Sauvegarder chaque module
|
||||
json metadata;
|
||||
metadata["save_key"] = saveKey;
|
||||
metadata["timestamp"] = getCurrentTimestamp();
|
||||
metadata["game_version"] = GAME_VERSION;
|
||||
|
||||
for (auto& module : moduleSystem->getAllModules()) {
|
||||
std::string moduleName = module->getName();
|
||||
|
||||
try {
|
||||
// Sérialiser module
|
||||
json moduleData = module->serialize();
|
||||
|
||||
// Écrire fichier
|
||||
std::string modulePath = savePath + "server_1/" +
|
||||
moduleName + ".json";
|
||||
writeJsonFile(modulePath, moduleData);
|
||||
|
||||
// Mettre à jour metadata
|
||||
metadata["modules"][moduleName] = {
|
||||
{"version", module->getVersion()},
|
||||
{"load_status", "ok"}
|
||||
};
|
||||
|
||||
LOG_INFO("Module {} saved successfully", moduleName);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR("Failed to save module {}: {}", moduleName, e.what());
|
||||
metadata["modules"][moduleName] = {
|
||||
{"version", module->getVersion()},
|
||||
{"load_status", "failed"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Sauvegarder metachunks modifiés
|
||||
int metachunkCount = 0;
|
||||
for (auto& [coords, metachunk] : dirtyMetachunks) {
|
||||
json metachunkData = metachunk->serialize();
|
||||
std::string filename = std::to_string(coords.x) + "_" +
|
||||
std::to_string(coords.y) + ".json";
|
||||
writeJsonFile(savePath + "metachunks/" + filename, metachunkData);
|
||||
metachunkCount++;
|
||||
}
|
||||
metadata["metachunks_count"] = metachunkCount;
|
||||
|
||||
// 4. Écrire metadata
|
||||
writeJsonFile(savePath + "save_metadata.json", metadata);
|
||||
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - startTime
|
||||
);
|
||||
|
||||
LOG_INFO("Save completed in {}ms: {} modules, {} metachunks",
|
||||
duration.count(), metadata["modules"].size(), metachunkCount);
|
||||
}
|
||||
```
|
||||
|
||||
### Workflow de Chargement
|
||||
|
||||
```cpp
|
||||
void SaveSystem::loadGame(const std::string& saveKey) {
|
||||
std::string savePath = "saves/" + saveKey + "/";
|
||||
|
||||
// 1. Charger metadata
|
||||
json metadata = readJsonFile(savePath + "save_metadata.json");
|
||||
|
||||
// Validation game version (warning seulement en V1)
|
||||
if (metadata["game_version"] != GAME_VERSION) {
|
||||
LOG_WARN("Save created with different game version: {} vs {}",
|
||||
metadata["game_version"], GAME_VERSION);
|
||||
}
|
||||
|
||||
// 2. Charger world data (seed, params)
|
||||
worldGenerator->setSeed(metadata["world_seed"]);
|
||||
|
||||
// 3. Charger chaque module
|
||||
for (auto& module : moduleSystem->getAllModules()) {
|
||||
std::string moduleName = module->getName();
|
||||
std::string modulePath = savePath + "server_1/" +
|
||||
moduleName + ".json";
|
||||
|
||||
if (!fs::exists(modulePath)) {
|
||||
LOG_WARN("No save file for module {}, using defaults", moduleName);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
json moduleData = readJsonFile(modulePath);
|
||||
|
||||
// Vérification version module
|
||||
std::string savedVersion = moduleData["module_version"];
|
||||
std::string currentVersion = module->getVersion();
|
||||
|
||||
if (savedVersion != currentVersion) {
|
||||
LOG_WARN("Module {} version mismatch: save={}, current={}",
|
||||
moduleName, savedVersion, currentVersion);
|
||||
}
|
||||
|
||||
// Désérialiser
|
||||
bool success = module->deserialize(moduleData);
|
||||
|
||||
if (!success) {
|
||||
LOG_ERROR("Module {} deserialization failed, marked as load_pending",
|
||||
moduleName);
|
||||
metadata["modules"][moduleName]["load_status"] = "load_pending";
|
||||
}
|
||||
else {
|
||||
LOG_INFO("Module {} loaded successfully", moduleName);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR("Failed to load module {}: {}", moduleName, e.what());
|
||||
metadata["modules"][moduleName]["load_status"] = "load_pending";
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Metachunks chargés à la demande (streaming)
|
||||
// Voir Chunk Streaming ci-dessous
|
||||
|
||||
LOG_INFO("Save loaded: {}", saveKey);
|
||||
}
|
||||
```
|
||||
|
||||
### Chunk Streaming
|
||||
|
||||
Les metachunks ne sont **pas tous chargés au démarrage** pour économiser la mémoire. Système de chargement à la demande :
|
||||
|
||||
```cpp
|
||||
Chunk* ChunkManager::getChunk(int x, int y) {
|
||||
ChunkCoords coords{x, y};
|
||||
|
||||
// 1. Vérifier si déjà en RAM
|
||||
if (loadedChunks.contains(coords)) {
|
||||
return loadedChunks[coords];
|
||||
}
|
||||
|
||||
// 2. Calculer metachunk parent
|
||||
MetachunkCoords metaCoords = getMetachunkCoords(x, y);
|
||||
ChunkLocalCoords localCoords = getLocalCoords(x, y);
|
||||
|
||||
// 3. Charger metachunk si nécessaire
|
||||
if (!loadedMetachunks.contains(metaCoords)) {
|
||||
loadMetachunk(metaCoords);
|
||||
}
|
||||
|
||||
// 4. Extraire chunk du metachunk
|
||||
Metachunk* metachunk = loadedMetachunks[metaCoords];
|
||||
Chunk* chunk = metachunk->getChunk(localCoords);
|
||||
|
||||
if (chunk) {
|
||||
loadedChunks[coords] = chunk;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// 5. Si chunk n'existe pas dans save → génération procédurale
|
||||
return generateNewChunk(coords);
|
||||
}
|
||||
|
||||
void ChunkManager::loadMetachunk(MetachunkCoords coords) {
|
||||
std::string path = "saves/" + currentSave + "/metachunks/" +
|
||||
std::to_string(coords.x) + "_" +
|
||||
std::to_string(coords.y) + ".json";
|
||||
|
||||
if (!fs::exists(path)) {
|
||||
// Metachunk pas encore exploré/modifié
|
||||
loadedMetachunks[coords] = new Metachunk(coords);
|
||||
return;
|
||||
}
|
||||
|
||||
// Charger et désérialiser metachunk
|
||||
json metachunkData = readJsonFile(path);
|
||||
Metachunk* metachunk = new Metachunk(coords);
|
||||
metachunk->deserialize(metachunkData);
|
||||
|
||||
loadedMetachunks[coords] = metachunk;
|
||||
LOG_DEBUG("Metachunk loaded: ({}, {})", coords.x, coords.y);
|
||||
}
|
||||
```
|
||||
|
||||
### Gestion des Erreurs : load_pending
|
||||
|
||||
Lorsqu'un module échoue à charger (JSON corrompu, incompatibilité version, etc.), il est marqué `load_pending` dans le metadata.
|
||||
|
||||
#### Workflow de Récupération
|
||||
|
||||
```cpp
|
||||
// Au chargement, si erreur détectée
|
||||
if (!module->deserialize(moduleData)) {
|
||||
metadata["modules"][moduleName]["load_status"] = "load_pending";
|
||||
|
||||
// Sauvegarder metadata mis à jour
|
||||
writeJsonFile(savePath + "save_metadata.json", metadata);
|
||||
|
||||
// Continuer le chargement des autres modules
|
||||
}
|
||||
```
|
||||
|
||||
#### Interface Utilisateur
|
||||
|
||||
```cpp
|
||||
void UI::displayLoadPendingModules() {
|
||||
for (const auto& [moduleName, info] : metadata["modules"].items()) {
|
||||
if (info["load_status"] == "load_pending") {
|
||||
std::cout << "[WARNING] Module '" << moduleName
|
||||
<< "' failed to load. Check logs and fix JSON file.\n";
|
||||
std::cout << " File: saves/" << saveKey << "/server_1/"
|
||||
<< moduleName << ".json\n";
|
||||
std::cout << " Version: " << info["version"] << "\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Retry Manuel
|
||||
|
||||
Après avoir corrigé le fichier JSON manuellement :
|
||||
|
||||
```cpp
|
||||
void SaveSystem::retryLoadModule(const std::string& moduleName) {
|
||||
auto module = moduleSystem->getModule(moduleName);
|
||||
std::string modulePath = savePath + "server_1/" + moduleName + ".json";
|
||||
|
||||
try {
|
||||
json moduleData = readJsonFile(modulePath);
|
||||
bool success = module->deserialize(moduleData);
|
||||
|
||||
if (success) {
|
||||
metadata["modules"][moduleName]["load_status"] = "ok";
|
||||
writeJsonFile(savePath + "save_metadata.json", metadata);
|
||||
LOG_INFO("Module {} successfully reloaded", moduleName);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR("Retry failed for module {}: {}", moduleName, e.what());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dirty Tracking
|
||||
|
||||
Seuls les chunks/metachunks **modifiés** sont sauvegardés pour optimiser la taille des saves.
|
||||
|
||||
```cpp
|
||||
class ChunkManager {
|
||||
private:
|
||||
std::unordered_set<MetachunkCoords> dirtyMetachunks;
|
||||
|
||||
public:
|
||||
void markChunkDirty(int chunkX, int chunkY) {
|
||||
MetachunkCoords metaCoords = getMetachunkCoords(chunkX, chunkY);
|
||||
dirtyMetachunks.insert(metaCoords);
|
||||
}
|
||||
|
||||
void onBuildingPlaced(int x, int y) {
|
||||
int chunkX = x / 64;
|
||||
int chunkY = y / 64;
|
||||
markChunkDirty(chunkX, chunkY);
|
||||
}
|
||||
|
||||
void onResourceMined(int x, int y) {
|
||||
int chunkX = x / 64;
|
||||
int chunkY = y / 64;
|
||||
markChunkDirty(chunkX, chunkY);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Performance Targets V1
|
||||
|
||||
- **Autosave** : < 100ms pause perceptible (background thread recommandé)
|
||||
- **Save manuelle** : < 500ms acceptable (avec feedback UI)
|
||||
- **Load game** : < 3 secondes pour metadata + modules
|
||||
- **Chunk streaming** : < 16ms par metachunk (1 frame @60fps)
|
||||
- **Taille save** : ~10-50MB pour partie moyenne (dépend exploration)
|
||||
|
||||
### Limitations V1
|
||||
|
||||
Ces limitations seront résolues dans les versions futures :
|
||||
|
||||
1. **Pas de migration format** : Si le format JSON d'un module change, incompatibilité
|
||||
2. **JSON verbeux** : Fichiers volumineux comparé à format binaire (acceptable pour debug)
|
||||
3. **Pas de compression** : Taille disque non optimale
|
||||
4. **Pas de checksums** : Corruption de données détectée tard (au parsing JSON)
|
||||
5. **Concurrence limitée** : Save/load synchrones (pas de multi-threading)
|
||||
|
||||
## Évolution Future
|
||||
|
||||
### Version 2 : Compression et Migration
|
||||
|
||||
- **Compression LZ4/Zstd** : Réduction 60-80% taille fichiers
|
||||
- **Format binaire optionnel** : MessagePack ou Protobuf pour données volumineuses
|
||||
- **Migration automatique** : Système de conversion entre versions de format
|
||||
- **Checksums** : Validation intégrité (CRC32, SHA256)
|
||||
- **Async I/O** : Save/load en background threads
|
||||
|
||||
### Version 3 : Incremental Saves
|
||||
|
||||
- **Delta encoding** : Sauvegardes différentielles (snapshot + journal de changements)
|
||||
- **Rollback temporel** : Restaurer état à timestamp spécifique
|
||||
- **Compression inter-saves** : Déduplication entre sauvegardes
|
||||
- **Hot-save** : Sauvegarde pendant le jeu sans pause
|
||||
|
||||
### Version 4 : Cloud et Multiplayer
|
||||
|
||||
- **Synchronisation cloud** : Steam Cloud, Google Drive, etc.
|
||||
- **Save distribué** : Réplication multi-serveur automatique
|
||||
- **Conflict resolution** : Merge intelligent pour multiplayer
|
||||
- **Versioning git-like** : Branches, merge, rollback
|
||||
|
||||
## Références Croisées
|
||||
|
||||
- `module-versioning.md` : Système de versioning automatique des modules
|
||||
- `architecture-modulaire.md` : Interface IModule, contraintes autonomie
|
||||
- `systemes-techniques.md` : Architecture chunks multi-échelle
|
||||
- `map-system.md` : Génération procédurale, resource patches
|
||||
- `metriques-joueur.md` : Métriques à sauvegarder (3.1GB analytics)
|
||||
|
||||
## Exemples Pratiques
|
||||
|
||||
### Créer une Nouvelle Save
|
||||
|
||||
```cpp
|
||||
// Single-process
|
||||
saveSystem->saveGame("my_first_base");
|
||||
|
||||
// Multi-serveur
|
||||
coordinator->broadcastSaveCommand("my_first_base_1728226320");
|
||||
```
|
||||
|
||||
### Charger une Save Existante
|
||||
|
||||
```cpp
|
||||
saveSystem->loadGame("my_first_base_1728226320");
|
||||
```
|
||||
|
||||
### Éditer une Save Manuellement
|
||||
|
||||
```bash
|
||||
# Ouvrir fichier module
|
||||
nano saves/abc123_1728226320/server_1/economy.json
|
||||
|
||||
# Modifier prix du marché
|
||||
# "iron_ore": 2.5 → "iron_ore": 5.0
|
||||
|
||||
# Recharger le module spécifique
|
||||
saveSystem->retryLoadModule("economy");
|
||||
```
|
||||
|
||||
### Lister les Saves Disponibles
|
||||
|
||||
```cpp
|
||||
std::vector<SaveInfo> SaveSystem::listSaves() {
|
||||
std::vector<SaveInfo> saves;
|
||||
|
||||
for (const auto& entry : fs::directory_iterator("saves/")) {
|
||||
if (!entry.is_directory()) continue;
|
||||
|
||||
std::string metadataPath = entry.path().string() + "/save_metadata.json";
|
||||
if (!fs::exists(metadataPath)) continue;
|
||||
|
||||
json metadata = readJsonFile(metadataPath);
|
||||
saves.push_back({
|
||||
.saveKey = metadata["save_key"],
|
||||
.timestamp = metadata["timestamp"],
|
||||
.gameVersion = metadata["game_version"],
|
||||
.moduleCount = metadata["modules"].size(),
|
||||
.metachunkCount = metadata["metachunks_count"]
|
||||
});
|
||||
}
|
||||
|
||||
// Trier par timestamp décroissant (plus récent en premier)
|
||||
std::sort(saves.begin(), saves.end(), [](const auto& a, const auto& b) {
|
||||
return a.timestamp > b.timestamp;
|
||||
});
|
||||
|
||||
return saves;
|
||||
}
|
||||
```
|
||||
164
gameData/Biomes/alpine.json
Normal file
164
gameData/Biomes/alpine.json
Normal file
@ -0,0 +1,164 @@
|
||||
{
|
||||
"biome_id": "alpine",
|
||||
"display_name": "Alpine",
|
||||
"description": "High-altitude mountain regions above treeline with extreme cold, intense UV radiation, and specialized cold-adapted vegetation",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 15,
|
||||
"token_requirements": {
|
||||
"temperature": {"max": 0, "condition": "below_freezing"},
|
||||
"elevation": {"min": 2000, "condition": "high_altitude"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"extreme_cold": true,
|
||||
"high_altitude_effects": true,
|
||||
"intense_uv_radiation": true,
|
||||
"short_growing_season": true,
|
||||
"strong_winds": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 2000,
|
||||
"typical_range": [2500, 4000],
|
||||
"formation_zone": "above_treeline"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by combination of cold temperatures (≤0°C) and high elevation (≥2000m)",
|
||||
"geographic_distribution": "Mountain peaks and high plateaus above treeline",
|
||||
"rarity": "Uncommon - limited to high mountain areas",
|
||||
"minimum_area": 25,
|
||||
"typical_area_range": [50, 300]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "alpine_specialists",
|
||||
"secondary": ["alpine_grasses", "cushion_plants", "mountain_wildflowers", "dwarf_conifers"],
|
||||
"characteristics": [
|
||||
"extremely_low_growth_forms",
|
||||
"cold_and_wind_adaptation",
|
||||
"UV_radiation_protection",
|
||||
"short_intense_growing_season",
|
||||
"deep_root_systems"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Above treeline - only specialized alpine plants survive extreme conditions"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"altitude_extremes": 3.0,
|
||||
"temperature_extremes": 2.8,
|
||||
"uv_radiation": 2.9,
|
||||
"wind_exposure": 2.7,
|
||||
"oxygen_levels": 0.6,
|
||||
"growing_season": 0.3,
|
||||
"biodiversity": 0.8
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"mineral_extraction": 2.2,
|
||||
"rare_earth_elements": 2.0,
|
||||
"precious_metals": 1.8,
|
||||
"glacial_water": 1.6,
|
||||
"wind_energy": 2.1,
|
||||
"solar_energy": 1.7,
|
||||
"agriculture": 0.0,
|
||||
"forestry": 0.0,
|
||||
"tourism": 1.8,
|
||||
"research_value": 2.4
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"extreme_altitude_engineering",
|
||||
"wind_and_cold_resistance",
|
||||
"oxygen_supplementation_systems",
|
||||
"helicopter_or_cable_access"
|
||||
],
|
||||
"advantages": [
|
||||
"rich_mineral_deposits",
|
||||
"excellent_wind_and_solar_exposure",
|
||||
"natural_isolation_and_security",
|
||||
"fresh_water_sources_from_glaciers"
|
||||
],
|
||||
"challenges": [
|
||||
"extreme_construction_costs",
|
||||
"altitude_sickness_for_workers",
|
||||
"limited_access_and_logistics",
|
||||
"equipment_stress_from_conditions"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_fortress": 3.2,
|
||||
"altitude_advantage": 2.8,
|
||||
"difficult_approach": 3.0
|
||||
},
|
||||
"economic_factors": {
|
||||
"mining_bonus": 2.2,
|
||||
"construction_costs": 3.8,
|
||||
"transportation_costs": 3.5,
|
||||
"energy_generation_bonus": 1.9
|
||||
},
|
||||
"strategic_value": {
|
||||
"territorial_control": 2.9,
|
||||
"observation_posts": 3.0,
|
||||
"resource_monopoly": 2.4
|
||||
}
|
||||
},
|
||||
|
||||
"altitude_effects": {
|
||||
"oxygen_reduction": "significant_breathing_difficulty",
|
||||
"atmospheric_pressure": "reduced_pressure_affects_equipment",
|
||||
"temperature_lapse": "colder_with_increasing_elevation",
|
||||
"uv_intensity": "increased_radiation_exposure"
|
||||
},
|
||||
|
||||
"seasonal_extremes": {
|
||||
"winter": {
|
||||
"conditions": "extreme_cold_and_snow_cover",
|
||||
"accessibility": "extremely_limited",
|
||||
"survival": "life_threatening_conditions"
|
||||
},
|
||||
"summer": {
|
||||
"conditions": "brief_growing_season",
|
||||
"accessibility": "limited_weather_windows",
|
||||
"activities": "peak_construction_and_research"
|
||||
}
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"mountain_goats",
|
||||
"alpine_birds",
|
||||
"high_altitude_insects",
|
||||
"cold_adapted_mammals"
|
||||
],
|
||||
"hunting_opportunities": 0.8,
|
||||
"biodiversity": 0.8,
|
||||
"conservation_value": "unique_high_altitude_adaptations"
|
||||
},
|
||||
|
||||
"geological_features": {
|
||||
"exposed_bedrock": "minimal_soil_cover",
|
||||
"glacial_formations": "cirques_and_moraines",
|
||||
"talus_slopes": "unstable_rock_debris",
|
||||
"alpine_lakes": "pristine_high_altitude_water"
|
||||
},
|
||||
|
||||
"mountaineering_aspects": {
|
||||
"climbing_opportunities": 2.5,
|
||||
"avalanche_risk": 2.8,
|
||||
"weather_unpredictability": 3.0,
|
||||
"rescue_difficulty": 3.2
|
||||
},
|
||||
|
||||
"water_resources": {
|
||||
"glacial_melt": "seasonal_water_source",
|
||||
"alpine_springs": "pure_mountain_water",
|
||||
"snow_accumulation": "winter_water_storage",
|
||||
"watershed_importance": "supplies_lower_elevations"
|
||||
},
|
||||
|
||||
}
|
||||
141
gameData/Biomes/badlands.json
Normal file
141
gameData/Biomes/badlands.json
Normal file
@ -0,0 +1,141 @@
|
||||
{
|
||||
"biome_id": "badlands",
|
||||
"display_name": "Badlands",
|
||||
"description": "Harsh, wind-scoured regions with minimal vegetation, created by persistent high winds and limited rainfall",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 8,
|
||||
"token_requirements": {
|
||||
"highWind_tokens": {"min": 2, "condition": "above_storm_threshold"},
|
||||
"rain_tokens": {"max": 300, "condition": "insufficient_moisture"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"persistent_high_winds": true,
|
||||
"limited_rainfall": true,
|
||||
"extreme_temperature_variations": true,
|
||||
"severe_erosion": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 200,
|
||||
"maximum": 1500,
|
||||
"typical_range": [400, 1200],
|
||||
"formation_zone": "wind_exposed_continental_interiors"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by highWind_tokens in areas with insufficient rain_tokens",
|
||||
"geographic_distribution": "Interior continental areas with extreme wind exposure and low precipitation",
|
||||
"rarity": "Rare - requires extreme combination of high wind and low rainfall",
|
||||
"minimum_area": 75,
|
||||
"typical_area_range": [150, 600]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "sparse_wind_resistant",
|
||||
"secondary": ["hardy_cacti", "thorny_shrubs", "rock_lichens", "drought_adapted_grasses"],
|
||||
"characteristics": [
|
||||
"extremely_deep_roots",
|
||||
"water_storage_adaptations",
|
||||
"minimal_surface_area",
|
||||
"protective_spines_or_waxy_coatings"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Only the most resilient plants can survive the combination of wind and drought"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"wind_energy": 2.2,
|
||||
"erosion_rate": 2.8,
|
||||
"water_scarcity": 2.5,
|
||||
"temperature_extremes": 2.3,
|
||||
"soil_quality": 0.3,
|
||||
"biodiversity": 0.4
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"wind_energy": 2.2,
|
||||
"mineral_exposure": 1.8,
|
||||
"rare_earth_elements": 1.4,
|
||||
"solar_energy": 1.9,
|
||||
"geothermal_potential": 1.3,
|
||||
"agriculture": 0.1,
|
||||
"forestry": 0.0,
|
||||
"water_resources": 0.2,
|
||||
"industrial_suitability": 0.8,
|
||||
"tourism": 0.6
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"extreme_wind_resistance",
|
||||
"sandstorm_protection",
|
||||
"water_importation_systems",
|
||||
"temperature_resistant_materials"
|
||||
],
|
||||
"advantages": [
|
||||
"exceptional_wind_energy_sites",
|
||||
"exposed_mineral_deposits",
|
||||
"excellent_solar_exposure",
|
||||
"natural_isolation_for_sensitive_operations"
|
||||
],
|
||||
"challenges": [
|
||||
"extreme_construction_conditions",
|
||||
"constant_erosion_and_sandblasting",
|
||||
"water_scarcity",
|
||||
"equipment_maintenance_difficulties"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_fortress": 2.5,
|
||||
"difficult_terrain": 2.8,
|
||||
"visibility_reduction": 1.8
|
||||
},
|
||||
"economic_factors": {
|
||||
"construction_costs": 2.8,
|
||||
"maintenance_costs": 3.2,
|
||||
"resource_extraction_bonus": 1.6,
|
||||
"energy_generation_bonus": 2.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"natural_barrier": 2.7,
|
||||
"hidden_base_potential": 2.2,
|
||||
"resource_control": 1.9
|
||||
}
|
||||
},
|
||||
|
||||
"environmental_hazards": {
|
||||
"sandstorms": {
|
||||
"frequency": "frequent",
|
||||
"intensity": "severe",
|
||||
"effects": "equipment_damage_and_visibility_loss"
|
||||
},
|
||||
"flash_floods": {
|
||||
"frequency": "rare_but_devastating",
|
||||
"cause": "sudden_rainfall_on_hard_packed_earth",
|
||||
"effects": "temporary_impassable_terrain"
|
||||
},
|
||||
"temperature_extremes": {
|
||||
"daily_variation": "extreme",
|
||||
"seasonal_variation": "severe",
|
||||
"effects": "equipment_stress_and_human_discomfort"
|
||||
}
|
||||
},
|
||||
|
||||
"geological_features": {
|
||||
"exposed_rock_formations": "dramatic_geological_history_visible",
|
||||
"mineral_outcroppings": "rare_elements_accessible_at_surface",
|
||||
"wind_carved_formations": "unique_landscape_features",
|
||||
"erosion_patterns": "constantly_changing_topography"
|
||||
},
|
||||
|
||||
"survival_considerations": {
|
||||
"water_sources": "extremely_rare_and_precious",
|
||||
"shelter_requirements": "protection_from_wind_and_temperature",
|
||||
"navigation_challenges": "shifting_landmarks_and_poor_visibility",
|
||||
"supply_lines": "critical_for_any_operations"
|
||||
},
|
||||
|
||||
}
|
||||
215
gameData/Biomes/biome_index.json
Normal file
215
gameData/Biomes/biome_index.json
Normal file
@ -0,0 +1,215 @@
|
||||
{
|
||||
"biome_system_version": "1.0",
|
||||
"description": "Comprehensive biome definitions for WindRegion-based climate simulation system",
|
||||
"last_updated": "2024-09-29",
|
||||
|
||||
"classification_system": {
|
||||
"special_climate_zones": {
|
||||
"description": "Biomes created by extreme weather token accumulation",
|
||||
"priority_range": [1, 5],
|
||||
"evaluation_order": "first",
|
||||
"override_normal_biomes": true
|
||||
},
|
||||
"normal_biomes": {
|
||||
"description": "Standard biomes based on temperature and rainfall patterns",
|
||||
"priority_range": [10, 20],
|
||||
"evaluation_order": "second",
|
||||
"fallback_system": true
|
||||
}
|
||||
},
|
||||
|
||||
"biome_definitions": {
|
||||
"special_climate_zones": [
|
||||
{
|
||||
"biome_id": "wetlands",
|
||||
"file": "wetlands.json",
|
||||
"priority": 1,
|
||||
"token_requirement": "flood_tokens > flood_threshold",
|
||||
"description": "Marshes and swamps from recurring flooding patterns"
|
||||
},
|
||||
{
|
||||
"biome_id": "coastal_plain",
|
||||
"file": "coastal_plain.json",
|
||||
"priority": 2,
|
||||
"token_requirement": "rain_tokens >= 150 AND coastal_proximity <= 5",
|
||||
"description": "Low-lying coastal areas with maritime influence and salt-tolerant vegetation"
|
||||
},
|
||||
{
|
||||
"biome_id": "cliffs",
|
||||
"file": "cliffs.json",
|
||||
"priority": 3,
|
||||
"token_requirement": "elevation >= 50 AND coastal_proximity <= 2",
|
||||
"description": "Dramatic vertical coastal formations with extreme wind exposure"
|
||||
},
|
||||
{
|
||||
"biome_id": "sandy_coast",
|
||||
"file": "sandy_coast.json",
|
||||
"priority": 4,
|
||||
"token_requirement": "rain_tokens >= 100 AND coastal_proximity <= 3",
|
||||
"description": "Expansive sandy beaches and dune systems with tourism potential"
|
||||
},
|
||||
{
|
||||
"biome_id": "rocky_shore",
|
||||
"file": "rocky_shore.json",
|
||||
"priority": 5,
|
||||
"token_requirement": "rain_tokens >= 120 AND coastal_proximity <= 2",
|
||||
"description": "Rugged coastal areas with tidal pools and marine ecosystems"
|
||||
},
|
||||
{
|
||||
"biome_id": "hurricane_zone",
|
||||
"file": "hurricane_zone.json",
|
||||
"priority": 6,
|
||||
"token_requirement": "hurricane_tokens > 0",
|
||||
"description": "Storm-resistant coastal vegetation in hurricane-prone areas"
|
||||
},
|
||||
{
|
||||
"biome_id": "storm_prairie",
|
||||
"file": "storm_prairie.json",
|
||||
"priority": 7,
|
||||
"token_requirement": "highWind_tokens > storm_threshold AND rain_tokens > 300",
|
||||
"description": "Wind-resistant grasslands with adequate moisture"
|
||||
},
|
||||
{
|
||||
"biome_id": "badlands",
|
||||
"file": "badlands.json",
|
||||
"priority": 8,
|
||||
"token_requirement": "highWind_tokens > storm_threshold AND rain_tokens <= 300",
|
||||
"description": "Sparse vegetation in extreme wind and drought conditions"
|
||||
}
|
||||
],
|
||||
"normal_biomes": [
|
||||
{
|
||||
"biome_id": "tropical_rainforest",
|
||||
"file": "tropical_rainforest.json",
|
||||
"priority": 10,
|
||||
"requirements": "rain_tokens >= 500 AND temperature >= 25",
|
||||
"description": "Dense equatorial forests with maximum biodiversity"
|
||||
},
|
||||
{
|
||||
"biome_id": "hot_desert",
|
||||
"file": "hot_desert.json",
|
||||
"priority": 11,
|
||||
"requirements": "rain_tokens <= 50 AND temperature >= 20",
|
||||
"description": "Arid regions with minimal vegetation and extreme heat"
|
||||
},
|
||||
{
|
||||
"biome_id": "temperate_forest",
|
||||
"file": "temperate_forest.json",
|
||||
"priority": 12,
|
||||
"requirements": "rain_tokens >= 300 AND temperature >= 15 AND temperature <= 25",
|
||||
"description": "Seasonal forests in moderate climate zones"
|
||||
},
|
||||
{
|
||||
"biome_id": "grassland",
|
||||
"file": "grassland.json",
|
||||
"priority": 13,
|
||||
"requirements": "rain_tokens >= 200 AND temperature >= 10",
|
||||
"description": "Temperate grasslands ideal for agriculture"
|
||||
},
|
||||
{
|
||||
"biome_id": "tundra",
|
||||
"file": "tundra.json",
|
||||
"priority": 14,
|
||||
"requirements": "temperature <= -10",
|
||||
"description": "Arctic regions with permafrost and minimal vegetation"
|
||||
},
|
||||
{
|
||||
"biome_id": "alpine",
|
||||
"file": "alpine.json",
|
||||
"priority": 15,
|
||||
"requirements": "temperature <= 0 AND elevation >= 2000",
|
||||
"description": "High-altitude mountain regions above treeline"
|
||||
},
|
||||
{
|
||||
"biome_id": "cold_desert",
|
||||
"file": "cold_desert.json",
|
||||
"priority": 16,
|
||||
"requirements": "rain_tokens <= 30 AND temperature <= 10",
|
||||
"description": "High-altitude or high-latitude arid regions with cold temperatures"
|
||||
},
|
||||
{
|
||||
"biome_id": "hills",
|
||||
"file": "hills.json",
|
||||
"priority": 17,
|
||||
"requirements": "elevation >= 500 AND elevation <= 1500 AND rain_tokens >= 150",
|
||||
"description": "Rolling hill country with diverse microclimates and mixed vegetation"
|
||||
},
|
||||
{
|
||||
"biome_id": "rocky_plateau",
|
||||
"file": "rocky_plateau.json",
|
||||
"priority": 18,
|
||||
"requirements": "elevation >= 800 AND rain_tokens >= 100 AND rain_tokens <= 400",
|
||||
"description": "Elevated flat-topped terrain with exposed bedrock and hardy vegetation"
|
||||
},
|
||||
{
|
||||
"biome_id": "scrubland",
|
||||
"file": "scrubland.json",
|
||||
"priority": 1,
|
||||
"requirements": "fallback_biome",
|
||||
"description": "Semi-arid transition zones with sparse vegetation - default fallback biome"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"token_thresholds": {
|
||||
"climate_zone_tokens": {
|
||||
"storm_threshold": 2.0,
|
||||
"flood_threshold": 3.0,
|
||||
"hurricane_requirement": "wind >= 2.5 AND rain >= 2.0"
|
||||
},
|
||||
"normal_biome_tokens": {
|
||||
"rain_abundant": 500,
|
||||
"rain_moderate": 300,
|
||||
"rain_limited": 200,
|
||||
"rain_minimal": 50,
|
||||
"rain_very_minimal": 30
|
||||
},
|
||||
"temperature_ranges": {
|
||||
"tropical": 25,
|
||||
"temperate_warm": 20,
|
||||
"temperate_cool": 15,
|
||||
"cold": 10,
|
||||
"freezing": 0,
|
||||
"arctic": -10
|
||||
},
|
||||
"elevation_thresholds": {
|
||||
"sea_level": 0,
|
||||
"hills": 500,
|
||||
"mountains": 1000,
|
||||
"high_mountains": 2000,
|
||||
"alpine_zone": 2500
|
||||
}
|
||||
},
|
||||
|
||||
"biome_selection_algorithm": {
|
||||
"step_1": "Check special climate zone tokens (priority 1-5)",
|
||||
"step_2": "If no special zones match, evaluate normal biomes (priority 10+)",
|
||||
"step_3": "Use highest priority match, or fallback to 'scrubland' if none match",
|
||||
"step_4": "Apply forest feature integration for forest-compatible biomes"
|
||||
},
|
||||
|
||||
"integration_notes": {
|
||||
"climate_system": "Biomes are generated from accumulated tokens from mobile WindRegions",
|
||||
"congo_vs_sahara": "System designed to create tropical_rainforest (Congo) vs hot_desert (Sahara)",
|
||||
"token_accumulation": "Permanent climate record from WindRegion movements over 300 cycles",
|
||||
"special_zones": "Extreme weather creates unique biomes not found in traditional climate models",
|
||||
"forest_features": "Existing forest features from geological phases influence final biome selection"
|
||||
},
|
||||
|
||||
"validation_patterns": {
|
||||
"congo_basin": {
|
||||
"expected_biome": "tropical_rainforest",
|
||||
"token_pattern": "rain_tokens > 500 from ITCZ convergence",
|
||||
"latitude": "equatorial (45-55%)"
|
||||
},
|
||||
"sahara_desert": {
|
||||
"expected_biome": "hot_desert",
|
||||
"token_pattern": "rain_tokens < 50 due to no ITCZ influence",
|
||||
"latitude": "subtropical (25-35%)"
|
||||
},
|
||||
"hurricane_coasts": {
|
||||
"expected_biome": "hurricane_zone",
|
||||
"token_pattern": "hurricane_tokens from coastal storm activity"
|
||||
}
|
||||
}
|
||||
}
|
||||
156
gameData/Biomes/cliffs.json
Normal file
156
gameData/Biomes/cliffs.json
Normal file
@ -0,0 +1,156 @@
|
||||
{
|
||||
"biome_id": "cliffs",
|
||||
"display_name": "Coastal Cliffs",
|
||||
"description": "Dramatic vertical coastal formations with rugged terrain, seabird colonies and strategic defensive positions",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 3,
|
||||
"token_requirements": {
|
||||
"elevation": {"min": 50, "condition": "elevated_coastal_terrain"},
|
||||
"coastal_proximity": {"max": 2, "condition": "immediate_ocean_access"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"extreme_wind_exposure": true,
|
||||
"salt_spray_intense": true,
|
||||
"maritime_influence": true,
|
||||
"erosion_active": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 50,
|
||||
"maximum": 500,
|
||||
"typical_range": [100, 300],
|
||||
"formation_zone": "elevated_coastal_areas_with_vertical_drops"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by coastal elevation requirements with immediate ocean access",
|
||||
"geographic_distribution": "Vertical coastal formations and sea cliffs",
|
||||
"rarity": "Uncommon - specific geological coastal conditions",
|
||||
"minimum_area": 50,
|
||||
"typical_area_range": [100, 400]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "cliff_adapted_specialists",
|
||||
"secondary": ["hardy_coastal_shrubs", "cliff_grasses", "maritime_lichens", "wind_sculpted_trees"],
|
||||
"characteristics": [
|
||||
"extreme_wind_tolerance",
|
||||
"salt_spray_resistance",
|
||||
"cliff_face_adaptation",
|
||||
"shallow_root_systems",
|
||||
"low_growth_forms"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Only the most specialized plants survive on exposed cliff faces"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"wind_exposure": 3.0,
|
||||
"salt_spray": 2.8,
|
||||
"erosion_activity": 2.6,
|
||||
"soil_depth": 0.3,
|
||||
"access_difficulty": 2.9,
|
||||
"biodiversity": 1.2
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"stone_quarrying": 2.4,
|
||||
"seabird_guano": 1.8,
|
||||
"lighthouse_sites": 2.8,
|
||||
"wind_energy": 2.6,
|
||||
"defensive_positions": 3.0,
|
||||
"agriculture": 0.1,
|
||||
"forestry": 0.0,
|
||||
"tourism": 2.1,
|
||||
"industrial_suitability": 0.3,
|
||||
"research_value": 1.9
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"extreme_wind_protection",
|
||||
"cliff_face_stabilization",
|
||||
"specialized_access_systems",
|
||||
"salt_spray_corrosion_prevention"
|
||||
],
|
||||
"advantages": [
|
||||
"unparalleled_defensive_position",
|
||||
"lighthouse_and_navigation_sites",
|
||||
"stone_quarrying_opportunities",
|
||||
"extreme_wind_energy_potential"
|
||||
],
|
||||
"challenges": [
|
||||
"extremely_difficult_access",
|
||||
"continuous_erosion_threats",
|
||||
"construction_cost_multipliers",
|
||||
"limited_flat_building_space"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_fortress": 3.2,
|
||||
"coastal_observation": 3.0,
|
||||
"amphibious_invasion_prevention": 3.5
|
||||
},
|
||||
"economic_factors": {
|
||||
"construction_costs": 4.2,
|
||||
"maintenance_costs": 3.8,
|
||||
"stone_extraction_bonus": 2.4,
|
||||
"tourism_lighthouse_revenue": 2.1
|
||||
},
|
||||
"strategic_value": {
|
||||
"naval_observation": 3.2,
|
||||
"coastal_defense": 3.5,
|
||||
"navigation_control": 2.8
|
||||
}
|
||||
},
|
||||
|
||||
"survival_challenges": {
|
||||
"access_limitations": "rope_and_climbing_equipment_required",
|
||||
"wind_safety": "extreme_weather_poses_constant_danger",
|
||||
"erosion_instability": "cliff_faces_subject_to_sudden_collapse",
|
||||
"isolation": "limited_escape_routes_during_emergencies"
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"seabird_colonies",
|
||||
"cliff_nesting_birds",
|
||||
"marine_mammals_below",
|
||||
"specialized_cliff_insects"
|
||||
],
|
||||
"hunting_opportunities": 0.8,
|
||||
"biodiversity": 1.2,
|
||||
"conservation_value": "critical_seabird_nesting_habitat"
|
||||
},
|
||||
|
||||
"geological_characteristics": {
|
||||
"rock_type": "resistant_coastal_bedrock",
|
||||
"stability": "variable_depending_on_rock_type_and_weather",
|
||||
"erosion_patterns": "continuous_marine_erosion",
|
||||
"cliff_height": "typically_50_to_300_meters"
|
||||
},
|
||||
|
||||
"maritime_interaction": {
|
||||
"wave_action": "intense_wave_impact_at_base",
|
||||
"tidal_influence": "extreme_tidal_variation_exposure",
|
||||
"storm_impact": "severe_weather_amplification",
|
||||
"navigation_hazard": "dangerous_waters_for_small_vessels"
|
||||
},
|
||||
|
||||
"research_opportunities": {
|
||||
"coastal_erosion_studies": 2.4,
|
||||
"seabird_ecology": 2.2,
|
||||
"maritime_archaeology": 1.8,
|
||||
"wind_pattern_analysis": 2.0
|
||||
},
|
||||
|
||||
"historical_significance": {
|
||||
"lighthouse_heritage": "traditional_navigation_aid_locations",
|
||||
"defensive_castles": "medieval_coastal_fortification_sites",
|
||||
"shipwreck_archaeology": "dangerous_waters_with_historical_wrecks",
|
||||
"smuggling_history": "hidden_coves_and_secret_landing_sites"
|
||||
}
|
||||
}
|
||||
154
gameData/Biomes/coastal_plain.json
Normal file
154
gameData/Biomes/coastal_plain.json
Normal file
@ -0,0 +1,154 @@
|
||||
{
|
||||
"biome_id": "coastal_plain",
|
||||
"display_name": "Coastal Plain",
|
||||
"description": "Low-lying areas along coastlines with maritime influence, salt-tolerant vegetation and access to marine resources",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 2,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"min": 150, "condition": "moderate_coastal_rainfall"},
|
||||
"coastal_proximity": {"max": 5, "condition": "near_ocean"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"maritime_influence": true,
|
||||
"moderate_temperatures": true,
|
||||
"salt_spray_exposure": true,
|
||||
"sea_breeze_circulation": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"typical_range": [0, 50],
|
||||
"formation_zone": "low_coastal_areas_with_marine_influence"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by moderate rainfall with coastal proximity requirements",
|
||||
"geographic_distribution": "Coastal lowlands with maritime climate influence",
|
||||
"rarity": "Common - major coastal settlement areas",
|
||||
"minimum_area": 100,
|
||||
"typical_area_range": [200, 800]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "salt_tolerant_coastal_plants",
|
||||
"secondary": ["sea_grasses", "coastal_shrubs", "salt_marsh_plants", "dune_vegetation"],
|
||||
"characteristics": [
|
||||
"salt_tolerance",
|
||||
"wind_resistance",
|
||||
"sand_stabilization",
|
||||
"maritime_adaptation",
|
||||
"moderate_productivity"
|
||||
],
|
||||
"forest_compatibility": "coastal_adapted_trees_only",
|
||||
"note": "Specialized vegetation adapted to salt spray and coastal conditions"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"salt_tolerance": 2.5,
|
||||
"wind_exposure": 2.1,
|
||||
"soil_salinity": 1.8,
|
||||
"erosion_resistance": 1.4,
|
||||
"marine_influence": 2.8,
|
||||
"biodiversity": 1.6
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"fishing": 2.5,
|
||||
"salt_production": 2.0,
|
||||
"seaweed_harvest": 1.8,
|
||||
"maritime_trade": 2.2,
|
||||
"agriculture": 1.1,
|
||||
"livestock_grazing": 1.3,
|
||||
"wind_energy": 1.8,
|
||||
"tourism": 1.9,
|
||||
"forestry": 0.4,
|
||||
"industrial_suitability": 1.2
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"salt_corrosion_protection",
|
||||
"wind_resistant_design",
|
||||
"foundation_drainage_systems",
|
||||
"storm_surge_preparation"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_port_access",
|
||||
"maritime_trade_routes",
|
||||
"flat_construction_terrain",
|
||||
"consistent_wind_resources"
|
||||
],
|
||||
"challenges": [
|
||||
"salt_corrosion_issues",
|
||||
"storm_surge_vulnerability",
|
||||
"soil_salinity_problems",
|
||||
"seasonal_tourism_variations"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"amphibious_operations": 2.4,
|
||||
"naval_support_access": 2.6
|
||||
},
|
||||
"economic_factors": {
|
||||
"maritime_trade_bonus": 2.2,
|
||||
"fishing_industry_income": 2.5,
|
||||
"tourism_revenue": 1.9,
|
||||
"salt_corrosion_costs": 1.8
|
||||
},
|
||||
"strategic_value": {
|
||||
"port_development": 2.8,
|
||||
"naval_base_suitability": 2.4,
|
||||
"international_trade": 2.3
|
||||
}
|
||||
},
|
||||
|
||||
"seasonal_patterns": {
|
||||
"storm_season": {
|
||||
"conditions": "increased_wind_and_precipitation_from_ocean_storms",
|
||||
"challenges": "storm_surge_flooding_and_infrastructure_damage",
|
||||
"opportunities": "increased_fish_migration_and_wave_energy"
|
||||
},
|
||||
"calm_season": {
|
||||
"conditions": "stable_weather_with_consistent_sea_breezes",
|
||||
"opportunities": "optimal_fishing_and_maritime_trade_conditions",
|
||||
"tourism": "peak_visitor_season_with_mild_coastal_climate"
|
||||
}
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"seabirds",
|
||||
"coastal_mammals",
|
||||
"intertidal_species",
|
||||
"migratory_shorebirds"
|
||||
],
|
||||
"hunting_opportunities": 1.4,
|
||||
"biodiversity": 1.6,
|
||||
"conservation_value": "important_bird_migration_corridors"
|
||||
},
|
||||
|
||||
"soil_characteristics": {
|
||||
"soil_type": "sandy_coastal_soils_with_salt_content",
|
||||
"drainage": "excellent_natural_drainage",
|
||||
"salinity": "moderate_to_high_salt_content",
|
||||
"fertility": "moderate_with_marine_nutrient_input"
|
||||
},
|
||||
|
||||
"maritime_features": {
|
||||
"tidal_influence": "strong_tidal_variations",
|
||||
"beach_access": "natural_beaches_and_sandy_shores",
|
||||
"harbor_potential": "excellent_natural_harbors",
|
||||
"storm_protection": "requires_artificial_breakwaters"
|
||||
},
|
||||
|
||||
"land_use_potential": {
|
||||
"port_development": "primary_economic_opportunity",
|
||||
"fishing_industry": "major_coastal_resource_exploitation",
|
||||
"tourism_development": "beach_and_maritime_recreation",
|
||||
"salt_farming": "traditional_coastal_industry"
|
||||
}
|
||||
}
|
||||
184
gameData/Biomes/cold_desert.json
Normal file
184
gameData/Biomes/cold_desert.json
Normal file
@ -0,0 +1,184 @@
|
||||
{
|
||||
"biome_id": "cold_desert",
|
||||
"display_name": "Cold Desert",
|
||||
"description": "High-altitude or high-latitude desert regions with cold temperatures and minimal precipitation, featuring specialized cold-adapted arid vegetation",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 16,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"max": 30, "condition": "very_low_precipitation"},
|
||||
"temperature": {"max": 10, "condition": "cold_climate"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"cold_temperatures": true,
|
||||
"extreme_aridity": true,
|
||||
"high_altitude_or_latitude": true,
|
||||
"strong_temperature_variations": true,
|
||||
"low_humidity": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 500,
|
||||
"maximum": 3000,
|
||||
"typical_range": [1000, 2500],
|
||||
"formation_zone": "high_altitude_plateaus_and_polar_deserts"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by very low rain_tokens (≤30) combined with cold temperatures (≤10°C)",
|
||||
"geographic_distribution": "High-altitude plateaus, continental interiors with cold climates, polar deserts",
|
||||
"rarity": "Uncommon - requires specific combination of cold and extreme aridity",
|
||||
"minimum_area": 100,
|
||||
"typical_area_range": [250, 1000]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "cold_adapted_desert_plants",
|
||||
"secondary": ["hardy_shrubs", "drought_cold_tolerant_grasses", "alpine_succulents", "cushion_plants"],
|
||||
"characteristics": [
|
||||
"dual_stress_adaptation",
|
||||
"cold_and_drought_tolerance",
|
||||
"compact_growth_forms",
|
||||
"deep_root_systems",
|
||||
"protective_surface_structures"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Must survive both extreme cold and water scarcity simultaneously"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"water_scarcity": 2.9,
|
||||
"cold_extremes": 2.4,
|
||||
"temperature_variation": 2.7,
|
||||
"wind_exposure": 2.3,
|
||||
"soil_aridity": 2.8,
|
||||
"growing_season": 0.4,
|
||||
"biodiversity": 0.4
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"mineral_deposits": 1.9,
|
||||
"rare_earth_elements": 1.6,
|
||||
"wind_energy": 1.8,
|
||||
"solar_energy": 1.4,
|
||||
"geothermal_potential": 1.5,
|
||||
"salt_deposits": 1.7,
|
||||
"agriculture": 0.05,
|
||||
"forestry": 0.0,
|
||||
"water_resources": 0.15,
|
||||
"industrial_suitability": 0.6,
|
||||
"research_value": 1.8
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"cold_weather_protection",
|
||||
"water_conservation_systems",
|
||||
"wind_and_dust_protection",
|
||||
"specialized_heating_systems"
|
||||
],
|
||||
"advantages": [
|
||||
"mineral_resource_access",
|
||||
"low_environmental_impact_restrictions",
|
||||
"natural_preservation_conditions",
|
||||
"strategic_isolation"
|
||||
],
|
||||
"challenges": [
|
||||
"dual_environmental_stress",
|
||||
"water_importation_requirements",
|
||||
"extreme_temperature_management",
|
||||
"limited_growing_season"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_barrier": 2.6,
|
||||
"difficult_logistics": 2.8,
|
||||
"environmental_protection": 2.4
|
||||
},
|
||||
"economic_factors": {
|
||||
"construction_costs": 2.6,
|
||||
"heating_costs": 2.8,
|
||||
"water_importation_costs": 3.2,
|
||||
"mineral_extraction_bonus": 1.7
|
||||
},
|
||||
"strategic_value": {
|
||||
"resource_control": 2.0,
|
||||
"territorial_buffer": 2.5,
|
||||
"research_isolation": 2.2
|
||||
}
|
||||
},
|
||||
|
||||
"survival_challenges": {
|
||||
"water_procurement": {
|
||||
"sources": "snow_melt_and_rare_springs",
|
||||
"conservation": "critical_water_management",
|
||||
"quality": "often_high_mineral_content"
|
||||
},
|
||||
"temperature_management": {
|
||||
"heating_requirements": "essential_for_survival",
|
||||
"insulation_needs": "extreme_cold_protection",
|
||||
"equipment_protection": "cold_weather_maintenance"
|
||||
},
|
||||
"food_procurement": {
|
||||
"agriculture": "nearly_impossible",
|
||||
"hunting": "limited_wildlife",
|
||||
"imports": "critical_supply_dependence"
|
||||
}
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"cold_desert_lizards",
|
||||
"hardy_small_mammals",
|
||||
"migratory_birds",
|
||||
"specialized_arthropods"
|
||||
],
|
||||
"hunting_opportunities": 0.4,
|
||||
"biodiversity": 0.4,
|
||||
"conservation_value": "unique_dual_stress_adaptations"
|
||||
},
|
||||
|
||||
"seasonal_patterns": {
|
||||
"winter": {
|
||||
"conditions": "extreme_cold_with_minimal_precipitation",
|
||||
"challenges": "frozen_water_sources_and_heating_demands",
|
||||
"wildlife": "minimal_activity_and_hibernation"
|
||||
},
|
||||
"summer": {
|
||||
"conditions": "brief_warming_period_with_slight_moisture",
|
||||
"opportunities": "limited_growing_season_and_construction",
|
||||
"wildlife": "peak_activity_and_reproduction"
|
||||
}
|
||||
},
|
||||
|
||||
"geological_characteristics": {
|
||||
"soil_type": "thin_rocky_soils_with_poor_water_retention",
|
||||
"rock_formations": "exposed_bedrock_and_scree_slopes",
|
||||
"mineral_exposure": "weathering_exposes_valuable_deposits",
|
||||
"erosion_patterns": "wind_and_freeze_thaw_erosion"
|
||||
},
|
||||
|
||||
"water_sources": {
|
||||
"seasonal_snowmelt": "primary_annual_water_input",
|
||||
"underground_springs": "rare_but_critical_resources",
|
||||
"atmospheric_moisture": "dew_and_frost_collection",
|
||||
"imported_water": "essential_for_human_activities"
|
||||
},
|
||||
|
||||
"research_opportunities": {
|
||||
"extreme_environment_biology": 2.0,
|
||||
"cold_arid_adaptations": 1.9,
|
||||
"climate_change_indicators": 1.8,
|
||||
"mineral_formation_processes": 1.7
|
||||
},
|
||||
|
||||
"land_use_potential": {
|
||||
"mining_operations": "primary_economic_activity",
|
||||
"research_stations": "isolated_study_locations",
|
||||
"strategic_installations": "remote_monitoring_posts",
|
||||
"renewable_energy": "wind_and_limited_solar"
|
||||
},
|
||||
|
||||
}
|
||||
153
gameData/Biomes/grassland.json
Normal file
153
gameData/Biomes/grassland.json
Normal file
@ -0,0 +1,153 @@
|
||||
{
|
||||
"biome_id": "grassland",
|
||||
"display_name": "Grassland",
|
||||
"description": "Temperate grasslands with moderate rainfall and temperature, ideal for agriculture and grazing, featuring vast open plains",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 13,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"min": 200, "condition": "moderate_rainfall"},
|
||||
"temperature": {"min": 10, "condition": "temperate_climate"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"moderate_temperatures": true,
|
||||
"adequate_rainfall": true,
|
||||
"seasonal_variation": true,
|
||||
"insufficient_for_forest_growth": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 800,
|
||||
"typical_range": [100, 600],
|
||||
"formation_zone": "continental_interiors_with_moderate_precipitation"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by moderate rain_tokens (200+) with temperate temperatures but insufficient for forests",
|
||||
"geographic_distribution": "Continental interiors with moderate precipitation",
|
||||
"rarity": "Common - major agricultural regions worldwide",
|
||||
"minimum_area": 200,
|
||||
"typical_area_range": [500, 2500]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "perennial_grasses",
|
||||
"secondary": ["prairie_grasses", "wildflowers", "scattered_shrubs"],
|
||||
"characteristics": [
|
||||
"deep_root_systems",
|
||||
"drought_tolerance",
|
||||
"fire_adaptation",
|
||||
"seasonal_growth_cycles",
|
||||
"high_productivity"
|
||||
],
|
||||
"forest_compatibility": "scattered_trees_only",
|
||||
"note": "Natural grassland ecosystem with high agricultural potential"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"agricultural_potential": 2.5,
|
||||
"soil_quality": 2.2,
|
||||
"carbon_storage": 1.8,
|
||||
"erosion_resistance": 1.6,
|
||||
"fire_resilience": 2.0,
|
||||
"biodiversity": 1.4
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"agriculture": 1.8,
|
||||
"livestock_grazing": 2.2,
|
||||
"grain_production": 2.0,
|
||||
"hay_and_forage": 2.5,
|
||||
"wild_game": 1.6,
|
||||
"wind_energy": 1.4,
|
||||
"forestry": 0.2,
|
||||
"industrial_suitability": 0.9,
|
||||
"recreation": 1.3
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"minimal_ground_preparation",
|
||||
"wind_exposure_considerations",
|
||||
"seasonal_weather_protection"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_agricultural_land",
|
||||
"easy_construction_conditions",
|
||||
"flat_terrain_for_development",
|
||||
"good_transportation_routes"
|
||||
],
|
||||
"challenges": [
|
||||
"limited_natural_windbreaks",
|
||||
"fire_risk_management",
|
||||
"soil_conservation_needs",
|
||||
"seasonal_weather_extremes"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"open_terrain_visibility": 2.2,
|
||||
"cavalry_advantage": 2.0
|
||||
},
|
||||
"economic_factors": {
|
||||
"agricultural_productivity": 2.2,
|
||||
"low_development_costs": 1.5,
|
||||
"food_security_bonus": 2.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"food_production_hub": 2.5,
|
||||
"population_support": 2.2,
|
||||
"transportation_network": 1.8
|
||||
}
|
||||
},
|
||||
|
||||
"agricultural_systems": {
|
||||
"crop_rotation": "sustainable_soil_management",
|
||||
"livestock_integration": "mixed_farming_systems",
|
||||
"irrigation_potential": "moderate_water_requirements",
|
||||
"mechanization": "ideal_for_large_scale_farming"
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"grassland_species": [
|
||||
"prairie_dogs",
|
||||
"ground_nesting_birds",
|
||||
"grazing_mammals",
|
||||
"raptors"
|
||||
],
|
||||
"hunting_opportunities": 1.6,
|
||||
"biodiversity": 1.4,
|
||||
"migration_routes": "important_corridors_for_many_species"
|
||||
},
|
||||
|
||||
"seasonal_patterns": {
|
||||
"growing_season": "spring_through_early_autumn",
|
||||
"dormancy_period": "winter_with_possible_snow_cover",
|
||||
"fire_season": "late_summer_natural_fire_cycles",
|
||||
"grazing_patterns": "seasonal_animal_movement"
|
||||
},
|
||||
|
||||
"soil_characteristics": {
|
||||
"soil_type": "deep_fertile_prairie_soils",
|
||||
"organic_matter": "high_due_to_grass_root_systems",
|
||||
"drainage": "generally_well_drained",
|
||||
"erosion_risk": "moderate_without_ground_cover"
|
||||
},
|
||||
|
||||
"fire_ecology": {
|
||||
"natural_fire_frequency": "every_3_10_years",
|
||||
"fire_benefits": "removes_woody_plants_and_stimulates_grass_growth",
|
||||
"fire_management": "controlled_burns_for_ecosystem_health",
|
||||
"fire_prevention": "firebreaks_and_early_detection"
|
||||
},
|
||||
|
||||
"land_use_patterns": {
|
||||
"agriculture": "crop_production_and_livestock",
|
||||
"urban_development": "preferred_sites_for_cities",
|
||||
"transportation": "ideal_for_roads_and_railways",
|
||||
"energy_production": "wind_farms_and_solar_installations"
|
||||
},
|
||||
|
||||
}
|
||||
180
gameData/Biomes/hills.json
Normal file
180
gameData/Biomes/hills.json
Normal file
@ -0,0 +1,180 @@
|
||||
{
|
||||
"biome_id": "hills",
|
||||
"display_name": "Hills",
|
||||
"description": "Rolling hill country with moderate elevation, diverse microclimates, and mixed vegetation creating natural terraced landscapes",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 17,
|
||||
"token_requirements": {
|
||||
"elevation": {"min": 500, "max": 1500, "condition": "moderate_altitude"},
|
||||
"rain_tokens": {"min": 150, "condition": "adequate_moisture"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"moderate_elevation_effects": true,
|
||||
"varied_microclimates": true,
|
||||
"good_drainage": true,
|
||||
"wind_exposure_variation": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 500,
|
||||
"maximum": 1500,
|
||||
"typical_range": [600, 1200],
|
||||
"formation_zone": "transition_between_plains_and_mountains"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by moderate elevation (500-1500m) with adequate moisture (≥150 rain_tokens)",
|
||||
"geographic_distribution": "Transition zones between plains and mountains",
|
||||
"rarity": "Common - natural intermediate terrain",
|
||||
"minimum_area": 100,
|
||||
"typical_area_range": [200, 800]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "mixed_elevation_adapted",
|
||||
"secondary": ["hill_grasslands", "scattered_woodlands", "shrublands", "valley_forests"],
|
||||
"characteristics": [
|
||||
"elevation_gradient_adaptation",
|
||||
"diverse_microhabitats",
|
||||
"slope_aspect_variation",
|
||||
"mixed_vegetation_types",
|
||||
"erosion_resistance"
|
||||
],
|
||||
"forest_compatibility": "partial_woodlands",
|
||||
"note": "Diverse vegetation zones based on slope orientation and elevation"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"topographic_diversity": 2.5,
|
||||
"drainage_quality": 2.2,
|
||||
"microclimate_variation": 2.3,
|
||||
"erosion_control": 1.8,
|
||||
"scenic_value": 2.4,
|
||||
"biodiversity": 1.6
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"mixed_agriculture": 1.4,
|
||||
"livestock_grazing": 1.8,
|
||||
"forestry": 1.2,
|
||||
"stone_quarrying": 1.6,
|
||||
"wind_energy": 1.3,
|
||||
"water_sources": 1.5,
|
||||
"tourism": 1.9,
|
||||
"industrial_suitability": 1.1,
|
||||
"transportation": 0.8,
|
||||
"recreation": 2.1
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"slope_stabilization",
|
||||
"terraced_construction",
|
||||
"drainage_management",
|
||||
"access_road_engineering"
|
||||
],
|
||||
"advantages": [
|
||||
"natural_defensive_positions",
|
||||
"diverse_resource_access",
|
||||
"good_water_drainage",
|
||||
"scenic_development_potential"
|
||||
],
|
||||
"challenges": [
|
||||
"uneven_terrain_costs",
|
||||
"erosion_management",
|
||||
"transportation_complexity",
|
||||
"varying_soil_conditions"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"elevated_positions": 1.8,
|
||||
"natural_fortification": 1.6,
|
||||
"observation_advantage": 2.0
|
||||
},
|
||||
"economic_factors": {
|
||||
"construction_costs": 1.4,
|
||||
"agricultural_diversity": 1.6,
|
||||
"tourism_income": 1.8,
|
||||
"transportation_costs": 1.3
|
||||
},
|
||||
"strategic_value": {
|
||||
"tactical_advantage": 1.9,
|
||||
"resource_diversity": 1.7,
|
||||
"settlement_desirability": 1.8
|
||||
}
|
||||
},
|
||||
|
||||
"topographic_features": {
|
||||
"rolling_terrain": "gentle_to_moderate_slopes",
|
||||
"valley_systems": "natural_drainage_and_shelter",
|
||||
"ridge_lines": "elevated_transportation_routes",
|
||||
"natural_terraces": "stepped_landscape_features"
|
||||
},
|
||||
|
||||
"agricultural_potential": {
|
||||
"terraced_farming": "slope_agriculture_adaptation",
|
||||
"mixed_land_use": "crops_pasture_and_woodland",
|
||||
"orchard_suitability": "fruit_trees_on_slopes",
|
||||
"vineyard_potential": "wine_production_terrain"
|
||||
},
|
||||
|
||||
"water_systems": {
|
||||
"spring_sources": "hillside_water_emergence",
|
||||
"creek_systems": "valley_drainage_networks",
|
||||
"pond_potential": "natural_water_collection",
|
||||
"watershed_management": "erosion_and_runoff_control"
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"habitat_diversity": [
|
||||
"valley_woodland_species",
|
||||
"grassland_animals",
|
||||
"edge_habitat_specialists",
|
||||
"slope_adapted_plants"
|
||||
],
|
||||
"hunting_opportunities": 1.6,
|
||||
"biodiversity": 1.6,
|
||||
"wildlife_corridors": "natural_movement_pathways"
|
||||
},
|
||||
|
||||
"settlement_patterns": {
|
||||
"hilltop_settlements": "defensive_and_scenic_locations",
|
||||
"valley_villages": "water_access_and_shelter",
|
||||
"slope_farming": "terraced_agricultural_communities",
|
||||
"ridge_transportation": "natural_road_corridors"
|
||||
},
|
||||
|
||||
"seasonal_characteristics": {
|
||||
"spring": "varied_blooming_times_by_elevation",
|
||||
"summer": "diverse_microclimates_and_activities",
|
||||
"autumn": "spectacular_color_displays",
|
||||
"winter": "snow_variation_by_elevation_and_aspect"
|
||||
},
|
||||
|
||||
"recreational_opportunities": {
|
||||
"hiking_trails": 2.2,
|
||||
"scenic_driving": 2.0,
|
||||
"mountain_biking": 1.9,
|
||||
"photography": 2.1,
|
||||
"camping": 1.7,
|
||||
"nature_education": 1.8
|
||||
},
|
||||
|
||||
"microclimate_zones": {
|
||||
"south_facing_slopes": "warmer_and_drier_conditions",
|
||||
"north_facing_slopes": "cooler_and_moister_conditions",
|
||||
"valley_bottoms": "protected_and_humid_microclimates",
|
||||
"ridge_tops": "exposed_and_windy_conditions"
|
||||
},
|
||||
|
||||
"soil_characteristics": {
|
||||
"slope_variation": "thinner_soils_on_slopes_deeper_in_valleys",
|
||||
"drainage_quality": "generally_good_with_slope_advantage",
|
||||
"erosion_potential": "managed_through_vegetation_cover",
|
||||
"fertility_variation": "nutrient_accumulation_in_lower_areas"
|
||||
},
|
||||
|
||||
}
|
||||
165
gameData/Biomes/hot_desert.json
Normal file
165
gameData/Biomes/hot_desert.json
Normal file
@ -0,0 +1,165 @@
|
||||
{
|
||||
"biome_id": "hot_desert",
|
||||
"display_name": "Hot Desert",
|
||||
"description": "Arid regions with high temperatures and minimal rainfall, featuring specialized drought-adapted vegetation and extreme environmental conditions",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 11,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"max": 50, "condition": "minimal_rainfall"},
|
||||
"temperature": {"min": 20, "condition": "hot_climate"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"extreme_aridity": true,
|
||||
"high_daytime_temperatures": true,
|
||||
"cold_nighttime_temperatures": true,
|
||||
"irregular_precipitation": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 1200,
|
||||
"typical_range": [200, 800],
|
||||
"formation_zone": "continental_interiors_and_subtropical_zones"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by minimal rain_tokens (≤50) combined with hot temperatures (≥20°C)",
|
||||
"geographic_distribution": "Continental interiors and subtropical high-pressure zones without ITCZ influence",
|
||||
"rarity": "Common - represents Sahara success pattern",
|
||||
"minimum_area": 300,
|
||||
"typical_area_range": [800, 3000],
|
||||
"formation_priority": "High - represents successful Congo vs Sahara differentiation"
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "drought_adapted_specialists",
|
||||
"secondary": ["cacti", "succulents", "drought_deciduous_shrubs", "ephemeral_annuals"],
|
||||
"characteristics": [
|
||||
"water_storage_organs",
|
||||
"reduced_leaf_surface_area",
|
||||
"waxy_protective_coatings",
|
||||
"deep_tap_roots",
|
||||
"CAM_photosynthesis"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Only highly specialized plants can survive extreme water scarcity"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"water_scarcity": 2.8,
|
||||
"solar_exposure": 3.0,
|
||||
"temperature_extremes": 2.5,
|
||||
"wind_exposure": 1.8,
|
||||
"soil_aridity": 2.9,
|
||||
"biodiversity": 0.3
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"solar_energy": 2.5,
|
||||
"mineral_deposits": 1.8,
|
||||
"rare_earth_elements": 1.5,
|
||||
"salt_deposits": 2.0,
|
||||
"geothermal_energy": 1.4,
|
||||
"agriculture": 0.1,
|
||||
"forestry": 0.0,
|
||||
"water_resources": 0.1,
|
||||
"industrial_suitability": 1.2,
|
||||
"tourism": 1.0
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"extreme_heat_resistance",
|
||||
"sand_and_dust_protection",
|
||||
"water_conservation_systems",
|
||||
"thermal_insulation"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_solar_energy_potential",
|
||||
"exposed_mineral_resources",
|
||||
"vast_open_spaces",
|
||||
"minimal_environmental_constraints"
|
||||
],
|
||||
"challenges": [
|
||||
"extreme_water_scarcity",
|
||||
"temperature_stress_on_equipment",
|
||||
"sandstorm_damage",
|
||||
"worker_health_and_safety"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_barrier": 2.0,
|
||||
"difficult_logistics": 2.5,
|
||||
"heat_exhaustion_advantage": 2.2
|
||||
},
|
||||
"economic_factors": {
|
||||
"solar_farm_efficiency": 2.8,
|
||||
"mineral_extraction_bonus": 1.7,
|
||||
"water_importation_costs": 3.0,
|
||||
"construction_heat_costs": 1.8
|
||||
},
|
||||
"strategic_value": {
|
||||
"renewable_energy_hub": 2.7,
|
||||
"resource_control": 1.9,
|
||||
"natural_isolation": 2.3
|
||||
}
|
||||
},
|
||||
|
||||
"survival_adaptations": {
|
||||
"water_sources": [
|
||||
"rare_oases",
|
||||
"underground_aquifers",
|
||||
"seasonal_water_holes",
|
||||
"dew_collection"
|
||||
],
|
||||
"temperature_management": [
|
||||
"underground_shelter",
|
||||
"thermal_mass_utilization",
|
||||
"reflective_surfaces",
|
||||
"shade_structures"
|
||||
],
|
||||
"navigation_challenges": [
|
||||
"shifting_sand_dunes",
|
||||
"heat_mirages",
|
||||
"sandstorm_visibility",
|
||||
"landmark_scarcity"
|
||||
]
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"desert_reptiles",
|
||||
"nocturnal_mammals",
|
||||
"water_conserving_birds",
|
||||
"specialized_insects"
|
||||
],
|
||||
"hunting_opportunities": 0.3,
|
||||
"biodiversity": 0.3,
|
||||
"conservation_value": "specialized_endemic_species"
|
||||
},
|
||||
|
||||
"climatic_patterns": {
|
||||
"daily_temperature_cycle": "extreme_day_night_variation",
|
||||
"seasonal_patterns": "hot_dry_vs_less_hot_dry",
|
||||
"precipitation_events": "rare_but_intense_flash_floods",
|
||||
"wind_patterns": "dust_storms_and_thermal_circulation"
|
||||
},
|
||||
|
||||
"geological_features": {
|
||||
"sand_dunes": "shifting_landscape_features",
|
||||
"rock_outcroppings": "rare_shelter_and_navigation_points",
|
||||
"salt_flats": "remnants_of_ancient_lakes",
|
||||
"mineral_exposures": "valuable_surface_deposits"
|
||||
},
|
||||
|
||||
"water_economy": {
|
||||
"conservation_priority": "critical",
|
||||
"sources": "extremely_limited_and_precious",
|
||||
"management": "every_drop_must_be_utilized",
|
||||
"technology": "advanced_conservation_required"
|
||||
},
|
||||
|
||||
}
|
||||
100
gameData/Biomes/hurricane_zone.json
Normal file
100
gameData/Biomes/hurricane_zone.json
Normal file
@ -0,0 +1,100 @@
|
||||
{
|
||||
"biome_id": "hurricane_zone",
|
||||
"display_name": "Hurricane Zone",
|
||||
"description": "Coastal regions subjected to frequent hurricane activity, featuring storm-resistant vegetation and specialized ecosystems",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 6,
|
||||
"token_requirements": {
|
||||
"hurricane_tokens": {"min": 1, "condition": "greater_than_zero"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"high_wind_exposure": true,
|
||||
"frequent_storm_activity": true,
|
||||
"salt_spray_tolerance_required": true,
|
||||
"coastal_proximity": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"typical_range": [0, 50],
|
||||
"formation_zone": "coastal_areas_near_sea_level"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by hurricane_tokens from WindRegions with high wind_strength + high wetness",
|
||||
"geographic_distribution": "Coastal areas in hurricane-prone latitudes",
|
||||
"rarity": "Moderate - found along storm-prone coastlines",
|
||||
"minimum_area": 50,
|
||||
"typical_area_range": [100, 500]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "storm_resistant_palms",
|
||||
"secondary": ["coastal_grasses", "mangrove_species", "salt_tolerant_shrubs"],
|
||||
"characteristics": [
|
||||
"deep_root_systems",
|
||||
"flexible_trunks",
|
||||
"salt_tolerance",
|
||||
"rapid_recovery_after_storms"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Traditional forests cannot survive the frequent high-wind disturbances"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"storm_resistance": 3.0,
|
||||
"coastal_access": 2.0,
|
||||
"wind_energy_potential": 2.5,
|
||||
"biodiversity": 1.2,
|
||||
"soil_stability": 0.6,
|
||||
"water_drainage": 1.8
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"wind_energy": 2.5,
|
||||
"seafood": 1.8,
|
||||
"storm_resistant_materials": 2.0,
|
||||
"agriculture": 0.4,
|
||||
"forestry": 0.1,
|
||||
"industrial_suitability": 0.6,
|
||||
"tourism_potential": 1.4
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"hurricane_resistant_buildings",
|
||||
"elevated_foundations",
|
||||
"storm_surge_protection"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_wind_energy_sites",
|
||||
"natural_harbors_from_storm_carving",
|
||||
"unique_marine_resources"
|
||||
],
|
||||
"challenges": [
|
||||
"seasonal_evacuation_needs",
|
||||
"infrastructure_maintenance_costs",
|
||||
"limited_agricultural_productivity"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"coastal_fortification_bonus": 1.5,
|
||||
"storm_shelter_effectiveness": 2.0
|
||||
},
|
||||
"economic_factors": {
|
||||
"insurance_costs": 2.5,
|
||||
"reconstruction_frequency": "seasonal",
|
||||
"specialized_industry_bonus": 1.3
|
||||
},
|
||||
"strategic_value": {
|
||||
"naval_base_suitability": 1.8,
|
||||
"early_warning_systems": 2.0,
|
||||
"hurricane_tracking_advantage": true
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
194
gameData/Biomes/rocky_plateau.json
Normal file
194
gameData/Biomes/rocky_plateau.json
Normal file
@ -0,0 +1,194 @@
|
||||
{
|
||||
"biome_id": "rocky_plateau",
|
||||
"display_name": "Rocky Plateau",
|
||||
"description": "Elevated flat-topped landforms with exposed bedrock, thin soils, and hardy vegetation adapted to wind exposure and rocky terrain",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 18,
|
||||
"token_requirements": {
|
||||
"elevation": {"min": 800, "condition": "elevated_terrain"},
|
||||
"rain_tokens": {"min": 100, "max": 400, "condition": "moderate_to_low_moisture"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"elevated_exposure": true,
|
||||
"strong_winds": true,
|
||||
"thin_soils": true,
|
||||
"temperature_extremes": true,
|
||||
"good_drainage": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 800,
|
||||
"typical_range": [1000, 2500],
|
||||
"formation_zone": "elevated_flat_topped_terrain"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by elevated terrain (≥800m) with moderate to low moisture (100-400 rain_tokens)",
|
||||
"geographic_distribution": "Elevated areas with resistant geology and moderate precipitation",
|
||||
"rarity": "Uncommon - requires specific geological and climatic conditions",
|
||||
"minimum_area": 75,
|
||||
"typical_area_range": [150, 600]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "rocky_terrain_specialists",
|
||||
"secondary": ["plateau_grasses", "hardy_shrubs", "rock_garden_plants", "windswept_trees"],
|
||||
"characteristics": [
|
||||
"rock_crevice_adaptation",
|
||||
"wind_resistance",
|
||||
"drought_tolerance",
|
||||
"shallow_root_systems",
|
||||
"hardy_constitution"
|
||||
],
|
||||
"forest_compatibility": "stunted_woodlands_only",
|
||||
"note": "Vegetation limited by thin soils and wind exposure"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"rock_exposure": 2.8,
|
||||
"wind_exposure": 2.6,
|
||||
"soil_depth": 0.4,
|
||||
"drainage_quality": 2.9,
|
||||
"temperature_variation": 2.3,
|
||||
"erosion_resistance": 2.5,
|
||||
"biodiversity": 0.9
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"stone_quarrying": 2.5,
|
||||
"mineral_extraction": 2.2,
|
||||
"wind_energy": 2.3,
|
||||
"solar_energy": 1.9,
|
||||
"water_collection": 1.4,
|
||||
"grazing_land": 0.6,
|
||||
"agriculture": 0.3,
|
||||
"forestry": 0.4,
|
||||
"tourism": 1.7,
|
||||
"industrial_suitability": 1.3
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"rock_drilling_and_blasting",
|
||||
"wind_resistant_structures",
|
||||
"water_importation_systems",
|
||||
"specialized_foundation_work"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_building_stone_access",
|
||||
"stable_geological_foundation",
|
||||
"commanding_views_and_positions",
|
||||
"wind_and_solar_energy_potential"
|
||||
],
|
||||
"challenges": [
|
||||
"limited_water_sources",
|
||||
"difficult_excavation",
|
||||
"extreme_wind_exposure",
|
||||
"thin_soil_for_agriculture"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_fortress": 2.8,
|
||||
"observation_advantage": 2.9,
|
||||
"difficult_approach": 2.4
|
||||
},
|
||||
"economic_factors": {
|
||||
"quarrying_income": 2.4,
|
||||
"construction_costs": 2.2,
|
||||
"water_importation_costs": 2.6,
|
||||
"energy_generation_bonus": 2.1
|
||||
},
|
||||
"strategic_value": {
|
||||
"territorial_control": 2.7,
|
||||
"communication_advantage": 2.8,
|
||||
"resource_monopoly": 2.3
|
||||
}
|
||||
},
|
||||
|
||||
"geological_features": {
|
||||
"bedrock_exposure": "extensive_rock_outcroppings",
|
||||
"flat_topped_terrain": "erosion_resistant_caprock",
|
||||
"cliff_edges": "dramatic_escarpments",
|
||||
"joint_and_fracture_systems": "natural_stone_quarrying_sites"
|
||||
},
|
||||
|
||||
"water_systems": {
|
||||
"surface_runoff": "rapid_drainage_with_minimal_retention",
|
||||
"rock_pools": "temporary_water_collection_in_depressions",
|
||||
"spring_emergence": "water_sources_at_plateau_edges",
|
||||
"cistern_potential": "artificial_water_storage_in_rock"
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"cliff_dwelling_birds",
|
||||
"rock_crevice_mammals",
|
||||
"hardy_reptiles",
|
||||
"wind_dispersed_plants"
|
||||
],
|
||||
"hunting_opportunities": 0.8,
|
||||
"biodiversity": 0.9,
|
||||
"conservation_value": "specialized_rocky_habitat_species"
|
||||
},
|
||||
|
||||
"wind_patterns": {
|
||||
"exposure_effects": "constant_wind_stress_on_vegetation",
|
||||
"wind_channeling": "increased_velocity_over_flat_surfaces",
|
||||
"turbulence_zones": "complex_airflow_around_edges",
|
||||
"energy_potential": "excellent_wind_farm_locations"
|
||||
},
|
||||
|
||||
"agricultural_limitations": {
|
||||
"soil_depth": "insufficient_for_most_crops",
|
||||
"water_scarcity": "irrigation_challenges",
|
||||
"wind_damage": "crop_protection_difficulties",
|
||||
"specialized_techniques": "rock_garden_and_terrace_farming"
|
||||
},
|
||||
|
||||
"construction_opportunities": {
|
||||
"castle_and_fort_sites": "natural_defensive_positions",
|
||||
"observation_towers": "communication_and_surveillance",
|
||||
"wind_farms": "optimal_renewable_energy_sites",
|
||||
"quarry_operations": "building_stone_extraction"
|
||||
},
|
||||
|
||||
"seasonal_characteristics": {
|
||||
"winter": "extreme_wind_chill_and_ice_formation",
|
||||
"spring": "brief_flowering_in_protected_crevices",
|
||||
"summer": "intense_heat_reflection_from_rock",
|
||||
"autumn": "dramatic_temperature_swings"
|
||||
},
|
||||
|
||||
"erosion_patterns": {
|
||||
"differential_weathering": "harder_rocks_form_resistant_caps",
|
||||
"joint_widening": "freeze_thaw_processes",
|
||||
"surface_scaling": "temperature_expansion_effects",
|
||||
"chemical_weathering": "slow_soil_formation_processes"
|
||||
},
|
||||
|
||||
"recreational_uses": {
|
||||
"rock_climbing": 2.2,
|
||||
"hiking_and_exploration": 1.8,
|
||||
"photography": 2.0,
|
||||
"astronomical_observation": 2.3,
|
||||
"paragliding_launch": 2.1
|
||||
},
|
||||
|
||||
"microhabitats": {
|
||||
"rock_crevices": "protected_growing_spaces",
|
||||
"lee_slopes": "wind_protection_zones",
|
||||
"water_collection_areas": "temporary_moist_zones",
|
||||
"exposed_surfaces": "extreme_environment_specialists"
|
||||
},
|
||||
|
||||
"formation_requirements": {
|
||||
"geological_stability": "resistant_caprock_preservation",
|
||||
"elevation_maintenance": "ongoing_uplift_or_erosion_resistance",
|
||||
"climate_balance": "enough_moisture_for_some_vegetation",
|
||||
"time_scale": "long_term_landscape_evolution"
|
||||
},
|
||||
|
||||
}
|
||||
110
gameData/Biomes/rocky_shore.json
Normal file
110
gameData/Biomes/rocky_shore.json
Normal file
@ -0,0 +1,110 @@
|
||||
{
|
||||
"biome_id": "rocky_shore",
|
||||
"display_name": "Rocky Shore",
|
||||
"description": "Rugged coastal areas with exposed bedrock, tidal pools and rich marine ecosystems",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 5,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"min": 120, "condition": "moderate_coastal_precipitation"},
|
||||
"coastal_proximity": {"max": 2, "condition": "immediate_ocean_access"},
|
||||
"rock_exposure": {"min": 1, "condition": "bedrock_substrate"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"intense_salt_spray": true,
|
||||
"tidal_variation_extreme": true,
|
||||
"wave_action_strong": true,
|
||||
"maritime_influence": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 25,
|
||||
"typical_range": [0, 10],
|
||||
"formation_zone": "low_rocky_coastal_areas_with_tidal_exposure"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by moderate rainfall with rocky coastal proximity",
|
||||
"geographic_distribution": "Rocky coastlines with exposed bedrock and tidal zones",
|
||||
"rarity": "Common - many temperate and cold coastlines",
|
||||
"minimum_area": 60,
|
||||
"typical_area_range": [120, 400]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "rock_crevice_specialists",
|
||||
"secondary": ["maritime_lichens", "salt_marsh_edges", "cliff_grasses", "seaweed_beds"],
|
||||
"characteristics": [
|
||||
"extreme_salt_tolerance",
|
||||
"tidal_submersion_resistance",
|
||||
"rock_crevice_growth",
|
||||
"wave_impact_tolerance",
|
||||
"minimal_soil_requirements"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Highly specialized flora adapted to harsh intertidal conditions"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"salt_exposure": 3.0,
|
||||
"wave_impact": 2.8,
|
||||
"tidal_variation": 2.9,
|
||||
"rock_weathering": 2.2,
|
||||
"marine_productivity": 2.6,
|
||||
"biodiversity": 1.8
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"marine_biology": 2.4,
|
||||
"shellfish_harvesting": 2.6,
|
||||
"seaweed_collection": 2.2,
|
||||
"tidal_energy": 2.0,
|
||||
"stone_quarrying": 1.8,
|
||||
"research_value": 2.2,
|
||||
"fishing": 2.0,
|
||||
"tourism": 1.6,
|
||||
"agriculture": 0.1,
|
||||
"forestry": 0.0,
|
||||
"industrial_suitability": 0.5
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"extreme_salt_corrosion_protection",
|
||||
"wave_impact_resistant_design",
|
||||
"tidal_flood_management",
|
||||
"rock_anchor_foundation_systems"
|
||||
],
|
||||
"advantages": [
|
||||
"solid_bedrock_foundations",
|
||||
"natural_wave_barriers",
|
||||
"rich_marine_resource_access",
|
||||
"tidal_energy_potential"
|
||||
],
|
||||
"challenges": [
|
||||
"extreme_corrosion_environment",
|
||||
"limited_flat_construction_space",
|
||||
"tidal_flooding_issues",
|
||||
"harsh_working_conditions"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_barriers": 2.4,
|
||||
"amphibious_defense": 2.6
|
||||
},
|
||||
"economic_factors": {
|
||||
"marine_harvesting_bonus": 2.4,
|
||||
"extreme_maintenance_costs": 2.8,
|
||||
"research_station_value": 2.2,
|
||||
"tidal_energy_income": 2.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"marine_resource_control": 2.4,
|
||||
"coastal_observation": 2.0,
|
||||
"scientific_research": 2.2
|
||||
}
|
||||
}
|
||||
}
|
||||
109
gameData/Biomes/sandy_coast.json
Normal file
109
gameData/Biomes/sandy_coast.json
Normal file
@ -0,0 +1,109 @@
|
||||
{
|
||||
"biome_id": "sandy_coast",
|
||||
"display_name": "Sandy Coast",
|
||||
"description": "Expansive sandy beaches and dune systems with dynamic coastal environment and tourism potential",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 4,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"min": 100, "condition": "moderate_coastal_precipitation"},
|
||||
"coastal_proximity": {"max": 3, "condition": "close_ocean_access"},
|
||||
"sediment_availability": {"min": 1, "condition": "sandy_substrate"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"maritime_influence": true,
|
||||
"sand_mobility": true,
|
||||
"moderate_salt_exposure": true,
|
||||
"dune_formation_active": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 30,
|
||||
"typical_range": [0, 15],
|
||||
"formation_zone": "low_coastal_areas_with_sandy_substrate"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by moderate rainfall with sandy coastal proximity",
|
||||
"geographic_distribution": "Sandy beaches, dune systems, barrier islands",
|
||||
"rarity": "Common - major tourist and recreational coastlines",
|
||||
"minimum_area": 80,
|
||||
"typical_area_range": [150, 600]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "dune_stabilizing_plants",
|
||||
"secondary": ["beach_grasses", "salt_tolerant_shrubs", "coastal_pines", "dune_flowers"],
|
||||
"characteristics": [
|
||||
"sand_stabilization",
|
||||
"salt_spray_tolerance",
|
||||
"deep_root_systems",
|
||||
"wind_resistance",
|
||||
"seasonal_adaptation"
|
||||
],
|
||||
"forest_compatibility": "coastal_pine_forests_only",
|
||||
"note": "Specialized vegetation for mobile sand environments"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"sand_mobility": 2.4,
|
||||
"salt_tolerance": 2.2,
|
||||
"wind_exposure": 2.0,
|
||||
"erosion_variability": 2.3,
|
||||
"tourism_appeal": 2.8,
|
||||
"biodiversity": 1.4
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"tourism": 2.8,
|
||||
"recreation": 2.6,
|
||||
"fishing": 1.8,
|
||||
"sand_extraction": 2.2,
|
||||
"wind_energy": 1.6,
|
||||
"salt_production": 1.4,
|
||||
"agriculture": 0.4,
|
||||
"forestry": 0.6,
|
||||
"industrial_suitability": 0.8,
|
||||
"coastal_development": 2.4
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"sand_stabilization_systems",
|
||||
"hurricane_storm_surge_protection",
|
||||
"seasonal_erosion_management",
|
||||
"foundation_sand_compaction"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_tourism_development",
|
||||
"recreational_beach_access",
|
||||
"sand_construction_materials",
|
||||
"flat_development_terrain"
|
||||
],
|
||||
"challenges": [
|
||||
"seasonal_storm_damage",
|
||||
"sand_erosion_and_mobility",
|
||||
"limited_freshwater_access",
|
||||
"environmental_protection_regulations"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"amphibious_landing_zones": 1.8,
|
||||
"coastal_monitoring": 1.6
|
||||
},
|
||||
"economic_factors": {
|
||||
"tourism_revenue": 2.8,
|
||||
"seasonal_income_variation": 2.2,
|
||||
"beach_maintenance_costs": 1.6,
|
||||
"sand_resource_income": 2.2
|
||||
},
|
||||
"strategic_value": {
|
||||
"recreational_development": 2.8,
|
||||
"coastal_access": 2.4,
|
||||
"tourism_infrastructure": 2.6
|
||||
}
|
||||
}
|
||||
}
|
||||
158
gameData/Biomes/scrubland.json
Normal file
158
gameData/Biomes/scrubland.json
Normal file
@ -0,0 +1,158 @@
|
||||
{
|
||||
"biome_id": "scrubland",
|
||||
"display_name": "Scrubland",
|
||||
"description": "Semi-arid transition zones with sparse vegetation, scattered shrubs and bushes, serving as fallback biome for indeterminate climate conditions",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 1,
|
||||
"token_requirements": {
|
||||
"_comment": "Fallback biome - no specific requirements, catches all unmatched areas"
|
||||
},
|
||||
"climate_conditions": {
|
||||
"moderate_aridity": true,
|
||||
"variable_temperatures": true,
|
||||
"irregular_precipitation": true,
|
||||
"transitional_zone": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 1500,
|
||||
"typical_range": [200, 800],
|
||||
"formation_zone": "transition_areas_between_major_biomes"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Default fallback biome for areas not matching specific climate criteria",
|
||||
"geographic_distribution": "Transition zones, climate boundaries, indeterminate areas",
|
||||
"rarity": "Common - appears where other biomes don't fit",
|
||||
"minimum_area": 50,
|
||||
"typical_area_range": [100, 500]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "mixed_shrubs_and_bushes",
|
||||
"secondary": ["drought_tolerant_shrubs", "hardy_grasses", "scattered_small_trees", "thorny_bushes"],
|
||||
"characteristics": [
|
||||
"sparse_vegetation_cover",
|
||||
"drought_adaptation",
|
||||
"mixed_growth_patterns",
|
||||
"seasonal_variation",
|
||||
"opportunistic_growth"
|
||||
],
|
||||
"forest_compatibility": "scattered_trees_only",
|
||||
"note": "Adaptable vegetation that survives in variable conditions"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"vegetation_density": 1.2,
|
||||
"soil_stability": 1.4,
|
||||
"erosion_resistance": 1.1,
|
||||
"water_retention": 1.0,
|
||||
"fire_risk": 1.6,
|
||||
"biodiversity": 1.1
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"agriculture": 0.7,
|
||||
"livestock_grazing": 1.4,
|
||||
"small_game_hunting": 1.2,
|
||||
"medicinal_plants": 1.3,
|
||||
"thorny_wood": 1.1,
|
||||
"wind_energy": 1.2,
|
||||
"solar_energy": 1.3,
|
||||
"forestry": 0.3,
|
||||
"industrial_suitability": 0.8,
|
||||
"tourism": 0.6
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"basic_ground_preparation",
|
||||
"seasonal_weather_adaptation",
|
||||
"dust_and_wind_protection"
|
||||
],
|
||||
"advantages": [
|
||||
"low_environmental_restrictions",
|
||||
"moderate_construction_costs",
|
||||
"good_solar_exposure",
|
||||
"reasonable_access_routes"
|
||||
],
|
||||
"challenges": [
|
||||
"limited_water_availability",
|
||||
"variable_soil_conditions",
|
||||
"fire_risk_management",
|
||||
"dust_storm_considerations"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"moderate_concealment": 1.2,
|
||||
"irregular_terrain_advantage": 1.1
|
||||
},
|
||||
"economic_factors": {
|
||||
"low_development_costs": 1.3,
|
||||
"moderate_maintenance_costs": 1.1,
|
||||
"grazing_income": 1.4
|
||||
},
|
||||
"strategic_value": {
|
||||
"transition_zone_control": 1.2,
|
||||
"buffer_territory": 1.3,
|
||||
"fallback_settlement": 1.1
|
||||
}
|
||||
},
|
||||
|
||||
"seasonal_patterns": {
|
||||
"wet_season": {
|
||||
"conditions": "increased_vegetation_growth_and_temporary_blooming",
|
||||
"opportunities": "grazing_improvement_and_limited_agriculture",
|
||||
"wildlife": "increased_activity_and_breeding"
|
||||
},
|
||||
"dry_season": {
|
||||
"conditions": "vegetation_dormancy_and_increased_fire_risk",
|
||||
"challenges": "water_scarcity_and_livestock_stress",
|
||||
"wildlife": "reduced_activity_and_migration"
|
||||
}
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"small_mammals",
|
||||
"ground_birds",
|
||||
"reptiles",
|
||||
"hardy_insects"
|
||||
],
|
||||
"hunting_opportunities": 1.2,
|
||||
"biodiversity": 1.1,
|
||||
"conservation_value": "moderate_ecosystem_diversity"
|
||||
},
|
||||
|
||||
"soil_characteristics": {
|
||||
"soil_type": "variable_sandy_clay_soils",
|
||||
"organic_matter": "moderate_due_to_mixed_vegetation",
|
||||
"drainage": "generally_well_drained_with_seasonal_variation",
|
||||
"erosion_risk": "moderate_especially_during_dry_periods"
|
||||
},
|
||||
|
||||
"land_use_potential": {
|
||||
"extensive_grazing": "primary_economic_use",
|
||||
"limited_agriculture": "drought_resistant_crops_only",
|
||||
"renewable_energy": "good_solar_and_wind_potential",
|
||||
"rural_settlements": "viable_with_water_management"
|
||||
},
|
||||
|
||||
"water_management": {
|
||||
"water_sources": "seasonal_streams_and_groundwater",
|
||||
"conservation_needs": "essential_for_any_development",
|
||||
"irrigation_potential": "limited_but_possible_with_investment",
|
||||
"drought_resilience": "moderate_natural_adaptation"
|
||||
},
|
||||
|
||||
"fire_ecology": {
|
||||
"natural_fire_frequency": "irregular_seasonal_fires",
|
||||
"fire_adaptation": "mixed_vegetation_recovery_rates",
|
||||
"fire_management": "controlled_burns_for_grazing_improvement",
|
||||
"fire_prevention": "firebreaks_and_early_warning_systems"
|
||||
}
|
||||
}
|
||||
131
gameData/Biomes/storm_prairie.json
Normal file
131
gameData/Biomes/storm_prairie.json
Normal file
@ -0,0 +1,131 @@
|
||||
{
|
||||
"biome_id": "storm_prairie",
|
||||
"display_name": "Storm Prairie",
|
||||
"description": "Windswept grasslands in high-wind zones with sufficient rainfall, featuring wind-resistant vegetation but hostile to forest growth",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 7,
|
||||
"token_requirements": {
|
||||
"highWind_tokens": {"min": 2, "condition": "above_storm_threshold"},
|
||||
"rain_tokens": {"min": 300, "condition": "sufficient_moisture"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"frequent_high_winds": true,
|
||||
"adequate_rainfall": true,
|
||||
"temperature_suitable_for_growth": true,
|
||||
"forest_growth_prevented": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 100,
|
||||
"maximum": 1000,
|
||||
"typical_range": [200, 800],
|
||||
"formation_zone": "interior_continental_areas_with_wind_exposure"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by highWind_tokens in areas with sufficient rain_tokens but prevented forest growth",
|
||||
"geographic_distribution": "Interior continental areas with strong wind patterns",
|
||||
"rarity": "Uncommon - requires specific combination of high wind and adequate rainfall",
|
||||
"minimum_area": 100,
|
||||
"typical_area_range": [200, 800]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "wind_resistant_grasslands",
|
||||
"secondary": ["hardy_shrubs", "low_bushes", "wind_adapted_wildflowers"],
|
||||
"characteristics": [
|
||||
"deep_root_systems",
|
||||
"flexible_stems",
|
||||
"low_profile_growth",
|
||||
"rapid_regrowth_after_damage"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "High winds prevent tree establishment and growth"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"wind_energy": 2.0,
|
||||
"grassland_productivity": 1.6,
|
||||
"soil_conservation": 1.4,
|
||||
"wildfire_resilience": 1.8,
|
||||
"erosion_resistance": 1.3,
|
||||
"carbon_storage": 1.2
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"wind_energy": 2.0,
|
||||
"grazing_land": 1.8,
|
||||
"wild_game": 1.4,
|
||||
"medicinal_herbs": 1.3,
|
||||
"honey_production": 1.6,
|
||||
"agriculture": 0.7,
|
||||
"forestry": 0.0,
|
||||
"industrial_suitability": 1.1,
|
||||
"recreation": 1.2
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"wind_resistant_building_design",
|
||||
"deep_foundations",
|
||||
"aerodynamic_structures",
|
||||
"flexible_infrastructure"
|
||||
],
|
||||
"advantages": [
|
||||
"excellent_wind_energy_potential",
|
||||
"wide_open_spaces_for_development",
|
||||
"good_soil_for_adapted_agriculture",
|
||||
"natural_firebreaks"
|
||||
],
|
||||
"challenges": [
|
||||
"constant_wind_stress_on_structures",
|
||||
"limited_natural_windbreaks",
|
||||
"difficulty_establishing_trees",
|
||||
"seasonal_wind_variations"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"open_terrain_visibility": 2.0,
|
||||
"difficult_approach": 1.3
|
||||
},
|
||||
"economic_factors": {
|
||||
"wind_farm_efficiency": 2.2,
|
||||
"livestock_grazing_bonus": 1.5,
|
||||
"construction_wind_resistance_costs": 1.4
|
||||
},
|
||||
"strategic_value": {
|
||||
"renewable_energy_hub": 2.5,
|
||||
"cavalry_and_vehicle_advantage": 1.8,
|
||||
"early_warning_systems": 1.9
|
||||
}
|
||||
},
|
||||
|
||||
"seasonal_variations": {
|
||||
"growing_season": {
|
||||
"grass_growth_peak": "spring_and_early_summer",
|
||||
"wildflower_blooms": "creating_temporary_beauty",
|
||||
"wildlife_activity": "peak_grazing_and_nesting"
|
||||
},
|
||||
"wind_patterns": {
|
||||
"storm_season": "maximum_wind_intensity",
|
||||
"calm_periods": "rare_opportunities_for_maintenance",
|
||||
"seasonal_wind_direction_changes": "affecting_energy_generation"
|
||||
}
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"prairie_dogs",
|
||||
"wind_resistant_birds",
|
||||
"grazing_herbivores",
|
||||
"burrowing_mammals"
|
||||
],
|
||||
"hunting_opportunities": 1.4,
|
||||
"biodiversity": 1.1,
|
||||
"migration_routes": "important_stopover_for_wind_dispersed_species"
|
||||
},
|
||||
|
||||
}
|
||||
157
gameData/Biomes/temperate_forest.json
Normal file
157
gameData/Biomes/temperate_forest.json
Normal file
@ -0,0 +1,157 @@
|
||||
{
|
||||
"biome_id": "temperate_forest",
|
||||
"display_name": "Temperate Forest",
|
||||
"description": "Deciduous and mixed forests in moderate climate zones with seasonal variations, balanced temperature and moderate rainfall",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 12,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"min": 300, "condition": "moderate_rainfall"},
|
||||
"temperature": {"min": 15, "max": 25, "condition": "temperate_climate"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"moderate_temperatures": true,
|
||||
"seasonal_variation": true,
|
||||
"adequate_rainfall": true,
|
||||
"winter_dormancy_period": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 1200,
|
||||
"typical_range": [100, 800],
|
||||
"formation_zone": "mid_latitude_regions_with_seasonal_climate"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by moderate rain_tokens (300+) with temperate temperatures (15-25°C)",
|
||||
"geographic_distribution": "Mid-latitude regions with seasonal climate patterns",
|
||||
"rarity": "Common - standard forest biome in temperate zones",
|
||||
"minimum_area": 150,
|
||||
"typical_area_range": [300, 1200]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "deciduous_and_mixed_forests",
|
||||
"secondary": ["oak_maple_forests", "beech_birch_woodlands", "mixed_coniferous_deciduous"],
|
||||
"characteristics": [
|
||||
"seasonal_leaf_drop",
|
||||
"cold_adaptation",
|
||||
"moderate_growth_rates",
|
||||
"diverse_understory",
|
||||
"autumn_color_displays"
|
||||
],
|
||||
"forest_compatibility": true,
|
||||
"note": "Classic forest ecosystem with seasonal adaptations"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"biodiversity": 1.8,
|
||||
"carbon_storage": 1.9,
|
||||
"seasonal_beauty": 2.5,
|
||||
"soil_quality": 2.0,
|
||||
"water_regulation": 1.7,
|
||||
"wildlife_habitat": 2.2
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"wood": 1.5,
|
||||
"paper_products": 1.8,
|
||||
"maple_syrup": 2.0,
|
||||
"nuts_and_berries": 1.6,
|
||||
"mushrooms": 1.7,
|
||||
"wildlife": 1.8,
|
||||
"agriculture": 1.2,
|
||||
"industrial_suitability": 0.7,
|
||||
"tourism": 2.0,
|
||||
"recreation": 2.2
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"seasonal_weather_protection",
|
||||
"foundation_frost_protection",
|
||||
"moderate_humidity_control"
|
||||
],
|
||||
"advantages": [
|
||||
"sustainable_timber_production",
|
||||
"good_construction_conditions",
|
||||
"reliable_water_sources",
|
||||
"moderate_climate_for_workers"
|
||||
],
|
||||
"challenges": [
|
||||
"seasonal_access_limitations",
|
||||
"winter_construction_delays",
|
||||
"forest_clearing_requirements",
|
||||
"environmental_protection_laws"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_concealment": 1.8,
|
||||
"seasonal_tactical_variation": 1.6
|
||||
},
|
||||
"economic_factors": {
|
||||
"sustainable_resource_income": 1.8,
|
||||
"seasonal_tourism_peaks": 2.0,
|
||||
"moderate_construction_costs": 1.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"resource_sustainability": 2.0,
|
||||
"population_support": 1.8,
|
||||
"defensive_terrain": 1.6
|
||||
}
|
||||
},
|
||||
|
||||
"seasonal_cycle": {
|
||||
"spring": {
|
||||
"characteristics": "leaf_emergence_and_flowering",
|
||||
"activities": "planting_and_early_harvesting",
|
||||
"wildlife": "breeding_and_migration"
|
||||
},
|
||||
"summer": {
|
||||
"characteristics": "full_canopy_and_peak_growth",
|
||||
"activities": "maximum_productivity_period",
|
||||
"wildlife": "peak_activity_and_abundance"
|
||||
},
|
||||
"autumn": {
|
||||
"characteristics": "leaf_color_change_and_fall",
|
||||
"activities": "harvest_and_preparation",
|
||||
"wildlife": "migration_and_preparation"
|
||||
},
|
||||
"winter": {
|
||||
"characteristics": "dormancy_and_snow_cover",
|
||||
"activities": "planning_and_indoor_work",
|
||||
"wildlife": "hibernation_and_adaptation"
|
||||
}
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"diversity_index": 1.8,
|
||||
"game_animals": [
|
||||
"deer",
|
||||
"wild_boar",
|
||||
"small_mammals",
|
||||
"forest_birds"
|
||||
],
|
||||
"hunting_opportunities": 1.8,
|
||||
"conservation_value": "moderate_biodiversity_and_ecosystem_services"
|
||||
},
|
||||
|
||||
"forest_management": {
|
||||
"sustainable_harvesting": "selective_cutting_and_rotation",
|
||||
"regeneration": "natural_and_assisted_forest_renewal",
|
||||
"fire_management": "controlled_burns_and_fire_prevention",
|
||||
"pest_control": "integrated_pest_management"
|
||||
},
|
||||
|
||||
"recreation_opportunities": {
|
||||
"hiking_and_trails": 2.0,
|
||||
"camping": 1.8,
|
||||
"wildlife_watching": 1.9,
|
||||
"autumn_foliage_tourism": 2.5,
|
||||
"hunting_and_fishing": 1.7
|
||||
},
|
||||
|
||||
}
|
||||
147
gameData/Biomes/tropical_rainforest.json
Normal file
147
gameData/Biomes/tropical_rainforest.json
Normal file
@ -0,0 +1,147 @@
|
||||
{
|
||||
"biome_id": "tropical_rainforest",
|
||||
"display_name": "Tropical Rainforest",
|
||||
"description": "Dense, high-biodiversity forests in equatorial regions with high temperature and abundant rainfall, representing peak terrestrial biodiversity",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 10,
|
||||
"token_requirements": {
|
||||
"rain_tokens": {"min": 500, "condition": "abundant_rainfall"},
|
||||
"temperature": {"min": 25, "condition": "tropical_heat"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"high_temperature": true,
|
||||
"abundant_rainfall": true,
|
||||
"high_humidity": true,
|
||||
"minimal_seasonal_variation": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 1500,
|
||||
"typical_range": [0, 800],
|
||||
"formation_zone": "equatorial_lowlands_and_foothills"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by high rain_tokens (500+) combined with tropical temperatures (25°C+)",
|
||||
"geographic_distribution": "Equatorial regions with ITCZ influence and abundant moisture",
|
||||
"rarity": "Moderate - requires specific combination of heat and extreme moisture",
|
||||
"minimum_area": 200,
|
||||
"typical_area_range": [500, 2000],
|
||||
"formation_priority": "High - represents Congo Basin success pattern"
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "multi_layered_forest_canopy",
|
||||
"secondary": ["emergent_trees", "canopy_layer", "understory", "forest_floor"],
|
||||
"characteristics": [
|
||||
"extreme_biodiversity",
|
||||
"rapid_nutrient_cycling",
|
||||
"vertical_stratification",
|
||||
"epiphytic_communities",
|
||||
"buttress_root_systems"
|
||||
],
|
||||
"forest_compatibility": true,
|
||||
"note": "Peak forest development with maximum biomass and species diversity"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"biodiversity": 3.0,
|
||||
"carbon_storage": 2.8,
|
||||
"oxygen_production": 2.5,
|
||||
"water_regulation": 2.2,
|
||||
"soil_protection": 2.0,
|
||||
"climate_regulation": 2.3
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"wood": 2.0,
|
||||
"biodiversity": 3.0,
|
||||
"medicinal_plants": 2.8,
|
||||
"exotic_fruits": 2.5,
|
||||
"rubber_and_latex": 2.2,
|
||||
"spices": 2.0,
|
||||
"agriculture": 0.8,
|
||||
"industrial_suitability": 0.3,
|
||||
"tourism": 2.4,
|
||||
"research_value": 3.0
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"humidity_resistant_materials",
|
||||
"elevated_foundations",
|
||||
"pest_control_systems",
|
||||
"climate_controlled_storage"
|
||||
],
|
||||
"advantages": [
|
||||
"abundant_biological_resources",
|
||||
"natural_pharmaceuticals",
|
||||
"eco_tourism_potential",
|
||||
"carbon_credit_opportunities"
|
||||
],
|
||||
"challenges": [
|
||||
"extremely_difficult_construction",
|
||||
"high_maintenance_costs",
|
||||
"disease_and_pest_pressure",
|
||||
"environmental_protection_requirements"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_concealment": 2.5,
|
||||
"difficult_terrain": 2.0,
|
||||
"guerrilla_warfare_advantage": 2.8
|
||||
},
|
||||
"economic_factors": {
|
||||
"construction_costs": 2.5,
|
||||
"maintenance_difficulty": 2.3,
|
||||
"biological_resource_income": 2.8,
|
||||
"environmental_services_value": 3.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"natural_fortress": 2.2,
|
||||
"resource_monopoly": 2.6,
|
||||
"environmental_importance": 3.0
|
||||
}
|
||||
},
|
||||
|
||||
"ecosystem_services": {
|
||||
"climate_regulation": "global_carbon_cycling_and_oxygen_production",
|
||||
"water_cycle": "rainfall_generation_and_watershed_protection",
|
||||
"biodiversity_conservation": "highest_species_diversity_on_planet",
|
||||
"soil_conservation": "preventing_erosion_and_maintaining_fertility"
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"diversity_index": 3.0,
|
||||
"endemic_species": "extremely_high",
|
||||
"hunting_opportunities": 1.8,
|
||||
"conservation_priority": "critical",
|
||||
"research_opportunities": 3.0
|
||||
},
|
||||
|
||||
"layered_structure": {
|
||||
"emergent_layer": "tallest_trees_reaching_60m_plus",
|
||||
"canopy_layer": "main_photosynthetic_layer_30_45m",
|
||||
"understory": "shade_adapted_plants_5_25m",
|
||||
"forest_floor": "decomposition_and_nutrient_cycling"
|
||||
},
|
||||
|
||||
"seasonal_patterns": {
|
||||
"wet_season": "peak_growth_and_reproduction",
|
||||
"dry_season": "minimal_but_still_adequate_rainfall",
|
||||
"temperature_variation": "minimal_seasonal_change",
|
||||
"biological_activity": "year_round_high_activity"
|
||||
},
|
||||
|
||||
"formation_requirements": {
|
||||
"temperature_stability": "consistent_warm_temperatures",
|
||||
"rainfall_consistency": "year_round_abundant_water",
|
||||
"soil_drainage": "well_drained_but_water_retentive",
|
||||
"minimal_disturbance": "requires_stable_conditions_for_development"
|
||||
},
|
||||
|
||||
}
|
||||
156
gameData/Biomes/tundra.json
Normal file
156
gameData/Biomes/tundra.json
Normal file
@ -0,0 +1,156 @@
|
||||
{
|
||||
"biome_id": "tundra",
|
||||
"display_name": "Tundra",
|
||||
"description": "Arctic and alpine regions with extremely cold temperatures, permafrost, and minimal vegetation adapted to harsh conditions",
|
||||
|
||||
"classification": {
|
||||
"type": "normal_biome",
|
||||
"priority": 14,
|
||||
"token_requirements": {
|
||||
"temperature": {"max": -10, "condition": "extremely_cold"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"extremely_cold_temperatures": true,
|
||||
"permafrost_layer": true,
|
||||
"short_growing_season": true,
|
||||
"low_precipitation": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": 0,
|
||||
"maximum": 2000,
|
||||
"typical_range": [0, 500],
|
||||
"formation_zone": "arctic_regions_and_high_mountain_areas"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by extremely cold temperatures (≤-10°C) regardless of precipitation",
|
||||
"geographic_distribution": "Arctic regions and high mountain areas",
|
||||
"rarity": "Uncommon - limited to polar and high-altitude zones",
|
||||
"minimum_area": 100,
|
||||
"typical_area_range": [300, 1500]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "cold_adapted_specialists",
|
||||
"secondary": ["mosses", "lichens", "dwarf_shrubs", "sedges"],
|
||||
"characteristics": [
|
||||
"extremely_low_growth_forms",
|
||||
"cold_tolerance",
|
||||
"short_growing_season_adaptation",
|
||||
"permafrost_root_systems",
|
||||
"UV_radiation_protection"
|
||||
],
|
||||
"forest_compatibility": false,
|
||||
"note": "Only the most cold-adapted plants can survive permafrost conditions"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"permafrost_depth": 2.8,
|
||||
"cold_extremes": 3.0,
|
||||
"growing_season_length": 0.2,
|
||||
"solar_radiation_extremes": 2.5,
|
||||
"wind_exposure": 2.2,
|
||||
"biodiversity": 0.3
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"mineral_extraction": 1.6,
|
||||
"oil_and_gas": 1.8,
|
||||
"rare_earth_elements": 1.4,
|
||||
"ice_and_freshwater": 2.0,
|
||||
"wildlife_fur": 1.5,
|
||||
"agriculture": 0.0,
|
||||
"forestry": 0.0,
|
||||
"renewable_energy": 0.8,
|
||||
"industrial_suitability": 0.4,
|
||||
"research_value": 2.2
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"permafrost_foundation_systems",
|
||||
"extreme_cold_protection",
|
||||
"heating_system_redundancy",
|
||||
"ice_road_transportation"
|
||||
],
|
||||
"advantages": [
|
||||
"mineral_and_energy_resources",
|
||||
"natural_refrigeration",
|
||||
"strategic_location_value",
|
||||
"minimal_environmental_constraints"
|
||||
],
|
||||
"challenges": [
|
||||
"extreme_construction_costs",
|
||||
"permafrost_instability",
|
||||
"transportation_difficulties",
|
||||
"worker_safety_and_health"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"extreme_weather_advantage": 3.0,
|
||||
"natural_fortress": 2.8,
|
||||
"supply_line_difficulty": 3.2
|
||||
},
|
||||
"economic_factors": {
|
||||
"extraction_bonus": 1.8,
|
||||
"construction_costs": 4.0,
|
||||
"heating_and_energy_costs": 3.5,
|
||||
"specialized_equipment_requirements": 3.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"resource_control": 2.2,
|
||||
"territorial_claims": 2.5,
|
||||
"climate_research": 2.8
|
||||
}
|
||||
},
|
||||
|
||||
"survival_challenges": {
|
||||
"temperature_management": "critical_for_survival",
|
||||
"food_scarcity": "hunting_and_imported_supplies",
|
||||
"isolation": "extreme_remoteness_and_communication",
|
||||
"equipment_failure": "catastrophic_in_cold_conditions"
|
||||
},
|
||||
|
||||
"wildlife": {
|
||||
"adapted_species": [
|
||||
"arctic_foxes",
|
||||
"caribou_and_reindeer",
|
||||
"polar_bears",
|
||||
"migratory_birds"
|
||||
],
|
||||
"hunting_opportunities": 1.5,
|
||||
"biodiversity": 0.3,
|
||||
"conservation_value": "unique_cold_adapted_species"
|
||||
},
|
||||
|
||||
"seasonal_extremes": {
|
||||
"polar_night": "months_of_darkness",
|
||||
"midnight_sun": "months_of_continuous_daylight",
|
||||
"temperature_variation": "extreme_seasonal_differences",
|
||||
"ice_cycles": "freeze_thaw_permafrost_dynamics"
|
||||
},
|
||||
|
||||
"permafrost_dynamics": {
|
||||
"active_layer": "seasonal_thaw_zone",
|
||||
"permafrost_table": "permanently_frozen_layer",
|
||||
"thermokarst": "ground_collapse_from_thawing",
|
||||
"frost_heave": "ground_expansion_from_freezing"
|
||||
},
|
||||
|
||||
"research_opportunities": {
|
||||
"climate_change_studies": 2.8,
|
||||
"permafrost_research": 2.5,
|
||||
"cold_adaptation_biology": 2.2,
|
||||
"ice_core_paleoclimatology": 2.0
|
||||
},
|
||||
|
||||
"transportation": {
|
||||
"ice_roads": "seasonal_transportation_corridors",
|
||||
"aircraft_dependency": "primary_year_round_access",
|
||||
"specialized_vehicles": "cold_weather_equipment_required",
|
||||
"fuel_logistics": "critical_supply_chain_management"
|
||||
},
|
||||
|
||||
}
|
||||
124
gameData/Biomes/wetlands.json
Normal file
124
gameData/Biomes/wetlands.json
Normal file
@ -0,0 +1,124 @@
|
||||
{
|
||||
"biome_id": "wetlands",
|
||||
"display_name": "Wetlands",
|
||||
"description": "Marshy regions formed by recurring flood patterns, creating specialized aquatic ecosystems with high biodiversity",
|
||||
|
||||
"classification": {
|
||||
"type": "special_climate_zone",
|
||||
"priority": 1,
|
||||
"token_requirements": {
|
||||
"flood_tokens": {"min": 3, "condition": "above_flood_threshold"}
|
||||
},
|
||||
"climate_conditions": {
|
||||
"frequent_flooding": true,
|
||||
"high_water_table": true,
|
||||
"poor_drainage": true,
|
||||
"seasonal_water_variation": true
|
||||
},
|
||||
"elevation_range": {
|
||||
"minimum": -10,
|
||||
"maximum": 200,
|
||||
"typical_range": [0, 100],
|
||||
"formation_zone": "low_lying_areas_with_poor_drainage"
|
||||
},
|
||||
"generation_notes": {
|
||||
"formation_process": "Created by flood_tokens from WindRegions with high wetness concentrations",
|
||||
"geographic_distribution": "Low-lying areas with poor drainage and frequent flooding",
|
||||
"rarity": "Common in flood-prone river deltas and coastal plains",
|
||||
"minimum_area": 25,
|
||||
"typical_area_range": [50, 300]
|
||||
}
|
||||
},
|
||||
|
||||
"vegetation": {
|
||||
"primary": "marshes_and_swamps",
|
||||
"secondary": ["cattails", "water_lilies", "cypress_trees", "bog_plants"],
|
||||
"characteristics": [
|
||||
"water_adapted_root_systems",
|
||||
"flood_tolerance",
|
||||
"nutrient_cycling_specialists",
|
||||
"methane_production"
|
||||
],
|
||||
"forest_compatibility": "specialized_swamp_forests_only",
|
||||
"note": "Only specialized flood-tolerant tree species can survive"
|
||||
},
|
||||
|
||||
"environmental_properties": {
|
||||
"water_resources": 2.5,
|
||||
"biodiversity": 1.8,
|
||||
"carbon_sequestration": 2.2,
|
||||
"flood_control": 2.0,
|
||||
"water_filtration": 2.3,
|
||||
"methane_production": 1.6
|
||||
},
|
||||
|
||||
"resource_modifiers": {
|
||||
"freshwater": 2.0,
|
||||
"fish_and_waterfowl": 2.5,
|
||||
"medicinal_plants": 1.7,
|
||||
"peat": 2.8,
|
||||
"natural_gas": 1.4,
|
||||
"agriculture": 0.3,
|
||||
"forestry": 0.5,
|
||||
"industrial_suitability": 0.2,
|
||||
"recreation": 1.6
|
||||
},
|
||||
|
||||
"industrial_considerations": {
|
||||
"construction_requirements": [
|
||||
"pile_foundations",
|
||||
"waterproof_construction",
|
||||
"elevated_roads_and_platforms",
|
||||
"specialized_drainage_systems"
|
||||
],
|
||||
"advantages": [
|
||||
"natural_water_treatment",
|
||||
"flood_protection_for_surrounding_areas",
|
||||
"unique_ecosystem_services",
|
||||
"peat_energy_source"
|
||||
],
|
||||
"challenges": [
|
||||
"extremely_difficult_construction",
|
||||
"seasonal_accessibility_issues",
|
||||
"methane_emission_management",
|
||||
"environmental_protection_requirements"
|
||||
]
|
||||
},
|
||||
|
||||
"gameplay_effects": {
|
||||
"defensive_bonuses": {
|
||||
"natural_barrier": 1.8,
|
||||
"difficult_terrain_advantage": 2.2
|
||||
},
|
||||
"economic_factors": {
|
||||
"construction_costs": 3.0,
|
||||
"maintenance_difficulty": 2.5,
|
||||
"environmental_services_value": 2.0
|
||||
},
|
||||
"strategic_value": {
|
||||
"natural_fortress": 1.9,
|
||||
"water_control": 2.1,
|
||||
"ecosystem_services": 2.3
|
||||
}
|
||||
},
|
||||
|
||||
"special_features": {
|
||||
"seasonal_variations": {
|
||||
"wet_season": "maximum_biodiversity_and_inaccessibility",
|
||||
"dry_season": "limited_access_for_construction_and_harvesting"
|
||||
},
|
||||
"ecosystem_services": [
|
||||
"flood_control",
|
||||
"water_purification",
|
||||
"carbon_storage",
|
||||
"wildlife_habitat"
|
||||
],
|
||||
"environmental_hazards": [
|
||||
"methane_accumulation",
|
||||
"disease_vectors",
|
||||
"unstable_ground",
|
||||
"toxic_plant_species"
|
||||
]
|
||||
},
|
||||
|
||||
}
|
||||
40
gameData/MapFeatures/aluminum.json
Normal file
40
gameData/MapFeatures/aluminum.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"aluminum_resources": {
|
||||
"bauxite_deposit": {
|
||||
"display_name": "Bauxite Deposit",
|
||||
"description": "Primary aluminum ore with high aluminum oxide content ideal for smelting",
|
||||
"formation_type": "tropical_laterite_weathering",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"laterite_aluminum": {
|
||||
"display_name": "Laterite Aluminum",
|
||||
"description": "Weathered aluminum-rich soil formed in tropical climates",
|
||||
"formation_type": "tropical_soil_weathering",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"nepheline_syenite": {
|
||||
"display_name": "Nepheline Syenite",
|
||||
"description": "Igneous rock with aluminum silicate minerals suitable for aluminum extraction",
|
||||
"formation_type": "alkaline_igneous_intrusion",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"clay_aluminum": {
|
||||
"display_name": "Aluminum Clay",
|
||||
"description": "Clay deposits with elevated aluminum content requiring advanced processing",
|
||||
"formation_type": "sedimentary_aluminum_concentration",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "high",
|
||||
"quality": "low"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/anomalies.json
Normal file
40
gameData/MapFeatures/anomalies.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"anomalies": {
|
||||
"magnetic_anomaly": {
|
||||
"display_name": "Magnetic Anomaly",
|
||||
"description": "Area with unusual magnetic properties affecting instruments and containing rare metals",
|
||||
"formation_type": "magnetic_field",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"radio_silence_zone": {
|
||||
"display_name": "Radio Silence Zone",
|
||||
"description": "Mysterious area where radio communications are disrupted",
|
||||
"formation_type": "electromagnetic",
|
||||
"budget_impact": -1
|
||||
},
|
||||
"meteorite_impact": {
|
||||
"display_name": "Meteorite Impact",
|
||||
"description": "Site of ancient meteorite strike with rare metals and unique minerals",
|
||||
"formation_type": "extraterrestrial",
|
||||
"budget_impact": 5
|
||||
},
|
||||
"crystalline_formation": {
|
||||
"display_name": "Crystalline Formation",
|
||||
"description": "Natural crystal deposits with technological and commercial value",
|
||||
"formation_type": "mineral_crystal",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"thermal_vent": {
|
||||
"display_name": "Thermal Vent",
|
||||
"description": "Underground heat source with geothermal energy potential",
|
||||
"formation_type": "geothermal",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"unstable_ground": {
|
||||
"display_name": "Unstable Ground",
|
||||
"description": "Geologically unstable area prone to landslides and collapse",
|
||||
"formation_type": "geological_instability",
|
||||
"budget_impact": -3
|
||||
}
|
||||
}
|
||||
}
|
||||
58
gameData/MapFeatures/base_metals.json
Normal file
58
gameData/MapFeatures/base_metals.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"base_metal_resources": {
|
||||
"tin_placer": {
|
||||
"display_name": "Tin Placer",
|
||||
"description": "Cassiterite deposits concentrated in alluvial gravels and beach sands",
|
||||
"formation_type": "alluvial_tin_concentration",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"tin_lode": {
|
||||
"display_name": "Tin Lode",
|
||||
"description": "Primary cassiterite ore in granite-related veins and greisen",
|
||||
"formation_type": "granitic_tin_mineralization",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"lead_galena": {
|
||||
"display_name": "Lead Galena",
|
||||
"description": "Primary lead sulfide ore often associated with silver and zinc",
|
||||
"formation_type": "sulfide_mineralization",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"lead_carbonate": {
|
||||
"display_name": "Lead Carbonate",
|
||||
"description": "Weathered lead ore with cerussite and anglesite minerals",
|
||||
"formation_type": "lead_oxidation_zone",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"nickel_laterite": {
|
||||
"display_name": "Nickel Laterite",
|
||||
"description": "Tropical weathering deposit with garnierite and limonite nickel ores",
|
||||
"formation_type": "laterite_nickel_weathering",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"nickel_sulfide": {
|
||||
"display_name": "Nickel Sulfide",
|
||||
"description": "Primary nickel ore with pentlandite in mafic intrusions",
|
||||
"formation_type": "magmatic_sulfide_segregation",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
}
|
||||
}
|
||||
}
|
||||
58
gameData/MapFeatures/coal.json
Normal file
58
gameData/MapFeatures/coal.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"coal_resources": {
|
||||
"rich_coal_seam": {
|
||||
"display_name": "Rich Coal Seam",
|
||||
"description": "High-quality coal deposit with excellent heating value and low impurities",
|
||||
"formation_type": "compressed_carboniferous_forest",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"coal_seam": {
|
||||
"display_name": "Coal Seam",
|
||||
"description": "Standard coal deposit suitable for industrial and heating applications",
|
||||
"formation_type": "compressed_carboniferous_forest",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"coal_outcrop": {
|
||||
"display_name": "Coal Outcrop",
|
||||
"description": "Surface-exposed coal formation easy to access but lower quality",
|
||||
"formation_type": "exposed_carboniferous_forest",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"surface_coal": {
|
||||
"display_name": "Surface Coal",
|
||||
"description": "Weathered coal deposits scattered on surface with minimal extraction requirements",
|
||||
"formation_type": "eroded_coal_seam",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "low",
|
||||
"quality": "low"
|
||||
},
|
||||
"peat_bog": {
|
||||
"display_name": "Peat Bog",
|
||||
"description": "Early-stage coal formation providing low-grade fuel and soil amendment",
|
||||
"formation_type": "partially_decomposed_organic_matter",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "low",
|
||||
"quality": "low"
|
||||
},
|
||||
"lignite_deposit": {
|
||||
"display_name": "Lignite Deposit",
|
||||
"description": "Brown coal with moderate heating value, intermediate between peat and bituminous coal",
|
||||
"formation_type": "intermediate_carboniferous_compression",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "medium",
|
||||
"quality": "medium"
|
||||
}
|
||||
}
|
||||
}
|
||||
52
gameData/MapFeatures/coastal_features.json
Normal file
52
gameData/MapFeatures/coastal_features.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"coastal_features": {
|
||||
"sea_cave": {
|
||||
"display_name": "Sea Cave",
|
||||
"description": "Ocean-carved cavern accessible at low tide with marine ecosystems",
|
||||
"formation_type": "marine_erosion",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"tidal_pool": {
|
||||
"display_name": "Tidal Pool",
|
||||
"description": "Rock depressions filled with seawater hosting unique marine life",
|
||||
"formation_type": "tidal_formation",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"natural_harbor": {
|
||||
"display_name": "Natural Harbor",
|
||||
"description": "Sheltered coastal bay perfect for maritime activities and ports",
|
||||
"formation_type": "coastal_geography",
|
||||
"budget_impact": 3
|
||||
},
|
||||
"coral_reef": {
|
||||
"display_name": "Coral Reef",
|
||||
"description": "Living reef structure providing marine biodiversity and coastal protection",
|
||||
"formation_type": "biological_formation",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"sea_stack": {
|
||||
"display_name": "Sea Stack",
|
||||
"description": "Isolated rocky pillar standing in shallow coastal waters",
|
||||
"formation_type": "marine_erosion",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"beach_dunes": {
|
||||
"display_name": "Beach Dunes",
|
||||
"description": "Sand formations shaped by wind providing coastal protection",
|
||||
"formation_type": "aeolian_formation",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"estuary": {
|
||||
"display_name": "Estuary",
|
||||
"description": "River mouth where freshwater meets saltwater creating rich ecosystems",
|
||||
"formation_type": "fluvial_marine",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"blowhole": {
|
||||
"display_name": "Blowhole",
|
||||
"description": "Coastal rock formation that shoots water sprays during high waves",
|
||||
"formation_type": "marine_erosion",
|
||||
"budget_impact": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
58
gameData/MapFeatures/copper.json
Normal file
58
gameData/MapFeatures/copper.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"copper_resources": {
|
||||
"porphyry_copper": {
|
||||
"display_name": "Porphyry Copper",
|
||||
"description": "Large-scale copper deposit in igneous intrusion with molybdenum traces",
|
||||
"formation_type": "igneous_hydrothermal_intrusion",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"copper_vein": {
|
||||
"display_name": "Copper Vein",
|
||||
"description": "High-grade copper ore in hydrothermal veins with excellent purity",
|
||||
"formation_type": "hydrothermal_vein_formation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"chalcopyrite_deposit": {
|
||||
"display_name": "Chalcopyrite Deposit",
|
||||
"description": "Standard copper sulfide ore suitable for flotation processing",
|
||||
"formation_type": "sulfide_mineralization",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"malachite_outcrop": {
|
||||
"display_name": "Malachite Outcrop",
|
||||
"description": "Green copper carbonate formation indicating deeper copper deposits",
|
||||
"formation_type": "copper_oxidation_zone",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"native_copper": {
|
||||
"display_name": "Native Copper",
|
||||
"description": "Pure metallic copper deposits requiring minimal processing",
|
||||
"formation_type": "basalt_flow_copper_precipitation",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"copper_shale": {
|
||||
"display_name": "Copper Shale",
|
||||
"description": "Sedimentary copper deposit with low grade but large extent",
|
||||
"formation_type": "sedimentary_copper_precipitation",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "high",
|
||||
"quality": "low"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/cultural_sites.json
Normal file
40
gameData/MapFeatures/cultural_sites.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"cultural_sites": {
|
||||
"ancient_ruins": {
|
||||
"display_name": "Ancient Ruins",
|
||||
"description": "Archaeological remains from past civilizations with historical value",
|
||||
"formation_type": "archaeological",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"abandoned_village": {
|
||||
"display_name": "Abandoned Village",
|
||||
"description": "Deserted rural settlement with basic infrastructure",
|
||||
"formation_type": "abandoned_settlement",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"old_monastery": {
|
||||
"display_name": "Old Monastery",
|
||||
"description": "Historic religious complex with stone architecture and strategic position",
|
||||
"formation_type": "religious_heritage",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"castle_ruins": {
|
||||
"display_name": "Castle Ruins",
|
||||
"description": "Remains of medieval fortress with defensive advantages and stone materials",
|
||||
"formation_type": "military_heritage",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"lighthouse": {
|
||||
"display_name": "Lighthouse",
|
||||
"description": "Coastal navigation aid with strategic maritime position",
|
||||
"formation_type": "maritime_infrastructure",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"historical_cemetery": {
|
||||
"display_name": "Historical Cemetery",
|
||||
"description": "Old burial ground with cultural significance and central location",
|
||||
"formation_type": "cultural_heritage",
|
||||
"budget_impact": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
45
gameData/MapFeatures/features_index.json
Normal file
45
gameData/MapFeatures/features_index.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"feature_system_version": "1.0",
|
||||
"description": "Map features catalog for procedural world generation",
|
||||
"last_updated": "2024-09-29",
|
||||
|
||||
"feature_categories": {
|
||||
"geological_formations": {
|
||||
"file": "geological_formations.json",
|
||||
"description": "Natural rock and terrain formations",
|
||||
"count": 10
|
||||
},
|
||||
"natural_landmarks": {
|
||||
"file": "natural_landmarks.json",
|
||||
"description": "Distinctive natural monuments and formations",
|
||||
"count": 6
|
||||
},
|
||||
"water_features": {
|
||||
"file": "water_features.json",
|
||||
"description": "Lakes, rivers, springs and wetlands",
|
||||
"count": 8
|
||||
},
|
||||
"industrial_ruins": {
|
||||
"file": "industrial_ruins.json",
|
||||
"description": "Abandoned industrial and military sites",
|
||||
"count": 8
|
||||
},
|
||||
"anomalies": {
|
||||
"file": "anomalies.json",
|
||||
"description": "Unusual geological and electromagnetic phenomena",
|
||||
"count": 6
|
||||
},
|
||||
"cultural_sites": {
|
||||
"file": "cultural_sites.json",
|
||||
"description": "Historical and archaeological locations",
|
||||
"count": 6
|
||||
}
|
||||
},
|
||||
|
||||
"generation_parameters": {
|
||||
"placement_probability": 0.05,
|
||||
"max_features_per_tile": 1,
|
||||
"biome_filtering": true,
|
||||
"budget_impact_range": [-3, 5]
|
||||
}
|
||||
}
|
||||
52
gameData/MapFeatures/forest_features.json
Normal file
52
gameData/MapFeatures/forest_features.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"forest_features": {
|
||||
"ancient_grove": {
|
||||
"display_name": "Ancient Grove",
|
||||
"description": "Stand of extremely old trees with rare wood and spiritual significance",
|
||||
"formation_type": "old_growth_forest",
|
||||
"budget_impact": 3
|
||||
},
|
||||
"forest_clearing": {
|
||||
"display_name": "Forest Clearing",
|
||||
"description": "Natural open space within forest perfect for settlements",
|
||||
"formation_type": "natural_opening",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"giant_tree": {
|
||||
"display_name": "Giant Tree",
|
||||
"description": "Massive individual tree suitable for treehouse construction",
|
||||
"formation_type": "exceptional_growth",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"bamboo_grove": {
|
||||
"display_name": "Bamboo Grove",
|
||||
"description": "Dense bamboo forest with rapid growth and construction materials",
|
||||
"formation_type": "bamboo_ecosystem",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"fruit_orchard": {
|
||||
"display_name": "Wild Fruit Orchard",
|
||||
"description": "Natural grove of fruit-bearing trees providing food resources",
|
||||
"formation_type": "fruit_tree_cluster",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"medicinal_grove": {
|
||||
"display_name": "Medicinal Grove",
|
||||
"description": "Forest area rich in plants with pharmaceutical properties",
|
||||
"formation_type": "medicinal_ecosystem",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"mushroom_grove": {
|
||||
"display_name": "Mushroom Grove",
|
||||
"description": "Forest area with abundant fungal growth and rare mushroom species",
|
||||
"formation_type": "fungal_ecosystem",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"carboniferous_forest": {
|
||||
"display_name": "Carboniferous Forest",
|
||||
"description": "Ancient forest remnant with giant ferns and primitive trees, containing coal seams",
|
||||
"formation_type": "paleozoic_relic",
|
||||
"budget_impact": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
64
gameData/MapFeatures/geological_formations.json
Normal file
64
gameData/MapFeatures/geological_formations.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"geological_formations": {
|
||||
"cave": {
|
||||
"display_name": "Cave",
|
||||
"description": "Natural underground cavern providing shelter and potential hidden resources",
|
||||
"formation_type": "erosion",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"hot_spring": {
|
||||
"display_name": "Hot Spring",
|
||||
"description": "Geothermally heated groundwater emerging at surface",
|
||||
"formation_type": "geothermal",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"canyon": {
|
||||
"display_name": "Canyon",
|
||||
"description": "Deep gorge carved by water erosion providing natural barriers",
|
||||
"formation_type": "erosion",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"plateau": {
|
||||
"display_name": "Plateau",
|
||||
"description": "Elevated flat-topped landform with commanding views",
|
||||
"formation_type": "erosion_resistant",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"geyser": {
|
||||
"display_name": "Geyser",
|
||||
"description": "Periodic eruption of heated groundwater and steam",
|
||||
"formation_type": "geothermal",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"cliff": {
|
||||
"display_name": "Cliff",
|
||||
"description": "Steep vertical rock face formed by erosion or faulting",
|
||||
"formation_type": "erosion_faulting",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"gorge": {
|
||||
"display_name": "Gorge",
|
||||
"description": "Narrow valley with steep rocky walls carved by water flow",
|
||||
"formation_type": "water_erosion",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"natural_bridge": {
|
||||
"display_name": "Natural Bridge",
|
||||
"description": "Rock arch formation spanning across valleys or rivers",
|
||||
"formation_type": "erosion_arch",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"sinkhole": {
|
||||
"display_name": "Sinkhole",
|
||||
"description": "Circular depression formed by underground water dissolution",
|
||||
"formation_type": "karst_dissolution",
|
||||
"budget_impact": -1
|
||||
},
|
||||
"spring": {
|
||||
"display_name": "Spring",
|
||||
"description": "Natural emergence of groundwater at surface",
|
||||
"formation_type": "groundwater_emergence",
|
||||
"budget_impact": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
58
gameData/MapFeatures/gold.json
Normal file
58
gameData/MapFeatures/gold.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"gold_resources": {
|
||||
"gold_lode": {
|
||||
"display_name": "Gold Lode",
|
||||
"description": "Primary gold deposit in quartz veins with high-grade ore concentrations",
|
||||
"formation_type": "hydrothermal_quartz_vein",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"placer_gold": {
|
||||
"display_name": "Placer Gold",
|
||||
"description": "Alluvial gold deposits concentrated in river gravels and ancient streambeds",
|
||||
"formation_type": "alluvial_gold_concentration",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"epithermal_gold": {
|
||||
"display_name": "Epithermal Gold",
|
||||
"description": "Shallow gold deposit formed by hot springs with silver associations",
|
||||
"formation_type": "epithermal_mineralization",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"residual_gold": {
|
||||
"display_name": "Residual Gold",
|
||||
"description": "Weathered gold deposits concentrated by erosion of primary sources",
|
||||
"formation_type": "weathering_concentration",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"conglomerate_gold": {
|
||||
"display_name": "Conglomerate Gold",
|
||||
"description": "Ancient gold deposits in fossil river conglomerates with uranium traces",
|
||||
"formation_type": "paleozoic_conglomerate",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"sulfide_gold": {
|
||||
"display_name": "Sulfide Gold",
|
||||
"description": "Gold associated with sulfide minerals requiring complex processing",
|
||||
"formation_type": "sulfide_mineralization",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
}
|
||||
}
|
||||
}
|
||||
52
gameData/MapFeatures/industrial_ruins.json
Normal file
52
gameData/MapFeatures/industrial_ruins.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"industrial_ruins": {
|
||||
"terikon": {
|
||||
"display_name": "Terikon",
|
||||
"description": "Artificial hill of mining waste with recoverable materials but pollution",
|
||||
"formation_type": "mining_waste",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"abandoned_factory": {
|
||||
"display_name": "Abandoned Factory",
|
||||
"description": "Derelict industrial facility with scrap metal and machinery",
|
||||
"formation_type": "industrial_ruin",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"ghost_town": {
|
||||
"display_name": "Ghost Town",
|
||||
"description": "Deserted settlement with infrastructure but potential dangers",
|
||||
"formation_type": "abandoned_settlement",
|
||||
"budget_impact": -1
|
||||
},
|
||||
"tank_graveyard": {
|
||||
"display_name": "Tank Graveyard",
|
||||
"description": "Collection of abandoned military vehicles with valuable scrap metal",
|
||||
"formation_type": "military_scrap",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"car_cemetery": {
|
||||
"display_name": "Car Cemetery",
|
||||
"description": "Abandoned vehicles providing civilian scrap metal",
|
||||
"formation_type": "civilian_scrap",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"plane_wreckage": {
|
||||
"display_name": "Plane Wreckage",
|
||||
"description": "Crashed aircraft with rare aviation alloys and components",
|
||||
"formation_type": "aviation_scrap",
|
||||
"budget_impact": 3
|
||||
},
|
||||
"abandoned_mine": {
|
||||
"display_name": "Abandoned Mine",
|
||||
"description": "Old mining facility with potential resources but structural dangers",
|
||||
"formation_type": "extraction_ruin",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"derelict_refinery": {
|
||||
"display_name": "Derelict Refinery",
|
||||
"description": "Abandoned oil processing facility with infrastructure but contamination",
|
||||
"formation_type": "chemical_ruin",
|
||||
"budget_impact": -2
|
||||
}
|
||||
}
|
||||
}
|
||||
67
gameData/MapFeatures/iron.json
Normal file
67
gameData/MapFeatures/iron.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"iron_resources": {
|
||||
"rich_iron_ore": {
|
||||
"display_name": "Rich Iron Ore",
|
||||
"description": "High-grade iron ore deposit with excellent purity and minimal processing requirements",
|
||||
"formation_type": "banded_iron_formation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"iron_ore_vein": {
|
||||
"display_name": "Iron Ore Vein",
|
||||
"description": "Standard iron ore deposit suitable for industrial steel production",
|
||||
"formation_type": "hydrothermal_iron_precipitation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"magnetite_deposit": {
|
||||
"display_name": "Magnetite Deposit",
|
||||
"description": "Magnetic iron ore with high iron content and easy magnetic separation",
|
||||
"formation_type": "metamorphic_iron_concentration",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"hematite_outcrop": {
|
||||
"display_name": "Hematite Outcrop",
|
||||
"description": "Surface-exposed iron oxide formation with moderate iron content",
|
||||
"formation_type": "weathered_iron_oxidation",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"bog_iron": {
|
||||
"display_name": "Bog Iron",
|
||||
"description": "Iron deposits formed in wetlands through bacterial precipitation",
|
||||
"formation_type": "biological_iron_precipitation",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "low",
|
||||
"quality": "low"
|
||||
},
|
||||
"laterite_iron": {
|
||||
"display_name": "Laterite Iron",
|
||||
"description": "Tropical weathering iron deposit with mixed aluminum and iron content",
|
||||
"formation_type": "tropical_weathering_concentration",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "medium",
|
||||
"quality": "medium"
|
||||
},
|
||||
"taconite": {
|
||||
"display_name": "Taconite",
|
||||
"description": "Low-grade iron ore requiring beneficiation but with massive reserves",
|
||||
"formation_type": "precambrian_banded_iron",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "low"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/natural_landmarks.json
Normal file
40
gameData/MapFeatures/natural_landmarks.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"natural_landmarks": {
|
||||
"natural_arch": {
|
||||
"display_name": "Natural Arch",
|
||||
"description": "Spectacular stone arch formation created by selective erosion",
|
||||
"formation_type": "erosion_arch",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"monolith": {
|
||||
"display_name": "Monolith",
|
||||
"description": "Large isolated stone pillar standing prominently in landscape",
|
||||
"formation_type": "erosion_resistant",
|
||||
"budget_impact": 3
|
||||
},
|
||||
"rock_spire": {
|
||||
"display_name": "Rock Spire",
|
||||
"description": "Tall needle-like rock formation pointing skyward",
|
||||
"formation_type": "erosion_pillar",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"mesa": {
|
||||
"display_name": "Mesa",
|
||||
"description": "Flat-topped mountain with steep cliff sides",
|
||||
"formation_type": "erosion_resistant",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"hoodoo": {
|
||||
"display_name": "Hoodoo",
|
||||
"description": "Tall thin spire of rock formed by differential erosion",
|
||||
"formation_type": "erosion_pillar",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"crater": {
|
||||
"display_name": "Crater",
|
||||
"description": "Large circular depression from ancient impact or volcanic activity",
|
||||
"formation_type": "impact_volcanic",
|
||||
"budget_impact": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
67
gameData/MapFeatures/oil.json
Normal file
67
gameData/MapFeatures/oil.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"oil_resources": {
|
||||
"major_oil_field": {
|
||||
"display_name": "Major Oil Field",
|
||||
"description": "Large petroleum reservoir with high pressure and excellent crude quality",
|
||||
"formation_type": "deep_carboniferous_compression_with_geological_trap",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"oil_well": {
|
||||
"display_name": "Oil Well",
|
||||
"description": "Standard petroleum deposit accessible through drilling operations",
|
||||
"formation_type": "carboniferous_compression_with_geological_trap",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"shallow_oil_pocket": {
|
||||
"display_name": "Shallow Oil Pocket",
|
||||
"description": "Surface-near petroleum deposit with easier access but lower pressure",
|
||||
"formation_type": "shallow_carboniferous_trap",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"oil_seep": {
|
||||
"display_name": "Oil Seep",
|
||||
"description": "Natural petroleum surface emergence indicating deeper reserves",
|
||||
"formation_type": "surface_petroleum_migration",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "low",
|
||||
"quality": "medium"
|
||||
},
|
||||
"tar_sands": {
|
||||
"display_name": "Tar Sands",
|
||||
"description": "Heavy oil mixed with sand requiring specialized extraction methods",
|
||||
"formation_type": "degraded_petroleum_in_sandstone",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "low"
|
||||
},
|
||||
"offshore_oil": {
|
||||
"display_name": "Offshore Oil",
|
||||
"description": "Underwater petroleum reservoir requiring marine drilling platforms",
|
||||
"formation_type": "submerged_carboniferous_compression",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"shale_oil": {
|
||||
"display_name": "Shale Oil",
|
||||
"description": "Oil trapped in shale rock formations requiring hydraulic fracturing",
|
||||
"formation_type": "carboniferous_matter_in_shale",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "medium"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/platinum.json
Normal file
40
gameData/MapFeatures/platinum.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"platinum_resources": {
|
||||
"pge_reef": {
|
||||
"display_name": "PGE Reef",
|
||||
"description": "Platinum group elements concentrated in layered igneous intrusions",
|
||||
"formation_type": "layered_igneous_intrusion",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 6,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"platinum_placer": {
|
||||
"display_name": "Platinum Placer",
|
||||
"description": "Alluvial platinum deposits concentrated in river systems from eroded sources",
|
||||
"formation_type": "alluvial_pge_concentration",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"sperrylite_deposit": {
|
||||
"display_name": "Sperrylite Deposit",
|
||||
"description": "Platinum arsenide ore associated with copper-nickel sulfides",
|
||||
"formation_type": "magmatic_sulfide_segregation",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"cooperite_vein": {
|
||||
"display_name": "Cooperite Vein",
|
||||
"description": "Platinum sulfide mineral in hydrothermal veins with palladium content",
|
||||
"formation_type": "hydrothermal_pge_precipitation",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
}
|
||||
}
|
||||
}
|
||||
76
gameData/MapFeatures/rare_metals.json
Normal file
76
gameData/MapFeatures/rare_metals.json
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
"rare_metal_resources": {
|
||||
"tungsten_vein": {
|
||||
"display_name": "Tungsten Vein",
|
||||
"description": "High-grade tungsten ore in quartz veins with scheelite and wolframite",
|
||||
"formation_type": "hydrothermal_tungsten_precipitation",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 6,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"molybdenum_porphyry": {
|
||||
"display_name": "Molybdenum Porphyry",
|
||||
"description": "Molybdenum sulfide in large porphyry copper systems",
|
||||
"formation_type": "porphyry_molybdenum_system",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"chromite_deposit": {
|
||||
"display_name": "Chromite Deposit",
|
||||
"description": "Chromium-iron oxide ore in layered mafic intrusions",
|
||||
"formation_type": "layered_mafic_intrusion",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"antimony_vein": {
|
||||
"display_name": "Antimony Vein",
|
||||
"description": "Stibnite ore in hydrothermal veins with mercury associations",
|
||||
"formation_type": "epithermal_antimony_vein",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"cobalt_arsenide": {
|
||||
"display_name": "Cobalt Arsenide",
|
||||
"description": "Cobalt-arsenic minerals in hydrothermal deposits with silver traces",
|
||||
"formation_type": "hydrothermal_cobalt_precipitation",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"iridium_placer": {
|
||||
"display_name": "Iridium Placer",
|
||||
"description": "Ultra-rare platinum group metal in alluvial concentrations",
|
||||
"formation_type": "alluvial_pge_concentration",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 7,
|
||||
"resource_yield": "very_low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"lithium_pegmatite": {
|
||||
"display_name": "Lithium Pegmatite",
|
||||
"description": "Spodumene-bearing granite pegmatite with lithium silicate minerals",
|
||||
"formation_type": "granitic_pegmatite",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"lithium_brine": {
|
||||
"display_name": "Lithium Brine",
|
||||
"description": "Salt lake brines with concentrated lithium chloride solutions",
|
||||
"formation_type": "evaporite_lithium_concentration",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
}
|
||||
}
|
||||
}
|
||||
49
gameData/MapFeatures/silver.json
Normal file
49
gameData/MapFeatures/silver.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"silver_resources": {
|
||||
"silver_vein": {
|
||||
"display_name": "Silver Vein",
|
||||
"description": "High-grade silver ore in hydrothermal veins with excellent purity",
|
||||
"formation_type": "hydrothermal_precious_metal_vein",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"galena_silver": {
|
||||
"display_name": "Galena Silver",
|
||||
"description": "Silver-bearing lead sulfide ore requiring lead-silver separation",
|
||||
"formation_type": "sulfide_mineralization",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"argentite_deposit": {
|
||||
"display_name": "Argentite Deposit",
|
||||
"description": "Silver sulfide mineral with high silver content and moderate processing",
|
||||
"formation_type": "sulfide_precipitation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"native_silver": {
|
||||
"display_name": "Native Silver",
|
||||
"description": "Pure metallic silver deposits requiring minimal processing",
|
||||
"formation_type": "hydrothermal_metal_precipitation",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"silver_placer": {
|
||||
"display_name": "Silver Placer",
|
||||
"description": "Alluvial silver deposits concentrated in ancient river systems",
|
||||
"formation_type": "alluvial_precious_metal_concentration",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
}
|
||||
}
|
||||
}
|
||||
103
gameData/MapFeatures/stone.json
Normal file
103
gameData/MapFeatures/stone.json
Normal file
@ -0,0 +1,103 @@
|
||||
{
|
||||
"stone_resources": {
|
||||
"stone_quarry": {
|
||||
"display_name": "Stone Quarry",
|
||||
"description": "Generic rock outcrop suitable for basic construction materials",
|
||||
"formation_type": "surface_rock_exposure",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"granite_quarry": {
|
||||
"display_name": "Granite Quarry",
|
||||
"description": "High-quality igneous rock perfect for construction and monuments",
|
||||
"formation_type": "plutonic_igneous_intrusion",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"limestone_quarry": {
|
||||
"display_name": "Limestone Quarry",
|
||||
"description": "Sedimentary rock ideal for cement production and building materials",
|
||||
"formation_type": "marine_carbonate_precipitation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"sandstone_quarry": {
|
||||
"display_name": "Sandstone Quarry",
|
||||
"description": "Layered sedimentary rock suitable for construction blocks and aggregate",
|
||||
"formation_type": "clastic_sedimentary_formation",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"marble_deposit": {
|
||||
"display_name": "Marble Deposit",
|
||||
"description": "Metamorphic limestone with excellent carving properties and durability",
|
||||
"formation_type": "limestone_metamorphism",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"clay_pit": {
|
||||
"display_name": "Clay Pit",
|
||||
"description": "Fine sedimentary material essential for ceramics and construction",
|
||||
"formation_type": "weathering_accumulation",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"sand_deposit": {
|
||||
"display_name": "Sand Deposit",
|
||||
"description": "Fine granular material perfect for concrete and glass production",
|
||||
"formation_type": "weathering_erosion_accumulation",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"gravel_pit": {
|
||||
"display_name": "Gravel Pit",
|
||||
"description": "Mixed rock fragments perfect for concrete aggregate and road base",
|
||||
"formation_type": "fluvial_glacial_accumulation",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"slate_deposit": {
|
||||
"display_name": "Slate Deposit",
|
||||
"description": "Fine-grained metamorphic rock perfect for roofing and flooring",
|
||||
"formation_type": "shale_metamorphism",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"quartzite_deposit": {
|
||||
"display_name": "Quartzite Deposit",
|
||||
"description": "Hard metamorphic quartz rock with excellent abrasive properties",
|
||||
"formation_type": "sandstone_metamorphism",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"gneiss_outcrop": {
|
||||
"display_name": "Gneiss Outcrop",
|
||||
"description": "Banded metamorphic rock suitable for decorative construction",
|
||||
"formation_type": "high_grade_metamorphism",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
}
|
||||
}
|
||||
}
|
||||
31
gameData/MapFeatures/thorium.json
Normal file
31
gameData/MapFeatures/thorium.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"thorium_resources": {
|
||||
"monazite_placer": {
|
||||
"display_name": "Monazite Placer",
|
||||
"description": "Heavy mineral sand deposit with thorium-bearing rare earth phosphates",
|
||||
"formation_type": "beach_placer_concentration",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"thorite_vein": {
|
||||
"display_name": "Thorite Vein",
|
||||
"description": "Primary thorium silicate mineral in granite pegmatites",
|
||||
"formation_type": "granitic_pegmatite",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"thorium_granite": {
|
||||
"display_name": "Thorium Granite",
|
||||
"description": "Radioactive granite with elevated thorium content requiring bulk processing",
|
||||
"formation_type": "radioactive_granite_intrusion",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "low"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/titanium.json
Normal file
40
gameData/MapFeatures/titanium.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"titanium_resources": {
|
||||
"ilmenite_deposit": {
|
||||
"display_name": "Ilmenite Deposit",
|
||||
"description": "Primary titanium-iron oxide ore with excellent titanium content",
|
||||
"formation_type": "magmatic_oxide_segregation",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"rutile_placer": {
|
||||
"display_name": "Rutile Placer",
|
||||
"description": "Heavy mineral sand deposit concentrated by wave action with pure titanium dioxide",
|
||||
"formation_type": "beach_placer_concentration",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"anatase_vein": {
|
||||
"display_name": "Anatase Vein",
|
||||
"description": "Crystalline titanium dioxide in hydrothermal veins with high purity",
|
||||
"formation_type": "hydrothermal_oxide_precipitation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"titaniferous_magnetite": {
|
||||
"display_name": "Titaniferous Magnetite",
|
||||
"description": "Iron-titanium oxide requiring separation processing for both metals",
|
||||
"formation_type": "layered_igneous_intrusion",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/underground_features.json
Normal file
40
gameData/MapFeatures/underground_features.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"underground_features": {
|
||||
"cave_network": {
|
||||
"display_name": "Cave Network",
|
||||
"description": "Interconnected underground cavern system with multiple entrances",
|
||||
"formation_type": "limestone_dissolution",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"underground_lake": {
|
||||
"display_name": "Underground Lake",
|
||||
"description": "Subterranean water body accessible through cave systems",
|
||||
"formation_type": "groundwater_accumulation",
|
||||
"budget_impact": 3
|
||||
},
|
||||
"crystal_cavern": {
|
||||
"display_name": "Crystal Cavern",
|
||||
"description": "Underground chamber with natural crystal formations",
|
||||
"formation_type": "mineral_crystallization",
|
||||
"budget_impact": 4
|
||||
},
|
||||
"bat_cave": {
|
||||
"display_name": "Bat Cave",
|
||||
"description": "Large cave system inhabited by bat colonies with guano deposits",
|
||||
"formation_type": "biological_cave",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"underground_river": {
|
||||
"display_name": "Underground River",
|
||||
"description": "Subterranean watercourse flowing through cave systems",
|
||||
"formation_type": "groundwater_flow",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"deep_cavern": {
|
||||
"display_name": "Deep Cavern",
|
||||
"description": "Extremely deep cave system reaching significant depths",
|
||||
"formation_type": "tectonic_cave",
|
||||
"budget_impact": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
49
gameData/MapFeatures/uranium.json
Normal file
49
gameData/MapFeatures/uranium.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"uranium_resources": {
|
||||
"pitchblende_vein": {
|
||||
"display_name": "Pitchblende Vein",
|
||||
"description": "High-grade uranium ore in hydrothermal veins with exceptional uranium content",
|
||||
"formation_type": "hydrothermal_uranium_concentration",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 6,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"uranium_roll_front": {
|
||||
"display_name": "Uranium Roll Front",
|
||||
"description": "Crescent-shaped uranium deposit formed by groundwater flow in sandstone",
|
||||
"formation_type": "groundwater_uranium_precipitation",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"carnotite_deposit": {
|
||||
"display_name": "Carnotite Deposit",
|
||||
"description": "Uranium-vanadium ore in sedimentary formations with yellow coloration",
|
||||
"formation_type": "sedimentary_uranium_vanadium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"uraninite_placer": {
|
||||
"display_name": "Uraninite Placer",
|
||||
"description": "Detrital uranium deposits concentrated in ancient river channels",
|
||||
"formation_type": "alluvial_uranium_concentration",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "low",
|
||||
"quality": "premium"
|
||||
},
|
||||
"phosphate_uranium": {
|
||||
"display_name": "Phosphate Uranium",
|
||||
"description": "Low-grade uranium associated with phosphate rock formations",
|
||||
"formation_type": "phosphate_uranium_association",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "low"
|
||||
}
|
||||
}
|
||||
}
|
||||
67
gameData/MapFeatures/volcanic.json
Normal file
67
gameData/MapFeatures/volcanic.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"volcanic_resources": {
|
||||
"sulfur_fumarole": {
|
||||
"display_name": "Sulfur Fumarole",
|
||||
"description": "Volcanic vent depositing pure sulfur crystals from gas emissions",
|
||||
"formation_type": "volcanic_gas_precipitation",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"obsidian_flow": {
|
||||
"display_name": "Obsidian Flow",
|
||||
"description": "Volcanic glass formation suitable for cutting tools and decoration",
|
||||
"formation_type": "rapid_lava_cooling",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "high",
|
||||
"quality": "premium"
|
||||
},
|
||||
"basalt_flow": {
|
||||
"display_name": "Basalt Flow",
|
||||
"description": "Dense volcanic rock excellent for construction and road aggregate",
|
||||
"formation_type": "mafic_lava_flow",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"pumice_deposit": {
|
||||
"display_name": "Pumice Deposit",
|
||||
"description": "Lightweight volcanic rock perfect for construction and abrasives",
|
||||
"formation_type": "explosive_volcanic_eruption",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"volcanic_ash": {
|
||||
"display_name": "Volcanic Ash",
|
||||
"description": "Fine volcanic material excellent for cement production and soil amendment",
|
||||
"formation_type": "pyroclastic_fallout",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"resource_yield": "very_high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"perlite_deposit": {
|
||||
"display_name": "Perlite Deposit",
|
||||
"description": "Volcanic glass that expands when heated, used for insulation",
|
||||
"formation_type": "hydrated_volcanic_glass",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"zeolite_formation": {
|
||||
"display_name": "Zeolite Formation",
|
||||
"description": "Crystalline volcanic minerals with molecular sieve properties",
|
||||
"formation_type": "volcanic_glass_alteration",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/volcanic_features.json
Normal file
40
gameData/MapFeatures/volcanic_features.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"volcanic_features": {
|
||||
"volcano": {
|
||||
"display_name": "Volcano",
|
||||
"description": "Active or dormant volcanic cone with potential geothermal energy",
|
||||
"formation_type": "volcanic_activity",
|
||||
"budget_impact": 3
|
||||
},
|
||||
"lava_field": {
|
||||
"display_name": "Lava Field",
|
||||
"description": "Solidified lava flows creating rough terrain with mineral deposits",
|
||||
"formation_type": "volcanic_flow",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"volcanic_vent": {
|
||||
"display_name": "Volcanic Vent",
|
||||
"description": "Secondary volcanic opening with gas emissions and sulfur deposits",
|
||||
"formation_type": "volcanic_secondary",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"caldera": {
|
||||
"display_name": "Caldera",
|
||||
"description": "Large volcanic depression with fertile soils and geothermal activity",
|
||||
"formation_type": "volcanic_collapse",
|
||||
"budget_impact": 4
|
||||
},
|
||||
"fumarole": {
|
||||
"display_name": "Fumarole",
|
||||
"description": "Volcanic gas vent with sulfur deposits and geothermal potential",
|
||||
"formation_type": "volcanic_gas",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"obsidian_field": {
|
||||
"display_name": "Obsidian Field",
|
||||
"description": "Natural volcanic glass deposits valuable for precision tools",
|
||||
"formation_type": "volcanic_glass",
|
||||
"budget_impact": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
64
gameData/MapFeatures/water_features.json
Normal file
64
gameData/MapFeatures/water_features.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"water_features": {
|
||||
"lake": {
|
||||
"display_name": "Lake",
|
||||
"description": "Large body of fresh water surrounded by land",
|
||||
"formation_type": "water_accumulation",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"pond": {
|
||||
"display_name": "Pond",
|
||||
"description": "Small body of still fresh water",
|
||||
"formation_type": "water_accumulation",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"waterfall": {
|
||||
"display_name": "Waterfall",
|
||||
"description": "Water cascading down from height with hydroelectric potential",
|
||||
"formation_type": "water_erosion",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"marsh": {
|
||||
"display_name": "Marsh",
|
||||
"description": "Wetland area with standing water and specialized vegetation",
|
||||
"formation_type": "water_saturation",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"central_hill_swamp": {
|
||||
"display_name": "Central Hill Swamp",
|
||||
"description": "Marshy wetland with elevated central hill providing strategic position",
|
||||
"formation_type": "water_saturation_with_elevation",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"islands_swamp": {
|
||||
"display_name": "Islands Swamp",
|
||||
"description": "Swampland dotted with multiple small dry islands and complex waterways",
|
||||
"formation_type": "fragmented_water_saturation",
|
||||
"budget_impact": 1
|
||||
},
|
||||
"hilly_swampy": {
|
||||
"display_name": "Hilly Swampy",
|
||||
"description": "Rolling terrain with marshy valleys and elevated dry ridges",
|
||||
"formation_type": "terrain_drainage_pattern",
|
||||
"budget_impact": 0
|
||||
},
|
||||
"river_source": {
|
||||
"display_name": "River Source",
|
||||
"description": "Origin point of a major river with strategic importance",
|
||||
"formation_type": "groundwater_emergence",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"delta": {
|
||||
"display_name": "River Delta",
|
||||
"description": "Fertile river mouth area with rich sediment deposits",
|
||||
"formation_type": "sediment_deposit",
|
||||
"budget_impact": 2
|
||||
},
|
||||
"oasis": {
|
||||
"display_name": "Oasis",
|
||||
"description": "Isolated fertile spot in desert with precious water source",
|
||||
"formation_type": "groundwater_emergence",
|
||||
"budget_impact": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
40
gameData/MapFeatures/zinc.json
Normal file
40
gameData/MapFeatures/zinc.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"zinc_resources": {
|
||||
"sphalerite_deposit": {
|
||||
"display_name": "Sphalerite Deposit",
|
||||
"description": "Primary zinc sulfide ore with high zinc content and lead associations",
|
||||
"formation_type": "sulfide_mineralization",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "high",
|
||||
"quality": "standard"
|
||||
},
|
||||
"zinc_carbonate": {
|
||||
"display_name": "Zinc Carbonate",
|
||||
"description": "Oxidized zinc ore formed by weathering of sulfide deposits",
|
||||
"formation_type": "zinc_oxidation_zone",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
},
|
||||
"franklinite_ore": {
|
||||
"display_name": "Franklinite Ore",
|
||||
"description": "Zinc-iron-manganese oxide mineral in metamorphic formations",
|
||||
"formation_type": "metamorphic_oxide_formation",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"resource_yield": "medium",
|
||||
"quality": "premium"
|
||||
},
|
||||
"willemite_deposit": {
|
||||
"display_name": "Willemite Deposit",
|
||||
"description": "Zinc silicate mineral with fluorescent properties under UV light",
|
||||
"formation_type": "silicate_mineralization",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"resource_yield": "medium",
|
||||
"quality": "standard"
|
||||
}
|
||||
}
|
||||
}
|
||||
81
gameData/Regions/README.json
Normal file
81
gameData/Regions/README.json
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"region_system_v3": {
|
||||
"description": "Scalable blacklist + frequent biomes system with mass requirements",
|
||||
"version": "3.0",
|
||||
|
||||
"revolutionary_simplification": {
|
||||
"problem_solved": "Exponential complexity of biome compatibility (20 biomes × 50 features = 1000 combinations)",
|
||||
"old_system": "compatible_biomes + incompatible_biomes + probability (redundant and massive)",
|
||||
"new_system": "incompatible_biomes (blacklist) + frequent_biomes (priority) - NO probability"
|
||||
},
|
||||
|
||||
"core_logic": {
|
||||
"default_behavior": "All features available everywhere by default",
|
||||
"blacklist_filtering": "incompatible_biomes = hard exclusions (geological impossibility)",
|
||||
"priority_system": "frequent_biomes = higher priority/likelihood in these environments",
|
||||
"mass_gating": "minimum_region_mass = geological strength requirements",
|
||||
"selection_method": "Filter by mass + blacklist, then prioritize frequent biomes"
|
||||
},
|
||||
|
||||
"workflow_example": {
|
||||
"scenario": "Iron region (mass=200) placing feature in 'alpine' biome",
|
||||
"step_1": "Filter by mass: rich_iron_ore (≥150✅), iron_ore_vein (≥75✅), bog_iron (≥10✅), etc.",
|
||||
"step_2": "Filter by blacklist: remove bog_iron (alpine incompatible), keep rich_iron_ore + iron_ore_vein",
|
||||
"step_3": "Check frequent biomes: rich_iron_ore has alpine in frequent_biomes → HIGH PRIORITY",
|
||||
"step_4": "Result: rich_iron_ore selected (mass ok, not blacklisted, frequent in alpine)"
|
||||
},
|
||||
|
||||
"scalability_advantages": {
|
||||
"new_biome_addition": "Automatically compatible with all features except explicit blacklists",
|
||||
"maintenance_load": "~3 blacklist entries per feature vs ~15+ whitelist entries",
|
||||
"geological_logic": "Blacklist = impossible formations, frequent = optimal conditions",
|
||||
"no_probability_management": "Eliminates probability balancing and normalization complexity"
|
||||
},
|
||||
|
||||
"feature_examples": {
|
||||
"rich_iron_ore": {
|
||||
"incompatible_biomes": ["tropical_rainforest", "wetlands"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"explanation": "Cannot form in tropical/wetland conditions, optimal in mountain/hill tectonics"
|
||||
},
|
||||
"laterite_iron": {
|
||||
"incompatible_biomes": ["alpine", "cold_desert", "tundra", "hot_desert"],
|
||||
"frequent_biomes": ["tropical_rainforest"],
|
||||
"explanation": "Requires tropical weathering, impossible in cold/dry conditions"
|
||||
},
|
||||
"peat_bog": {
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine", "rocky_plateau"],
|
||||
"frequent_biomes": ["wetlands"],
|
||||
"explanation": "Needs wetland accumulation, impossible in dry/rocky conditions"
|
||||
}
|
||||
},
|
||||
|
||||
"files_updated": {
|
||||
"iron_regions.json": "7 features with blacklist+frequent system",
|
||||
"copper_regions.json": "6 features with blacklist+frequent system",
|
||||
"coal_regions.json": "6 features with blacklist+frequent system",
|
||||
"oil_regions.json": "7 features with blacklist+frequent system",
|
||||
"spatial_distribution_patterns.json": "5 random density patterns for regions"
|
||||
},
|
||||
|
||||
"implementation_ready": {
|
||||
"phase_8_integration": "System ready for world generation Phase 8",
|
||||
"algorithm": [
|
||||
"1. Region assigned random pattern (concentrated/uniform/ring/clustered/gradient)",
|
||||
"2. Pattern determines density distribution within region radius",
|
||||
"3. For each feature placement:",
|
||||
"4. - Check region.mass >= feature.minimum_region_mass",
|
||||
"5. - Check local_biome NOT IN feature.incompatible_biomes",
|
||||
"6. - Prioritize features where local_biome IN feature.frequent_biomes",
|
||||
"7. - Select from available features",
|
||||
"8. - Place according to region density pattern"
|
||||
]
|
||||
},
|
||||
|
||||
"maintenance_metrics": {
|
||||
"old_system": "1000+ compatibility combinations to maintain",
|
||||
"new_system": "~200 blacklist entries total across all features",
|
||||
"reduction_factor": "5x less maintenance, infinite scalability for new biomes"
|
||||
}
|
||||
}
|
||||
}
|
||||
90
gameData/Regions/coal_regions.json
Normal file
90
gameData/Regions/coal_regions.json
Normal file
@ -0,0 +1,90 @@
|
||||
{
|
||||
"coal_region_system": {
|
||||
"resource_type": "coal",
|
||||
"description": "Coal feature selection based on region mass and biome compatibility",
|
||||
|
||||
"features": {
|
||||
"rich_coal_seam": {
|
||||
"display_name": "Rich Coal Seam",
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine", "wetlands"],
|
||||
"frequent_biomes": ["temperate_forest", "hills"],
|
||||
"minimum_region_mass": 100,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"description": "High-quality coal requiring substantial geological compression"
|
||||
},
|
||||
|
||||
"coal_seam": {
|
||||
"display_name": "Coal Seam",
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine"],
|
||||
"frequent_biomes": ["temperate_forest", "grassland", "hills"],
|
||||
"minimum_region_mass": 50,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"description": "Standard coal in medium-strength regions"
|
||||
},
|
||||
|
||||
"coal_outcrop": {
|
||||
"display_name": "Coal Outcrop",
|
||||
"incompatible_biomes": ["hot_desert", "alpine", "tropical_rainforest"],
|
||||
"frequent_biomes": ["temperate_forest", "grassland", "hills", "scrubland"],
|
||||
"minimum_region_mass": 25,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"description": "Surface coal accessible in small regions"
|
||||
},
|
||||
|
||||
"surface_coal": {
|
||||
"display_name": "Surface Coal",
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine", "wetlands"],
|
||||
"frequent_biomes": ["temperate_forest", "grassland", "scrubland"],
|
||||
"minimum_region_mass": 15,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"description": "Weathered coal in small regions"
|
||||
},
|
||||
|
||||
"lignite_deposit": {
|
||||
"display_name": "Lignite Deposit",
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine", "rocky_plateau"],
|
||||
"frequent_biomes": ["temperate_forest", "grassland"],
|
||||
"minimum_region_mass": 75,
|
||||
"quality_base": "medium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 2,
|
||||
"description": "Brown coal in medium sedimentary regions"
|
||||
},
|
||||
|
||||
"peat_bog": {
|
||||
"display_name": "Peat Bog",
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine", "rocky_plateau"],
|
||||
"frequent_biomes": ["wetlands"],
|
||||
"minimum_region_mass": 10,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 1,
|
||||
"description": "Early coal formation in wetland environments"
|
||||
}
|
||||
},
|
||||
|
||||
"selection_logic": {
|
||||
"step_1": "Check region mass against minimum_region_mass",
|
||||
"step_2": "Filter out features with incompatible biomes",
|
||||
"step_3": "Prioritize features with frequent biomes for this location",
|
||||
"step_4": "Select from available features",
|
||||
"fallback": "If no features available, place generic coal"
|
||||
},
|
||||
|
||||
"mass_categories": {
|
||||
"tiny_region": {"mass_range": [10, 25], "typical_features": ["peat_bog", "surface_coal"]},
|
||||
"small_region": {"mass_range": [25, 50], "typical_features": ["coal_outcrop", "surface_coal"]},
|
||||
"medium_region": {"mass_range": [50, 100], "typical_features": ["coal_seam", "lignite_deposit"]},
|
||||
"large_region": {"mass_range": [100, 300], "typical_features": ["rich_coal_seam", "coal_seam"]},
|
||||
"huge_region": {"mass_range": [300, 1000], "typical_features": ["rich_coal_seam"]}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
gameData/Regions/copper_regions.json
Normal file
89
gameData/Regions/copper_regions.json
Normal file
@ -0,0 +1,89 @@
|
||||
{
|
||||
"copper_region_system": {
|
||||
"resource_type": "copper_ore",
|
||||
"description": "Copper feature selection based on region mass and biome compatibility",
|
||||
|
||||
"features": {
|
||||
"porphyry_copper": {
|
||||
"display_name": "Porphyry Copper",
|
||||
"incompatible_biomes": ["wetlands", "coastal_plain"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"minimum_region_mass": 200,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"description": "Large-scale copper system requiring massive geological activity"
|
||||
},
|
||||
|
||||
"copper_vein": {
|
||||
"display_name": "Copper Vein",
|
||||
"incompatible_biomes": ["wetlands"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"minimum_region_mass": 75,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"description": "High-grade copper veins in medium-strength regions"
|
||||
},
|
||||
|
||||
"chalcopyrite_deposit": {
|
||||
"display_name": "Chalcopyrite Deposit",
|
||||
"incompatible_biomes": ["wetlands", "tropical_rainforest"],
|
||||
"frequent_biomes": ["hills", "temperate_forest", "grassland", "scrubland"],
|
||||
"minimum_region_mass": 50,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"description": "Standard copper sulfide in moderate regions"
|
||||
},
|
||||
|
||||
"malachite_outcrop": {
|
||||
"display_name": "Malachite Outcrop",
|
||||
"incompatible_biomes": ["wetlands", "tropical_rainforest"],
|
||||
"frequent_biomes": ["hills", "scrubland", "grassland"],
|
||||
"minimum_region_mass": 30,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"description": "Surface copper ore in small to medium regions"
|
||||
},
|
||||
|
||||
"native_copper": {
|
||||
"display_name": "Native Copper",
|
||||
"incompatible_biomes": ["wetlands", "tropical_rainforest", "hot_desert"],
|
||||
"frequent_biomes": ["rocky_plateau", "hills", "alpine"],
|
||||
"minimum_region_mass": 100,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"description": "Pure copper requiring specific geological conditions"
|
||||
},
|
||||
|
||||
"copper_shale": {
|
||||
"display_name": "Copper Shale",
|
||||
"incompatible_biomes": ["wetlands", "alpine", "rocky_plateau"],
|
||||
"frequent_biomes": ["grassland", "temperate_forest", "scrubland"],
|
||||
"minimum_region_mass": 150,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 2,
|
||||
"description": "Low-grade copper in large sedimentary regions"
|
||||
}
|
||||
},
|
||||
|
||||
"selection_logic": {
|
||||
"step_1": "Check region mass against minimum_region_mass",
|
||||
"step_2": "Filter out features with incompatible biomes",
|
||||
"step_3": "Prioritize features with frequent biomes for this location",
|
||||
"step_4": "Select from available features",
|
||||
"fallback": "If no features available, place generic copper_ore"
|
||||
},
|
||||
|
||||
"mass_categories": {
|
||||
"small_region": {"mass_range": [30, 75], "typical_features": ["malachite_outcrop", "chalcopyrite_deposit"]},
|
||||
"medium_region": {"mass_range": [75, 150], "typical_features": ["copper_vein", "chalcopyrite_deposit"]},
|
||||
"large_region": {"mass_range": [150, 300], "typical_features": ["porphyry_copper", "copper_shale", "native_copper"]},
|
||||
"huge_region": {"mass_range": [300, 1000], "typical_features": ["porphyry_copper", "copper_shale"]}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
gameData/Regions/gold_regions.json
Normal file
80
gameData/Regions/gold_regions.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"gold_region_system": {
|
||||
"resource_type": "gold_ore",
|
||||
"description": "Gold deposit regions with biome-compatible feature selection",
|
||||
|
||||
"features": {
|
||||
"gold_lode": {
|
||||
"display_name": "Gold Lode",
|
||||
"compatible_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"incompatible_biomes": ["wetlands", "coastal_plain"],
|
||||
"pattern": "concentrated",
|
||||
"probability": 0.25,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"geological_requirements": ["hydrothermal_quartz_vein"]
|
||||
},
|
||||
|
||||
"placer_gold": {
|
||||
"display_name": "Placer Gold",
|
||||
"compatible_biomes": ["temperate_forest", "grassland", "coastal_plain"],
|
||||
"incompatible_biomes": ["alpine", "rocky_plateau", "hot_desert"],
|
||||
"pattern": "clustered",
|
||||
"probability": 0.30,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"geological_requirements": ["alluvial_gold_concentration"]
|
||||
},
|
||||
|
||||
"epithermal_gold": {
|
||||
"display_name": "Epithermal Gold",
|
||||
"compatible_biomes": ["hills", "scrubland", "temperate_forest"],
|
||||
"incompatible_biomes": ["wetlands", "cold_desert"],
|
||||
"pattern": "ring",
|
||||
"probability": 0.20,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"geological_requirements": ["epithermal_mineralization"]
|
||||
},
|
||||
|
||||
"residual_gold": {
|
||||
"display_name": "Residual Gold",
|
||||
"compatible_biomes": ["hills", "scrubland", "grassland"],
|
||||
"incompatible_biomes": ["wetlands", "alpine"],
|
||||
"pattern": "gradient",
|
||||
"probability": 0.15,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 2,
|
||||
"geological_requirements": ["weathering_concentration"]
|
||||
},
|
||||
|
||||
"conglomerate_gold": {
|
||||
"display_name": "Conglomerate Gold",
|
||||
"compatible_biomes": ["hills", "rocky_plateau"],
|
||||
"incompatible_biomes": ["wetlands", "coastal_plain", "tropical_rainforest"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.08,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 4,
|
||||
"geological_requirements": ["paleozoic_conglomerate"]
|
||||
},
|
||||
|
||||
"sulfide_gold": {
|
||||
"display_name": "Sulfide Gold",
|
||||
"compatible_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"incompatible_biomes": ["wetlands", "coastal_plain"],
|
||||
"pattern": "concentrated",
|
||||
"probability": 0.02,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"geological_requirements": ["sulfide_mineralization"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
gameData/Regions/iron_regions.json
Normal file
101
gameData/Regions/iron_regions.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"iron_region_system": {
|
||||
"resource_type": "iron_ore",
|
||||
"description": "Iron feature selection based on region mass and biome compatibility",
|
||||
|
||||
"features": {
|
||||
"rich_iron_ore": {
|
||||
"display_name": "Rich Iron Ore",
|
||||
"incompatible_biomes": ["tropical_rainforest", "wetlands"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"minimum_region_mass": 150,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"description": "High-grade iron ore requiring strong geological activity"
|
||||
},
|
||||
|
||||
"iron_ore_vein": {
|
||||
"display_name": "Iron Ore Vein",
|
||||
"incompatible_biomes": ["tropical_rainforest", "wetlands"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "alpine", "temperate_forest"],
|
||||
"minimum_region_mass": 75,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"description": "Standard iron ore in medium-strength regions"
|
||||
},
|
||||
|
||||
"magnetite_deposit": {
|
||||
"display_name": "Magnetite Deposit",
|
||||
"incompatible_biomes": ["wetlands", "hot_desert"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"minimum_region_mass": 50,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"description": "Magnetic iron ore accessible in moderate regions"
|
||||
},
|
||||
|
||||
"hematite_outcrop": {
|
||||
"display_name": "Hematite Outcrop",
|
||||
"incompatible_biomes": ["tropical_rainforest", "wetlands"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "grassland", "scrubland"],
|
||||
"minimum_region_mass": 25,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"description": "Surface iron ore available in small regions"
|
||||
},
|
||||
|
||||
"laterite_iron": {
|
||||
"display_name": "Laterite Iron",
|
||||
"incompatible_biomes": ["alpine", "cold_desert", "tundra", "hot_desert"],
|
||||
"frequent_biomes": ["tropical_rainforest"],
|
||||
"minimum_region_mass": 30,
|
||||
"quality_base": "medium",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 2,
|
||||
"description": "Tropical weathering iron, specialized formation"
|
||||
},
|
||||
|
||||
"bog_iron": {
|
||||
"display_name": "Bog Iron",
|
||||
"incompatible_biomes": ["hot_desert", "cold_desert", "alpine", "rocky_plateau"],
|
||||
"frequent_biomes": ["wetlands"],
|
||||
"minimum_region_mass": 10,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"description": "Low-grade iron in wetland environments"
|
||||
},
|
||||
|
||||
"taconite": {
|
||||
"display_name": "Taconite",
|
||||
"incompatible_biomes": ["tropical_rainforest", "wetlands", "hot_desert"],
|
||||
"frequent_biomes": ["hills", "rocky_plateau", "grassland"],
|
||||
"minimum_region_mass": 200,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 2,
|
||||
"description": "Low-grade iron requiring very large, stable regions"
|
||||
}
|
||||
},
|
||||
|
||||
"selection_logic": {
|
||||
"step_1": "Check region mass against minimum_region_mass",
|
||||
"step_2": "Filter out features with incompatible biomes",
|
||||
"step_3": "Prioritize features with frequent biomes for this location",
|
||||
"step_4": "Select from available features",
|
||||
"fallback": "If no features available, place generic iron_ore"
|
||||
},
|
||||
|
||||
"mass_categories": {
|
||||
"tiny_region": {"mass_range": [10, 30], "typical_features": ["bog_iron", "laterite_iron"]},
|
||||
"small_region": {"mass_range": [30, 75], "typical_features": ["hematite_outcrop", "magnetite_deposit"]},
|
||||
"medium_region": {"mass_range": [75, 150], "typical_features": ["iron_ore_vein", "magnetite_deposit"]},
|
||||
"large_region": {"mass_range": [150, 300], "typical_features": ["rich_iron_ore", "iron_ore_vein"]},
|
||||
"huge_region": {"mass_range": [300, 1000], "typical_features": ["rich_iron_ore", "taconite"]}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
gameData/Regions/oil_regions.json
Normal file
101
gameData/Regions/oil_regions.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"oil_region_system": {
|
||||
"resource_type": "crude_oil",
|
||||
"description": "Oil feature selection based on region mass and biome compatibility",
|
||||
|
||||
"features": {
|
||||
"major_oil_field": {
|
||||
"display_name": "Major Oil Field",
|
||||
"incompatible_biomes": ["alpine", "rocky_plateau", "wetlands"],
|
||||
"frequent_biomes": ["grassland", "scrubland", "hot_desert"],
|
||||
"minimum_region_mass": 250,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 5,
|
||||
"description": "Large oil reservoirs requiring massive sedimentary basins"
|
||||
},
|
||||
|
||||
"oil_well": {
|
||||
"display_name": "Oil Well",
|
||||
"incompatible_biomes": ["alpine", "wetlands"],
|
||||
"frequent_biomes": ["grassland", "temperate_forest", "scrubland"],
|
||||
"minimum_region_mass": 75,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 4,
|
||||
"description": "Standard oil deposits in medium regions"
|
||||
},
|
||||
|
||||
"shallow_oil_pocket": {
|
||||
"display_name": "Shallow Oil Pocket",
|
||||
"incompatible_biomes": ["alpine", "wetlands"],
|
||||
"frequent_biomes": ["grassland", "temperate_forest", "scrubland", "hills"],
|
||||
"minimum_region_mass": 30,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 3,
|
||||
"description": "Surface-near oil accessible in small regions"
|
||||
},
|
||||
|
||||
"oil_seep": {
|
||||
"display_name": "Oil Seep",
|
||||
"incompatible_biomes": ["alpine", "cold_desert", "wetlands"],
|
||||
"frequent_biomes": ["grassland", "scrubland", "temperate_forest"],
|
||||
"minimum_region_mass": 15,
|
||||
"quality_base": "medium",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 2,
|
||||
"description": "Natural oil emergence in tiny regions"
|
||||
},
|
||||
|
||||
"offshore_oil": {
|
||||
"display_name": "Offshore Oil",
|
||||
"incompatible_biomes": ["hills", "rocky_plateau", "alpine", "hot_desert"],
|
||||
"frequent_biomes": ["coastal_plain"],
|
||||
"minimum_region_mass": 150,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 4,
|
||||
"description": "Marine oil deposits in coastal regions"
|
||||
},
|
||||
|
||||
"tar_sands": {
|
||||
"display_name": "Tar Sands",
|
||||
"incompatible_biomes": ["alpine", "hot_desert", "wetlands"],
|
||||
"frequent_biomes": ["grassland", "temperate_forest"],
|
||||
"minimum_region_mass": 200,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"description": "Heavy oil requiring large sedimentary systems"
|
||||
},
|
||||
|
||||
"shale_oil": {
|
||||
"display_name": "Shale Oil",
|
||||
"incompatible_biomes": ["alpine", "wetlands", "tropical_rainforest"],
|
||||
"frequent_biomes": ["grassland", "scrubland"],
|
||||
"minimum_region_mass": 100,
|
||||
"quality_base": "medium",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 3,
|
||||
"description": "Unconventional oil in shale formations"
|
||||
}
|
||||
},
|
||||
|
||||
"selection_logic": {
|
||||
"step_1": "Check region mass against minimum_region_mass",
|
||||
"step_2": "Filter out features with incompatible biomes",
|
||||
"step_3": "Prioritize features with frequent biomes for this location",
|
||||
"step_4": "Select from available features",
|
||||
"fallback": "If no features available, place generic oil_seep"
|
||||
},
|
||||
|
||||
"mass_categories": {
|
||||
"tiny_region": {"mass_range": [15, 30], "typical_features": ["oil_seep"]},
|
||||
"small_region": {"mass_range": [30, 75], "typical_features": ["shallow_oil_pocket", "oil_seep"]},
|
||||
"medium_region": {"mass_range": [75, 150], "typical_features": ["oil_well", "shale_oil"]},
|
||||
"large_region": {"mass_range": [150, 300], "typical_features": ["major_oil_field", "offshore_oil", "tar_sands"]},
|
||||
"huge_region": {"mass_range": [300, 1000], "typical_features": ["major_oil_field", "tar_sands"]}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
gameData/Regions/spatial_distribution_patterns.json
Normal file
73
gameData/Regions/spatial_distribution_patterns.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"region_density_patterns": {
|
||||
"version": "2.0",
|
||||
"description": "Density distribution patterns within resource regions - randomly assigned per region",
|
||||
|
||||
"available_patterns": [
|
||||
"concentrated",
|
||||
"uniform",
|
||||
"ring",
|
||||
"clustered",
|
||||
"gradient"
|
||||
],
|
||||
|
||||
"pattern_definitions": {
|
||||
"concentrated": {
|
||||
"description": "High feature density near region center, low at edges",
|
||||
"density_center": 1.0,
|
||||
"density_edge": 0.2,
|
||||
"effective_radius_percent": 50,
|
||||
"use_cases": "Rich ore bodies, primary deposits"
|
||||
},
|
||||
|
||||
"uniform": {
|
||||
"description": "Equal feature density throughout entire region",
|
||||
"density_center": 1.0,
|
||||
"density_edge": 1.0,
|
||||
"effective_radius_percent": 100,
|
||||
"use_cases": "Sedimentary layers, widespread deposits"
|
||||
},
|
||||
|
||||
"ring": {
|
||||
"description": "Feature density concentrated in annular zone",
|
||||
"density_center": 0.1,
|
||||
"density_ring_start": 0.6,
|
||||
"density_ring_peak": 1.0,
|
||||
"density_edge": 0.3,
|
||||
"use_cases": "Contact metamorphism, intrusion margins"
|
||||
},
|
||||
|
||||
"clustered": {
|
||||
"description": "Multiple high-density sub-zones within region",
|
||||
"cluster_count": {"min": 2, "max": 4},
|
||||
"density_in_cluster": 1.0,
|
||||
"density_between_clusters": 0.2,
|
||||
"use_cases": "Pod formations, scattered deposits"
|
||||
},
|
||||
|
||||
"gradient": {
|
||||
"description": "Smooth density decrease from center to edge",
|
||||
"density_center": 1.0,
|
||||
"density_edge": 0.4,
|
||||
"gradient_function": "logarithmic",
|
||||
"use_cases": "Diffusion halos, weathering profiles"
|
||||
}
|
||||
},
|
||||
|
||||
"pattern_assignment": {
|
||||
"method": "random_selection",
|
||||
"equal_probability": true,
|
||||
"description": "Each region gets a random pattern from available_patterns"
|
||||
},
|
||||
|
||||
"feature_placement_workflow": {
|
||||
"1": "Region created with random pattern",
|
||||
"2": "Pattern determines density distribution within region",
|
||||
"3": "For each tile needing feature placement:",
|
||||
"4": " - Check region mass (strength)",
|
||||
"5": " - Check local biome",
|
||||
"6": " - Select compatible feature based on mass + biome",
|
||||
"7": " - Place feature if density allows"
|
||||
}
|
||||
}
|
||||
}
|
||||
92
gameData/Regions/stone_regions.json
Normal file
92
gameData/Regions/stone_regions.json
Normal file
@ -0,0 +1,92 @@
|
||||
{
|
||||
"stone_region_system": {
|
||||
"resource_type": "construction_materials",
|
||||
"description": "Construction stone regions with biome-compatible feature selection",
|
||||
|
||||
"features": {
|
||||
"granite_quarry": {
|
||||
"display_name": "Granite Quarry",
|
||||
"compatible_biomes": ["hills", "rocky_plateau", "alpine"],
|
||||
"incompatible_biomes": ["wetlands", "coastal_plain"],
|
||||
"pattern": "concentrated",
|
||||
"probability": 0.20,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"geological_requirements": ["plutonic_igneous_intrusion"]
|
||||
},
|
||||
|
||||
"limestone_quarry": {
|
||||
"display_name": "Limestone Quarry",
|
||||
"compatible_biomes": ["hills", "grassland", "temperate_forest"],
|
||||
"incompatible_biomes": ["alpine", "hot_desert"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.25,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"geological_requirements": ["marine_carbonate_precipitation"]
|
||||
},
|
||||
|
||||
"sandstone_quarry": {
|
||||
"display_name": "Sandstone Quarry",
|
||||
"compatible_biomes": ["grassland", "scrubland", "temperate_forest"],
|
||||
"incompatible_biomes": ["alpine", "wetlands"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.20,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "easy",
|
||||
"budget_impact": 2,
|
||||
"geological_requirements": ["clastic_sedimentary_formation"]
|
||||
},
|
||||
|
||||
"marble_deposit": {
|
||||
"display_name": "Marble Deposit",
|
||||
"compatible_biomes": ["hills", "rocky_plateau"],
|
||||
"incompatible_biomes": ["wetlands", "coastal_plain", "hot_desert"],
|
||||
"pattern": "concentrated",
|
||||
"probability": 0.10,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"geological_requirements": ["limestone_metamorphism"]
|
||||
},
|
||||
|
||||
"clay_pit": {
|
||||
"display_name": "Clay Pit",
|
||||
"compatible_biomes": ["temperate_forest", "grassland", "coastal_plain"],
|
||||
"incompatible_biomes": ["alpine", "rocky_plateau", "hot_desert"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.15,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"geological_requirements": ["weathering_accumulation"]
|
||||
},
|
||||
|
||||
"sand_deposit": {
|
||||
"display_name": "Sand Deposit",
|
||||
"compatible_biomes": ["coastal_plain", "grassland", "scrubland"],
|
||||
"incompatible_biomes": ["alpine", "rocky_plateau"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.08,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"geological_requirements": ["weathering_erosion_accumulation"]
|
||||
},
|
||||
|
||||
"gravel_pit": {
|
||||
"display_name": "Gravel Pit",
|
||||
"compatible_biomes": ["temperate_forest", "grassland", "hills"],
|
||||
"incompatible_biomes": ["hot_desert", "wetlands"],
|
||||
"pattern": "clustered",
|
||||
"probability": 0.02,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "very_easy",
|
||||
"budget_impact": 1,
|
||||
"geological_requirements": ["fluvial_glacial_accumulation"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
gameData/Regions/uranium_regions.json
Normal file
68
gameData/Regions/uranium_regions.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"uranium_region_system": {
|
||||
"resource_type": "uranium_ore",
|
||||
"description": "Uranium deposit regions with biome-compatible feature selection",
|
||||
|
||||
"features": {
|
||||
"pitchblende_vein": {
|
||||
"display_name": "Pitchblende Vein",
|
||||
"compatible_biomes": ["hills", "rocky_plateau", "cold_desert"],
|
||||
"incompatible_biomes": ["wetlands", "tropical_rainforest", "coastal_plain"],
|
||||
"pattern": "concentrated",
|
||||
"probability": 0.25,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 6,
|
||||
"geological_requirements": ["hydrothermal_uranium_concentration"]
|
||||
},
|
||||
|
||||
"uranium_roll_front": {
|
||||
"display_name": "Uranium Roll Front",
|
||||
"compatible_biomes": ["grassland", "scrubland", "cold_desert"],
|
||||
"incompatible_biomes": ["wetlands", "alpine", "tropical_rainforest"],
|
||||
"pattern": "ring",
|
||||
"probability": 0.30,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "hard",
|
||||
"budget_impact": 4,
|
||||
"geological_requirements": ["groundwater_uranium_precipitation"]
|
||||
},
|
||||
|
||||
"carnotite_deposit": {
|
||||
"display_name": "Carnotite Deposit",
|
||||
"compatible_biomes": ["scrubland", "cold_desert", "grassland"],
|
||||
"incompatible_biomes": ["wetlands", "tropical_rainforest", "temperate_forest"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.25,
|
||||
"quality_base": "standard",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"geological_requirements": ["sedimentary_uranium_vanadium"]
|
||||
},
|
||||
|
||||
"uraninite_placer": {
|
||||
"display_name": "Uraninite Placer",
|
||||
"compatible_biomes": ["grassland", "scrubland"],
|
||||
"incompatible_biomes": ["wetlands", "alpine", "tropical_rainforest"],
|
||||
"pattern": "clustered",
|
||||
"probability": 0.15,
|
||||
"quality_base": "premium",
|
||||
"extraction_difficulty": "medium",
|
||||
"budget_impact": 3,
|
||||
"geological_requirements": ["alluvial_uranium_concentration"]
|
||||
},
|
||||
|
||||
"phosphate_uranium": {
|
||||
"display_name": "Phosphate Uranium",
|
||||
"compatible_biomes": ["grassland", "scrubland", "coastal_plain"],
|
||||
"incompatible_biomes": ["alpine", "rocky_plateau"],
|
||||
"pattern": "uniform",
|
||||
"probability": 0.05,
|
||||
"quality_base": "low",
|
||||
"extraction_difficulty": "very_hard",
|
||||
"budget_impact": 2,
|
||||
"geological_requirements": ["phosphate_uranium_association"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
gameData/Ressources/rawChemicals.json
Normal file
86
gameData/Ressources/rawChemicals.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"sulfur": {
|
||||
"name": "Sulfur",
|
||||
"category": "basic_chemical",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.1,
|
||||
"stack_size": 100,
|
||||
"container_type": "chemical_powder",
|
||||
"ui": {
|
||||
"icon": "sulfur.png",
|
||||
"color": "#FFFF00",
|
||||
"map_color": "#FFD700",
|
||||
"particle_effect": "sulfur_dust"
|
||||
}
|
||||
},
|
||||
"phosphorus": {
|
||||
"name": "Phosphorus",
|
||||
"category": "reactive_chemical",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.8,
|
||||
"stack_size": 50,
|
||||
"container_type": "reactive_chemical",
|
||||
"ui": {
|
||||
"icon": "phosphorus.png",
|
||||
"color": "#FF4500",
|
||||
"map_color": "#FF6347",
|
||||
"particle_effect": "phosphorus_glow"
|
||||
}
|
||||
},
|
||||
"potassium": {
|
||||
"name": "Potassium",
|
||||
"category": "alkali_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.9,
|
||||
"stack_size": 25,
|
||||
"container_type": "reactive_metal",
|
||||
"ui": {
|
||||
"icon": "potassium.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#A9A9A9",
|
||||
"particle_effect": "metallic_shine"
|
||||
}
|
||||
},
|
||||
"sodium": {
|
||||
"name": "Sodium",
|
||||
"category": "alkali_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.0,
|
||||
"stack_size": 25,
|
||||
"container_type": "reactive_metal",
|
||||
"ui": {
|
||||
"icon": "sodium.png",
|
||||
"color": "#D3D3D3",
|
||||
"map_color": "#DCDCDC",
|
||||
"particle_effect": "sodium_shine"
|
||||
}
|
||||
},
|
||||
"magnesium": {
|
||||
"name": "Magnesium",
|
||||
"category": "alkaline_earth_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.7,
|
||||
"stack_size": 50,
|
||||
"container_type": "light_metal",
|
||||
"ui": {
|
||||
"icon": "magnesium.png",
|
||||
"color": "#F5F5F5",
|
||||
"map_color": "#E0E0E0",
|
||||
"particle_effect": "bright_metallic_dust"
|
||||
}
|
||||
},
|
||||
"calcium": {
|
||||
"name": "Calcium",
|
||||
"category": "alkaline_earth_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.5,
|
||||
"stack_size": 50,
|
||||
"container_type": "reactive_metal",
|
||||
"ui": {
|
||||
"icon": "calcium.png",
|
||||
"color": "#FFFAF0",
|
||||
"map_color": "#F0F8FF",
|
||||
"particle_effect": "calcium_dust"
|
||||
}
|
||||
}
|
||||
}
|
||||
82
gameData/Ressources/rawCrystals.json
Normal file
82
gameData/Ressources/rawCrystals.json
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
"quartz_crystal": {
|
||||
"name": "Quartz Crystal",
|
||||
"category": "silicon_crystal",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.6,
|
||||
"stack_size": 25,
|
||||
"container_type": "crystal_material",
|
||||
"hardness_mohs": 7,
|
||||
"processing_note": "Essential for electronics and optics",
|
||||
"ui": {
|
||||
"icon": "quartz_crystal.png",
|
||||
"color": "#F5F5F5",
|
||||
"map_color": "#E0E0E0",
|
||||
"particle_effect": "crystal_sparkle"
|
||||
}
|
||||
},
|
||||
"micro_diamonds": {
|
||||
"name": "Micro Diamonds",
|
||||
"category": "precious_crystal",
|
||||
"logistic_category": "resource",
|
||||
"density": 3.5,
|
||||
"stack_size": 5,
|
||||
"container_type": "precious_material",
|
||||
"hardness_mohs": 10,
|
||||
"processing_note": "Industrial grade diamonds for cutting tools",
|
||||
"ui": {
|
||||
"icon": "micro_diamonds.png",
|
||||
"color": "#E0E0E0",
|
||||
"map_color": "#FFFFFF",
|
||||
"particle_effect": "diamond_sparkle"
|
||||
}
|
||||
},
|
||||
"volcanic_glass": {
|
||||
"name": "Volcanic Glass",
|
||||
"category": "natural_glass",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.4,
|
||||
"stack_size": 25,
|
||||
"container_type": "glass_material",
|
||||
"hardness_mohs": 5.5,
|
||||
"processing_note": "Natural glass formed by rapid cooling",
|
||||
"ui": {
|
||||
"icon": "volcanic_glass.png",
|
||||
"color": "#000000",
|
||||
"map_color": "#2F2F2F",
|
||||
"particle_effect": "glass_reflection"
|
||||
}
|
||||
},
|
||||
"magnetite": {
|
||||
"name": "Magnetite",
|
||||
"category": "magnetic_mineral",
|
||||
"logistic_category": "resource",
|
||||
"density": 5.2,
|
||||
"stack_size": 50,
|
||||
"container_type": "magnetic_ore",
|
||||
"magnetic_strength": "strong_natural",
|
||||
"processing_note": "Naturally magnetic iron oxide",
|
||||
"ui": {
|
||||
"icon": "magnetite.png",
|
||||
"color": "#2F4F4F",
|
||||
"map_color": "#708090",
|
||||
"particle_effect": "magnetic_field"
|
||||
}
|
||||
},
|
||||
"rare_earth_magnets": {
|
||||
"name": "Rare Earth Magnets",
|
||||
"category": "advanced_magnetic",
|
||||
"logistic_category": "resource",
|
||||
"density": 8.1,
|
||||
"stack_size": 10,
|
||||
"container_type": "magnetic_material",
|
||||
"magnetic_strength": "extremely_strong",
|
||||
"processing_note": "Neodymium-iron-boron permanent magnets",
|
||||
"ui": {
|
||||
"icon": "rare_earth_magnets.png",
|
||||
"color": "#4169E1",
|
||||
"map_color": "#0000FF",
|
||||
"particle_effect": "strong_magnetic_field"
|
||||
}
|
||||
}
|
||||
}
|
||||
108
gameData/Ressources/rawEnergy.json
Normal file
108
gameData/Ressources/rawEnergy.json
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"coal": {
|
||||
"name": "Coal",
|
||||
"category": "fossil_fuel",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.3,
|
||||
"stack_size": 100,
|
||||
"container_type": "bulk_fuel",
|
||||
"energy_content_mj": 25,
|
||||
"ui": {
|
||||
"icon": "coal.png",
|
||||
"color": "#2F2F2F",
|
||||
"map_color": "#1C1C1C",
|
||||
"particle_effect": "coal_dust"
|
||||
}
|
||||
},
|
||||
"crude_oil": {
|
||||
"name": "Crude Oil",
|
||||
"category": "liquid_fuel",
|
||||
"logistic_category": "fluid",
|
||||
"density": 0.85,
|
||||
"stack_size": 0,
|
||||
"container_type": "liquid_fuel",
|
||||
"energy_content_mj": 42,
|
||||
"ui": {
|
||||
"icon": "crude_oil.png",
|
||||
"color": "#2F2F2F",
|
||||
"map_color": "#000000",
|
||||
"particle_effect": "oil_drops"
|
||||
}
|
||||
},
|
||||
"natural_gas": {
|
||||
"name": "Natural Gas",
|
||||
"category": "gaseous_fuel",
|
||||
"logistic_category": "fluid",
|
||||
"density": 0.0007,
|
||||
"stack_size": 0,
|
||||
"container_type": "pressurized_gas",
|
||||
"energy_content_mj": 55,
|
||||
"ui": {
|
||||
"icon": "natural_gas.png",
|
||||
"color": "#B0E0E6",
|
||||
"map_color": "#87CEEB",
|
||||
"particle_effect": "gas_wisps"
|
||||
}
|
||||
},
|
||||
"uranium_235": {
|
||||
"name": "Uranium-235",
|
||||
"category": "fissile_fuel",
|
||||
"logistic_category": "resource",
|
||||
"density": 19.1,
|
||||
"stack_size": 1,
|
||||
"container_type": "fissile_material",
|
||||
"energy_content_mj": 80000000,
|
||||
"ui": {
|
||||
"icon": "uranium_235.png",
|
||||
"color": "#00FF00",
|
||||
"map_color": "#32CD32",
|
||||
"particle_effect": "uranium_glow"
|
||||
}
|
||||
},
|
||||
"uranium_ore": {
|
||||
"name": "Uranium Ore",
|
||||
"category": "radioactive_ore",
|
||||
"logistic_category": "resource",
|
||||
"density": 19.1,
|
||||
"stack_size": 10,
|
||||
"container_type": "radioactive_ore",
|
||||
"processing_note": "Requires enrichment to produce Uranium-235",
|
||||
"ui": {
|
||||
"icon": "uranium_ore.png",
|
||||
"color": "#FFFF00",
|
||||
"map_color": "#FFD700",
|
||||
"particle_effect": "uranium_glow"
|
||||
}
|
||||
},
|
||||
"thorium_ore": {
|
||||
"name": "Thorium Ore",
|
||||
"category": "radioactive_ore",
|
||||
"logistic_category": "resource",
|
||||
"density": 11.7,
|
||||
"stack_size": 15,
|
||||
"container_type": "radioactive_ore",
|
||||
"processing_note": "Alternative nuclear fuel, requires breeder reactor",
|
||||
"ui": {
|
||||
"icon": "thorium_ore.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#A9A9A9",
|
||||
"particle_effect": "thorium_radiation"
|
||||
}
|
||||
},
|
||||
"plutonium": {
|
||||
"name": "Plutonium",
|
||||
"category": "fissile_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 19.8,
|
||||
"stack_size": 1,
|
||||
"container_type": "fissile_material",
|
||||
"energy_content_mj": 87000000,
|
||||
"processing_note": "Weapons-grade nuclear material",
|
||||
"ui": {
|
||||
"icon": "plutonium.png",
|
||||
"color": "#8B0000",
|
||||
"map_color": "#FF0000",
|
||||
"particle_effect": "plutonium_energy"
|
||||
}
|
||||
}
|
||||
}
|
||||
81
gameData/Ressources/rawExotics.json
Normal file
81
gameData/Ressources/rawExotics.json
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"rare_earth_elements": {
|
||||
"name": "Rare Earth Elements",
|
||||
"category": "exotic_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 7.2,
|
||||
"stack_size": 5,
|
||||
"container_type": "exotic_material",
|
||||
"rarity": "very_rare",
|
||||
"ui": {
|
||||
"icon": "rare_earth_elements.png",
|
||||
"color": "#FF69B4",
|
||||
"map_color": "#FF1493",
|
||||
"particle_effect": "rare_earth_glow"
|
||||
}
|
||||
},
|
||||
"unknown_minerals": {
|
||||
"name": "Unknown Minerals",
|
||||
"category": "xenomaterial",
|
||||
"logistic_category": "resource",
|
||||
"density": 12.0,
|
||||
"stack_size": 1,
|
||||
"container_type": "xenomaterial",
|
||||
"rarity": "legendary",
|
||||
"processing_note": "Composition defies known physics",
|
||||
"ui": {
|
||||
"icon": "unknown_minerals.png",
|
||||
"color": "#8A2BE2",
|
||||
"map_color": "#9400D3",
|
||||
"particle_effect": "xenomineral_aura"
|
||||
}
|
||||
},
|
||||
"unknown_isotopes": {
|
||||
"name": "Unknown Isotopes",
|
||||
"category": "exotic_radioactive",
|
||||
"logistic_category": "resource",
|
||||
"density": 15.8,
|
||||
"stack_size": 1,
|
||||
"container_type": "hazmat_container",
|
||||
"rarity": "legendary",
|
||||
"processing_note": "Isotopes not found in periodic table",
|
||||
"ui": {
|
||||
"icon": "unknown_isotopes.png",
|
||||
"color": "#FF0000",
|
||||
"map_color": "#DC143C",
|
||||
"particle_effect": "isotope_radiation"
|
||||
}
|
||||
},
|
||||
"mystery_inclusions": {
|
||||
"name": "Mystery Inclusions",
|
||||
"category": "unknown_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 8.5,
|
||||
"stack_size": 1,
|
||||
"container_type": "anomalous_material",
|
||||
"rarity": "artifact",
|
||||
"processing_note": "Origin and purpose unknown",
|
||||
"ui": {
|
||||
"icon": "mystery_inclusions.png",
|
||||
"color": "#8B008B",
|
||||
"map_color": "#9932CC",
|
||||
"particle_effect": "mystery_sparkle"
|
||||
}
|
||||
},
|
||||
"rare_earth_metals": {
|
||||
"name": "Rare Earth Metals",
|
||||
"category": "high_tech_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 6.8,
|
||||
"stack_size": 10,
|
||||
"container_type": "specialized_alloy",
|
||||
"rarity": "rare",
|
||||
"processing_note": "Essential for advanced electronics",
|
||||
"ui": {
|
||||
"icon": "rare_earth_metals.png",
|
||||
"color": "#DA70D6",
|
||||
"map_color": "#BA55D3",
|
||||
"particle_effect": "tech_shimmer"
|
||||
}
|
||||
}
|
||||
}
|
||||
93
gameData/Ressources/rawOrganics.json
Normal file
93
gameData/Ressources/rawOrganics.json
Normal file
@ -0,0 +1,93 @@
|
||||
{
|
||||
"wood": {
|
||||
"name": "Wood",
|
||||
"category": "biomass",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.6,
|
||||
"stack_size": 100,
|
||||
"container_type": "organic_material",
|
||||
"renewable": true,
|
||||
"ui": {
|
||||
"icon": "wood.png",
|
||||
"color": "#8B4513",
|
||||
"map_color": "#A0522D",
|
||||
"particle_effect": "wood_chips"
|
||||
}
|
||||
},
|
||||
"rubber": {
|
||||
"name": "Rubber",
|
||||
"category": "elastic_polymer",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.9,
|
||||
"stack_size": 50,
|
||||
"container_type": "polymer_material",
|
||||
"renewable": true,
|
||||
"ui": {
|
||||
"icon": "rubber.png",
|
||||
"color": "#2F2F2F",
|
||||
"map_color": "#1C1C1C",
|
||||
"particle_effect": "rubber_bits"
|
||||
}
|
||||
},
|
||||
"organic_compounds": {
|
||||
"name": "Organic Compounds",
|
||||
"category": "biological_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.2,
|
||||
"stack_size": 50,
|
||||
"container_type": "organic_material",
|
||||
"processing_note": "Complex carbon-based molecules from space",
|
||||
"ui": {
|
||||
"icon": "organic_compounds.png",
|
||||
"color": "#228B22",
|
||||
"map_color": "#32CD32",
|
||||
"particle_effect": "organic_particles"
|
||||
}
|
||||
},
|
||||
"plastic_waste": {
|
||||
"name": "Plastic Waste",
|
||||
"category": "recyclable_polymer",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.1,
|
||||
"stack_size": 100,
|
||||
"container_type": "waste_material",
|
||||
"recyclable": true,
|
||||
"ui": {
|
||||
"icon": "plastic_waste.png",
|
||||
"color": "#FF69B4",
|
||||
"map_color": "#FF1493",
|
||||
"particle_effect": "plastic_fragments"
|
||||
}
|
||||
},
|
||||
"electronic_scrap": {
|
||||
"name": "Electronic Scrap",
|
||||
"category": "tech_waste",
|
||||
"logistic_category": "resource",
|
||||
"density": 3.5,
|
||||
"stack_size": 50,
|
||||
"container_type": "electronic_waste",
|
||||
"recyclable": true,
|
||||
"processing_note": "Contains valuable metals and rare earth elements",
|
||||
"ui": {
|
||||
"icon": "electronic_scrap.png",
|
||||
"color": "#32CD32",
|
||||
"map_color": "#228B22",
|
||||
"particle_effect": "circuit_sparks"
|
||||
}
|
||||
},
|
||||
"metal_scrap": {
|
||||
"name": "Metal Scrap",
|
||||
"category": "recyclable_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 4.5,
|
||||
"stack_size": 100,
|
||||
"container_type": "scrap_metal",
|
||||
"recyclable": true,
|
||||
"ui": {
|
||||
"icon": "metal_scrap.png",
|
||||
"color": "#708090",
|
||||
"map_color": "#2F4F4F",
|
||||
"particle_effect": "metal_shavings"
|
||||
}
|
||||
}
|
||||
}
|
||||
257
gameData/Ressources/rawResources.json
Normal file
257
gameData/Ressources/rawResources.json
Normal file
@ -0,0 +1,257 @@
|
||||
{
|
||||
"iron_ore": {
|
||||
"name": "Iron Ore",
|
||||
"category": "basic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 5.2,
|
||||
"melting_point_celsius": 1538,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "iron_ore.png",
|
||||
"color": "#8B4513",
|
||||
"map_color": "#654321",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"copper_ore": {
|
||||
"name": "Copper Ore",
|
||||
"category": "basic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 4.8,
|
||||
"melting_point_celsius": 1085,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "copper_ore.png",
|
||||
"color": "#CD7F32",
|
||||
"map_color": "#B87333",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"aluminum_ore": {
|
||||
"name": "Aluminum Ore (Bauxite)",
|
||||
"category": "basic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.8,
|
||||
"melting_point_celsius": 660,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "bauxite.png",
|
||||
"color": "#CD853F",
|
||||
"map_color": "#D2691E",
|
||||
"particle_effect": "clay_dust"
|
||||
}
|
||||
},
|
||||
"zinc_ore": {
|
||||
"name": "Zinc Ore",
|
||||
"category": "basic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 4.2,
|
||||
"melting_point_celsius": 420,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "zinc_ore.png",
|
||||
"color": "#A8A8A8",
|
||||
"map_color": "#DCDCDC",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"tin_ore": {
|
||||
"name": "Tin Ore",
|
||||
"category": "basic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 4.5,
|
||||
"melting_point_celsius": 232,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "tin_ore.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#B8860B",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"lead_ore": {
|
||||
"name": "Lead Ore",
|
||||
"category": "basic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 6.8,
|
||||
"melting_point_celsius": 327,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "lead_ore.png",
|
||||
"color": "#708090",
|
||||
"map_color": "#696969",
|
||||
"particle_effect": "heavy_dust"
|
||||
}
|
||||
},
|
||||
"nickel_ore": {
|
||||
"name": "Nickel Ore",
|
||||
"category": "advanced_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 5.6,
|
||||
"melting_point_celsius": 1455,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "nickel_ore.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#A9A9A9",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"chromium_ore": {
|
||||
"name": "Chromium Ore",
|
||||
"category": "advanced_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 3.8,
|
||||
"melting_point_celsius": 1907,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "chromium_ore.png",
|
||||
"color": "#708090",
|
||||
"map_color": "#778899",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"antimony_ore": {
|
||||
"name": "Antimony Ore",
|
||||
"category": "advanced_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 4.6,
|
||||
"melting_point_celsius": 631,
|
||||
"stack_size": 50,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "antimony_ore.png",
|
||||
"color": "#A8A8A8",
|
||||
"map_color": "#C0C0C0",
|
||||
"particle_effect": "metallic_dust"
|
||||
}
|
||||
},
|
||||
"gold_ore": {
|
||||
"name": "Gold Ore",
|
||||
"category": "precious_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 8.9,
|
||||
"melting_point_celsius": 1064,
|
||||
"stack_size": 25,
|
||||
"container_type": "precious_ore",
|
||||
"ui": {
|
||||
"icon": "gold_ore.png",
|
||||
"color": "#FFD700",
|
||||
"map_color": "#DAA520",
|
||||
"particle_effect": "precious_dust"
|
||||
}
|
||||
},
|
||||
"silver_ore": {
|
||||
"name": "Silver Ore",
|
||||
"category": "precious_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 6.1,
|
||||
"melting_point_celsius": 962,
|
||||
"stack_size": 25,
|
||||
"container_type": "precious_ore",
|
||||
"ui": {
|
||||
"icon": "silver_ore.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#E6E6FA",
|
||||
"particle_effect": "precious_dust"
|
||||
}
|
||||
},
|
||||
"platinum_ore": {
|
||||
"name": "Platinum Ore",
|
||||
"category": "precious_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 9.8,
|
||||
"melting_point_celsius": 1768,
|
||||
"stack_size": 10,
|
||||
"container_type": "precious_ore",
|
||||
"ui": {
|
||||
"icon": "platinum_ore.png",
|
||||
"color": "#E5E4E2",
|
||||
"map_color": "#B0C4DE",
|
||||
"particle_effect": "precious_dust"
|
||||
}
|
||||
},
|
||||
"titanium_ore": {
|
||||
"name": "Titanium Ore",
|
||||
"category": "rare_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 3.2,
|
||||
"melting_point_celsius": 1668,
|
||||
"stack_size": 25,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "titanium_ore.png",
|
||||
"color": "#D3D3D3",
|
||||
"map_color": "#B0C4DE",
|
||||
"particle_effect": "light_metallic_dust"
|
||||
}
|
||||
},
|
||||
"tungsten_ore": {
|
||||
"name": "Tungsten Ore",
|
||||
"category": "rare_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 8.2,
|
||||
"melting_point_celsius": 3414,
|
||||
"stack_size": 25,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "tungsten_ore.png",
|
||||
"color": "#696969",
|
||||
"map_color": "#2F4F4F",
|
||||
"particle_effect": "heavy_metallic_dust"
|
||||
}
|
||||
},
|
||||
"iridium_ore": {
|
||||
"name": "Iridium Ore",
|
||||
"category": "rare_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 11.2,
|
||||
"melting_point_celsius": 2466,
|
||||
"stack_size": 5,
|
||||
"container_type": "precious_ore",
|
||||
"ui": {
|
||||
"icon": "iridium_ore.png",
|
||||
"color": "#F8F8FF",
|
||||
"map_color": "#E6E6FA",
|
||||
"particle_effect": "rare_dust"
|
||||
}
|
||||
},
|
||||
"lithium": {
|
||||
"name": "Lithium",
|
||||
"category": "alkali_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.5,
|
||||
"melting_point_celsius": 181,
|
||||
"stack_size": 25,
|
||||
"container_type": "light_metal",
|
||||
"ui": {
|
||||
"icon": "lithium.png",
|
||||
"color": "#F0F8FF",
|
||||
"map_color": "#E6E6FA",
|
||||
"particle_effect": "light_metallic_dust"
|
||||
}
|
||||
},
|
||||
"cobalt": {
|
||||
"name": "Cobalt",
|
||||
"category": "strategic_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 8.9,
|
||||
"melting_point_celsius": 1495,
|
||||
"stack_size": 25,
|
||||
"container_type": "metal_ore",
|
||||
"ui": {
|
||||
"icon": "cobalt.png",
|
||||
"color": "#0047AB",
|
||||
"map_color": "#4169E1",
|
||||
"particle_effect": "blue_metallic_dust"
|
||||
}
|
||||
}
|
||||
}
|
||||
280
gameData/Ressources/rawRocks.json
Normal file
280
gameData/Ressources/rawRocks.json
Normal file
@ -0,0 +1,280 @@
|
||||
{
|
||||
"stone": {
|
||||
"name": "Stone",
|
||||
"category": "basic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.5,
|
||||
"melting_point_celsius": 1200,
|
||||
"stack_size": 100,
|
||||
"container_type": "bulk_solid",
|
||||
"ui": {
|
||||
"icon": "stone.png",
|
||||
"color": "#808080",
|
||||
"map_color": "#696969",
|
||||
"particle_effect": "stone_dust"
|
||||
}
|
||||
},
|
||||
"silicate_rock": {
|
||||
"name": "Silicate Rock",
|
||||
"category": "meteorite_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.8,
|
||||
"melting_point_celsius": 1400,
|
||||
"stack_size": 50,
|
||||
"container_type": "bulk_solid",
|
||||
"ui": {
|
||||
"icon": "silicate_rock.png",
|
||||
"color": "#A0522D",
|
||||
"map_color": "#8B4513",
|
||||
"particle_effect": "rock_dust"
|
||||
}
|
||||
},
|
||||
"cosmic_dust": {
|
||||
"name": "Cosmic Dust",
|
||||
"category": "meteorite_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.2,
|
||||
"melting_point_celsius": 1100,
|
||||
"stack_size": 25,
|
||||
"container_type": "fine_powder",
|
||||
"ui": {
|
||||
"icon": "cosmic_dust.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#A9A9A9",
|
||||
"particle_effect": "fine_dust"
|
||||
}
|
||||
},
|
||||
"carbon_matrix": {
|
||||
"name": "Carbon Matrix",
|
||||
"category": "meteorite_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.8,
|
||||
"melting_point_celsius": 3550,
|
||||
"stack_size": 25,
|
||||
"container_type": "carbon_solid",
|
||||
"ui": {
|
||||
"icon": "carbon_matrix.png",
|
||||
"color": "#2F4F4F",
|
||||
"map_color": "#36454F",
|
||||
"particle_effect": "carbon_dust"
|
||||
}
|
||||
},
|
||||
"pumice_like_rock": {
|
||||
"name": "Pumice-like Rock",
|
||||
"category": "meteorite_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.6,
|
||||
"melting_point_celsius": 1200,
|
||||
"stack_size": 50,
|
||||
"container_type": "light_rock",
|
||||
"ui": {
|
||||
"icon": "pumice_rock.png",
|
||||
"color": "#D3D3D3",
|
||||
"map_color": "#DCDCDC",
|
||||
"particle_effect": "light_dust"
|
||||
}
|
||||
},
|
||||
"silicate_foam": {
|
||||
"name": "Silicate Foam",
|
||||
"category": "meteorite_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.4,
|
||||
"melting_point_celsius": 1400,
|
||||
"stack_size": 50,
|
||||
"container_type": "foam_material",
|
||||
"ui": {
|
||||
"icon": "silicate_foam.png",
|
||||
"color": "#F5F5F5",
|
||||
"map_color": "#E0E0E0",
|
||||
"particle_effect": "foam_particles"
|
||||
}
|
||||
},
|
||||
"granite": {
|
||||
"name": "Granite",
|
||||
"category": "construction_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.7,
|
||||
"melting_point_celsius": 1260,
|
||||
"stack_size": 100,
|
||||
"container_type": "bulk_solid",
|
||||
"ui": {
|
||||
"icon": "granite.png",
|
||||
"color": "#708090",
|
||||
"map_color": "#778899",
|
||||
"particle_effect": "stone_dust"
|
||||
}
|
||||
},
|
||||
"limestone": {
|
||||
"name": "Limestone",
|
||||
"category": "construction_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.3,
|
||||
"melting_point_celsius": 825,
|
||||
"stack_size": 100,
|
||||
"container_type": "bulk_solid",
|
||||
"ui": {
|
||||
"icon": "limestone.png",
|
||||
"color": "#F5F5DC",
|
||||
"map_color": "#F0E68C",
|
||||
"particle_effect": "limestone_dust"
|
||||
}
|
||||
},
|
||||
"sandstone": {
|
||||
"name": "Sandstone",
|
||||
"category": "construction_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.2,
|
||||
"melting_point_celsius": 1713,
|
||||
"stack_size": 100,
|
||||
"container_type": "bulk_solid",
|
||||
"ui": {
|
||||
"icon": "sandstone.png",
|
||||
"color": "#F4A460",
|
||||
"map_color": "#DEB887",
|
||||
"particle_effect": "sand_dust"
|
||||
}
|
||||
},
|
||||
"marble": {
|
||||
"name": "Marble",
|
||||
"category": "construction_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.7,
|
||||
"stack_size": 50,
|
||||
"container_type": "stone_block",
|
||||
"ui": {
|
||||
"icon": "marble.png",
|
||||
"color": "#F8F8FF",
|
||||
"map_color": "#E6E6FA",
|
||||
"particle_effect": "fine_stone_dust"
|
||||
}
|
||||
},
|
||||
"clay": {
|
||||
"name": "Clay",
|
||||
"category": "sedimentary_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.9,
|
||||
"stack_size": 100,
|
||||
"container_type": "clay_material",
|
||||
"ui": {
|
||||
"icon": "clay.png",
|
||||
"color": "#CD853F",
|
||||
"map_color": "#D2691E",
|
||||
"particle_effect": "clay_dust"
|
||||
}
|
||||
},
|
||||
"sand": {
|
||||
"name": "Sand",
|
||||
"category": "sedimentary_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.5,
|
||||
"stack_size": 100,
|
||||
"container_type": "fine_granules",
|
||||
"ui": {
|
||||
"icon": "sand.png",
|
||||
"color": "#F4A460",
|
||||
"map_color": "#DEB887",
|
||||
"particle_effect": "sand_particles"
|
||||
}
|
||||
},
|
||||
"gravel": {
|
||||
"name": "Gravel",
|
||||
"category": "sedimentary_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 1.8,
|
||||
"stack_size": 100,
|
||||
"container_type": "coarse_granules",
|
||||
"ui": {
|
||||
"icon": "gravel.png",
|
||||
"color": "#696969",
|
||||
"map_color": "#808080",
|
||||
"particle_effect": "gravel_dust"
|
||||
}
|
||||
},
|
||||
"obsidian": {
|
||||
"name": "Obsidian",
|
||||
"category": "volcanic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.4,
|
||||
"melting_point_celsius": 1100,
|
||||
"stack_size": 25,
|
||||
"container_type": "glass_rock",
|
||||
"ui": {
|
||||
"icon": "obsidian.png",
|
||||
"color": "#000000",
|
||||
"map_color": "#2F2F2F",
|
||||
"particle_effect": "glass_shards"
|
||||
}
|
||||
},
|
||||
"basalt": {
|
||||
"name": "Basalt",
|
||||
"category": "volcanic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 3.0,
|
||||
"melting_point_celsius": 1200,
|
||||
"stack_size": 100,
|
||||
"container_type": "volcanic_rock",
|
||||
"ui": {
|
||||
"icon": "basalt.png",
|
||||
"color": "#2F4F4F",
|
||||
"map_color": "#36454F",
|
||||
"particle_effect": "volcanic_dust"
|
||||
}
|
||||
},
|
||||
"pumice": {
|
||||
"name": "Pumice",
|
||||
"category": "volcanic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.9,
|
||||
"melting_point_celsius": 1200,
|
||||
"stack_size": 100,
|
||||
"container_type": "light_rock",
|
||||
"ui": {
|
||||
"icon": "pumice.png",
|
||||
"color": "#D3D3D3",
|
||||
"map_color": "#DCDCDC",
|
||||
"particle_effect": "light_volcanic_dust"
|
||||
}
|
||||
},
|
||||
"slate": {
|
||||
"name": "Slate",
|
||||
"category": "metamorphic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.8,
|
||||
"stack_size": 50,
|
||||
"container_type": "layered_rock",
|
||||
"ui": {
|
||||
"icon": "slate.png",
|
||||
"color": "#708090",
|
||||
"map_color": "#2F4F4F",
|
||||
"particle_effect": "slate_chips"
|
||||
}
|
||||
},
|
||||
"quartzite": {
|
||||
"name": "Quartzite",
|
||||
"category": "metamorphic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.6,
|
||||
"stack_size": 50,
|
||||
"container_type": "hard_rock",
|
||||
"ui": {
|
||||
"icon": "quartzite.png",
|
||||
"color": "#F5F5F5",
|
||||
"map_color": "#E0E0E0",
|
||||
"particle_effect": "quartz_dust"
|
||||
}
|
||||
},
|
||||
"gneiss": {
|
||||
"name": "Gneiss",
|
||||
"category": "metamorphic_rock",
|
||||
"logistic_category": "resource",
|
||||
"density": 2.7,
|
||||
"stack_size": 50,
|
||||
"container_type": "banded_rock",
|
||||
"ui": {
|
||||
"icon": "gneiss.png",
|
||||
"color": "#8B7D6B",
|
||||
"map_color": "#A0522D",
|
||||
"particle_effect": "metamorphic_dust"
|
||||
}
|
||||
}
|
||||
}
|
||||
78
gameData/Ressources/rawSpecialMaterials.json
Normal file
78
gameData/Ressources/rawSpecialMaterials.json
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"mystery_inclusions": {
|
||||
"name": "Mystery Inclusions",
|
||||
"category": "unknown_material",
|
||||
"logistic_category": "resource",
|
||||
"density": 8.5,
|
||||
"stack_size": 1,
|
||||
"container_type": "anomalous_material",
|
||||
"ui": {
|
||||
"icon": "mystery_inclusions.png",
|
||||
"color": "#8B008B",
|
||||
"map_color": "#9932CC",
|
||||
"particle_effect": "mystery_sparkle"
|
||||
}
|
||||
},
|
||||
"trapped_gases": {
|
||||
"name": "Trapped Gases",
|
||||
"category": "exotic_gas",
|
||||
"logistic_category": "fluid",
|
||||
"density": 0.002,
|
||||
"stack_size": 0,
|
||||
"container_type": "pressure_vessel",
|
||||
"ui": {
|
||||
"icon": "trapped_gases.png",
|
||||
"color": "#E0FFFF",
|
||||
"map_color": "#F0F8FF",
|
||||
"particle_effect": "gas_bubbles"
|
||||
}
|
||||
},
|
||||
"trace_metals": {
|
||||
"name": "Trace Metals",
|
||||
"category": "metal_mixture",
|
||||
"logistic_category": "resource",
|
||||
"density": 6.2,
|
||||
"stack_size": 10,
|
||||
"container_type": "mixed_metals",
|
||||
"ui": {
|
||||
"icon": "trace_metals.png",
|
||||
"color": "#C0C0C0",
|
||||
"map_color": "#A9A9A9",
|
||||
"particle_effect": "fine_metallic_dust"
|
||||
}
|
||||
},
|
||||
"metal_inclusions": {
|
||||
"name": "Metal Inclusions",
|
||||
"category": "embedded_metal",
|
||||
"logistic_category": "resource",
|
||||
"density": 4.8,
|
||||
"stack_size": 5,
|
||||
"container_type": "composite_material",
|
||||
"ui": {
|
||||
"icon": "metal_inclusions.png",
|
||||
"color": "#696969",
|
||||
"map_color": "#708090",
|
||||
"particle_effect": "embedded_sparkle"
|
||||
}
|
||||
},
|
||||
"meteoric_iron_ore": {
|
||||
"name": "Meteoric Iron Ore",
|
||||
"category": "space_alloy",
|
||||
"logistic_category": "resource",
|
||||
"density": 6.8,
|
||||
"melting_point_celsius": 1600,
|
||||
"stack_size": 25,
|
||||
"container_type": "meteoric_ore",
|
||||
"processing_note": "Space-forged iron-nickel alloy, produces superior steel with minimal processing",
|
||||
"ui": {
|
||||
"icon": "meteoric_iron_ore.png",
|
||||
"color": "#4682B4",
|
||||
"map_color": "#5F9EA0",
|
||||
"particle_effect": "meteoric_sparkle"
|
||||
}
|
||||
},
|
||||
// DECOMPOSED MATERIALS - Use individual ores instead:
|
||||
// "other_metals" → zinc_ore + tin_ore + lead_ore + antimony_ore (random distribution)
|
||||
// "precious_metals" → silver_ore + gold_ore + platinum_ore (random distribution)
|
||||
// "rare_metals" → titanium_ore + tungsten_ore + iridium_ore (random distribution)
|
||||
}
|
||||
49
gameData/Ressources/rawVolatiles.json
Normal file
49
gameData/Ressources/rawVolatiles.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"water_ice": {
|
||||
"name": "Water Ice",
|
||||
"category": "frozen_liquid",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.92,
|
||||
"stack_size": 100,
|
||||
"container_type": "ice_material",
|
||||
"melting_point_celsius": 0,
|
||||
"processing_note": "Melts to produce water",
|
||||
"ui": {
|
||||
"icon": "water_ice.png",
|
||||
"color": "#B0E0E6",
|
||||
"map_color": "#87CEEB",
|
||||
"particle_effect": "ice_crystals"
|
||||
}
|
||||
},
|
||||
"methane_ice": {
|
||||
"name": "Methane Ice",
|
||||
"category": "frozen_gas",
|
||||
"logistic_category": "resource",
|
||||
"density": 0.42,
|
||||
"stack_size": 50,
|
||||
"container_type": "volatile_ice",
|
||||
"melting_point_celsius": -182,
|
||||
"processing_note": "Sublimates to methane gas",
|
||||
"ui": {
|
||||
"icon": "methane_ice.png",
|
||||
"color": "#FFF8DC",
|
||||
"map_color": "#F0E68C",
|
||||
"particle_effect": "methane_vapor"
|
||||
}
|
||||
},
|
||||
"trapped_gases": {
|
||||
"name": "Trapped Gases",
|
||||
"category": "exotic_gas",
|
||||
"logistic_category": "fluid",
|
||||
"density": 0.002,
|
||||
"stack_size": 0,
|
||||
"container_type": "pressure_vessel",
|
||||
"processing_note": "Mixed atmospheric gases from space",
|
||||
"ui": {
|
||||
"icon": "trapped_gases.png",
|
||||
"color": "#E0FFFF",
|
||||
"map_color": "#F0F8FF",
|
||||
"particle_effect": "gas_bubbles"
|
||||
}
|
||||
}
|
||||
}
|
||||
919
gameData/WorldGeneration/Regular_world.json
Normal file
919
gameData/WorldGeneration/Regular_world.json
Normal file
@ -0,0 +1,919 @@
|
||||
{
|
||||
"geological_simulation": {
|
||||
"description": "Complete planetary formation simulation over 4.65 billion years",
|
||||
"total_duration_years": 4650000000,
|
||||
"phases": [
|
||||
// ===== PHASE 0: WORLD INITIALIZATION (1 cycle × 100M years = 0.1 Ga) =====
|
||||
{
|
||||
"name": "world_initialization",
|
||||
"description": "Initialize world state with starting conditions",
|
||||
"duration_cycles": 1,
|
||||
"years_per_cycle": 100000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "initialize_world_terrain",
|
||||
"process_type": "initialize_world_terrain",
|
||||
"parameters": {
|
||||
"surface_temperature_celsius": -100,
|
||||
"surface_elevation_meters": -30000,
|
||||
"world_size": {"width": 1000, "height": 1000}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initialize_planetary_core",
|
||||
"process_type": "initialize_planetary_core",
|
||||
"parameters": {
|
||||
"core_temperature_celsius": -100,
|
||||
"max_core_capacity": 1940000000000000000000,
|
||||
"base_composition": {
|
||||
"iron_ore": 155200000000000000000,
|
||||
"stone": 38800000000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 1: PLANETARY ACCRETION (30 cycles × 100M years = 3.0 Ga) =====
|
||||
{
|
||||
"name": "planetary_accretion",
|
||||
"description": "Initial planetary formation through meteorite bombardment",
|
||||
"duration_cycles": 30,
|
||||
"years_per_cycle": 100000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "meteorite_impact_generation",
|
||||
"process_type": "generate_meteorite_impacts",
|
||||
"parameters": {
|
||||
"impacts_per_wave": {"min": 100, "max": 500},
|
||||
"meteorite_source": "meteorites.json",
|
||||
"size_bias": "larger",
|
||||
"type_weights": {
|
||||
"chondrite_ordinary": 60,
|
||||
"carbonaceous_chondrite": 15,
|
||||
"stony_iron": 12,
|
||||
"iron_meteorite": 8,
|
||||
"ice_comet_fragment": 3,
|
||||
"platinum_rich_rare": 2,
|
||||
"bubble_meteorite": 1,
|
||||
"magnetic_anomaly": 0.8,
|
||||
"crystal_meteorite": 0.5,
|
||||
"glass_meteorite": 0.3,
|
||||
"diamond_meteorite": 0.2,
|
||||
"radioactive_anomaly": 0.1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "impact_effects_application",
|
||||
"process_type": "apply_impact_effects",
|
||||
"parameters": {
|
||||
"kinetic_energy_to_heat_ratio": 2000,
|
||||
"crater_formation_factor": 1.0,
|
||||
"surface_metal_deposit_ratio": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "planetary_differentiation",
|
||||
"process_type": "heavy_metal_sinking",
|
||||
"parameters": {
|
||||
"sinking_rate_per_cycle": 0.7,
|
||||
"heavy_metal_threshold_density": 5.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "volcanic_redistribution",
|
||||
"process_type": "core_driven_volcanism",
|
||||
"parameters": {
|
||||
"core_pressure_threshold": 0.8,
|
||||
"volcanic_overflow_rate": 0.2,
|
||||
"volcanic_generation": {
|
||||
"base_material_per_volcano": 1000000000000,
|
||||
"main_pick_count": 3,
|
||||
"secondary_pick_count": 5,
|
||||
"default_volcano_type": "stratovolcano"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cooling_phase",
|
||||
"process_type": "gradual_cooling",
|
||||
"parameters": {
|
||||
"surface_cooling_rate_per_cycle": 50,
|
||||
"energy_to_core_ratio": 0.3,
|
||||
"energy_to_space_ratio": 0.7,
|
||||
"minimum_surface_temperature": -273,
|
||||
"minimum_core_temperature": 1000,
|
||||
"optimal_cooling_core_temperature": 2000,
|
||||
"reference_surface_temperature": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "universal_region_fusion",
|
||||
"process_type": "manage_all_region_fusion",
|
||||
"parameters": {
|
||||
"enabled": true,
|
||||
"radius_calculation": "natural_logarithm",
|
||||
"base_radius": 1.5,
|
||||
"mass_reference": 5.0,
|
||||
"fusion_threshold_percentage": 0.3,
|
||||
"use_largest_radius_for_threshold": true,
|
||||
"weighted_position_update": true,
|
||||
"mass_combination": "additive",
|
||||
"applies_to_all_region_types": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 2: TECTONIC FORMATION (25 cycles × 100M years = 2.5 Ga) =====
|
||||
{
|
||||
"name": "tectonic_formation",
|
||||
"description": "Formation of tectonic plates and crustal thickening",
|
||||
"duration_cycles": 25,
|
||||
"years_per_cycle": 100000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "reduced_meteorite_bombardment",
|
||||
"process_type": "generate_meteorite_impacts",
|
||||
"parameters": {
|
||||
"impacts_per_wave": {"min": 10, "max": 50},
|
||||
"meteorite_source": "meteorites.json",
|
||||
"impact_probability_per_cycle": 0.3,
|
||||
"size_bias": "smaller",
|
||||
"type_weights": {
|
||||
"chondrite_ordinary": 35,
|
||||
"carbonaceous_chondrite": 20,
|
||||
"ice_comet_fragment": 15,
|
||||
"stony_iron": 8,
|
||||
"iron_meteorite": 5,
|
||||
"crystal_meteorite": 4,
|
||||
"magnetic_anomaly": 4,
|
||||
"bubble_meteorite": 3,
|
||||
"glass_meteorite": 2,
|
||||
"platinum_rich_rare": 2,
|
||||
"diamond_meteorite": 1.5,
|
||||
"radioactive_anomaly": 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "initial_tectonic_region_creation",
|
||||
"process_type": "create_tectonic_regions",
|
||||
"parameters": {
|
||||
"target_region_count": {"min": 15, "max": 25},
|
||||
"region_types": ["oceanic", "continental", "volcanic"],
|
||||
"initial_type_distribution": {
|
||||
"oceanic": 0.6,
|
||||
"continental": 0.35,
|
||||
"volcanic": 0.05
|
||||
},
|
||||
"initial_radius_range": {"min": 50, "max": 200},
|
||||
"random_placement": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tectonic_physics_simulation",
|
||||
"process_type": "tectonic_physics_engine",
|
||||
"parameters": {
|
||||
"repulsion_constant": 0.8,
|
||||
"velocity_damping": 0.95,
|
||||
"max_velocity": 5.0,
|
||||
"collision_detection": true,
|
||||
"force_calculation": "overlap_squared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "region_evolution",
|
||||
"process_type": "tectonic_region_evolution",
|
||||
"parameters": {
|
||||
"split_probability_per_cycle": 0.01,
|
||||
"growth_rate_range": {"min": -0.5, "max": 1.0},
|
||||
"stability_factor": 0.8,
|
||||
"minimum_region_radius": 20,
|
||||
"maximum_region_radius": 500
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "collision_effects",
|
||||
"process_type": "tectonic_collision_processing",
|
||||
"parameters": {
|
||||
"mountain_formation_threshold": 1.0,
|
||||
"mountain_height_multiplier": 2000,
|
||||
"rift_valley_depth": 500,
|
||||
"volcanic_zone_creation": true,
|
||||
"volcanic_zone_lifetime_cycles": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "universal_region_fusion",
|
||||
"process_type": "manage_all_region_fusion",
|
||||
"parameters": {
|
||||
"enabled": true,
|
||||
"radius_calculation": "natural_logarithm",
|
||||
"base_radius": 1.8,
|
||||
"mass_reference": 8.0,
|
||||
"fusion_threshold_percentage": 0.25,
|
||||
"use_largest_radius_for_threshold": true,
|
||||
"weighted_position_update": true,
|
||||
"mass_combination": "additive",
|
||||
"applies_to_all_region_types": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 3: GEOLOGICAL PREPARATION (25 cycles × 20M years = 0.5 Ga) =====
|
||||
{
|
||||
"name": "geological_preparation",
|
||||
"description": "Sea level rise and geological basin formation (preparation for future hydrology)",
|
||||
"duration_cycles": 25,
|
||||
"years_per_cycle": 20000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "tectonic_movement_slowdown",
|
||||
"process_type": "tectonic_physics_engine",
|
||||
"parameters": {
|
||||
"velocity_reduction_factor": 0.8,
|
||||
"repulsion_constant": 0.64,
|
||||
"velocity_damping": 0.95,
|
||||
"max_velocity": 4.0,
|
||||
"collision_detection": true,
|
||||
"force_calculation": "overlap_squared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "residual_meteorite_impacts",
|
||||
"process_type": "generate_meteorite_impacts",
|
||||
"parameters": {
|
||||
"impacts_per_wave": {"min": 1, "max": 5},
|
||||
"meteorite_source": "meteorites.json",
|
||||
"impact_probability_per_cycle": 0.1,
|
||||
"size_bias": "smaller",
|
||||
"type_weights": {
|
||||
"chondrite_ordinary": 20,
|
||||
"carbonaceous_chondrite": 15,
|
||||
"ice_comet_fragment": 25,
|
||||
"crystal_meteorite": 10,
|
||||
"magnetic_anomaly": 10,
|
||||
"glass_meteorite": 8,
|
||||
"bubble_meteorite": 7,
|
||||
"diamond_meteorite": 3,
|
||||
"platinum_rich_rare": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "residual_volcanism",
|
||||
"process_type": "core_driven_volcanism",
|
||||
"parameters": {
|
||||
"volcanic_activity_reduction": 0.1,
|
||||
"core_overflow_rate": 0.05,
|
||||
"eruption_probability_per_cycle": 0.2,
|
||||
"eruption_intensity_factor": 0.3,
|
||||
"core_pressure_threshold": 0.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sea_level_elevation",
|
||||
"process_type": "elevate_sea_level",
|
||||
"parameters": {
|
||||
"initial_sea_level_meters": -5000,
|
||||
"target_sea_level_meters": 0,
|
||||
"elevation_rate_per_cycle": 200,
|
||||
"ice_volume_effect": true,
|
||||
"thermal_expansion_effect": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tectonic_erosion",
|
||||
"process_type": "apply_tectonic_erosion",
|
||||
"parameters": {
|
||||
"erosion_rate_factor": 1.0,
|
||||
"elevation_erosion_threshold": 1000,
|
||||
"mass_to_core_transfer": true,
|
||||
"mountain_erosion_rate": 5.0,
|
||||
"weathering_rate": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "geological_basin_formation",
|
||||
"process_type": "form_geological_basins",
|
||||
"parameters": {
|
||||
"basin_formation_probability": 0.05,
|
||||
"valley_carving_intensity": 2.0,
|
||||
"depression_depth_factor": 1.5,
|
||||
"future_drainage_preparation": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "basic_climate_stabilization",
|
||||
"process_type": "stabilize_basic_climate",
|
||||
"parameters": {
|
||||
"temperature_stabilization_rate": 0.1,
|
||||
"co2_equilibrium_target": 350,
|
||||
"volcanic_co2_reduction": 0.05,
|
||||
"weathering_co2_absorption": 0.02
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coastal_zone_preparation",
|
||||
"process_type": "prepare_coastal_zones",
|
||||
"parameters": {
|
||||
"shallow_water_threshold": 50,
|
||||
"deep_water_threshold": 200,
|
||||
"coastal_shelf_formation": true,
|
||||
"sediment_accumulation_zones": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "universal_region_fusion",
|
||||
"process_type": "manage_all_region_fusion",
|
||||
"parameters": {
|
||||
"enabled": true,
|
||||
"radius_calculation": "natural_logarithm",
|
||||
"base_radius": 1.9,
|
||||
"mass_reference": 9.0,
|
||||
"fusion_threshold_percentage": 0.22,
|
||||
"use_largest_radius_for_threshold": true,
|
||||
"weighted_position_update": true,
|
||||
"mass_combination": "additive",
|
||||
"applies_to_all_region_types": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 4: CARBONIFEROUS PERIOD (35 cycles × 10M years = 0.35 Ga) =====
|
||||
{
|
||||
"name": "carboniferous_period",
|
||||
"description": "Dynamic forest evolution and coal formation through geological cycles",
|
||||
"duration_cycles": 35,
|
||||
"years_per_cycle": 10000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "tectonic_movement_continued",
|
||||
"process_type": "tectonic_physics_engine",
|
||||
"parameters": {
|
||||
"velocity_reduction_factor": 0.6,
|
||||
"repulsion_constant": 0.48,
|
||||
"velocity_damping": 0.96,
|
||||
"max_velocity": 3.0,
|
||||
"collision_detection": true,
|
||||
"force_calculation": "overlap_squared",
|
||||
"carbon_region_attachment_update": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dynamic_forest_seeding",
|
||||
"process_type": "seed_new_forests",
|
||||
"parameters": {
|
||||
"base_forest_seed_rate": 0.001,
|
||||
"temperature_optimal_range": {"min": 15.0, "max": 35.0},
|
||||
"temperature_bonus": 2.0,
|
||||
"humidity_threshold": 0.4,
|
||||
"humidity_bonus": 1.5,
|
||||
"elevation_max": 2000.0,
|
||||
"elevation_bonus": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "forest_expansion",
|
||||
"process_type": "expand_existing_forests",
|
||||
"parameters": {
|
||||
"forest_expansion_rate": 0.05,
|
||||
"neighbor_viability_check": true,
|
||||
"expansion_distance": 1,
|
||||
"density_growth_factor": 1.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "carbon_region_formation",
|
||||
"process_type": "create_carbon_regions",
|
||||
"parameters": {
|
||||
"minimum_forest_density": 0.3,
|
||||
"carbon_mass_base": 100.0,
|
||||
"region_radius_factor": 8.0,
|
||||
"tectonic_attachment_strength": 0.9,
|
||||
"carbon_type_initial": "COAL"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "carbon_region_movement",
|
||||
"process_type": "update_carbon_regions",
|
||||
"parameters": {
|
||||
"attachment_strength": 0.9,
|
||||
"merge_distance_factor": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coal_to_oil_conversion",
|
||||
"process_type": "convert_carbon_deposits",
|
||||
"parameters": {
|
||||
"conversion_rate_per_cycle": 0.01,
|
||||
"underwater_cycles_required": 3,
|
||||
"minimum_conversion_threshold": 1.0,
|
||||
"underwater_depth_minimum": 50.0,
|
||||
"surface_based_conversion": true,
|
||||
"create_separate_oil_regions": true,
|
||||
"oil_position_calculation": "underwater_center_of_mass",
|
||||
"natural_gas_generation": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "universal_region_fusion",
|
||||
"process_type": "manage_all_region_fusion",
|
||||
"parameters": {
|
||||
"enabled": true,
|
||||
"radius_calculation": "natural_logarithm",
|
||||
"base_radius": 2.0,
|
||||
"mass_reference": 10.0,
|
||||
"fusion_threshold_percentage": 0.2,
|
||||
"use_largest_radius_for_threshold": true,
|
||||
"weighted_position_update": true,
|
||||
"mass_combination": "additive",
|
||||
"applies_to_all_region_types": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "geological_forest_destruction",
|
||||
"process_type": "destroy_forests_by_events",
|
||||
"parameters": {
|
||||
"volcanic_destruction_radius": 10.0,
|
||||
"flood_destruction_threshold": 100,
|
||||
"erosion_destruction_threshold": 5.0,
|
||||
"temperature_destruction_min": -10.0,
|
||||
"temperature_destruction_max": 50.0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 5: PRE-FAUNAL STABILIZATION (15 cycles × 10M years = 0.15 Ga) =====
|
||||
{
|
||||
"name": "pre_faunal_stabilization",
|
||||
"description": "Final geological maturation and climate stabilization",
|
||||
"duration_cycles": 15,
|
||||
"years_per_cycle": 10000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "tectonic_movement_final_slowdown",
|
||||
"process_type": "tectonic_physics_engine",
|
||||
"parameters": {
|
||||
"velocity_reduction_factor": 0.48,
|
||||
"repulsion_constant": 0.38,
|
||||
"velocity_damping": 0.97,
|
||||
"max_velocity": 2.4,
|
||||
"collision_detection": true,
|
||||
"force_calculation": "overlap_squared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "reduced_carbon_formation",
|
||||
"process_type": "create_carbon_regions",
|
||||
"parameters": {
|
||||
"no_new_forests": true,
|
||||
"existing_forest_to_carbon_only": true,
|
||||
"carbon_mass_base": 50.0,
|
||||
"region_radius_factor": 8.0,
|
||||
"tectonic_attachment_strength": 0.9,
|
||||
"carbon_type_initial": "COAL"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hydrocarbon_maturation_continued",
|
||||
"process_type": "convert_carbon_deposits",
|
||||
"parameters": {
|
||||
"conversion_rate_per_cycle": 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "universal_region_fusion",
|
||||
"process_type": "manage_all_region_fusion",
|
||||
"parameters": {
|
||||
"enabled": true,
|
||||
"radius_calculation": "natural_logarithm",
|
||||
"base_radius": 2.2,
|
||||
"mass_reference": 15.0,
|
||||
"fusion_threshold_percentage": 0.2,
|
||||
"use_largest_radius_for_threshold": true,
|
||||
"weighted_position_update": true,
|
||||
"mass_combination": "additive",
|
||||
"applies_to_all_region_types": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "petroleum_migration_to_traps",
|
||||
"process_type": "migrate_petroleum_to_geological_traps",
|
||||
"parameters": {
|
||||
"trap_identification": true,
|
||||
"anticline_formation_factor": 1.0,
|
||||
"fault_trap_creation": true,
|
||||
"salt_dome_probability": 0.05,
|
||||
"migration_efficiency": 0.3,
|
||||
"trap_capacity_factor": 50.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "final_erosion_phase",
|
||||
"process_type": "apply_final_erosion",
|
||||
"parameters": {
|
||||
"erosion_rate_reduction": 0.5,
|
||||
"coal_seam_exposure": true,
|
||||
"river_valley_carving": true,
|
||||
"coastal_feature_formation": true,
|
||||
"erosion_depth_threshold": 50.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "soil_development",
|
||||
"process_type": "develop_soil_layers",
|
||||
"parameters": {
|
||||
"soil_types": ["clay", "sand", "loam", "peat", "rocky", "alluvial"],
|
||||
"soil_depth_factor": 0.1,
|
||||
"climate_soil_correlation": true,
|
||||
"river_alluvial_bonus": true,
|
||||
"elevation_soil_effects": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "final_climate_stabilization",
|
||||
"process_type": "stabilize_final_climate",
|
||||
"parameters": {
|
||||
"volcanic_activity_reduction": 0.8,
|
||||
"climate_stability_increase": 0.1,
|
||||
"climate_zone_establishment": true,
|
||||
"temperature_variance_reduction": 0.9
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 6A: LANDMASS ANALYSIS & ITCZ PREPARATION (1 cycle × 1M years) =====
|
||||
{
|
||||
"name": "landmass_analysis_and_itcz_preparation",
|
||||
"description": "Analyze continental masses from existing TectonicRegions and create Inter-Tropical Convergence Zones",
|
||||
"duration_cycles": 1,
|
||||
"years_per_cycle": 1000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "continental_mass_analysis",
|
||||
"process_type": "analyze_continental_masses",
|
||||
"parameters": {
|
||||
"_comment": "Uses existing TectonicRegions to identify continental masses for ITCZ placement",
|
||||
"continental_grouping": {
|
||||
"proximity_threshold": 100,
|
||||
"minimum_region_count": 2,
|
||||
"mass_calculation_method": "area_weighted",
|
||||
"continental_type_filter": ["continental", "volcanic"]
|
||||
},
|
||||
"landmass_requirements": {
|
||||
"minimum_total_area": 5000,
|
||||
"minimum_individual_region_area": 1000,
|
||||
"connectivity_analysis": true
|
||||
},
|
||||
"equatorial_filtering": {
|
||||
"latitude_band": [0.40, 0.60],
|
||||
"strict_equatorial_requirement": false,
|
||||
"latitude_scoring_weight": 0.7
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ocean_basin_detection",
|
||||
"process_type": "detect_ocean_basins",
|
||||
"parameters": {
|
||||
"_comment": "Inverse analysis to identify ocean masses from continental positions",
|
||||
"ocean_detection_method": "inverse_continental_analysis",
|
||||
"minimum_ocean_size": 5000,
|
||||
"coastal_connectivity_check": true,
|
||||
"ocean_temperature_estimation": {
|
||||
"latitude_based": true,
|
||||
"equator_temp": 28.0,
|
||||
"pole_temp": 2.0,
|
||||
"thermal_gradient": "cosine_distribution"
|
||||
},
|
||||
"evaporation_potential_calculation": {
|
||||
"temperature_factor": true,
|
||||
"surface_area_factor": true,
|
||||
"wind_exposure_factor": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "itcz_zone_creation",
|
||||
"process_type": "create_itcz_convergence_zones",
|
||||
"parameters": {
|
||||
"_comment": "Create ITCZ zones on qualifying equatorial landmasses",
|
||||
"itcz_requirements": {
|
||||
"latitude_band": [0.45, 0.55],
|
||||
"min_landmass_size": 10000,
|
||||
"max_ocean_distance": 800,
|
||||
"continental_heating_threshold": 5000
|
||||
},
|
||||
"itcz_zone_properties": {
|
||||
"center_calculation": "continental_center_of_mass",
|
||||
"gravitational_range_formula": "sqrt(landmass_area) * 50",
|
||||
"mass_calculation": "landmass_total_area",
|
||||
"amplification_factor": 3.0,
|
||||
"intensity_falloff": "inverse_square_law"
|
||||
},
|
||||
"multiple_itcz_handling": {
|
||||
"allow_multiple_zones": true,
|
||||
"minimum_separation_distance": 500,
|
||||
"interaction_between_zones": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "climate_infrastructure_preparation",
|
||||
"process_type": "prepare_climate_simulation_infrastructure",
|
||||
"parameters": {
|
||||
"_comment": "Clean slate preparation for WindRegion-based simulation",
|
||||
"data_cleanup": {
|
||||
"clear_legacy_wind_data": true,
|
||||
"clear_legacy_humidity_data": true,
|
||||
"preserve_temperature_gradients": true,
|
||||
"preserve_elevation_data": true
|
||||
},
|
||||
"token_system_initialization": {
|
||||
"initialize_token_counters": true,
|
||||
"token_types": ["wind", "rain", "highWind", "flood", "hurricane"],
|
||||
"reset_all_tokens": true
|
||||
},
|
||||
"performance_optimization": {
|
||||
"pre_allocate_wind_region_pool": true,
|
||||
"max_concurrent_wind_regions": 200,
|
||||
"spatial_indexing_setup": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 6B: CLIMATE SIMULATION & BIOME GENERATION (300 cycles × 100K years = 30M years) =====
|
||||
{
|
||||
"name": "climate_simulation_and_biome_generation",
|
||||
"description": "Advanced climate simulation using mobile WindRegions and ITCZ zones for realistic weather patterns",
|
||||
"duration_cycles": 300,
|
||||
"years_per_cycle": 100000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "wind_region_spawning_system",
|
||||
"process_type": "spawn_mobile_wind_regions",
|
||||
"parameters": {
|
||||
"_comment": "Mobile WindRegions spawn from ocean masses with biased distribution",
|
||||
"spawn_system": {
|
||||
"spawn_locations": "ocean_masses_only",
|
||||
"spawn_frequency_formula": "water_mass_size / 1000",
|
||||
"spawn_distribution": "random_within_water_region_biased_toward_center",
|
||||
"max_concurrent_regions": 200,
|
||||
"initial_strength_formula": "water_temperature * evaporation_factor"
|
||||
},
|
||||
"wind_region_properties": {
|
||||
"initial_wind_strength": 1.0,
|
||||
"initial_wetness": 0.0,
|
||||
"wind_tokens": 100,
|
||||
"rain_tokens": 0,
|
||||
"decay_per_move": 0.02,
|
||||
"decay_per_tile": 0.01,
|
||||
"minimum_survival_threshold": 0.1
|
||||
},
|
||||
"ocean_moisture_gain": {
|
||||
"ocean_moisture_rate": 0.1,
|
||||
"temperature_factor": true,
|
||||
"evaporation_efficiency": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "planetary_circulation_and_movement",
|
||||
"process_type": "apply_planetary_circulation",
|
||||
"parameters": {
|
||||
"_comment": "Planetary rotation bands based on real atmospheric data",
|
||||
"planetary_circulation_bands": {
|
||||
"polar_jet_north": {
|
||||
"latitude_range": [0.10, 0.25],
|
||||
"direction": "west_to_east",
|
||||
"strength": 1.8
|
||||
},
|
||||
"calm_transition_1": {
|
||||
"latitude_range": [0.25, 0.40],
|
||||
"movement": "chaos_plus_procedural"
|
||||
},
|
||||
"equatorial_trades": {
|
||||
"latitude_range": [0.40, 0.60],
|
||||
"direction": "east_to_west",
|
||||
"strength": 1.5
|
||||
},
|
||||
"calm_transition_2": {
|
||||
"latitude_range": [0.60, 0.75],
|
||||
"movement": "chaos_plus_procedural"
|
||||
},
|
||||
"polar_jet_south": {
|
||||
"latitude_range": [0.75, 0.95],
|
||||
"direction": "west_to_east",
|
||||
"strength": 1.8
|
||||
}
|
||||
},
|
||||
"movement_calculation": {
|
||||
"planetary_circulation_weight": 0.6,
|
||||
"equator_to_pole_bias_weight": 0.2,
|
||||
"terrain_deflection_weight": 0.1,
|
||||
"random_variation_weight": 0.1
|
||||
},
|
||||
"movement_physics": {
|
||||
"velocity_damping": 0.95,
|
||||
"terrain_interaction": true,
|
||||
"boundary_wrapping": "spherical_world"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wind_region_evolution_and_interactions",
|
||||
"process_type": "evolve_wind_regions",
|
||||
"parameters": {
|
||||
"_comment": "WindRegion interactions including repulsion system and ITCZ effects",
|
||||
"repulsion_system": {
|
||||
"enabled": true,
|
||||
"repulsion_calculation": "spatial_competition_proxy",
|
||||
"acceleration_factor": 1.0,
|
||||
"maximum_interaction_distance": 50.0,
|
||||
"_design_note": "Prevents region stacking while creating realistic dispersion patterns",
|
||||
"_alternative_algorithms": {
|
||||
"density_based_drift": false,
|
||||
"no_interaction": false,
|
||||
"collision_division": false
|
||||
}
|
||||
},
|
||||
"itcz_gravitational_effects": {
|
||||
"enabled": true,
|
||||
"attraction_formula": "itcz.mass / (distance * distance)",
|
||||
"gravitational_metaphor": "influence_strength_not_literal_physics",
|
||||
"amplification_calculation": {
|
||||
"proximity_factor": "(itcz.range - distance) / itcz.range",
|
||||
"max_amplification": 3.0,
|
||||
"wind_strength_multiplier": true,
|
||||
"wetness_multiplier": true
|
||||
}
|
||||
},
|
||||
"regional_evolution": {
|
||||
"wind_strength_decay": true,
|
||||
"moisture_accumulation": true,
|
||||
"death_threshold": 0.1,
|
||||
"lifecycle_management": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token_distribution_and_climate_zones",
|
||||
"process_type": "distribute_climate_tokens",
|
||||
"parameters": {
|
||||
"_comment": "Token-based climate zone classification system",
|
||||
"basic_token_distribution": {
|
||||
"wind_token_factor": 10,
|
||||
"rain_token_factor": 10,
|
||||
"tokens_per_tile_visit": true,
|
||||
"accumulation_system": true
|
||||
},
|
||||
"climate_zone_thresholds": {
|
||||
"high_wind_threshold": 2.0,
|
||||
"flood_threshold": 1.5,
|
||||
"hurricane_wind_threshold": 2.5,
|
||||
"hurricane_rain_threshold": 2.0
|
||||
},
|
||||
"special_climate_tokens": {
|
||||
"high_wind_tokens": {
|
||||
"description": "Hostile to forests",
|
||||
"biome_effect": "prevents_forest_growth",
|
||||
"token_value": 1
|
||||
},
|
||||
"flood_tokens": {
|
||||
"description": "Forces wetlands/marshes",
|
||||
"biome_effect": "mandatory_wetlands",
|
||||
"token_value": 1
|
||||
},
|
||||
"hurricane_tokens": {
|
||||
"description": "Specialized hurricane biome",
|
||||
"biome_effect": "storm_resistant_vegetation",
|
||||
"token_value": 1
|
||||
}
|
||||
},
|
||||
"token_persistence": {
|
||||
"accumulation_method": "additive",
|
||||
"decay_rate": 0.0,
|
||||
"permanent_climate_record": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "biome_classification_from_tokens",
|
||||
"process_type": "classify_biomes_from_climate_tokens",
|
||||
"parameters": {
|
||||
"_comment": "Load biome system from external definitions - all rules and modifiers defined in biome files",
|
||||
"biome_system_source": "gameData/Biomes/biome_index.json",
|
||||
"load_all_biome_definitions": true,
|
||||
"use_external_classification_rules": true,
|
||||
"use_external_resource_modifiers": true,
|
||||
"fallback_biome": "scrubland"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "temporal_token_dissipation",
|
||||
"process_type": "apply_token_dissipation",
|
||||
"parameters": {
|
||||
"_comment": "Random token dissipation - high for normal tokens (variation), low for catastrophe tokens (preserve special zones)",
|
||||
"rain_tokens": {
|
||||
"dissipation_range": [5, 25],
|
||||
"dissipation_frequency": 0.12
|
||||
},
|
||||
"wind_tokens": {
|
||||
"dissipation_range": [3, 15],
|
||||
"dissipation_frequency": 0.10
|
||||
},
|
||||
"highWind_tokens": {
|
||||
"dissipation_range": [2, 8],
|
||||
"dissipation_frequency": 0.08
|
||||
},
|
||||
"flood_tokens": {
|
||||
"dissipation_range": [1, 2],
|
||||
"dissipation_frequency": 0.02
|
||||
},
|
||||
"hurricane_tokens": {
|
||||
"dissipation_range": [1, 2],
|
||||
"dissipation_frequency": 0.015
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 7: BUDGET ASSIGNMENT =====
|
||||
{
|
||||
"name": "budget_assignment",
|
||||
"description": "Random budget score distribution for economic gameplay",
|
||||
"duration_cycles": 1,
|
||||
"years_per_cycle": 1000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "assign_budget_scores",
|
||||
"process_type": "random_budget_assignment",
|
||||
"parameters": {
|
||||
"distribution": "normal",
|
||||
"mean": 0.0,
|
||||
"std_dev": 3.0,
|
||||
"range": [-10, 10]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ===== PHASE 7: BUDGET & FEATURES =====
|
||||
{
|
||||
"name": "budget_and_features",
|
||||
"description": "Random budget assignment and biome-appropriate natural features placement",
|
||||
"duration_cycles": 1,
|
||||
"years_per_cycle": 1000000,
|
||||
"steps": [
|
||||
{
|
||||
"name": "assign_budget_scores",
|
||||
"process_type": "random_budget_assignment",
|
||||
"parameters": {
|
||||
"distribution": "normal",
|
||||
"mean": 0.0,
|
||||
"std_dev": 3.0,
|
||||
"range": [-10, 10]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "place_natural_features",
|
||||
"process_type": "biome_based_feature_placement",
|
||||
"parameters": {
|
||||
"chance": 0.05,
|
||||
"feature_sources": [
|
||||
"gameData/MapFeatures/geological_formations.json",
|
||||
"gameData/MapFeatures/natural_landmarks.json",
|
||||
"gameData/MapFeatures/water_features.json",
|
||||
"gameData/MapFeatures/volcanic_features.json",
|
||||
"gameData/MapFeatures/underground_features.json",
|
||||
"gameData/MapFeatures/forest_features.json",
|
||||
"gameData/MapFeatures/coastal_features.json"
|
||||
],
|
||||
"biome_compatibility": {
|
||||
"tropical_rainforest": ["giant_tree", "ancient_grove", "bamboo_grove", "fruit_orchard", "carboniferous_forest", "underground_river"],
|
||||
"hot_desert": ["canyon", "cliff", "sinkhole", "oasis", "volcano", "lava_field", "obsidian_field"],
|
||||
"temperate_forest": ["forest_clearing", "ancient_grove", "medicinal_grove", "mushroom_grove", "carboniferous_forest", "underground_lake"],
|
||||
"grassland": ["plateau", "natural_bridge", "sinkhole", "lake", "spring"],
|
||||
"tundra": ["geyser", "sinkhole", "cliff", "lake", "crater", "fumarole", "deep_cavern"],
|
||||
"alpine": ["canyon", "cliff", "gorge", "volcano", "caldera", "crystal_cavern", "volcanic_vent"],
|
||||
"cold_desert": ["canyon", "cliff", "sinkhole", "hoodoo", "crater", "obsidian_field"],
|
||||
"hills": ["cave", "spring", "plateau", "gorge", "cave_network", "bat_cave"],
|
||||
"rocky_plateau": ["canyon", "cliff", "natural_bridge", "mesa", "rock_spire", "monolith"],
|
||||
"hurricane_zone": ["cave", "gorge", "marsh", "central_hill_swamp", "bat_cave"],
|
||||
"wetlands": ["central_hill_swamp", "islands_swamp", "hilly_swampy", "underground_lake", "delta"],
|
||||
"storm_prairie": ["plateau", "sinkhole", "natural_bridge", "hoodoo", "monolith"],
|
||||
"badlands": ["canyon", "cliff", "gorge", "mesa", "sinkhole", "lava_field"],
|
||||
"coastal_plain": ["delta", "pond", "marsh", "estuary", "natural_harbor"],
|
||||
"cliffs": ["sea_cave", "cliff", "natural_arch", "blowhole", "sea_stack"],
|
||||
"sandy_coast": ["beach_dunes", "delta", "natural_harbor", "tidal_pool", "estuary"],
|
||||
"rocky_shore": ["sea_cave", "tidal_pool", "sea_stack", "blowhole", "coral_reef"],
|
||||
"scrubland": ["cave", "plateau", "spring", "sinkhole", "canyon", "monolith", "rock_spire"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
33
gameData/WorldGeneration/World_index.json
Normal file
33
gameData/WorldGeneration/World_index.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"world_generation_scenarios": {
|
||||
"description": "Available world generation scenarios and their configurations",
|
||||
"default_scenario": "regular_world",
|
||||
"scenarios": {
|
||||
"regular_world": {
|
||||
"name": "Regular World",
|
||||
"description": "Standard planetary formation with realistic geological processes",
|
||||
"config_file": "Regular_world.json",
|
||||
"difficulty": "standard",
|
||||
"estimated_generation_time_seconds": 30,
|
||||
"features": [
|
||||
"complete_geological_simulation",
|
||||
"meteorite_bombardment",
|
||||
"tectonic_activity",
|
||||
"climate_formation",
|
||||
"resource_distribution"
|
||||
],
|
||||
"recommended_for": ["standard_gameplay", "balanced_resources", "realistic_geology"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"shared_resources": {
|
||||
"meteorite_definitions": "meteorites.json",
|
||||
"process_definitions": "process_definitions.json"
|
||||
},
|
||||
"generation_settings": {
|
||||
"default_map_size": {"width": 1000, "height": 1000},
|
||||
"performance_mode": "balanced",
|
||||
"debug_output": false,
|
||||
"save_intermediate_states": false
|
||||
}
|
||||
}
|
||||
222
gameData/WorldGeneration/meteorites.json
Normal file
222
gameData/WorldGeneration/meteorites.json
Normal file
@ -0,0 +1,222 @@
|
||||
{
|
||||
"_comments": {
|
||||
"decomposed_materials": "Future materials to implement:",
|
||||
"other_metals": "zinc_ore + tin_ore + lead_ore + antimony_ore (random distribution)",
|
||||
"precious_metals": "silver_ore + gold_ore + platinum_ore (random distribution)",
|
||||
"rare_metals": "titanium_ore + tungsten_ore + iridium_ore (random distribution)",
|
||||
"note": "meteoric_iron_ore should be rare (1-5%) - premium material for superior steel"
|
||||
},
|
||||
"meteorite_types": {
|
||||
"chondrite_ordinary": {
|
||||
"name": "Ordinary Chondrite",
|
||||
"description": "Most common meteorite type - rocky with some metal",
|
||||
"composition": {
|
||||
"silicate_rock": 85,
|
||||
"iron_ore": 8,
|
||||
"meteoric_iron_ore": 1,
|
||||
"nickel_ore": 3,
|
||||
"zinc_ore": 2,
|
||||
"tin_ore": 1
|
||||
},
|
||||
"mass_range": {"min": 1e10, "max": 1e13},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.0,
|
||||
"heat_generation": 800,
|
||||
"fragmentation": "medium"
|
||||
}
|
||||
},
|
||||
"carbonaceous_chondrite": {
|
||||
"name": "Carbonaceous Chondrite",
|
||||
"description": "Water and organic-rich meteorites",
|
||||
"composition": {
|
||||
"silicate_rock": 70,
|
||||
"water_ice": 15,
|
||||
"organic_compounds": 10,
|
||||
"iron_ore": 3,
|
||||
"nickel_ore": 2
|
||||
},
|
||||
"mass_range": {"min": 5e9, "max": 8e12},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 0.8,
|
||||
"heat_generation": 600,
|
||||
"fragmentation": "high"
|
||||
}
|
||||
},
|
||||
"iron_meteorite": {
|
||||
"name": "Iron Meteorite",
|
||||
"description": "Almost pure metal - core fragments from destroyed planetoids",
|
||||
"composition": {
|
||||
"iron_ore": 80,
|
||||
"meteoric_iron_ore": 5,
|
||||
"nickel_ore": 12,
|
||||
"silver_ore": 1,
|
||||
"gold_ore": 1,
|
||||
"platinum_ore": 1
|
||||
},
|
||||
"mass_range": {"min": 1e12, "max": 1e15},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.5,
|
||||
"heat_generation": 1500,
|
||||
"fragmentation": "low"
|
||||
}
|
||||
},
|
||||
"stony_iron": {
|
||||
"name": "Stony-Iron Meteorite",
|
||||
"description": "Mixed rock and metal - rare but valuable",
|
||||
"composition": {
|
||||
"silicate_rock": 50,
|
||||
"iron_ore": 30,
|
||||
"meteoric_iron_ore": 3,
|
||||
"nickel_ore": 10,
|
||||
"silver_ore": 2,
|
||||
"gold_ore": 1,
|
||||
"zinc_ore": 2,
|
||||
"tin_ore": 1,
|
||||
"lead_ore": 1
|
||||
},
|
||||
"mass_range": {"min": 5e11, "max": 5e14},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.2,
|
||||
"heat_generation": 1200,
|
||||
"fragmentation": "medium"
|
||||
}
|
||||
},
|
||||
"platinum_rich_rare": {
|
||||
"name": "Platinum-Rich Asteroid Fragment",
|
||||
"description": "Extremely rare precious metal rich meteorite",
|
||||
"composition": {
|
||||
"silicate_rock": 30,
|
||||
"iron_ore": 18,
|
||||
"meteoric_iron_ore": 5,
|
||||
"nickel_ore": 15,
|
||||
"platinum_ore": 15,
|
||||
"gold_ore": 8,
|
||||
"titanium_ore": 4,
|
||||
"tungsten_ore": 2,
|
||||
"iridium_ore": 2,
|
||||
"silver_ore": 1
|
||||
},
|
||||
"mass_range": {"min": 1e11, "max": 1e14},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.3,
|
||||
"heat_generation": 1000,
|
||||
"fragmentation": "low"
|
||||
}
|
||||
},
|
||||
"crystal_meteorite": {
|
||||
"name": "Crystalline Meteorite",
|
||||
"description": "Bizarre meteorite made of pure quartz crystals - origin unknown",
|
||||
"composition": {
|
||||
"quartz_crystal": 90,
|
||||
"rare_earth_elements": 5,
|
||||
"unknown_minerals": 5
|
||||
},
|
||||
"mass_range": {"min": 1e9, "max": 1e12},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 0.3,
|
||||
"heat_generation": 200,
|
||||
"fragmentation": "explosive",
|
||||
"special_effects": ["crystal_formations", "electromagnetic_anomaly"]
|
||||
}
|
||||
},
|
||||
"ice_comet_fragment": {
|
||||
"name": "Dirty Snowball Fragment",
|
||||
"description": "Massive chunk of dirty ice from the outer solar system",
|
||||
"composition": {
|
||||
"water_ice": 60,
|
||||
"methane_ice": 20,
|
||||
"cosmic_dust": 15,
|
||||
"organic_compounds": 5
|
||||
},
|
||||
"mass_range": {"min": 1e12, "max": 1e16},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 2.0,
|
||||
"heat_generation": 300,
|
||||
"fragmentation": "explosive",
|
||||
"special_effects": ["steam_explosion", "temporary_atmosphere", "organic_seeding"]
|
||||
}
|
||||
},
|
||||
"radioactive_anomaly": {
|
||||
"name": "Radioactive Anomaly",
|
||||
"description": "Highly radioactive meteorite of unknown composition - handle with care",
|
||||
"composition": {
|
||||
"uranium_ore": 40,
|
||||
"thorium_ore": 25,
|
||||
"plutonium": 15,
|
||||
"unknown_isotopes": 20
|
||||
},
|
||||
"mass_range": {"min": 1e10, "max": 1e13},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.0,
|
||||
"heat_generation": 3000,
|
||||
"fragmentation": "low",
|
||||
"special_effects": ["radiation_zone", "mutation_field", "thermal_anomaly"]
|
||||
}
|
||||
},
|
||||
"magnetic_anomaly": {
|
||||
"name": "Magnetic Core Fragment",
|
||||
"description": "Intensely magnetic meteorite that disrupts compasses for kilometers",
|
||||
"composition": {
|
||||
"magnetite": 70,
|
||||
"iron_ore": 20,
|
||||
"rare_earth_magnets": 10
|
||||
},
|
||||
"mass_range": {"min": 1e11, "max": 1e14},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.4,
|
||||
"heat_generation": 1200,
|
||||
"fragmentation": "medium",
|
||||
"special_effects": ["magnetic_field_disruption", "compass_anomaly", "metallic_attraction"]
|
||||
}
|
||||
},
|
||||
"glass_meteorite": {
|
||||
"name": "Obsidian Wanderer",
|
||||
"description": "Perfectly smooth glass meteorite - natural or artificial origin unclear",
|
||||
"composition": {
|
||||
"volcanic_glass": 95,
|
||||
"trace_metals": 3,
|
||||
"mystery_inclusions": 2
|
||||
},
|
||||
"mass_range": {"min": 1e9, "max": 1e11},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 0.5,
|
||||
"heat_generation": 400,
|
||||
"fragmentation": "high",
|
||||
"special_effects": ["razor_sharp_shards", "perfect_reflections", "optical_effects"]
|
||||
}
|
||||
},
|
||||
"bubble_meteorite": {
|
||||
"name": "Foam Stone",
|
||||
"description": "Incredibly light meteorite full of gas bubbles - floats on water",
|
||||
"composition": {
|
||||
"pumice_like_rock": 40,
|
||||
"trapped_gases": 50,
|
||||
"silicate_foam": 10
|
||||
},
|
||||
"mass_range": {"min": 1e8, "max": 1e10},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 0.1,
|
||||
"heat_generation": 100,
|
||||
"fragmentation": "low",
|
||||
"special_effects": ["gas_release", "floating_debris", "minimal_damage"]
|
||||
}
|
||||
},
|
||||
"diamond_meteorite": {
|
||||
"name": "Diamond Rain",
|
||||
"description": "Meteorite studded with micro-diamonds - forms under extreme pressure",
|
||||
"composition": {
|
||||
"micro_diamonds": 30,
|
||||
"carbon_matrix": 50,
|
||||
"silicate_rock": 15,
|
||||
"metal_inclusions": 5
|
||||
},
|
||||
"mass_range": {"min": 1e10, "max": 1e12},
|
||||
"impact_characteristics": {
|
||||
"crater_factor": 1.1,
|
||||
"heat_generation": 900,
|
||||
"fragmentation": "low",
|
||||
"special_effects": ["diamond_scatter", "extreme_hardness", "cutting_capability"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
gameconfig.json
Normal file
110
gameconfig.json
Normal file
@ -0,0 +1,110 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"created": "2025-01-27",
|
||||
"description": "Warfactory system configuration - infrastructure only",
|
||||
"hash": "sha256:placeholder"
|
||||
},
|
||||
|
||||
"coordination": {
|
||||
"enabled": true,
|
||||
"module_deployment_timeout": 30000,
|
||||
"health_check_interval": 5000,
|
||||
"hot_reload": {
|
||||
"enabled": true,
|
||||
"watch_directories": ["modules/", "config/"],
|
||||
"extensions": [".so", ".json"]
|
||||
}
|
||||
},
|
||||
|
||||
"modules": {
|
||||
"debug_world_gen": {
|
||||
"enabled": true,
|
||||
"priority": 1,
|
||||
"frequency": 1.0,
|
||||
"library_path": "modules/debug_world_gen/build/libdebug_world_gen.so",
|
||||
"config_file": "config/debug_world_gen.json"
|
||||
},
|
||||
|
||||
"tank": {
|
||||
"enabled": true,
|
||||
"priority": 2,
|
||||
"frequency": 60.0,
|
||||
"library_path": "modules/tank/build/libtank.so",
|
||||
"config_file": "config/tank.json"
|
||||
},
|
||||
|
||||
"economy": {
|
||||
"enabled": true,
|
||||
"priority": 3,
|
||||
"frequency": 0.1,
|
||||
"library_path": "modules/economy/build/libeconomy.so",
|
||||
"config_file": "config/economy.json"
|
||||
},
|
||||
|
||||
"factory": {
|
||||
"enabled": true,
|
||||
"priority": 4,
|
||||
"frequency": 60.0,
|
||||
"library_path": "modules/factory/build/libfactory.so",
|
||||
"config_file": "config/factory.json"
|
||||
},
|
||||
|
||||
"logistic": {
|
||||
"enabled": true,
|
||||
"priority": 5,
|
||||
"frequency": 1.0,
|
||||
"library_path": "modules/logistic/build/liblogistic.so",
|
||||
"config_file": "config/logistic.json"
|
||||
}
|
||||
},
|
||||
|
||||
"engine": {
|
||||
"type": "DEBUG",
|
||||
"target_fps": 60,
|
||||
"step_by_step": false,
|
||||
"verbose_logging": true,
|
||||
"performance_monitoring": true,
|
||||
"module_system": {
|
||||
"type": "SEQUENTIAL",
|
||||
"thread_pool_size": 4,
|
||||
"task_queue_size": 1000
|
||||
}
|
||||
},
|
||||
|
||||
"performance": {
|
||||
"targets": {
|
||||
"v1_client_fps": 30,
|
||||
"v2_client_fps": 60,
|
||||
"v1_server_players": 10,
|
||||
"v2_server_players": 100,
|
||||
"iteration_cycle_seconds": 5,
|
||||
"hot_reload_ms": 1
|
||||
},
|
||||
"optimization": {
|
||||
"simd": false,
|
||||
"cluster_distribution": false,
|
||||
"memory_pooling": true,
|
||||
"cache_friendly_data": true
|
||||
}
|
||||
},
|
||||
|
||||
"debugging": {
|
||||
"sanitizers": {
|
||||
"address": true,
|
||||
"undefined_behavior": true,
|
||||
"leak": true
|
||||
},
|
||||
"profiling": {
|
||||
"enabled": true,
|
||||
"per_module_metrics": true,
|
||||
"memory_tracking": true
|
||||
},
|
||||
"logging": {
|
||||
"level": "DEBUG",
|
||||
"file_output": true,
|
||||
"console_output": true,
|
||||
"json_structured": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "IDataTree.h"
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
/**
|
||||
* @brief Factory for creating data tree instances
|
||||
*/
|
||||
class DataTreeFactory {
|
||||
public:
|
||||
/**
|
||||
* @brief Create data tree from configuration source
|
||||
* @param type Tree type ("json", "database", etc.)
|
||||
* @param sourcePath Path to configuration source
|
||||
* @return Data tree instance
|
||||
*/
|
||||
static std::unique_ptr<IDataTree> create(const std::string& type, const std::string& sourcePath);
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,233 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/**
|
||||
* @brief Interface for a single node in the data tree
|
||||
*
|
||||
* Each node can have:
|
||||
* - Children nodes (tree navigation)
|
||||
* - Its own data blob (JSON)
|
||||
* - Properties accessible by name with type safety
|
||||
*/
|
||||
class IDataNode {
|
||||
public:
|
||||
virtual ~IDataNode() = default;
|
||||
|
||||
// ========================================
|
||||
// TREE NAVIGATION
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get direct child by name
|
||||
* @param name Exact name of the child
|
||||
* @return Child node or nullptr if not found
|
||||
*/
|
||||
virtual std::unique_ptr<IDataNode> getChild(const std::string& name) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get names of all direct children
|
||||
* @return Vector of child names
|
||||
*/
|
||||
virtual std::vector<std::string> getChildNames() = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if this node has any children
|
||||
* @return true if children exist
|
||||
*/
|
||||
virtual bool hasChildren() = 0;
|
||||
|
||||
// ========================================
|
||||
// EXACT SEARCH IN CHILDREN
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Find all children with exact name (direct children only)
|
||||
* @param name Exact name to search for
|
||||
* @return Vector of matching child nodes
|
||||
*/
|
||||
virtual std::vector<IDataNode*> getChildrenByName(const std::string& name) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if any children have the exact name
|
||||
* @param name Exact name to search for
|
||||
* @return true if found
|
||||
*/
|
||||
virtual bool hasChildrenByName(const std::string& name) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get first child with exact name
|
||||
* @param name Exact name to search for
|
||||
* @return First matching child or nullptr
|
||||
*/
|
||||
virtual IDataNode* getFirstChildByName(const std::string& name) = 0;
|
||||
|
||||
// ========================================
|
||||
// PATTERN MATCHING SEARCH (DEEP SEARCH IN WHOLE SUBTREE)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Find all nodes in subtree matching pattern
|
||||
* @param pattern Pattern with wildcards (* supported)
|
||||
* @return Vector of matching nodes in entire subtree
|
||||
*
|
||||
* Examples:
|
||||
* - "component*" matches "component_armor", "component_engine"
|
||||
* - "*heavy*" matches "tank_heavy_mk1", "artillery_heavy"
|
||||
* - "model_*" matches "model_01", "model_02"
|
||||
*/
|
||||
virtual std::vector<IDataNode*> getChildrenByNameMatch(const std::string& pattern) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if any nodes in subtree match pattern
|
||||
* @param pattern Pattern with wildcards
|
||||
* @return true if any matches found
|
||||
*/
|
||||
virtual bool hasChildrenByNameMatch(const std::string& pattern) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get first node in subtree matching pattern
|
||||
* @param pattern Pattern with wildcards
|
||||
* @return First matching node or nullptr
|
||||
*/
|
||||
virtual IDataNode* getFirstChildByNameMatch(const std::string& pattern) = 0;
|
||||
|
||||
// ========================================
|
||||
// QUERY BY PROPERTIES
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Query nodes in subtree by property value
|
||||
* @param propName Property name to check
|
||||
* @param predicate Function to test property value
|
||||
* @return Vector of nodes where predicate returns true
|
||||
*
|
||||
* Example:
|
||||
* // Find all tanks with armor > 150
|
||||
* queryByProperty("armor", [](const json& val) {
|
||||
* return val.is_number() && val.get<int>() > 150;
|
||||
* });
|
||||
*/
|
||||
virtual std::vector<IDataNode*> queryByProperty(const std::string& propName,
|
||||
const std::function<bool(const json&)>& predicate) = 0;
|
||||
|
||||
// ========================================
|
||||
// NODE'S OWN DATA
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get this node's data blob
|
||||
* @return JSON data or empty JSON if no data
|
||||
*/
|
||||
virtual json getData() = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if this node has data
|
||||
* @return true if data exists
|
||||
*/
|
||||
virtual bool hasData() = 0;
|
||||
|
||||
/**
|
||||
* @brief Set this node's data
|
||||
* @param data JSON data to set
|
||||
*/
|
||||
virtual void setData(const json& data) = 0;
|
||||
|
||||
// ========================================
|
||||
// TYPED DATA ACCESS BY PROPERTY NAME
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get string property from this node's data
|
||||
* @param name Property name
|
||||
* @param defaultValue Default if property not found or wrong type
|
||||
* @return Property value or default
|
||||
*/
|
||||
virtual std::string getString(const std::string& name, const std::string& defaultValue = "") = 0;
|
||||
|
||||
/**
|
||||
* @brief Get integer property from this node's data
|
||||
* @param name Property name
|
||||
* @param defaultValue Default if property not found or wrong type
|
||||
* @return Property value or default
|
||||
*/
|
||||
virtual int getInt(const std::string& name, int defaultValue = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get double property from this node's data
|
||||
* @param name Property name
|
||||
* @param defaultValue Default if property not found or wrong type
|
||||
* @return Property value or default
|
||||
*/
|
||||
virtual double getDouble(const std::string& name, double defaultValue = 0.0) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get boolean property from this node's data
|
||||
* @param name Property name
|
||||
* @param defaultValue Default if property not found or wrong type
|
||||
* @return Property value or default
|
||||
*/
|
||||
virtual bool getBool(const std::string& name, bool defaultValue = false) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if property exists in this node's data
|
||||
* @param name Property name
|
||||
* @return true if property exists
|
||||
*/
|
||||
virtual bool hasProperty(const std::string& name) = 0;
|
||||
|
||||
// ========================================
|
||||
// HASH SYSTEM FOR VALIDATION & SYNCHRO
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get hash of this node's data only
|
||||
* @return SHA256 hash of data blob
|
||||
*/
|
||||
virtual std::string getDataHash() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get recursive hash of this node and all children
|
||||
* @return SHA256 hash of entire subtree
|
||||
*/
|
||||
virtual std::string getTreeHash() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get hash of specific child subtree
|
||||
* @param childPath Path to child from this node
|
||||
* @return SHA256 hash of child subtree
|
||||
*/
|
||||
virtual std::string getSubtreeHash(const std::string& childPath) = 0;
|
||||
|
||||
// ========================================
|
||||
// METADATA
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get full path from root to this node
|
||||
* @return Path string (e.g., "vehicles/tanks/heavy/model5")
|
||||
*/
|
||||
virtual std::string getPath() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get this node's name
|
||||
* @return Node name
|
||||
*/
|
||||
virtual std::string getName() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get node type (extensible for templates/inheritance later)
|
||||
* @return Node type identifier
|
||||
*/
|
||||
virtual std::string getNodeType() = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "IDataNode.h"
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
/**
|
||||
* @brief Interface for the root data tree container
|
||||
*
|
||||
* Manages the entire tree structure and provides hot-reload capabilities
|
||||
*/
|
||||
class IDataTree {
|
||||
public:
|
||||
virtual ~IDataTree() = default;
|
||||
|
||||
// ========================================
|
||||
// TREE ACCESS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get root node of the tree
|
||||
* @return Root node
|
||||
*/
|
||||
virtual std::unique_ptr<IDataNode> getRoot() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get node by path from root
|
||||
* @param path Path from root (e.g., "vehicles/tanks/heavy")
|
||||
* @return Node at path or nullptr if not found
|
||||
*/
|
||||
virtual std::unique_ptr<IDataNode> getNode(const std::string& path) = 0;
|
||||
|
||||
// ========================================
|
||||
// MANUAL HOT-RELOAD (SIMPLE & EFFECTIVE)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Check if source files have changed
|
||||
* @return true if changes detected
|
||||
*/
|
||||
virtual bool checkForChanges() = 0;
|
||||
|
||||
/**
|
||||
* @brief Reload entire tree if changes detected
|
||||
* @return true if reload was performed
|
||||
*/
|
||||
virtual bool reloadIfChanged() = 0;
|
||||
|
||||
/**
|
||||
* @brief Register callback for when tree is reloaded
|
||||
* @param callback Function called after successful reload
|
||||
*/
|
||||
virtual void onTreeReloaded(std::function<void()> callback) = 0;
|
||||
|
||||
// ========================================
|
||||
// METADATA
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get tree implementation type
|
||||
* @return Type identifier (e.g., "JSONDataTree", "DatabaseDataTree")
|
||||
*/
|
||||
virtual std::string getType() = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,129 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/**
|
||||
* @brief Pure Generic UI Interface - Zero assumptions about content
|
||||
*
|
||||
* Completely data-agnostic. Implementation decides how to handle each data type.
|
||||
*/
|
||||
class IUI {
|
||||
public:
|
||||
virtual ~IUI() = default;
|
||||
|
||||
// ========================================
|
||||
// LIFECYCLE
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Initialize UI system
|
||||
* @param config Generic config, implementation interprets
|
||||
*/
|
||||
virtual void initialize(const json& config) = 0;
|
||||
|
||||
/**
|
||||
* @brief Update/render one frame
|
||||
* @return true to continue, false to quit
|
||||
*/
|
||||
virtual bool update() = 0;
|
||||
|
||||
/**
|
||||
* @brief Clean shutdown
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
// ========================================
|
||||
// GENERIC DATA FLOW
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Display any data of any type with layout/windowing info
|
||||
* @param dataType "economy", "map", "inventory", "status", whatever
|
||||
* @param data JSON with content + layout:
|
||||
* {
|
||||
* "content": {...}, // Actual data to display
|
||||
* "window": { // Window/layout configuration
|
||||
* "id": "economy_main", // Unique window ID
|
||||
* "title": "Economy Dashboard",
|
||||
* "parent": "main_dock", // Parent window/dock ID (optional)
|
||||
* "dock": "left", // Dock position: "left", "right", "top", "bottom", "center", "tab"
|
||||
* "size": {"width": 400, "height": 300},
|
||||
* "position": {"x": 100, "y": 50},
|
||||
* "floating": false, // true = floating window, false = docked
|
||||
* "resizable": true,
|
||||
* "closeable": true
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
virtual void showData(const std::string& dataType, const json& data) = 0;
|
||||
|
||||
/**
|
||||
* @brief Handle any user request of any type
|
||||
* @param requestType "get_prices", "move_unit", "save_game", whatever
|
||||
* @param callback Function to call when request happens
|
||||
*/
|
||||
virtual void onRequest(const std::string& requestType, std::function<void(const json&)> callback) = 0;
|
||||
|
||||
/**
|
||||
* @brief Show any event/message
|
||||
* @param level "info", "error", "debug", whatever
|
||||
* @param message Human readable text
|
||||
*/
|
||||
virtual void showEvent(const std::string& level, const std::string& message) = 0;
|
||||
|
||||
// ========================================
|
||||
// WINDOW MANAGEMENT
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Create or configure a dock/container window
|
||||
* @param dockId Unique dock identifier
|
||||
* @param config Dock configuration:
|
||||
* {
|
||||
* "type": "dock", // "dock", "tabbed", "split"
|
||||
* "orientation": "horizontal", // "horizontal", "vertical" (for splits)
|
||||
* "parent": "main_window", // Parent dock (for nested docks)
|
||||
* "position": "left", // Initial position
|
||||
* "size": {"width": 300}, // Initial size
|
||||
* "collapsible": true, // Can be collapsed
|
||||
* "tabs": true // Enable tabbed interface
|
||||
* }
|
||||
*/
|
||||
virtual void createDock(const std::string& dockId, const json& config) = 0;
|
||||
|
||||
/**
|
||||
* @brief Close/remove window or dock
|
||||
* @param windowId Window or dock ID to close
|
||||
*/
|
||||
virtual void closeWindow(const std::string& windowId) = 0;
|
||||
|
||||
/**
|
||||
* @brief Focus/bring to front a specific window
|
||||
* @param windowId Window ID to focus
|
||||
*/
|
||||
virtual void focusWindow(const std::string& windowId) = 0;
|
||||
|
||||
// ========================================
|
||||
// GENERIC STATE
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get current UI state
|
||||
* @return JSON state, implementation defines structure
|
||||
*/
|
||||
virtual json getState() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Restore UI state
|
||||
* @param state JSON state from previous getState()
|
||||
*/
|
||||
virtual void setState(const json& state) = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,340 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// ========================================
|
||||
// ENUMS FOR TYPE SAFETY
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Data types for UI display
|
||||
*/
|
||||
enum class DataType {
|
||||
ECONOMY,
|
||||
MAP,
|
||||
INVENTORY,
|
||||
CONSOLE,
|
||||
PERFORMANCE,
|
||||
COMPANIES,
|
||||
ALERTS,
|
||||
PRODUCTION,
|
||||
LOGISTICS,
|
||||
PLAYER,
|
||||
SETTINGS,
|
||||
DEBUG,
|
||||
CUSTOM // For extending with string fallback
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Request types from UI
|
||||
*/
|
||||
enum class RequestType {
|
||||
GET_PRICES,
|
||||
GET_CHUNK,
|
||||
MOVE_PLAYER,
|
||||
SAVE_GAME,
|
||||
LOAD_GAME,
|
||||
CLOSE_WINDOW,
|
||||
FOCUS_WINDOW,
|
||||
UPDATE_SETTINGS,
|
||||
EXECUTE_COMMAND,
|
||||
CUSTOM // For extending with string fallback
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event/message levels
|
||||
*/
|
||||
enum class EventLevel {
|
||||
INFO,
|
||||
SUCCESS,
|
||||
WARNING,
|
||||
ERROR,
|
||||
DEBUG,
|
||||
TRACE
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Dock types for window management
|
||||
*/
|
||||
enum class DockType {
|
||||
DOCK, // Standard dockable panel
|
||||
SPLIT, // Horizontal/vertical split
|
||||
TABBED, // Tabbed container
|
||||
FLOATING // Floating window
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Dock positions
|
||||
*/
|
||||
enum class DockPosition {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
TOP,
|
||||
BOTTOM,
|
||||
CENTER,
|
||||
TAB // Add as tab to parent
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Split orientations
|
||||
*/
|
||||
enum class Orientation {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Pure Generic UI Interface - Type-safe with enums
|
||||
*/
|
||||
class IUI {
|
||||
public:
|
||||
virtual ~IUI() = default;
|
||||
|
||||
// ========================================
|
||||
// LIFECYCLE
|
||||
// ========================================
|
||||
|
||||
virtual void initialize(const json& config) = 0;
|
||||
virtual bool update() = 0;
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
// ========================================
|
||||
// GENERIC DATA FLOW - ENUM VERSIONS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Display data with type-safe enum
|
||||
* @param dataType Enum data type
|
||||
* @param data JSON with content + optional window config:
|
||||
* {
|
||||
* "content": {...}, // Actual data to display
|
||||
* "window": { // Window configuration (optional)
|
||||
* "id": "window_id",
|
||||
* "title": "Window Title",
|
||||
* "parent": "parent_dock_id",
|
||||
* "dock": "left|right|top|bottom|center|tab",
|
||||
*
|
||||
* // SIZE SYSTEM - Hybrid percentage + absolute constraints
|
||||
* "size": {"width": "20%", "height": 300}, // Target: 20% of parent width, 300px height
|
||||
* "size": {"width": 400, "height": "50%"}, // Target: 400px width, 50% of parent height
|
||||
* "size": {"width": "30%", "height": "40%"}, // Target: 30% width, 40% height
|
||||
*
|
||||
* "min_size": {"width": 200, "height": 150}, // ABSOLUTE minimum in pixels (always respected)
|
||||
* "max_size": {"width": 800, "height": "80%"}, // Maximum: 800px width OR 80% of parent (whichever smaller)
|
||||
*
|
||||
* "position": {"x": 100, "y": 50},
|
||||
* "floating": false,
|
||||
* "resizable": true,
|
||||
* "closeable": true,
|
||||
* "collapsible": false
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
virtual void showData(DataType dataType, const json& data) = 0;
|
||||
|
||||
/**
|
||||
* @brief Display custom data type (fallback to string)
|
||||
* @param customType Custom data type name
|
||||
* @param data JSON data
|
||||
*/
|
||||
virtual void showDataCustom(const std::string& customType, const json& data) = 0;
|
||||
|
||||
/**
|
||||
* @brief Handle user request with type-safe enum
|
||||
* @param requestType Enum request type
|
||||
* @param callback Function to call when request happens
|
||||
*/
|
||||
virtual void onRequest(RequestType requestType, std::function<void(const json&)> callback) = 0;
|
||||
|
||||
/**
|
||||
* @brief Handle custom request type (fallback to string)
|
||||
* @param customType Custom request type name
|
||||
* @param callback Function to call when request happens
|
||||
*/
|
||||
virtual void onRequestCustom(const std::string& customType, std::function<void(const json&)> callback) = 0;
|
||||
|
||||
/**
|
||||
* @brief Show event with type-safe level
|
||||
* @param level Event level enum
|
||||
* @param message Human readable text
|
||||
*/
|
||||
virtual void showEvent(EventLevel level, const std::string& message) = 0;
|
||||
|
||||
// ========================================
|
||||
// WINDOW MANAGEMENT - ENUM VERSIONS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Create dock with type-safe enums
|
||||
* @param dockId Unique dock identifier
|
||||
* @param type Dock type enum
|
||||
* @param position Dock position enum
|
||||
* @param config Additional configuration:
|
||||
* {
|
||||
* "parent": "parent_dock_id", // Parent dock (optional)
|
||||
*
|
||||
* // HYBRID SIZE SYSTEM
|
||||
* "size": {"width": "25%", "height": 200}, // Target: 25% of parent width, 200px height
|
||||
* "min_size": {"width": 200, "height": 100}, // ABSOLUTE minimum pixels (overrides percentage)
|
||||
* "max_size": {"width": "50%", "height": 600}, // Maximum: 50% of parent OR 600px (whichever smaller)
|
||||
*
|
||||
* "orientation": "horizontal", // For SPLIT type
|
||||
* "collapsible": true, // Can be collapsed
|
||||
* "resizable": true, // Can be resized
|
||||
* "tabs": true // Enable tabbed interface
|
||||
* }
|
||||
*/
|
||||
virtual void createDock(const std::string& dockId, DockType type, DockPosition position, const json& config = {}) = 0;
|
||||
|
||||
/**
|
||||
* @brief Create split dock with orientation
|
||||
* @param dockId Unique dock identifier
|
||||
* @param orientation Split orientation
|
||||
* @param config Additional configuration:
|
||||
* {
|
||||
* "parent": "parent_dock_id", // Parent dock (optional)
|
||||
* "size": {"width": 300, "height": 200}, // Initial size
|
||||
* "min_size": {"width": 100, "height": 50}, // Minimum split size in pixels
|
||||
* "max_size": {"width": 1000, "height": 800}, // Maximum split size in pixels
|
||||
* "split_ratio": 0.5, // Split ratio (0.0 to 1.0)
|
||||
* "min_panel_size": 80, // Minimum size for each panel in split
|
||||
* "resizable": true // Can be resized by dragging splitter
|
||||
* }
|
||||
*/
|
||||
virtual void createSplit(const std::string& dockId, Orientation orientation, const json& config = {}) = 0;
|
||||
|
||||
/**
|
||||
* @brief Close window or dock
|
||||
* @param windowId Window/dock ID to close
|
||||
*/
|
||||
virtual void closeWindow(const std::string& windowId) = 0;
|
||||
|
||||
/**
|
||||
* @brief Focus window
|
||||
* @param windowId Window ID to focus
|
||||
*/
|
||||
virtual void focusWindow(const std::string& windowId) = 0;
|
||||
|
||||
// ========================================
|
||||
// GENERIC STATE
|
||||
// ========================================
|
||||
|
||||
virtual json getState() const = 0;
|
||||
virtual void setState(const json& state) = 0;
|
||||
|
||||
// ========================================
|
||||
// CONVENIENCE METHODS WITH ENUMS
|
||||
// ========================================
|
||||
|
||||
void info(const std::string& message) {
|
||||
showEvent(EventLevel::INFO, message);
|
||||
}
|
||||
|
||||
void success(const std::string& message) {
|
||||
showEvent(EventLevel::SUCCESS, message);
|
||||
}
|
||||
|
||||
void warning(const std::string& message) {
|
||||
showEvent(EventLevel::WARNING, message);
|
||||
}
|
||||
|
||||
void error(const std::string& message) {
|
||||
showEvent(EventLevel::ERROR, message);
|
||||
}
|
||||
|
||||
void debug(const std::string& message) {
|
||||
showEvent(EventLevel::DEBUG, message);
|
||||
}
|
||||
};
|
||||
|
||||
// ========================================
|
||||
// ENUM TO STRING CONVERSIONS (for implementations)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Convert DataType enum to string (for implementations that need strings)
|
||||
*/
|
||||
constexpr const char* toString(DataType type) {
|
||||
switch (type) {
|
||||
case DataType::ECONOMY: return "economy";
|
||||
case DataType::MAP: return "map";
|
||||
case DataType::INVENTORY: return "inventory";
|
||||
case DataType::CONSOLE: return "console";
|
||||
case DataType::PERFORMANCE: return "performance";
|
||||
case DataType::COMPANIES: return "companies";
|
||||
case DataType::ALERTS: return "alerts";
|
||||
case DataType::PRODUCTION: return "production";
|
||||
case DataType::LOGISTICS: return "logistics";
|
||||
case DataType::PLAYER: return "player";
|
||||
case DataType::SETTINGS: return "settings";
|
||||
case DataType::DEBUG: return "debug";
|
||||
case DataType::CUSTOM: return "custom";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char* toString(RequestType type) {
|
||||
switch (type) {
|
||||
case RequestType::GET_PRICES: return "get_prices";
|
||||
case RequestType::GET_CHUNK: return "get_chunk";
|
||||
case RequestType::MOVE_PLAYER: return "move_player";
|
||||
case RequestType::SAVE_GAME: return "save_game";
|
||||
case RequestType::LOAD_GAME: return "load_game";
|
||||
case RequestType::CLOSE_WINDOW: return "close_window";
|
||||
case RequestType::FOCUS_WINDOW: return "focus_window";
|
||||
case RequestType::UPDATE_SETTINGS: return "update_settings";
|
||||
case RequestType::EXECUTE_COMMAND: return "execute_command";
|
||||
case RequestType::CUSTOM: return "custom";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char* toString(EventLevel level) {
|
||||
switch (level) {
|
||||
case EventLevel::INFO: return "info";
|
||||
case EventLevel::SUCCESS: return "success";
|
||||
case EventLevel::WARNING: return "warning";
|
||||
case EventLevel::ERROR: return "error";
|
||||
case EventLevel::DEBUG: return "debug";
|
||||
case EventLevel::TRACE: return "trace";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char* toString(DockType type) {
|
||||
switch (type) {
|
||||
case DockType::DOCK: return "dock";
|
||||
case DockType::SPLIT: return "split";
|
||||
case DockType::TABBED: return "tabbed";
|
||||
case DockType::FLOATING: return "floating";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char* toString(DockPosition pos) {
|
||||
switch (pos) {
|
||||
case DockPosition::LEFT: return "left";
|
||||
case DockPosition::RIGHT: return "right";
|
||||
case DockPosition::TOP: return "top";
|
||||
case DockPosition::BOTTOM: return "bottom";
|
||||
case DockPosition::CENTER: return "center";
|
||||
case DockPosition::TAB: return "tab";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char* toString(Orientation orient) {
|
||||
switch (orient) {
|
||||
case Orientation::HORIZONTAL: return "horizontal";
|
||||
case Orientation::VERTICAL: return "vertical";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,707 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IUI_Enums.h"
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
/**
|
||||
* @brief ImGui implementation of IUI interface
|
||||
*
|
||||
* Provides full windowing system with docking, tabs, splits, and floating windows.
|
||||
* Handles hybrid percentage + pixel sizing with automatic constraint enforcement.
|
||||
*/
|
||||
class ImGuiUI : public IUI {
|
||||
private:
|
||||
// ========================================
|
||||
// CORE STATE
|
||||
// ========================================
|
||||
|
||||
GLFWwindow* window = nullptr;
|
||||
bool initialized = false;
|
||||
bool should_close = false;
|
||||
int frame_count = 0;
|
||||
|
||||
// Screen/parent sizes for percentage calculations
|
||||
ImVec2 screen_size = {1400, 900};
|
||||
ImVec2 previous_screen_size = {0, 0};
|
||||
|
||||
// ========================================
|
||||
// WINDOW MANAGEMENT
|
||||
// ========================================
|
||||
|
||||
struct WindowInfo {
|
||||
std::string id;
|
||||
std::string title;
|
||||
std::string parent;
|
||||
DockPosition dock_position = DockPosition::CENTER;
|
||||
bool is_open = true;
|
||||
bool is_floating = false;
|
||||
bool resizable = true;
|
||||
bool closeable = true;
|
||||
|
||||
// Size system
|
||||
ImVec2 size = {400, 300};
|
||||
ImVec2 min_size = {100, 100};
|
||||
ImVec2 max_size = {2000, 1500};
|
||||
ImVec2 position = {0, 0};
|
||||
|
||||
// Percentage tracking
|
||||
std::string size_width_percent = "";
|
||||
std::string size_height_percent = "";
|
||||
std::string min_width_percent = "";
|
||||
std::string min_height_percent = "";
|
||||
std::string max_width_percent = "";
|
||||
std::string max_height_percent = "";
|
||||
|
||||
// Content
|
||||
DataType data_type = DataType::CUSTOM;
|
||||
json content_data;
|
||||
};
|
||||
|
||||
std::map<std::string, WindowInfo> windows;
|
||||
|
||||
struct DockInfo {
|
||||
std::string id;
|
||||
DockType type = DockType::DOCK;
|
||||
DockPosition position = DockPosition::LEFT;
|
||||
std::string parent;
|
||||
bool collapsible = true;
|
||||
bool resizable = true;
|
||||
ImVec2 size = {300, 200};
|
||||
ImVec2 min_size = {100, 100};
|
||||
ImVec2 max_size = {1000, 800};
|
||||
std::vector<std::string> child_windows;
|
||||
};
|
||||
|
||||
std::map<std::string, DockInfo> docks;
|
||||
|
||||
// ========================================
|
||||
// CALLBACKS
|
||||
// ========================================
|
||||
|
||||
std::map<RequestType, std::function<void(const json&)>> request_callbacks;
|
||||
std::map<std::string, std::function<void(const json&)>> custom_request_callbacks;
|
||||
|
||||
// ========================================
|
||||
// MESSAGE SYSTEM
|
||||
// ========================================
|
||||
|
||||
struct LogMessage {
|
||||
EventLevel level;
|
||||
std::string message;
|
||||
std::chrono::steady_clock::time_point timestamp;
|
||||
};
|
||||
|
||||
std::vector<LogMessage> log_messages;
|
||||
static constexpr size_t MAX_LOG_MESSAGES = 100;
|
||||
|
||||
public:
|
||||
ImGuiUI() = default;
|
||||
~ImGuiUI() override { shutdown(); }
|
||||
|
||||
// ========================================
|
||||
// LIFECYCLE IMPLEMENTATION
|
||||
// ========================================
|
||||
|
||||
void initialize(const json& config) override {
|
||||
if (initialized) return;
|
||||
|
||||
// Initialize GLFW
|
||||
if (!glfwInit()) {
|
||||
throw std::runtime_error("Failed to initialize GLFW");
|
||||
}
|
||||
|
||||
// OpenGL 3.3 Core
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
// Create window
|
||||
std::string title = config.value("title", "Warfactory ImGui UI");
|
||||
auto window_size = config.value("window_size", json{{"width", 1400}, {"height", 900}});
|
||||
if (window_size.is_object()) {
|
||||
screen_size.x = window_size.value("width", 1400);
|
||||
screen_size.y = window_size.value("height", 900);
|
||||
} else {
|
||||
screen_size.x = 1400;
|
||||
screen_size.y = 900;
|
||||
}
|
||||
|
||||
window = glfwCreateWindow(
|
||||
static_cast<int>(screen_size.x),
|
||||
static_cast<int>(screen_size.y),
|
||||
title.c_str(), nullptr, nullptr
|
||||
);
|
||||
|
||||
if (!window) {
|
||||
glfwTerminate();
|
||||
throw std::runtime_error("Failed to create GLFW window");
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1); // VSync
|
||||
|
||||
// Initialize ImGui
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
// Note: Docking features depend on ImGui docking branch
|
||||
// Using manual docking simulation for compatibility
|
||||
|
||||
// Basic style setup
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
// Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 330 core");
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
bool update() override {
|
||||
if (!initialized || !window) return false;
|
||||
|
||||
if (glfwWindowShouldClose(window)) {
|
||||
should_close = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update screen size for percentage calculations
|
||||
int fb_width, fb_height;
|
||||
glfwGetFramebufferSize(window, &fb_width, &fb_height);
|
||||
ImVec2 new_screen_size = {static_cast<float>(fb_width), static_cast<float>(fb_height)};
|
||||
|
||||
// Detect screen size changes and recalculate if needed
|
||||
if (new_screen_size.x != previous_screen_size.x || new_screen_size.y != previous_screen_size.y) {
|
||||
if (frame_count > 0) { // Skip first frame (initialization)
|
||||
debug("🔄 Screen size changed: " + std::to_string((int)new_screen_size.x) + "x" + std::to_string((int)new_screen_size.y));
|
||||
recalculateAllSizes();
|
||||
}
|
||||
previous_screen_size = screen_size;
|
||||
}
|
||||
screen_size = new_screen_size;
|
||||
|
||||
frame_count++;
|
||||
|
||||
// Poll events
|
||||
glfwPollEvents();
|
||||
|
||||
// Start ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
// Render all windows
|
||||
renderAllWindows();
|
||||
|
||||
// Render ImGui
|
||||
ImGui::Render();
|
||||
|
||||
// OpenGL rendering
|
||||
glViewport(0, 0, static_cast<int>(screen_size.x), static_cast<int>(screen_size.y));
|
||||
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
return !should_close;
|
||||
}
|
||||
|
||||
void shutdown() override {
|
||||
if (!initialized) return;
|
||||
|
||||
if (window) {
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
window = nullptr;
|
||||
}
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
private:
|
||||
// ========================================
|
||||
// SIZE CALCULATION HELPERS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Parse size value - handles both pixels and percentages
|
||||
*/
|
||||
float parseSize(const json& size_value, float parent_size, float default_size) {
|
||||
try {
|
||||
if (size_value.is_number()) {
|
||||
return size_value.get<float>();
|
||||
}
|
||||
|
||||
if (size_value.is_string()) {
|
||||
std::string size_str = size_value.get<std::string>();
|
||||
if (!size_str.empty() && size_str.back() == '%') {
|
||||
float percent = std::stof(size_str.substr(0, size_str.length() - 1));
|
||||
return (percent / 100.0f) * parent_size;
|
||||
} else {
|
||||
// String but not percentage - try to parse as number
|
||||
return std::stof(size_str);
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
// Any JSON or parsing error - return default
|
||||
}
|
||||
|
||||
// Neither number nor string or error - return default
|
||||
return default_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate effective size with hybrid constraints
|
||||
*/
|
||||
ImVec2 calculateEffectiveSize(const WindowInfo& win, ImVec2 parent_size) {
|
||||
// Use already parsed sizes (converted in showData)
|
||||
float target_width = win.size.x;
|
||||
float target_height = win.size.y;
|
||||
|
||||
// Calculate constraint bounds
|
||||
float min_width = win.min_size.x;
|
||||
float min_height = win.min_size.y;
|
||||
float max_width = win.max_size.x;
|
||||
float max_height = win.max_size.y;
|
||||
|
||||
// Apply constraints (clamp)
|
||||
float final_width = std::max(min_width, std::min(target_width, max_width));
|
||||
float final_height = std::max(min_height, std::min(target_height, max_height));
|
||||
|
||||
return {final_width, final_height};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate window position based on docking
|
||||
*/
|
||||
ImVec2 calculateDockedPosition(const WindowInfo& win, ImVec2 size) {
|
||||
if (win.parent.empty() || win.is_floating) {
|
||||
// For windows without parent, use explicit position or calculate smart default
|
||||
debug("🔍 Checking position for '" + win.id + "': pos=" +
|
||||
std::to_string(win.position.x) + "," + std::to_string(win.position.y) +
|
||||
" floating=" + (win.is_floating ? "true" : "false"));
|
||||
|
||||
// Only use explicit position if it was actually set by user (not just default values)
|
||||
if (win.position.x > 10 && win.position.y > 10) {
|
||||
debug("📌 Using explicit position for '" + win.id + "'");
|
||||
return win.position; // Use explicit position
|
||||
} else {
|
||||
// Simple approach: use actual window sizes from economy_main window
|
||||
float left_edge_end = 252; // Real end of economy_main (we know it's 252px wide)
|
||||
float top_edge_end = 88; // Real end of toolbar + margin
|
||||
|
||||
// Find the right sidebar start by looking for info_panel_main
|
||||
float right_edge_start = 1050; // We know info_panel starts at 1050px
|
||||
|
||||
debug("🔧 Simple positioning for window '" + win.id + "': left_end=" +
|
||||
std::to_string(left_edge_end) + "px, right_start=" +
|
||||
std::to_string(right_edge_start) + "px, top_end=" +
|
||||
std::to_string(top_edge_end) + "px");
|
||||
|
||||
// Position directly against the real edge of existing windows
|
||||
float x = left_edge_end; // Directly touching end of left sidebar (252px)
|
||||
float y = top_edge_end; // Directly below toolbar (88px)
|
||||
|
||||
// If window would overlap with right sidebar, push it left to touch right edge
|
||||
if (x + size.x > right_edge_start) {
|
||||
x = right_edge_start - size.x; // Touch right sidebar windows
|
||||
}
|
||||
|
||||
debug("🎯 Calculated position for '" + win.id + "': " +
|
||||
std::to_string(x) + "," + std::to_string(y) +
|
||||
" (touching real window edges)");
|
||||
|
||||
return {x, y};
|
||||
}
|
||||
}
|
||||
|
||||
// Find parent dock
|
||||
auto dock_it = docks.find(win.parent);
|
||||
if (dock_it == docks.end()) {
|
||||
return {0, 0}; // Parent dock not found
|
||||
}
|
||||
|
||||
const DockInfo& dock = dock_it->second;
|
||||
|
||||
// Calculate dock area based on position
|
||||
switch (dock.position) {
|
||||
case DockPosition::LEFT:
|
||||
return {0, 80}; // Left edge but below toolbar (72px + margin)
|
||||
case DockPosition::RIGHT:
|
||||
return {screen_size.x - dock.size.x, 80}; // Right edge but below toolbar
|
||||
case DockPosition::TOP:
|
||||
// Top edge - if dock spans full width, start at 0, else offset
|
||||
if (dock.size.x >= screen_size.x * 0.9f) {
|
||||
return {0, 0}; // Full width toolbar starts at screen edge
|
||||
} else {
|
||||
return {280, 0}; // Partial width toolbar starts after sidebar
|
||||
}
|
||||
case DockPosition::BOTTOM:
|
||||
return {0, screen_size.y - dock.size.y}; // Bottom edge
|
||||
case DockPosition::CENTER:
|
||||
default:
|
||||
return {screen_size.x * 0.5f - size.x * 0.5f, screen_size.y * 0.5f - size.y * 0.5f}; // Center
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// RECALCULATION METHODS
|
||||
// ========================================
|
||||
|
||||
void recalculateAllSizes() {
|
||||
// Recalculate dock sizes
|
||||
for (auto& [dock_id, dock] : docks) {
|
||||
// Recalculate dock size if it uses percentages
|
||||
recalculateDockSize(dock);
|
||||
}
|
||||
|
||||
// Recalculate window sizes
|
||||
for (auto& [window_id, win] : windows) {
|
||||
recalculateWindowSize(win);
|
||||
}
|
||||
}
|
||||
|
||||
void recalculateDockSize(DockInfo& dock) {
|
||||
// Re-parse dock size with new screen size
|
||||
// This would need the original JSON config, for now just log
|
||||
debug("📐 Recalculating dock: " + dock.id);
|
||||
// TODO: Store original percentage strings to recalculate properly
|
||||
}
|
||||
|
||||
void recalculateWindowSize(WindowInfo& win) {
|
||||
// Re-parse window size with new screen/parent sizes
|
||||
debug("📐 Recalculating window: " + win.id);
|
||||
|
||||
// Recalculate width if percentage
|
||||
if (!win.size_width_percent.empty()) {
|
||||
float parent_width = screen_size.x;
|
||||
if (!win.parent.empty() && docks.find(win.parent) != docks.end()) {
|
||||
parent_width = docks[win.parent].size.x;
|
||||
}
|
||||
win.size.x = parseSize(win.size_width_percent, parent_width, 400);
|
||||
}
|
||||
|
||||
// Recalculate height if percentage
|
||||
if (!win.size_height_percent.empty()) {
|
||||
float parent_height = screen_size.y;
|
||||
if (!win.parent.empty() && docks.find(win.parent) != docks.end()) {
|
||||
parent_height = docks[win.parent].size.y;
|
||||
}
|
||||
win.size.y = parseSize(win.size_height_percent, parent_height, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// RENDERING IMPLEMENTATION
|
||||
// ========================================
|
||||
|
||||
void renderAllWindows() {
|
||||
// Log screen size for debugging (only first frame to avoid spam)
|
||||
if (frame_count == 1) {
|
||||
debug("🖥️ Screen Size: " + std::to_string((int)screen_size.x) + "x" + std::to_string((int)screen_size.y) + "px");
|
||||
info("🏗️ Manual docking system active (simulated docking layout)");
|
||||
}
|
||||
|
||||
for (auto& [window_id, win] : windows) {
|
||||
if (!win.is_open) continue;
|
||||
|
||||
if (frame_count <= 5) { // Log first 5 frames for each window
|
||||
debug("🪟 Window: " + window_id + " (" + win.title + ")");
|
||||
debug(" 📐 Target Size: " + std::to_string((int)win.size.x) + "x" + std::to_string((int)win.size.y) + "px");
|
||||
debug(" 📏 Size %: width='" + win.size_width_percent + "' height='" + win.size_height_percent + "'");
|
||||
debug(" ⚖️ Constraints: min=" + std::to_string((int)win.min_size.x) + "x" + std::to_string((int)win.min_size.y) +
|
||||
" max=" + std::to_string((int)win.max_size.x) + "x" + std::to_string((int)win.max_size.y));
|
||||
debug(" 🔗 Docking: parent='" + win.parent + "' position=" + std::to_string((int)win.dock_position));
|
||||
}
|
||||
|
||||
// Calculate effective size with constraints
|
||||
ImVec2 effective_size = calculateEffectiveSize(win, screen_size);
|
||||
if (frame_count <= 5) {
|
||||
debug(" ✅ Effective Size: " + std::to_string((int)effective_size.x) + "x" + std::to_string((int)effective_size.y) + "px");
|
||||
}
|
||||
|
||||
// Set window constraints
|
||||
ImGui::SetNextWindowSizeConstraints(win.min_size, win.max_size);
|
||||
|
||||
// Set window size
|
||||
if (win.is_floating) {
|
||||
// For floating windows, force initial size and position
|
||||
ImGuiCond size_condition = (frame_count <= 3) ? ImGuiCond_Always : ImGuiCond_FirstUseEver;
|
||||
ImGui::SetNextWindowSize(effective_size, size_condition);
|
||||
|
||||
// Calculate smart position that avoids dock overlaps
|
||||
ImVec2 floating_position = calculateDockedPosition(win, effective_size);
|
||||
ImGuiCond position_condition = (frame_count <= 3) ? ImGuiCond_Always : ImGuiCond_FirstUseEver;
|
||||
ImGui::SetNextWindowPos(floating_position, position_condition);
|
||||
|
||||
if (frame_count <= 5) {
|
||||
debug(" 🎈 Floating Position: " + std::to_string((int)floating_position.x) + "," + std::to_string((int)floating_position.y));
|
||||
}
|
||||
} else {
|
||||
// For docked windows, calculate position and force it during initial frames
|
||||
ImVec2 dock_position = calculateDockedPosition(win, effective_size);
|
||||
|
||||
ImGuiCond condition = (frame_count <= 3) ? ImGuiCond_Always : ImGuiCond_FirstUseEver;
|
||||
ImGui::SetNextWindowSize(effective_size, condition);
|
||||
ImGui::SetNextWindowPos(dock_position, condition);
|
||||
|
||||
if (frame_count <= 5) {
|
||||
debug(" 📍 Docked Position: " + std::to_string((int)dock_position.x) + "," + std::to_string((int)dock_position.y));
|
||||
}
|
||||
}
|
||||
|
||||
// Window flags
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_None;
|
||||
if (!win.resizable) flags |= ImGuiWindowFlags_NoResize;
|
||||
|
||||
// Render window
|
||||
if (ImGui::Begin(win.title.c_str(), win.closeable ? &win.is_open : nullptr, flags)) {
|
||||
// Log actual ImGui window size after rendering (first 5 frames only)
|
||||
if (frame_count <= 5) {
|
||||
ImVec2 current_size = ImGui::GetWindowSize();
|
||||
ImVec2 current_pos = ImGui::GetWindowPos();
|
||||
debug(" 🎯 ImGui Actual: pos=" + std::to_string((int)current_pos.x) + "," + std::to_string((int)current_pos.y) +
|
||||
" size=" + std::to_string((int)current_size.x) + "x" + std::to_string((int)current_size.y) + "px");
|
||||
}
|
||||
|
||||
renderWindowContent(win);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void renderWindowContent(const WindowInfo& win) {
|
||||
switch (win.data_type) {
|
||||
case DataType::ECONOMY:
|
||||
renderEconomyContent(win.content_data);
|
||||
break;
|
||||
case DataType::MAP:
|
||||
renderMapContent(win.content_data);
|
||||
break;
|
||||
case DataType::INVENTORY:
|
||||
renderInventoryContent(win.content_data);
|
||||
break;
|
||||
case DataType::CONSOLE:
|
||||
renderConsoleContent(win.content_data);
|
||||
break;
|
||||
case DataType::PERFORMANCE:
|
||||
renderPerformanceContent(win.content_data);
|
||||
break;
|
||||
case DataType::COMPANIES:
|
||||
renderCompaniesContent(win.content_data);
|
||||
break;
|
||||
case DataType::ALERTS:
|
||||
renderAlertsContent(win.content_data);
|
||||
break;
|
||||
case DataType::SETTINGS:
|
||||
renderSettingsContent(win.content_data);
|
||||
break;
|
||||
default:
|
||||
renderGenericContent(win.content_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// ========================================
|
||||
// IUI INTERFACE IMPLEMENTATION - DATA DISPLAY
|
||||
// ========================================
|
||||
|
||||
void showData(DataType dataType, const json& data) override {
|
||||
// Extract window configuration
|
||||
json window_config = data.value("window", json{});
|
||||
json content = data.value("content", data);
|
||||
|
||||
// Generate ID if not provided
|
||||
std::string window_id = window_config.value("id", "window_" + std::to_string(windows.size()));
|
||||
|
||||
// Create or update window info
|
||||
WindowInfo& win = windows[window_id];
|
||||
win.id = window_id;
|
||||
win.title = window_config.value("title", toString(dataType));
|
||||
win.data_type = dataType;
|
||||
win.content_data = content;
|
||||
win.is_open = true;
|
||||
|
||||
// Parse parent first (needed for size calculations)
|
||||
win.parent = window_config.value("parent", "");
|
||||
|
||||
// Parse size configuration with percentage support
|
||||
if (window_config.contains("size")) {
|
||||
auto size_config = window_config["size"];
|
||||
if (size_config.is_object()) {
|
||||
if (size_config.contains("width")) {
|
||||
auto width_val = size_config["width"];
|
||||
if (width_val.is_string()) {
|
||||
win.size_width_percent = width_val.get<std::string>();
|
||||
debug("🔧 Processing width percentage '" + win.size_width_percent +
|
||||
"' for window '" + win.id + "' with parent='" + win.parent + "'");
|
||||
|
||||
// Calculate parent size for percentage - use dock size if docked
|
||||
float parent_width = screen_size.x;
|
||||
if (!win.parent.empty() && docks.find(win.parent) != docks.end()) {
|
||||
parent_width = docks[win.parent].size.x;
|
||||
debug("🔍 Found parent dock '" + win.parent + "' with width=" +
|
||||
std::to_string((int)parent_width) + "px");
|
||||
} else if (!win.parent.empty()) {
|
||||
debug("❌ Parent dock '" + win.parent + "' not found! Using screen width.");
|
||||
}
|
||||
|
||||
win.size.x = parseSize(width_val, parent_width, 400);
|
||||
} else if (width_val.is_number()) {
|
||||
win.size.x = width_val.get<float>();
|
||||
} else {
|
||||
win.size.x = 400; // Default fallback
|
||||
}
|
||||
}
|
||||
|
||||
if (size_config.contains("height")) {
|
||||
auto height_val = size_config["height"];
|
||||
if (height_val.is_string()) {
|
||||
win.size_height_percent = height_val.get<std::string>();
|
||||
float parent_height = screen_size.y;
|
||||
if (!win.parent.empty() && docks.find(win.parent) != docks.end()) {
|
||||
parent_height = docks[win.parent].size.y;
|
||||
}
|
||||
win.size.y = parseSize(height_val, parent_height, 300);
|
||||
} else if (height_val.is_number()) {
|
||||
win.size.y = height_val.get<float>();
|
||||
} else {
|
||||
win.size.y = 300; // Default fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse constraints
|
||||
if (window_config.contains("min_size")) {
|
||||
auto min_config = window_config["min_size"];
|
||||
if (min_config.is_object()) {
|
||||
if (min_config.contains("width")) {
|
||||
win.min_size.x = parseSize(min_config["width"], screen_size.x, 100);
|
||||
} else {
|
||||
win.min_size.x = 100;
|
||||
}
|
||||
if (min_config.contains("height")) {
|
||||
win.min_size.y = parseSize(min_config["height"], screen_size.y, 100);
|
||||
} else {
|
||||
win.min_size.y = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window_config.contains("max_size")) {
|
||||
auto max_config = window_config["max_size"];
|
||||
if (max_config.is_object()) {
|
||||
if (max_config.contains("width")) {
|
||||
win.max_size.x = parseSize(max_config["width"], screen_size.x, 2000);
|
||||
} else {
|
||||
win.max_size.x = 2000;
|
||||
}
|
||||
if (max_config.contains("height")) {
|
||||
win.max_size.y = parseSize(max_config["height"], screen_size.y, 1500);
|
||||
} else {
|
||||
win.max_size.y = 1500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse other properties
|
||||
win.is_floating = window_config.value("floating", false);
|
||||
win.resizable = window_config.value("resizable", true);
|
||||
win.closeable = window_config.value("closeable", true);
|
||||
|
||||
// Parse dock position if specified
|
||||
if (window_config.contains("dock")) {
|
||||
std::string dock_str = window_config["dock"].get<std::string>();
|
||||
if (dock_str == "left") win.dock_position = DockPosition::LEFT;
|
||||
else if (dock_str == "right") win.dock_position = DockPosition::RIGHT;
|
||||
else if (dock_str == "top") win.dock_position = DockPosition::TOP;
|
||||
else if (dock_str == "bottom") win.dock_position = DockPosition::BOTTOM;
|
||||
else if (dock_str == "tab") win.dock_position = DockPosition::CENTER; // tabs go in center
|
||||
else win.dock_position = DockPosition::CENTER;
|
||||
}
|
||||
|
||||
if (window_config.contains("position")) {
|
||||
auto pos = window_config["position"];
|
||||
if (pos.is_object()) {
|
||||
win.position.x = pos.value("x", 0);
|
||||
win.position.y = pos.value("y", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showDataCustom(const std::string& customType, const json& data) override {
|
||||
// Treat as generic data with custom type in title
|
||||
json modified_data = data;
|
||||
if (!modified_data.contains("window")) {
|
||||
modified_data["window"] = json{};
|
||||
}
|
||||
if (!modified_data["window"].contains("title")) {
|
||||
modified_data["window"]["title"] = customType;
|
||||
}
|
||||
|
||||
showData(DataType::CUSTOM, modified_data);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// IUI INTERFACE IMPLEMENTATION - REQUESTS & EVENTS
|
||||
// ========================================
|
||||
|
||||
void onRequest(RequestType requestType, std::function<void(const json&)> callback) override;
|
||||
void onRequestCustom(const std::string& customType, std::function<void(const json&)> callback) override;
|
||||
void showEvent(EventLevel level, const std::string& message) override;
|
||||
|
||||
// ========================================
|
||||
// WINDOW MANAGEMENT IMPLEMENTATION
|
||||
// ========================================
|
||||
|
||||
void createDock(const std::string& dockId, DockType type, DockPosition position, const json& config = {}) override;
|
||||
void createSplit(const std::string& dockId, Orientation orientation, const json& config = {}) override;
|
||||
void closeWindow(const std::string& windowId) override;
|
||||
void focusWindow(const std::string& windowId) override;
|
||||
|
||||
// ========================================
|
||||
// STATE MANAGEMENT
|
||||
// ========================================
|
||||
|
||||
json getState() const override;
|
||||
void setState(const json& state) override;
|
||||
|
||||
private:
|
||||
// ========================================
|
||||
// CONTENT RENDERING IMPLEMENTATIONS
|
||||
// ========================================
|
||||
|
||||
void renderEconomyContent(const json& content);
|
||||
void renderMapContent(const json& content);
|
||||
void renderInventoryContent(const json& content);
|
||||
void renderConsoleContent(const json& content);
|
||||
void renderPerformanceContent(const json& content);
|
||||
void renderCompaniesContent(const json& content);
|
||||
void renderAlertsContent(const json& content);
|
||||
void renderSettingsContent(const json& content);
|
||||
void renderGenericContent(const json& content);
|
||||
void renderLogConsole();
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,546 +0,0 @@
|
||||
#include "warfactory/ImGuiUI.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
// ========================================
|
||||
// IUI INTERFACE IMPLEMENTATION - REQUESTS & EVENTS
|
||||
// ========================================
|
||||
|
||||
void ImGuiUI::onRequest(RequestType requestType, std::function<void(const json&)> callback) {
|
||||
request_callbacks[requestType] = callback;
|
||||
}
|
||||
|
||||
void ImGuiUI::onRequestCustom(const std::string& customType, std::function<void(const json&)> callback) {
|
||||
custom_request_callbacks[customType] = callback;
|
||||
}
|
||||
|
||||
void ImGuiUI::showEvent(EventLevel level, const std::string& message) {
|
||||
LogMessage log_msg;
|
||||
log_msg.level = level;
|
||||
log_msg.message = message;
|
||||
log_msg.timestamp = std::chrono::steady_clock::now();
|
||||
|
||||
log_messages.push_back(log_msg);
|
||||
|
||||
// Keep only last MAX_LOG_MESSAGES
|
||||
if (log_messages.size() > MAX_LOG_MESSAGES) {
|
||||
log_messages.erase(log_messages.begin());
|
||||
}
|
||||
|
||||
// Also output to console for debugging
|
||||
const char* level_str = toString(level);
|
||||
std::cout << "[" << level_str << "] " << message << std::endl;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// WINDOW MANAGEMENT IMPLEMENTATION
|
||||
// ========================================
|
||||
|
||||
void ImGuiUI::createDock(const std::string& dockId, DockType type, DockPosition position, const json& config) {
|
||||
DockInfo& dock = docks[dockId];
|
||||
dock.id = dockId;
|
||||
dock.type = type;
|
||||
dock.position = position;
|
||||
dock.parent = config.value("parent", "");
|
||||
|
||||
// Parse size with percentage support
|
||||
if (config.contains("size")) {
|
||||
auto size_config = config["size"];
|
||||
if (size_config.is_object()) {
|
||||
if (size_config.contains("width")) {
|
||||
dock.size.x = parseSize(size_config["width"], screen_size.x, 300);
|
||||
} else {
|
||||
dock.size.x = 300; // Default
|
||||
}
|
||||
if (size_config.contains("height")) {
|
||||
dock.size.y = parseSize(size_config["height"], screen_size.y, 200);
|
||||
} else {
|
||||
dock.size.y = 200; // Default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("min_size")) {
|
||||
auto min_config = config["min_size"];
|
||||
if (min_config.is_object()) {
|
||||
if (min_config.contains("width")) {
|
||||
dock.min_size.x = parseSize(min_config["width"], screen_size.x, 100);
|
||||
} else {
|
||||
dock.min_size.x = 100;
|
||||
}
|
||||
if (min_config.contains("height")) {
|
||||
dock.min_size.y = parseSize(min_config["height"], screen_size.y, 100);
|
||||
} else {
|
||||
dock.min_size.y = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("max_size")) {
|
||||
auto max_config = config["max_size"];
|
||||
if (max_config.is_object()) {
|
||||
if (max_config.contains("width")) {
|
||||
dock.max_size.x = parseSize(max_config["width"], screen_size.x, 1000);
|
||||
} else {
|
||||
dock.max_size.x = 1000;
|
||||
}
|
||||
if (max_config.contains("height")) {
|
||||
dock.max_size.y = parseSize(max_config["height"], screen_size.y, 800);
|
||||
} else {
|
||||
dock.max_size.y = 800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dock.collapsible = config.value("collapsible", true);
|
||||
dock.resizable = config.value("resizable", true);
|
||||
|
||||
// Debug logging for dock creation
|
||||
showEvent(EventLevel::DEBUG, "🏗️ Created dock '" + dockId + "': " + std::string(toString(type)) +
|
||||
" size=" + std::to_string((int)dock.size.x) + "x" + std::to_string((int)dock.size.y) + "px");
|
||||
|
||||
showEvent(EventLevel::INFO, "Created " + std::string(toString(type)) + " dock: " + dockId);
|
||||
}
|
||||
|
||||
void ImGuiUI::createSplit(const std::string& dockId, Orientation orientation, const json& config) {
|
||||
// Create as a split dock
|
||||
json split_config = config;
|
||||
split_config["orientation"] = toString(orientation);
|
||||
createDock(dockId, DockType::SPLIT, DockPosition::CENTER, split_config);
|
||||
}
|
||||
|
||||
void ImGuiUI::closeWindow(const std::string& windowId) {
|
||||
auto it = windows.find(windowId);
|
||||
if (it != windows.end()) {
|
||||
it->second.is_open = false;
|
||||
showEvent(EventLevel::INFO, "Closed window: " + windowId);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::focusWindow(const std::string& windowId) {
|
||||
auto it = windows.find(windowId);
|
||||
if (it != windows.end()) {
|
||||
ImGui::SetWindowFocus(it->second.title.c_str());
|
||||
showEvent(EventLevel::DEBUG, "Focused window: " + windowId);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// STATE MANAGEMENT
|
||||
// ========================================
|
||||
|
||||
json ImGuiUI::getState() const {
|
||||
json state;
|
||||
state["frame_count"] = frame_count;
|
||||
state["window_open"] = !should_close;
|
||||
state["screen_size"] = {{"width", screen_size.x}, {"height", screen_size.y}};
|
||||
|
||||
// Save window states
|
||||
json window_states = json::object();
|
||||
for (const auto& [id, win] : windows) {
|
||||
window_states[id] = {
|
||||
{"is_open", win.is_open},
|
||||
{"size", {{"width", win.size.x}, {"height", win.size.y}}},
|
||||
{"position", {{"x", win.position.x}, {"y", win.position.y}}},
|
||||
{"floating", win.is_floating}
|
||||
};
|
||||
}
|
||||
state["windows"] = window_states;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void ImGuiUI::setState(const json& state) {
|
||||
if (state.contains("windows")) {
|
||||
for (const auto& [id, win_state] : state["windows"].items()) {
|
||||
auto it = windows.find(id);
|
||||
if (it != windows.end()) {
|
||||
auto& win = it->second;
|
||||
win.is_open = win_state.value("is_open", true);
|
||||
|
||||
if (win_state.contains("size")) {
|
||||
auto size_state = win_state["size"];
|
||||
if (size_state.is_object()) {
|
||||
win.size.x = size_state.value("width", win.size.x);
|
||||
win.size.y = size_state.value("height", win.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (win_state.contains("position")) {
|
||||
auto pos_state = win_state["position"];
|
||||
if (pos_state.is_object()) {
|
||||
win.position.x = pos_state.value("x", win.position.x);
|
||||
win.position.y = pos_state.value("y", win.position.y);
|
||||
}
|
||||
}
|
||||
|
||||
win.is_floating = win_state.value("floating", win.is_floating);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// CONTENT RENDERING IMPLEMENTATIONS
|
||||
// ========================================
|
||||
|
||||
void ImGuiUI::renderEconomyContent(const json& content) {
|
||||
ImGui::Text("💰 Economy Dashboard");
|
||||
ImGui::Separator();
|
||||
|
||||
if (content.contains("prices")) {
|
||||
ImGui::Text("Market Prices:");
|
||||
ImGui::BeginTable("prices_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg);
|
||||
|
||||
ImGui::TableSetupColumn("Item");
|
||||
ImGui::TableSetupColumn("Price");
|
||||
ImGui::TableSetupColumn("Trend");
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (const auto& [item, price] : content["prices"].items()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", item.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
if (price.is_number()) {
|
||||
ImGui::Text("%.2f", price.get<float>());
|
||||
} else {
|
||||
ImGui::Text("%s", price.dump().c_str());
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Show trend if available
|
||||
if (content.contains("trends") && content["trends"].contains(item)) {
|
||||
std::string trend = content["trends"][item];
|
||||
if (trend[0] == '+') {
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%s", trend.c_str());
|
||||
} else if (trend[0] == '-') {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", trend.c_str());
|
||||
} else {
|
||||
ImGui::Text("%s", trend.c_str());
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("--");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// Action buttons
|
||||
if (ImGui::Button("🔄 Refresh Prices")) {
|
||||
if (request_callbacks.count(RequestType::GET_PRICES)) {
|
||||
request_callbacks[RequestType::GET_PRICES]({});
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("📊 Market Analysis")) {
|
||||
if (custom_request_callbacks.count("market_analysis")) {
|
||||
custom_request_callbacks["market_analysis"]({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderMapContent(const json& content) {
|
||||
ImGui::Text("🗺️ Global Map");
|
||||
ImGui::Separator();
|
||||
|
||||
if (content.contains("current_chunk")) {
|
||||
auto chunk = content["current_chunk"];
|
||||
if (chunk.is_object()) {
|
||||
ImGui::Text("Current Chunk: (%d, %d)", chunk.value("x", 0), chunk.value("y", 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (content.contains("tiles")) {
|
||||
ImGui::Text("Map Display:");
|
||||
|
||||
// Navigation controls
|
||||
if (ImGui::Button("⬆️")) {
|
||||
if (request_callbacks.count(RequestType::GET_CHUNK)) {
|
||||
request_callbacks[RequestType::GET_CHUNK]({{"action", "move_up"}});
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("⬅️")) {
|
||||
if (request_callbacks.count(RequestType::GET_CHUNK)) {
|
||||
request_callbacks[RequestType::GET_CHUNK]({{"action", "move_left"}});
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("➡️")) {
|
||||
if (request_callbacks.count(RequestType::GET_CHUNK)) {
|
||||
request_callbacks[RequestType::GET_CHUNK]({{"action", "move_right"}});
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("⬇️")) {
|
||||
if (request_callbacks.count(RequestType::GET_CHUNK)) {
|
||||
request_callbacks[RequestType::GET_CHUNK]({{"action", "move_down"}});
|
||||
}
|
||||
}
|
||||
|
||||
// Simple tile grid representation
|
||||
ImGui::Text("Tile Grid (sample):");
|
||||
for (int y = 0; y < 4; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
if (x > 0) ImGui::SameLine();
|
||||
|
||||
// Generate simple tile representation
|
||||
char tile_str[2] = "."; // Null-terminated string
|
||||
if ((x + y) % 3 == 0) tile_str[0] = 'I'; // Iron
|
||||
else if ((x + y) % 5 == 0) tile_str[0] = 'C'; // Copper
|
||||
else if ((x + y) % 7 == 0) tile_str[0] = 'T'; // Tree
|
||||
|
||||
ImGui::Button(tile_str, ImVec2(20, 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("🔄 Refresh Map")) {
|
||||
if (request_callbacks.count(RequestType::GET_CHUNK)) {
|
||||
request_callbacks[RequestType::GET_CHUNK]({{"type", "refresh"}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderInventoryContent(const json& content) {
|
||||
ImGui::Text("🎒 Inventory");
|
||||
ImGui::Separator();
|
||||
|
||||
if (content.contains("items")) {
|
||||
ImGui::BeginTable("inventory_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg);
|
||||
ImGui::TableSetupColumn("Item");
|
||||
ImGui::TableSetupColumn("Quantity");
|
||||
ImGui::TableSetupColumn("Reserved");
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (const auto& item : content["items"]) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", item.value("name", "Unknown").c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", item.value("quantity", 0));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", item.value("reserved", 0));
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderConsoleContent(const json& content) {
|
||||
ImGui::Text("🖥️ Console");
|
||||
ImGui::Separator();
|
||||
|
||||
// Console output area
|
||||
ImGui::BeginChild("console_output", ImVec2(0, -30), true);
|
||||
|
||||
if (content.contains("logs")) {
|
||||
for (const auto& log : content["logs"]) {
|
||||
std::string level = log.value("level", "info");
|
||||
std::string message = log.value("message", "");
|
||||
std::string timestamp = log.value("timestamp", "");
|
||||
|
||||
// Color based on level
|
||||
if (level == "error") {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "[%s] %s - %s",
|
||||
timestamp.c_str(), level.c_str(), message.c_str());
|
||||
} else if (level == "warning") {
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "[%s] %s - %s",
|
||||
timestamp.c_str(), level.c_str(), message.c_str());
|
||||
} else if (level == "success") {
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "[%s] %s - %s",
|
||||
timestamp.c_str(), level.c_str(), message.c_str());
|
||||
} else {
|
||||
ImGui::Text("[%s] %s - %s", timestamp.c_str(), level.c_str(), message.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
// Command input
|
||||
static char command_buffer[256] = "";
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::InputText("##command", command_buffer, sizeof(command_buffer),
|
||||
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
if (custom_request_callbacks.count("console_command")) {
|
||||
custom_request_callbacks["console_command"]({{"command", std::string(command_buffer)}});
|
||||
}
|
||||
command_buffer[0] = '\0'; // Clear buffer
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderPerformanceContent(const json& content) {
|
||||
ImGui::Text("📊 Performance Monitor");
|
||||
ImGui::Separator();
|
||||
|
||||
if (content.contains("fps")) {
|
||||
ImGui::Text("FPS: %d", content.value("fps", 0));
|
||||
}
|
||||
if (content.contains("frame_time")) {
|
||||
ImGui::Text("Frame Time: %s", content.value("frame_time", "0ms").c_str());
|
||||
}
|
||||
if (content.contains("memory_usage")) {
|
||||
ImGui::Text("Memory: %s", content.value("memory_usage", "0MB").c_str());
|
||||
}
|
||||
if (content.contains("entities")) {
|
||||
ImGui::Text("Entities: %d", content.value("entities", 0));
|
||||
}
|
||||
|
||||
// Real-time FPS display
|
||||
ImGui::Spacing();
|
||||
ImGui::Text("Real-time FPS: %.1f", ImGui::GetIO().Framerate);
|
||||
}
|
||||
|
||||
void ImGuiUI::renderCompaniesContent(const json& content) {
|
||||
ImGui::Text("🏢 Companies");
|
||||
ImGui::Separator();
|
||||
|
||||
for (const auto& [company_name, company_data] : content.items()) {
|
||||
if (ImGui::CollapsingHeader(company_name.c_str())) {
|
||||
if (company_data.contains("cash")) {
|
||||
ImGui::Text("💰 Cash: $%d", company_data.value("cash", 0));
|
||||
}
|
||||
if (company_data.contains("status")) {
|
||||
ImGui::Text("📊 Status: %s", company_data.value("status", "unknown").c_str());
|
||||
}
|
||||
if (company_data.contains("strategy")) {
|
||||
ImGui::Text("🎯 Strategy: %s", company_data.value("strategy", "none").c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderAlertsContent(const json& content) {
|
||||
ImGui::Text("⚠️ Alerts");
|
||||
ImGui::Separator();
|
||||
|
||||
if (content.contains("urgent_alerts")) {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "🚨 URGENT:");
|
||||
for (const auto& alert : content["urgent_alerts"]) {
|
||||
if (alert.is_string()) {
|
||||
ImGui::BulletText("%s", alert.get<std::string>().c_str());
|
||||
} else {
|
||||
ImGui::BulletText("%s", alert.dump().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (content.contains("warnings")) {
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "⚠️ Warnings:");
|
||||
for (const auto& warning : content["warnings"]) {
|
||||
if (warning.is_string()) {
|
||||
ImGui::BulletText("%s", warning.get<std::string>().c_str());
|
||||
} else {
|
||||
ImGui::BulletText("%s", warning.dump().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("✅ Acknowledge All")) {
|
||||
if (custom_request_callbacks.count("acknowledge_alerts")) {
|
||||
custom_request_callbacks["acknowledge_alerts"]({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderSettingsContent(const json& content) {
|
||||
ImGui::Text("⚙️ Settings");
|
||||
ImGui::Separator();
|
||||
|
||||
if (content.contains("graphics")) {
|
||||
if (ImGui::CollapsingHeader("🖥️ Graphics")) {
|
||||
auto graphics = content["graphics"];
|
||||
if (graphics.is_object()) {
|
||||
ImGui::Text("Resolution: %s", graphics.value("resolution", "Unknown").c_str());
|
||||
bool fullscreen = graphics.value("fullscreen", false);
|
||||
if (ImGui::Checkbox("Fullscreen", &fullscreen)) {
|
||||
// Handle setting change
|
||||
}
|
||||
bool vsync = graphics.value("vsync", true);
|
||||
if (ImGui::Checkbox("VSync", &vsync)) {
|
||||
// Handle setting change
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (content.contains("audio")) {
|
||||
if (ImGui::CollapsingHeader("🔊 Audio")) {
|
||||
auto audio = content["audio"];
|
||||
if (audio.is_object()) {
|
||||
float master_vol = audio.value("master_volume", 1.0f);
|
||||
if (ImGui::SliderFloat("Master Volume", &master_vol, 0.0f, 1.0f)) {
|
||||
// Handle setting change
|
||||
}
|
||||
float effects_vol = audio.value("effects_volume", 1.0f);
|
||||
if (ImGui::SliderFloat("Effects Volume", &effects_vol, 0.0f, 1.0f)) {
|
||||
// Handle setting change
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiUI::renderGenericContent(const json& content) {
|
||||
ImGui::Text("📄 Data");
|
||||
ImGui::Separator();
|
||||
|
||||
// Generic JSON display
|
||||
std::ostringstream oss;
|
||||
oss << content.dump(2); // Pretty print with 2-space indent
|
||||
ImGui::TextWrapped("%s", oss.str().c_str());
|
||||
}
|
||||
|
||||
void ImGuiUI::renderLogConsole() {
|
||||
// Always visible log console at bottom
|
||||
ImGui::SetNextWindowSize(ImVec2(screen_size.x, 200), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(0, screen_size.y - 200), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (ImGui::Begin("📜 System Log", nullptr,
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
|
||||
ImGui::BeginChild("log_scroll", ImVec2(0, 150), true);
|
||||
|
||||
for (const auto& log_msg : log_messages) {
|
||||
auto duration = log_msg.timestamp.time_since_epoch();
|
||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 100000;
|
||||
|
||||
const char* level_str = toString(log_msg.level);
|
||||
|
||||
// Color based on level
|
||||
ImVec4 color = {1.0f, 1.0f, 1.0f, 1.0f}; // Default white
|
||||
switch (log_msg.level) {
|
||||
case EventLevel::ERROR: color = {1.0f, 0.0f, 0.0f, 1.0f}; break;
|
||||
case EventLevel::WARNING: color = {1.0f, 1.0f, 0.0f, 1.0f}; break;
|
||||
case EventLevel::SUCCESS: color = {0.0f, 1.0f, 0.0f, 1.0f}; break;
|
||||
case EventLevel::DEBUG: color = {0.7f, 0.7f, 0.7f, 1.0f}; break;
|
||||
case EventLevel::INFO:
|
||||
default: color = {1.0f, 1.0f, 1.0f, 1.0f}; break;
|
||||
}
|
||||
|
||||
ImGui::TextColored(color, "[%05lld] [%s] %s",
|
||||
millis, level_str, log_msg.message.c_str());
|
||||
}
|
||||
|
||||
// Auto-scroll to bottom
|
||||
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace warfactory
|
||||
78
src/modules/map/CLAUDE.md
Normal file
78
src/modules/map/CLAUDE.md
Normal file
@ -0,0 +1,78 @@
|
||||
# Map Module
|
||||
|
||||
**Responsabilité**: Structures de données pour cartes, régions et tiles du système de génération de monde.
|
||||
|
||||
## Description
|
||||
|
||||
Ce module contient les structures de données fondamentales pour la représentation géographique du monde : cartes, tiles, régions et leur gestion. Conçu pour être utilisé par les modules de génération de monde et autres systèmes nécessitant des données géographiques.
|
||||
|
||||
## Structures Incluses
|
||||
|
||||
### Core Map Data
|
||||
- **GMap**: Structure principale de carte avec dimensions et données de tiles
|
||||
- **GTile**: Représentation d'une tile individuelle avec propriétés géographiques
|
||||
- **IRegion**: Interface pour toutes les régions géographiques
|
||||
|
||||
### Region Management
|
||||
- **RegionManager**: Gestionnaire pour collections de régions avec opérations spatiales
|
||||
- **ResourceRegion**: Région spécialisée pour dépôts de ressources minérales
|
||||
|
||||
## Architecture
|
||||
|
||||
### Interfaces
|
||||
- **IRegion**: Interface commune pour tous types de régions
|
||||
- Position (x, y)
|
||||
- Masse/influence
|
||||
- Type de région
|
||||
- Opérations de fusion
|
||||
|
||||
### Types de Régions
|
||||
- **ResourceRegion**: Dépôts minéraux avec mapping ressource → quantité
|
||||
- **TectonicRegion**: Plaques tectoniques (dans world-generation-realist)
|
||||
- **ClimateRegion**: Zones climatiques (dans world-generation-realist)
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Dans world-generation-realist
|
||||
```cpp
|
||||
#include "map/GMap.h"
|
||||
#include "map/ResourceRegion.h"
|
||||
|
||||
// Génération de carte
|
||||
GMap heightmap(width, height);
|
||||
|
||||
// Création de régions de ressources
|
||||
ResourceRegion iron_deposit("iron_ore", x, y, total_mass);
|
||||
```
|
||||
|
||||
### Duck Typing Support
|
||||
Toutes les régions supportent l'interface duck typing pour UniversalRegionFusionFunction:
|
||||
- `std::string getNameType() const`
|
||||
- `float getX() const, float getY() const`
|
||||
- `float getMass() const`
|
||||
- `void setPosition(float x, float y)`
|
||||
- `void addMass(float mass)`
|
||||
|
||||
## Contraintes Modules
|
||||
- **Header-only**: Pas d'implémentations .cpp (structures de données simples)
|
||||
- **Template-friendly**: Compatible avec les templates C++ pour type safety
|
||||
- **Autonomous**: Pas de dépendances externes aux interfaces core
|
||||
- **Hot-reload compatible**: Structures sérialisables
|
||||
|
||||
## Build System
|
||||
|
||||
### Commands
|
||||
```bash
|
||||
cd src/modules/map/
|
||||
cmake . # Configuration autonome
|
||||
make warfactory-map-module # Build module (headers only)
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
- **Core**: Aucune dépendance core/ requise
|
||||
- **Standards**: C++20 pour features modernes
|
||||
- **Compatibility**: Utilisable par tous autres modules
|
||||
|
||||
---
|
||||
|
||||
**État actuel**: Module créé avec structures de données déplacées depuis world-generation-realist. Fichiers .cpp inclus dans build system.
|
||||
42
src/modules/map/CMakeLists.txt
Normal file
42
src/modules/map/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(warfactory-map-module)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Find nlohmann_json
|
||||
find_package(nlohmann_json QUIET)
|
||||
|
||||
# Minimal FetchContent for missing deps
|
||||
if(NOT nlohmann_json_FOUND)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(nlohmann_json
|
||||
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
|
||||
URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d
|
||||
)
|
||||
FetchContent_MakeAvailable(nlohmann_json)
|
||||
endif()
|
||||
|
||||
# Include and source directories
|
||||
include_directories(include)
|
||||
include_directories(../../core/include)
|
||||
|
||||
# Headers only (header-only library)
|
||||
file(GLOB_RECURSE HEADERS "include/*.h")
|
||||
|
||||
# Create header-only interface library
|
||||
add_library(warfactory-map-module INTERFACE)
|
||||
|
||||
# Set include directories for interface library
|
||||
target_include_directories(warfactory-map-module INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
# Link nlohmann_json as interface dependency
|
||||
target_link_libraries(warfactory-map-module INTERFACE nlohmann_json::nlohmann_json)
|
||||
|
||||
# Install headers for other modules to use
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include/warfactory/map
|
||||
FILES_MATCHING PATTERN "*.h")
|
||||
207
src/modules/map/include/GMap.h
Normal file
207
src/modules/map/include/GMap.h
Normal file
@ -0,0 +1,207 @@
|
||||
#pragma once
|
||||
|
||||
#include "GTile.h"
|
||||
#include "warfactory/ASerializable.h"
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
class GMap : public ASerializable {
|
||||
private:
|
||||
int width, height;
|
||||
GTile* tiles; // Contiguous memory block: tiles[y * width + x]
|
||||
|
||||
public:
|
||||
GMap(int w, int h);
|
||||
~GMap();
|
||||
|
||||
// Prevent copy (expensive with large maps)
|
||||
GMap(const GMap&) = delete;
|
||||
GMap& operator=(const GMap&) = delete;
|
||||
|
||||
// Move constructor/assignment for efficiency
|
||||
GMap(GMap&& other) noexcept;
|
||||
GMap& operator=(GMap&& other) noexcept;
|
||||
|
||||
// ========================================
|
||||
// MAP ACCESS
|
||||
// ========================================
|
||||
|
||||
GTile* getTile(int x, int y);
|
||||
const GTile* getTile(int x, int y) const;
|
||||
|
||||
bool isValidCoordinate(int x, int y) const {
|
||||
return x >= 0 && x < width && y >= 0 && y < height;
|
||||
}
|
||||
|
||||
int getWidth() const { return width; }
|
||||
int getHeight() const { return height; }
|
||||
|
||||
// ========================================
|
||||
// MAP STATISTICS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get average temperature across map
|
||||
*/
|
||||
float getAverageTemperature() const;
|
||||
|
||||
/**
|
||||
* @brief Get average elevation across map
|
||||
*/
|
||||
float getAverageElevation() const;
|
||||
|
||||
// ========================================
|
||||
// ITERATION SUPPORT (cache-friendly)
|
||||
// ========================================
|
||||
|
||||
GTile* begin() { return tiles; }
|
||||
GTile* end() { return tiles + (width * height); }
|
||||
const GTile* begin() const { return tiles; }
|
||||
const GTile* end() const { return tiles + (width * height); }
|
||||
|
||||
// ========================================
|
||||
// SERIALIZATION
|
||||
// ========================================
|
||||
|
||||
json serialize() const override;
|
||||
void deserialize(const json& data) override;
|
||||
|
||||
private:
|
||||
void allocateTiles();
|
||||
void deallocateTiles();
|
||||
};
|
||||
|
||||
// ========================================
|
||||
// INLINE IMPLEMENTATIONS
|
||||
// ========================================
|
||||
|
||||
inline GMap::GMap(int w, int h) : ASerializable("gmap"), width(w), height(h), tiles(nullptr) {
|
||||
allocateTiles();
|
||||
}
|
||||
|
||||
inline GMap::~GMap() {
|
||||
deallocateTiles();
|
||||
}
|
||||
|
||||
inline GMap::GMap(GMap&& other) noexcept
|
||||
: ASerializable("gmap"), width(other.width), height(other.height), tiles(other.tiles) {
|
||||
other.width = 0;
|
||||
other.height = 0;
|
||||
other.tiles = nullptr;
|
||||
}
|
||||
|
||||
inline GMap& GMap::operator=(GMap&& other) noexcept {
|
||||
if (this != &other) {
|
||||
deallocateTiles();
|
||||
width = other.width;
|
||||
height = other.height;
|
||||
tiles = other.tiles;
|
||||
|
||||
other.width = 0;
|
||||
other.height = 0;
|
||||
other.tiles = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline GTile* GMap::getTile(int x, int y) {
|
||||
if (!isValidCoordinate(x, y)) return nullptr;
|
||||
return &tiles[y * width + x];
|
||||
}
|
||||
|
||||
inline const GTile* GMap::getTile(int x, int y) const {
|
||||
if (!isValidCoordinate(x, y)) return nullptr;
|
||||
return &tiles[y * width + x];
|
||||
}
|
||||
|
||||
inline float GMap::getAverageTemperature() const {
|
||||
if (width == 0 || height == 0) return 0.0f;
|
||||
|
||||
double temperature_sum = 0.0;
|
||||
const int total_tiles = width * height;
|
||||
|
||||
for (int i = 0; i < total_tiles; ++i) {
|
||||
temperature_sum += tiles[i].getTemperatureCelsius();
|
||||
}
|
||||
|
||||
return static_cast<float>(temperature_sum / total_tiles);
|
||||
}
|
||||
|
||||
inline float GMap::getAverageElevation() const {
|
||||
if (width == 0 || height == 0) return 0.0f;
|
||||
|
||||
double elevation_sum = 0.0;
|
||||
const int total_tiles = width * height;
|
||||
|
||||
for (int i = 0; i < total_tiles; ++i) {
|
||||
elevation_sum += tiles[i].getElevationMeters();
|
||||
}
|
||||
|
||||
return static_cast<float>(elevation_sum / total_tiles);
|
||||
}
|
||||
|
||||
inline json GMap::serialize() const {
|
||||
json data;
|
||||
data["width"] = width;
|
||||
data["height"] = height;
|
||||
data["tiles"] = json::array();
|
||||
|
||||
const int total_tiles = width * height;
|
||||
for (int i = 0; i < total_tiles; ++i) {
|
||||
const GTile& tile = tiles[i];
|
||||
json tile_data;
|
||||
tile_data["elevation"] = tile.elevation;
|
||||
tile_data["temperature"] = tile.temperature;
|
||||
tile_data["biome_type_id"] = tile.biome_type_id;
|
||||
tile_data["water_token"] = tile.water_token;
|
||||
tile_data["wind_token"] = tile.wind_token;
|
||||
tile_data["target_budget_score"] = tile.target_budget_score;
|
||||
tile_data["destruction_token"] = tile.destruction_token;
|
||||
tile_data["flags"] = tile.flags;
|
||||
tile_data["feature_set_id"] = tile.feature_set_id;
|
||||
data["tiles"].push_back(tile_data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
inline void GMap::deserialize(const json& data) {
|
||||
deallocateTiles();
|
||||
|
||||
width = data.at("width").get<int>();
|
||||
height = data.at("height").get<int>();
|
||||
|
||||
allocateTiles();
|
||||
|
||||
const json& tiles_data = data.at("tiles");
|
||||
const int total_tiles = width * height;
|
||||
|
||||
for (int i = 0; i < total_tiles && i < static_cast<int>(tiles_data.size()); ++i) {
|
||||
const json& tile_data = tiles_data[i];
|
||||
GTile& tile = tiles[i];
|
||||
|
||||
tile.elevation = tile_data.at("elevation").get<uint16_t>();
|
||||
tile.temperature = tile_data.at("temperature").get<int16_t>();
|
||||
tile.biome_type_id = tile_data.at("biome_type_id").get<uint16_t>();
|
||||
tile.water_token = tile_data.at("water_token").get<uint8_t>();
|
||||
tile.wind_token = tile_data.at("wind_token").get<uint8_t>();
|
||||
tile.target_budget_score = tile_data.at("target_budget_score").get<int8_t>();
|
||||
tile.destruction_token = tile_data.at("destruction_token").get<uint16_t>();
|
||||
tile.flags = tile_data.at("flags").get<uint16_t>();
|
||||
tile.feature_set_id = tile_data.at("feature_set_id").get<uint32_t>();
|
||||
}
|
||||
}
|
||||
|
||||
inline void GMap::allocateTiles() {
|
||||
if (width > 0 && height > 0) {
|
||||
const int total_tiles = width * height;
|
||||
tiles = new GTile[total_tiles];
|
||||
}
|
||||
}
|
||||
|
||||
inline void GMap::deallocateTiles() {
|
||||
delete[] tiles;
|
||||
tiles = nullptr;
|
||||
}
|
||||
|
||||
} // namespace warfactory
|
||||
261
src/modules/map/include/GTile.h
Normal file
261
src/modules/map/include/GTile.h
Normal file
@ -0,0 +1,261 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
struct GTile {
|
||||
// ========================================
|
||||
// CORE DATA (16 bytes total) - Complete tile data
|
||||
// ========================================
|
||||
uint16_t elevation; // Elevation: 0-65535 = -32km to +32km (geological range)
|
||||
int16_t temperature; // Temperature: -32768 to +32767 = -3276°C to +3276°C (0.1°C increments)
|
||||
uint16_t biome_type_id; // Biome classification
|
||||
uint8_t water_token; // Water/rain tokens from climate simulation
|
||||
uint8_t wind_token; // Wind tokens from climate simulation
|
||||
int8_t target_budget_score; // Target budget score: -10 to +10
|
||||
uint16_t destruction_token; // Bits 1-4: highWind, 5-8: flood, 9-12: hurricane, 13-16: reserved
|
||||
uint16_t flags; // Tile properties and state flags
|
||||
uint32_t feature_set_id; // Features present on this tile (0 = no features)
|
||||
|
||||
/**
|
||||
* @brief Constructor with default values
|
||||
*/
|
||||
GTile() : elevation(0), temperature(-1000), biome_type_id(0), water_token(0), wind_token(0),
|
||||
target_budget_score(0), destruction_token(0), flags(0), feature_set_id(0) {}
|
||||
|
||||
// ========================================
|
||||
// ELEVATION CONVERSION (same as WorldTileData)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Convert elevation to meters (geological range: -32km to +32km)
|
||||
*/
|
||||
float getElevationMeters() const {
|
||||
return (elevation / 65535.0f) * 64000.0f - 32000.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set elevation from meters
|
||||
*/
|
||||
void setElevationMeters(float meters) {
|
||||
float normalized = (meters + 32000.0f) / 64000.0f;
|
||||
elevation = static_cast<uint16_t>(std::clamp(normalized * 65535.0f, 0.0f, 65535.0f));
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// TEMPERATURE CONVERSION (same as WorldTileData)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Convert temperature to Celsius (0.1°C precision, range: -3276°C to +3276°C)
|
||||
*/
|
||||
float getTemperatureCelsius() const {
|
||||
return temperature * 0.1f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set temperature from Celsius
|
||||
*/
|
||||
void setTemperatureCelsius(float celsius) {
|
||||
temperature = static_cast<int16_t>(std::clamp(celsius * 10.0f, -32768.0f, 32767.0f));
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// BIOME & CLIMATE DATA
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get biome type ID
|
||||
*/
|
||||
uint16_t getBiomeTypeId() const { return biome_type_id; }
|
||||
|
||||
/**
|
||||
* @brief Set biome type ID
|
||||
*/
|
||||
void setBiomeTypeId(uint16_t biome_id) { biome_type_id = biome_id; }
|
||||
|
||||
/**
|
||||
* @brief Get water tokens from climate simulation
|
||||
*/
|
||||
uint8_t getWaterToken() const { return water_token; }
|
||||
|
||||
/**
|
||||
* @brief Set water tokens
|
||||
*/
|
||||
void setWaterToken(uint8_t tokens) { water_token = tokens; }
|
||||
|
||||
/**
|
||||
* @brief Add water tokens
|
||||
*/
|
||||
void addWaterToken(uint8_t additional_tokens) {
|
||||
uint16_t new_total = static_cast<uint16_t>(water_token) + additional_tokens;
|
||||
water_token = static_cast<uint8_t>(std::min(new_total, static_cast<uint16_t>(255)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get wind tokens from climate simulation
|
||||
*/
|
||||
uint8_t getWindToken() const { return wind_token; }
|
||||
|
||||
/**
|
||||
* @brief Set wind tokens
|
||||
*/
|
||||
void setWindToken(uint8_t tokens) { wind_token = tokens; }
|
||||
|
||||
/**
|
||||
* @brief Add wind tokens
|
||||
*/
|
||||
void addWindToken(uint8_t additional_tokens) {
|
||||
uint16_t new_total = static_cast<uint16_t>(wind_token) + additional_tokens;
|
||||
wind_token = static_cast<uint8_t>(std::min(new_total, static_cast<uint16_t>(255)));
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// DESTRUCTION TOKEN (packed in 16 bits)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get high wind token (bits 1-4)
|
||||
*/
|
||||
uint8_t getHighWindToken() const {
|
||||
return destruction_token & 0x0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set high wind token (0-15)
|
||||
*/
|
||||
void setHighWindToken(uint8_t tokens) {
|
||||
destruction_token = (destruction_token & 0xFFF0) | (tokens & 0x0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get flood token (bits 5-8)
|
||||
*/
|
||||
uint8_t getFloodToken() const {
|
||||
return (destruction_token >> 4) & 0x0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set flood token (0-15)
|
||||
*/
|
||||
void setFloodToken(uint8_t tokens) {
|
||||
destruction_token = (destruction_token & 0xFF0F) | ((tokens & 0x0F) << 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get hurricane token (bits 9-12)
|
||||
*/
|
||||
uint8_t getHurricaneToken() const {
|
||||
return (destruction_token >> 8) & 0x0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set hurricane token (0-15)
|
||||
*/
|
||||
void setHurricaneToken(uint8_t tokens) {
|
||||
destruction_token = (destruction_token & 0xF0FF) | ((tokens & 0x0F) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add high wind tokens
|
||||
*/
|
||||
void addHighWindToken(uint8_t additional) {
|
||||
uint8_t current = getHighWindToken();
|
||||
setHighWindToken(std::min(static_cast<uint8_t>(current + additional), static_cast<uint8_t>(15)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add flood tokens
|
||||
*/
|
||||
void addFloodToken(uint8_t additional) {
|
||||
uint8_t current = getFloodToken();
|
||||
setFloodToken(std::min(static_cast<uint8_t>(current + additional), static_cast<uint8_t>(15)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add hurricane tokens
|
||||
*/
|
||||
void addHurricaneToken(uint8_t additional) {
|
||||
uint8_t current = getHurricaneToken();
|
||||
setHurricaneToken(std::min(static_cast<uint8_t>(current + additional), static_cast<uint8_t>(15)));
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// BUDGET SYSTEM
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get target budget score (-10 to +10)
|
||||
*/
|
||||
int8_t getTargetBudgetScore() const { return target_budget_score; }
|
||||
|
||||
/**
|
||||
* @brief Set target budget score
|
||||
*/
|
||||
void setTargetBudgetScore(int8_t score) { target_budget_score = score; }
|
||||
|
||||
// ========================================
|
||||
// FLAGS & FEATURES
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Get tile flags
|
||||
*/
|
||||
uint16_t getFlags() const { return flags; }
|
||||
|
||||
/**
|
||||
* @brief Set specific flag
|
||||
*/
|
||||
void setFlag(uint16_t flag, bool value) {
|
||||
if (value) {
|
||||
flags |= flag;
|
||||
} else {
|
||||
flags &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if flag is set
|
||||
*/
|
||||
bool hasFlag(uint16_t flag) const { return (flags & flag) != 0; }
|
||||
|
||||
/**
|
||||
* @brief Get feature set ID
|
||||
*/
|
||||
uint32_t getFeatureSetId() const { return feature_set_id; }
|
||||
|
||||
/**
|
||||
* @brief Set feature set ID
|
||||
*/
|
||||
void setFeatureSetId(uint32_t feature_id) { feature_set_id = feature_id; }
|
||||
|
||||
/**
|
||||
* @brief Check if tile has features
|
||||
*/
|
||||
bool hasFeatures() const { return feature_set_id != 0; }
|
||||
|
||||
// ========================================
|
||||
// PHASE 1 OPERATIONS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* @brief Apply heat from meteorite impact
|
||||
*/
|
||||
void applyImpactHeat(float heat_celsius) {
|
||||
float current_temp = getTemperatureCelsius();
|
||||
setTemperatureCelsius(current_temp + heat_celsius);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cool tile by given amount
|
||||
*/
|
||||
void coolTile(float cooling_celsius) {
|
||||
float current_temp = getTemperatureCelsius();
|
||||
setTemperatureCelsius(current_temp - cooling_celsius);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
35
src/modules/map/include/IRegion.h
Normal file
35
src/modules/map/include/IRegion.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "IAttachedElement.h"
|
||||
#include "IElementData.h"
|
||||
#include <memory>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
class IRegion : public IAttachedElement {
|
||||
public:
|
||||
virtual ~IRegion() = default;
|
||||
|
||||
virtual void setPosition(float x, float y) = 0;
|
||||
|
||||
virtual void setMass(float mass) = 0;
|
||||
|
||||
virtual void setRadius(float radius) = 0;
|
||||
|
||||
virtual std::unique_ptr<IElementData> getRegionData() const = 0;
|
||||
virtual void setRegionData(std::unique_ptr<IElementData> data) = 0;
|
||||
|
||||
virtual void updatePosition(float delta_x, float delta_y) = 0;
|
||||
|
||||
virtual void updateMass(float delta_mass) = 0;
|
||||
|
||||
virtual void updateRadius(float delta_radius) = 0;
|
||||
|
||||
virtual float getAttachmentStrength(int attached_element_id) const = 0;
|
||||
virtual void setAttachmentStrength(int attached_element_id, float strength) = 0;
|
||||
|
||||
virtual bool canFuseWith(const IRegion& other) const = 0;
|
||||
virtual void fuseWith(const IRegion& other) = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user