rpg-event-generator 1.1.0 โ†’ 1.1.1

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 +408 -472
  2. package/dist/index.js +36 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,32 +2,18 @@
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
- ## โœจ Features
6
-
7
- - **Infinite Event Generation**: Creates unique, contextual events using custom Markov chains and procedural techniques
8
- - **Player-Aware**: Events adapt to player stats, career, relationships, life stage, reputation, and social standing
9
- - **14+ Dramatic Event Types**: From court scandals and noble duels to ancient curses and bandit kings
10
- - **Immersive Storytelling**: Each event features rich narratives with atmospheric descriptions and meaningful consequences
11
- - **Dynamic Effects**: Context-aware rewards and consequences that scale with character development and power level
12
- - **Career Integration**: Events specifically tailored to noble, merchant, warrior, and criminal careers
13
- - **Relationship Impact**: Events that affect and are affected by your social connections and personal history
14
- - **Seasonal & Location Themes**: Events adapt to time of year and geographical setting for added immersion
15
- - **Consequence Tracking**: Events can have long-term effects on character development and reputation
16
- - **Personality-Driven Choices**: Multiple meaningful choices that define your character's personality and path
17
- - **Quality Filtering**: Built-in filters ensure only interesting, non-generic events are generated
18
- - **Modular Design**: Easy to integrate into existing game systems
19
- - **Highly Configurable**: Customize training data, templates, and generation parameters
20
-
21
- ## ๐Ÿš€ Quick Start
5
+ ## ๐Ÿš€ Installation
22
6
 
23
7
  ```bash
24
8
  npm install rpg-event-generator
25
9
  ```
26
10
 
11
+ ## โœจ Quick Start
12
+
27
13
  ```javascript
28
14
  import { RPGEventGenerator, generateRPGEvent } from 'rpg-event-generator';
29
15
 
30
- // Quick single event
16
+ // Simple event generation
31
17
  const event = generateRPGEvent({
32
18
  age: 25,
33
19
  gold: 500,
@@ -35,65 +21,44 @@ const event = generateRPGEvent({
35
21
  career: 'merchant'
36
22
  });
37
23
 
38
- console.log(event.title); // "Golden Opportunity"
39
- console.log(event.description); // Procedurally generated description
40
- console.log(event.choices); // Array of choices with effects
24
+ console.log(event.title); // "Golden Opportunity"
25
+ console.log(event.description); // Procedurally generated narrative
26
+ console.log(event.choices); // Array of meaningful choices
27
+ ```
41
28
 
42
- // Advanced usage with custom generator
43
- const generator = new RPGEventGenerator({
44
- stateSize: 2,
45
- trainingData: ['Your custom story fragments...']
46
- });
29
+ ## ๐Ÿ“‹ Features
47
30
 
48
- // Generate multiple events
49
- const events = generator.generateEvents({
50
- age: 30,
51
- gold: 1000,
52
- influence: 25,
53
- career: 'knight',
54
- skills: { combat: 60, diplomacy: 40 }
55
- }, 3);
56
- ```
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
57
42
 
58
- ## ๐Ÿ“– Usage Examples
43
+ ## ๐Ÿ“– Usage Guide
59
44
 
60
45
  ### Basic Event Generation
61
46
 
62
47
  ```javascript
63
48
  const generator = new RPGEventGenerator();
64
-
65
- // Generate a random event
66
49
  const event = generator.generateEvent();
67
50
 
68
51
  console.log(event);
69
52
  // {
70
53
  // id: "event_1704567890123_xyz789",
71
54
  // title: "Perilous Bandit King's Challenge",
72
- // description: "The infamous bandit king blocks your path, offering you a choice: join his band or face certain death. Your business interests are directly affected by this development. Choose wisely, for the wrong path leads to ruin.",
73
- // narrative: "The infamous bandit king blocks your path, offering you a choice: join his band or face certain death.",
55
+ // description: "Generated narrative based on Markov chains...",
74
56
  // choices: [
75
- // {
76
- // text: "Join the bandits",
77
- // effect: { gold: 375, reputation: -23, combat_skill: 12 },
78
- // consequence: "bandit"
79
- // },
80
- // {
81
- // text: "Challenge him to single combat",
82
- // effect: { reputation: 32, health: -18 },
83
- // requirements: { combat_skill: 60 },
84
- // consequence: "hero"
85
- // },
86
- // {
87
- // text: "Bribe your way past",
88
- // effect: { gold: -320, safe_passage: true },
89
- // consequence: "diplomat"
90
- // }
57
+ // { text: "Fight back", effect: { health: -20, reputation: 25 } },
58
+ // { text: "Pay tribute", effect: { gold: -200, safe_passage: true } }
91
59
  // ],
92
60
  // type: "BANDIT_KING",
93
- // consequence: null,
94
- // urgency: "normal",
95
- // theme: "adventure",
96
- // context: { /* player context used */ }
61
+ // difficulty: "normal"
97
62
  // }
98
63
  ```
99
64
 
@@ -106,319 +71,43 @@ const playerContext = {
106
71
  influence: 40,
107
72
  reputation: 25,
108
73
  career: 'noble',
109
- skills: {
110
- diplomacy: 70,
111
- combat: 45,
112
- intrigue: 30
113
- },
74
+ skills: { diplomacy: 70, combat: 45, intrigue: 30 },
114
75
  relationships: [
115
- { name: 'Lord Harrington', type: 'ally', relationship: 60 },
116
- { name: 'Lady Beaumont', type: 'lover', relationship: 45 }
76
+ { name: 'Lord Harrington', type: 'ally', relationship: 60 }
117
77
  ],
118
78
  location: 'capital',
119
79
  season: 'winter'
120
80
  };
121
81
 
122
82
  const event = generator.generateEvent(playerContext);
123
- // Generates events like:
124
- // - Diplomatic missions (high diplomacy skill)
125
- // - Court intrigue opportunities (high influence)
126
- // - Social events involving relationships
127
- // - Winter-themed challenges
83
+ // Generates events appropriate to noble career, high influence, winter season
128
84
  ```
