@ak--47/dungeon-master 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +51 -13
  3. package/dungeons/technical/ad-spend.js +2 -2
  4. package/dungeons/technical/anonymous-users.js +2 -2
  5. package/dungeons/technical/array-of-object-lookup.js +2 -2
  6. package/dungeons/technical/experiments.js +2 -2
  7. package/dungeons/technical/foobar.js +2 -2
  8. package/dungeons/technical/group-analytics.js +2 -2
  9. package/dungeons/technical/mirror-strategies.js +2 -2
  10. package/dungeons/technical/nested-objects.js +2 -2
  11. package/dungeons/technical/retention-cadence.js +2 -3
  12. package/dungeons/technical/sanity.js +2 -2
  13. package/dungeons/technical/scale-test.js +2 -2
  14. package/dungeons/technical/scd.js +2 -2
  15. package/dungeons/technical/simple.js +2 -2
  16. package/dungeons/technical/simplest.js +2 -2
  17. package/dungeons/technical/text-generation.js +2 -2
  18. package/dungeons/vertical/ai-platform-schema.json +617 -0
  19. package/dungeons/vertical/ai-platform.js +799 -0
  20. package/dungeons/vertical/community.js +40 -26
  21. package/dungeons/vertical/crypto-schema.json +546 -0
  22. package/dungeons/vertical/crypto.js +721 -0
  23. package/dungeons/vertical/dating-schema.json +401 -0
  24. package/dungeons/vertical/dating.js +798 -0
  25. package/dungeons/vertical/devtools.js +13 -9
  26. package/dungeons/vertical/ecommerce.js +2 -3
  27. package/dungeons/vertical/education.js +4 -5
  28. package/dungeons/vertical/fintech.js +32 -29
  29. package/dungeons/vertical/fitness.js +2 -3
  30. package/dungeons/vertical/food-delivery.js +37 -43
  31. package/dungeons/vertical/gaming-schema.json +2495 -230
  32. package/dungeons/vertical/gaming.js +771 -388
  33. package/dungeons/vertical/healthcare.js +2 -3
  34. package/dungeons/vertical/insurance-application.js +2 -3
  35. package/dungeons/vertical/logistics.js +20 -14
  36. package/dungeons/vertical/marketplace.js +22 -14
  37. package/dungeons/vertical/media.js +39 -30
  38. package/dungeons/vertical/real-estate-schema.json +527 -0
  39. package/dungeons/vertical/real-estate.js +774 -0
  40. package/dungeons/vertical/sass.js +2 -3
  41. package/dungeons/vertical/social.js +15 -13
  42. package/dungeons/vertical/travel.js +59 -26
  43. package/lib/core/config-validator.js +71 -15
  44. package/lib/core/storage.js +14 -4
  45. package/lib/orchestrators/user-loop.js +39 -5
  46. package/lib/templates/macro-presets.js +111 -0
  47. package/lib/templates/soup-presets.js +19 -36
  48. package/package.json +8 -2
  49. package/types.d.ts +219 -42
  50. package/dungeons/user/.gitkeep +0 -0
  51. package/dungeons/vertical/rpg-schema.json +0 -2491
  52. package/dungeons/vertical/rpg.js +0 -976
@@ -1,8 +1,8 @@
1
1
  // ── TWEAK THESE ──
2
- const SEED = "my-seed";
3
- const num_days = 180;
4
- const num_users = 12_000;
5
- const avg_events_per_user = 90;
2
+ const SEED = "questforge";
3
+ const num_days = 100;
4
+ const num_users = 5_000;
5
+ const avg_events_per_user_per_day = 1.2;
6
6
  let token = "your-mixpanel-token";
7
7
 
8
8
  // ── env overrides ──
@@ -24,497 +24,553 @@ const chance = u.initChance(SEED);
24
24
  * DATASET OVERVIEW
25
25
  * ═══════════════════════════════════════════════════════════════════════════════
26
26
  *
27
- * QuestForge — A D&D-inspired action RPG where players create characters,
28
- * join parties, embark on quests, fight bosses, and level up. Think Baldur's
29
- * Gate meets a mobile RPG with in-game purchases and seasonal content.
27
+ * QuestForge — a D&D-inspired action RPG with a deep character system, party-
28
+ * based dungeon crawls, boss fights, a player-driven economy, guilds, and
29
+ * subscription tiers. Combines the strategic depth of a tabletop RPG with the
30
+ * monetization and engagement loops of a modern live-service game.
30
31
  *
31
- * CORE USER LOOP:
32
- * Players install the app, create a character (race + class + alignment),
33
- * and join a party. They then cycle through quests — starting quests,
34
- * engaging in gameplay (attacks, defenses, enemy defeats), completing quests
35
- * for gold rewards, fighting bosses, and leveling up. In-game purchases
36
- * (gold, gems, weapons, armor, boosts) monetize the experience.
32
+ * CORE LOOP: Players create characters (12 classes, 9 races, 9 alignments,
33
+ * 13 backgrounds) and progress through quests, dungeon crawls, boss fights,
34
+ * and combat encounters. Strategic preparation (inspect, search for clues,
35
+ * Ancient Compass) creates skill gaps. Guild membership drives social
36
+ * retention. Monetization via premium currency, lucky charms, season pass,
37
+ * and subscription tiers (Free / Premium / Elite).
37
38
  *
38
- * SCALE: 12,000 users, ~1.08M events, 180 days
39
+ * SCALE: 5,000 users × 120 events = 600K events over 100 days
40
+ * 24 event types, 7 funnels, guild group analytics, subscription tiers
39
41
  *
40
- * KEY DIMENSIONS:
41
- * - Platform: Mobile, Xbox, Playstation, Switch, Web
42
- * - Game mode: Single Player vs Multiplayer (biased toward Multiplayer)
43
- * - Character: 9 races, 12 classes, 9 alignments, 13 backgrounds
44
- * - Quests: 5 types, 4 difficulties, 5 locations
45
- * - Experiment: fast leveling / tension economy / free trial with A/B/C/Control
46
- *
47
- * FUNNELS:
48
- * 1. Onboarding: app install character creation join party (80% conversion)
49
- * 2. Quest loop: start quest gameplay summary complete quest (99% conversion)
42
+ * KEY SYSTEMS:
43
+ * - Character: 12 D&D classes, 9 races, 9 alignments, 13 backgrounds
44
+ * - Quests: accept objective turn in (5 quest types, gold/XP rewards)
45
+ * - Dungeons: enter find treasure exit (50 dungeons, party-based, 3 outcomes)
46
+ * - Combat: initiate → complete (6 enemy types), boss fights, attack/defend
47
+ * - Economy: item purchase/sell, real money purchases, vendor types
48
+ * - Progression: level up (1-50), stat points, level-scaled rewards
49
+ * - Social: guild join/leave (5-100 members, guild levels 1-20)
50
+ * - Monetization: premium currency, lucky charms, legendary chests, season pass
51
+ * - Subscriptions: Free / Premium ($9.99/mo) / Elite ($19.99/mo)
52
+ * - Experiments: A/B/C/Control variants across "fast leveling", "tension
53
+ * economy", "free trial"
50
54
  */
51
55
 
