rpg-event-generator 1.1.2 โ†’ 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +119 -15
  2. package/dist/index.js +610 -105
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  A powerful procedural event generation system for RPG games, capable of creating virtually infinite contextual events based on player state and game world.
4
4
 
5
- ## ๐Ÿš€ Installation
5
+ ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install rpg-event-generator
9
9
  ```
10
10
 
11
- ## โœจ Quick Start
11
+ ## Quick Start
12
12
 
13
13
  ```javascript
14
14
  import { RPGEventGenerator, generateRPGEvent } from 'rpg-event-generator';
@@ -26,19 +26,26 @@ console.log(event.description); // Procedurally generated narrative
26
26
  console.log(event.choices); // Array of meaningful choices
27
27
  ```
28
28
 
29
- ## ๐Ÿ“‹ Features
29
+ ## Features
30
30
 
31
- - **๐ŸŽฒ Infinite Event Generation**: Custom Markov chains create unique, contextual events
32
- - **๐Ÿ‘ค Player-Aware**: Events adapt to stats, career, relationships, reputation, and social standing
33
- - **๐ŸŽญ 14+ Event Types**: Court scandals, noble duels, ancient curses, bandit kings, and more
34
- - **๐Ÿ“– Immersive Storytelling**: Rich narratives with atmospheric descriptions and meaningful consequences
35
- - **โš–๏ธ Dynamic Difficulty Scaling**: Events automatically scale based on player power level
36
- - **๐ŸŽจ Thematic Training Sets**: Fantasy, sci-fi, and historical themes with cultural variants
37
- - **โ›“๏ธ Event Chains**: Multi-part story sequences with escalating consequences
38
- - **โฐ Time-Based Events**: Seasonal changes and evolving long-term storylines
39
- - **๐Ÿ”ง Modular Event System**: Create and manage custom templates, training data, and chains
40
- - **๐Ÿ’พ Game Integration**: Proper save/load state management for real games
41
- - **๐Ÿงช Comprehensive Testing**: 45+ automated tests ensuring reliability
31
+ - **Infinite Event Generation**: Custom Markov chains create unique, contextual events
32
+ - **Player-Aware**: Events adapt to stats, career, relationships, reputation, and social standing
33
+ - **14+ Event Types**: Court scandals, noble duels, ancient curses, bandit kings, and more
34
+ - **Immersive Storytelling**: Rich narratives with atmospheric descriptions and meaningful consequences
35
+ - **Dynamic Difficulty Scaling**: Events automatically scale based on player power level
36
+ - **Thematic Training Sets**: Fantasy, sci-fi, and historical themes with cultural variants
37
+ - **Event Chains**: Multi-part story sequences with escalating consequences
38
+ - **Time-Based Events**: Seasonal changes and evolving long-term storylines
39
+ - **Modular Event System**: Create and manage custom templates, training data, and chains
40
+ - **Game Integration**: Proper save/load state management for real games
41
+ - **Comprehensive Testing**: 45+ automated tests ensuring reliability
42
+
43
+ ### Enhanced Features (v1.2.0)
44
+
45
+ - **๐ŸŒ Multi-Language Support**: Generate events in different languages with cultural adaptation
46
+ - **๐Ÿ”— Event Dependencies**: Complex prerequisite systems for event triggering
47
+ - **๐ŸŒค๏ธ Environmental Modifiers**: Weather, season, and location-based event modifications
48
+ - **๐Ÿ‘ฅ NPC Relationships**: Dynamic character relationship networks and social consequences
42
49
 
43
50
  ## ๐Ÿ“– Usage Guide
44
51
 
@@ -195,6 +202,96 @@ const currentTime = generator.getCurrentTime();
195
202
  console.log(`Day ${currentTime.day}, Season: ${currentTime.season}`);
196
203
  ```
197
204
 
205
+ ### Multi-Language Support ๐ŸŒ
206
+
207
+ Generate events in different languages with cultural adaptation:
208
+
209
+ ```javascript
210
+ const generator = new RPGEventGenerator({
211
+ language: 'es', // Spanish events
212
+ theme: 'fantasy'
213
+ });
214
+
215
+ // Load additional language packs
216
+ generator.loadLanguagePack('fr', frenchTranslations);
217
+ generator.setLanguage('fr');
218
+
219
+ // Events now generate in French
220
+ const event = generator.generateEvent();
221
+ console.log(event.title); // "Embuscade de Brigands"
222
+ ```
223
+
224
+ ### Environmental Modifiers ๐ŸŒค๏ธ
225
+
226
+ Weather, season, and location affect event generation:
227
+
228
+ ```javascript
229
+ const generator = new RPGEventGenerator({ enableModifiers: true });
230
+
231
+ // Set environmental context
232
+ generator.setEnvironmentalContext({
233
+ weather: 'storm',
234
+ season: 'winter',
235
+ timeOfDay: 'night'
236
+ });
237
+
238
+ // Events adapt to harsh winter storm conditions
239
+ const event = generator.generateEnhancedEvent({
240
+ environment: { weather: 'storm', season: 'winter' }
241
+ });
242
+ ```
243
+
244
+ ### Event Dependencies ๐Ÿ”—
245
+
246
+ Complex prerequisite systems control when events can occur:
247
+
248
+ ```javascript
249
+ // Register event dependencies
250
+ generator.registerEventDependency('ROYAL_WEDDING', {
251
+ type: 'event_completed',
252
+ eventId: 'COURT_INTRODUCTION'
253
+ });
254
+
255
+ generator.registerEventDependency('ADVANCED_QUEST', {
256
+ operator: 'AND',
257
+ conditions: [
258
+ { type: 'stat_requirement', stat: 'level', min: 5 },
259
+ { type: 'event_completed', eventId: 'BASIC_QUEST' }
260
+ ]
261
+ });
262
+
263
+ // Only generate events whose dependencies are met
264
+ const gameState = { completedEvents: new Set(['COURT_INTRODUCTION']) };
265
+ const event = generator.generateEnhancedEvent({ gameState });
266
+ ```
267
+
268
+ ### NPC Relationship Networks ๐Ÿ‘ฅ
269
+
270
+ Dynamic character relationships that evolve based on player actions:
271
+
272
+ ```javascript
273
+ const generator = new RPGEventGenerator({ enableRelationships: true });
274
+
275
+ // Add NPCs to the relationship network
276
+ generator.addNPC({
277
+ id: 'king_arthur',
278
+ name: 'King Arthur',
279
+ type: 'noble'
280
+ });
281
+
282
+ // Update relationships based on player actions
283
+ generator.applyRelationshipRule('king_arthur', 'player', 'save_life');
284
+ // Relationship with king improves significantly
285
+
286
+ generator.updateRelationship('merchant_john', 'player', -10, 'stole goods');
287
+ // Relationship with merchant deteriorates
288
+
289
+ // Generate events that consider relationship context
290
+ const event = generator.generateEnhancedEvent({
291
+ player: { id: 'player' }
292
+ });
293
+ ```
294
+
198
295
  ### Modular Event System
199
296
 
200
297
  ```javascript
@@ -298,10 +395,17 @@ console.log(`Difficulty: ${epicEvent.difficulty}`); // "legendary"
298
395
 
299
396
  ```javascript
300
397
  const generator = new RPGEventGenerator({
398
+ // Core options
301
399
  stateSize: 2, // Markov chain state size (default: 2)
302
400
  trainingData: [...], // Custom training data array
303
401
  theme: 'fantasy', // 'fantasy', 'sci-fi', 'historical'
304
- culture: 'norse' // Cultural variant within theme
402
+ culture: 'norse', // Cultural variant within theme
403
+
404
+ // Enhanced features (all enabled by default)
405
+ enableDependencies: true, // Complex event prerequisites
406
+ enableModifiers: true, // Weather/season/location modifiers
407
+ enableRelationships: true, // NPC relationship networks
408
+ language: 'en' // Default language for events
305
409
  });