129
85
 
130
86
  ### Custom Training Data
131
87
 
88
+ Enhance text generation with your own story fragments:
89
+
132
90
  ```javascript
133
91
  const customTrainingData = [
134
92
  'In the shadowed alleys of the ancient city',
135
- 'The dragon\'s roar echoes through the mountains',
136
- 'Elven merchants display their enchanted wares',
137
- 'A dwarven smith forges weapons of legend',
138
- 'The tavern is filled with adventurers and mercenaries',
139
- 'Ancient runes glow with mystical power',
140
- 'The forest whispers secrets to those who listen'
93
+ 'The dragon\'s roar echoes through the misty mountains',
94
+ 'Elven merchants display their enchanted crystal wares',
95
+ 'A dwarven smith forges weapons of legendary power',
96
+ 'The tavern overflows with adventurers and mysterious strangers',
97
+ 'Ancient runes glow with ethereal magical energy',
98
+ 'The enchanted forest whispers secrets to those who listen carefully'
141
99
  ];
142
100
 
143
101
  const generator = new RPGEventGenerator({
144
102
  trainingData: customTrainingData
145
103
  });
146
- ```
147
-
148
- ## ๐Ÿ”ง API Reference
149
-
150
- ### RPGEventGenerator Class
151
-
152
- #### Constructor Options
153
-
154
- ```javascript
155
- const generator = new RPGEventGenerator({
156
- stateSize: 2, // Markov chain state size (default: 2)
157
- trainingData: [...] // Custom training data array (optional)
158
- });
159
- ```
160
104
 
161
- #### Methods
162
-
163
- - `generateEvent(playerContext)` - Generate a single event
164
- - `generateEvents(playerContext, count)` - Generate multiple events
165
- - `addTrainingData(data)` - Add more training data
166
- - `resetTrainingData(data)` - Reset with new training data
167
-
168
- ### Player Context Object
169
-
170
- ```javascript
171
- {
172
- age: number, // Player age
173
- gold: number, // Player wealth
174
- influence: number, // Political/social influence
175
- reputation: number, // Social reputation
176
- career: string, // Player's career/job
177
- skills: { // Skill levels object
178
- combat: number,
179
- diplomacy: number,
180
- // ... other skills
181
- },
182
- relationships: [{ // Array of relationships
183
- name: string,
184
- type: string, // 'friend', 'lover', 'ally', etc.
185
- relationship: number // Relationship strength (0-100)
186
- }],
187
- location: string, // Current location
188
- season: string // Current season
189
- }
190
- ```
191
-
192
- ### Event Object Structure
193
-
194
- ```javascript
195
- {
196
- id: string, // Unique event identifier
197
- title: string, // Dynamic, context-aware title
198
- description: string, // Rich procedural description
199
- narrative: string, // Core story premise
200
- choices: [{ // Array of meaningful choices
201
- text: string, // Choice text with contextual flavor
202
- effect: { // Effects scaled by context
203
- gold?: number, // Wealth changes
204
- influence?: number, // Social/political power
205
- reputation?: number, // Social standing
206
- health?: number, // Physical well-being
207
- stress?: number, // Mental strain
208
- karma?: number, // Moral standing
209
- // ... many more effects
210
- },
211
- consequence: string // Long-term character effect
212
- }],
213
- type: string, // Rich event category (COURT_SCANDAL, etc.)
214
- consequence: string|null, // Applied consequence after choice
215
- urgency: string, // 'normal', 'high', 'critical'
216
- theme: string, // 'political', 'criminal', 'supernatural', etc.
217
- context: object // Full context used for generation
218
- }
219
- ```
220
-
221
- ## ๐ŸŽฎ Integration Guide
222
-
223
- ### React Native Game Integration
224
-
225
- ```javascript
226
- import React, { useState, useEffect } from 'react';
227
- import { RPGEventGenerator } from 'rpg-event-generator';
228
-
229
- function GameEventSystem({ playerStats }) {
230
- const [currentEvent, setCurrentEvent] = useState(null);
231
- const [generator] = useState(() => new RPGEventGenerator());
232
-
233
- useEffect(() => {
234
- // Generate event when time advances
235
- const event = generator.generateEvent(playerStats);
236
- setCurrentEvent(event);
237
- }, [playerStats, generator]);
238
-
239
- const handleChoice = (choiceIndex) => {
240
- const choice = currentEvent.choices[choiceIndex];
241
- // Apply effects to player stats
242
- applyEffects(choice.effect);
243
- setCurrentEvent(null); // Clear event
244
- };
245
-
246
- if (!currentEvent) return null;
247
-
248
- return (
249
- <EventDialog
250
- event={currentEvent}
251
- onChoice={handleChoice}
252
- />
253
- );
254
- }
255
- ```
256
-
257
- ### Redux Integration
258
-
259
- ```javascript
260
- // Action creators
261
- export const generateEvent = (playerContext) => {
262
- const generator = new RPGEventGenerator();
263
- const event = generator.generateEvent(playerContext);
264
-
265
- return {
266
- type: 'GENERATE_EVENT',
267
- payload: event
268
- };
269
- };
270
-
271
- export const resolveEvent = (eventId, choiceIndex) => ({
272
- type: 'RESOLVE_EVENT',
273
- payload: { eventId, choiceIndex }
274
- });
275
-
276
- // Reducer
277
- const eventReducer = (state = {}, action) => {
278
- switch (action.type) {
279
- case 'GENERATE_EVENT':
280
- return { ...state, currentEvent: action.payload };
281
- case 'RESOLVE_EVENT':
282
- return { ...state, currentEvent: null };
283
- default:
284
- return state;
285
- }
286
- };
287
- ```
288
-
289
- ## ๐Ÿงช Testing
290
-
291
- ```bash
292
- npm test
293
- ```
294
-
295
- The package includes comprehensive tests covering:
296
- - Event generation with various contexts
297
- - Effect resolution
298
- - Markov chain text generation
299
- - Template selection algorithms
300
-
301
- ## ๐ŸŽฏ Event Types
302
-
303
- ### Court & Political (Variable probability)
304
- - **Court Scandal**: Royal court intrigue with betrayal and scandal
305
- - **Noble Duel**: Honor challenges and duels of reputation
306
- - **Market Crash**: Economic disasters affecting trade and wealth
307
- - **Trade War**: Merchant rivalries and economic warfare
308
-
309
- ### Criminal Underworld (Variable probability)
310
- - **Thieves' Guild**: Criminal organization recruitment and underworld dealings
311
- - **Blackmail Opportunity**: Leverage compromising information for gain
312
- - **Bandit King Challenge**: Highway robbery and outlaw confrontations
313
-
314
- ### Supernatural & Mysterious (Variable probability)
315
- - **Ancient Curse**: Cursed artifacts and supernatural afflictions
316
- - **Ghostly Visitation**: Spirits seeking justice or redemption
317
- - **Lost Civilization**: Archaeological discoveries and ancient treasures
318
-
319
- ### Personal & Dramatic (Variable probability)
320
- - **Forbidden Love**: Romance across social boundaries with scandal
321
- - **Family Secret**: Hidden lineage and ancestral revelations
322
- - **Desertion Temptation**: Military crises testing loyalty and courage
323
- - **Mercenary Contract**: Dangerous employment with high rewards
324
-
325
- ### Adventure & Exploration (Variable probability)
326
- - **Bandit King**: Confrontations with notorious outlaws
327
- - **Lost Civilization**: Exploration of ancient ruins and artifacts
328
-
329
- Probabilities dynamically adjust based on player career, skills, reputation, wealth, and current life circumstances.
330
-
331
- ## ๐Ÿ”„ How It Works
332
-
333
- ### 1. Context Analysis
334
- The generator analyzes player stats to understand their current situation and capabilities.
335
-
336
- ### 2. Template Selection
337
- Based on context, it selects an appropriate event template from 14+ rich narrative types (Court Scandal, Forbidden Love, Ancient Curse, etc.).
338
-
339
- ### 3. Procedural Description
340
- Uses custom Markov chains trained on immersive RPG-themed text to generate unique, atmospheric descriptions.
341
-
342
- ### 4. Dynamic Choices
343
- Creates contextually appropriate choices with effects that scale based on player stats, career, and relationships.
344
-
345
- ### 5. Effect Resolution
346
- Converts effect ranges into specific numbers and applies sophisticated context multipliers based on character background.
347
-
348
- ## ๐ŸŽจ Customization
349
-
350
- ### Custom Event Templates
351
-
352
- ```javascript
353
- const customTemplates = {
354
- QUEST: {
355
- title: 'Epic Quest',
356
- choices: [
357
- { text: 'Accept the quest', effect: { influence: [20, 40] } },
358
- { text: 'Decline politely', effect: {} }
359
- ]
360
- }
361
- };
362
-
363
- // Extend the generator
364
- class CustomRPGEventGenerator extends RPGEventGenerator {
365
- constructor(options) {
366
- super(options);
367
- this.templates = { ...this.templates, ...customTemplates };
368
- }
369
- }
370
- ```
371
-
372
- ### Custom Effect Types
373
-
374
- ```javascript
375
- // Add custom effects
376
- const event = generator.generateEvent(playerContext);
377
-
378
- // Custom effect resolution
379
- function resolveCustomEffects(choice, playerContext) {
380
- const effects = resolveEffect(choice.effect, playerContext);
381
-
382
- // Add custom logic
383
- if (effects.experience) {
384
- // Handle experience gain
385
- }
386
-
387
- if (effects.relationshipChange) {
388
- // Update relationship values
389
- }
390
-
391
- return effects;
392
- }
105
+ // Events will now incorporate your custom story elements
106
+ const event = generator.generateEvent();
107
+ // May generate: "In the shadowed alleys of the ancient city, a mysterious stranger approaches..."
393
108
  ```
