@jcendal/opencode-digital-pet 0.4.0 → 0.6.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 (31) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +2 -2
  3. package/dist/adapters/opencode/create-server-hooks.d.ts +5 -5
  4. package/dist/adapters/opencode/usage-event-mapper.d.ts +1 -1
  5. package/dist/adapters/sqlite/sqlite-digital-pet-archive-reader.d.ts +1 -1
  6. package/dist/adapters/sqlite/sqlite-digital-pet-write-store.d.ts +2 -2
  7. package/dist/adapters/sqlite/sqlite-sidebar-snapshot-reader.d.ts +1 -1
  8. package/dist/dev/attach-dev-tools.js +1327 -7
  9. package/dist/digital-pet-animation/constants/evolution-battle.d.ts +2 -2
  10. package/dist/digital-pet-animation/sequences/evolution-battle-artwork.d.ts +5 -8
  11. package/dist/digital-pet-animation/sessions/evolution-battle-session.d.ts +1 -1
  12. package/dist/digital-pet-animation/sessions/evolution-presentation.d.ts +14 -0
  13. package/dist/digital-pet-animation/sessions/presentation-state.d.ts +1 -1
  14. package/dist/digital-pet-core/adapters/sqlite/sqlite-digital-pet-types.d.ts +2 -2
  15. package/dist/digital-pet-core/application/use-cases/resolve-evolution-battle.d.ts +1 -1
  16. package/dist/digital-pet-core/application/use-cases/spawn-partner.d.ts +1 -1
  17. package/dist/digital-pet-core/data/combat-stats.d.ts +3 -0
  18. package/dist/digital-pet-core/data/stages.d.ts +2 -2
  19. package/dist/digital-pet-core/domain/combat.d.ts +28 -0
  20. package/dist/digital-pet-core/domain/digimon-node.d.ts +2 -0
  21. package/dist/digital-pet-core/domain/evolution-battle.d.ts +2 -0
  22. package/dist/digital-pet-core/domain/feeding.d.ts +14 -0
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +1690 -370
  25. package/dist/tui/digital-pet-command-layer.d.ts +1 -1
  26. package/dist/tui/digital-pet-dex-dialog.d.ts +2 -1
  27. package/dist/tui/digital-pet-history-dialog.d.ts +2 -1
  28. package/dist/tui/sidebar-card.d.ts +2 -2
  29. package/dist/tui.d.ts +5 -5
  30. package/dist/tui.js +9822 -8482
  31. package/package.json +7 -2
