@sbugallo/pokecode 0.2.0 → 0.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 (141) hide show
  1. package/README.md +17 -11
  2. package/dist/adapters/opencode/tui/choices/cards.d.ts +4 -0
  3. package/dist/adapters/opencode/tui/choices/cards.d.ts.map +1 -1
  4. package/dist/adapters/opencode/tui/choices/cards.jsx +6 -6
  5. package/dist/adapters/opencode/tui/choices/cards.jsx.map +1 -1
  6. package/dist/adapters/opencode/tui/choices/encounter.d.ts +2 -0
  7. package/dist/adapters/opencode/tui/choices/encounter.d.ts.map +1 -1
  8. package/dist/adapters/opencode/tui/choices/encounter.jsx +1 -1
  9. package/dist/adapters/opencode/tui/choices/encounter.jsx.map +1 -1
  10. package/dist/adapters/opencode/tui/components/image-protocol.d.ts +31 -0
  11. package/dist/adapters/opencode/tui/components/image-protocol.d.ts.map +1 -0
  12. package/dist/adapters/opencode/tui/components/image-protocol.js +83 -0
  13. package/dist/adapters/opencode/tui/components/image-protocol.js.map +1 -0
  14. package/dist/adapters/opencode/tui/components/sprite.d.ts +2 -0
  15. package/dist/adapters/opencode/tui/components/sprite.d.ts.map +1 -1
  16. package/dist/adapters/opencode/tui/components/sprite.jsx +1 -1
  17. package/dist/adapters/opencode/tui/components/sprite.jsx.map +1 -1
  18. package/dist/adapters/opencode/tui/pc/actions.d.ts +2 -0
  19. package/dist/adapters/opencode/tui/pc/actions.d.ts.map +1 -1
  20. package/dist/adapters/opencode/tui/pc/actions.jsx +1 -1
  21. package/dist/adapters/opencode/tui/pc/actions.jsx.map +1 -1
  22. package/dist/adapters/opencode/tui/pc/details.d.ts +2 -0
  23. package/dist/adapters/opencode/tui/pc/details.d.ts.map +1 -1
  24. package/dist/adapters/opencode/tui/pc/details.jsx +1 -1
  25. package/dist/adapters/opencode/tui/pc/details.jsx.map +1 -1
  26. package/dist/adapters/opencode/tui/pc/dialog.d.ts +2 -0
  27. package/dist/adapters/opencode/tui/pc/dialog.d.ts.map +1 -1
  28. package/dist/adapters/opencode/tui/pc/dialog.jsx +1 -1
  29. package/dist/adapters/opencode/tui/pc/dialog.jsx.map +1 -1
  30. package/dist/adapters/opencode/tui/plugin.d.ts.map +1 -1
  31. package/dist/adapters/opencode/tui/plugin.jsx +8 -0
  32. package/dist/adapters/opencode/tui/plugin.jsx.map +1 -1
  33. package/dist/adapters/opencode/tui/sidebar/register.d.ts +2 -0
  34. package/dist/adapters/opencode/tui/sidebar/register.d.ts.map +1 -1
  35. package/dist/adapters/opencode/tui/sidebar/register.jsx +1 -1
  36. package/dist/adapters/opencode/tui/sidebar/register.jsx.map +1 -1
  37. package/dist/adapters/opencode/tui/sidebar/view.d.ts +4 -0
  38. package/dist/adapters/opencode/tui/sidebar/view.d.ts.map +1 -1
  39. package/dist/adapters/opencode/tui/sidebar/view.jsx +9 -9
  40. package/dist/adapters/opencode/tui/sidebar/view.jsx.map +1 -1
  41. package/dist/adapters/opencode/tui/state/cleanup.d.ts +1 -0
  42. package/dist/adapters/opencode/tui/state/cleanup.d.ts.map +1 -1
  43. package/dist/adapters/opencode/tui/state/cleanup.js +1 -0
  44. package/dist/adapters/opencode/tui/state/cleanup.js.map +1 -1
  45. package/dist/adapters/opencode/tui/travel/actions.d.ts +2 -0
  46. package/dist/adapters/opencode/tui/travel/actions.d.ts.map +1 -1
  47. package/dist/adapters/opencode/tui/travel/actions.jsx +1 -1
  48. package/dist/adapters/opencode/tui/travel/actions.jsx.map +1 -1
  49. package/dist/adapters/opencode/tui/travel/dialog.d.ts +2 -0
  50. package/dist/adapters/opencode/tui/travel/dialog.d.ts.map +1 -1
  51. package/dist/adapters/opencode/tui/travel/dialog.jsx +1 -1
  52. package/dist/adapters/opencode/tui/travel/dialog.jsx.map +1 -1
  53. package/dist/adapters/sqlite/game-repository.d.ts +2 -1
  54. package/dist/adapters/sqlite/game-repository.d.ts.map +1 -1
  55. package/dist/adapters/sqlite/game-repository.js +9 -1
  56. package/dist/adapters/sqlite/game-repository.js.map +1 -1
  57. package/dist/adapters/sqlite/queries/game-state.d.ts +2 -1
  58. package/dist/adapters/sqlite/queries/game-state.d.ts.map +1 -1
  59. package/dist/adapters/sqlite/queries/game-state.js +9 -3
  60. package/dist/adapters/sqlite/queries/game-state.js.map +1 -1
  61. package/dist/adapters/sqlite/transaction-stores/pokemon.js +7 -7
  62. package/dist/adapters/sqlite/transaction-stores/pokemon.js.map +1 -1
  63. package/dist/application/contracts/game.d.ts +3 -2
  64. package/dist/application/contracts/game.d.ts.map +1 -1
  65. package/dist/application/contracts/game.js +3 -2
  66. package/dist/application/contracts/game.js.map +1 -1
  67. package/dist/application/game.d.ts.map +1 -1
  68. package/dist/application/game.js +5 -1
  69. package/dist/application/game.js.map +1 -1
  70. package/dist/application/ports/game-transaction.d.ts +3 -2
  71. package/dist/application/ports/game-transaction.d.ts.map +1 -1
  72. package/dist/application/ports/game.d.ts +2 -1
  73. package/dist/application/ports/game.d.ts.map +1 -1
  74. package/dist/application/use-cases/choices.d.ts.map +1 -1
  75. package/dist/application/use-cases/choices.js +2 -0
  76. package/dist/application/use-cases/choices.js.map +1 -1
  77. package/dist/application/use-cases/choose-regional-starter.js +1 -1
  78. package/dist/application/use-cases/choose-regional-starter.js.map +1 -1
  79. package/dist/application/use-cases/encounters.js +1 -1
  80. package/dist/application/use-cases/encounters.js.map +1 -1
  81. package/dist/application/use-cases/record-usage.d.ts.map +1 -1
  82. package/dist/application/use-cases/record-usage.js +17 -4
  83. package/dist/application/use-cases/record-usage.js.map +1 -1
  84. package/dist/application/use-cases/resolve-progression.js +2 -0
  85. package/dist/application/use-cases/resolve-progression.js.map +1 -1
  86. package/dist/domain/content/catalog.d.ts +4 -0
  87. package/dist/domain/content/catalog.d.ts.map +1 -1
  88. package/dist/domain/content/catalog.js +17 -0
  89. package/dist/domain/content/catalog.js.map +1 -1
  90. package/dist/domain/content/catalogs/alola-locations-catalog.d.ts +1 -0
  91. package/dist/domain/content/catalogs/alola-locations-catalog.d.ts.map +1 -1
  92. package/dist/domain/content/catalogs/alola-locations-catalog.js +1 -0
  93. package/dist/domain/content/catalogs/alola-locations-catalog.js.map +1 -1
  94. package/dist/domain/content/catalogs/galar-locations-catalog.d.ts +1 -0
  95. package/dist/domain/content/catalogs/galar-locations-catalog.d.ts.map +1 -1
  96. package/dist/domain/content/catalogs/galar-locations-catalog.js +1 -0
  97. package/dist/domain/content/catalogs/galar-locations-catalog.js.map +1 -1
  98. package/dist/domain/content/catalogs/hoenn-locations-catalog.d.ts +1 -0
  99. package/dist/domain/content/catalogs/hoenn-locations-catalog.d.ts.map +1 -1
  100. package/dist/domain/content/catalogs/hoenn-locations-catalog.js +1 -0
  101. package/dist/domain/content/catalogs/hoenn-locations-catalog.js.map +1 -1
  102. package/dist/domain/content/catalogs/johto-locations-catalog.d.ts +1 -0
  103. package/dist/domain/content/catalogs/johto-locations-catalog.d.ts.map +1 -1
  104. package/dist/domain/content/catalogs/johto-locations-catalog.js +1 -0
  105. package/dist/domain/content/catalogs/johto-locations-catalog.js.map +1 -1
  106. package/dist/domain/content/catalogs/kalos-locations-catalog.d.ts +1 -0
  107. package/dist/domain/content/catalogs/kalos-locations-catalog.d.ts.map +1 -1
  108. package/dist/domain/content/catalogs/kalos-locations-catalog.js +1 -0
  109. package/dist/domain/content/catalogs/kalos-locations-catalog.js.map +1 -1
  110. package/dist/domain/content/catalogs/kanto-locations-catalog.d.ts +1 -0
  111. package/dist/domain/content/catalogs/kanto-locations-catalog.d.ts.map +1 -1
  112. package/dist/domain/content/catalogs/kanto-locations-catalog.js +1 -0
  113. package/dist/domain/content/catalogs/kanto-locations-catalog.js.map +1 -1
  114. package/dist/domain/content/catalogs/paldea-locations-catalog.d.ts +1 -0
  115. package/dist/domain/content/catalogs/paldea-locations-catalog.d.ts.map +1 -1
  116. package/dist/domain/content/catalogs/paldea-locations-catalog.js +1 -0
  117. package/dist/domain/content/catalogs/paldea-locations-catalog.js.map +1 -1
  118. package/dist/domain/content/catalogs/sinnoh-locations-catalog.d.ts +1 -0
  119. package/dist/domain/content/catalogs/sinnoh-locations-catalog.d.ts.map +1 -1
  120. package/dist/domain/content/catalogs/sinnoh-locations-catalog.js +1 -0
  121. package/dist/domain/content/catalogs/sinnoh-locations-catalog.js.map +1 -1
  122. package/dist/domain/content/catalogs/unova-locations-catalog.d.ts +1 -0
  123. package/dist/domain/content/catalogs/unova-locations-catalog.d.ts.map +1 -1
  124. package/dist/domain/content/catalogs/unova-locations-catalog.js +1 -0
  125. package/dist/domain/content/catalogs/unova-locations-catalog.js.map +1 -1
  126. package/dist/domain/content/schema.d.ts +1 -0
  127. package/dist/domain/content/schema.d.ts.map +1 -1
  128. package/dist/domain/content/schema.js +2 -0
  129. package/dist/domain/content/schema.js.map +1 -1
  130. package/dist/domain/exploration/exploration.d.ts +20 -0
  131. package/dist/domain/exploration/exploration.d.ts.map +1 -1
  132. package/dist/domain/exploration/exploration.js +17 -0
  133. package/dist/domain/exploration/exploration.js.map +1 -1
  134. package/dist/domain/usage/usage.d.ts +3 -3
  135. package/dist/domain/usage/usage.d.ts.map +1 -1
  136. package/dist/domain/usage/usage.js +4 -2
  137. package/dist/domain/usage/usage.js.map +1 -1
  138. package/dist/index.js +76 -17
  139. package/dist/rpc.js +8 -2
  140. package/dist/tui.js +195 -36
  141. package/package.json +1 -1