394
109
 
395
- ## ๐Ÿ“Š Performance
396
-
397
- - **Generation Speed**: ~10-50ms per event
398
- - **Memory Usage**: ~2-5MB for trained Markov generator
399
- - **Infinite Variety**: Can generate millions of unique events
400
- - **Scalable**: Works with any number of players/contexts
401
-
402
- ## ๐Ÿค Contributing
403
-
404
- 1. Fork the repository
405
- 2. Create a feature branch
406
- 3. Add tests for new functionality
407
- 4. Ensure all tests pass
408
- 5. Submit a pull request
409
-
410
- ## ๐Ÿ“„ License
411
-
412
- MIT License - see LICENSE file for details.
413
-
414
- ## ๐Ÿ™ Acknowledgments
415
-
416
- - Uses [Chance.js](https://chancejs.com/) for random number generation
417
- - Custom Markov chain implementation for procedural text generation
418
-
419
- ## ๐ŸŽจ Thematic Training Sets
420
-
421
- Choose from different genres and settings for your RPG events:
110
+ ### Thematic Training Sets
422
111
 
423
112
  ```javascript
424
113
  // Fantasy (default) - knights, magic, dragons
@@ -429,15 +118,19 @@ const norseGen = new RPGEventGenerator({
429
118
  theme: 'fantasy',
430
119
  culture: 'norse'
431
120
  });
121
+ const norseEvent = norseGen.generateEvent();
122
+ // Generates: "The longships sail into the fjord under the northern lights..."
432
123
 
433
124
  // Sci-fi - corporations, AI, space exploration
434
125
  const sciFiGen = new RPGEventGenerator({ theme: 'sci-fi' });
435
126
 
436
- // Cyberpunk sci-fi - neon lights, megacorps, hackers
127
+ // Cyberpunk sci-fi - neon cities, megacorps, hackers
437
128
  const cyberpunkGen = new RPGEventGenerator({
438
129
  theme: 'sci-fi',
439
130
  culture: 'cyberpunk'
440
131
  });
132
+ const cyberEvent = cyberpunkGen.generateEvent();
133
+ // Generates: "Neon lights reflect off rain-slicked streets in the megacity sprawl..."
441
134
 
442
135
  // Historical - medieval politics, exploration, warfare
443
136
  const historicalGen = new RPGEventGenerator({ theme: 'historical' });
@@ -447,44 +140,82 @@ const victorianGen = new RPGEventGenerator({
447
140
  theme: 'historical',
448
141
  culture: 'victorian'
449
142
  });
143
+ const victorianEvent = victorianGen.generateEvent();
144
+ // Generates: "Steam engines power the industrial revolution across soot-stained cities..."
450
145
  ```
451
146
 
452
- ## โ›“๏ธ Event Chains
453
-
454
- Create multi-part story sequences where events trigger follow-ups:
147
+ ### Event Chains
455
148
 
456
149
  ```javascript
150
+ // Start a multi-part storyline
457
151
  const generator = new RPGEventGenerator();
458
-
459
- // Start a bandit rising chain
460
152
  const firstEvent = generator.startChain('BANDIT_RISING');
153
+
461
154
  console.log(firstEvent.title); // "Treacherous Bandit Ambush"
155
+ console.log(firstEvent.chainId); // "chain_1704567890123_xyz789"
462
156
 
463
157
  // Advance chain based on player choice
464
- const nextEvent = generator.advanceChain(firstEvent.chainId, 'bandit');
158
+ const nextEvent = generator.advanceChain(firstEvent.chainId, 'hero');
465
159
  console.log(nextEvent.title); // "Perilous Bandit King's Challenge"
466
160
 
467
- // Available chains: BANDIT_RISING, COURT_SCANDAL_CHAIN, CURSE_OF_THE_ARTIFACT, MERCHANT_EMPIRE
161
+ // Check active chains
162
+ const activeChains = generator.getActiveChains();
163
+ console.log(`Active chains: ${activeChains.length}`);
164
+
165
+ // Available built-in chains:
166
+ // - BANDIT_RISING: Highway robbery escalating to kingdom threat
167
+ // - COURT_SCANDAL_CHAIN: Royal intrigue with multiple betrayals
168
+ // - CURSE_OF_THE_ARTIFACT: Ancient curse with escalating effects
169
+ // - MERCHANT_EMPIRE: Trade empire building with setbacks
468
170
  ```
469
171
 
470
- Event chains create more engaging narratives with escalating consequences and multi-stage stories.
172
+ ### Time-Based Events
471
173
 
472
- ## ๐Ÿ”ง Modular Event System
174
+ ```javascript
175
+ // Advance game time and handle due events
176
+ const dueEvents = generator.advanceGameDay();
177
+
178
+ dueEvents.forEach(event => {
179
+ if (event.type === 'time_based_chain') {
180
+ const chainData = generator.timeSystem.timeBasedEvents.get(event.chainId);
181
+ const gameEvent = generator.generateChainEvent(chainData);
182
+ // Add to your game's event system
183
+ }
184
+ });
473
185
 
474
- Create and manage custom event templates, training data, and chains:
186
+ // Start evolving storylines
187
+ generator.startTimeBasedChain('POLITICAL_UPRISING');
188
+ // - Day 1: Whispers of dissent appear
189
+ // - Day 7: Public protests erupt
190
+ // - Day 14: Open rebellion begins
191
+ // - Day 21: Revolutionary climax
475
192
 
476
- ```javascript
477
- const generator = new RPGEventGenerator();
193
+ // Check current game time
194
+ const currentTime = generator.getCurrentTime();
195
+ console.log(`Day ${currentTime.day}, Season: ${currentTime.season}`);
196
+ ```
197
+
198
+ ### Modular Event System
478
199
 
200
+ ```javascript
479
201
  // Register custom event templates
480
202
  const customTemplate = {
481
203
  title: 'Mystic Vision',
482
204
  narrative: 'You experience a vivid prophetic dream showing future events.',
483
205
  choices: [
484
- { text: 'Seek out the prophecy', effect: { wisdom: 15, risk: 20 } },
485
- { text: 'Dismiss it as a dream', effect: { stress: -10 } }
206
+ {
207
+ text: 'Seek out the prophecy',
208
+ effect: { wisdom: 15, risk: 20 },
209
+ consequence: 'visionary'
210
+ },
211
+ {
212
+ text: 'Dismiss it as a dream',
213
+ effect: { stress: -10 },
214
+ consequence: 'skeptical'
215
+ }
486
216
  ]
487
217
  };
218
+
488
219
  generator.registerEventTemplate('MYSTIC_VISION', customTemplate);
489
220
 
490
221
  // Add custom training data for better text generation
@@ -504,181 +235,386 @@ const visionChain = {
504
235
  { day: 10, template: 'FINAL_PROPHECY' }
505
236
  ]
506
237
  };