52
56
  /*
53
57
  * ═══════════════════════════════════════════════════════════════════════════════
54
- * ANALYTICS HOOKS
58
+ * ANALYTICS HOOKS (11 architected patterns)
55
59
  * ═══════════════════════════════════════════════════════════════════════════════
56
60
  *
57
- * This dungeon has 3 deliberate patterns engineered via hooks:
58
- *
59
- * ───────────────────────────────────────────────────────────────────────────────
60
- * 1. GOLD SCALING BY LEVEL (event hook)
61
- * ───────────────────────────────────────────────────────────────────────────────
61
+ * 1. CONVERSION: Ancient Compass Effect
62
+ * Players who use the "Ancient Compass" item have 3x quest completion rate
63
+ * and earn 1.5x more rewards.
64
+ * Mixpanel: Segment users by "use item" where item_type = "Ancient Compass"
65
+ * Compare quest completion rate and average reward_gold / reward_xp
66
+ * → Look for compass_user = true on quest turned in events
62
67
  *
63
- * PATTERN: On "complete quest" events, the quest reward (gold) is multiplied by
64
- * (1 + level * 0.1), so a level-10 player earns 2x gold and a level-20 player
65
- * earns 3x gold compared to level-1.
68
+ * 2. TIME-BASED: Cursed Week (days 40-47)
69
+ * Death rates spike 5x, dungeon completion plummets, resurrection usage 4x.
70
+ * Mixpanel: Chart "player death" count by day — clear spike days 40-47
71
+ * → Filter cause_of_death = "Curse" and cursed_week = true
66
72
  *
67
- * HOW TO FIND IT IN MIXPANEL:
68
- * - Report type: Insights
69
- * - Event: "complete quest"
70
- * - Measure: Average of "quest reward (gold)"
71
- * - Breakdown: "level at end"
72
- * - Expected: Linear increase — level 1 ≈ 55 gold, level 10 ≈ 110 gold,
73
- * level 20 ≈ 165 gold. Clear positive correlation between level and reward.
73
+ * 3. RETENTION: Early Guild Joiners
74
+ * Players who join a guild within first 3 days have 80% D30 retention vs 20%.
75
+ * Mixpanel: Cohort users who did "guild joined" within first 3 days
76
+ * Compare D30 retention rate; look for guild_member_retained = true
74
77
  *
75
- * ───────────────────────────────────────────────────────────────────────────────
76
- * 2. WHALE PURCHASES (event hook)
77
- * ───────────────────────────────────────────────────────────────────────────────
78
+ * 4. CHURN: Death Spiral
79
+ * Players with 3+ deaths in first week have 70% churn rate (events removed).
80
+ * Mixpanel: Segment users by count of "player death" in first 7 days
81
+ * → Bucket: 0-2, 3-4, 5+ deaths — compare events after day 7
78
82
  *
79
- * PATTERN: ~33% of users (determined by first character of user_id hash) are
80
- * "whales" who spend 1.8x on in-game purchases and are tagged is_whale: true.
83
+ * 5. PURCHASE VALUE: Lucky Charm LTV
84
+ * Lucky Charm Pack buyers become 5x higher LTV customers.
85
+ * → Mixpanel: Segment by "real money purchase" where product = "Lucky Charm Pack"
86
+ * → Compare total revenue, purchase frequency; look for lucky_charm_effect = true
81
87
  *
82
- * HOW TO FIND IT IN MIXPANEL:
88
+ * 6. BEHAVIORS TOGETHER: Strategic Explorers
89
+ * Players who both "inspect" AND "search for clues" before dungeons have
90
+ * 85% dungeon completion (vs 45%) and 2x treasure value.
91
+ * → Look for strategic_explorer = true on exit dungeon / find treasure events
83
92
  *
84
- * Report 1: Whale vs Normal Purchase Amounts
85
- * - Report type: Insights
86
- * - Event: "in-game purchase"
87
- * - Measure: Average of "purchase amount"
88
- * - Breakdown: "is_whale"
89
- * - Expected: is_whale=true shows ~1.8x higher avg purchase amount than
90
- * is_whale=false (e.g., ~18 vs ~10)
93
+ * 7. TIMED RELEASE: Shadowmourne Legendary Weapon (day 45)
94
+ * 2% of players find the legendary weapon after release. They get 90% combat
95
+ * win rate (vs 60%) and complete dungeons 40% faster.
96
+ * Filter "find treasure" where treasure_type = "Shadowmourne Legendary"
97
+ * Look for legendary_weapon_equipped = true
91
98
  *
92
- * Report 2: Revenue Concentration
93
- * - Report type: Insights
94
- * - Event: "in-game purchase"
95
- * - Measure: Sum of "purchase amount"
96
- * - Breakdown: "is_whale"
97
- * - Expected: ~33% of users (whales) contribute disproportionate total revenue
99
+ * 8. SUBSCRIPTION TIER: Premium/Elite Advantage
100
+ * Premium: 50% better combat wins, 1.4x rewards, 45% higher dungeon completion
101
+ * Elite: 70% better combat wins, 1.8x rewards, 65% higher dungeon completion,
102
+ * bonus treasure events, reduced death rates.
103
+ * Segment by subscription_tier super property
104
+ * Look for subscriber_advantage = "Premium" or "Elite"
98
105
  *
99
- * ───────────────────────────────────────────────────────────────────────────────
100
- * 3. ALIGNMENT ARCHETYPE (user hook)
101
- * ───────────────────────────────────────────────────────────────────────────────
106
+ * 9. PROGRESSION SCALING: Gold Reward by Level
107
+ * Quest gold reward scales with player level: reward_gold *= (1 + level * 0.1).
108
+ * A level-10 player earns 2x gold and a level-20 player earns 3x gold vs level-1.
109
+ * → Mixpanel: Insights on "quest turned in", avg of reward_gold, breakdown by level
110
+ * → Expected: linear positive correlation between level and avg reward_gold
102
111
  *
103
- * PATTERN: User profiles are enriched with an "archetype" property based on
104
- * alignment. Evil alignments "villain", Good alignments "hero", others "neutral".
112
+ * 10. WHALE PURCHASES: Top-Spender Cohort
113
+ * ~33% of users (deterministic via user_id hash) are "whales" who spend 1.8x
114
+ * on real money purchases and are tagged is_whale: true.
115
+ * → Mixpanel: Insights on "real money purchase", avg of price_usd, breakdown by is_whale
116
+ * → Expected: is_whale=true ~1.8x higher avg purchase amount than is_whale=false
105
117
  *
106
- * HOW TO FIND IT IN MIXPANEL:
118
+ * 11. ALIGNMENT ARCHETYPE: Hero / Villain / Neutral
119
+ * User profiles are enriched with an "archetype" derived from alignment:
120
+ * Good → "hero" (~22%), Evil → "villain" (~22%), other → "neutral" (~56%).
121
+ * → Mixpanel: Insights, total unique users, breakdown by user profile "archetype"
107
122
  *
108
- * Report 1: Archetype Distribution
109
- * - Report type: Insights
110
- * - Event: Any event (e.g., "complete quest")
111
- * - Measure: Total unique users
112
- * - Breakdown: User profile "archetype"
113
- * - Expected: Three segments — "hero" (~22%), "villain" (~22%), "neutral" (~56%)
114
- * matching the 2/9, 2/9, 5/9 alignment split
115
- *
116
- * Report 2: Archetype Behavior Comparison
117
- * - Report type: Insights
118
- * - Event: "fight boss"
119
- * - Measure: Total events per user
120
- * - Breakdown: User profile "archetype"
121
- * - Expected: All three archetypes should show similar event volumes
122
- * (archetype doesn't affect gameplay — just a profiling hook)
123
- *
124
- * ═══════════════════════════════════════════════════════════════════════════════
123
+ * ───────────────────────────────────────────────────────────────────────────────
125
124
  * EXPECTED METRICS SUMMARY
126
- * ═══════════════════════════════════════════════════════════════════════════════
127
- *
128
- * Hook | Metric | Baseline | Hook Effect | Ratio
129
- * ────────────────────────|─────────────────────────|──────────|──────────────|──────
130
- * Gold Scaling | Avg gold at level 1 | ~55 | ~55 | 1.0x
131
- * Gold Scaling | Avg gold at level 10 | ~55 | ~110 | 2.0x
132
- * Gold Scaling | Avg gold at level 20 | ~55 | ~165 | 3.0x
133
- * Whale Purchases | Avg purchase (whale) | ~10 | ~18 | 1.8x
134
- * Whale Purchases | Revenue share (whale) | ~33% | >50% | disprop.
135
- * Alignment Archetype | Hero users | — | ~22% | 2/9
136
- * Alignment Archetype | Villain users | — | ~22% | 2/9
137
- * Alignment Archetype | Neutral users | — | ~56% | 5/9
138
- *
139
- * ═══════════════════════════════════════════════════════════════════════════════
140
- * ADVANCED ANALYSIS IDEAS
141
- * ═══════════════════════════════════════════════════════════════════════════════
142
- *
143
- * 1. Gold Economy Analysis: Plot avg gold earned by level AND quest difficulty.
144
- * Do Legendary quests at high levels create outsized gold rewards?
145
- *
146
- * 2. Whale Segmentation: Cross-reference is_whale with platform and game mode.
147
- * Are whales concentrated on mobile? Do multiplayer whales spend more?
148
- *
149
- * 3. Archetype × Class Matrix: Do certain class/archetype combos correlate
150
- * with higher boss fight rates or quest completion?
151
- *
152
- * 4. Experiment Impact: Compare "fast leveling" vs "tension economy" vs
153
- * "free trial" on purchase amounts, level progression, and retention.
154
- *
155
- * 5. Quest Difficulty Funnel: How does quest difficulty affect completion
156
- * rate, death count, and hint/boost usage? Is "Legendary" too hard?
125
+ * ───────────────────────────────────────────────────────────────────────────────
157
126
  *
158
- * ═══════════════════════════════════════════════════════════════════════════════
127
+ * Hook | Metric | Baseline | Hook Effect | Ratio
128
+ * ──────────────────────|──────────────────────|──────────|─────────────|──────
129
+ * Ancient Compass | Quest completion | 55% | 85-90% | ~1.6x
130
+ * Cursed Week | Death rate | 8% | 40% | 5x
131
+ * Early Guild Join | D30 Retention | 20% | 80% | 4x
132
+ * Death Spiral | Retention (3+ deaths)| 100% | 30% | 0.3x
133
+ * Lucky Charm | LTV | $15 | $75 | 5x
134
+ * Strategic Explorer | Dungeon completion | 45% | 85% | ~1.9x
135
+ * Legendary Weapon | Combat win rate | 60% | 90% | 1.5x
136
+ * Premium Tier | Combat win rate | 60% | 90% | 1.5x
137
+ * Elite Tier | Combat win rate | 60% | 102% | 1.7x
138
+ * Gold Scaling (lvl 10) | Avg quest gold | ~100 | ~200 | 2.0x
139
+ * Gold Scaling (lvl 20) | Avg quest gold | ~100 | ~300 | 3.0x
140
+ * Whale Purchases | Avg real money spend | ~$15 | ~$27 | 1.8x
141
+ * Hero archetype | User share | — | ~22% | 2/9
142
+ * Villain archetype | User share | — | ~22% | 2/9
143
+ * Neutral archetype | User share | — | ~56% | 5/9
159
144
  */