306
410
  ```
307
411
 
package/dist/index.js CHANGED
@@ -133,6 +133,11 @@ class RPGEventGenerator {
133
133
  this.customTemplates = new Set();
134
134
  this.customChains = new Set();
135
135
  this.customTrainingData = {};
136
+ this.enableDependencies = options.enableDependencies !== false;
137
+ this.enableModifiers = options.enableModifiers !== false;
138
+ this.enableRelationships = options.enableRelationships !== false;
139
+ this.language = options.language || 'en';
140
+ this.initializeEnhancedFeatures(options);
136
141
  this.initializeThemes();
137
142
  this.activeChains = new Map();
138
143
  this.chainDefinitions = this.initializeChainDefinitions();
@@ -158,8 +163,6 @@ class RPGEventGenerator {
158
163
  penaltyMultiplier: 1.6
159
164
  }
160
165
  };
161
-
162
- // Initialize time system
163
166
  this.timeSystem = {
164
167
  currentDay: 1,
165
168
  currentSeason: 'spring',
@@ -554,7 +557,6 @@ class RPGEventGenerator {
554
557
  consequence: 'prudent'
555
558
  }]
556
559
  },
557
- // Event Chain Templates
558
560
  BANDIT_AMBUSH: {
559
561
  title: 'Bandit Ambush',
560
562
  narrative: 'A small group of bandits springs an ambush on your caravan, demanding tribute or blood.',
@@ -710,7 +712,6 @@ class RPGEventGenerator {
710
712
  consequence: 'cursed'
711
713
  }]
712
714
  },
713
- // Seasonal Event Templates
714
715
  BLOOMING_ROMANCE: {
715
716
  title: 'Spring Blossoms',
716
717
  narrative: 'The spring air carries the sweet scent of blooming flowers, and romance fills the atmosphere.',
@@ -841,7 +842,6 @@ class RPGEventGenerator {
841
842
  consequence: 'philosophical'
842
843
  }]
843
844
  },
844
- // Time-based Event Templates
845
845
  RUMORS_OF_DISSENT: {
846
846
  title: 'Whispers of Unrest',
847
847
  narrative: 'Rumors of dissatisfaction with the current regime begin circulating through the streets.',
@@ -963,76 +963,31 @@ class RPGEventGenerator {
963
963
  * Initialize thematic training data sets
964
964
  * @private
965
965
  */
966
+ /**
967
+ * Initialize enhanced features based on options
968
+ * @private
969
+ * @param {Object} options - Constructor options
970
+ */
971
+ initializeEnhancedFeatures(options) {
972
+ this.locales = new Map();
973
+ this.dependencies = new Map();
974
+ this.modifiers = new Map();
975
+ this.relationships = new Map();
976
+ this.activeModifiers = new Set();
977
+ this.loadDefaultLocale();
978
+ if (this.enableModifiers) {
979
+ this.initializeBuiltInModifiers();
980
+ }
981
+ if (this.enableRelationships) {
982
+ this.initializeRelationshipRules();
983
+ }
984
+ }
966
985
  initializeThemes() {
967
986
  this.themes = {
968
- fantasy: [
969
- // Noble Court Intrigue
970
- 'The royal court is abuzz with whispers of scandal and betrayal', 'A noble lord approaches you with a proposition that could change your destiny', 'Court politics have reached a fever pitch as alliances shift like desert sands', 'The king\'s advisors plot in shadowed corners while the court dances obliviously', 'A mysterious letter arrives sealed with wax from a noble house you don\'t recognize',
971
- // Criminal Underworld
972
- 'The thieves\' guild has put out a contract that bears your name', 'Shadowy figures lurk in alleyways, watching your every move', 'The black market thrives under the cover of night, offering forbidden luxuries', 'A notorious crime lord has taken an interest in your activities', 'Corrupt guards demand tribute while turning a blind eye to greater crimes',
973
- // Supernatural & Mysterious
974
- 'Strange runes appear on your bedroom wall, glowing with ethereal light', 'An ancient prophecy speaks of a hero who matches your description exactly', 'Ghostly apparitions warn of impending doom in fevered dreams', 'A witch in the woods offers you power beyond mortal comprehension', 'Cursed artifacts surface in the market, promising great power at terrible cost',
975
- // Personal & Dramatic
976
- 'Your past sins come back to haunt you in the most unexpected ways', 'A long-lost relative appears with a tale that shakes your world', 'Your reputation draws admirers and enemies in equal measure', 'A betrayal cuts deeper than any blade, leaving scars on your soul', 'Love and ambition war within your heart as opportunities arise',
977
- // Adventure & Exploration
978
- 'Ancient ruins whisper secrets to those brave enough to listen', 'A dragon\'s hoard lies hidden, protected by trials and tribulations', 'Bandits rule the roads, but their leader seems oddly familiar', 'A legendary artifact calls to you from across distant lands', 'The wilderness holds both peril and promise for the bold adventurer',
979
- // Social & Relationship
980
- 'Romantic entanglements complicate your carefully laid plans', 'Old friends become new enemies as loyalties are tested', 'Family secrets emerge that threaten to destroy everything you hold dear', 'Mentors offer wisdom that comes with strings attached', 'Rivals emerge from unexpected places, challenging your hard-won position',
981
- // Economic & Mercantile
982
- 'The market crashes send shockwaves through the merchant class', 'A get-rich-quick scheme promises fortunes but demands your soul', 'Trade wars erupt between rival merchant houses', 'Investment opportunities arise that could make or break your fortune', 'Black market deals offer power but carry the weight of damnation',
983
- // Military & Combat
984
- 'War drums beat as kingdoms prepare for inevitable conflict', 'Desertion offers freedom but brands you a coward forever', 'A duel of honor is proposed, with your reputation on the line', 'Mercenary companies seek captains brave enough to lead them', 'Battle scars tell stories of glory and horror in equal measure',
985
- // Magical & Mystical
986
- 'The veil between worlds thins, allowing magic to seep into reality', 'Curses and blessings intertwine in ways you never expected', 'Ancient bloodlines awaken powers dormant for generations', 'Rituals performed in secret grant power at terrible personal cost', 'The stars themselves seem to conspire in your favor or against you',
987
- // Seasonal & Natural
988
- 'Winter\'s cruel bite forces desperate measures from the populace', 'Spring\'s renewal brings both hope and dangerous new beginnings', 'Summer tournaments test the mettle of warriors and nobles alike', 'Autumn harvests reveal secrets long buried in the fields', 'The changing seasons mirror the turmoil in your own life',
989
- // Dramatic Twists
990
- 'What seems like a blessing reveals itself as a curse in disguise', 'Enemies become allies, and allies become your greatest threat', 'The path of righteousness leads to ruin, while villainy brings reward', 'Fate itself seems to take notice of your actions, for good or ill', 'The world bends around you as your choices reshape reality itself'],
991
- 'sci-fi': [
992
- // Corporate Intrigue
993
- 'Megacorporations wage shadow wars through proxy conflicts and data manipulation', 'Neural implants malfunction, flooding your mind with corporate secrets', 'A black-market AI offers forbidden knowledge at the cost of your sanity', 'Corporate espionage turns deadly when rival agents converge on your location', 'Whistleblower data reveals systemic corruption in the highest levels of power',
994
- // Cyberpunk Underworld
995
- 'Hackers breach your personal network, exposing vulnerabilities you never knew existed', 'Street gangs control the undercity with drone swarms and illegal augmentations', 'The dark web pulses with illegal tech trades and forbidden experiments', 'Corporate bounty hunters track you through the neon-lit sprawl', 'Data runners risk everything for the ultimate information score',
996
- // Space & Exploration
997
- 'Alien artifacts whisper secrets from beyond the galactic rim', 'Space pirates demand tribute or face the void of decompression', 'Ancient derelict ships hold treasures and horrors from forgotten eras', 'Wormhole anomalies bend reality, creating unpredictable temporal events', 'Colony worlds rebel against Earth\'s iron-fisted governance',
998
- // AI & Technology
999
- 'Sentient AIs manipulate events from within the global network', 'Nanobot swarms escape containment, evolving beyond their programming', 'Virtual reality simulations bleed into the real world disastrously', 'Genetic engineering experiments create monstrous hybrid beings', 'Quantum computers predict the future, but at what cost to free will?',
1000
- // Dystopian Society
1001
- 'Social credit systems reward compliance and punish deviation', 'Surveillance drones watch every move, every transaction, every thought', 'Rebellions simmer beneath the surface of totalitarian control', 'Resource wars rage over the last viable mining asteroids', 'Climate engineering projects backfire spectacularly',
1002
- // Personal & Cybernetic
1003
- 'Implant malfunctions cause vivid hallucinations and system crashes', 'Identity theft becomes literal as someone steals your digital consciousness', 'Memory wipes erase crucial knowledge, leaving you vulnerable', 'Cybernetic enhancements demand maintenance that costs more than you can afford', 'Neural links create unintended telepathic connections with strangers',
1004
- // Economic & Corporate
1005
- 'Cryptocurrency markets crash, wiping out fortunes in digital dust', 'Hostile takeovers turn friendly acquisitions into bloody boardroom coups', 'Trade wars erupt between orbital habitats and planetary governments', 'Investment opportunities in black-market tech promise riches or ruin', 'Corporate espionage turns personal when family members are leveraged',
1006
- // Military & Combat
1007
- 'Drone wars rage in the skies above abandoned cities', 'Cyber warfare disables entire infrastructure networks', 'Private military companies offer their services to the highest bidder', 'Nuclear deterrence fails when EMP weapons render missiles useless', 'Bioterrorism releases engineered plagues upon unsuspecting populations',
1008
- // Mystery & Conspiracy
1009
- 'Government cover-ups hide the truth about alien visitations', 'Time travel experiments create paradoxical timeline fractures', 'Parallel dimensions bleed through, creating impossible phenomena', 'Ancient alien technology reactivates with catastrophic consequences', 'Conspiracy theories prove true, but the reality is far worse',
1010
- // Environmental & Planetary
1011
- 'Terraforming projects unleash ancient microbes from the soil', 'Climate control systems fail, creating unpredictable weather patterns', 'Asteroid mining operations awaken dormant extraterrestrial threats', 'Ocean acidification drives aquatic mutations to the surface', 'Atmospheric processors malfunction, creating toxic breathing conditions'],
1012
- historical: [
1013
- // Medieval Court Intrigue
1014
- 'The king\'s advisors plot in shadowed corners of the great hall', 'Noble houses form secret alliances against the crown', 'Whispers of heresy spread through the royal court like wildfire', 'A foreign diplomat offers treacherous propositions under diplomatic immunity', 'Court jesters hide dangerous truths behind masks of folly',
1015
- // Warfare & Conquest
1016
- 'Armies mass at the borders, their banners fluttering in the wind of war', 'Siege engines pound ancient walls as defenders hold the line', 'Cavalry charges break enemy formations in clouds of dust and blood', 'Naval blockades starve cities into submission or desperate rebellion', 'Mercenary companies switch sides based on the highest bidder',
1017
- // Exploration & Discovery
1018
- 'New World expeditions return with gold and strange diseases', 'Ancient artifacts surface from archaeological digs, rewriting history', 'Trade caravans brave bandits and harsh terrains for exotic goods', 'Mapping expeditions chart unknown territories and hostile natives', 'Scientific discoveries challenge religious doctrines and established truths',
1019
- // Social & Class Conflict
1020
- 'Peasant revolts spread like contagion through the countryside', 'Guilds clash over trade monopolies and apprenticeship rights', 'Religious schisms divide communities along ideological lines', 'Women maneuver within restrictive social structures for power and influence', 'Immigrants bring new customs that clash with traditional ways',
1021
- // Economic & Mercantile
1022
- 'Market monopolies drive independent merchants to desperation', 'Banking houses manipulate currency values for political gain', 'Trade embargoes create black markets and smuggling operations', 'Agricultural failures lead to famines and social unrest', 'Colonial exploitation enriches the crown while impoverishing subjects',
1023
- // Political & Diplomatic
1024
- 'Treaty negotiations mask underlying territorial ambitions', 'Spy networks weave webs of deception across national borders', 'Succession crises threaten to plunge nations into civil war', 'Diplomatic incidents escalate into full-scale military conflicts', 'Royal marriages forge alliances that crumble under stress',
1025
- // Religious & Ideological
1026
- 'Inquisitions root out heresy with fire and torture', 'Crusades call warriors to distant lands for faith and glory', 'Reformation movements challenge the authority of established churches', 'Cult leaders promise salvation through devotion and sacrifice', 'Religious relics inspire pilgrimages and bloody conflicts',
1027
- // Personal & Dramatic
1028
- 'Family feuds span generations, poisoning bloodlines with vengeance', 'Scandals rock aristocratic families, threatening social standing', 'Personal ambitions clash with familial duties and expectations', 'Love affairs defy social conventions and familial arrangements', 'Betrayals cut deeper than any blade, leaving lasting scars',
1029
- // Natural & Environmental
1030
- 'Plagues sweep through densely packed cities, claiming thousands', 'Famines force desperate migrations and social breakdowns', 'Natural disasters reveal underlying social and political tensions', 'Harsh winters test the limits of human endurance and charity', 'Droughts drive conflicts over dwindling water resources',
1031
- // Innovation & Progress
1032
- 'Scientific discoveries revolutionize warfare and exploration', 'Technological innovations disrupt traditional crafts and livelihoods', 'Medical breakthroughs save lives but challenge religious views', 'Educational reforms open knowledge to new social classes', 'Engineering marvels push the boundaries of human capability']
987
+ fantasy: ['The royal court is abuzz with whispers of scandal and betrayal', 'A noble lord approaches you with a proposition that could change your destiny', 'Court politics have reached a fever pitch as alliances shift like desert sands', 'The king\'s advisors plot in shadowed corners while the court dances obliviously', 'A mysterious letter arrives sealed with wax from a noble house you don\'t recognize', 'The thieves\' guild has put out a contract that bears your name', 'Shadowy figures lurk in alleyways, watching your every move', 'The black market thrives under the cover of night, offering forbidden luxuries', 'A notorious crime lord has taken an interest in your activities', 'Corrupt guards demand tribute while turning a blind eye to greater crimes', 'Strange runes appear on your bedroom wall, glowing with ethereal light', 'An ancient prophecy speaks of a hero who matches your description exactly', 'Ghostly apparitions warn of impending doom in fevered dreams', 'A witch in the woods offers you power beyond mortal comprehension', 'Cursed artifacts surface in the market, promising great power at terrible cost', 'Your past sins come back to haunt you in the most unexpected ways', 'A long-lost relative appears with a tale that shakes your world', 'Your reputation draws admirers and enemies in equal measure', 'A betrayal cuts deeper than any blade, leaving scars on your soul', 'Love and ambition war within your heart as opportunities arise', 'Ancient ruins whisper secrets to those brave enough to listen', 'A dragon\'s hoard lies hidden, protected by trials and tribulations', 'Bandits rule the roads, but their leader seems oddly familiar', 'A legendary artifact calls to you from across distant lands', 'The wilderness holds both peril and promise for the bold adventurer', 'Romantic entanglements complicate your carefully laid plans', 'Old friends become new enemies as loyalties are tested', 'Family secrets emerge that threaten to destroy everything you hold dear', 'Mentors offer wisdom that comes with strings attached', 'Rivals emerge from unexpected places, challenging your hard-won position', 'The market crashes send shockwaves through the merchant class', 'A get-rich-quick scheme promises fortunes but demands your soul', 'Trade wars erupt between rival merchant houses', 'Investment opportunities arise that could make or break your fortune', 'Black market deals offer power but carry the weight of damnation', 'War drums beat as kingdoms prepare for inevitable conflict', 'Desertion offers freedom but brands you a coward forever', 'A duel of honor is proposed, with your reputation on the line', 'Mercenary companies seek captains brave enough to lead them', 'Battle scars tell stories of glory and horror in equal measure', 'The veil between worlds thins, allowing magic to seep into reality', 'Curses and blessings intertwine in ways you never expected', 'Ancient bloodlines awaken powers dormant for generations', 'Rituals performed in secret grant power at terrible personal cost', 'The stars themselves seem to conspire in your favor or against you', 'Winter\'s cruel bite forces desperate measures from the populace', 'Spring\'s renewal brings both hope and dangerous new beginnings', 'Summer tournaments test the mettle of warriors and nobles alike', 'Autumn harvests reveal secrets long buried in the fields', 'The changing seasons mirror the turmoil in your own life', 'What seems like a blessing reveals itself as a curse in disguise', 'Enemies become allies, and allies become your greatest threat', 'The path of righteousness leads to ruin, while villainy brings reward', 'Fate itself seems to take notice of your actions, for good or ill', 'The world bends around you as your choices reshape reality itself'],
988
+ 'sci-fi': ['Megacorporations wage shadow wars through proxy conflicts and data manipulation', 'Neural implants malfunction, flooding your mind with corporate secrets', 'A black-market AI offers forbidden knowledge at the cost of your sanity', 'Corporate espionage turns deadly when rival agents converge on your location', 'Whistleblower data reveals systemic corruption in the highest levels of power', 'Hackers breach your personal network, exposing vulnerabilities you never knew existed', 'Street gangs control the undercity with drone swarms and illegal augmentations', 'The dark web pulses with illegal tech trades and forbidden experiments', 'Corporate bounty hunters track you through the neon-lit sprawl', 'Data runners risk everything for the ultimate information score', 'Alien artifacts whisper secrets from beyond the galactic rim', 'Space pirates demand tribute or face the void of decompression', 'Ancient derelict ships hold treasures and horrors from forgotten eras', 'Wormhole anomalies bend reality, creating unpredictable temporal events', 'Colony worlds rebel against Earth\'s iron-fisted governance', 'Sentient AIs manipulate events from within the global network', 'Nanobot swarms escape containment, evolving beyond their programming', 'Virtual reality simulations bleed into the real world disastrously', 'Genetic engineering experiments create monstrous hybrid beings', 'Quantum computers predict the future, but at what cost to free will?', 'Social credit systems reward compliance and punish deviation', 'Surveillance drones watch every move, every transaction, every thought', 'Rebellions simmer beneath the surface of totalitarian control', 'Resource wars rage over the last viable mining asteroids', 'Climate engineering projects backfire spectacularly', 'Implant malfunctions cause vivid hallucinations and system crashes', 'Identity theft becomes literal as someone steals your digital consciousness', 'Memory wipes erase crucial knowledge, leaving you vulnerable', 'Cybernetic enhancements demand maintenance that costs more than you can afford', 'Neural links create unintended telepathic connections with strangers', 'Cryptocurrency markets crash, wiping out fortunes in digital dust', 'Hostile takeovers turn friendly acquisitions into bloody boardroom coups', 'Trade wars erupt between orbital habitats and planetary governments', 'Investment opportunities in black-market tech promise riches or ruin', 'Corporate espionage turns personal when family members are leveraged', 'Drone wars rage in the skies above abandoned cities', 'Cyber warfare disables entire infrastructure networks', 'Private military companies offer their services to the highest bidder', 'Nuclear deterrence fails when EMP weapons render missiles useless', 'Bioterrorism releases engineered plagues upon unsuspecting populations', 'Government cover-ups hide the truth about alien visitations', 'Time travel experiments create paradoxical timeline fractures', 'Parallel dimensions bleed through, creating impossible phenomena', 'Ancient alien technology reactivates with catastrophic consequences', 'Conspiracy theories prove true, but the reality is far worse', 'Terraforming projects unleash ancient microbes from the soil', 'Climate control systems fail, creating unpredictable weather patterns', 'Asteroid mining operations awaken dormant extraterrestrial threats', 'Ocean acidification drives aquatic mutations to the surface', 'Atmospheric processors malfunction, creating toxic breathing conditions'],
989
+ historical: ['The king\'s advisors plot in shadowed corners of the great hall', 'Noble houses form secret alliances against the crown', 'Whispers of heresy spread through the royal court like wildfire', 'A foreign diplomat offers treacherous propositions under diplomatic immunity', 'Court jesters hide dangerous truths behind masks of folly', 'Armies mass at the borders, their banners fluttering in the wind of war', 'Siege engines pound ancient walls as defenders hold the line', 'Cavalry charges break enemy formations in clouds of dust and blood', 'Naval blockades starve cities into submission or desperate rebellion', 'Mercenary companies switch sides based on the highest bidder', 'New World expeditions return with gold and strange diseases', 'Ancient artifacts surface from archaeological digs, rewriting history', 'Trade caravans brave bandits and harsh terrains for exotic goods', 'Mapping expeditions chart unknown territories and hostile natives', 'Scientific discoveries challenge religious doctrines and established truths', 'Peasant revolts spread like contagion through the countryside', 'Guilds clash over trade monopolies and apprenticeship rights', 'Religious schisms divide communities along ideological lines', 'Women maneuver within restrictive social structures for power and influence', 'Immigrants bring new customs that clash with traditional ways', 'Market monopolies drive independent merchants to desperation', 'Banking houses manipulate currency values for political gain', 'Trade embargoes create black markets and smuggling operations', 'Agricultural failures lead to famines and social unrest', 'Colonial exploitation enriches the crown while impoverishing subjects', 'Treaty negotiations mask underlying territorial ambitions', 'Spy networks weave webs of deception across national borders', 'Succession crises threaten to plunge nations into civil war', 'Diplomatic incidents escalate into full-scale military conflicts', 'Royal marriages forge alliances that crumble under stress', 'Inquisitions root out heresy with fire and torture', 'Crusades call warriors to distant lands for faith and glory', 'Reformation movements challenge the authority of established churches', 'Cult leaders promise salvation through devotion and sacrifice', 'Religious relics inspire pilgrimages and bloody conflicts', 'Family feuds span generations, poisoning bloodlines with vengeance', 'Scandals rock aristocratic families, threatening social standing', 'Personal ambitions clash with familial duties and expectations', 'Love affairs defy social conventions and familial arrangements', 'Betrayals cut deeper than any blade, leaving lasting scars', 'Plagues sweep through densely packed cities, claiming thousands', 'Famines force desperate migrations and social breakdowns', 'Natural disasters reveal underlying social and political tensions', 'Harsh winters test the limits of human endurance and charity', 'Droughts drive conflicts over dwindling water resources', 'Scientific discoveries revolutionize warfare and exploration', 'Technological innovations disrupt traditional crafts and livelihoods', 'Medical breakthroughs save lives but challenge religious views', 'Educational reforms open knowledge to new social classes', 'Engineering marvels push the boundaries of human capability']
1033
990
  };
1034
-
1035
- // Cultural variants within themes
1036
991
  this.cultures = {
1037
992
  fantasy: {
1038
993
  norse: ['The longships sail into the fjord under the northern lights', 'Runes carved in ancient stone whisper forgotten secrets', 'The mead hall echoes with tales of heroic deeds and tragic fates', 'Berserkers rage through the village leaving destruction in their wake', 'The gods themselves seem to take notice of mortal affairs', 'Viking raiders demand tribute or face the wrath of the axe', 'Shamanic visions reveal the threads of fate woven by the Norns', 'The sacred grove hides a portal to the realm of the Aesir', 'Blood oaths bind warriors to quests of honor and vengeance', 'Thunder rolls as Thor\'s hammer strikes down the unworthy'],
@@ -1051,8 +1006,6 @@ class RPGEventGenerator {
1051
1006
  ancient_roman: ['Gladiators fight for glory in the Colosseum\'s sandy arena', 'The Roman Senate debates matters of republic and empire', 'Barbarian hordes threaten the borders of civilized lands', 'The aqueducts carry water across vast engineering marvels', 'Political assassinations reshape the corridors of power', 'Slave revolts challenge the foundations of imperial society', 'The gods demand tribute through elaborate public ceremonies', 'Military legions march under eagles forged in sacred fires', 'Patrician families feud over matters of honor and inheritance', 'The imperial palace echoes with plots and betrayals']
1052
1007
  }
1053
1008
  };
1054
-
1055
- // Seasonal and time-based event templates
1056
1009
  this.seasonalEvents = {
1057
1010
  spring: {
1058
1011
  templates: ['BLOOMING_ROMANCE', 'SPRING_FESTIVAL', 'NEW_BEGINNINGS'],
@@ -1088,8 +1041,6 @@ class RPGEventGenerator {
1088
1041
  }
1089
1042
  }
1090
1043
  };
1091
-
1092
- // Time-based event chains (events that evolve over time)
1093
1044
  this.timeBasedEventChains = {
1094
1045
  POLITICAL_UPRISING: {
1095
1046
  name: 'Political Uprising',
@@ -1281,8 +1232,6 @@ class RPGEventGenerator {
1281
1232
  }
1282
1233
  };
1283
1234
  this.activeChains.set(chain.id, chain);
1284
-
1285
- // Generate first event in chain
1286
1235
  return this.generateChainEvent(chain);
1287
1236
  }
1288
1237
 
@@ -1326,20 +1275,15 @@ class RPGEventGenerator {
1326
1275
  if (!chain) return null;
1327
1276
  const chainDef = this.chainDefinitions[chain.definition];
1328
1277
  const currentStage = chainDef.stages[chain.stage];
1329
-
1330
- // Check if current stage triggers next based on choice
1331
1278
  if (currentStage.triggerNext && currentStage.triggerNext.choice === choice) {
1332
1279
  chain.stage++;
1333
1280
  chain.playerContext = {
1334
1281
  ...chain.playerContext,
1335
1282
  lastChoice: choice
1336
1283
  };
1337
-
1338
- // Schedule next event for game integration
1339
1284
  if (chain.stage < chainDef.stages.length) {
1340
1285
  chain.nextEventTime = this.timeSystem.currentDay + currentStage.triggerNext.delay;
1341
1286
  chain.nextEventTemplate = chainDef.stages[chain.stage].template;
1342
- // In a real game, save this chain state and check for due events on each game day
1343
1287
  }
1344
1288
  return this.generateChainEvent(chain);
1345
1289
  }
@@ -1383,8 +1327,6 @@ class RPGEventGenerator {
1383
1327
  day: this.timeSystem.currentDay
1384
1328
  });
1385
1329
  }
1386
-
1387
- // Check for time-based event triggers
1388
1330
  const dayEvents = this.checkTimeBasedEventTriggers();
1389
1331
  triggeredEvents.push(...dayEvents);
1390
1332
  }
@@ -2160,8 +2102,6 @@ class RPGEventGenerator {
2160
2102
  weights.DESERTION_TEMPTATION *= 1.5;
2161
2103
  }
2162
2104
  }
2163
-
2164
- // Age-based modifiers
2165
2105
  if (context.age < 25) {
2166
2106
  weights.FORBIDDEN_LOVE *= 1.6;
2167
2107
  weights.FAMILY_SECRET *= 1.4;
@@ -2169,21 +2109,15 @@ class RPGEventGenerator {
2169
2109
  weights.GHOSTLY_VISITATION *= 1.8;
2170
2110
  weights.FAMILY_SECRET *= 1.6;
2171
2111
  }
2172
-
2173
- // Wealth-based modifiers
2174
2112
  if (context.wealth > 1000) {
2175
2113
  weights.MARKET_CRASH *= 1.8;
2176
2114
  weights.TRADE_WAR *= 1.6;
2177
2115
  weights.BLACKMAIL_OPPORTUNITY *= 1.4;
2178
2116
  }
2179
-
2180
- // Influence-based modifiers
2181
2117
  if (context.influence > 50) {
2182
2118
  weights.COURT_SCANDAL *= 2.0;
2183
2119
  weights.NOBLE_DUEL *= 1.8;
2184
2120
  }
2185
-
2186
- // Skill-based modifiers
2187
2121
  if (context.skills.combat > 60) {
2188
2122
  weights.NOBLE_DUEL *= 1.6;
2189
2123
  weights.MERCENARY_CONTRACT *= 1.4;
@@ -2196,21 +2130,15 @@ class RPGEventGenerator {
2196
2130
  weights.THIEVES_GUILD *= 1.7;
2197
2131
  weights.BLACKMAIL_OPPORTUNITY *= 1.5;
2198
2132
  }
2199
-
2200
- // Reputation-based modifiers
2201
2133
  if (context.reputation < -20) {
2202
2134
  weights.THIEVES_GUILD *= 1.8;
2203
2135
  weights.BLACKMAIL_OPPORTUNITY *= 2.0;
2204
2136
  }
2205
-
2206
- // Relationship-based modifiers
2207
2137
  if (context.relationships && context.relationships.length > 3) {
2208
2138
  weights.FORBIDDEN_LOVE *= 1.4;
2209
2139
  weights.FAMILY_SECRET *= 1.6;
2210
2140
  weights.COURT_SCANDAL *= 1.3;
2211
2141
  }
2212
-
2213
- // Seasonal modifiers
2214
2142
  if (context.season === 'winter') {
2215
2143
  weights.GHOSTLY_VISITATION *= 1.5;
2216
2144
  weights.ANCIENT_CURSE *= 1.3;
@@ -2300,21 +2228,15 @@ class RPGEventGenerator {
2300
2228
  additions.push('The battlefield calls, and honor demands a response.');
2301
2229
  }
2302
2230
  }
2303
-
2304
- // Age-based additions
2305
2231
  if (context.age < 25) {
2306
2232
  additions.push('At your young age, this experience could shape your entire future.');
2307
2233
  } else if (context.age > 60) {
2308
2234
  additions.push('With age comes wisdom, but also the weight of past decisions.');
2309
2235
  }
2310
-
2311
- // Relationship-based additions
2312
2236
  if (context.relationships && context.relationships.length > 0) {
2313
2237
  additions.push('Your personal connections may influence how this unfolds.');
2314
2238
  additions.push('Someone you know is intimately involved in this matter.');
2315
2239
  }
2316
-
2317
- // Seasonal additions
2318
2240
  if (context.season) {
2319
2241
  const seasonAdditions = {
2320
2242
  winter: 'The harsh winter weather makes resolution all the more urgent.',
@@ -2591,6 +2513,589 @@ class RPGEventGenerator {
2591
2513
  });
2592
2514
  this.addTrainingData(data);
2593
2515
  }
2516
+
2517
+ /**
2518
+ * Load default English locale
2519
+ * @private
2520
+ */
2521
+ loadDefaultLocale() {
2522
+ this.locales.set('en', {
2523
+ templates: {},
2524
+ trainingData: [],
2525
+ ui: {
2526
+ 'event.title.default': 'Unexpected Event',
2527
+ 'event.description.default': 'Something unexpected occurs...',
2528
+ 'choice.accept': 'Accept',
2529
+ 'choice.decline': 'Decline',
2530
+ 'choice.fight': 'Fight',
2531
+ 'choice.flee': 'Flee',
2532
+ 'choice.negotiate': 'Negotiate'
2533
+ },
2534
+ culture: {
2535
+ nameFormats: ['western'],
2536
+ dateFormats: ['MM/DD/YYYY'],
2537
+ currencySymbols: ['$'],
2538
+ honorifics: ['Sir', 'Lady', 'Lord']
2539
+ }
2540
+ });
2541
+ }
2542
+
2543
+ /**
2544
+ * Load a language pack
2545
+ * @param {string} language - Language code
2546
+ * @param {Object} languagePack - Language pack data
2547
+ */
2548
+ loadLanguagePack(language, languagePack) {
2549
+ this.locales.set(language, languagePack);
2550
+ }
2551
+
2552
+ /**
2553
+ * Set the current language
2554
+ * @param {string} language - Language code
2555
+ */
2556
+ setLanguage(language) {
2557
+ if (this.locales.has(language)) {
2558
+ this.language = language;
2559
+ } else {
2560
+ console.warn(`Language '${language}' not loaded, staying with '${this.language}'`);
2561
+ }
2562
+ }
2563
+
2564
+ /**
2565
+ * Get translated text
2566
+ * @param {string} key - Translation key
2567
+ * @param {Object} variables - Substitution variables
2568
+ * @returns {string} Translated text
2569
+ */
2570
+ translate(key, variables = {}) {
2571
+ const locale = this.locales.get(this.language) || this.locales.get('en');
2572
+ if (!locale || !locale.ui[key]) {
2573
+ return key;
2574
+ }
2575
+ let text = locale.ui[key];
2576
+ Object.entries(variables).forEach(([varKey, value]) => {
2577
+ text = text.replace(new RegExp(`{{${varKey}}}`, 'g'), value);
2578
+ });
2579
+ return text;
2580
+ }
2581
+
2582
+ /**
2583
+ * Initialize built-in modifiers
2584
+ * @private
2585
+ */
2586
+ initializeBuiltInModifiers() {
2587
+ this.modifiers.set('rain', {
2588
+ type: 'weather',
2589
+ effects: {
2590
+ visibility: 0.7,
2591
+ movement_penalty: 0.2,
2592
+ encounter_rate: 0.8,
2593
+ health_drain: 2
2594
+ },
2595
+ text_modifiers: {
2596
+ atmosphere: 'dismal',
2597
+ add_descriptors: ['wet', 'rainy']
2598
+ }
2599
+ });
2600
+ this.modifiers.set('storm', {
2601
+ type: 'weather',
2602
+ effects: {
2603
+ visibility: 0.4,
2604
+ movement_penalty: 0.5,
2605
+ encounter_rate: 1.3,
2606
+ health_drain: 5
2607
+ },
2608
+ text_modifiers: {
2609
+ atmosphere: 'chaotic',
2610
+ add_descriptors: ['thunderous', 'tempestuous']
2611
+ }
2612
+ });
2613
+ this.modifiers.set('winter', {
2614
+ type: 'season',
2615
+ effects: {
2616
+ cold_modifier: 1.5,
2617
+ movement_penalty: 0.2
2618
+ },
2619
+ text_modifiers: {
2620
+ add_descriptors: ['frozen', 'harsh'],
2621
+ atmosphere: 'bleak'
2622
+ }
2623
+ });
2624
+ this.modifiers.set('summer', {
2625
+ type: 'season',
2626
+ effects: {
2627
+ heat_modifier: 1.3,
2628
+ energy_bonus: 10
2629
+ },
2630
+ text_modifiers: {
2631
+ add_descriptors: ['sunny', 'warm'],
2632
+ atmosphere: 'energetic'
2633
+ }
2634
+ });
2635
+ }
2636
+
2637
+ /**
2638
+ * Activate environmental modifiers
2639
+ * @param {Object} context - Environmental context
2640
+ */
2641
+ setEnvironmentalContext(context) {
2642
+ if (!this.enableModifiers) return;
2643
+ this.activeModifiers.clear();
2644
+ if (context.weather && this.modifiers.has(context.weather)) {
2645
+ this.activeModifiers.add(context.weather);
2646
+ }
2647
+ if (context.season && this.modifiers.has(context.season)) {
2648
+ this.activeModifiers.add(context.season);
2649
+ }
2650
+ }
2651
+
2652
+ /**
2653
+ * Apply active modifiers to an event
2654
+ * @param {Object} event - Event to modify
2655
+ * @returns {Object} Modified event
2656
+ */
2657
+ applyModifiers(event) {
2658
+ if (!this.enableModifiers || this.activeModifiers.size === 0) {
2659
+ return event;
2660
+ }
2661
+ let modifiedEvent = {
2662
+ ...event
2663
+ };
2664
+ const modifierOrder = ['storm', 'rain', 'winter', 'summer', 'spring', 'autumn'];
2665
+ const orderedModifiers = Array.from(this.activeModifiers).sort((a, b) => {
2666
+ const aIndex = modifierOrder.indexOf(a);
2667
+ const bIndex = modifierOrder.indexOf(b);
2668
+ return (aIndex === -1 ? 999 : aIndex) - (bIndex === -1 ? 999 : bIndex);
2669
+ });
2670
+ for (const modifierId of orderedModifiers) {
2671
+ const modifier = this.modifiers.get(modifierId);
2672
+ if (modifier) {
2673
+ modifiedEvent = this.applySingleModifier(modifiedEvent, modifier);
2674
+ }
2675
+ }
2676
+ return modifiedEvent;
2677
+ }
2678
+
2679
+ /**
2680
+ * Apply a single modifier to an event
2681
+ * @private
2682
+ * @param {Object} event - Event to modify
2683
+ * @param {Object} modifier - Modifier to apply
2684
+ * @returns {Object} Modified event
2685
+ */
2686
+ applySingleModifier(event, modifier) {
2687
+ const modifiedEvent = {
2688
+ ...event
2689
+ };
2690
+ if (modifier.effects && modifiedEvent.choices) {
2691
+ modifiedEvent.choices = modifiedEvent.choices.map(choice => {
2692
+ const modifiedChoice = {
2693
+ ...choice,
2694
+ effect: {
2695
+ ...choice.effect
2696
+ }
2697
+ };
2698
+ if (modifier.effects.movement_penalty && modifiedChoice.effect.movement !== undefined) {
2699
+ modifiedChoice.effect.movement *= 1 - modifier.effects.movement_penalty;
2700
+ }
2701
+ if (modifier.effects.health_drain) {
2702
+ modifiedChoice.effect.health = (modifiedChoice.effect.health || 0) - modifier.effects.health_drain;
2703
+ }
2704
+ if (modifier.effects.cold_modifier && modifiedChoice.effect.health !== undefined) {
2705
+ modifiedChoice.effect.health = Math.floor(modifiedChoice.effect.health * modifier.effects.cold_modifier);
2706
+ }
2707
+ return modifiedChoice;
2708
+ });
2709
+ }
2710
+ if (modifier.text_modifiers) {
2711
+ if (modifier.text_modifiers.atmosphere) {
2712
+ const atmospheres = {
2713
+ 'dismal': ' under gloomy skies',
2714
+ 'chaotic': ' amidst the chaos',
2715
+ 'bleak': ' in the bleak cold',
2716
+ 'energetic': ' with vibrant energy'
2717
+ };
2718
+ const atmosphereText = atmospheres[modifier.text_modifiers.atmosphere];
2719
+ if (atmosphereText && !modifiedEvent.description.includes(atmosphereText)) {
2720
+ modifiedEvent.description += atmosphereText;
2721
+ }
2722
+ }
2723
+ }
2724
+ return modifiedEvent;
2725
+ }
2726
+
2727
+ /**
2728
+ * Register an event dependency
2729
+ * @param {string} eventId - Event identifier
2730
+ * @param {Object} dependencyConfig - Dependency configuration
2731
+ */
2732
+ registerEventDependency(eventId, dependencyConfig) {
2733
+ if (!this.enableDependencies) {
2734
+ console.warn('Dependencies feature is disabled');
2735
+ return;
2736
+ }
2737
+ this.dependencies.set(eventId, dependencyConfig);
2738
+ }
2739
+
2740
+ /**
2741
+ * Check if event dependencies are met
2742
+ * @param {string} eventId - Event identifier
2743
+ * @param {Object} gameState - Current game state
2744
+ * @returns {boolean} True if dependencies are met
2745
+ */
2746
+ checkEventDependencies(eventId, gameState) {
2747
+ if (!this.enableDependencies) return true;
2748
+ const dependency = this.dependencies.get(eventId);
2749
+ if (!dependency) return true;
2750
+ return this.evaluateDependencyCondition(dependency, gameState);
2751
+ }
2752
+
2753
+ /**
2754
+ * Evaluate a dependency condition
2755
+ * @private
2756
+ * @param {Object} condition - Condition to evaluate
2757
+ * @param {Object} gameState - Current game state
2758
+ * @returns {boolean} Evaluation result
2759
+ */
2760
+ evaluateDependencyCondition(condition, gameState) {
2761
+ if (condition.operator) {
2762
+ return this.evaluateDependencyOperator(condition, gameState);
2763
+ }
2764
+ return this.evaluateSingleDependency(condition, gameState);
2765
+ }
2766
+
2767
+ /**
2768
+ * Evaluate operator-based dependency conditions
2769
+ * @private
2770
+ * @param {Object} condition - Operator condition
2771
+ * @param {Object} gameState - Current game state
2772
+ * @returns {boolean} Evaluation result
2773
+ */
2774
+ evaluateDependencyOperator(condition, gameState) {
2775
+ const {
2776
+ operator,
2777
+ conditions
2778
+ } = condition;
2779
+ switch (operator.toUpperCase()) {
2780
+ case 'AND':
2781
+ return conditions.every(cond => this.evaluateDependencyCondition(cond, gameState));
2782
+ case 'OR':
2783
+ return conditions.some(cond => this.evaluateDependencyCondition(cond, gameState));
2784
+ default:
2785
+ return false;
2786
+ }
2787
+ }
2788
+
2789
+ /**
2790
+ * Evaluate a single dependency condition
2791
+ * @private
2792
+ * @param {Object} condition - Single condition
2793
+ * @param {Object} gameState - Current game state
2794
+ * @returns {boolean} Evaluation result
2795
+ */
2796
+ evaluateSingleDependency(condition, gameState) {
2797
+ const {
2798
+ type
2799
+ } = condition;
2800
+ switch (type) {
2801
+ case 'event_completed':
2802
+ const completedEvents = gameState.completedEvents || new Set();
2803
+ return condition.eventIds ? condition.eventIds.every(id => completedEvents.has(id)) : completedEvents.has(condition.eventId);
2804
+ case 'stat_requirement':
2805
+ const playerStats = gameState.player || {};
2806
+ const statValue = playerStats[condition.stat] || 0;
2807
+ const minReq = condition.min || 0;
2808
+ const maxReq = condition.max;
2809
+ return statValue >= minReq && (maxReq === undefined || statValue <= maxReq);
2810
+ default:
2811
+ return false;
2812
+ }
2813
+ }
2814
+
2815
+ /**
2816
+ * Initialize relationship rules
2817
+ * @private
2818
+ */
2819
+ initializeRelationshipRules() {
2820
+ this.relationshipRules = new Map();
2821
+ this.relationshipRules.set('help_combat', {
2822
+ change: 15,
2823
+ reason: 'aided in battle'
2824
+ });
2825
+ this.relationshipRules.set('save_life', {
2826
+ change: 25,
2827
+ reason: 'life saved'
2828
+ });
2829
+ this.relationshipRules.set('betray_trust', {
2830
+ change: -30,
2831
+ reason: 'betrayed trust'
2832
+ });
2833
+ }
2834
+
2835
+ /**
2836
+ * Add an NPC to the relationship system
2837
+ * @param {Object} npcConfig - NPC configuration
2838
+ */
2839
+ addNPC(npcConfig) {
2840
+ if (!this.enableRelationships) {
2841
+ console.warn('Relationships feature is disabled');
2842
+ return;
2843
+ }
2844
+ this.relationships.set(npcConfig.id, {
2845
+ id: npcConfig.id,
2846
+ name: npcConfig.name,
2847
+ type: npcConfig.type,
2848
+ relationships: new Map(),
2849
+ history: [],
2850
+ createdAt: Date.now()
2851
+ });
2852
+ }
2853
+
2854
+ /**
2855
+ * Update NPC relationship
2856
+ * @param {string} npcId - NPC identifier
2857
+ * @param {string} targetId - Target NPC (usually player)
2858
+ * @param {number} change - Relationship change
2859
+ * @param {string} reason - Reason for change
2860
+ */
2861
+ updateRelationship(npcId, targetId, change, reason) {
2862
+ if (!this.enableRelationships) return;
2863
+ const npc = this.relationships.get(npcId);
2864
+ if (!npc) return;
2865
+ if (!npc.relationships.has(targetId)) {
2866
+ npc.relationships.set(targetId, {
2867
+ strength: 0,
2868
+ type: 'acquaintance'
2869
+ });
2870
+ }
2871
+ const relationship = npc.relationships.get(targetId);
2872
+ relationship.strength = Math.max(-100, Math.min(100, relationship.strength + change));
2873
+ npc.history.push({
2874
+ timestamp: Date.now(),
2875
+ targetId,
2876
+ change,
2877
+ newStrength: relationship.strength,
2878
+ reason
2879
+ });
2880
+ }
2881
+
2882
+ /**
2883
+ * Apply relationship evolution rule
2884
+ * @param {string} npcId - NPC affected
2885
+ * @param {string} targetId - Target NPC
2886
+ * @param {string} ruleId - Evolution rule
2887
+ */
2888
+ applyRelationshipRule(npcId, targetId, ruleId) {
2889
+ if (!this.enableRelationships) return;
2890
+ const rule = this.relationshipRules.get(ruleId);
2891
+ if (rule) {
2892
+ this.updateRelationship(npcId, targetId, rule.change, rule.reason);
2893
+ }
2894
+ }
2895
+
2896
+ /**
2897
+ * Get relationship data between two NPCs
2898
+ * @param {string} npcId - NPC identifier
2899
+ * @param {string} targetId - Target NPC
2900
+ * @returns {Object} Relationship data or null
2901
+ */
2902
+ getRelationship(npcId, targetId) {
2903
+ if (!this.enableRelationships) return null;
2904
+ const npc = this.relationships.get(npcId);
2905
+ if (!npc) return null;
2906
+ return npc.relationships.get(targetId) || null;
2907
+ }
2908
+
2909
+ /**
2910
+ * Enhanced event generation with all features
2911
+ * @param {Object} context - Generation context
2912
+ * @returns {Object} Generated event
2913
+ */
2914
+ generateEnhancedEvent(context = {}) {
2915
+ const event = this.generateEvent(context.player || context);
2916
+ let enhancedEvent = event;
2917
+ if (this.enableModifiers) {
2918
+ this.setEnvironmentalContext(context.environment || {});
2919
+ enhancedEvent = this.applyModifiers(event);
2920
+ }
2921
+ if (this.enableDependencies && context.gameState) {}
2922
+ if (this.enableRelationships && context.player) {
2923
+ enhancedEvent = this.addRelationshipContext(enhancedEvent, context.player);
2924
+ }
2925
+ return enhancedEvent;
2926
+ }
2927
+
2928
+ /**
2929
+ * Get relationship data between two NPCs
2930
+ * @param {string} npcId - NPC identifier
2931
+ * @param {string} targetId - Target NPC
2932
+ * @returns {Object} Relationship data or null
2933
+ */
2934
+ getRelationship(npcId, targetId) {
2935
+ if (!this.enableRelationships) return null;
2936
+ const npc = this.relationships.get(npcId);
2937
+ if (!npc) return null;
2938
+ return npc.relationships.get(targetId) || null;
2939
+ }
2940
+
2941
+ /**
2942
+ * Get relationship summary for an NPC
2943
+ * @param {string} npcId - NPC identifier
2944
+ * @returns {Object} Relationship summary
2945
+ */
2946
+ getRelationshipSummary(npcId) {
2947
+ if (!this.enableRelationships) return {
2948
+ totalRelationships: 0,
2949
+ averageStrength: 0,
2950
+ allyCount: 0,
2951
+ enemyCount: 0,
2952
+ neutralCount: 0
2953
+ };
2954
+ const npc = this.relationships.get(npcId);
2955
+ if (!npc) return {
2956
+ totalRelationships: 0,
2957
+ averageStrength: 0,
2958
+ allyCount: 0,
2959
+ enemyCount: 0,
2960
+ neutralCount: 0
2961
+ };
2962
+ const relationships = Array.from(npc.relationships.values());
2963
+ const summary = {
2964
+ totalRelationships: relationships.length,
2965
+ averageStrength: 0,
2966
+ allyCount: 0,
2967
+ enemyCount: 0,
2968
+ neutralCount: 0
2969
+ };
2970
+ if (relationships.length > 0) {
2971
+ const totalStrength = relationships.reduce((sum, rel) => sum + rel.strength, 0);
2972
+ summary.averageStrength = totalStrength / relationships.length;
2973
+ relationships.forEach(rel => {
2974
+ if (rel.strength > 50) summary.allyCount++;else if (rel.strength < -30) summary.enemyCount++;else summary.neutralCount++;
2975
+ });
2976
+ }
2977
+ return summary;
2978
+ }
2979
+
2980
+ /**
2981
+ * Get relationship network around an NPC
2982
+ * @param {string} npcId - Central NPC
2983
+ * @param {number} depth - Network depth (default: 1)
2984
+ * @returns {Object} Relationship network
2985
+ */
2986
+ getRelationshipNetwork(npcId, depth = 1) {
2987
+ if (!this.enableRelationships) return {
2988
+ nodes: new Map(),
2989
+ edges: []
2990
+ };
2991
+ const network = {
2992
+ center: npcId,
2993
+ nodes: new Map(),
2994
+ edges: []
2995
+ };
2996
+ const visited = new Set();
2997
+ const queue = [{
2998
+ id: npcId,
2999
+ currentDepth: 0
3000
+ }];
3001
+ while (queue.length > 0) {
3002
+ const {
3003
+ id,
3004
+ currentDepth
3005
+ } = queue.shift();
3006
+ if (visited.has(id) || currentDepth > depth) continue;
3007
+ visited.add(id);
3008
+ const npc = this.relationships.get(id);
3009
+ if (!npc) continue;
3010
+ network.nodes.set(id, {
3011
+ id,
3012
+ name: npc.name,
3013
+ type: npc.type,
3014
+ relationshipCount: npc.relationships.size
3015
+ });
3016
+ for (const [targetId, relationship] of npc.relationships) {
3017
+ network.edges.push({
3018
+ source: id,
3019
+ target: targetId,
3020
+ type: relationship.type,
3021
+ strength: relationship.strength,
3022
+ trust: relationship.trust || 50,
3023
+ respect: relationship.respect || 50
3024
+ });
3025
+ if (!visited.has(targetId) && currentDepth < depth) {
3026
+ queue.push({
3027
+ id: targetId,
3028
+ currentDepth: currentDepth + 1
3029
+ });
3030
+ }
3031
+ }
3032
+ }
3033
+ return network;
3034
+ }
3035
+
3036
+ /**
3037
+ * Register a custom modifier
3038
+ * @param {string} modifierId - Modifier identifier
3039
+ * @param {Object} modifierConfig - Modifier configuration
3040
+ */
3041
+ registerModifier(modifierId, modifierConfig) {
3042
+ if (!this.enableModifiers) {
3043
+ console.warn('Modifiers feature is disabled');
3044
+ return;
3045
+ }
3046
+ this.modifiers.set(modifierId, {
3047
+ id: modifierId,
3048
+ ...modifierConfig,
3049
+ registeredAt: Date.now()
3050
+ });
3051
+ }
3052
+
3053
+ /**
3054
+ * Get system status information
3055
+ * @returns {Object} System status
3056
+ */
3057
+ getSystemStatus() {
3058
+ return {
3059
+ version: '1.2.0',
3060
+ language: this.language,
3061
+ availableLanguages: Array.from(this.locales.keys()),
3062
+ modifiersEnabled: this.enableModifiers,
3063
+ relationshipsEnabled: this.enableRelationships,
3064
+ dependenciesEnabled: this.enableDependencies,
3065
+ totalNPCs: this.enableRelationships ? this.relationships.size : 0,
3066
+ activeModifiers: this.enableModifiers ? Array.from(this.activeModifiers) : [],
3067
+ totalLocales: this.locales.size,
3068
+ timeSystem: {
3069
+ currentDay: this.timeSystem.currentDay,
3070
+ currentSeason: this.timeSystem.currentSeason
3071
+ }
3072
+ };
3073
+ }
3074
+
3075
+ /**
3076
+ * Add relationship context to event
3077
+ * @private
3078
+ * @param {Object} event - Event to enhance
3079
+ * @param {Object} player - Player data
3080
+ * @returns {Object} Enhanced event
3081
+ */
3082
+ addRelationshipContext(event, player) {
3083
+ const enhancedEvent = {
3084
+ ...event
3085
+ };
3086
+ if (event.npcs && event.npcs.length > 0) {
3087
+ event.npcs.forEach(npcId => {
3088
+ const npc = this.relationships.get(npcId);
3089
+ if (npc) {
3090
+ const playerRel = npc.relationships.get('player');
3091
+ if (playerRel && playerRel.strength > 50) {
3092
+ enhancedEvent.description = enhancedEvent.description.replace(new RegExp(npcId, 'gi'), `your ally ${npcId}`);
3093
+ }
3094
+ }
3095
+ });
3096
+ }
3097
+ return enhancedEvent;
3098
+ }
2594
3099
  }
2595
3100
  exports.RPGEventGenerator = RPGEventGenerator;
2596
3101
  function generateRPGEvent(playerContext = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpg-event-generator",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Procedural RPG event generation system for games",
5
5
  "main": "dist/index.js",
6
6
  "files": [