238
+
507
239
  generator.registerEventChain('PROPHECY_CHAIN', visionChain);
508
240
 
509
241
  // Export/import custom content for sharing
510
242
  const customContent = generator.exportCustomContent();
511
- // Share with other developers or save for backup
243
+ console.log('Exported:', Object.keys(customContent.templates).length, 'templates');
512
244
 
513
- const anotherGenerator = new RPGEventGenerator();
514
- anotherGenerator.importCustomContent(customContent);
245
+ const newGenerator = new RPGEventGenerator();
246
+ const importResult = newGenerator.importCustomContent(customContent);
247
+ console.log('Imported:', importResult.templates.success, 'templates');
515
248
  ```
516
249
 
517
- **Custom Content Management:**
518
- - **Templates**: `getCustomTemplates()`, `unregisterEventTemplate()`
519
- - **Training Data**: Organized by categories for easy management
520
- - **Event Chains**: `getCustomChains()`, `unregisterEventChain()`
521
- - **Export/Import**: Full backup and sharing capabilities
522
-
523
- ## โš–๏ธ Dynamic Difficulty Scaling
250
+ ### Dynamic Difficulty Scaling
524
251
 
525
252
  Events automatically scale based on player power level:
526
253
 
527
254
  ```javascript
528
255
  // Weak character (easy difficulty)