160
145
 
146
+ // Generate consistent item/location IDs for lookup tables
147
+ const dungeonIds = v.range(1, 51).map(n => `dungeon_${v.uid(6)}`);
148
+ const questIds = v.range(1, 201).map(n => `quest_${v.uid(8)}`);
149
+ const itemIds = v.range(1, 301).map(n => `item_${v.uid(7)}`);
150
+
161
151
  /** @type {Config} */
162
152
  const config = {
163
153
  token,
164
- seed: "i am gamer face",
154
+ seed: SEED,
165
155
  numDays: num_days,
166
- numEvents: num_users * avg_events_per_user,
156
+ avgEventsPerUserPerDay: avg_events_per_user_per_day,
167
157
  numUsers: num_users,
168
158
  hasAnonIds: false,
169
- hasSessionIds: false,
159
+ hasSessionIds: true,
170
160
  format: "json",
171
- alsoInferFunnels: true,
161
+ gzip: true,
162
+ alsoInferFunnels: false,
172
163
  hasLocation: true,
173
- hasAndroidDevices: false,
174
- hasIOSDevices: false,
175
- hasDesktopDevices: false,
164
+ hasAndroidDevices: true,
165
+ hasIOSDevices: true,
166
+ hasDesktopDevices: true,
176
167
  hasBrowser: false,
177
168
  hasCampaigns: false,
178
169
  isAnonymous: false,
179
170
  hasAdSpend: false,
180
- percentUsersBornInDataset: 25,
181
171
 
182
172
  hasAvatar: true,
183
173
 
184
174
  concurrency: 1,
185
175
  writeToDisk: false,
176
+
186
177
  funnels: [
187
178
  {
188
- "sequence": ["app install", "character creation", "join party"],
189
- "isFirstFunnel": true,
190
- "conversionRate": 0.8,
191
- "timeToConvert": .25,
179
+ sequence: ["character created", "tutorial completed", "quest accepted"],
180
+ isFirstFunnel: true,
181
+ conversionRate: 75,
182
+ timeToConvert: 0.5,
192
183
  },
193
184
  {
194
- "sequence": ["start quest", "gameplay summary", "complete quest"],
195
- conversionRate: 0.99,
196
- timeToConvert: 1,
185
+ // Core combat loop: most frequent player activity
186
+ sequence: ["combat initiated", "combat completed", "use item"],
187
+ conversionRate: 75,
188
+ timeToConvert: 0.5,
189
+ weight: 5,
190
+ },
191
+ {
192
+ // Dungeon crawl: enter, explore, loot, exit
193
+ sequence: ["enter dungeon", "find treasure", "exit dungeon"],
194
+ conversionRate: 60,
195
+ timeToConvert: 2,
196
+ weight: 4,
197
197
  props: {
198
- "quest type": [
199
- "Rescue",
200
- "Retrieve",
201
- "Explore",
202
- "Destroy",
203
- "Investigate",
204
- ],
205
- "quest difficulty": [
206
- "Easy",
207
- "Medium",
208
- "Hard",
209
- "Legendary",
210
- ],
211
- "quest location": [
212
- "Forest",
213
- "Dungeon",
214
- "Mountain",
215
- "City",
216
- "Desert",
217
- ]
198
+ "dungeon_id": dungeonIds,
199
+ "difficulty": ["Easy", "Medium", "Hard", "Deadly"],
218
200
  }
219
201
  },
202
+ {
203
+ // Quest lifecycle
204
+ sequence: ["quest accepted", "quest objective completed", "quest turned in"],
205
+ conversionRate: 55,
206
+ timeToConvert: 3,
207
+ weight: 3,
208
+ props: { "quest_id": questIds },
209
+ },
210
+ {
211
+ // Preparation before dungeon: inspect + search for strategic explorer hook
212
+ sequence: ["inspect", "search for clues", "enter dungeon"],
213
+ conversionRate: 50,
214
+ timeToConvert: 1,
215
+ weight: 3,
216
+ },
217
+ {
218
+ // Economy: buy gear, sell loot
219
+ sequence: ["item purchased", "use item", "item sold"],
220
+ conversionRate: 45,
221
+ timeToConvert: 6,
222
+ weight: 2,
223
+ },
224
+ {
225
+ // Social and progression
226
+ sequence: ["guild joined", "level up", "real money purchase"],
227
+ conversionRate: 25,
228
+ timeToConvert: 24,
229
+ weight: 1,
230
+ },
220
231
  ],
232
+
221
233
  events: [
222
- { event: "app install", weight: 10, isFirstEvent: true },
223
234
  {
224
- event: "character creation",
235
+ event: "character created",
236
+ weight: 1,
237
+ isFirstEvent: true,
238
+ properties: {
239
+ "character_class": [
240
+ "Barbarian", "Bard", "Cleric", "Druid", "Fighter", "Monk",
241
+ "Paladin", "Ranger", "Rogue", "Sorcerer", "Warlock", "Wizard"
242
+ ],
243
+ "starting_race": [
244
+ "Human", "Elf", "Dwarf", "Halfling", "Dragonborn",
245
+ "Gnome", "Half-Elf", "Half-Orc", "Tiefling"
246
+ ],
247
+ }
248
+ },
249
+ {
250
+ event: "tutorial completed",
225
251
  weight: 2,
226
252
  properties: {
227
- mode: ["fast", "slow", "template"],
228
- },
253
+ "completion_time_mins": u.weighNumRange(3, 25, 0.8, 10),
254
+ "skipped": [false, false, false, false, false, false, true],
255
+ }
229
256
  },
230
257
  {
231
- event: "join party",
232
- weight: 8,
258
+ event: "quest accepted",
259
+ weight: 15,
233
260
  properties: {
234
- "party size": u.weighNumRange(1, 6),
235
- "party leader": [
236
- "Bard",
237
- "Cleric",
238
- "Fighter",
239
- "Rogue",
240
- "Wizard",
241
- "Paladin",
242
- "Ranger",
243
- "Sorcerer",
244
- "Warlock",
245
- ],
246
- },
261
+ "quest_id": questIds,
262
+ "quest_type": ["Main Story", "Side Quest", "Bounty", "Exploration", "Escort"],
263
+ "recommended_level": u.weighNumRange(1, 50),
264
+ }
247
265
  },
