@ak--47/dungeon-master 1.0.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.
- package/README.md +518 -0
- package/dungeons/array-of-object-lookup-schema.json +327 -0
- package/dungeons/array-of-object-lookup.js +220 -0
- package/dungeons/ecommerce-schema.json +462 -0
- package/dungeons/ecommerce.js +447 -0
- package/dungeons/education-schema.json +2409 -0
- package/dungeons/education.js +768 -0
- package/dungeons/fintech-schema.json +14034 -0
- package/dungeons/fintech.js +696 -0
- package/dungeons/foobar-schema.json +403 -0
- package/dungeons/foobar.js +296 -0
- package/dungeons/food-delivery-schema.json +192 -0
- package/dungeons/food-delivery.js +602 -0
- package/dungeons/food-schema.json +1152 -0
- package/dungeons/food.js +754 -0
- package/dungeons/gaming-schema.json +1270 -0
- package/dungeons/gaming.js +508 -0
- package/dungeons/insurance-application-schema.json +204 -0
- package/dungeons/insurance-application.js +605 -0
- package/dungeons/media-schema.json +906 -0
- package/dungeons/media.js +790 -0
- package/dungeons/retention-cadence-schema.json +78 -0
- package/dungeons/retention-cadence.js +244 -0
- package/dungeons/rpg-schema.json +4526 -0
- package/dungeons/rpg.js +919 -0
- package/dungeons/sanity-schema.json +255 -0
- package/dungeons/sanity.js +152 -0
- package/dungeons/sass-schema.json +1291 -0
- package/dungeons/sass.js +795 -0
- package/dungeons/scd-schema.json +919 -0
- package/dungeons/scd.js +277 -0
- package/dungeons/simple-schema.json +608 -0
- package/dungeons/simple.js +285 -0
- package/dungeons/simplest-schema.json +1418 -0
- package/dungeons/simplest.js +392 -0
- package/dungeons/social-schema.json +1118 -0
- package/dungeons/social.js +686 -0
- package/dungeons/text-generation-schema.json +3096 -0
- package/dungeons/text-generation.js +812 -0
- package/index.js +567 -0
- package/lib/core/config-validator.js +395 -0
- package/lib/core/context.js +204 -0
- package/lib/core/dungeon-loader.js +337 -0
- package/lib/core/storage.js +379 -0
- package/lib/generators/adspend.js +132 -0
- package/lib/generators/events.js +271 -0
- package/lib/generators/funnels.js +407 -0
- package/lib/generators/mirror.js +167 -0
- package/lib/generators/product-lookup.js +262 -0
- package/lib/generators/product-names.js +195 -0
- package/lib/generators/profiles.js +93 -0
- package/lib/generators/scd.js +124 -0
- package/lib/generators/text.js +1192 -0
- package/lib/orchestrators/mixpanel-sender.js +266 -0
- package/lib/orchestrators/user-loop.js +335 -0
- package/lib/templates/abbreviated.d.ts +169 -0
- package/lib/templates/defaults.js +1405 -0
- package/lib/templates/phrases.js +2526 -0
- package/lib/templates/schema.d.ts +173 -0
- package/lib/templates/soup-presets.js +188 -0
- package/lib/utils/function-registry.js +302 -0
- package/lib/utils/json-evaluator.js +172 -0
- package/lib/utils/logger.js +34 -0
- package/lib/utils/utils.js +1490 -0
- package/package.json +89 -0
- package/types.d.ts +865 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
|
|
2
|
+
import dayjs from "dayjs";
|
|
3
|
+
import utc from "dayjs/plugin/utc.js";
|
|
4
|
+
import "dotenv/config";
|
|
5
|
+
import * as u from "../lib/utils/utils.js";
|
|
6
|
+
import * as v from "ak-tools";
|
|
7
|
+
|
|
8
|
+
const SEED = "my-seed";
|
|
9
|
+
dayjs.extend(utc);
|
|
10
|
+
const chance = u.initChance(SEED);
|
|
11
|
+
const num_users = 12_000;
|
|
12
|
+
const days = 180;
|
|
13
|
+
|
|
14
|
+
/** @typedef {import("../types.d.ts").Dungeon} Config */
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
18
|
+
* DATASET OVERVIEW
|
|
19
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
20
|
+
*
|
|
21
|
+
* QuestForge — A D&D-inspired action RPG where players create characters,
|
|
22
|
+
* join parties, embark on quests, fight bosses, and level up. Think Baldur's
|
|
23
|
+
* Gate meets a mobile RPG with in-game purchases and seasonal content.
|
|
24
|
+
*
|
|
25
|
+
* CORE USER LOOP:
|
|
26
|
+
* Players install the app, create a character (race + class + alignment),
|
|
27
|
+
* and join a party. They then cycle through quests — starting quests,
|
|
28
|
+
* engaging in gameplay (attacks, defenses, enemy defeats), completing quests
|
|
29
|
+
* for gold rewards, fighting bosses, and leveling up. In-game purchases
|
|
30
|
+
* (gold, gems, weapons, armor, boosts) monetize the experience.
|
|
31
|
+
*
|
|
32
|
+
* SCALE: 12,000 users, ~1.08M events, 180 days
|
|
33
|
+
*
|
|
34
|
+
* KEY DIMENSIONS:
|
|
35
|
+
* - Platform: Mobile, Xbox, Playstation, Switch, Web
|
|
36
|
+
* - Game mode: Single Player vs Multiplayer (biased toward Multiplayer)
|
|
37
|
+
* - Character: 9 races, 12 classes, 9 alignments, 13 backgrounds
|
|
38
|
+
* - Quests: 5 types, 4 difficulties, 5 locations
|
|
39
|
+
* - Experiment: fast leveling / tension economy / free trial with A/B/C/Control
|
|
40
|
+
*
|
|
41
|
+
* FUNNELS:
|
|
42
|
+
* 1. Onboarding: app install → character creation → join party (80% conversion)
|
|
43
|
+
* 2. Quest loop: start quest → gameplay summary → complete quest (99% conversion)
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
48
|
+
* ANALYTICS HOOKS
|
|
49
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
50
|
+
*
|
|
51
|
+
* This dungeon has 3 deliberate patterns engineered via hooks:
|
|
52
|
+
*
|
|
53
|
+
* ───────────────────────────────────────────────────────────────────────────────
|
|
54
|
+
* 1. GOLD SCALING BY LEVEL (event hook)
|
|
55
|
+
* ───────────────────────────────────────────────────────────────────────────────
|
|
56
|
+
*
|
|
57
|
+
* PATTERN: On "complete quest" events, the quest reward (gold) is multiplied by
|
|
58
|
+
* (1 + level * 0.1), so a level-10 player earns 2x gold and a level-20 player
|
|
59
|
+
* earns 3x gold compared to level-1.
|
|
60
|
+
*
|
|
61
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
62
|
+
* - Report type: Insights
|
|
63
|
+
* - Event: "complete quest"
|
|
64
|
+
* - Measure: Average of "quest reward (gold)"
|
|
65
|
+
* - Breakdown: "level at end"
|
|
66
|
+
* - Expected: Linear increase — level 1 ≈ 55 gold, level 10 ≈ 110 gold,
|
|
67
|
+
* level 20 ≈ 165 gold. Clear positive correlation between level and reward.
|
|
68
|
+
*
|
|
69
|
+
* ───────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
* 2. WHALE PURCHASES (event hook)
|
|
71
|
+
* ───────────────────────────────────────────────────────────────────────────────
|
|
72
|
+
*
|
|
73
|
+
* PATTERN: ~33% of users (determined by first character of user_id hash) are
|
|
74
|
+
* "whales" who spend 1.8x on in-game purchases and are tagged is_whale: true.
|
|
75
|
+
*
|
|
76
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
77
|
+
*
|
|
78
|
+
* Report 1: Whale vs Normal Purchase Amounts
|
|
79
|
+
* - Report type: Insights
|
|
80
|
+
* - Event: "in-game purchase"
|
|
81
|
+
* - Measure: Average of "purchase amount"
|
|
82
|
+
* - Breakdown: "is_whale"
|
|
83
|
+
* - Expected: is_whale=true shows ~1.8x higher avg purchase amount than
|
|
84
|
+
* is_whale=false (e.g., ~18 vs ~10)
|
|
85
|
+
*
|
|
86
|
+
* Report 2: Revenue Concentration
|
|
87
|
+
* - Report type: Insights
|
|
88
|
+
* - Event: "in-game purchase"
|
|
89
|
+
* - Measure: Sum of "purchase amount"
|
|
90
|
+
* - Breakdown: "is_whale"
|
|
91
|
+
* - Expected: ~33% of users (whales) contribute disproportionate total revenue
|
|
92
|
+
*
|
|
93
|
+
* ───────────────────────────────────────────────────────────────────────────────
|
|
94
|
+
* 3. ALIGNMENT ARCHETYPE (user hook)
|
|
95
|
+
* ───────────────────────────────────────────────────────────────────────────────
|
|
96
|
+
*
|
|
97
|
+
* PATTERN: User profiles are enriched with an "archetype" property based on
|
|
98
|
+
* alignment. Evil alignments → "villain", Good alignments → "hero", others → "neutral".
|
|
99
|
+
*
|
|
100
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
101
|
+
*
|
|
102
|
+
* Report 1: Archetype Distribution
|
|
103
|
+
* - Report type: Insights
|
|
104
|
+
* - Event: Any event (e.g., "complete quest")
|
|
105
|
+
* - Measure: Total unique users
|
|
106
|
+
* - Breakdown: User profile "archetype"
|
|
107
|
+
* - Expected: Three segments — "hero" (~22%), "villain" (~22%), "neutral" (~56%)
|
|
108
|
+
* matching the 2/9, 2/9, 5/9 alignment split
|
|
109
|
+
*
|
|
110
|
+
* Report 2: Archetype Behavior Comparison
|
|
111
|
+
* - Report type: Insights
|
|
112
|
+
* - Event: "fight boss"
|
|
113
|
+
* - Measure: Total events per user
|
|
114
|
+
* - Breakdown: User profile "archetype"
|
|
115
|
+
* - Expected: All three archetypes should show similar event volumes
|
|
116
|
+
* (archetype doesn't affect gameplay — just a profiling hook)
|
|
117
|
+
*
|
|
118
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
119
|
+
* EXPECTED METRICS SUMMARY
|
|
120
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
121
|
+
*
|
|
122
|
+
* Hook | Metric | Baseline | Hook Effect | Ratio
|
|
123
|
+
* ────────────────────────|─────────────────────────|──────────|──────────────|──────
|
|
124
|
+
* Gold Scaling | Avg gold at level 1 | ~55 | ~55 | 1.0x
|
|
125
|
+
* Gold Scaling | Avg gold at level 10 | ~55 | ~110 | 2.0x
|
|
126
|
+
* Gold Scaling | Avg gold at level 20 | ~55 | ~165 | 3.0x
|
|
127
|
+
* Whale Purchases | Avg purchase (whale) | ~10 | ~18 | 1.8x
|
|
128
|
+
* Whale Purchases | Revenue share (whale) | ~33% | >50% | disprop.
|
|
129
|
+
* Alignment Archetype | Hero users | — | ~22% | 2/9
|
|
130
|
+
* Alignment Archetype | Villain users | — | ~22% | 2/9
|
|
131
|
+
* Alignment Archetype | Neutral users | — | ~56% | 5/9
|
|
132
|
+
*
|
|
133
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
134
|
+
* ADVANCED ANALYSIS IDEAS
|
|
135
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
136
|
+
*
|
|
137
|
+
* 1. Gold Economy Analysis: Plot avg gold earned by level AND quest difficulty.
|
|
138
|
+
* Do Legendary quests at high levels create outsized gold rewards?
|
|
139
|
+
*
|
|
140
|
+
* 2. Whale Segmentation: Cross-reference is_whale with platform and game mode.
|
|
141
|
+
* Are whales concentrated on mobile? Do multiplayer whales spend more?
|
|
142
|
+
*
|
|
143
|
+
* 3. Archetype × Class Matrix: Do certain class/archetype combos correlate
|
|
144
|
+
* with higher boss fight rates or quest completion?
|
|
145
|
+
*
|
|
146
|
+
* 4. Experiment Impact: Compare "fast leveling" vs "tension economy" vs
|
|
147
|
+
* "free trial" on purchase amounts, level progression, and retention.
|
|
148
|
+
*
|
|
149
|
+
* 5. Quest Difficulty Funnel: How does quest difficulty affect completion
|
|
150
|
+
* rate, death count, and hint/boost usage? Is "Legendary" too hard?
|
|
151
|
+
*
|
|
152
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
/** @type {Config} */
|
|
156
|
+
const config = {
|
|
157
|
+
token: "",
|
|
158
|
+
seed: "i am gamer face",
|
|
159
|
+
numDays: days,
|
|
160
|
+
numEvents: num_users * 90,
|
|
161
|
+
numUsers: num_users,
|
|
162
|
+
hasAnonIds: false,
|
|
163
|
+
hasSessionIds: false,
|
|
164
|
+
format: "json",
|
|
165
|
+
alsoInferFunnels: true,
|
|
166
|
+
hasLocation: true,
|
|
167
|
+
hasAndroidDevices: false,
|
|
168
|
+
hasIOSDevices: false,
|
|
169
|
+
hasDesktopDevices: false,
|
|
170
|
+
hasBrowser: false,
|
|
171
|
+
hasCampaigns: false,
|
|
172
|
+
isAnonymous: false,
|
|
173
|
+
hasAdSpend: false,
|
|
174
|
+
percentUsersBornInDataset: 25,
|
|
175
|
+
|
|
176
|
+
hasAvatar: true,
|
|
177
|
+
|
|
178
|
+
batchSize: 2_500_000,
|
|
179
|
+
concurrency: 1,
|
|
180
|
+
writeToDisk: false,
|
|
181
|
+
funnels: [
|
|
182
|
+
{
|
|
183
|
+
"sequence": ["app install", "character creation", "join party"],
|
|
184
|
+
"isFirstFunnel": true,
|
|
185
|
+
"conversionRate": 0.8,
|
|
186
|
+
"timeToConvert": .25,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"sequence": ["start quest", "gameplay summary", "complete quest"],
|
|
190
|
+
conversionRate: 0.99,
|
|
191
|
+
timeToConvert: 1,
|
|
192
|
+
props: {
|
|
193
|
+
"quest type": [
|
|
194
|
+
"Rescue",
|
|
195
|
+
"Retrieve",
|
|
196
|
+
"Explore",
|
|
197
|
+
"Destroy",
|
|
198
|
+
"Investigate",
|
|
199
|
+
],
|
|
200
|
+
"quest difficulty": [
|
|
201
|
+
"Easy",
|
|
202
|
+
"Medium",
|
|
203
|
+
"Hard",
|
|
204
|
+
"Legendary",
|
|
205
|
+
],
|
|
206
|
+
"quest location": [
|
|
207
|
+
"Forest",
|
|
208
|
+
"Dungeon",
|
|
209
|
+
"Mountain",
|
|
210
|
+
"City",
|
|
211
|
+
"Desert",
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
events: [
|
|
217
|
+
{ event: "app install", weight: 10, isFirstEvent: true },
|
|
218
|
+
{
|
|
219
|
+
event: "character creation",
|
|
220
|
+
weight: 2,
|
|
221
|
+
properties: {
|
|
222
|
+
mode: ["fast", "slow", "template"],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
event: "join party",
|
|
227
|
+
weight: 8,
|
|
228
|
+
properties: {
|
|
229
|
+
"party size": u.weighNumRange(1, 6),
|
|
230
|
+
"party leader": [
|
|
231
|
+
"Bard",
|
|
232
|
+
"Cleric",
|
|
233
|
+
"Fighter",
|
|
234
|
+
"Rogue",
|
|
235
|
+
"Wizard",
|
|
236
|
+
"Paladin",
|
|
237
|
+
"Ranger",
|
|
238
|
+
"Sorcerer",
|
|
239
|
+
"Warlock",
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
event: "start quest",
|
|
245
|
+
weight: 12,
|
|
246
|
+
properties: {
|
|
247
|
+
"quest type": [
|
|
248
|
+
"Rescue",
|
|
249
|
+
"Retrieve",
|
|
250
|
+
"Explore",
|
|
251
|
+
"Destroy",
|
|
252
|
+
"Investigate",
|
|
253
|
+
],
|
|
254
|
+
"quest difficulty": [
|
|
255
|
+
"Easy",
|
|
256
|
+
"Medium",
|
|
257
|
+
"Hard",
|
|
258
|
+
"Legendary",
|
|
259
|
+
],
|
|
260
|
+
"quest location": [
|
|
261
|
+
"Forest",
|
|
262
|
+
"Dungeon",
|
|
263
|
+
"Mountain",
|
|
264
|
+
"City",
|
|
265
|
+
"Desert",
|
|
266
|
+
],
|
|
267
|
+
"party size": u.weighNumRange(1, 6),
|
|
268
|
+
"used hint": u.pickAWinner(["yes", "no"], 0.3),
|
|
269
|
+
"used boost": u.pickAWinner(["yes", "no"], 0.2),
|
|
270
|
+
"level at start": u.weighNumRange(1, 20),
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
event: "complete quest",
|
|
275
|
+
weight: 12,
|
|
276
|
+
properties: {
|
|
277
|
+
"completion time (mins)": u.weighNumRange(5, 120, 1, 30),
|
|
278
|
+
"quest reward (gold)": u.weighNumRange(10, 500, 1, 100),
|
|
279
|
+
"quest success": u.pickAWinner(["yes", "no"], 0.9),
|
|
280
|
+
"used hint": u.pickAWinner(["yes", "no"], 0.3),
|
|
281
|
+
"used boost": u.pickAWinner(["yes", "no"], 0.2),
|
|
282
|
+
"number of deaths": u.weighNumRange(0, 5, 1, 2),
|
|
283
|
+
"level at start": u.weighNumRange(1, 20),
|
|
284
|
+
"level at end": u.weighNumRange(1, 20),
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"event": "gameplay summary",
|
|
289
|
+
"weight": 14,
|
|
290
|
+
"properties": {
|
|
291
|
+
"# enemies defeated": u.weighNumRange(0, 100),
|
|
292
|
+
"# respawns": u.weighNumRange(0, 10, 5),
|
|
293
|
+
"# attacks": u.weighNumRange(0, 100, 6, 12),
|
|
294
|
+
"# gold found": u.weighNumRange(0, 1000),
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"event": "in-game purchase",
|
|
299
|
+
"weight": 2,
|
|
300
|
+
"properties": {
|
|
301
|
+
"purchase type": [
|
|
302
|
+
"Gold",
|
|
303
|
+
"Gems",
|
|
304
|
+
"Items: Weapons",
|
|
305
|
+
"Items: Armor",
|
|
306
|
+
"Items: Potions",
|
|
307
|
+
"Items: Scrolls",
|
|
308
|
+
"Boosts",
|
|
309
|
+
"Currency",
|
|
310
|
+
],
|
|
311
|
+
"purchase amount": u.weighNumRange(1, 50, 1, 20),
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
event: "fight boss",
|
|
316
|
+
weight: 3,
|
|
317
|
+
properties: {
|
|
318
|
+
"boss type": [
|
|
319
|
+
"Dragon",
|
|
320
|
+
"Demon",
|
|
321
|
+
"Lich",
|
|
322
|
+
"Vampire",
|
|
323
|
+
"Beholder",
|
|
324
|
+
],
|
|
325
|
+
"boss level": u.weighNumRange(10, 20),
|
|
326
|
+
"boss difficulty": [
|
|
327
|
+
"Hard",
|
|
328
|
+
"Legendary",
|
|
329
|
+
"Impossible",
|
|
330
|
+
],
|
|
331
|
+
"fight duration (mins)": u.weighNumRange(1, 60),
|
|
332
|
+
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
event: "level up",
|
|
337
|
+
weight: 1,
|
|
338
|
+
properties: {
|
|
339
|
+
"new abilities": [
|
|
340
|
+
"Attack",
|
|
341
|
+
"Spell",
|
|
342
|
+
"Feat",
|
|
343
|
+
"Skill",
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
event: "attack",
|
|
349
|
+
weight: 5,
|
|
350
|
+
properties: {
|
|
351
|
+
generic_prop: ["foo", "bar", "baz", "qux"],
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
event: "defend",
|
|
356
|
+
weight: 3,
|
|
357
|
+
properties: {
|
|
358
|
+
generic_prop: ["foo", "bar", "baz", "qux"],
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
superProps: {
|
|
363
|
+
platform: [
|
|
364
|
+
"Mobile",
|
|
365
|
+
"Xbox",
|
|
366
|
+
"Playstation",
|
|
367
|
+
"Switch",
|
|
368
|
+
"Web"
|
|
369
|
+
],
|
|
370
|
+
"game mode": u.pickAWinner([
|
|
371
|
+
"Single Player",
|
|
372
|
+
"Multiplayer",
|
|
373
|
+
], 1),
|
|
374
|
+
language: [
|
|
375
|
+
"English",
|
|
376
|
+
"Spanish",
|
|
377
|
+
"French",
|
|
378
|
+
"German",
|
|
379
|
+
"Japanese",
|
|
380
|
+
"Korean",
|
|
381
|
+
"Chinese",
|
|
382
|
+
],
|
|
383
|
+
|
|
384
|
+
},
|
|
385
|
+
scdProps: {
|
|
386
|
+
// "subscription MRR" : {
|
|
387
|
+
// "frequency": "week",
|
|
388
|
+
// "type": "number",
|
|
389
|
+
// values: u.weighNumRange(0, 250, 1, 200),
|
|
390
|
+
// timing: "fixed",
|
|
391
|
+
// max: 250,
|
|
392
|
+
// }
|
|
393
|
+
},
|
|
394
|
+
userProps: {
|
|
395
|
+
experiment: [
|
|
396
|
+
"fast leveling",
|
|
397
|
+
"tension economy",
|
|
398
|
+
"free trial",
|
|
399
|
+
],
|
|
400
|
+
variant: ["A", "B", "C", "Control"],
|
|
401
|
+
|
|
402
|
+
race: [
|
|
403
|
+
"Human",
|
|
404
|
+
"Elf",
|
|
405
|
+
"Dwarf",
|
|
406
|
+
"Halfling",
|
|
407
|
+
"Dragonborn",
|
|
408
|
+
"Gnome",
|
|
409
|
+
"Half-Elf",
|
|
410
|
+
"Half-Orc",
|
|
411
|
+
"Tiefling",
|
|
412
|
+
],
|
|
413
|
+
class: [
|
|
414
|
+
"Barbarian",
|
|
415
|
+
"Bard",
|
|
416
|
+
"Cleric",
|
|
417
|
+
"Druid",
|
|
418
|
+
"Fighter",
|
|
419
|
+
"Monk",
|
|
420
|
+
"Paladin",
|
|
421
|
+
"Ranger",
|
|
422
|
+
"Rogue",
|
|
423
|
+
"Sorcerer",
|
|
424
|
+
"Warlock",
|
|
425
|
+
"Wizard",
|
|
426
|
+
],
|
|
427
|
+
alignment: [
|
|
428
|
+
"Lawful Good",
|
|
429
|
+
"Neutral Good",
|
|
430
|
+
"Chaotic Good",
|
|
431
|
+
"Lawful Neutral",
|
|
432
|
+
"True Neutral",
|
|
433
|
+
"Chaotic Neutral",
|
|
434
|
+
"Lawful Evil",
|
|
435
|
+
"Neutral Evil",
|
|
436
|
+
"Chaotic Evil",
|
|
437
|
+
],
|
|
438
|
+
level: u.weighNumRange(1, 20),
|
|
439
|
+
background: [
|
|
440
|
+
"Acolyte",
|
|
441
|
+
"Charlatan",
|
|
442
|
+
"Criminal",
|
|
443
|
+
"Entertainer",
|
|
444
|
+
"Folk Hero",
|
|
445
|
+
"Guild Artisan",
|
|
446
|
+
"Hermit",
|
|
447
|
+
"Noble",
|
|
448
|
+
"Outlander",
|
|
449
|
+
"Sage",
|
|
450
|
+
"Sailor",
|
|
451
|
+
"Soldier",
|
|
452
|
+
"Urchin",
|
|
453
|
+
],
|
|
454
|
+
"subscription MRR": u.weighNumRange(0, 250, 1, 200)
|
|
455
|
+
},
|
|
456
|
+
// HOOK: 3 patterns — gold scaling by level, whale purchases, alignment archetype
|
|
457
|
+
hook: function (record, type, meta) {
|
|
458
|
+
|
|
459
|
+
if (type === "event") {
|
|
460
|
+
// Pattern 1: Higher-level players earn more gold and defeat more enemies
|
|
461
|
+
if (record.event === "complete quest") {
|
|
462
|
+
const level = record["level at end"] || 1;
|
|
463
|
+
record["quest reward (gold)"] = Math.round((record["quest reward (gold)"] || 50) * (1 + level * 0.1));
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Pattern 2: In-game purchases are bigger for "free trial" experiment users
|
|
467
|
+
if (record.event === "in-game purchase") {
|
|
468
|
+
// We don't have profile here, so use a hash-based approach
|
|
469
|
+
const uid = record.user_id || record.distinct_id || "";
|
|
470
|
+
if (uid.charCodeAt(0) % 3 === 0) {
|
|
471
|
+
record["purchase amount"] = Math.round((record["purchase amount"] || 10) * 1.8);
|
|
472
|
+
record.is_whale = true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (type === "user") {
|
|
478
|
+
// Pattern 3: Chaotic Evil players get a "villain" tag; Lawful Good get "hero"
|
|
479
|
+
if (record.alignment === "Chaotic Evil" || record.alignment === "Neutral Evil") {
|
|
480
|
+
record.archetype = "villain";
|
|
481
|
+
} else if (record.alignment === "Lawful Good" || record.alignment === "Neutral Good") {
|
|
482
|
+
record.archetype = "hero";
|
|
483
|
+
} else {
|
|
484
|
+
record.archetype = "neutral";
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (type === "funnel-post") {
|
|
489
|
+
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (type === "funnel-pre") {
|
|
493
|
+
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (type === "scd") {
|
|
497
|
+
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (type === "everything") {
|
|
501
|
+
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return record;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
export default config;
|