529
- const weakling = { gold: 50, influence: 10 };
256
+ const weakling = {
257
+ gold: 50,
258
+ influence: 10,
259
+ skills: { combat: 20 }
260
+ };
530
261
  const easyEvent = generator.generateEvent(weakling);
531
- // Rewards: 50% higher, penalties: 30% lower
262
+ console.log(`Difficulty: ${easyEvent.difficulty}`); // "easy"
263
+ // Effects scaled for beginners: higher rewards, lower penalties
532
264
 
533
265
  // Powerful character (hard difficulty)
534
- const hero = { gold: 50000, influence: 500, skills: { combat: 100 } };
266
+ const hero = {
267
+ gold: 50000,
268
+ influence: 500,
269
+ skills: { combat: 100, diplomacy: 80 },
270
+ relationships: [{ name: 'King', type: 'ally', relationship: 80 }]
271
+ };
535
272
  const hardEvent = generator.generateEvent(hero);
536
- // Rewards: 20% lower, penalties: 30% higher
273
+ console.log(`Difficulty: ${hardEvent.difficulty}`); // "hard"
274
+ // Effects scaled for challenge: lower rewards, higher penalties
537
275
 
538
276
  // Legendary character (legendary difficulty)
539
- const god = { gold: 200000, influence: 1000, skills: { combat: 200 } };
540
- const epicEvent = generator.generateEvent(god);
541
- // Rewards: 40% lower, penalties: 60% higher
277
+ const godlike = {
278
+ gold: 200000,
279
+ influence: 1000,
280
+ skills: { combat: 200, diplomacy: 150 },
281
+ age: 120,
282
+ reputation: 95
283
+ };
284
+ const epicEvent = generator.generateEvent(godlike);
285
+ console.log(`Difficulty: ${epicEvent.difficulty}`); // "legendary"
286
+ // Effects scaled for epic gameplay: minimal rewards, maximum penalties
542
287
  ```
543
288
 
544
289
  **Difficulty Tiers:**
545
- - **Easy** (Power 0-50): Beginner-friendly events
546
- - **Normal** (Power 25-150): Balanced challenges
547
- - **Hard** (Power 100-300): Demanding encounters
548
- - **Legendary** (Power 250+): Epic, high-stakes events
290
+ - **Easy** (Power 0-50): Generous rewards, forgiving penalties
291
+ - **Normal** (Power 25-150): Standard scaling, balanced challenges
292
+ - **Hard** (Power 100-300): Reduced rewards, harsher penalties
293
+ - **Legendary** (Power 250+): Minimal rewards, extreme challenges
549
294
 
550
- ## โฐ Time-Based Events
295
+ ## ๐Ÿ”ง API Reference
551
296
 
552
- Events evolve over time with seasonal changes and long-term story arcs:
297
+ ### Constructor Options
553
298
 
554
299
  ```javascript
555
- const generator = new RPGEventGenerator();
300
+ const generator = new RPGEventGenerator({
301
+ stateSize: 2, // Markov chain state size (default: 2)
302
+ trainingData: [...], // Custom training data array
303
+ theme: 'fantasy', // 'fantasy', 'sci-fi', 'historical'
304
+ culture: 'norse' // Cultural variant within theme
305
+ });
306
+ ```
556
307
 
557
- // Advance game time
558
- const timeEvents = generator.advanceTime(30); // Advance 30 days
559
- console.log('Season:', generator.getCurrentTime().season); // May change
308
+ ### Core Methods
560
309
 
561
- // Start evolving storylines
562
- generator.startTimeBasedChain('POLITICAL_UPRISING');
563
- // - Day 1: Whispers of dissent
564
- // - Day 7: Public protests
565
- // - Day 14: Open rebellion
566
- // - Day 21: Revolutionary climax
310
+ - `generateEvent(playerContext)` - Generate single event
311
+ - `generateEvents(playerContext, count)` - Generate multiple events
312
+ - `generateTimeAwareEvent(playerContext)` - Generate season-aware event
313
+
314
+ ### Event Chain Methods
315
+
316
+ - `startChain(chainId)` - Start choice-based event chain
317
+ - `advanceChain(chainId, choice)` - Advance chain based on choice
318
+ - `getActiveChains()` - Get all active chains
319
+
320
+ ### Time-Based Methods
321
+
322
+ - `advanceGameDay()` - Advance time and return due events
323
+ - `startTimeBasedChain(chainId)` - Start time-evolving chain
324
+ - `getCurrentTime()` - Get current game time/season
325
+ - `getActiveTimeChains()` - Get active time-based chains
326
+
327
+ ### Game State Methods
328
+
329
+ - `getGameState()` - Export complete game state
330
+ - `loadGameState(state)` - Import saved game state
567
331
 
568
- // Generate time-aware events
569
- const seasonalEvent = generator.generateTimeAwareEvent(playerContext);
570
- // Events adapt to current season with appropriate themes
332
+ ### Modular Methods
333
+
334
+ - `registerEventTemplate(id, template)` - Add custom event template
335
+ - `addCustomTrainingData(data, category)` - Add custom training data
336
+ - `registerEventChain(id, chainConfig)` - Add custom event chain
337
+ - `exportCustomContent()` - Export custom templates/chains/data
338
+ - `importCustomContent(content)` - Import custom content
339
+
340
+ ### Player Context Object
341
+
342
+ ```javascript
343
+ {
344
+ age: number, // Player age
345
+ gold: number, // Player wealth
346
+ influence: number, // Political/social influence
347
+ reputation: number, // Social reputation
348
+ career: string, // Player's career/job ('noble', 'merchant', 'warrior', etc.)
349
+ skills: { // Skill levels object
350
+ combat: number, // 0-100 scale
351
+ diplomacy: number,
352
+ intrigue: number,
353
+ magic: number,
354
+ survival: number
355
+ },
356
+ relationships: [{ // Array of NPC relationships
357
+ name: string, // NPC name
358
+ type: string, // 'friend', 'lover', 'ally', 'enemy', 'rival'
359
+ relationship: number // Relationship strength (0-100)
360
+ }],
361
+ location: string, // Current location ('capital', 'village', 'forest', etc.)
362
+ season: string // Current season ('spring', 'summer', 'autumn', 'winter')
363
+ }
571
364
  ```
572
365
 
573
- **Available Time-Based Chains:**
574
- - **`POLITICAL_UPRISING`**: Rebellion that builds over weeks
575
- - **`ECONOMIC_COLLAPSE`**: Market crisis with escalating consequences
576
- - **`MYSTICAL_AWAKENING`**: Supernatural events that intensify over time
366
+ ### Complete Event Object Structure
577
367
 
578
- **Seasonal Events:**
579
- - **Spring**: Romance, renewal, festivals
580
- - **Summer**: Tournaments, celebrations, activity
581
- - **Autumn**: Harvest, preparation, scarcity
582
- - **Winter**: Solstice rituals, survival challenges, warmth-seeking
368
+ ```javascript
369
+ {
370
+ id: "event_1704567890123_xyz789", // Unique event identifier
371
+ title: "Perilous Bandit King's Challenge", // Dynamic, context-aware title
372
+ description: "The infamous bandit king blocks your path, offering you a choice...", // Rich procedural description
373
+ narrative: "The infamous bandit king blocks your path, offering you a choice: join his band or face certain death.",
374
+ choices: [
375
+ {
376
+ text: "Join the bandits",
377
+ effect: { gold: 375, reputation: -23, combat_skill: 12 },
378
+ consequence: "bandit"
379
+ },
380
+ {
381
+ text: "Challenge him to single combat",
382
+ effect: { reputation: 32, health: -18 },
383
+ requirements: { combat_skill: 60 },
384
+ consequence: "hero"
385
+ },
386
+ {
387
+ text: "Bribe your way past",
388
+ effect: { gold: -320, safe_passage: true },
389
+ consequence: "diplomat"
390
+ }
391
+ ],
392
+ type: "BANDIT_KING",
393
+ consequence: null,
394
+ context: { /* Full context used for generation */ },
395
+ urgency: "normal",
396
+ theme: "adventure",
397
+ difficulty: "normal"
398
+ }
399
+ ```
583
400
 
584
401
  ## ๐ŸŽฎ Game Integration
585
402
 
586
- For real game integration, use these methods instead of timers:
403
+ ### Real-Time Strategy Integration
587
404
 
588
405
  ```javascript