package/dist/index.js CHANGED
@@ -1,119 +1,1492 @@
1
- // ../digital-pet-core/src/application/use-cases/freeze-digital-pet.ts
2
- var freezeDigitalPet = (control) => control.freeze();
3
-
4
- // src/commands/digital-pet-freeze.ts
5
- var runDigitalPetFreezeCommand = async (control, context) => {
6
- const outcome = freezeDigitalPet(control);
7
- const parts = [
8
- {
9
- id: context.messageID,
10
- sessionID: context.sessionID,
11
- messageID: context.messageID,
12
- type: "text",
13
- text: "Digital Pet frozen."
14
- }
15
- ];
16
- switch (outcome.kind) {
17
- case "frozen":
18
- return { parts, event: { kind: "frozen" } };
19
- case "already_frozen":
20
- return { parts };
21
- default: {
22
- const unexpectedOutcome = outcome;
23
- return unexpectedOutcome;
24
- }
1
+ // ../digital-pet-core/src/domain/evolution-battle.ts
2
+ var pickEvolutionTarget = (current, selector) => {
3
+ if (current.nextEvolutions.length === 0) {
4
+ throw new Error("Evolution target selection failed: partner has no evolution options");
5
+ }
6
+ const selection = selector();
7
+ if (!Number.isFinite(selection) || selection < 0 || selection >= 1) {
8
+ throw new Error(`Evolution selector must return a finite number in [0, 1), received ${selection}`);
25
9
  }
10
+ const targetId = current.nextEvolutions[Math.floor(selection * current.nextEvolutions.length)];
11
+ if (targetId === void 0) throw new Error("Evolution target selection failed");
12
+ return targetId;
13
+ };
14
+ var pickRandomSameStageOpponent = (current, catalogNodes, selector) => {
15
+ const candidates = catalogNodes.filter((node) => node.stage === current.stage && node.id !== current.id);
16
+ if (candidates.length === 0) {
17
+ return current.id;
18
+ }
19
+ const selection = selector();
20
+ if (!Number.isFinite(selection) || selection < 0 || selection >= 1) {
21
+ throw new Error(`Evolution selector must return a finite number in [0, 1), received ${selection}`);
22
+ }
23
+ const opponent = candidates[Math.floor(selection * candidates.length)];
24
+ if (opponent === void 0) throw new Error("Same-stage opponent selection failed");
25
+ return opponent.id;
26
26
  };
27
27
 
28
- // ../digital-pet-core/src/application/use-cases/spawn-partner.ts
29
- var spawnPartner = (lifecycle, createdAt) => {
30
- const partner = lifecycle.spawnPartner({
31
- currentNodeId: "0-001",
32
- gauge: 0,
33
- isTerminal: false,
34
- createdAt
35
- });
36
- return { generation: partner.generation };
28
+ // ../digital-pet-core/src/domain/stage.ts
29
+ var DIGIMON_STAGES = [0, 1, 2, 3, 4, 5, 6, 7];
30
+ var isDigimonStage = (value) => {
31
+ return DIGIMON_STAGES.some((stage) => stage === value);
37
32
  };
38
33
 
39
- // src/commands/digital-pet-spawn.ts
40
- var runDigitalPetSpawnCommand = async (lifecycle, context) => {
41
- const partner = spawnPartner(lifecycle, context.createdAt);
34
+ // ../digital-pet-core/src/domain/evolution.ts
35
+ var STAGE_GAUGE_THRESHOLDS = Object.freeze({
36
+ 0: 5e6,
37
+ 1: 1e7,
38
+ 2: 2e7,
39
+ 3: 4e7,
40
+ 4: 75e6,
41
+ 5: 125e6,
42
+ 6: 2e8,
43
+ 7: 3e8
44
+ });
45
+ var isRecord = (value) => {
46
+ return typeof value === "object" && value !== null;
47
+ };
48
+ var isStageThresholds = (thresholds) => {
49
+ if (!isRecord(thresholds) || !Object.isFrozen(thresholds)) return false;
50
+ return DIGIMON_STAGES.every((stage) => {
51
+ const threshold = thresholds[stage];
52
+ return typeof threshold === "number" && Number.isFinite(threshold) && threshold > 0;
53
+ });
54
+ };
55
+ var hasPendingBattle = (state) => state.pendingEvolutionTargetId != null && state.battleOpponentNodeId != null;
56
+ var applyTokenProgress = (state, tokenDelta, selector, digimonById, catalogNodes, thresholds) => {
57
+ if (!isStageThresholds(thresholds)) {
58
+ throw new Error("Evolution thresholds must be a complete frozen policy of positive finite numbers");
59
+ }
60
+ if (state.isTerminal) return state;
61
+ if (hasPendingBattle(state)) return state;
62
+ const threshold = thresholds[state.current.stage];
63
+ const gauge = state.gauge + tokenDelta;
64
+ if (gauge < threshold) return { ...state, gauge };
65
+ if (state.current.nextEvolutions.length === 0) {
66
+ return { ...state, gauge: 0, isTerminal: true, pendingEvolutionTargetId: null, battleOpponentNodeId: null };
67
+ }
68
+ const pendingEvolutionTargetId = pickEvolutionTarget(state.current, selector);
69
+ const target = digimonById.get(pendingEvolutionTargetId);
70
+ if (target === void 0) {
71
+ throw new Error(`Evolution target ${pendingEvolutionTargetId} is missing from the catalog`);
72
+ }
73
+ if (state.current.stage === 0) {
74
+ return {
75
+ current: target,
76
+ gauge: 0,
77
+ isTerminal: target.nextEvolutions.length === 0,
78
+ pendingEvolutionTargetId: null,
79
+ battleOpponentNodeId: null
80
+ };
81
+ }
82
+ const battleOpponentNodeId = pickRandomSameStageOpponent(state.current, catalogNodes, selector);
83
+ if (digimonById.get(battleOpponentNodeId) === void 0) {
84
+ throw new Error(`Battle opponent ${battleOpponentNodeId} is missing from the catalog`);
85
+ }
42
86
  return {
43
- parts: [
44
- {
45
- id: context.messageID,
46
- sessionID: context.sessionID,
47
- messageID: context.messageID,
48
- type: "text",
49
- text: `Spawned Generation ${partner.generation}.`
50
- }
51
- ],
52
- event: { kind: "spawned", nodeId: "0-001", generation: partner.generation }
87
+ current: state.current,
88
+ gauge: threshold,
89
+ isTerminal: false,
90
+ pendingEvolutionTargetId,
91
+ battleOpponentNodeId
53
92
  };
54
93
  };
55
94
 
56
- // ../digital-pet-core/src/application/use-cases/set-digital-pet-cheat-node.ts
57
- var setDigitalPetCheatNode = (control, validatedNodeId) => control.setCheatNode(validatedNodeId);
58
-
59
- // src/commands/digital-pet-set.ts
60
- var textPart = (context, text) => ({
61
- id: context.messageID,
62
- sessionID: context.sessionID,
63
- messageID: context.messageID,
64
- type: "text",
65
- text
66
- });
67
- var runDigitalPetSetCommand = async (control, context, loadCatalog) => {
68
- if (context.arguments.includes("\n")) return { parts: [textPart(context, "Usage: /digital-pet-set <id>.")] };
69
- const tokens = context.arguments.trim().split(/\s+/);
70
- if (context.arguments.trim() === "" || tokens.length !== 1)
71
- return { parts: [textPart(context, "Usage: /digital-pet-set <id>.")] };
72
- const requestedId = tokens[0];
73
- if (requestedId === void 0) return { parts: [textPart(context, "Usage: /digital-pet-set <id>.")] };
74
- const node = (await loadCatalog()).byId.get(requestedId);
75
- if (node === void 0) return { parts: [textPart(context, `Unknown Digimon ID: ${requestedId}.`)] };
76
- const outcome = setDigitalPetCheatNode(control, node.id);
77
- const parts = [textPart(context, `Digital Pet set to ${node.nameEn} (${node.id}).`)];
78
- switch (outcome.kind) {
79
- case "set":
80
- return { parts, event: { kind: "set", nodeId: node.id } };
81
- case "already_set":
82
- return { parts };
83
- default: {
84
- const unexpectedOutcome = outcome;
85
- return unexpectedOutcome;
95
+ // ../digital-pet-core/src/application/use-cases/record-usage.ts
96
+ var recordUsage = ({
97
+ usage,
98
+ ledger,
99
+ digimonById,
100
+ catalogNodes,
101
+ selector,
102
+ thresholds
103
+ }) => {
104
+ let evolution;
105
+ let evolutionBattlePending;
106
+ const outcome = ledger.applyUsageReceipt(usage, (partner) => {
107
+ const current = digimonById.get(partner.currentNodeId);
108
+ if (current === void 0)
109
+ throw new Error(`Persisted partner node ${partner.currentNodeId} is missing from the catalog`);
110
+ const hadPendingBattle = partner.pendingEvolutionTargetId != null && partner.battleOpponentNodeId != null;
111
+ const next = applyTokenProgress(
112
+ {
113
+ current,
114
+ gauge: partner.gauge,
115
+ isTerminal: partner.isTerminal,
116
+ pendingEvolutionTargetId: partner.pendingEvolutionTargetId,
117
+ battleOpponentNodeId: partner.battleOpponentNodeId
118
+ },
119
+ usage.tokenDelta,
120
+ selector,
121
+ digimonById,
122
+ catalogNodes,
123
+ thresholds
124
+ );
125
+ if (!hadPendingBattle && next.pendingEvolutionTargetId !== null && next.battleOpponentNodeId !== null && next.current.id === current.id) {
126
+ evolutionBattlePending = {
127
+ opponentNodeId: next.battleOpponentNodeId,
128
+ targetNodeId: next.pendingEvolutionTargetId
129
+ };
86
130
  }
131
+ if (next.current.id !== current.id) {
132
+ evolution = { fromNodeId: current.id, toNodeId: next.current.id };
133
+ }
134
+ return {
135
+ currentNodeId: next.current.id,
136
+ gauge: next.gauge,
137
+ isTerminal: next.isTerminal,
138
+ pendingEvolutionTargetId: next.pendingEvolutionTargetId,
139
+ battleOpponentNodeId: next.battleOpponentNodeId
140
+ };
141
+ });
142
+ switch (outcome.kind) {
143
+ case "applied":
144
+ if (evolutionBattlePending !== void 0) {
145
+ return { kind: "applied", receiptKey: usage.receiptKey, evolutionBattlePending };
146
+ }
147
+ return evolution === void 0 ? { kind: "applied", receiptKey: usage.receiptKey } : { kind: "applied", receiptKey: usage.receiptKey, evolution };
148
+ case "duplicate":
149
+ return { kind: "duplicate", receiptKey: usage.receiptKey };
150
+ case "no_active_partner":
151
+ return { kind: "no_active_partner", receiptKey: usage.receiptKey };
87
152
  }
88
153
  };
89
154
 
90
- // ../digital-pet-core/src/application/use-cases/unfreeze-digital-pet.ts
91
- var unfreezeDigitalPet = (control) => control.unfreeze();
155
+ // ../digital-pet-core/src/application/use-cases/reconcile-usage.ts
156
+ var reconcileUsage = ({
157
+ usages,
158
+ ledger,
159
+ digimonById,
160
+ catalogNodes,
161
+ selector,
162
+ thresholds
163
+ }) => {
164
+ const outcomes = [];
165
+ for (const usage of usages) {
166
+ outcomes.push(recordUsage({ usage, ledger, digimonById, catalogNodes, selector, thresholds }));
167
+ }
168
+ return outcomes;
169
+ };
92
170
 
93
- // src/commands/digital-pet-unfreeze.ts
94
- var runDigitalPetUnfreezeCommand = async (control, context) => {
95
- const outcome = unfreezeDigitalPet(control);
96
- const parts = [
97
- {
98
- id: context.messageID,
99
- sessionID: context.sessionID,
100
- messageID: context.messageID,
101
- type: "text",
102
- text: "Digital Pet unfrozen."
103
- }
104
- ];
105
- switch (outcome.kind) {
106
- case "unfrozen":
107
- return { parts, event: { kind: "unfrozen" } };
108
- case "already_unfrozen":
109
- return { parts };
110
- default: {
111
- const unexpectedOutcome = outcome;
112
- return unexpectedOutcome;
113
- }
171
+ // ../digital-pet-core/src/domain/combat.ts
172
+ var COMBAT_POLICY = Object.freeze({ hitsToWin: 3, maxShots: 24, scale: 25, minimum: 0.05, maximum: 0.95 });
173
+ var NEUTRAL_COMBAT_STATS = Object.freeze({ strength: 50, evasion: 50 });
174
+ var validateCombatStats = (stats) => {
175
+ for (const value of [stats.strength, stats.evasion]) {
176
+ if (!Number.isInteger(value) || value < 0 || value > 100)
177
+ throw new Error("Combat stats must be integers in [0, 100]");
114
178
  }
179
+ return Object.freeze({ ...stats });
115
180
  };
116
181
 
182
+ // ../digital-pet-core/src/data/combat-stats.ts
183
+ var COMBAT_STATS = new Map(
184
+ [
185
+ ["0-001", 0, 0],
186
+ // Digiegg
187
+ // Baby I: gentle variation around (25, 35); familiar starters receive a modest edge.
188
+ ["1-001", 26, 34],
189
+ // Argomon: balanced
190
+ ["1-002", 29, 37],
191
+ // Botamon: versatile classic
192
+ ["1-003", 27, 38],
193
+ // Chibomon: agile starter
194
+ ["1-004", 25, 32],
195
+ // Choromon: measured attacker
196
+ ["1-005", 24, 38],
197
+ // Conomon: evasive
198
+ ["1-006", 28, 31],
199
+ // Cotsucomon: offense over mobility
200
+ ["1-007", 29, 33],
201
+ // Dodomon: assertive attacker
202
+ ["1-008", 23, 40],
203
+ // Fufumon: elusive
204
+ ["1-009", 26, 36],
205
+ // Keemon: balanced
206
+ ["1-010", 27, 34],
207
+ // Ketomon: offensive leaning
208
+ ["1-011", 28, 36],
209
+ // Kuramon: accurate, still mobile
210
+ ["1-012", 22, 39],
211
+ // Mokumon: evasive specialist
212
+ ["1-013", 23, 36],
213
+ // Nyokimon: defensive leaning
214
+ ["1-014", 24, 37],
215
+ // Pabumon: defensive leaning
216
+ ["1-015", 30, 31],
217
+ // Petitmon: strongest attack, low evasion
218
+ ["1-016", 22, 38],
219
+ // Pichimon: evasive specialist
220
+ ["1-017", 24, 41],
221
+ // Poyomon: elusive classic
222
+ ["1-018", 30, 35],
223
+ // Punimon: offensive classic
224
+ ["1-019", 23, 39],
225
+ // Pururumon: elusive
226
+ ["1-020", 25, 39],
227
+ // Puttimon: defensive balance
228
+ ["1-021", 28, 32],
229
+ // Sakumon: offensive specialist
230
+ ["1-022", 26, 37],
231
+ // Tsubumon: steady all-rounder
232
+ ["1-023", 24, 40],
233
+ // YukimiBotamon: evasive starter
234
+ ["1-024", 25, 40],
235
+ // Yuramon: defensive classic
236
+ ["1-025", 27, 35],
237
+ // Zerimon: offensive balance
238
+ ["1-026", 25, 34],
239
+ // Zurumon: balanced
240
+ ["1-027", 26, 38],
241
+ // Chibickmon: mobile all-rounder
242
+ ["1-028", 26, 33],
243
+ // Dokimon: offensive leaning
244
+ ["1-029", 30, 33],
245
+ // Jyarimon: offensive starter
246
+ ["1-030", 23, 41],
247
+ // Relemon: elusive specialist
248
+ ["1-031", 28, 34],
249
+ // Sandmon: offensive balance
250
+ // Baby II: variation around (35, 40); distinct roles with no overwhelming starter.
251
+ ["2-001", 37, 38],
252
+ // Argomon: offensive balance
253
+ ["2-002", 39, 36],
254
+ // Bebydomon: offensive specialist
255
+ ["2-003", 34, 41],
256
+ // Budmon: defensive balance
257
+ ["2-004", 35, 46],
258
+ // Bukamon: evasive classic
259
+ ["2-005", 40, 35],
260
+ // DemiMeramon: offense over mobility
261
+ ["2-006", 40, 42],
262
+ // DemiVeemon: versatile starter
263
+ ["2-007", 41, 37],
264
+ // Dorimon: assertive attacker
265
+ ["2-008", 37, 45],
266
+ // Gummymon: agile starter
267
+ ["2-009", 38, 39],
268
+ // Hopmon: offensive balance
269
+ ["2-010", 39, 35],
270
+ // Kakkinmon: offense over mobility
271
+ ["2-011", 36, 38],
272
+ // Kapurimon: measured attacker
273
+ ["2-012", 36, 45],
274
+ // Kokomon: agile starter
275
+ ["2-013", 40, 43],
276
+ // Koromon: versatile classic
277
+ ["2-014", 33, 44],
278
+ // Kyokyomon: evasive specialist
279
+ ["2-015", 37, 43],
280
+ // Motimon: balanced classic
281
+ ["2-016", 33, 47],
282
+ // Nyaromon: agile, weaker attack
283
+ ["2-017", 35, 42],
284
+ // Pagumon: defensive balance
285
+ ["2-018", 32, 46],
286
+ // Poromon: elusive specialist
287
+ ["2-019", 40, 36],
288
+ // Sakuttomon: offensive specialist
289
+ ["2-020", 34, 46],
290
+ // Tanemon: defensive classic
291
+ ["2-021", 42, 40],
292
+ // Tokomon: powerful bite, moderate evasion
293
+ ["2-022", 42, 42],
294
+ // Tokomon X: a small evasion upgrade
295
+ ["2-023", 41, 36],
296
+ // Tsumemon: offensive specialist
297
+ ["2-024", 41, 42],
298
+ // Tsunomon: offensive classic
299
+ ["2-025", 34, 44],
300
+ // Upamon: defensive balance
301
+ ["2-026", 35, 45],
302
+ // Wanyamon: agile all-rounder
303
+ ["2-027", 38, 38],
304
+ // Yaamon: offensive balance
305
+ ["2-028", 35, 44],
306
+ // Yokomon: defensive classic
307
+ ["2-029", 36, 44],
308
+ // Bibimon: mobile all-rounder
309
+ ["2-030", 42, 38],
310
+ // Gigimon: offensive starter
311
+ ["2-031", 38, 36],
312
+ // Tumblemon: offensive leaning
313
+ ["2-032", 33, 43],
314
+ // Hiyarimon: evasive specialist
315
+ ["2-033", 32, 40],
316
+ // Minomon: modest defensive profile
317
+ ["2-034", 31, 45],
318
+ // Moonmon: evasion over offense
319
+ ["2-035", 36, 39],
320
+ // Pickmon: balanced
321
+ ["2-036", 34, 47],
322
+ // Viximon: elusive starter
323
+ ["2-037", 39, 37],
324
+ // Sunmon: offense over evasion
325
+ ["3-001", 58, 44],
326
+ // Agumon
327
+ ["3-002", 50, 50],
328
+ // Agumon (Black) X
329
+ ["3-003", 50, 50],
330
+ // Agumon Expert
331
+ ["3-004", 50, 50],
332
+ // Agumon X
333
+ ["3-005", 50, 50],
334
+ // Argomon
335
+ ["3-006", 50, 50],
336
+ // Armadillomon
337
+ ["3-007", 50, 50],
338
+ // Betamon
339
+ ["3-008", 50, 50],
340
+ // Biyomon
341
+ ["3-009", 50, 50],
342
+ // Bulucomon
343
+ ["3-010", 50, 50],
344
+ // BushiAgumon
345
+ ["3-011", 50, 50],
346
+ // Candlemon
347
+ ["3-012", 50, 50],
348
+ // Coronamon
349
+ ["3-013", 50, 50],
350
+ // Crabmon
351
+ ["3-014", 50, 50],
352
+ // DemiDevimon
353
+ ["3-015", 50, 50],
354
+ // Dorumon
355
+ ["3-016", 50, 50],
356
+ // Dracomon
357
+ ["3-017", 50, 50],
358
+ // Dracomon X
359
+ ["3-018", 50, 50],
360
+ // Duskmon
361
+ ["3-019", 50, 50],
362
+ // Elecmon
363
+ ["3-020", 50, 50],
364
+ // Falcomon
365
+ ["3-021", 46, 54],
366
+ // Floramon
367
+ ["3-022", 50, 56],
368
+ // Gabumon
369
+ ["3-023", 50, 50],
370
+ // Gabumon X
371
+ ["3-024", 50, 50],
372
+ // Gaomon
373
+ ["3-025", 52, 68],
374
+ // Gatomon
375
+ ["3-026", 50, 50],
376
+ // Gazimon
377
+ ["3-027", 50, 50],
378
+ // Ghostmon
379
+ ["3-028", 50, 50],
380
+ // Gizamon
381
+ ["3-029", 50, 50],
382
+ // Gomamon
383
+ ["3-030", 50, 50],
384
+ // Gomamon X
385
+ ["3-031", 50, 50],
386
+ // Gotsumon
387
+ ["3-032", 50, 50],
388
+ // Guilmon
389
+ ["3-033", 50, 50],
390
+ // Hagurumon
391
+ ["3-034", 42, 62],
392
+ // Hawkmon
393
+ ["3-035", 50, 50],
394
+ // Herissmon
395
+ ["3-036", 50, 50],
396
+ // Huckmon
397
+ ["3-037", 50, 50],
398
+ // Impmon
399
+ ["3-038", 50, 50],
400
+ // Impmon X
401
+ ["3-039", 50, 50],
402
+ // Jazamon
403
+ ["3-040", 50, 50],
404
+ // Junkmon
405
+ ["3-041", 50, 50],
406
+ // Keramon X
407
+ ["3-042", 50, 50],
408
+ // Kokuwamon
409
+ ["3-043", 50, 50],
410
+ // Kokuwamon X
411
+ ["3-044", 50, 50],
412
+ // Kunemon
413
+ ["3-045", 50, 50],
414
+ // Labramon
415
+ ["3-046", 50, 50],
416
+ // Lalamon
417
+ ["3-047", 50, 50],
418
+ // Lopmon
419
+ ["3-048", 50, 50],
420
+ // Lopmon X
421
+ ["3-049", 50, 50],
422
+ // Ludomon
423
+ ["3-050", 50, 50],
424
+ // Lunamon
425
+ ["3-051", 50, 50],
426
+ // Monodramon
427
+ ["3-052", 50, 50],
428
+ // Morphomon
429
+ ["3-053", 50, 50],
430
+ // Mushroomon
431
+ ["3-054", 50, 50],
432
+ // Otamamon
433
+ ["3-055", 50, 50],
434
+ // Otamamon X
435
+ ["3-056", 46, 54],
436
+ // Palmon
437
+ ["3-057", 46, 54],
438
+ // Palmon X
439
+ ["3-058", 44, 66],
440
+ // Patamon
441
+ ["3-059", 50, 50],
442
+ // Phascomon
443
+ ["3-060", 50, 50],
444
+ // Pomumon
445
+ ["3-061", 50, 50],
446
+ // Renamon X
447
+ ["3-062", 50, 50],
448
+ // Ryudamon
449
+ ["3-063", 50, 50],
450
+ // Salamon
451
+ ["3-064", 50, 50],
452
+ // Salamon X
453
+ ["3-065", 50, 50],
454
+ // Sangomon
455
+ ["3-066", 50, 50],
456
+ // Shoutmon
457
+ ["3-067", 50, 50],
458
+ // Sistermon Blanc
459
+ ["3-068", 50, 50],
460
+ // Sunarizamon
461
+ ["3-069", 50, 50],
462
+ // Swimmon
463
+ ["3-070", 50, 50],
464
+ // Syakomon
465
+ ["3-071", 50, 50],
466
+ // Syakomon X
467
+ ["3-072", 50, 50],
468
+ // Tapirmon
469
+ ["3-073", 50, 50],
470
+ // Tentomon
471
+ ["3-074", 50, 50],
472
+ // Terriermon
473
+ ["3-075", 50, 50],
474
+ // Terriermon X
475
+ ["3-076", 50, 50],
476
+ // Tinkermon
477
+ ["3-077", 50, 50],
478
+ // ToyAgumon
479
+ ["3-078", 50, 50],
480
+ // Veemon
481
+ ["3-079", 50, 50],
482
+ // Vorvomon
483
+ ["3-080", 50, 50],
484
+ // Wormmon
485
+ ["3-081", 50, 50],
486
+ // Zubamon
487
+ ["3-082", 50, 50],
488
+ // Agumon (Black)
489
+ ["3-083", 50, 50],
490
+ // Dracmon
491
+ ["3-084", 50, 50],
492
+ // Pulsemon
493
+ ["3-085", 50, 50],
494
+ // Renamon
495
+ ["4-001", 60, 50],
496
+ // Agunimon
497
+ ["4-002", 60, 50],
498
+ // Airdramon
499
+ ["4-003", 60, 50],
500
+ // Allomon X
501
+ ["4-004", 68, 60],
502
+ // Angemon
503
+ ["4-005", 60, 50],
504
+ // Ankylomon
505
+ ["4-006", 60, 50],
506
+ // Apemon
507
+ ["4-007", 60, 50],
508
+ // Aquilamon
509
+ ["4-008", 60, 50],
510
+ // Argomon
511
+ ["4-009", 60, 50],
512
+ // Arresterdramon
513
+ ["4-010", 60, 50],
514
+ // Baboongamon
515
+ ["4-011", 60, 50],
516
+ // Bakemon
517
+ ["4-012", 60, 50],
518
+ // Baluchimon
519
+ ["4-013", 60, 50],
520
+ // BaoHuckmon
521
+ ["4-014", 52, 62],
522
+ // Birdramon
523
+ ["4-015", 60, 50],
524
+ // Centarumon
525
+ ["4-016", 60, 50],
526
+ // Clockmon
527
+ ["4-017", 60, 50],
528
+ // Coelamon
529
+ ["4-018", 60, 50],
530
+ // Coredramon (Blue)
531
+ ["4-019", 60, 50],
532
+ // Coredramon (Green)
533
+ ["4-020", 60, 50],
534
+ // Cyclonemon
535
+ ["4-021", 60, 50],
536
+ // Damemon
537
+ ["4-022", 60, 50],
538
+ // Darcmon
539
+ ["4-023", 72, 38],
540
+ // DarkTyrannomon
541
+ ["4-024", 72, 38],
542
+ // DarkTyrannomon X
543
+ ["4-025", 60, 50],
544
+ // Deltamon
545
+ ["4-026", 60, 50],
546
+ // Deputymon
547
+ ["4-027", 60, 50],
548
+ // Devidramon
549
+ ["4-028", 60, 50],
550
+ // Devimon
551
+ ["4-029", 60, 50],
552
+ // Diatrymon
553
+ ["4-030", 60, 50],
554
+ // Dobermon
555
+ ["4-031", 60, 50],
556
+ // Dokugumon
557
+ ["4-032", 60, 50],
558
+ // Dolphmon
559
+ ["4-033", 60, 50],
560
+ // Dorugamon
561
+ ["4-034", 60, 50],
562
+ // Drimogemon
563
+ ["4-035", 60, 50],
564
+ // Duskmon
565
+ ["4-036", 60, 50],
566
+ // Ebidramon
567
+ ["4-037", 60, 50],
568
+ // Eosmon
569
+ ["4-038", 60, 50],
570
+ // ExVeemon
571
+ ["4-039", 60, 50],
572
+ // Filmon
573
+ ["4-040", 60, 50],
574
+ // Firamon
575
+ ["4-041", 60, 50],
576
+ // Flarerizamon
577
+ ["4-042", 52, 62],
578
+ // Flymon
579
+ ["4-043", 60, 50],
580
+ // Frigimon
581
+ ["4-044", 60, 50],
582
+ // Gaogamon
583
+ ["4-045", 60, 50],
584
+ // Gargomon
585
+ ["4-046", 64, 70],
586
+ // Garurumon
587
+ ["4-047", 52, 68],
588
+ // Gatomon
589
+ ["4-048", 60, 50],
590
+ // Gatomon X
591
+ ["4-049", 60, 50],
592
+ // Gekomon
593
+ ["4-050", 72, 38],
594
+ // GeoGreymon
595
+ ["4-051", 60, 50],
596
+ // Gesomon
597
+ ["4-052", 60, 50],
598
+ // Ginryumon
599
+ ["4-053", 72, 38],
600
+ // Golemon
601
+ ["4-054", 78, 35],
602
+ // Greymon
603
+ ["4-055", 60, 50],
604
+ // Growlmon
605
+ ["4-056", 60, 50],
606
+ // Growlmon X
607
+ ["4-057", 68, 42],
608
+ // Guardromon
609
+ ["4-058", 60, 50],
610
+ // Hookmon
611
+ ["4-059", 60, 50],
612
+ // Hudiemon
613
+ ["4-060", 60, 50],
614
+ // Ikkakumon
615
+ ["4-061", 60, 50],
616
+ // Jazardmon
617
+ ["4-062", 60, 50],
618
+ // Kabuterimon
619
+ ["4-063", 60, 50],
620
+ // Kiwimon
621
+ ["4-064", 60, 50],
622
+ // Kokatorimon
623
+ ["4-065", 60, 50],
624
+ // Komondomon
625
+ ["4-066", 60, 50],
626
+ // Kuwagamon
627
+ ["4-067", 60, 50],
628
+ // Kuwagamon X
629
+ ["4-068", 60, 50],
630
+ // Lavorvomon
631
+ ["4-069", 60, 50],
632
+ // Lekismon
633
+ ["4-070", 60, 50],
634
+ // Leomon
635
+ ["4-071", 60, 50],
636
+ // Leomon X
637
+ ["4-072", 60, 50],
638
+ // Lobomon
639
+ ["4-073", 60, 50],
640
+ // Machmon
641
+ ["4-074", 60, 50],
642
+ // MadLeomon
643
+ ["4-075", 60, 50],
644
+ // Manbomon
645
+ ["4-076", 60, 50],
646
+ // Mantaraymon X
647
+ ["4-077", 60, 50],
648
+ // Meicoomon
649
+ ["4-078", 60, 50],
650
+ // Mekanorimon
651
+ ["4-079", 60, 50],
652
+ // Meramon
653
+ ["4-080", 60, 50],
654
+ // Meramon X
655
+ ["4-081", 60, 50],
656
+ // Mimicmon
657
+ ["4-082", 60, 50],
658
+ // Minotarumon
659
+ ["4-083", 60, 50],
660
+ // Mojyamon
661
+ ["4-084", 60, 50],
662
+ // Monochromon
663
+ ["4-085", 60, 50],
664
+ // Nanimon
665
+ ["4-086", 60, 50],
666
+ // Nefertimon X
667
+ ["4-087", 52, 62],
668
+ // Ninjamon
669
+ ["4-088", 35, 40],
670
+ // Numemon
671
+ ["4-089", 60, 50],
672
+ // Numemon X
673
+ ["4-090", 60, 50],
674
+ // Octomon
675
+ ["4-091", 72, 38],
676
+ // Ogremon
677
+ ["4-092", 72, 38],
678
+ // Ogremon X
679
+ ["4-093", 60, 50],
680
+ // Omekamon
681
+ ["4-094", 60, 50],
682
+ // Paledramon
683
+ ["4-095", 60, 50],
684
+ // Parasaurmon
685
+ ["4-096", 60, 50],
686
+ // Peckmon
687
+ ["4-097", 60, 50],
688
+ // Pegasusmon X
689
+ ["4-098", 60, 50],
690
+ // Petermon
691
+ ["4-099", 60, 50],
692
+ // Porcupamon
693
+ ["4-100", 60, 50],
694
+ // Pteramon X
695
+ ["4-101", 60, 50],
696
+ // Raremon
697
+ ["4-102", 56, 54],
698
+ // RedVegiemon
699
+ ["4-103", 60, 50],
700
+ // Reppamon
701
+ ["4-104", 60, 50],
702
+ // Rhinomon X
703
+ ["4-105", 60, 50],
704
+ // Roachmon
705
+ ["4-106", 60, 50],
706
+ // Sangloupmon
707
+ ["4-107", 60, 50],
708
+ // Seadramon
709
+ ["4-108", 60, 50],
710
+ // Seadramon X
711
+ ["4-109", 60, 50],
712
+ // Seasarmon X
713
+ ["4-110", 60, 50],
714
+ // Shadramon
715
+ ["4-111", 60, 50],
716
+ // Shellmon
717
+ ["4-112", 60, 50],
718
+ // ShellNumemon
719
+ ["4-113", 60, 50],
720
+ // Shoutmon X3
721
+ ["4-114", 60, 50],
722
+ // Sistermon Ciel
723
+ ["4-115", 60, 50],
724
+ // Starmon
725
+ ["4-116", 52, 62],
726
+ // Stingmon
727
+ ["4-117", 60, 50],
728
+ // Strikedramon
729
+ ["4-118", 60, 50],
730
+ // Submarimon
731
+ ["4-119", 60, 50],
732
+ // Sukamon
733
+ ["4-120", 60, 50],
734
+ // Sunflowmon
735
+ ["4-121", 68, 42],
736
+ // Tankmon
737
+ ["4-122", 60, 50],
738
+ // Targetmon
739
+ ["4-123", 60, 50],
740
+ // Thundermon
741
+ ["4-124", 60, 50],
742
+ // TiaLudomon
743
+ ["4-125", 60, 50],
744
+ // Tobiumon
745
+ ["4-126", 60, 50],
746
+ // TobuCatmon
747
+ ["4-127", 56, 54],
748
+ // Togemon
749
+ ["4-128", 56, 54],
750
+ // Togemon X
751
+ ["4-129", 60, 50],
752
+ // Tortomon
753
+ ["4-130", 60, 50],
754
+ // Troopmon
755
+ ["4-131", 60, 50],
756
+ // Turuiemon
757
+ ["4-132", 60, 50],
758
+ // Tuskmon
759
+ ["4-133", 60, 50],
760
+ // Tylomon
761
+ ["4-134", 60, 50],
762
+ // Tylomon X
763
+ ["4-135", 72, 38],
764
+ // Tyrannomon
765
+ ["4-136", 72, 38],
766
+ // Tyrannomon X
767
+ ["4-137", 60, 50],
768
+ // Unimon
769
+ ["4-138", 60, 50],
770
+ // Veedramon
771
+ ["4-139", 56, 54],
772
+ // Vegiemon
773
+ ["4-140", 60, 50],
774
+ // Velgrmon
775
+ ["4-141", 60, 50],
776
+ // Whamon
777
+ ["4-142", 63, 57],
778
+ // Witchmon
779
+ ["4-143", 63, 57],
780
+ // Wizardmon
781
+ ["4-144", 63, 57],
782
+ // Wizardmon X
783
+ ["4-145", 56, 54],
784
+ // Woodmon
785
+ ["4-146", 60, 50],
786
+ // ZubaEagermon
787
+ ["4-147", 60, 50],
788
+ // Bulkmon
789
+ ["4-148", 60, 50],
790
+ // Fugamon
791
+ ["4-149", 60, 50],
792
+ // Hyogamon
793
+ ["4-150", 60, 50],
794
+ // Piddomon
795
+ ["4-151", 60, 50],
796
+ // Rhinomon
797
+ ["4-152", 60, 50],
798
+ // Saberdramon
799
+ ["5-001", 70, 55],
800
+ // AeroVeedramon
801
+ ["5-002", 70, 55],
802
+ // Aldamon
803
+ ["5-003", 78, 47],
804
+ // Andromon
805
+ ["5-004", 70, 55],
806
+ // Angewomon
807
+ ["5-005", 70, 55],
808
+ // Angewomon X
809
+ ["5-006", 70, 55],
810
+ // Antylamon
811
+ ["5-007", 70, 55],
812
+ // Argomon
813
+ ["5-008", 70, 55],
814
+ // Arukenimon
815
+ ["5-009", 70, 55],
816
+ // Astamon
817
+ ["5-010", 70, 55],
818
+ // Asuramon
819
+ ["5-011", 70, 55],
820
+ // Baalmon
821
+ ["5-012", 70, 55],
822
+ // Beowolfmon
823
+ ["5-013", 70, 55],
824
+ // BigMamemon
825
+ ["5-014", 66, 59],
826
+ // Blossomon
827
+ ["5-015", 70, 55],
828
+ // Bulbmon
829
+ ["5-016", 82, 43],
830
+ // BurningGreymon
831
+ ["5-017", 70, 55],
832
+ // CannonBeemon
833
+ ["5-018", 70, 55],
834
+ // Cerberusmon
835
+ ["5-019", 70, 55],
836
+ // Cerberusmon X
837
+ ["5-020", 70, 55],
838
+ // Cherrymon
839
+ ["5-021", 70, 55],
840
+ // Cho-Hakkaimon
841
+ ["5-022", 70, 55],
842
+ // Crescemon
843
+ ["5-023", 70, 55],
844
+ // Crowmon
845
+ ["5-024", 70, 55],
846
+ // CrysPaledramon
847
+ ["5-025", 78, 47],
848
+ // Cyberdramon
849
+ ["5-026", 78, 47],
850
+ // Cyberdramon X
851
+ ["5-027", 70, 55],
852
+ // DarkKnightmon
853
+ ["5-028", 70, 55],
854
+ // Datamon
855
+ ["5-029", 70, 55],
856
+ // Deramon
857
+ ["5-030", 70, 55],
858
+ // Digitamamon
859
+ ["5-031", 82, 43],
860
+ // Dinobeemon
861
+ ["5-032", 70, 55],
862
+ // Divermon
863
+ ["5-033", 70, 55],
864
+ // DoneDevimon
865
+ ["5-034", 82, 43],
866
+ // DoruGreymon
867
+ ["5-035", 70, 55],
868
+ // Dragomon
869
+ ["5-036", 70, 55],
870
+ // Duramon
871
+ ["5-037", 70, 55],
872
+ // Entmon
873
+ ["5-038", 70, 55],
874
+ // Eosmon
875
+ ["5-039", 70, 55],
876
+ // Etemon
877
+ ["5-040", 82, 43],
878
+ // ExTyrannomon
879
+ ["5-041", 70, 55],
880
+ // Flaremon
881
+ ["5-042", 70, 55],
882
+ // Garbagemon
883
+ ["5-043", 70, 55],
884
+ // Garudamon
885
+ ["5-044", 70, 55],
886
+ // Garudamon X
887
+ ["5-045", 70, 55],
888
+ // Giromon
889
+ ["5-046", 70, 55],
890
+ // Gogmamon
891
+ ["5-047", 70, 55],
892
+ // Grademon
893
+ ["5-048", 70, 55],
894
+ // Groundramon
895
+ ["5-049", 70, 55],
896
+ // Gusokumon
897
+ ["5-050", 70, 55],
898
+ // HippoGryphonmon
899
+ ["5-051", 70, 55],
900
+ // Hisyaryumon
901
+ ["5-052", 70, 55],
902
+ // Jagamon
903
+ ["5-053", 70, 55],
904
+ // JagerLoweemon
905
+ ["5-054", 70, 55],
906
+ // Jazarichmon
907
+ ["5-055", 70, 55],
908
+ // JewelBeemon
909
+ ["5-056", 70, 55],
910
+ // KendoGarurumon
911
+ ["5-057", 70, 55],
912
+ // Kimeramon
913
+ ["5-058", 70, 55],
914
+ // Knightmon
915
+ ["5-059", 70, 55],
916
+ // LadyDevimon
917
+ ["5-060", 70, 55],
918
+ // LadyDevimon X
919
+ ["5-061", 70, 55],
920
+ // Lavogaritamon
921
+ ["5-062", 70, 55],
922
+ // Lilamon
923
+ ["5-063", 70, 55],
924
+ // Lillymon
925
+ ["5-064", 70, 55],
926
+ // Lillymon X
927
+ ["5-065", 70, 55],
928
+ // LoaderLeomon
929
+ ["5-066", 70, 55],
930
+ // Locomon
931
+ ["5-067", 70, 55],
932
+ // Lucemon: Chaos Mode
933
+ ["5-068", 70, 55],
934
+ // MachGaogamon
935
+ ["5-069", 73, 62],
936
+ // MagnaAngemon
937
+ ["5-070", 70, 55],
938
+ // Mamemon
939
+ ["5-071", 70, 55],
940
+ // Mamemon X
941
+ ["5-072", 70, 55],
942
+ // Mametyramon
943
+ ["5-073", 82, 43],
944
+ // Mammothmon
945
+ ["5-074", 82, 43],
946
+ // Mammothmon X
947
+ ["5-075", 70, 55],
948
+ // Manticoremon
949
+ ["5-076", 70, 55],
950
+ // MarineChimairamon
951
+ ["5-077", 70, 55],
952
+ // MarineDevimon
953
+ ["5-078", 70, 55],
954
+ // Maycrackmon
955
+ ["5-079", 70, 55],
956
+ // Maycrackmon: Vicious Mode
957
+ ["5-080", 70, 55],
958
+ // Megadramon
959
+ ["5-081", 70, 55],
960
+ // MegaKabuterimon (Red)
961
+ ["5-082", 70, 55],
962
+ // MegaSeadramon
963
+ ["5-083", 70, 55],
964
+ // MegaSeadramon X
965
+ ["5-084", 70, 55],
966
+ // Mephistomon X
967
+ ["5-085", 70, 55],
968
+ // Mermaimon
969
+ ["5-086", 78, 47],
970
+ // MetalGreymon
971
+ ["5-087", 78, 47],
972
+ // MetalGreymon (Vaccine)
973
+ ["5-088", 78, 47],
974
+ // MetalGreymon (Virus)
975
+ ["5-089", 78, 47],
976
+ // MetalGreymon (Virus) X
977
+ ["5-090", 78, 47],
978
+ // MetalGreymon X
979
+ ["5-091", 78, 47],
980
+ // MetalMamemon
981
+ ["5-092", 78, 47],
982
+ // MetalPhantomon
983
+ ["5-093", 78, 47],
984
+ // MetalTyrannomon
985
+ ["5-094", 78, 47],
986
+ // MetalTyrannomon X
987
+ ["5-095", 70, 55],
988
+ // Monzaemon
989
+ ["5-096", 70, 55],
990
+ // Monzaemon X
991
+ ["5-097", 70, 55],
992
+ // Mummymon
993
+ ["5-098", 70, 55],
994
+ // Myotismon
995
+ ["5-099", 70, 55],
996
+ // Myotismon X
997
+ ["5-100", 70, 55],
998
+ // NeoDevimon
999
+ ["5-101", 70, 55],
1000
+ // Okuwamon
1001
+ ["5-102", 70, 55],
1002
+ // Okuwamon X
1003
+ ["5-103", 70, 55],
1004
+ // OmniShoutmon X
1005
+ ["5-104", 70, 55],
1006
+ // Orochimon
1007
+ ["5-105", 70, 55],
1008
+ // Paildramon
1009
+ ["5-106", 70, 55],
1010
+ // Parrotmon
1011
+ ["5-107", 70, 55],
1012
+ // Phantomon
1013
+ ["5-108", 70, 55],
1014
+ // Piranimon
1015
+ ["5-109", 70, 55],
1016
+ // Piximon
1017
+ ["5-110", 70, 55],
1018
+ // Pumpkinmon
1019
+ ["5-111", 70, 55],
1020
+ // RaijiLudomon
1021
+ ["5-112", 70, 55],
1022
+ // Rapidmon
1023
+ ["5-113", 70, 55],
1024
+ // Rebellimon
1025
+ ["5-114", 70, 55],
1026
+ // Rhihimon
1027
+ ["5-115", 82, 43],
1028
+ // RizeGreymon
1029
+ ["5-116", 82, 43],
1030
+ // RizeGreymon X
1031
+ ["5-117", 70, 55],
1032
+ // SaviorHuckmon
1033
+ ["5-118", 70, 55],
1034
+ // Scorpiomon
1035
+ ["5-119", 70, 55],
1036
+ // Scorpiomon X
1037
+ ["5-120", 70, 55],
1038
+ // Shakkoumon
1039
+ ["5-121", 70, 55],
1040
+ // ShogunGekomon
1041
+ ["5-122", 70, 55],
1042
+ // Shoutmon X5
1043
+ ["5-123", 70, 55],
1044
+ // Silphymon
1045
+ ["5-124", 70, 55],
1046
+ // Sirenmon
1047
+ ["5-125", 70, 55],
1048
+ // SkullBaluchimon
1049
+ ["5-126", 82, 43],
1050
+ // SkullGreymon
1051
+ ["5-127", 70, 55],
1052
+ // SkullMeramon
1053
+ ["5-128", 70, 55],
1054
+ // Stefilmon
1055
+ ["5-129", 70, 55],
1056
+ // Tekkamon
1057
+ ["5-130", 70, 55],
1058
+ // Toropiamon
1059
+ ["5-131", 82, 43],
1060
+ // Triceramon
1061
+ ["5-132", 82, 43],
1062
+ // Triceramon X
1063
+ ["5-133", 70, 55],
1064
+ // Vademon
1065
+ ["5-134", 70, 55],
1066
+ // Velgrmon
1067
+ ["5-135", 70, 55],
1068
+ // WarGrowlmon
1069
+ ["5-136", 70, 55],
1070
+ // WarGrowlmon X
1071
+ ["5-137", 70, 55],
1072
+ // WaruMonzaemon
1073
+ ["5-138", 70, 55],
1074
+ // WaruSeadramon
1075
+ ["5-139", 70, 55],
1076
+ // WereGarurumon
1077
+ ["5-140", 70, 55],
1078
+ // WereGarurumon X
1079
+ ["5-141", 70, 55],
1080
+ // Whamon
1081
+ ["5-142", 70, 55],
1082
+ // Wingdramon
1083
+ ["5-143", 70, 55],
1084
+ // Zudomon
1085
+ ["5-144", 70, 55],
1086
+ // Boutmon
1087
+ ["5-145", 70, 55],
1088
+ // DarkSuperStarmon
1089
+ ["5-146", 70, 55],
1090
+ // Doruguremon
1091
+ ["5-147", 70, 55],
1092
+ // Pandamon
1093
+ ["5-148", 70, 55],
1094
+ // SkullScorpiomon
1095
+ ["5-149", 70, 55],
1096
+ // SuperStarmon
1097
+ ["6-001", 80, 60],
1098
+ // Aegisdramon
1099
+ ["6-002", 80, 60],
1100
+ // Alphamon
1101
+ ["6-003", 80, 60],
1102
+ // AncientBeetlemon
1103
+ ["6-004", 80, 60],
1104
+ // AncientGarurumon
1105
+ ["6-005", 92, 48],
1106
+ // AncientGreymon
1107
+ ["6-006", 80, 60],
1108
+ // AncientKazemon
1109
+ ["6-007", 80, 60],
1110
+ // AncientMegatheriummon
1111
+ ["6-008", 80, 60],
1112
+ // AncientMermaimon
1113
+ ["6-009", 80, 60],
1114
+ // AncientSphinxmon
1115
+ ["6-010", 80, 60],
1116
+ // AncientTroymon
1117
+ ["6-011", 80, 60],
1118
+ // AncientVolcanomon
1119
+ ["6-012", 80, 60],
1120
+ // AncientWisemon
1121
+ ["6-013", 80, 60],
1122
+ // Anubismon
1123
+ ["6-014", 80, 60],
1124
+ // Apocalymon
1125
+ ["6-015", 80, 60],
1126
+ // Apollomon
1127
+ ["6-016", 80, 60],
1128
+ // Argomon
1129
+ ["6-017", 80, 60],
1130
+ // Armageddemon
1131
+ ["6-018", 80, 60],
1132
+ // Azulongmon
1133
+ ["6-019", 80, 60],
1134
+ // Bagramon
1135
+ ["6-020", 80, 60],
1136
+ // Baihumon
1137
+ ["6-021", 80, 60],
1138
+ // BanchoLeomon
1139
+ ["6-022", 80, 60],
1140
+ // BanchoMamemon
1141
+ ["6-023", 80, 60],
1142
+ // Barbamon
1143
+ ["6-024", 80, 60],
1144
+ // BeelStarmon X
1145
+ ["6-025", 80, 60],
1146
+ // Beelzemon
1147
+ ["6-026", 80, 60],
1148
+ // Belphemon: Rage Mode
1149
+ ["6-027", 92, 48],
1150
+ // BlackWarGreymon X
1151
+ ["6-028", 92, 48],
1152
+ // BlitzGreymon
1153
+ ["6-029", 80, 60],
1154
+ // Boltmon
1155
+ ["6-030", 80, 60],
1156
+ // Breakdramon
1157
+ ["6-031", 80, 60],
1158
+ // BryweLudramon
1159
+ ["6-032", 80, 60],
1160
+ // Chaosdramon X
1161
+ ["6-033", 80, 60],
1162
+ // Cherubimon (Virtue)
1163
+ ["6-034", 80, 60],
1164
+ // Cherubimon (Virtue) X
1165
+ ["6-035", 80, 60],
1166
+ // Cherubimon (Vice) X
1167
+ ["6-036", 80, 60],
1168
+ // Craniamon
1169
+ ["6-037", 80, 60],
1170
+ // Creepymon
1171
+ ["6-038", 80, 60],
1172
+ // CresGarurumon
1173
+ ["6-039", 80, 60],
1174
+ // Darkdramon
1175
+ ["6-040", 80, 60],
1176
+ // DarkKnightmon X
1177
+ ["6-041", 80, 60],
1178
+ // Dianamon
1179
+ ["6-042", 92, 48],
1180
+ // Dinorexmon
1181
+ ["6-043", 92, 48],
1182
+ // Dinotigermon
1183
+ ["6-044", 80, 60],
1184
+ // Durandamon
1185
+ ["6-045", 80, 60],
1186
+ // Dynasmon
1187
+ ["6-046", 80, 60],
1188
+ // Ebemon X
1189
+ ["6-047", 80, 60],
1190
+ // Ebonwumon
1191
+ ["6-048", 92, 48],
1192
+ // EmperorGreymon
1193
+ ["6-049", 80, 60],
1194
+ // Eosmon
1195
+ ["6-050", 80, 60],
1196
+ // Fanglongmon
1197
+ ["6-051", 80, 60],
1198
+ // Gaiomon
1199
+ ["6-052", 80, 60],
1200
+ // Gallantmon
1201
+ ["6-053", 80, 60],
1202
+ // Gallantmon X
1203
+ ["6-054", 80, 60],
1204
+ // Gankoomon
1205
+ ["6-055", 80, 60],
1206
+ // Ghoulmon
1207
+ ["6-056", 92, 48],
1208
+ // GigaSeadramon
1209
+ ["6-057", 80, 60],
1210
+ // Goldramon
1211
+ ["6-058", 80, 60],
1212
+ // Goldramon X
1213
+ ["6-059", 80, 60],
1214
+ // GrandisKuwagamon
1215
+ ["6-060", 80, 60],
1216
+ // GranDracmon
1217
+ ["6-061", 80, 60],
1218
+ // GranKuwagamon
1219
+ ["6-062", 80, 60],
1220
+ // GroundLocomon
1221
+ ["6-063", 80, 60],
1222
+ // Gryphonmon
1223
+ ["6-064", 80, 60],
1224
+ // Gundramon
1225
+ ["6-065", 80, 60],
1226
+ // HeavyLeomon
1227
+ ["6-066", 80, 60],
1228
+ // HerculesKabuterimon
1229
+ ["6-067", 80, 60],
1230
+ // Hexeblaumon
1231
+ ["6-068", 88, 52],
1232
+ // HiAndromon
1233
+ ["6-069", 80, 60],
1234
+ // Jesmon
1235
+ ["6-070", 80, 60],
1236
+ // Justimon X
1237
+ ["6-071", 80, 60],
1238
+ // Justimon: Blitz Arm
1239
+ ["6-072", 80, 60],
1240
+ // Kentaurosmon
1241
+ ["6-073", 80, 60],
1242
+ // KingEtemon
1243
+ ["6-074", 80, 60],
1244
+ // Leopardmon
1245
+ ["6-075", 80, 60],
1246
+ // Leviamon
1247
+ ["6-076", 80, 60],
1248
+ // Lilithmon
1249
+ ["6-077", 80, 60],
1250
+ // LordKnightmon
1251
+ ["6-078", 80, 60],
1252
+ // Lotosmon
1253
+ ["6-079", 80, 60],
1254
+ // Lucemon: Satan Mode
1255
+ ["6-080", 88, 52],
1256
+ // Machinedramon
1257
+ ["6-081", 83, 67],
1258
+ // Magnadramon
1259
+ ["6-082", 83, 67],
1260
+ // Magnadramon X
1261
+ ["6-083", 83, 67],
1262
+ // MagnaGarurumon
1263
+ ["6-084", 83, 67],
1264
+ // Magnamon
1265
+ ["6-085", 80, 60],
1266
+ // MaloMyotismon
1267
+ ["6-086", 83, 67],
1268
+ // MarineAngemon
1269
+ ["6-087", 80, 60],
1270
+ // MegaGargomon
1271
+ ["6-088", 80, 60],
1272
+ // Megidramon
1273
+ ["6-089", 80, 60],
1274
+ // Megidramon X
1275
+ ["6-090", 88, 52],
1276
+ // MetalEtemon
1277
+ ["6-091", 88, 78],
1278
+ // MetalGarurumon
1279
+ ["6-092", 88, 52],
1280
+ // MetalGarurumon X
1281
+ ["6-093", 88, 52],
1282
+ // Metallicdramon
1283
+ ["6-094", 88, 52],
1284
+ // MetalPiranimon
1285
+ ["6-095", 88, 52],
1286
+ // MetalSeadramon
1287
+ ["6-096", 80, 60],
1288
+ // MirageGaogamon
1289
+ ["6-097", 80, 60],
1290
+ // Murmukusmon
1291
+ ["6-098", 80, 60],
1292
+ // Nidhoggmon
1293
+ ["6-099", 80, 60],
1294
+ // NoblePumpkinmon
1295
+ ["6-100", 83, 67],
1296
+ // Ophanimon
1297
+ ["6-101", 83, 67],
1298
+ // Ophanimon X
1299
+ ["6-102", 83, 67],
1300
+ // Ophanimon: Falldown Mode X
1301
+ ["6-103", 80, 60],
1302
+ // Ornismon
1303
+ ["6-104", 80, 60],
1304
+ // Ouryumon
1305
+ ["6-105", 80, 60],
1306
+ // Phoenixmon
1307
+ ["6-106", 80, 60],
1308
+ // Phoenixmon X
1309
+ ["6-107", 80, 60],
1310
+ // Piedmon
1311
+ ["6-108", 80, 60],
1312
+ // PlatinumNumemon
1313
+ ["6-109", 80, 60],
1314
+ // Plesiomon
1315
+ ["6-110", 80, 60],
1316
+ // Plesiomon X
1317
+ ["6-111", 80, 60],
1318
+ // PrinceMamemon X
1319
+ ["6-112", 80, 60],
1320
+ // Pukumon
1321
+ ["6-113", 80, 60],
1322
+ // Puppetmon
1323
+ ["6-114", 80, 60],
1324
+ // Rafflesimon
1325
+ ["6-115", 80, 60],
1326
+ // Raguelmon
1327
+ ["6-116", 80, 60],
1328
+ // Rapidmon X
1329
+ ["6-117", 80, 60],
1330
+ // Rasenmon
1331
+ ["6-118", 80, 60],
1332
+ // Rasenmon: Fury Mode
1333
+ ["6-119", 80, 60],
1334
+ // Rasielmon
1335
+ ["6-120", 80, 60],
1336
+ // Ravemon
1337
+ ["6-121", 80, 60],
1338
+ // Regalecusmon
1339
+ ["6-122", 80, 60],
1340
+ // Rhihimon
1341
+ ["6-123", 76, 64],
1342
+ // Rosemon
1343
+ ["6-124", 76, 64],
1344
+ // Rosemon X
1345
+ ["6-125", 92, 48],
1346
+ // RustTyrannomon
1347
+ ["6-126", 80, 60],
1348
+ // SaberLeomon
1349
+ ["6-127", 80, 60],
1350
+ // Sakuyamon X
1351
+ ["6-128", 83, 67],
1352
+ // Seraphimon
1353
+ ["6-129", 92, 48],
1354
+ // ShineGreymon
1355
+ ["6-130", 92, 48],
1356
+ // SkullMammothmon
1357
+ ["6-131", 92, 48],
1358
+ // SkullMammothmon X
1359
+ ["6-132", 83, 67],
1360
+ // SlashAngemon
1361
+ ["6-133", 80, 60],
1362
+ // Slayerdramon
1363
+ ["6-134", 80, 60],
1364
+ // Susanomon
1365
+ ["6-135", 80, 60],
1366
+ // TigerVespamon
1367
+ ["6-136", 80, 60],
1368
+ // Titamon
1369
+ ["6-137", 80, 60],
1370
+ // UlforceVeedramon
1371
+ ["6-138", 80, 60],
1372
+ // UltimateBrachiomon
1373
+ ["6-139", 80, 60],
1374
+ // Valkyrimon
1375
+ ["6-140", 80, 60],
1376
+ // Varodurumon
1377
+ ["6-141", 80, 60],
1378
+ // VenomMyotismon
1379
+ ["6-142", 80, 60],
1380
+ // Volcanicdramon
1381
+ ["6-143", 94, 62],
1382
+ // WarGreymon
1383
+ ["6-144", 92, 48],
1384
+ // WarGreymon X
1385
+ ["6-145", 80, 60],
1386
+ // Zhuqiaomon
1387
+ ["6-146", 80, 60],
1388
+ // Vikemon
1389
+ ["6-147", 80, 60],
1390
+ // ShinMonzaemon
1391
+ ["6-148", 80, 60],
1392
+ // Kazuchimon
1393
+ ["6-149", 80, 60],
1394
+ // BanchoLillymon
1395
+ ["6-150", 80, 60],
1396
+ // Dorugoramon
1397
+ ["7-001", 90, 65],
1398
+ // Alphamon: Ouryuken
1399
+ ["7-002", 90, 65],
1400
+ // Armageddemon
1401
+ ["7-003", 90, 65],
1402
+ // Barbamon X
1403
+ ["7-004", 90, 65],
1404
+ // Beelzemon X
1405
+ ["7-005", 90, 65],
1406
+ // Beelzemon: Blast Mode
1407
+ ["7-006", 90, 65],
1408
+ // Belphemon X
1409
+ ["7-007", 90, 65],
1410
+ // Boltboutamon
1411
+ ["7-008", 90, 65],
1412
+ // Chaosmon
1413
+ ["7-009", 90, 65],
1414
+ // Craniamon X
1415
+ ["7-010", 90, 65],
1416
+ // Creepymon X
1417
+ ["7-011", 90, 65],
1418
+ // DarknessBagramon
1419
+ ["7-012", 90, 65],
1420
+ // Diaboromon X
1421
+ ["7-013", 90, 65],
1422
+ // Dynasmon X
1423
+ ["7-014", 90, 65],
1424
+ // Examon
1425
+ ["7-015", 90, 65],
1426
+ // Examon X
1427
+ ["7-016", 90, 65],
1428
+ // Gallantmon X
1429
+ ["7-017", 90, 65],
1430
+ // Gankoomon X
1431
+ ["7-018", 90, 65],
1432
+ // GraceNovamon
1433
+ ["7-019", 90, 65],
1434
+ // Imperialdramon: Fighter Mode
1435
+ ["7-020", 90, 65],
1436
+ // Imperialdramon: Paladin Mode
1437
+ ["7-021", 90, 65],
1438
+ // Jesmon X
1439
+ ["7-022", 90, 65],
1440
+ // Kentaurosmon X
1441
+ ["7-023", 90, 65],
1442
+ // Leopardmon X
1443
+ ["7-024", 90, 65],
1444
+ // Leviamon X
1445
+ ["7-025", 90, 65],
1446
+ // Lilithmon X
1447
+ ["7-026", 90, 65],
1448
+ // LordKnightmon X
1449
+ ["7-027", 90, 65],
1450
+ // Lucemon X
1451
+ ["7-028", 93, 72],
1452
+ // Magnamon X
1453
+ ["7-029", 90, 65],
1454
+ // Mastemon
1455
+ ["7-030", 90, 65],
1456
+ // Minervamon X
1457
+ ["7-031", 90, 65],
1458
+ // Ogudomon
1459
+ ["7-032", 90, 65],
1460
+ // Omnimon
1461
+ ["7-033", 90, 65],
1462
+ // Omnimon Alter-S
1463
+ ["7-034", 90, 65],
1464
+ // Omnimon X
1465
+ ["7-035", 90, 65],
1466
+ // Ordinemon
1467
+ ["7-036", 90, 65],
1468
+ // Rafflesimon
1469
+ ["7-037", 90, 65],
1470
+ // RagnaLoardmon
1471
+ ["7-038", 90, 65],
1472
+ // Rasenmon
1473
+ ["7-039", 100, 53],
1474
+ // RustTyrannomon
1475
+ ["7-040", 90, 65],
1476
+ // UlforceVeedramon X
1477
+ ["7-041", 90, 65],
1478
+ // Agumon (Bond of Bravery)
1479
+ ["7-042", 90, 65],
1480
+ // Gabumon (Bond of Friendship)
1481
+ ["7-043", 90, 65],
1482
+ // Jesmon GX
1483
+ ["7-044", 90, 65],
1484
+ // Ogudomon X
1485
+ ["7-045", 90, 65]
1486
+ // Chaosdramon
1487
+ ].map(([id, strength, evasion]) => [id, validateCombatStats({ strength, evasion })])
1488
+ );
1489
+
117
1490
  // ../digital-pet-core/src/data/digimon-data.ts
118
1491
  var DIGIMON_DATA = [
119
1492
  {
@@ -6222,12 +7595,6 @@ var DIGIMON_DATA = [
6222
7595
  }
6223
7596
  ];
6224
7597
 
6225
- // ../digital-pet-core/src/domain/stage.ts
6226
- var DIGIMON_STAGES = [0, 1, 2, 3, 4, 5, 6, 7];
6227
- var isDigimonStage = (value) => {
6228
- return DIGIMON_STAGES.some((stage) => stage === value);
6229
- };
6230
-
6231
7598
  // ../digital-pet-core/src/data/catalog.ts
6232
7599
  var parseNode = (input) => {
6233
7600
  if (!isDigimonStage(input.stage)) throw new Error(`Invalid stage ${input.stage} for ${input.id}`);
@@ -6238,7 +7605,8 @@ var parseNode = (input) => {
6238
7605
  nextEvolutions: Object.freeze([...input.next_evolutions]),
6239
7606
  sprite: input.sprite,
6240
7607
  stage: input.stage,
6241
- url: input.url
7608
+ url: input.url,
7609
+ combatStats: COMBAT_STATS.get(input.id) ?? NEUTRAL_COMBAT_STATS
6242
7610
  });
6243
7611
  };
6244
7612
  var parseDigimonCatalog = (input) => {
@@ -6258,189 +7626,120 @@ var parseDigimonCatalog = (input) => {
6258
7626
  var DIGIMON_CATALOG = parseDigimonCatalog(DIGIMON_DATA);
6259
7627
  var loadDigimonCatalog = async () => DIGIMON_CATALOG;
6260
7628
 
6261
- // ../digital-pet-core/src/domain/evolution-battle.ts
6262
- var pickEvolutionTarget = (current, selector) => {
6263
- if (current.nextEvolutions.length === 0) {
6264
- throw new Error("Evolution target selection failed: partner has no evolution options");
6265
- }
6266
- const selection = selector();
6267
- if (!Number.isFinite(selection) || selection < 0 || selection >= 1) {
6268
- throw new Error(`Evolution selector must return a finite number in [0, 1), received ${selection}`);
6269
- }
6270
- const targetId = current.nextEvolutions[Math.floor(selection * current.nextEvolutions.length)];
6271
- if (targetId === void 0) throw new Error("Evolution target selection failed");
6272
- return targetId;
6273
- };
6274
- var pickRandomSameStageOpponent = (current, catalogNodes, selector) => {
6275
- const candidates = catalogNodes.filter((node) => node.stage === current.stage && node.id !== current.id);
6276
- if (candidates.length === 0) {
6277
- return current.id;
6278
- }
6279
- const selection = selector();
6280
- if (!Number.isFinite(selection) || selection < 0 || selection >= 1) {
6281
- throw new Error(`Evolution selector must return a finite number in [0, 1), received ${selection}`);
7629
+ // ../digital-pet-core/src/application/use-cases/freeze-digital-pet.ts
7630
+ var freezeDigitalPet = (control) => control.freeze();
7631
+
7632
+ // src/commands/digital-pet-freeze.ts
7633
+ var runDigitalPetFreezeCommand = async (control, context) => {
7634
+ const outcome = freezeDigitalPet(control);
7635
+ const parts = [
7636
+ {
7637
+ id: context.messageID,
7638
+ sessionID: context.sessionID,
7639
+ messageID: context.messageID,
7640
+ type: "text",
7641
+ text: "Digital Pet frozen."
7642
+ }
7643
+ ];
7644
+ switch (outcome.kind) {
7645
+ case "frozen":
7646
+ return { parts, event: { kind: "frozen" } };
7647
+ case "already_frozen":
7648
+ return { parts };
7649
+ default: {
7650
+ const unexpectedOutcome = outcome;
7651
+ return unexpectedOutcome;
7652
+ }
6282
7653
  }
6283
- const opponent = candidates[Math.floor(selection * candidates.length)];
6284
- if (opponent === void 0) throw new Error("Same-stage opponent selection failed");
6285
- return opponent.id;
6286
7654
  };
6287
7655
 
6288
- // ../digital-pet-core/src/domain/evolution.ts
6289
- var STAGE_GAUGE_THRESHOLDS = Object.freeze({
6290
- 0: 5e6,
6291
- 1: 1e7,
6292
- 2: 2e7,
6293
- 3: 4e7,
6294
- 4: 75e6,
6295
- 5: 125e6,
6296
- 6: 2e8,
6297
- 7: 3e8
7656
+ // ../digital-pet-core/src/application/use-cases/set-digital-pet-cheat-node.ts
7657
+ var setDigitalPetCheatNode = (control, validatedNodeId) => control.setCheatNode(validatedNodeId);
7658
+
7659
+ // src/commands/digital-pet-set.ts
7660
+ var textPart = (context, text) => ({
7661
+ id: context.messageID,
7662
+ sessionID: context.sessionID,
7663
+ messageID: context.messageID,
7664
+ type: "text",
7665
+ text
6298
7666
  });
6299
- var isRecord = (value) => {
6300
- return typeof value === "object" && value !== null;
7667
+ var runDigitalPetSetCommand = async (control, context, loadCatalog) => {
7668
+ if (context.arguments.includes("\n")) return { parts: [textPart(context, "Usage: /digital-pet-set <id>.")] };
7669
+ const tokens = context.arguments.trim().split(/\s+/);
7670
+ if (context.arguments.trim() === "" || tokens.length !== 1)
7671
+ return { parts: [textPart(context, "Usage: /digital-pet-set <id>.")] };
7672
+ const requestedId = tokens[0];
7673
+ if (requestedId === void 0) return { parts: [textPart(context, "Usage: /digital-pet-set <id>.")] };
7674
+ const node = (await loadCatalog()).byId.get(requestedId);
7675
+ if (node === void 0) return { parts: [textPart(context, `Unknown Digimon ID: ${requestedId}.`)] };
7676
+ const outcome = setDigitalPetCheatNode(control, node.id);
7677
+ const parts = [textPart(context, `Digital Pet set to ${node.nameEn} (${node.id}).`)];
7678
+ switch (outcome.kind) {
7679
+ case "set":
7680
+ return { parts, event: { kind: "set", nodeId: node.id } };
7681
+ case "already_set":
7682
+ return { parts };
7683
+ default: {
7684
+ const unexpectedOutcome = outcome;
7685
+ return unexpectedOutcome;
7686
+ }
7687
+ }
6301
7688
  };
6302
- var isStageThresholds = (thresholds) => {
6303
- if (!isRecord(thresholds) || !Object.isFrozen(thresholds)) return false;
6304
- return DIGIMON_STAGES.every((stage) => {
6305
- const threshold = thresholds[stage];
6306
- return typeof threshold === "number" && Number.isFinite(threshold) && threshold > 0;
7689
+
7690
+ // ../digital-pet-core/src/application/use-cases/spawn-partner.ts
7691
+ var spawnPartner = (lifecycle, createdAt) => {
7692
+ const partner = lifecycle.spawnPartner({
7693
+ currentNodeId: "0-001",
7694
+ gauge: 0,
7695
+ isTerminal: false,
7696
+ createdAt
6307
7697
  });
7698
+ return { generation: partner.generation };
6308
7699
  };
6309
- var hasPendingBattle = (state) => state.pendingEvolutionTargetId != null && state.battleOpponentNodeId != null;
6310
- var applyTokenProgress = (state, tokenDelta, selector, digimonById, catalogNodes, thresholds) => {
6311
- if (!isStageThresholds(thresholds)) {
6312
- throw new Error("Evolution thresholds must be a complete frozen policy of positive finite numbers");
6313
- }
6314
- if (state.isTerminal) return state;
6315
- if (hasPendingBattle(state)) return state;
6316
- const threshold = thresholds[state.current.stage];
6317
- const gauge = state.gauge + tokenDelta;
6318
- if (gauge < threshold) return { ...state, gauge };
6319
- if (state.current.nextEvolutions.length === 0) {
6320
- return { ...state, gauge: 0, isTerminal: true, pendingEvolutionTargetId: null, battleOpponentNodeId: null };
6321
- }
6322
- const pendingEvolutionTargetId = pickEvolutionTarget(state.current, selector);
6323
- const target = digimonById.get(pendingEvolutionTargetId);
6324
- if (target === void 0) {
6325
- throw new Error(`Evolution target ${pendingEvolutionTargetId} is missing from the catalog`);
6326
- }
6327
- if (state.current.stage === 0) {
6328
- return {
6329
- current: target,
6330
- gauge: 0,
6331
- isTerminal: target.nextEvolutions.length === 0,
6332
- pendingEvolutionTargetId: null,
6333
- battleOpponentNodeId: null
6334
- };
6335
- }
6336
- const battleOpponentNodeId = pickRandomSameStageOpponent(state.current, catalogNodes, selector);
6337
- if (digimonById.get(battleOpponentNodeId) === void 0) {
6338
- throw new Error(`Battle opponent ${battleOpponentNodeId} is missing from the catalog`);
6339
- }
7700
+
7701
+ // src/commands/digital-pet-spawn.ts
7702
+ var runDigitalPetSpawnCommand = async (lifecycle, context) => {
7703
+ const partner = spawnPartner(lifecycle, context.createdAt);
6340
7704
  return {
6341
- current: state.current,
6342
- gauge: threshold,
6343
- isTerminal: false,
6344
- pendingEvolutionTargetId,
6345
- battleOpponentNodeId
7705
+ parts: [
7706
+ {
7707
+ id: context.messageID,
7708
+ sessionID: context.sessionID,
7709
+ messageID: context.messageID,
7710
+ type: "text",
7711
+ text: `Spawned Generation ${partner.generation}.`
7712
+ }
7713
+ ],
7714
+ event: { kind: "spawned", nodeId: "0-001", generation: partner.generation }
6346
7715
  };
6347
7716
  };
6348
7717
 
6349
- // ../digital-pet-core/src/application/use-cases/record-usage.ts
6350
- var recordUsage = ({
6351
- usage,
6352
- ledger,
6353
- digimonById,
6354
- catalogNodes,
6355
- selector,
6356
- thresholds
6357
- }) => {
6358
- let evolution;
6359
- let evolutionBattlePending;
6360
- const outcome = ledger.applyUsageReceipt(usage, (partner) => {
6361
- const current = digimonById.get(partner.currentNodeId);
6362
- if (current === void 0)
6363
- throw new Error(`Persisted partner node ${partner.currentNodeId} is missing from the catalog`);
6364
- const hadPendingBattle = partner.pendingEvolutionTargetId != null && partner.battleOpponentNodeId != null;
6365
- const next = applyTokenProgress(
6366
- {
6367
- current,
6368
- gauge: partner.gauge,
6369
- isTerminal: partner.isTerminal,
6370
- pendingEvolutionTargetId: partner.pendingEvolutionTargetId,
6371
- battleOpponentNodeId: partner.battleOpponentNodeId
6372
- },
6373
- usage.tokenDelta,
6374
- selector,
6375
- digimonById,
6376
- catalogNodes,
6377
- thresholds
6378
- );
6379
- if (!hadPendingBattle && next.pendingEvolutionTargetId !== null && next.battleOpponentNodeId !== null && next.current.id === current.id) {
6380
- evolutionBattlePending = {
6381
- opponentNodeId: next.battleOpponentNodeId,
6382
- targetNodeId: next.pendingEvolutionTargetId
6383
- };
6384
- }
6385
- if (next.current.id !== current.id) {
6386
- evolution = { fromNodeId: current.id, toNodeId: next.current.id };
7718
+ // ../digital-pet-core/src/application/use-cases/unfreeze-digital-pet.ts
7719
+ var unfreezeDigitalPet = (control) => control.unfreeze();
7720
+
7721
+ // src/commands/digital-pet-unfreeze.ts
7722
+ var runDigitalPetUnfreezeCommand = async (control, context) => {
7723
+ const outcome = unfreezeDigitalPet(control);
7724
+ const parts = [
7725
+ {
7726
+ id: context.messageID,
7727
+ sessionID: context.sessionID,
7728
+ messageID: context.messageID,
7729
+ type: "text",
7730
+ text: "Digital Pet unfrozen."
6387
7731
  }
6388
- return {
6389
- currentNodeId: next.current.id,
6390
- gauge: next.gauge,
6391
- isTerminal: next.isTerminal,
6392
- pendingEvolutionTargetId: next.pendingEvolutionTargetId,
6393
- battleOpponentNodeId: next.battleOpponentNodeId
6394
- };
6395
- });
7732
+ ];
6396
7733
  switch (outcome.kind) {
6397
- case "applied":
6398
- if (evolutionBattlePending !== void 0) {
6399
- return { kind: "applied", receiptKey: usage.receiptKey, evolutionBattlePending };
6400
- }
6401
- return evolution === void 0 ? { kind: "applied", receiptKey: usage.receiptKey } : { kind: "applied", receiptKey: usage.receiptKey, evolution };
6402
- case "duplicate":
6403
- return { kind: "duplicate", receiptKey: usage.receiptKey };
6404
- case "no_active_partner":
6405
- return { kind: "no_active_partner", receiptKey: usage.receiptKey };
6406
- }
6407
- };
6408
-
6409
- // ../digital-pet-core/src/application/use-cases/reconcile-usage.ts
6410
- var reconcileUsage = ({
6411
- usages,
6412
- ledger,
6413
- digimonById,
6414
- catalogNodes,
6415
- selector,
6416
- thresholds
6417
- }) => {
6418
- const outcomes = [];
6419
- for (const usage of usages) {
6420
- outcomes.push(recordUsage({ usage, ledger, digimonById, catalogNodes, selector, thresholds }));
7734
+ case "unfrozen":
7735
+ return { parts, event: { kind: "unfrozen" } };
7736
+ case "already_unfrozen":
7737
+ return { parts };
7738
+ default: {
7739
+ const unexpectedOutcome = outcome;
7740
+ return unexpectedOutcome;
7741
+ }
6421
7742
  }
6422
- return outcomes;
6423
- };
6424
-
6425
- // src/adapters/opencode/usage-event-mapper.ts
6426
- var isCompletedAssistantMessage = (message) => {
6427
- return message.role === "assistant" && "time" in message && message.time.completed !== void 0;
6428
- };
6429
- var toCompletedUsageFromMessage = (message) => {
6430
- if (!isCompletedAssistantMessage(message)) return null;
6431
- const completedAt = message.time.completed;
6432
- if (completedAt === void 0) return null;
6433
- return {
6434
- receiptKey: `message:${message.id}`,
6435
- eventId: `usage:${message.id}`,
6436
- tokenDelta: message.tokens.input + message.tokens.output + message.tokens.reasoning + message.tokens.cache.read + message.tokens.cache.write,
6437
- cost: Number.isFinite(message.cost) && message.cost > 0 ? message.cost : null,
6438
- createdAt: new Date(completedAt).toISOString()
6439
- };
6440
- };
6441
- var toCompletedUsageFromEvent = (event) => {
6442
- if (event.type !== "message.updated") return null;
6443
- return toCompletedUsageFromMessage(event.properties.info);
6444
7743
  };
6445
7744
 
6446
7745
  // src/adapters/opencode/digital-pet-toast.ts
@@ -6522,6 +7821,27 @@ var createBestEffortDigitalPetToastNotifier = (transport) => {
6522
7821
  );
6523
7822
  };
6524
7823
 
7824
+ // src/adapters/opencode/usage-event-mapper.ts
7825
+ var isCompletedAssistantMessage = (message) => {
7826
+ return message.role === "assistant" && "time" in message && message.time.completed !== void 0;
7827
+ };
7828
+ var toCompletedUsageFromMessage = (message) => {
7829
+ if (!isCompletedAssistantMessage(message)) return null;
7830
+ const completedAt = message.time.completed;
7831
+ if (completedAt === void 0) return null;
7832
+ return {
7833
+ receiptKey: `message:${message.id}`,
7834
+ eventId: `usage:${message.id}`,
7835
+ tokenDelta: message.tokens.input + message.tokens.output + message.tokens.reasoning + message.tokens.cache.read + message.tokens.cache.write,
7836
+ cost: Number.isFinite(message.cost) && message.cost > 0 ? message.cost : null,
7837
+ createdAt: new Date(completedAt).toISOString()
7838
+ };
7839
+ };
7840
+ var toCompletedUsageFromEvent = (event) => {
7841
+ if (event.type !== "message.updated") return null;
7842
+ return toCompletedUsageFromMessage(event.properties.info);
7843
+ };
7844
+
6525
7845
  // src/adapters/opencode/create-server-hooks.ts
6526
7846
  var noOpNotifier = async () => {
6527
7847
  };
@@ -6747,6 +8067,100 @@ var resolveHostDatabasePath = (options = {}) => {
6747
8067
  return join(resolveHostDataDirectory(options), DATABASE_FILE_NAME);
6748
8068
  };
6749
8069
 
8070
+ // ../digital-pet-core/src/adapters/sqlite/sqlite-digital-pet-schema.ts
8071
+ var PARTNER_COLUMNS = `
8072
+ partner_id,
8073
+ generation,
8074
+ current_node_id,
8075
+ gauge,
8076
+ is_terminal,
8077
+ pending_evolution_target_id,
8078
+ battle_opponent_node_id,
8079
+ created_at,
8080
+ retired_at
8081
+ `;
8082
+ var ACTIVE_PARTNER_SELECT = `
8083
+ SELECT
8084
+ ${PARTNER_COLUMNS}
8085
+ FROM partners
8086
+ WHERE retired_at IS NULL
8087
+ LIMIT 1
8088
+ `;
8089
+ var PARTNERS_SELECT = `
8090
+ SELECT
8091
+ ${PARTNER_COLUMNS}
8092
+ FROM partners
8093
+ ORDER BY generation ASC, created_at ASC, partner_id ASC
8094
+ `;
8095
+ var ARCHIVE_PARTNERS_SELECT = `
8096
+ SELECT
8097
+ ${PARTNER_COLUMNS}
8098
+ FROM partners
8099
+ ORDER BY partner_id ASC
8100
+ `;
8101
+ var PARTNER_BY_GENERATION_SELECT = `
8102
+ SELECT
8103
+ ${PARTNER_COLUMNS}
8104
+ FROM partners
8105
+ WHERE generation = ?
8106
+ LIMIT 1
8107
+ `;
8108
+ var PARTNER_EVENTS_SELECT = `
8109
+ SELECT
8110
+ event_id,
8111
+ partner_id,
8112
+ kind,
8113
+ current_node_id,
8114
+ gauge,
8115
+ is_terminal,
8116
+ token_delta,
8117
+ receipt_key,
8118
+ created_at
8119
+ FROM partner_events
8120
+ WHERE partner_id = ?
8121
+ ORDER BY created_at ASC, event_id ASC
8122
+ `;
8123
+ var USAGE_RECEIPTS_SELECT = `
8124
+ SELECT receipt_key, partner_id, event_id, token_delta, cost, created_at
8125
+ FROM usage_receipts
8126
+ ORDER BY created_at ASC, receipt_key ASC
8127
+ `;
8128
+ var toPartner = (row) => {
8129
+ return {
8130
+ partnerId: row.partner_id,
8131
+ generation: row.generation,
8132
+ currentNodeId: row.current_node_id,
8133
+ gauge: row.gauge,
8134
+ isTerminal: row.is_terminal === 1,
8135
+ pendingEvolutionTargetId: row.pending_evolution_target_id,
8136
+ battleOpponentNodeId: row.battle_opponent_node_id,
8137
+ createdAt: row.created_at,
8138
+ retiredAt: row.retired_at
8139
+ };
8140
+ };
8141
+ var toPersistedPartnerEvent = (row) => {
8142
+ return {
8143
+ eventId: row.event_id,
8144
+ partnerId: row.partner_id,
8145
+ kind: row.kind,
8146
+ currentNodeId: row.current_node_id,
8147
+ gauge: row.gauge,
8148
+ isTerminal: row.is_terminal === 1,
8149
+ tokenDelta: row.token_delta,
8150
+ receiptKey: row.receipt_key,
8151
+ createdAt: row.created_at
8152
+ };
8153
+ };
8154
+ var toUsageReceiptRecord = (row) => {
8155
+ return {
8156
+ receiptKey: row.receipt_key,
8157
+ partnerId: row.partner_id,
8158
+ eventId: row.event_id,
8159
+ tokenDelta: row.token_delta,
8160
+ createdAt: row.created_at
8161
+ };
8162
+ };
8163
+
6750
8164
  // ../digital-pet-core/src/adapters/sqlite/sqlite-migrations.ts
6751
8165
  var MIGRATIONS = [
6752
8166
  {
@@ -6883,100 +8297,6 @@ var runMigrations = (database) => {
6883
8297
  });
6884
8298
  };
6885
8299
 
6886
- // ../digital-pet-core/src/adapters/sqlite/sqlite-digital-pet-schema.ts
6887
- var PARTNER_COLUMNS = `
6888
- partner_id,
6889
- generation,
6890
- current_node_id,
6891
- gauge,
6892
- is_terminal,
6893
- pending_evolution_target_id,
6894
- battle_opponent_node_id,
6895
- created_at,
6896
- retired_at
6897
- `;
6898
- var ACTIVE_PARTNER_SELECT = `
6899
- SELECT
6900
- ${PARTNER_COLUMNS}
6901
- FROM partners
6902
- WHERE retired_at IS NULL
6903
- LIMIT 1
6904
- `;
6905
- var PARTNERS_SELECT = `
6906
- SELECT
6907
- ${PARTNER_COLUMNS}
6908
- FROM partners
6909
- ORDER BY generation ASC, created_at ASC, partner_id ASC
6910
- `;
6911
- var ARCHIVE_PARTNERS_SELECT = `
6912
- SELECT
6913
- ${PARTNER_COLUMNS}
6914
- FROM partners
6915
- ORDER BY partner_id ASC
6916
- `;
6917
- var PARTNER_BY_GENERATION_SELECT = `
6918
- SELECT
6919
- ${PARTNER_COLUMNS}
6920
- FROM partners
6921
- WHERE generation = ?
6922
- LIMIT 1
6923
- `;
6924
- var PARTNER_EVENTS_SELECT = `
6925
- SELECT
6926
- event_id,
6927
- partner_id,
6928
- kind,
6929
- current_node_id,
6930
- gauge,
6931
- is_terminal,
6932
- token_delta,
6933
- receipt_key,
6934
- created_at
6935
- FROM partner_events
6936
- WHERE partner_id = ?
6937
- ORDER BY created_at ASC, event_id ASC
6938
- `;
6939
- var USAGE_RECEIPTS_SELECT = `
6940
- SELECT receipt_key, partner_id, event_id, token_delta, cost, created_at
6941
- FROM usage_receipts
6942
- ORDER BY created_at ASC, receipt_key ASC
6943
- `;
6944
- var toPartner = (row) => {
6945
- return {
6946
- partnerId: row.partner_id,
6947
- generation: row.generation,
6948
- currentNodeId: row.current_node_id,
6949
- gauge: row.gauge,
6950
- isTerminal: row.is_terminal === 1,
6951
- pendingEvolutionTargetId: row.pending_evolution_target_id,
6952
- battleOpponentNodeId: row.battle_opponent_node_id,
6953
- createdAt: row.created_at,
6954
- retiredAt: row.retired_at
6955
- };
6956
- };
6957
- var toPersistedPartnerEvent = (row) => {
6958
- return {
6959
- eventId: row.event_id,
6960
- partnerId: row.partner_id,
6961
- kind: row.kind,
6962
- currentNodeId: row.current_node_id,
6963
- gauge: row.gauge,
6964
- isTerminal: row.is_terminal === 1,
6965
- tokenDelta: row.token_delta,
6966
- receiptKey: row.receipt_key,
6967
- createdAt: row.created_at
6968
- };
6969
- };
6970
- var toUsageReceiptRecord = (row) => {
6971
- return {
6972
- receiptKey: row.receipt_key,
6973
- partnerId: row.partner_id,
6974
- eventId: row.event_id,
6975
- tokenDelta: row.token_delta,
6976
- createdAt: row.created_at
6977
- };
6978
- };
6979
-
6980
8300
  // ../digital-pet-core/src/adapters/sqlite/sqlite-digital-pet-write-store.ts
6981
8301
  var createSqliteDigitalPetWriteStore = (options) => {
6982
8302
  const { databasePath, executor, close } = options;
@@ -7218,9 +8538,9 @@ var createSqliteDigitalPetWriteStore = (options) => {
7218
8538
  };
7219
8539
 
7220
8540
  // src/adapters/sqlite/bun-sqlite-driver.ts
8541
+ import { Database } from "bun:sqlite";
7221
8542
  import { mkdirSync } from "node:fs";
7222
8543
  import { dirname } from "node:path";
7223
- import { Database } from "bun:sqlite";
7224
8544
  var createExecutor = (database) => ({
7225
8545
  run(sql, params = []) {
7226
8546
  database.run(sql, Array.from(params));