248
266
  {
249
- event: "start quest",
267
+ event: "quest objective completed",
250
268
  weight: 12,
251
269
  properties: {
252
- "quest type": [
253
- "Rescue",
254
- "Retrieve",
255
- "Explore",
256
- "Destroy",
257
- "Investigate",
258
- ],
259
- "quest difficulty": [
260
- "Easy",
261
- "Medium",
262
- "Hard",
263
- "Legendary",
264
- ],
265
- "quest location": [
266
- "Forest",
267
- "Dungeon",
268
- "Mountain",
269
- "City",
270
- "Desert",
271
- ],
272
- "party size": u.weighNumRange(1, 6),
273
- "used hint": ["no", "no", "yes"],
274
- "used boost": ["no", "no", "no", "no", "yes"],
275
- "level at start": u.weighNumRange(1, 20),
276
- },
270
+ "quest_id": questIds,
271
+ "objective_number": u.weighNumRange(1, 5),
272
+ }
277
273
  },
278
274
  {
279
- event: "complete quest",
280
- weight: 12,
275
+ event: "quest turned in",
276
+ weight: 10,
277
+ properties: {
278
+ "quest_id": questIds,
279
+ "reward_gold": u.weighNumRange(10, 500, 0.5, 100),
280
+ "reward_xp": u.weighNumRange(50, 2000, 0.5, 500),
281
+ "compass_user": [false],
282
+ "subscriber_advantage": ["Free"],
283
+ "level_scaled": [false],
284
+ }
285
+ },
286
+ {
287
+ event: "enter dungeon",
288
+ weight: 18,
281
289
  properties: {
282
- "completion time (mins)": u.weighNumRange(5, 120, 1, 30),
283
- "quest reward (gold)": u.weighNumRange(10, 500, 1, 100),
284
- "quest success": ["yes", "yes", "yes", "yes", "yes", "yes", "yes", "yes", "yes", "no"],
285
- "used hint": ["no", "no", "yes"],
286
- "used boost": ["no", "no", "no", "no", "yes"],
287
- "number of deaths": u.weighNumRange(0, 5, 1, 2),
288
- "level at start": u.weighNumRange(1, 20),
289
- "level at end": u.weighNumRange(1, 20),
290
- },
290
+ "dungeon_id": dungeonIds,
291
+ "difficulty": ["Easy", "Medium", "Hard", "Deadly"],
292
+ "party_size": u.weighNumRange(1, 5),
293
+ }
291
294
  },