589
- const generator = new RPGEventGenerator();
590
-
591
- // Each game day, advance time and check for events
592
406
  function onNewGameDay() {
593
407
  const dueEvents = generator.advanceGameDay();
594
408
 
595
- // Process each due event in your game
596
409
  dueEvents.forEach(event => {
597
410
  if (event.type === 'time_based_chain') {
598
- // Generate the actual event for your game
599
411
  const chainData = generator.timeSystem.timeBasedEvents.get(event.chainId);
600
412
  const gameEvent = generator.generateChainEvent(chainData);
601
- // Add gameEvent to your game's event system
602
413
  triggerInGameEvent(gameEvent);
603
414
  } else if (event.type === 'seasonal_random') {
604
- // Generate a seasonal event
605
415
  const seasonalEvent = generator.generateTimeAwareEvent(playerContext);
606
416
  triggerInGameEvent(seasonalEvent);
607
417
  }
608
418
  });
609
419
  }
420
+ ```
610
421
 
611
- // Save/Load game state
612
- function saveGame() {
613
- const gameState = generator.getGameState();
614
- // Save gameState to your game's save file
615
- }
422
+ ### React Game Integration
616
423
 
617
- function loadGame(savedState) {
618
- generator.loadGameState(savedState);
619
- // Game is now restored with proper time/chain state
424
+ ```javascript
425
+ import React, { useState, useEffect } from 'react';
426
+ import { RPGEventGenerator } from 'rpg-event-generator';
427
+
428
+ function GameEventSystem({ playerStats }) {
429
+ const [currentEvent, setCurrentEvent] = useState(null);
430
+ const [generator] = useState(() => new RPGEventGenerator());
431
+
432
+ useEffect(() => {
433
+ // Generate event when time advances
434
+ const event = generator.generateEvent(playerStats);
435
+ setCurrentEvent(event);
436
+ }, [playerStats, generator]);
437
+
438
+ const handleChoice = (choiceIndex) => {
439
+ const choice = currentEvent.choices[choiceIndex];
440
+ // Apply effects to player stats
441
+ applyEffects(choice.effect);
442
+ setCurrentEvent(null); // Clear event
443
+ };
444
+
445
+ if (!currentEvent) return <div>No active events</div>;
446
+
447
+ return (
448
+ <div className="event-dialog">
449
+ <h2>{currentEvent.title}</h2>
450
+ <p>{currentEvent.description}</p>
451
+ <div className="choices">
452
+ {currentEvent.choices.map((choice, index) => (
453
+ <button
454
+ key={index}
455
+ onClick={() => handleChoice(index)}
456
+ className="choice-button"
457
+ >
458
+ {choice.text}
459
+ </button>
460
+ ))}
461
+ </div>
462
+ </div>
463
+ );
620
464
  }
465
+ ```
466
+
467
+ ### Redux Integration
468
+
469
+ ```javascript
470
+ // Action Types
471
+ export const GENERATE_EVENT = 'GENERATE_EVENT';
472
+ export const RESOLVE_EVENT = 'RESOLVE_EVENT';
473
+ export const ADVANCE_GAME_DAY = 'ADVANCE_GAME_DAY';
474
+
475
+ // Action Creators
476
+ export const generateEvent = (playerContext) => ({
477
+ type: GENERATE_EVENT,
478
+ payload: { playerContext }
479
+ });
480
+
481
+ export const resolveEvent = (eventId, choiceIndex) => ({
482
+ type: RESOLVE_EVENT,
483
+ payload: { eventId, choiceIndex }
484
+ });
485
+
486
+ export const advanceGameDay = () => ({
487
+ type: ADVANCE_GAME_DAY
488
+ });
621
489
 