@@ -21,6 +21,23 @@ export const explorationStatusSchema = z.object({
21
21
  locationUnlockThreshold: z.number().int().positive(),
22
22
  regionComplete: z.boolean(),
23
23
  });
24
+ /**
25
+ * Token cost to advance from the location at `index` to the next one.
26
+ *
27
+ * Follows a region-length-normalized power curve, T(I) = base·(I+1)^exponent·
28
+ * (championIndex+1)^regionExponent, calibrated against main-series gymLeader and
29
+ * champion ace levels so party level tracks story progress. Beyond the champion
30
+ * (postgame/DLC locations) the cost is capped at the champion-approach cost:
31
+ * the curve was fitted on story data only, and extrapolating it would price
32
+ * Galar's DLC tail at tens of millions of tokens.
33
+ */
34
+ export function locationUnlockThreshold(input) {
35
+ const capped = Math.min(Math.max(input.index, 0), input.championIndex);
36
+ const cumulative = (i) => input.curve.baseTokens *
37
+ (i + 1) ** input.curve.exponent *
38
+ (input.championIndex + 1) ** input.curve.regionExponent;
39
+ return Math.round(cumulative(capped + 1) - cumulative(capped));
40
+ }
24
41
  export function calculateUnlockProgress(input) {
25
42
  if (!input.currentLocationIsLatestUnlocked)
26
43
  return { kind: "not-latest" };
@@ -1 +1 @@
1
- {"version":3,"file":"exploration.js","sourceRoot":"","sources":["../../../src/domain/exploration/exploration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;IACrB,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;CAC3B,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,OAAO,EAAE,CAAC;SACP,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;QACpB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;QACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;KACzC,CAAC,CACH;SACA,OAAO,CAAC,EAAE,CAAC;IACd,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtD,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpD,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;CAC5B,CAAC,CAAA;AAQF,MAAM,UAAU,uBAAuB,CAAC,KAMvC;IACC,IAAI,CAAC,KAAK,CAAC,+BAA+B;QAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAA;IACzE,IAAI,CAAC,KAAK,CAAC,eAAe;QAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,UAAU,EAAE,KAAK,CAAC,aAAa,EAAE,CAAA;IAC/F,MAAM,UAAU,GAAG,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,YAAY,CAAA;IAC3D,OAAO,UAAU,GAAG,KAAK,CAAC,SAAS;QACjC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE;QACtC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;AACvC,CAAC;AAGD,MAAM,UAAU,yBAAyB,CAAC,KAGzC;IACC,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO,kBAAkB,CAAA;IACpD,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAA;AACvD,CAAC;AAOD,MAAM,UAAU,uBAAuB,CAAC,KAIvC;IACC,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,OAAO,gBAAgB,CAAA;IAChD,IAAI,CAAC,KAAK,CAAC,qBAAqB;QAAE,OAAO,mBAAmB,CAAA;IAC5D,IAAI,KAAK,CAAC,oBAAoB;QAAE,OAAO,iBAAiB,CAAA;IACxD,OAAO,SAAS,CAAA;AAClB,CAAC"}
1
+ {"version":3,"file":"exploration.js","sourceRoot":"","sources":["../../../src/domain/exploration/exploration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;IACrB,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;CAC3B,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,OAAO,EAAE,CAAC;SACP,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;QACpB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;QACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;KACzC,CAAC,CACH;SACA,OAAO,CAAC,EAAE,CAAC;IACd,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtD,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpD,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE;CAC5B,CAAC,CAAA;AAcF;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAIvC;IACC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;IACtE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,EAAE,CAC/B,KAAK,CAAC,KAAK,CAAC,UAAU;QACtB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ;QAC/B,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,cAAc,CAAA;IACzD,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;AAChE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAMvC;IACC,IAAI,CAAC,KAAK,CAAC,+BAA+B;QAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAA;IACzE,IAAI,CAAC,KAAK,CAAC,eAAe;QAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,UAAU,EAAE,KAAK,CAAC,aAAa,EAAE,CAAA;IAC/F,MAAM,UAAU,GAAG,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,YAAY,CAAA;IAC3D,OAAO,UAAU,GAAG,KAAK,CAAC,SAAS;QACjC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE;QACtC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;AACvC,CAAC;AAGD,MAAM,UAAU,yBAAyB,CAAC,KAGzC;IACC,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO,kBAAkB,CAAA;IACpD,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAA;AACvD,CAAC;AAOD,MAAM,UAAU,uBAAuB,CAAC,KAIvC;IACC,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,OAAO,gBAAgB,CAAA;IAChD,IAAI,CAAC,KAAK,CAAC,qBAAqB;QAAE,OAAO,mBAAmB,CAAA;IAC5D,IAAI,KAAK,CAAC,oBAAoB;QAAE,OAAO,iBAAiB,CAAA;IACxD,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -6,9 +6,9 @@ export type TokenUsage = {
6
6
  readonly cacheWriteTokens: number;
7
7
  };
8
8
  export declare function totalTokens(input: TokenUsage): number;
9
- export declare function experienceFromTokens(tokenCount: number, config: {
10
- readonly xpTokensPerPoint: number;
11
- }): number;
9
+ /** Fixed rate the unlock curve was calibrated against: 1000 tokens = 1 XP. */
10
+ export declare const tokensPerExperiencePoint = 1000;
11
+ export declare function experienceFromTokens(tokenCount: number): number;
12
12
  export declare function usageReceiptKey(input: {
13
13
  readonly sessionId: string;
14
14
  readonly messageId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/domain/usage/usage.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAQrD;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC5C,MAAM,CAER;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,GAAG,MAAM,CAET;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB,GAAG,WAAW,GAAG,UAAU,GAAG,kBAAkB,GAAG,SAAS,CAK5D"}
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/domain/usage/usage.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAQrD;AAED,8EAA8E;AAC9E,eAAO,MAAM,wBAAwB,OAAQ,CAAA;AAE7C,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,GAAG,MAAM,CAET;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB,GAAG,WAAW,GAAG,UAAU,GAAG,kBAAkB,GAAG,SAAS,CAK5D"}
@@ -5,8 +5,10 @@ export function totalTokens(input) {
5
5
  input.cacheReadTokens +
6
6
  input.cacheWriteTokens);
7
7
  }
8
- export function experienceFromTokens(tokenCount, config) {
9
- return tokenCount / config.xpTokensPerPoint;
8
+ /** Fixed rate the unlock curve was calibrated against: 1000 tokens = 1 XP. */
9
+ export const tokensPerExperiencePoint = 1_000;
10
+ export function experienceFromTokens(tokenCount) {
11
+ return tokenCount / tokensPerExperiencePoint;
10
12
  }
11
13
  export function usageReceiptKey(input) {
12
14
  return `${input.sessionId}:${input.messageId}`;
@@ -1 +1 @@
1
- {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/domain/usage/usage.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,OAAO,CACL,KAAK,CAAC,WAAW;QACjB,KAAK,CAAC,YAAY;QAClB,KAAK,CAAC,eAAe;QACrB,KAAK,CAAC,eAAe;QACrB,KAAK,CAAC,gBAAgB,CACvB,CAAA;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,UAAkB,EAClB,MAA6C;IAE7C,OAAO,UAAU,GAAG,MAAM,CAAC,gBAAgB,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAG/B;IACC,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,EAAE,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAIlC;IACC,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,WAAW,CAAA;IACvC,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,UAAU,CAAA;IACpC,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,kBAAkB,CAAA;IAC3C,OAAO,SAAS,CAAA;AAClB,CAAC"}
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/domain/usage/usage.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,OAAO,CACL,KAAK,CAAC,WAAW;QACjB,KAAK,CAAC,YAAY;QAClB,KAAK,CAAC,eAAe;QACrB,KAAK,CAAC,eAAe;QACrB,KAAK,CAAC,gBAAgB,CACvB,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,CAAA;AAE7C,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACrD,OAAO,UAAU,GAAG,wBAAwB,CAAA;AAC9C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAG/B;IACC,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,EAAE,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAIlC;IACC,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,WAAW,CAAA;IACvC,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,UAAU,CAAA;IACpC,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,kBAAkB,CAAA;IAC3C,OAAO,SAAS,CAAA;AAClB,CAAC"}
package/dist/index.js CHANGED
@@ -2088,6 +2088,7 @@ var alolaLocationsCatalog = {
2088
2088
  maximumLevel: 50
2089
2089
  }
2090
2090
  ],
2091
+ championLocationId: "alola-pokemon-league",
2091
2092
  locations: [
2092
2093
  {
2093
2094
  id: "iki-town",
@@ -8093,6 +8094,7 @@ var galarLocationsCatalog = {
8093
8094
  maximumLevel: 70
8094
8095
  }
8095
8096
  ],
8097
+ championLocationId: "energy-plant",
8096
8098
  locations: [
8097
8099
  {
8098
8100
  id: "postwick",
@@ -16165,6 +16167,7 @@ var hoennLocationsCatalog = {
16165
16167
  maximumLevel: 5
16166
16168
  }
16167
16169
  ],
16170
+ championLocationId: "ever-grande-city",
16168
16171
  locations: [
16169
16172
  {
16170
16173
  id: "littleroot-town",
@@ -19719,6 +19722,7 @@ var johtoLocationsCatalog = {
19719
19722
  maximumLevel: 40
19720
19723
  }
19721
19724
  ],
19725
+ championLocationId: "johto-indigo-plateau",
19722
19726
  locations: [
19723
19727
  {
19724
19728
  id: "new-bark-town",
@@ -23871,6 +23875,7 @@ var kalosLocationsCatalog = {
23871
23875
  maximumLevel: 70
23872
23876
  }
23873
23877
  ],
23878
+ championLocationId: "kalos-pokemon-league",
23874
23879
  locations: [
23875
23880
  {
23876
23881
  id: "vaniville-town",
@@ -28199,6 +28204,7 @@ var kantoLocationsCatalog = {
28199
28204
  "squirtle"
28200
28205
  ],
28201
28206
  specialEncounters: [],
28207
+ championLocationId: "indigo-plateau",
28202
28208
  locations: [
28203
28209
  {
28204
28210
  id: "pallet-town",
@@ -43880,6 +43886,7 @@ var paldeaLocationsCatalog = {
43880
43886
  "quaxly"
43881
43887
  ],
43882
43888
  specialEncounters: [],
43889
+ championLocationId: "paldea-pokemon-league",
43883
43890
  locations: [
43884
43891
  {
43885
43892
  id: "cabo-poco",
@@ -166726,6 +166733,7 @@ var sinnohLocationsCatalog = {
166726
166733
  maximumLevel: 50
166727
166734
  }
166728
166735
  ],
166736
+ championLocationId: "victory-road",
166729
166737
  locations: [
166730
166738
  {
166731
166739
  id: "twinleaf-town",
@@ -173929,6 +173937,7 @@ var unovaLocationsCatalog = {
173929
173937
  maximumLevel: 15
173930
173938
  }
173931
173939
  ],
173940
+ championLocationId: "unova-pokemon-league",
173932
173941
  locations: [
173933
173942
  {
173934
173943
  id: "nuvema-town",
@@ -180519,6 +180528,7 @@ var regionSchema = namedIdSchema.extend({
180519
180528
  locations: z3.array(locationSchema).min(1),
180520
180529
  starterSpeciesIds: z3.array(z3.string().min(1)).length(3),
180521
180530
  starterCatchLocationId: z3.string().min(1),
180531
+ championLocationId: z3.string().min(1),
180522
180532
  specials: z3.array(specialSchema)
180523
180533
  });
180524
180534
  var speciesSchema = namedIdSchema.extend({
@@ -180612,6 +180622,7 @@ var catalog = generatedCatalogSchema.parse({
180612
180622
  localization: region.localization,
180613
180623
  starterSpeciesIds: regionalCatalog.starterPokemons,
180614
180624
  starterCatchLocationId: locations[0]?.id ?? "",
180625
+ championLocationId: regionalCatalog.championLocationId,
180615
180626
  specials: specialsForCatalog(regionalCatalog).flatMap((special) => {
180616
180627
  const pokemon = pokemonById.get(special.id);
180617
180628
  const ability = englishAbilityName(pokemon?.abilities[0]);
@@ -180660,6 +180671,12 @@ var catalog = generatedCatalogSchema.parse({
180660
180671
  ]))))
180661
180672
  });
180662
180673
  var generatedContentCatalog = catalog;
180674
+ var championIndexByRegion = new Map(catalog.regions.map((region) => {
180675
+ const index = region.locations.findIndex((location) => location.id === region.championLocationId);
180676
+ if (index < 0)
180677
+ throw new Error(`Unknown championLocationId ${region.championLocationId}`);
180678
+ return [region.id, index];
180679
+ }));
180663
180680
  var regionsById = new Map(catalog.regions.map((region) => [region.id, region]));
180664
180681
  var speciesById = new Map([...catalog.species, ...catalog.regionalForms].map((species) => [species.id, species]));
180665
180682
  var movesById = new Map(movesCatalog.map((move) => [move.id, move]));
@@ -180712,6 +180729,13 @@ function nextLocation(regionId, locationId) {
180712
180729
  const index = locations.findIndex((location) => location.id === locationId);
180713
180730
  return index < 0 ? null : locations[index + 1] ?? null;
180714
180731
  }
180732
+ function championIndexForRegion(regionId) {
180733
+ return championIndexByRegion.get(regionId) ?? null;
180734
+ }
180735
+ function locationIndexFor(regionId, locationId) {
180736
+ const index = locationsForRegion(regionId).findIndex((location) => location.id === locationId);
180737
+ return index < 0 ? null : index;
180738
+ }
180715
180739
  function startersForRegion(regionId, language = "en") {
180716
180740
  return regionsById.get(regionId)?.starterSpeciesIds.flatMap((speciesId) => {
180717
180741
  const species = speciesById.get(speciesId);
@@ -180922,6 +180946,11 @@ var explorationStatusSchema = z5.object({
180922
180946
  locationUnlockThreshold: z5.number().int().positive(),
180923
180947
  regionComplete: z5.boolean()
180924
180948
  });
180949
+ function locationUnlockThreshold(input) {
180950
+ const capped = Math.min(Math.max(input.index, 0), input.championIndex);
180951
+ const cumulative = (i) => input.curve.baseTokens * (i + 1) ** input.curve.exponent * (input.championIndex + 1) ** input.curve.regionExponent;
180952
+ return Math.round(cumulative(capped + 1) - cumulative(capped));
180953
+ }
180925
180954
  function calculateUnlockProgress(input) {
180926
180955
  if (!input.currentLocationIsLatestUnlocked)
180927
180956
  return { kind: "not-latest" };
@@ -181016,10 +181045,11 @@ var starterChoiceResultSchema = z9.object({
181016
181045
  });
181017
181046
  var gameplayConfigSchema = z9.object({
181018
181047
  pauseOnPendingChoice: z9.boolean().default(true),
181019
- xpTokensPerPoint: z9.number().int().positive().default(1000),
181020
181048
  encounterMinimumTokens: z9.number().int().positive().default(200000),
181021
181049
  encounterMaximumTokens: z9.number().int().positive().default(400000),
181022
- locationUnlockTokens: z9.number().int().positive().default(2160000)
181050
+ locationUnlockBaseTokens: z9.number().int().positive().default(4214000),
181051
+ locationUnlockExponent: z9.number().positive().default(2.64),
181052
+ locationUnlockRegionExponent: z9.number().default(-1.72)
181023
181053
  });
181024
181054
  var usageInputSchema = z9.object({
181025
181055
  sessionId: z9.string().min(1),
@@ -181324,6 +181354,11 @@ function createPokemonTransactionStore(database) {
181324
181354
  database.query(`INSERT INTO pokedex_entries (trainer_id, species_id, seen, caught)
181325
181355
  VALUES (?1, ?2, 1, 0)
181326
181356
  ON CONFLICT(trainer_id, species_id) DO UPDATE SET seen = 1`).run(trainerId, speciesId);
181357
+ },
181358
+ markCaught: (trainerId, speciesId) => {
181359
+ database.query(`INSERT INTO pokedex_entries (trainer_id, species_id, seen, caught)
181360
+ VALUES (?1, ?2, 1, 1)
181361
+ ON CONFLICT(trainer_id, species_id) DO UPDATE SET seen = 1, caught = 1`).run(trainerId, speciesId);
181327
181362
  }
181328
181363
  },
181329
181364
  commands: {
@@ -181365,11 +181400,6 @@ function createPokemonTransactionStore(database) {
181365
181400
  database.query("INSERT INTO pokemon_moves (pokemon_id, position, move_id, move_name) VALUES (?1, ?2, ?3, ?4)").run(id, index + 1, move.id, move.name);
181366
181401
  }
181367
181402
  },
181368
- markCaught: (trainerId, speciesId) => {
181369
- database.query(`INSERT INTO pokedex_entries (trainer_id, species_id, seen, caught)
181370
- VALUES (?1, ?2, 1, 1)
181371
- ON CONFLICT(trainer_id, species_id) DO UPDATE SET seen = 1, caught = 1`).run(trainerId, speciesId);
181372
- },
181373
181403
  firstEmptyPartyPosition: (trainerId) => database.query("SELECT position FROM party_slots WHERE trainer_id = ?1 AND pokemon_id IS NULL ORDER BY position LIMIT 1").get(trainerId)?.position ?? null,
181374
181404
  assignPartyPosition: (trainerId, pokemonId, position) => {
181375
181405
  database.query("UPDATE party_slots SET pokemon_id = ?1 WHERE trainer_id = ?2 AND position = ?3").run(pokemonId, trainerId, position);
@@ -181515,7 +181545,7 @@ function trainerIdForQueries(database) {
181515
181545
 
181516
181546
  // src/adapters/sqlite/queries/game-state.ts
181517
181547
  function createSqliteGameStateQuery(database) {
181518
- return (locationUnlockThreshold) => {
181548
+ return (unlockCurve) => {
181519
181549
  const trainer = database.query("SELECT id, current_region_id AS regionId, current_location_id AS locationId FROM trainers LIMIT 1").get();
181520
181550
  if (trainer === null) {
181521
181551
  return gameStateSchema.parse({
@@ -181607,6 +181637,9 @@ function createSqliteGameStateQuery(database) {
181607
181637
  const progress = database.query("SELECT token_count AS tokenCount FROM location_unlock_progress WHERE trainer_id = ?1").get(trainer.id);
181608
181638
  const regionProgress = database.query("SELECT region_id AS regionId, completed FROM region_progress WHERE trainer_id = ?1").all(trainer.id);
181609
181639
  const progressByRegion = new Map(regionProgress.map((region) => [region.regionId, region]));
181640
+ const locationIndex = locationIndexFor(trainer.regionId, trainer.locationId);
181641
+ const championIndex = championIndexForRegion(trainer.regionId);
181642
+ const unlockThreshold = locationIndex === null || championIndex === null ? unlockCurve.baseTokens : locationUnlockThreshold({ index: locationIndex, championIndex, curve: unlockCurve });
181610
181643
  return gameStateSchema.parse({
181611
181644
  phase: "active",
181612
181645
  message: `Your ${trainer.regionId} adventure begins at ${trainer.locationId}.`,
@@ -181639,7 +181672,7 @@ function createSqliteGameStateQuery(database) {
181639
181672
  encounterless: location.encounterless
181640
181673
  })),
181641
181674
  locationUnlockProgress: progress?.tokenCount ?? 0,
181642
- locationUnlockThreshold,
181675
+ locationUnlockThreshold: unlockThreshold,
181643
181676
  regionComplete: progressByRegion.get(trainer.regionId)?.completed === 1
181644
181677
  }
181645
181678
  });
@@ -181962,7 +181995,15 @@ function openGameRepository(path = globalDatabasePath()) {
181962
181995
  database.run("PRAGMA journal_mode = WAL");
181963
181996
  });
181964
181997
  const queryState = createSqliteGameStateQuery(database);
181965
- const readState = (locationUnlockThreshold = gameplayConfigSchema.parse({}).locationUnlockTokens) => queryState(locationUnlockThreshold);
181998
+ const defaultUnlockCurve = () => {
181999
+ const config = gameplayConfigSchema.parse({});
182000
+ return {
182001
+ baseTokens: config.locationUnlockBaseTokens,
182002
+ exponent: config.locationUnlockExponent,
182003
+ regionExponent: config.locationUnlockRegionExponent
182004
+ };
182005
+ };
182006
+ const readState = (unlockCurve = defaultUnlockCurve()) => queryState(unlockCurve);
181966
182007
  const starterSelectionStore = createSqliteStarterSelectionStore(database, readState);
181967
182008
  const collectionQueries = createSqliteCollectionQueries(database);
181968
182009
  const collection = () => {
@@ -182668,6 +182709,7 @@ function resolvePokemonLevels(stores, trainerId, pokemon, regionId, createdAt, c
182668
182709
  const target = evolution.targets[0];
182669
182710
  speciesId = target.speciesId;
182670
182711
  stores.pokemon.evolve(pokemon.id, target.speciesId, target.name);
182712
+ stores.pokemon.markCaught(trainerId, target.speciesId);
182671
182713
  for (const move2 of movesAtLevel(speciesId, level)) {
182672
182714
  learnMove(stores, { trainerId, pokemonId: pokemon.id, move: move2, createdAt, createId });
182673
182715
  }
@@ -182727,7 +182769,7 @@ function createChooseRegionalStarter(dependencies, random) {
182727
182769
  return "already-selected";
182728
182770
  const id = dependencies.createId();
182729
182771
  stores.commands.pokemon.insertStarter({ id, trainerId: trainer.id, starter });
182730
- stores.commands.pokemon.markCaught(trainer.id, starter.speciesId);
182772
+ stores.pokemon.markCaught(trainer.id, starter.speciesId);
182731
182773
  const position = stores.commands.pokemon.firstEmptyPartyPosition(trainer.id);
182732
182774
  if (position !== null)
182733
182775
  stores.commands.pokemon.assignPartyPosition(trainer.id, id, position);
@@ -182843,6 +182885,7 @@ function createChoiceCommands(dependencies) {
182843
182885
  if (!eligible)
182844
182886
  return "invalid-choice";
182845
182887
  stores.pokemon.evolve(choice.payload.pokemonId, target.speciesId, target.name);
182888
+ stores.pokemon.markCaught(trainer.id, target.speciesId);
182846
182889
  const level = stores.commands.pokemon.level(choice.payload.pokemonId);
182847
182890
  if (level !== null) {
182848
182891
  for (const move2 of movesAtLevel(target.speciesId, level)) {
@@ -182892,7 +182935,7 @@ function createEncounterCommands(dependencies) {
182892
182935
  ivs: generated.ivs,
182893
182936
  moves: initialMoves(encounter.speciesId, encounter.level)
182894
182937
  });
182895
- stores.commands.pokemon.markCaught(trainer.id, encounter.speciesId);
182938
+ stores.pokemon.markCaught(trainer.id, encounter.speciesId);
182896
182939
  const position = stores.commands.pokemon.firstEmptyPartyPosition(trainer.id);
182897
182940
  if (position !== null)
182898
182941
  stores.commands.pokemon.assignPartyPosition(trainer.id, id, position);
@@ -183020,8 +183063,9 @@ function createGameCommands(dependencies) {
183020
183063
  function totalTokens(input) {
183021
183064
  return input.inputTokens + input.outputTokens + input.reasoningTokens + input.cacheReadTokens + input.cacheWriteTokens;
183022
183065
  }
183023
- function experienceFromTokens(tokenCount, config) {
183024
- return tokenCount / config.xpTokensPerPoint;
183066
+ var tokensPerExperiencePoint = 1000;
183067
+ function experienceFromTokens(tokenCount) {
183068
+ return tokenCount / tokensPerExperiencePoint;
183025
183069
  }
183026
183070
  function usageReceiptKey(input) {
183027
183071
  return `${input.sessionId}:${input.messageId}`;
@@ -183058,7 +183102,7 @@ function createRecordUsage(dependencies) {
183058
183102
  return disposition;
183059
183103
  if (trainer === null)
183060
183104
  return "inactive";
183061
- stores.pokemon.addPartyExperience(trainer.id, experienceFromTokens(tokenCount, config));
183105
+ stores.pokemon.addPartyExperience(trainer.id, experienceFromTokens(tokenCount));
183062
183106
  resolveUsageLevels(stores, trainer.id, trainer.regionId, input.completedAt, dependencies.createId);
183063
183107
  advanceLocationUnlock(stores, trainer, tokenCount, config, input.completedAt, dependencies.createId);
183064
183108
  advanceUsageEncounters(stores, trainer.id, input, tokenCount, config, random, dependencies.createId);
@@ -183073,10 +183117,21 @@ function advanceLocationUnlock(stores, trainer, tokenCount, config, completedAt,
183073
183117
  return;
183074
183118
  const currentTokens = stores.exploration.unlockTokenCount(trainer.id);
183075
183119
  const next = nextLocation(trainer.regionId, trainer.locationId);
183120
+ const index = locationIndexFor(trainer.regionId, trainer.locationId);
183121
+ const championIndex = championIndexForRegion(trainer.regionId);
183122
+ const threshold = index === null || championIndex === null ? config.locationUnlockBaseTokens : locationUnlockThreshold({
183123
+ index,
183124
+ championIndex,
183125
+ curve: {
183126
+ baseTokens: config.locationUnlockBaseTokens,
183127
+ exponent: config.locationUnlockExponent,
183128
+ regionExponent: config.locationUnlockRegionExponent
183129
+ }
183130
+ });
183076
183131
  const result = calculateUnlockProgress({
183077
183132
  currentTokens,
183078
183133
  gainedTokens: tokenCount,
183079
- threshold: config.locationUnlockTokens,
183134
+ threshold,
183080
183135
  hasNextLocation: next !== null,
183081
183136
  currentLocationIsLatestUnlocked: true
183082
183137
  });
@@ -183176,7 +183231,11 @@ function randomInterval(config, random) {
183176
183231
  // src/application/game.ts
183177
183232
  function createApplicationGame(dependencies) {
183178
183233
  const { repository, random, now, config, createId, createStarterIds } = dependencies;
183179
- const readState = () => repository.readState(config.locationUnlockTokens);
183234
+ const readState = () => repository.readState({
183235
+ baseTokens: config.locationUnlockBaseTokens,
183236
+ exponent: config.locationUnlockExponent,
183237
+ regionExponent: config.locationUnlockRegionExponent
183238
+ });
183180
183239
  const commands = createGameCommands({
183181
183240
  transactions: repository.transactions,
183182
183241
  readState,
package/dist/rpc.js CHANGED
@@ -130,6 +130,11 @@ var explorationStatusSchema = z4.object({
130
130
  locationUnlockThreshold: z4.number().int().positive(),
131
131
  regionComplete: z4.boolean()
132
132
  });
133
+ function locationUnlockThreshold(input) {
134
+ const capped = Math.min(Math.max(input.index, 0), input.championIndex);
135
+ const cumulative = (i) => input.curve.baseTokens * (i + 1) ** input.curve.exponent * (input.championIndex + 1) ** input.curve.regionExponent;
136
+ return Math.round(cumulative(capped + 1) - cumulative(capped));
137
+ }
133
138
  function calculateUnlockProgress(input) {
134
139
  if (!input.currentLocationIsLatestUnlocked)
135
140
  return { kind: "not-latest" };
@@ -224,10 +229,11 @@ var starterChoiceResultSchema = z8.object({
224
229
  });
225
230
  var gameplayConfigSchema = z8.object({
226
231
  pauseOnPendingChoice: z8.boolean().default(true),
227
- xpTokensPerPoint: z8.number().int().positive().default(1000),
228
232
  encounterMinimumTokens: z8.number().int().positive().default(200000),
229
233
  encounterMaximumTokens: z8.number().int().positive().default(400000),
230
- locationUnlockTokens: z8.number().int().positive().default(2160000)
234
+ locationUnlockBaseTokens: z8.number().int().positive().default(4214000),
235
+ locationUnlockExponent: z8.number().positive().default(2.64),
236
+ locationUnlockRegionExponent: z8.number().default(-1.72)
231
237
  });
232
238
  var usageInputSchema = z8.object({
233
239
  sessionId: z8.string().min(1),