292
295
  {
293
- "event": "gameplay summary",
294
- "weight": 14,
295
- "properties": {
296
- "# enemies defeated": u.weighNumRange(0, 100),
297
- "# respawns": u.weighNumRange(0, 10, 5),
298
- "# attacks": u.weighNumRange(0, 100, 6, 12),
299
- "# gold found": u.weighNumRange(0, 1000),
296
+ event: "exit dungeon",
297
+ weight: 14,
298
+ properties: {
299
+ "dungeon_id": dungeonIds,
300
+ "time_spent_mins": u.weighNumRange(5, 120, 0.6, 30),
301
+ "completion_status": ["completed", "abandoned", "died"],
302
+ "strategic_explorer": [false],
303
+ "legendary_weapon_equipped": [false],
304
+ "subscriber_advantage": ["Free"],
300
305
  }
301
306
  },
302
307
  {
303
- "event": "in-game purchase",
304
- "weight": 2,
305
- "properties": {
306
- "purchase type": [
307
- "Gold",
308
- "Gems",
309
- "Items: Weapons",
310
- "Items: Armor",
311
- "Items: Potions",
312
- "Items: Scrolls",
313
- "Boosts",
314
- "Currency",
315
- ],
316
- "purchase amount": u.weighNumRange(1, 50, 1, 20),
317
- is_whale: [false],
308
+ event: "find treasure",
309
+ weight: 16,
310
+ properties: {
311
+ "treasure_type": ["Gold", "Weapon", "Armor", "Potion", "Scroll", "Rare Artifact"],
312
+ "treasure_value": u.weighNumRange(5, 1000, 1.2, 50),
313
+ "legendary_drop": [false],
314
+ "strategic_explorer": [false],
315
+ "subscriber_advantage": ["Free"],
316
+ "elite_bonus": [false],
318
317
  }
319
318
  },
320
319
  {
321
- event: "fight boss",
320
+ event: "player death",
321
+ weight: 8,
322
+ properties: {
323
+ "cause_of_death": ["Monster", "Trap", "Fall Damage", "Poison", "Friendly Fire"],
324
+ "player_level": u.weighNumRange(1, 50),
325
+ "resurrection_used": [false, false, false, true],
326
+ "cursed_week": [false],
327
+ "near_death_survival": [false],
328
+ "subscriber_advantage": ["Free"],
329
+ }
330
+ },
331
+ {
332
+ event: "level up",
333
+ weight: 5,
334
+ properties: {
335
+ "new_level": u.weighNumRange(2, 50),
336
+ "stat_points_gained": u.weighNumRange(1, 5),
337
+ "new_abilities": ["Attack", "Spell", "Feat", "Skill"],
338
+ }
339
+ },
340
+ {
341
+ event: "item purchased",
342
+ weight: 11,
343
+ properties: {
344
+ "item_id": itemIds,
345
+ "item_type": ["Weapon", "Armor", "Potion", "Scroll", "Mount", "Cosmetic"],
346
+ "price_gold": u.weighNumRange(10, 500, 0.8, 100),
347
+ "vendor_type": ["Town", "Dungeon", "Special Event"],
348
+ }
349
+ },
350
+ {
351
+ event: "item sold",
352
+ weight: 7,
353
+ properties: {
354
+ "item_id": itemIds,
355
+ "item_type": ["Weapon", "Armor", "Potion", "Scroll", "Junk"],
356
+ "sell_price": u.weighNumRange(5, 250, 0.5, 50),
357
+ }
358
+ },
359
+ {
360
+ event: "real money purchase",
322
361
  weight: 3,
323
362
  properties: {
324
- "boss type": [
325
- "Dragon",
326
- "Demon",
327
- "Lich",
328
- "Vampire",
329
- "Beholder",
330
- ],
331
- "boss level": u.weighNumRange(10, 20),
332
- "boss difficulty": [
333
- "Hard",
334
- "Legendary",
335
- "Impossible",
363
+ "product": [
364
+ "Premium Currency (1000)",
365
+ "Premium Currency (5000)",
366
+ "Lucky Charm Pack",
367
+ "Legendary Weapon Chest",
368
+ "Cosmetic Bundle",
369
+ "Season Pass"
336
370
  ],
337
- "fight duration (mins)": u.weighNumRange(1, 60),
338
-
339
- },
371
+ "price_usd": [4.99, 9.99, 19.99, 49.99, 99.99],
372
+ "payment_method": ["Credit Card", "PayPal", "Apple Pay", "Google Pay"],
373
+ "lucky_charm_effect": [false],
374
+ "is_whale": [false],
375
+ }
340
376
  },
341
377
  {
342
- event: "level up",
378
+ event: "guild joined",
379
+ weight: 4,
380
+ properties: {
381
+ "guild_size": u.weighNumRange(5, 100),
382
+ "guild_level": u.weighNumRange(1, 20),
383
+ }
384
+ },
385
+ {
386
+ event: "guild left",
343
387
  weight: 1,
344
388
  properties: {
345
- "new abilities": [
346
- "Attack",
347
- "Spell",
348
- "Feat",
349
- "Skill",
389
+ "reason": ["Inactive", "Found Better Guild", "Conflict", "Disbanded"],
390
+ }
391
+ },
392
+ {
393
+ event: "inspect",
394
+ weight: 9,
395
+ properties: {
396
+ "inspect_target": ["NPC", "Monster", "Treasure Chest", "Door", "Statue", "Bookshelf"],
397
+ }
398
+ },
399
+ {
400
+ event: "search for clues",
401
+ weight: 8,
402
+ properties: {
403
+ "location_type": ["Dungeon Entrance", "Hidden Room", "Quest Location", "Town Square"],
404
+ "clue_found": [false, false, true, true, true],
405
+ }
406
+ },
407
+ {
408
+ event: "use item",
409
+ weight: 14,
410
+ properties: {
411
+ "item_id": itemIds,
412
+ "item_type": [
413
+ "Health Potion", "Mana Potion", "Buff Scroll",
414
+ "Ancient Compass", "Lucky Charm", "Resurrection Stone"
350
415
  ],
351
- },
416
+ "context": ["Combat", "Exploration", "Boss Fight", "Casual"],
417
+ }
418
+ },
419
+ {
420
+ event: "combat initiated",
421
+ weight: 20,
422
+ properties: {
423
+ "enemy_type": ["Goblin", "Skeleton", "Dragon", "Demon", "Undead", "Beast"],
424
+ "enemy_level": u.weighNumRange(1, 50),
425
+ "combat_duration_sec": u.weighNumRange(10, 300, 0.7, 60),
426
+ }
427
+ },
428
+ {
429
+ event: "combat completed",
430
+ weight: 18,
431
+ properties: {
432
+ "outcome": ["Victory", "Defeat", "Fled"],
433
+ "loot_gained": [false, false, false, true, true, true, true, true, true, true],
434
+ "legendary_weapon_equipped": [false],
435
+ "subscriber_advantage": ["Free"],
436
+ "near_death_survival": [false],
437
+ "guild_member_retained": [false],
438
+ }
439
+ },
440
+ {
441
+ event: "fight boss",
442
+ weight: 3,
443
+ properties: {
444
+ "boss_type": ["Dragon", "Demon", "Lich", "Vampire", "Beholder"],
445
+ "boss_level": u.weighNumRange(10, 50),
446
+ "boss_difficulty": ["Hard", "Legendary", "Impossible"],
447
+ "fight_duration_mins": u.weighNumRange(1, 60),
448
+ "victory": [false, true, true],
449
+ }
352
450
  },
353
451
  {
354
452
  event: "attack",
355
453
  weight: 5,
356
454
  properties: {
357
- generic_prop: ["foo", "bar", "baz", "qux"],
455
+ "attack_type": ["Melee", "Ranged", "Spell", "Special"],
456
+ "damage_dealt": u.weighNumRange(1, 200, 0.7, 30),
358
457
  }
359
458
  },
360
459
  {
361
460
  event: "defend",
362
461
  weight: 3,
363
462
  properties: {
364
- generic_prop: ["foo", "bar", "baz", "qux"],
463
+ "defense_type": ["Block", "Parry", "Dodge", "Shield"],
464
+ "damage_blocked": u.weighNumRange(0, 150, 0.7, 20),
465
+ }
466
+ },
467
+ {
468
+ event: "gameplay summary",
469
+ weight: 6,
470
+ properties: {
471
+ "enemies_defeated": u.weighNumRange(0, 100),
472
+ "respawns": u.weighNumRange(0, 10, 5),
473
+ "total_attacks": u.weighNumRange(0, 100, 6, 12),
474
+ "gold_found": u.weighNumRange(0, 1000),
365
475
  }
366
476
  },
367
477
  ],
368
- superProps: {
369
- Platform: [
370
- "Mobile",
371
- "Xbox",
372
- "Playstation",
373
- "Switch",
374
- "Web"
375
- ],
376
- "game mode": u.pickAWinner([
377
- "Single Player",
378
- "Multiplayer",
379
- ], 1),
380
- language: [
381
- "English",
382
- "Spanish",
383
- "French",
384
- "German",
385
- "Japanese",
386
- "Korean",
387
- "Chinese",
388
- ],
389
478
 
479
+ superProps: {
480
+ Platform: ["PC", "Mac", "PlayStation", "Xbox", "Switch"],
481
+ graphics_quality: ["Low", "Medium", "High", "Ultra"],
482
+ subscription_tier: ["Free", "Free", "Free", "Premium", "Elite"],
390
483
  },
484
+
391
485
  scdProps: {
392
- "subscription MRR" : {
393
- frequency: "week",
394
- values: u.weighNumRange(0, 250, 1, 200),
395
- timing: "fixed",
396
- max: 250,
397
- },
398
486
  player_rank: {
399
- values: ["bronze", "silver", "gold", "diamond", "legendary"],
487
+ values: ["recruit", "veteran", "elite", "legend"],
400
488
  frequency: "week",
401
489
  timing: "fuzzy",
402
- max: 250
403
- },
404
- guild_rank: {
405
- values: ["bronze", "silver", "gold", "legendary"],
406
- frequency: "month",
407
- timing: "fixed",
408
- max: 6,
409
- type: "guild_id"
490
+ max: 20
410
491
  }
411
492
  },
493
+
412
494
  userProps: {
413
- Platform: [
414
- "Mobile",
415
- "Xbox",
416
- "Playstation",
417
- "Switch",
418
- "Web"
495
+ "preferred_playstyle": [
496
+ "Solo Explorer", "Group Raider", "PvP Fighter",
497
+ "Quest Completionist", "Treasure Hunter"
419
498
  ],
420
- "game mode": u.pickAWinner([
421
- "Single Player",
422
- "Multiplayer",
423
- ], 1),
424
- language: [
425
- "English",
426
- "Spanish",
427
- "French",
428
- "German",
429
- "Japanese",
430
- "Korean",
431
- "Chinese",
499
+ "total_playtime_hours": u.weighNumRange(1, 500, 1.5, 50),
500
+ "achievement_points": u.weighNumRange(0, 5000, 0.8, 500),
501
+ "favorite_class": [
502
+ "Warrior", "Mage", "Rogue", "Cleric", "Ranger", "Paladin"
432
503
  ],
433
- experiment: [
434
- "fast leveling",
435
- "tension economy",
436
- "free trial",
437
- ],
438
- variant: ["A", "B", "C", "Control"],
504
+ Platform: ["PC", "Mac", "PlayStation", "Xbox", "Switch"],
505
+ graphics_quality: ["Low", "Medium", "High", "Ultra"],
506
+ subscription_tier: ["Free", "Free", "Free", "Premium", "Elite"],
439
507
 
508
+ // D&D character identity (from gaming dungeon)
440
509
  race: [
441
- "Human",
442
- "Elf",
443
- "Dwarf",
444
- "Halfling",
445
- "Dragonborn",
446
- "Gnome",
447
- "Half-Elf",
448
- "Half-Orc",
449
- "Tiefling",
510
+ "Human", "Elf", "Dwarf", "Halfling", "Dragonborn",
511
+ "Gnome", "Half-Elf", "Half-Orc", "Tiefling"
450
512
  ],
451
513
  class: [
452
- "Barbarian",
453
- "Bard",
454
- "Cleric",
455
- "Druid",
456
- "Fighter",
457
- "Monk",
458
- "Paladin",
459
- "Ranger",
460
- "Rogue",
461
- "Sorcerer",
462
- "Warlock",
463
- "Wizard",
514
+ "Barbarian", "Bard", "Cleric", "Druid", "Fighter", "Monk",
515
+ "Paladin", "Ranger", "Rogue", "Sorcerer", "Warlock", "Wizard"
464
516
  ],
465
517
  alignment: [
466
- "Lawful Good",
467
- "Neutral Good",
468
- "Chaotic Good",
469
- "Lawful Neutral",
470
- "True Neutral",
471
- "Chaotic Neutral",
472
- "Lawful Evil",
473
- "Neutral Evil",
474
- "Chaotic Evil",
518
+ "Lawful Good", "Neutral Good", "Chaotic Good",
519
+ "Lawful Neutral", "True Neutral", "Chaotic Neutral",
520
+ "Lawful Evil", "Neutral Evil", "Chaotic Evil"
475
521
  ],
476
- level: u.weighNumRange(1, 20),
477
522
  background: [
478
- "Acolyte",
479
- "Charlatan",
480
- "Criminal",
481
- "Entertainer",
482
- "Folk Hero",
483
- "Guild Artisan",
484
- "Hermit",
485
- "Noble",
486
- "Outlander",
487
- "Sage",
488
- "Sailor",
489
- "Soldier",
490
- "Urchin",
523
+ "Acolyte", "Charlatan", "Criminal", "Entertainer", "Folk Hero",
524
+ "Guild Artisan", "Hermit", "Noble", "Outlander", "Sage",
525
+ "Sailor", "Soldier", "Urchin"
491
526
  ],
492
- "subscription MRR": u.weighNumRange(0, 250, 1, 200),
527
+ level: u.weighNumRange(1, 20),
493
528
  archetype: ["neutral"],
529
+
530
+ // A/B/C experiment scaffolding
531
+ experiment: ["fast leveling", "tension economy", "free trial"],
532
+ variant: ["A", "B", "C", "Control"],
494
533
  },
495
- // HOOK: 3 patterns — gold scaling by level, whale purchases, alignment archetype
496
- hook: function (record, type, meta) {
497
534
 
498
- if (type === "event") {
499
- // Pattern 1: Higher-level players earn more gold and defeat more enemies
500
- if (record.event === "complete quest") {
501
- const level = record["level at end"] || 1;
502
- record["quest reward (gold)"] = Math.round((record["quest reward (gold)"] || 50) * (1 + level * 0.1));
503
- }
535
+ groupKeys: [
536
+ ["guild_id", 500, ["guild joined", "guild left", "quest turned in", "combat completed"]],
537
+ ],
504
538
 
505
- // Pattern 2: In-game purchases are bigger for "free trial" experiment users
506
- if (record.event === "in-game purchase") {
507
- // We don't have profile here, so use a hash-based approach
508
- const uid = record.user_id || record.distinct_id || "";
509
- if (uid.charCodeAt(0) % 3 === 0) {
510
- record["purchase amount"] = Math.round((record["purchase amount"] || 10) * 1.8);
511
- record.is_whale = true;
512
- }
513
- }
539
+ groupProps: {
540
+ guild_id: {
541
+ "name": () => `${chance.word()} ${chance.pickone(["Knights", "Dragons", "Warriors", "Seekers", "Legends"])}`,
542
+ "member_count": u.weighNumRange(5, 100),
543
+ "guild_level": u.weighNumRange(1, 20),
544
+ "total_wealth": u.weighNumRange(1000, 1000000, 0.5, 50000),
514
545
  }
546
+ },
547
+
548
+ lookupTables: [],
515
549
 
550
+ /**
551
+ * 🎯 ARCHITECTED ANALYTICS HOOKS — 11 patterns
552
+ *
553
+ * 1. CONVERSION: Ancient Compass users have 3x quest completion + 1.5x rewards
554
+ * 2. TIME-BASED: "Cursed Week" (days 40-47) has 5x death rates
555
+ * 3. RETENTION: Early guild joiners (first 3 days) have 80% D30 retention vs 20%
556
+ * 4. CHURN: Players with 3+ deaths in first week have 70% churn rate
557
+ * 5. PURCHASE VALUE: Lucky Charm buyers spend 5x more (LTV pattern)
558
+ * 6. BEHAVIORS TOGETHER: inspect + search before dungeon = 85% completion vs 45%
559
+ * 7. TIMED RELEASE: Legendary weapon released day 45, early adopters dominate
560
+ * 8. SUBSCRIPTION TIER: Premium/Elite users have higher engagement and success
561
+ * 9. PROGRESSION SCALING: Quest gold scales with player level (1 + level * 0.1)
562
+ * 10. WHALE PURCHASES: ~33% of users via deterministic hash spend 1.8x more
563
+ * 11. ALIGNMENT ARCHETYPE: Good=hero, Evil=villain, other=neutral (user hook)
564
+ */
565
+ hook: function (record, type, meta) {
566
+ const NOW = dayjs();
567
+ const DATASET_START = NOW.subtract(num_days, 'days');
568
+ const CURSED_WEEK_START = DATASET_START.add(40, 'days');
569
+ const CURSED_WEEK_END = DATASET_START.add(47, 'days');
570
+ const LEGENDARY_WEAPON_RELEASE = DATASET_START.add(45, 'days');
571
+
572
+ // Hook #11: ALIGNMENT ARCHETYPE — derive archetype on user profile
516
573
  if (type === "user") {
517
- // Pattern 3: Chaotic Evil players get a "villain" tag; Lawful Good get "hero"
518
574
  if (record.alignment === "Chaotic Evil" || record.alignment === "Neutral Evil") {
519
575
  record.archetype = "villain";
520
576
  } else if (record.alignment === "Lawful Good" || record.alignment === "Neutral Good") {
@@ -524,28 +580,355 @@ const config = {
524
580
  }
525
581
  }
526
582
 
527
- if (type === "funnel-post") {
528
-
529
- }
530
-
531
- if (type === "funnel-pre") {
532
-
533
- }
583
+ // Hook #2 event-level part removed — cursed week now handled in everything hook
534
584
 
535
- if (type === "scd") {
585
+ // Hook #7: TIMED RELEASE — Legendary Weapon
586
+ if (type === "event") {
587
+ const EVENT_TIME = dayjs(record.time);
536
588
 
589
+ if (record.event === "find treasure") {
590
+ if (EVENT_TIME.isAfter(LEGENDARY_WEAPON_RELEASE) && chance.bool({ likelihood: 2 })) {
591
+ record.treasure_type = "Shadowmourne Legendary";
592
+ record.treasure_value = 50000;
593
+ record.legendary_drop = true;
594
+ } else {
595
+ record.legendary_drop = false;
596
+ }
597
+ }
537
598
  }
538
599
 
600
+ // Hooks #1, #3, #4, #5, #6, #8, #9, #10: per-user behavioral patterns
539
601
  if (type === "everything") {
540
- // Stamp superProps from profile for consistency
602
+ const userEvents = record;
541
603
  const profile = meta.profile;
542
- record.forEach(e => {
604
+
605
+ // Stamp superProps from profile for consistency
606
+ userEvents.forEach(e => {
543
607
  e.Platform = profile.Platform;
544
- e["game mode"] = profile["game mode"];
545
- e.language = profile.language;
608
+ e.graphics_quality = profile.graphics_quality;
609
+ e.subscription_tier = profile.subscription_tier;
546
610
  });
547
611
 
548
- return record;
612
+ const firstEventTime = userEvents.length > 0 ? dayjs(userEvents[0].time) : null;
613
+ const userLevel = profile.level || 1;
614
+
615
+ // Track user behaviors
616
+ let usedAncientCompass = false;
617
+ let boughtLuckyCharm = false;
618
+ let joinedGuildEarly = false;
619
+ let earlyDeaths = 0;
620
+ let hasLegendaryWeapon = false;
621
+ let inspectedBeforeDungeon = false;
622
+ let searchedBeforeDungeon = false;
623
+ let subscriptionTier = "Free";
624
+
625
+ // Hook #10: Whale segmentation — deterministic via user_id hash (~33%)
626
+ const userId = userEvents.length > 0 ? (userEvents[0].user_id || userEvents[0].distinct_id || "") : "";
627
+ const isWhale = userId.length > 0 && userId.charCodeAt(0) % 3 === 0;
628
+
629
+ // First pass: identify user patterns
630
+ userEvents.forEach((event) => {
631
+ const eventTime = dayjs(event.time);
632
+ const daysSinceStart = firstEventTime ? eventTime.diff(firstEventTime, 'days', true) : 0;
633
+
634
+ if (event.subscription_tier) {
635
+ subscriptionTier = event.subscription_tier;
636
+ }
637
+
638
+ if (event.event === "use item" && event.item_type === "Ancient Compass") {
639
+ usedAncientCompass = true;
640
+ }
641
+
642
+ if (event.event === "real money purchase" && event.product === "Lucky Charm Pack") {
643
+ boughtLuckyCharm = true;
644
+ }
645
+
646
+ if (event.event === "guild joined" && daysSinceStart < 3) {
647
+ joinedGuildEarly = true;
648
+ }
649
+
650
+ if (event.event === "player death" && daysSinceStart < 7) {
651
+ earlyDeaths++;
652
+ }
653
+
654
+ if (event.event === "find treasure" && event.legendary_drop) {
655
+ hasLegendaryWeapon = true;
656
+ }
657
+
658
+ if (event.event === "inspect") {
659
+ inspectedBeforeDungeon = true;
660
+ }
661
+ if (event.event === "search for clues") {
662
+ searchedBeforeDungeon = true;
663
+ }
664
+ });
665
+
666
+ // Second pass: modify events based on patterns
667
+ userEvents.forEach((event, idx) => {
668
+ const eventTime = dayjs(event.time);
669
+
670
+ // Set schema defaults for conditional properties
671
+ if (event.event === "quest turned in") {
672
+ event.compass_user = false;
673
+ event.subscriber_advantage = "Free";
674
+ event.level_scaled = false;
675
+ }
676
+ if (event.event === "exit dungeon") {
677
+ event.strategic_explorer = false;
678
+ event.legendary_weapon_equipped = false;
679
+ event.subscriber_advantage = "Free";
680
+ }
681
+ if (event.event === "find treasure") {
682
+ event.strategic_explorer = false;
683
+ event.subscriber_advantage = "Free";
684
+ }
685
+ if (event.event === "combat completed") {
686
+ event.legendary_weapon_equipped = false;
687
+ event.subscriber_advantage = "Free";
688
+ event.near_death_survival = false;
689
+ }
690
+ if (event.event === "player death") {
691
+ event.near_death_survival = false;
692
+ event.subscriber_advantage = "Free";
693
+ }
694
+ if (event.event === "real money purchase") {
695
+ event.is_whale = false;
696
+ }
697
+
698
+ // Hook #9: PROGRESSION SCALING — Quest gold scales with level
699
+ if (event.event === "quest turned in") {
700
+ const baseGold = event.reward_gold || 100;
701
+ event.reward_gold = Math.floor(baseGold * (1 + userLevel * 0.1));
702
+ event.level_scaled = true;
703
+ }
704
+
705
+ // Hook #1: CONVERSION — Ancient Compass users complete more quests
706
+ if (usedAncientCompass && event.event === "quest turned in") {
707
+ event.reward_gold = Math.floor((event.reward_gold || 100) * 1.5);
708
+ event.reward_xp = Math.floor((event.reward_xp || 500) * 1.5);
709
+ event.compass_user = true;
710
+
711
+ if (chance.bool({ likelihood: 40 })) {
712
+ const extraQuest = {
713
+ ...event,
714
+ time: eventTime.add(chance.integer({ min: 10, max: 120 }), 'minutes').toISOString(),
715
+ quest_id: chance.pickone(questIds),
716
+ reward_gold: chance.integer({ min: 100, max: 500 }),
717
+ reward_xp: chance.integer({ min: 500, max: 2000 }),
718
+ compass_user: true,
719
+ };
720
+ userEvents.splice(idx + 1, 0, extraQuest);
721
+ }
722
+ }
723
+
724
+ // Hook #5: PURCHASE VALUE — Lucky charm buyers spend 5x more
725
+ if (boughtLuckyCharm) {
726
+ if (event.event === "real money purchase") {
727
+ if (event.price_usd) {
728
+ const currentPrice = event.price_usd;
729
+ if (currentPrice < 49.99) {
730
+ event.price_usd = currentPrice * 2;
731
+ }
732
+ event.lucky_charm_effect = true;
733
+ }
734
+ }
735
+
736
+ if (event.event === "item purchased" && chance.bool({ likelihood: 35 })) {
737
+ const purchaseTemplate = userEvents.find(e => e.event === "real money purchase");
738
+ if (purchaseTemplate) {
739
+ const extraPurchase = {
740
+ ...purchaseTemplate,
741
+ time: eventTime.add(chance.integer({ min: 1, max: 3 }), 'days').toISOString(),
742
+ user_id: event.user_id,
743
+ product: chance.pickone([
744
+ "Premium Currency (5000)",
745
+ "Legendary Weapon Chest",
746
+ "Season Pass"
747
+ ]),
748
+ price_usd: chance.pickone([19.99, 49.99, 99.99]),
749
+ payment_method: chance.pickone(["Credit Card", "PayPal"]),
750
+ lucky_charm_effect: true,
751
+ };
752
+ userEvents.splice(idx + 1, 0, extraPurchase);
753
+ }
754
+ }
755
+ }
756
+
757
+ // Hook #10: WHALE PURCHASES — boost real money purchase amounts
758
+ if (isWhale && event.event === "real money purchase") {
759
+ if (event.price_usd) {
760
+ event.price_usd = Math.round(event.price_usd * 1.8 * 100) / 100;
761
+ }
762
+ event.is_whale = true;
763
+ }
764
+
765
+ // Hook #6: BEHAVIORS TOGETHER — Inspect + Search before dungeon
766
+ if (inspectedBeforeDungeon && searchedBeforeDungeon) {
767
+ if (event.event === "exit dungeon") {
768
+ if (event.completion_status !== "completed") {
769
+ if (chance.bool({ likelihood: 85 })) {
770
+ event.completion_status = "completed";
771
+ event.strategic_explorer = true;
772
+ }
773
+ }
774
+ }
775
+
776
+ if (event.event === "find treasure") {
777
+ event.treasure_value = Math.floor((event.treasure_value || 50) * 2);
778
+ event.strategic_explorer = true;
779
+ }
780
+ }
781
+
782
+ // Hook #7: TIMED RELEASE — Legendary weapon owners dominate
783
+ if (hasLegendaryWeapon) {
784
+ if (event.event === "combat completed") {
785
+ if (event.outcome !== "Victory") {
786
+ if (chance.bool({ likelihood: 90 })) {
787
+ event.outcome = "Victory";
788
+ event.legendary_weapon_equipped = true;
789
+ }
790
+ }
791
+ }
792
+
793
+ if (event.event === "exit dungeon") {
794
+ event.completion_status = "completed";
795
+ event.time_spent_mins = Math.floor((event.time_spent_mins || 60) * 0.6);
796
+ event.legendary_weapon_equipped = true;
797
+ }
798
+ }
799
+
800
+ // Hook #8: SUBSCRIPTION TIER — Premium/Elite advantages
801
+ if (subscriptionTier === "Premium" || subscriptionTier === "Elite") {
802
+ const isElite = subscriptionTier === "Elite";
803
+
804
+ if (event.event === "combat completed") {
805
+ if (event.outcome !== "Victory") {
806
+ const winBoost = isElite ? 70 : 50;
807
+ if (Math.random() * 100 < winBoost) {
808
+ event.outcome = "Victory";
809
+ event.loot_gained = true;
810
+ event.subscriber_advantage = subscriptionTier;
811
+ }
812
+ }
813
+ }
814
+
815
+ if (event.event === "quest turned in") {
816
+ const rewardMultiplier = isElite ? 1.8 : 1.4;
817
+ event.reward_gold = Math.floor((event.reward_gold || 100) * rewardMultiplier);
818
+ event.reward_xp = Math.floor((event.reward_xp || 500) * rewardMultiplier);
819
+ event.subscriber_advantage = subscriptionTier;
820
+ }
821
+
822
+ if (event.event === "exit dungeon") {
823
+ if (event.completion_status !== "completed") {
824
+ const completionBoost = isElite ? 65 : 45;
825
+ if (Math.random() * 100 < completionBoost) {
826
+ event.completion_status = "completed";
827
+ event.subscriber_advantage = subscriptionTier;
828
+ }
829
+ }
830
+ if (event.completion_status === "completed") {
831
+ const speedBoost = isElite ? 0.7 : 0.85;
832
+ event.time_spent_mins = Math.floor((event.time_spent_mins || 60) * speedBoost);
833
+ }
834
+ }
835
+
836
+ if (event.event === "find treasure") {
837
+ const treasureBoost = isElite ? 2.0 : 1.5;
838
+ event.treasure_value = Math.floor((event.treasure_value || 50) * treasureBoost);
839
+ event.subscriber_advantage = subscriptionTier;
840
+ }
841
+
842
+ if (event.event === "player death" && !event.cursed_week) {
843
+ const survivalChance = isElite ? 50 : 30;
844
+ if (Math.random() * 100 < survivalChance) {
845
+ event.event = "combat completed";
846
+ event.outcome = "Victory";
847
+ event.loot_gained = true;
848
+ event.subscriber_advantage = subscriptionTier;
849
+ event.near_death_survival = true;
850
+ }
851
+ }
852
+
853
+ if (isElite && Math.random() * 100 < 15) {
854
+ if (event.event === "quest turned in" || event.event === "exit dungeon") {
855
+ const treasureTemplate = userEvents.find(e => e.event === "find treasure");
856
+ if (treasureTemplate) {
857
+ const treasureTypes = ["Rare Artifact", "Gold", "Weapon", "Armor"];
858
+ const bonusEvent = {
859
+ ...treasureTemplate,
860
+ time: eventTime.add(Math.floor(Math.random() * 26) + 5, 'minutes').toISOString(),
861
+ user_id: event.user_id,
862
+ treasure_type: treasureTypes[Math.floor(Math.random() * treasureTypes.length)],
863
+ treasure_value: Math.floor(Math.random() * 601) + 200,
864
+ subscriber_advantage: "Elite",
865
+ elite_bonus: true,
866
+ };
867
+ userEvents.splice(idx + 1, 0, bonusEvent);
868
+ }
869
+ }
870
+ }
871
+ }
872
+ });
873
+
874
+ // Hook #2: CURSED WEEK — inject death events for days 40-47 of each user's timeline
875
+ if (firstEventTime) {
876
+ const deathTemplate = userEvents.find(e => e.event === "player death");
877
+ if (deathTemplate) {
878
+ const cursedStart = firstEventTime.add(40, 'days');
879
+ const cursedEnd = firstEventTime.add(47, 'days');
880
+ const cursedEvents = userEvents.filter(e => {
881
+ const t = dayjs(e.time);
882
+ return t.isAfter(cursedStart) && t.isBefore(cursedEnd);
883
+ });
884
+ const deathsToInject = Math.floor(cursedEvents.length * 0.6);
885
+ for (let d = 0; d < deathsToInject; d++) {
886
+ const sourceEvent = cursedEvents[d % cursedEvents.length];
887
+ const injected = {
888
+ ...deathTemplate,
889
+ time: dayjs(sourceEvent.time).add(chance.integer({ min: 1, max: 30 }), 'minutes').toISOString(),
890
+ user_id: sourceEvent.user_id,
891
+ event: "player death",
892
+ cause_of_death: "Curse",
893
+ player_level: chance.integer({ min: 1, max: 50 }),
894
+ resurrection_used: chance.bool({ likelihood: 80 }),
895
+ cursed_week: true,
896
+ near_death_survival: false,
897
+ subscriber_advantage: "Free",
898
+ };
899
+ userEvents.push(injected);
900
+ }
901
+ }
902
+ }
903
+
904
+ // Hook #3 RETENTION + Hook #4 CHURN
905
+ const shouldChurn = (!joinedGuildEarly && earlyDeaths >= 3) || (earlyDeaths >= 5);
906
+
907
+ if (shouldChurn) {
908
+ const firstWeekEnd = firstEventTime ? firstEventTime.add(7, 'days') : null;
909
+ for (let i = userEvents.length - 1; i >= 0; i--) {
910
+ const evt = userEvents[i];
911
+ if (firstWeekEnd && dayjs(evt.time).isAfter(firstWeekEnd)) {
912
+ if (chance.bool({ likelihood: 70 })) {
913
+ userEvents.splice(i, 1);
914
+ }
915
+ }
916
+ }
917
+ } else if (joinedGuildEarly) {
918
+ const lastEvent = userEvents[userEvents.length - 1];
919
+ const combatTemplate = userEvents.find(e => e.event === "combat completed");
920
+ if (lastEvent && combatTemplate && chance.bool({ likelihood: 60 })) {
921
+ const retentionEvent = {
922
+ ...combatTemplate,
923
+ time: dayjs(lastEvent.time).add(chance.integer({ min: 1, max: 5 }), 'days').toISOString(),
924
+ user_id: lastEvent.user_id,
925
+ outcome: "Victory",
926
+ loot_gained: true,
927
+ guild_member_retained: true,
928
+ };
929
+ userEvents.push(retentionEvent);
930
+ }
931
+ }
549
932
  }
550
933
 
551
934
  return record;