622
- // Monitor active chains
623
- const activeChains = generator.getActiveTimeChains();
624
- // Shows all ongoing storylines with their progress
490
+ // Reducer
491
+ const initialState = {
492
+ generator: new RPGEventGenerator(),
493
+ currentEvent: null,
494
+ gameTime: { day: 1, season: 'spring' }
495
+ };
496
+
497
+ const eventReducer = (state = initialState, action) => {
498
+ switch (action.type) {
499
+ case GENERATE_EVENT:
500
+ const event = state.generator.generateEvent(action.payload.playerContext);
501
+ return { ...state, currentEvent: event };
502
+
503
+ case RESOLVE_EVENT:
504
+ // Apply choice effects to player state
505
+ const choice = state.currentEvent.choices[action.payload.choiceIndex];
506
+ const newPlayerState = applyChoiceEffects(choice.effect);
507
+ return {
508
+ ...state,
509
+ currentEvent: null,
510
+ playerState: newPlayerState
511
+ };
512
+
513
+ case ADVANCE_GAME_DAY:
514
+ const dueEvents = state.generator.advanceGameDay();
515
+ return {
516
+ ...state,
517
+ gameTime: state.generator.getCurrentTime(),
518
+ dueEvents: dueEvents
519
+ };
520
+
521
+ default:
522
+ return state;
523
+ }
524
+ };
625
525
  ```
626
526
 
627
- **Key Benefits:**
628
- - **Persistent State**: Chains survive game saves/loads
629
- - **Event-Driven**: No timers, events trigger when you advance days
630
- - **Game-Controlled**: You control when time passes
631
- - **Multiple Events**: Handle multiple events per day
527
+ ### Save/Load System
632
528
 
633
- ## ๐Ÿ—บ๏ธ Cultural Context
529
+ ```javascript
530
+ // Save complete game state
531
+ function saveGame(playerState) {
532
+ const gameState = {
533
+ player: playerState,
534
+ events: generator.getGameState(),
535
+ timestamp: Date.now()
536
+ };
634
537
 
635
- Add regional/cultural flavor within each theme:
538
+ localStorage.setItem('rpgGameSave', JSON.stringify(gameState));
539
+ console.log('Game saved successfully');
540
+ }
636
541
 
637
- ### Fantasy Cultures
638
- - **`norse`**: Vikings, runes, mead halls, thunder gods
639
- - **`arabian`**: Sultans, djinn, bazaars, flying carpets
640
- - **`celtic`**: Druids, fairy mounds, stone circles, clan warfare
641
- - **`asian`**: Imperial courts, samurai, dragon spirits, tea ceremonies
542
+ // Load complete game state
543
+ function loadGame() {
544
+ try {
545
+ const savedGame = JSON.parse(localStorage.getItem('rpgGameSave'));
546
+ if (!savedGame) return false;
642
547
 
643
- ### Sci-Fi Cultures
644
- - **`cyberpunk`**: Neon cities, megacorps, neural implants, hackers
645
- - **`space_opera`**: Galactic empires, Jedi knights, hyperspace, alien ambassadors
646
- - **`post_apocalyptic`**: Wastelands, mutants, vault dwellers, irradiated ruins
548
+ // Restore generator state
549
+ generator.loadGameState(savedGame.events);
647
550
 
648
- ### Historical Cultures
649
- - **`medieval`**: Knights, castles, feudal lords, alchemists
650
- - **`victorian`**: Industrial revolution, social reformers, steam power
651
- - **`ancient_roman`**: Gladiators, senators, aqueducts, barbarian hordes
551
+ // Restore player state
552
+ return savedGame.player;
652
553
 
653
- Cultural variants blend with base theme data for authentic regional flavor!
554
+ } catch (error) {
555
+ console.error('Failed to load game:', error);
556
+ return false;
557
+ }
558
+ }
559
+ ```
654
560
 
655
561
  ## ๐Ÿงช Testing
656
562
 
657
- This package includes comprehensive test coverage with **45+ automated tests** ensuring reliability and quality:
658
-
659
563
  ```bash
660
564
  npm test
