rpg-event-generator 1.0.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.
- package/README.md +447 -256
- package/dist/index.js +1506 -47
- 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
|
-
##
|
|
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
|
-
//
|
|
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);
|
|
39
|
-
console.log(event.description);
|
|
40
|
-
console.log(event.choices);
|
|
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
|
-
|
|
43
|
-
const generator = new RPGEventGenerator({
|
|
44
|
-
stateSize: 2,
|
|
45
|
-
trainingData: ['Your custom story fragments...']
|
|
46
|
-
});
|
|
29
|
+
## ๐ Features
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
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: "
|
|
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
|
-
//
|
|
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
|
-
//
|
|
94
|
-
// urgency: "normal",
|
|
95
|
-
// theme: "adventure",
|
|
96
|
-
// context: { /* player context used */ }
|
|
61
|
+
// difficulty: "normal"
|
|
97
62
|
// }
|
|
98
63
|
```
|
|
99
64
|
|
|
@@ -106,121 +71,355 @@ 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
|
|
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
|
|
138
|
-
'The tavern
|
|
139
|
-
'Ancient runes glow with
|
|
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
|
});
|
|
104
|
+
|
|
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..."
|
|
146
108
|
```
|
|
147
109
|
|
|
148
|
-
|
|
110
|
+
### Thematic Training Sets
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
// Fantasy (default) - knights, magic, dragons
|
|
114
|
+
const fantasyGen = new RPGEventGenerator({ theme: 'fantasy' });
|
|
115
|
+
|
|
116
|
+
// Fantasy with Norse culture - vikings, runes, fjords
|
|
117
|
+
const norseGen = new RPGEventGenerator({
|
|
118
|
+
theme: 'fantasy',
|
|
119
|
+
culture: 'norse'
|
|
120
|
+
});
|
|
121
|
+
const norseEvent = norseGen.generateEvent();
|
|
122
|
+
// Generates: "The longships sail into the fjord under the northern lights..."
|
|
123
|
+
|
|
124
|
+
// Sci-fi - corporations, AI, space exploration
|
|
125
|
+
const sciFiGen = new RPGEventGenerator({ theme: 'sci-fi' });
|
|
126
|
+
|
|
127
|
+
// Cyberpunk sci-fi - neon cities, megacorps, hackers
|
|
128
|
+
const cyberpunkGen = new RPGEventGenerator({
|
|
129
|
+
theme: 'sci-fi',
|
|
130
|
+
culture: 'cyberpunk'
|
|
131
|
+
});
|
|
132
|
+
const cyberEvent = cyberpunkGen.generateEvent();
|
|
133
|
+
// Generates: "Neon lights reflect off rain-slicked streets in the megacity sprawl..."
|
|
134
|
+
|
|
135
|
+
// Historical - medieval politics, exploration, warfare
|
|
136
|
+
const historicalGen = new RPGEventGenerator({ theme: 'historical' });
|
|
137
|
+
|
|
138
|
+
// Victorian historical - industrial revolution, social reform
|
|
139
|
+
const victorianGen = new RPGEventGenerator({
|
|
140
|
+
theme: 'historical',
|
|
141
|
+
culture: 'victorian'
|
|
142
|
+
});
|
|
143
|
+
const victorianEvent = victorianGen.generateEvent();
|
|
144
|
+
// Generates: "Steam engines power the industrial revolution across soot-stained cities..."
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Event Chains
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
// Start a multi-part storyline
|
|
151
|
+
const generator = new RPGEventGenerator();
|
|
152
|
+
const firstEvent = generator.startChain('BANDIT_RISING');
|
|
153
|
+
|
|
154
|
+
console.log(firstEvent.title); // "Treacherous Bandit Ambush"
|
|
155
|
+
console.log(firstEvent.chainId); // "chain_1704567890123_xyz789"
|
|
156
|
+
|
|
157
|
+
// Advance chain based on player choice
|
|
158
|
+
const nextEvent = generator.advanceChain(firstEvent.chainId, 'hero');
|
|
159
|
+
console.log(nextEvent.title); // "Perilous Bandit King's Challenge"
|
|
160
|
+
|
|
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
|
|
170
|
+
```
|
|
149
171
|
|
|
150
|
-
###
|
|
172
|
+
### Time-Based Events
|
|
151
173
|
|
|
152
|
-
|
|
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
|
+
});
|
|
185
|
+
|
|
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
|
|
192
|
+
|
|
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
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
// Register custom event templates
|
|
202
|
+
const customTemplate = {
|
|
203
|
+
title: 'Mystic Vision',
|
|
204
|
+
narrative: 'You experience a vivid prophetic dream showing future events.',
|
|
205
|
+
choices: [
|
|
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
|
+
}
|
|
216
|
+
]
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
generator.registerEventTemplate('MYSTIC_VISION', customTemplate);
|
|
220
|
+
|
|
221
|
+
// Add custom training data for better text generation
|
|
222
|
+
generator.addCustomTrainingData([
|
|
223
|
+
'The ancient prophecy foretells of great change',
|
|
224
|
+
'Mystic visions reveal hidden truths to the worthy',
|
|
225
|
+
'Dreams of the future guide the destinies of heroes'
|
|
226
|
+
], 'mystical');
|
|
227
|
+
|
|
228
|
+
// Create custom event chains
|
|
229
|
+
const visionChain = {
|
|
230
|
+
name: 'Prophetic Journey',
|
|
231
|
+
description: 'A chain of events triggered by mystic visions',
|
|
232
|
+
stages: [
|
|
233
|
+
{ day: 1, template: 'MYSTIC_VISION' },
|
|
234
|
+
{ day: 5, template: 'ANCIENT_RUINS' },
|
|
235
|
+
{ day: 10, template: 'FINAL_PROPHECY' }
|
|
236
|
+
]
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
generator.registerEventChain('PROPHECY_CHAIN', visionChain);
|
|
240
|
+
|
|
241
|
+
// Export/import custom content for sharing
|
|
242
|
+
const customContent = generator.exportCustomContent();
|
|
243
|
+
console.log('Exported:', Object.keys(customContent.templates).length, 'templates');
|
|
244
|
+
|
|
245
|
+
const newGenerator = new RPGEventGenerator();
|
|
246
|
+
const importResult = newGenerator.importCustomContent(customContent);
|
|
247
|
+
console.log('Imported:', importResult.templates.success, 'templates');
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Dynamic Difficulty Scaling
|
|
251
|
+
|
|
252
|
+
Events automatically scale based on player power level:
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
// Weak character (easy difficulty)
|
|
256
|
+
const weakling = {
|
|
257
|
+
gold: 50,
|
|
258
|
+
influence: 10,
|
|
259
|
+
skills: { combat: 20 }
|
|
260
|
+
};
|
|
261
|
+
const easyEvent = generator.generateEvent(weakling);
|
|
262
|
+
console.log(`Difficulty: ${easyEvent.difficulty}`); // "easy"
|
|
263
|
+
// Effects scaled for beginners: higher rewards, lower penalties
|
|
264
|
+
|
|
265
|
+
// Powerful character (hard difficulty)
|
|
266
|
+
const hero = {
|
|
267
|
+
gold: 50000,
|
|
268
|
+
influence: 500,
|
|
269
|
+
skills: { combat: 100, diplomacy: 80 },
|
|
270
|
+
relationships: [{ name: 'King', type: 'ally', relationship: 80 }]
|
|
271
|
+
};
|
|
272
|
+
const hardEvent = generator.generateEvent(hero);
|
|
273
|
+
console.log(`Difficulty: ${hardEvent.difficulty}`); // "hard"
|
|
274
|
+
// Effects scaled for challenge: lower rewards, higher penalties
|
|
275
|
+
|
|
276
|
+
// Legendary character (legendary difficulty)
|
|
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
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Difficulty Tiers:**
|
|
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
|
|
294
|
+
|
|
295
|
+
## ๐ง API Reference
|
|
296
|
+
|
|
297
|
+
### Constructor Options
|
|
153
298
|
|
|
154
299
|
```javascript
|
|
155
300
|
const generator = new RPGEventGenerator({
|
|
156
|
-
stateSize: 2,
|
|
157
|
-
trainingData: [...]
|
|
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
|
|
158
305
|
});
|
|
159
306
|
```
|
|
160
307
|
|
|
161
|
-
|
|
308
|
+
### Core Methods
|
|
162
309
|
|
|
163
|
-
- `generateEvent(playerContext)` - Generate
|
|
310
|
+
- `generateEvent(playerContext)` - Generate single event
|
|
164
311
|
- `generateEvents(playerContext, count)` - Generate multiple events
|
|
165
|
-
- `
|
|
166
|
-
|
|
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
|
|
331
|
+
|
|
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
|
|
167
339
|
|
|
168
340
|
### Player Context Object
|
|
169
341
|
|
|
170
342
|
```javascript
|
|
171
343
|
{
|
|
172
|
-
age: number,
|
|
173
|
-
gold: number,
|
|
174
|
-
influence: number,
|
|
175
|
-
reputation: number,
|
|
176
|
-
career: string,
|
|
177
|
-
skills: {
|
|
178
|
-
combat: number,
|
|
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
|
|
179
351
|
diplomacy: number,
|
|
180
|
-
|
|
352
|
+
intrigue: number,
|
|
353
|
+
magic: number,
|
|
354
|
+
survival: number
|
|
181
355
|
},
|
|
182
|
-
relationships: [{
|
|
183
|
-
name: string,
|
|
184
|
-
type: string,
|
|
185
|
-
relationship: number
|
|
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)
|
|
186
360
|
}],
|
|
187
|
-
location: string,
|
|
188
|
-
season: string
|
|
361
|
+
location: string, // Current location ('capital', 'village', 'forest', etc.)
|
|
362
|
+
season: string // Current season ('spring', 'summer', 'autumn', 'winter')
|
|
189
363
|
}
|
|
190
364
|
```
|
|
191
365
|
|
|
192
|
-
### Event Object Structure
|
|
366
|
+
### Complete Event Object Structure
|
|
193
367
|
|
|
194
368
|
```javascript
|
|
195
369
|
{
|
|
196
|
-
id:
|
|
197
|
-
title:
|
|
198
|
-
description:
|
|
199
|
-
narrative:
|
|
200
|
-
choices: [
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
gold
|
|
204
|
-
|
|
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
|
|
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"
|
|
210
379
|
},
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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"
|
|
218
398
|
}
|
|
219
399
|
```
|
|
220
400
|
|
|
221
|
-
## ๐ฎ Integration
|
|
401
|
+
## ๐ฎ Game Integration
|
|
402
|
+
|
|
403
|
+
### Real-Time Strategy Integration
|
|
404
|
+
|
|
405
|
+
```javascript
|
|
406
|
+
function onNewGameDay() {
|
|
407
|
+
const dueEvents = generator.advanceGameDay();
|
|
408
|
+
|
|
409
|
+
dueEvents.forEach(event => {
|
|
410
|
+
if (event.type === 'time_based_chain') {
|
|
411
|
+
const chainData = generator.timeSystem.timeBasedEvents.get(event.chainId);
|
|
412
|
+
const gameEvent = generator.generateChainEvent(chainData);
|
|
413
|
+
triggerInGameEvent(gameEvent);
|
|
414
|
+
} else if (event.type === 'seasonal_random') {
|
|
415
|
+
const seasonalEvent = generator.generateTimeAwareEvent(playerContext);
|
|
416
|
+
triggerInGameEvent(seasonalEvent);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
```
|
|
222
421
|
|
|
223
|
-
### React
|
|
422
|
+
### React Game Integration
|
|
224
423
|
|
|
225
424
|
```javascript
|
|
226
425
|
import React, { useState, useEffect } from 'react';
|
|
@@ -243,13 +442,24 @@ function GameEventSystem({ playerStats }) {
|
|
|
243
442
|
setCurrentEvent(null); // Clear event
|
|
244
443
|
};
|
|
245
444
|
|
|
246
|
-
if (!currentEvent) return
|
|
445
|
+
if (!currentEvent) return <div>No active events</div>;
|
|
247
446
|
|
|
248
447
|
return (
|
|
249
|
-
<
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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>
|
|
253
463
|
);
|
|
254
464
|
}
|
|
255
465
|
```
|
|
@@ -257,174 +467,155 @@ function GameEventSystem({ playerStats }) {
|
|
|
257
467
|
### Redux Integration
|
|
258
468
|
|
|
259
469
|
```javascript
|
|
260
|
-
// Action
|
|
261
|
-
export const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
};
|
|
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
|
+
});
|
|
270
480
|
|
|
271
481
|
export const resolveEvent = (eventId, choiceIndex) => ({
|
|
272
|
-
type:
|
|
482
|
+
type: RESOLVE_EVENT,
|
|
273
483
|
payload: { eventId, choiceIndex }
|
|
274
484
|
});
|
|
275
485
|
|
|
486
|
+
export const advanceGameDay = () => ({
|
|
487
|
+
type: ADVANCE_GAME_DAY
|
|
488
|
+
});
|
|
489
|
+
|
|
276
490
|
// Reducer
|
|
277
|
-
const
|
|
491
|
+
const initialState = {
|
|
492
|
+
generator: new RPGEventGenerator(),
|
|
493
|
+
currentEvent: null,
|
|
494
|
+
gameTime: { day: 1, season: 'spring' }
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
const eventReducer = (state = initialState, action) => {
|
|
278
498
|
switch (action.type) {
|
|
279
|
-
case
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
+
|
|
283
521
|
default:
|
|
284
522
|
return state;
|
|
285
523
|
}
|
|
286
524
|
};
|
|
287
525
|
```
|
|
288
526
|
|
|
289
|
-
|
|
527
|
+
### Save/Load System
|
|
290
528
|
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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.
|
|
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
|
+
};
|
|
344
537
|
|
|
345
|
-
|
|
346
|
-
|
|
538
|
+
localStorage.setItem('rpgGameSave', JSON.stringify(gameState));
|
|
539
|
+
console.log('Game saved successfully');
|
|
540
|
+
}
|
|
347
541
|
|
|
348
|
-
|
|
542
|
+
// Load complete game state
|
|
543
|
+
function loadGame() {
|
|
544
|
+
try {
|
|
545
|
+
const savedGame = JSON.parse(localStorage.getItem('rpgGameSave'));
|
|
546
|
+
if (!savedGame) return false;
|
|
349
547
|
|
|
350
|
-
|
|
548
|
+
// Restore generator state
|
|
549
|
+
generator.loadGameState(savedGame.events);
|
|
351
550
|
|
|
352
|
-
|
|
353
|
-
|
|
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
|
-
};
|
|
551
|
+
// Restore player state
|
|
552
|
+
return savedGame.player;
|
|
362
553
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
super(options);
|
|
367
|
-
this.templates = { ...this.templates, ...customTemplates };
|
|
554
|
+
} catch (error) {
|
|
555
|
+
console.error('Failed to load game:', error);
|
|
556
|
+
return false;
|
|
368
557
|
}
|
|
369
558
|
}
|
|
370
559
|
```
|
|
371
560
|
|
|
372
|
-
|
|
561
|
+
## ๐งช Testing
|
|
373
562
|
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
|
|
563
|
+
```bash
|
|
564
|
+
npm test
|
|
565
|
+
```
|
|
377
566
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
|
381
577
|
|
|
382
|
-
|
|
383
|
-
if (effects.experience) {
|
|
384
|
-
// Handle experience gain
|
|
385
|
-
}
|
|
578
|
+
## ๐ฏ Event Types
|
|
386
579
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
390
585
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
586
|
+
### Criminal Underworld
|
|
587
|
+
- **Thieves' Guild**: Criminal organisation recruitment
|
|
588
|
+
- **Blackmail Opportunity**: Leverage compromising information
|
|
589
|
+
- **Bandit King Challenge**: Highway robbery confrontations
|
|
394
590
|
|
|
395
|
-
|
|
591
|
+
### Supernatural & Mysterious
|
|
592
|
+
- **Ancient Curse**: Cursed artefacts and afflictions
|
|
593
|
+
- **Ghostly Visitation**: Spirits seeking justice
|
|
594
|
+
- **Lost Civilisation**: Archaeological discoveries
|
|
396
595
|
|
|
397
|
-
|
|
398
|
-
- **
|
|
399
|
-
- **
|
|
400
|
-
- **
|
|
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
|
|
401
601
|
|
|
402
602
|
## ๐ค Contributing
|
|
403
603
|
|
|
404
604
|
1. Fork the repository
|
|
405
|
-
2. Create a feature branch
|
|
406
|
-
3.
|
|
407
|
-
4.
|
|
408
|
-
5.
|
|
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
|
|
409
609
|
|
|
410
610
|
## ๐ License
|
|
411
611
|
|
|
412
|
-
MIT License - see LICENSE file for details.
|
|
612
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
413
613
|
|
|
414
614
|
## ๐ Acknowledgments
|
|
415
615
|
|
|
416
|
-
-
|
|
616
|
+
- [Chance.js](https://chancejs.com/) for random number generation
|
|
417
617
|
- Custom Markov chain implementation for procedural text generation
|
|
418
618
|
|
|
419
|
-
## ๐ฎ Future Enhancements
|
|
420
|
-
|
|
421
|
-
- **Thematic Training Sets**: Fantasy, Sci-fi, Historical themes
|
|
422
|
-
- **Multi-language Support**: Generate events in different languages
|
|
423
|
-
- **Event Chains**: Multi-part event sequences
|
|
424
|
-
- **Dynamic Difficulty**: Events scale with player power level
|
|
425
|
-
- **Cultural Context**: Region-specific event generation
|
|
426
|
-
- **Time-based Events**: Events that change over time
|
|
427
|
-
|
|
428
619
|
---
|
|
429
620
|
|
|
430
621
|
**Generate infinite adventures with RPG Event Generator!** โ๏ธ๐โจ
|