661
565
  ```
662
566
 
663
- **Test Coverage Includes:**
664
- - โœ… **Core Generation** - Event creation and validation
665
- - โœ… **Context Adaptation** - Player stat responsiveness
666
- - โœ… **Thematic Systems** - Theme and culture switching
667
- - โœ… **Event Chains** - Multi-stage story progression
668
- - โœ… **Difficulty Scaling** - Power-based event adjustment
669
- - โœ… **Time Systems** - Seasonal and temporal mechanics
670
- - โœ… **Modular Features** - Custom content registration
671
- - โœ… **Edge Cases** - Error handling and validation
672
- - โœ… **Integration** - Game state persistence
673
-
674
- All features are thoroughly tested with both unit and integration tests for maximum reliability.
675
-
676
- ## ๐Ÿ”ฎ Future Enhancements
677
- - **Multi-language Support**: Generate events in different languages
678
- - **Event Dependencies**: Complex prerequisite systems
679
- - **Event Modifiers**: Weather, season, and environmental effects
680
- - **Character Relationships**: NPC interaction networks
681
- - **Event Editor**: Visual template creation interface
567
+ **Comprehensive test coverage (45+ tests):**
568
+ - โœ… Core event generation and validation
569
+ - โœ… Context adaptation and player responsiveness
570
+ - โœ… Thematic systems and cultural variants
571
+ - โœ… Event chains and multi-stage progression
572
+ - โœ… Dynamic difficulty scaling
573
+ - โœ… Time systems and seasonal mechanics
574
+ - โœ… Modular features and custom content
575
+ - โœ… Edge cases and error handling
576
+ - โœ… Game state persistence and integration
577
+
578
+ ## ๐ŸŽฏ Event Types
579
+
580
+ ### Court & Political
581
+ - **Court Scandal**: Royal intrigue with betrayal and scandal
582
+ - **Noble Duel**: Honour challenges and duels of reputation
583
+ - **Market Crash**: Economic disasters affecting trade
584
+ - **Trade War**: Merchant rivalries and economic warfare
585
+
586
+ ### Criminal Underworld
587
+ - **Thieves' Guild**: Criminal organisation recruitment
588
+ - **Blackmail Opportunity**: Leverage compromising information
589
+ - **Bandit King Challenge**: Highway robbery confrontations
590
+
591
+ ### Supernatural & Mysterious
592
+ - **Ancient Curse**: Cursed artefacts and afflictions
593
+ - **Ghostly Visitation**: Spirits seeking justice
594
+ - **Lost Civilisation**: Archaeological discoveries
595
+
596
+ ### Personal & Dramatic
597
+ - **Forbidden Love**: Romance across social boundaries
598
+ - **Family Secret**: Hidden lineage revelations
599
+ - **Desertion Temptation**: Military loyalty crises
600
+ - **Mercenary Contract**: Dangerous employment opportunities
601
+
602
+ ## ๐Ÿค Contributing
603
+
604
+ 1. Fork the repository
605
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
606
+ 3. Commit changes (`git commit -m 'Add amazing feature'`)
607
+ 4. Push to branch (`git push origin feature/amazing-feature`)
608
+ 5. Open a Pull Request
609
+
610
+ ## ๐Ÿ“„ License
611
+
612
+ MIT License - see [LICENSE](LICENSE) file for details.
613
+
614
+ ## ๐Ÿ™ Acknowledgments
615
+
616
+ - [Chance.js](https://chancejs.com/) for random number generation
617
+ - Custom Markov chain implementation for procedural text generation
682
618
 
683
619
  ---
684
620
 
package/dist/index.js CHANGED
@@ -2274,7 +2274,8 @@ class RPGEventGenerator {
2274
2274
  }
2275
2275
  return description;
2276
2276
  } catch (error) {
2277
- return template.narrative;
2277
+ const templateType = this.mapTemplateToType(template.type || Object.keys(this.templates).find(key => this.templates[key] === template));
2278
+ return this.getFallbackDescription(templateType);
2278
2279
  }
2279
2280
  }
2280
2281
 
@@ -2524,16 +2525,46 @@ class RPGEventGenerator {
2524
2525
  return this.chance.pickone(locations);
2525
2526
  }
2526
2527
 
2528
+ /**
2529
+ * Map template ID to fallback type
2530
+ * @param {string} templateId - Template identifier
2531
+ * @returns {string} Fallback type
2532
+ * @private
2533
+ */
2534
+ mapTemplateToType(templateId) {
2535
+ if (!templateId) return 'ENCOUNTER';
2536
+ const typeMapping = {
2537
+ 'COURT_SCANDAL': 'ENCOUNTER',
2538
+ 'NOBLE_DUEL': 'CHALLENGE',
2539
+ 'FORBIDDEN_LOVE': 'ENCOUNTER',
2540
+ 'FAMILY_SECRET': 'MYSTERY',
2541
+ 'THIEVES_GUILD': 'CHALLENGE',
2542
+ 'BLACKMAIL_OPPORTUNITY': 'OPPORTUNITY',
2543
+ 'ANCIENT_CURSE': 'MYSTERY',
2544
+ 'GHOSTLY_VISITATION': 'MYSTERY',
2545
+ 'LOST_CIVILIZATION': 'MYSTERY',
2546
+ 'BANDIT_KING': 'CHALLENGE',
2547
+ 'MARKET_CRASH': 'CHALLENGE',
2548
+ 'TRADE_WAR': 'CHALLENGE',
2549
+ 'MERCENARY_CONTRACT': 'OPPORTUNITY',
2550
+ 'DESERTION_TEMPTATION': 'CHALLENGE'
2551
+ };
2552
+ return typeMapping[templateId] || 'ENCOUNTER';
2553
+ }
2554
+
2527
2555
  /**
2528
2556
  * Get fallback description if Markov generation fails
2529
2557
  * @private
2530
2558
  */
2531
2559
  getFallbackDescription(templateType) {
2560
+ const professions = ['merchant', 'warrior', 'mage', 'noble', 'thief', 'priest', 'blacksmith', 'alchemist'];
2561
+ const products = ['sword', 'potion', 'artifact', 'weapon', 'armor', 'tool', 'gem', 'scroll'];
2562
+ const locations = ['village', 'town', 'city', 'castle', 'forest', 'mountain', 'ruins'];
2532
2563
  const fallbacks = {
2533
- ENCOUNTER: `A ${faker.person.jobTitle()} approaches you with an unusual proposition.`,
2534
- OPPORTUNITY: `A rare ${faker.commerce.product()} has become available at an exceptional price.`,
2535
- CHALLENGE: `A ${faker.person.jobTitle()} challenges your position in the community.`,
2536
- MYSTERY: `Strange occurrences have been reported near ${faker.location.city()}.`
2564
+ ENCOUNTER: `A ${this.chance.pickone(professions)} approaches you with an unusual proposition.`,
2565
+ OPPORTUNITY: `A rare ${this.chance.pickone(products)} has become available at an exceptional price.`,
2566
+ CHALLENGE: `A ${this.chance.pickone(professions)} challenges your position in the community.`,
2567
+ MYSTERY: `Strange occurrences have been reported near ${this.chance.pickone(locations)}.`
2537
2568
  };
2538
2569
  return fallbacks[templateType] || fallbacks.ENCOUNTER;
2539
2570
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpg-event-generator",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Procedural RPG event generation system for games",
5
5
  "main": "dist/index.js",
6
6
  "files": [