run-dmcp 0.2.0 → 0.4.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 (59) hide show
  1. package/README.md +51 -13
  2. package/dist/bin/run-dmcp.js +1 -1
  3. package/dist/db/schema.js +170 -18
  4. package/dist/http/server.js +22 -1
  5. package/dist/index.d.ts +34 -2
  6. package/dist/index.js +86 -2
  7. package/dist/mcp-server.d.ts +1 -1
  8. package/dist/mcp-server.js +1 -1
  9. package/dist/register/resources.js +2 -2
  10. package/dist/rpg/index.d.ts +0 -16
  11. package/dist/rpg/index.js +4 -22
  12. package/dist/rpg/server.d.ts +16 -0
  13. package/dist/rpg/server.js +22 -0
  14. package/dist/schemas/index.d.ts +62 -62
  15. package/dist/server.d.ts +1 -0
  16. package/dist/server.js +20 -0
  17. package/dist/timeline/changes.d.ts +8 -0
  18. package/dist/timeline/changes.js +8 -0
  19. package/dist/timeline/export.d.ts +10 -0
  20. package/dist/timeline/export.js +10 -0
  21. package/dist/timeline/irreversible.d.ts +2 -0
  22. package/dist/timeline/replay.d.ts +22 -0
  23. package/dist/timeline/replay.js +22 -0
  24. package/dist/timeline/schema.js +2 -0
  25. package/dist/tools/audio.js +13 -9
  26. package/dist/tools/game.js +33 -1
  27. package/dist/tools/images.js +17 -10
  28. package/dist/tools/resource.d.ts +2 -2
  29. package/dist/tools/time.js +18 -3
  30. package/dist/types/index.d.ts +1 -1
  31. package/dist/utils/media-path.d.ts +52 -0
  32. package/dist/utils/media-path.js +106 -0
  33. package/dist/utils/output-schemas.d.ts +63 -63
  34. package/dist/utils/output-schemas.js +1 -1
  35. package/package.json +14 -2
  36. package/dist/register/abilities.d.ts +0 -2
  37. package/dist/register/abilities.js +0 -165
  38. package/dist/register/combat.d.ts +0 -2
  39. package/dist/register/combat.js +0 -207
  40. package/dist/register/mcp-prompts.d.ts +0 -2
  41. package/dist/register/mcp-prompts.js +0 -684
  42. package/dist/register/quests.d.ts +0 -2
  43. package/dist/register/quests.js +0 -118
  44. package/dist/register/status.d.ts +0 -2
  45. package/dist/register/status.js +0 -130
  46. package/dist/register/tables.d.ts +0 -2
  47. package/dist/register/tables.js +0 -146
  48. package/dist/tools/ability.d.ts +0 -48
  49. package/dist/tools/ability.js +0 -238
  50. package/dist/tools/combat.d.ts +0 -13
  51. package/dist/tools/combat.js +0 -195
  52. package/dist/tools/dice.d.ts +0 -23
  53. package/dist/tools/dice.js +0 -111
  54. package/dist/tools/quest.d.ts +0 -34
  55. package/dist/tools/quest.js +0 -164
  56. package/dist/tools/status.d.ts +0 -36
  57. package/dist/tools/status.js +0 -218
  58. package/dist/tools/tables.d.ts +0 -33
  59. package/dist/tools/tables.js +0 -209
@@ -1,238 +0,0 @@
1
- import { v4 as uuidv4 } from "uuid";
2
- import { getDatabase } from "../db/connection.js";
3
- import { safeJsonParse } from "../utils/json.js";
4
- import { validateGameExists } from "./game.js";
5
- import { getCharacter } from "./character.js";
6
- export function createAbility(params) {
7
- // Validate game exists to prevent orphaned records
8
- validateGameExists(params.gameId);
9
- const db = getDatabase();
10
- const id = uuidv4();
11
- const now = new Date().toISOString();
12
- const ownerId = params.ownerType === "template" ? null : (params.ownerId || null);
13
- db.prepare(`
14
- INSERT INTO abilities (id, game_id, owner_id, owner_type, name, description, category, cost, cooldown, effects, requirements, tags, created_at)
15
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
16
- `).run(id, params.gameId, ownerId, params.ownerType, params.name, params.description || "", params.category || null, JSON.stringify(params.cost || {}), params.cooldown ?? null, JSON.stringify(params.effects || []), JSON.stringify(params.requirements || {}), JSON.stringify(params.tags || []), now);
17
- return {
18
- id,
19
- gameId: params.gameId,
20
- ownerId,
21
- ownerType: params.ownerType,
22
- name: params.name,
23
- description: params.description || "",
24
- category: params.category || null,
25
- cost: params.cost || {},
26
- cooldown: params.cooldown ?? null,
27
- currentCooldown: 0,
28
- effects: params.effects || [],
29
- requirements: params.requirements || {},
30
- tags: params.tags || [],
31
- createdAt: now,
32
- };
33
- }
34
- export function getAbility(id) {
35
- const db = getDatabase();
36
- const row = db.prepare(`SELECT * FROM abilities WHERE id = ?`).get(id);
37
- if (!row)
38
- return null;
39
- return {
40
- id: row.id,
41
- gameId: row.game_id,
42
- ownerId: row.owner_id,
43
- ownerType: row.owner_type,
44
- name: row.name,
45
- description: row.description,
46
- category: row.category,
47
- cost: safeJsonParse(row.cost || "{}", {}),
48
- cooldown: row.cooldown,
49
- currentCooldown: row.current_cooldown,
50
- effects: safeJsonParse(row.effects || "[]", []),
51
- requirements: safeJsonParse(row.requirements || "{}", {}),
52
- tags: safeJsonParse(row.tags || "[]", []),
53
- createdAt: row.created_at,
54
- };
55
- }
56
- export function updateAbility(id, updates) {
57
- const db = getDatabase();
58
- const current = getAbility(id);
59
- if (!current)
60
- return null;
61
- const newName = updates.name ?? current.name;
62
- const newDescription = updates.description ?? current.description;
63
- const newCategory = updates.category !== undefined ? updates.category : current.category;
64
- const newCost = updates.cost ?? current.cost;
65
- const newCooldown = updates.cooldown !== undefined ? updates.cooldown : current.cooldown;
66
- const newEffects = updates.effects ?? current.effects;
67
- const newRequirements = updates.requirements ?? current.requirements;
68
- const newTags = updates.tags ?? current.tags;
69
- db.prepare(`
70
- UPDATE abilities
71
- SET name = ?, description = ?, category = ?, cost = ?, cooldown = ?, effects = ?, requirements = ?, tags = ?
72
- WHERE id = ?
73
- `).run(newName, newDescription, newCategory, JSON.stringify(newCost), newCooldown, JSON.stringify(newEffects), JSON.stringify(newRequirements), JSON.stringify(newTags), id);
74
- return {
75
- ...current,
76
- name: newName,
77
- description: newDescription,
78
- category: newCategory,
79
- cost: newCost,
80
- cooldown: newCooldown,
81
- effects: newEffects,
82
- requirements: newRequirements,
83
- tags: newTags,
84
- };
85
- }
86
- export function deleteAbility(id) {
87
- const db = getDatabase();
88
- const result = db.prepare(`DELETE FROM abilities WHERE id = ?`).run(id);
89
- return result.changes > 0;
90
- }
91
- export function listAbilities(gameId, filter) {
92
- const db = getDatabase();
93
- let query = `SELECT * FROM abilities WHERE game_id = ?`;
94
- const params = [gameId];
95
- if (filter?.ownerType) {
96
- query += ` AND owner_type = ?`;
97
- params.push(filter.ownerType);
98
- }
99
- if (filter?.ownerId) {
100
- query += ` AND owner_id = ?`;
101
- params.push(filter.ownerId);
102
- }
103
- if (filter?.category) {
104
- query += ` AND category = ?`;
105
- params.push(filter.category);
106
- }
107
- query += ` ORDER BY name`;
108
- const rows = db.prepare(query).all(...params);
109
- return rows.map(row => ({
110
- id: row.id,
111
- gameId: row.game_id,
112
- ownerId: row.owner_id,
113
- ownerType: row.owner_type,
114
- name: row.name,
115
- description: row.description,
116
- category: row.category,
117
- cost: safeJsonParse(row.cost || "{}", {}),
118
- cooldown: row.cooldown,
119
- currentCooldown: row.current_cooldown,
120
- effects: safeJsonParse(row.effects || "[]", []),
121
- requirements: safeJsonParse(row.requirements || "{}", {}),
122
- tags: safeJsonParse(row.tags || "[]", []),
123
- createdAt: row.created_at,
124
- }));
125
- }
126
- export function learnAbility(templateId, characterId) {
127
- const db = getDatabase();
128
- const template = getAbility(templateId);
129
- if (!template || template.ownerType !== "template")
130
- return null;
131
- // Validate character exists before creating ability
132
- const character = getCharacter(characterId);
133
- if (!character) {
134
- throw new Error(`Character '${characterId}' not found. Cannot learn ability without a valid character.`);
135
- }
136
- const id = uuidv4();
137
- const now = new Date().toISOString();
138
- db.prepare(`
139
- INSERT INTO abilities (id, game_id, owner_id, owner_type, name, description, category, cost, cooldown, effects, requirements, tags, created_at)
140
- VALUES (?, ?, ?, 'character', ?, ?, ?, ?, ?, ?, ?, ?, ?)
141
- `).run(id, template.gameId, characterId, template.name, template.description, template.category, JSON.stringify(template.cost), template.cooldown, JSON.stringify(template.effects), JSON.stringify(template.requirements), JSON.stringify(template.tags), now);
142
- return {
143
- id,
144
- gameId: template.gameId,
145
- ownerId: characterId,
146
- ownerType: "character",
147
- name: template.name,
148
- description: template.description,
149
- category: template.category,
150
- cost: template.cost,
151
- cooldown: template.cooldown,
152
- currentCooldown: 0,
153
- effects: template.effects,
154
- requirements: template.requirements,
155
- tags: template.tags,
156
- createdAt: now,
157
- };
158
- }
159
- export function useAbility(abilityId, _characterId) {
160
- const db = getDatabase();
161
- const ability = getAbility(abilityId);
162
- if (!ability) {
163
- return { success: false, ability: null, reason: "Ability not found" };
164
- }
165
- // Check cooldown
166
- if (ability.currentCooldown > 0) {
167
- return {
168
- success: false,
169
- ability,
170
- reason: `Ability on cooldown (${ability.currentCooldown} rounds remaining)`,
171
- };
172
- }
173
- // Check costs (would need character resources to validate)
174
- // For now, we just set the cooldown and return success
175
- // In a full implementation, we'd deduct from character resources
176
- if (ability.cooldown && ability.cooldown > 0) {
177
- db.prepare(`UPDATE abilities SET current_cooldown = ? WHERE id = ?`)
178
- .run(ability.cooldown, abilityId);
179
- }
180
- return {
181
- success: true,
182
- ability: { ...ability, currentCooldown: ability.cooldown || 0 },
183
- costsPaid: ability.cost,
184
- };
185
- }
186
- export function tickCooldowns(gameId, amount = 1) {
187
- const db = getDatabase();
188
- // Get all abilities on cooldown
189
- const rows = db.prepare(`
190
- SELECT * FROM abilities WHERE game_id = ? AND current_cooldown > 0
191
- `).all(gameId);
192
- const updated = [];
193
- for (const row of rows) {
194
- const currentCooldown = row.current_cooldown;
195
- const newCooldown = Math.max(0, currentCooldown - amount);
196
- db.prepare(`UPDATE abilities SET current_cooldown = ? WHERE id = ?`)
197
- .run(newCooldown, row.id);
198
- updated.push({
199
- id: row.id,
200
- gameId: row.game_id,
201
- ownerId: row.owner_id,
202
- ownerType: row.owner_type,
203
- name: row.name,
204
- description: row.description,
205
- category: row.category,
206
- cost: safeJsonParse(row.cost || "{}", {}),
207
- cooldown: row.cooldown,
208
- currentCooldown: newCooldown,
209
- effects: safeJsonParse(row.effects || "[]", []),
210
- requirements: safeJsonParse(row.requirements || "{}", {}),
211
- tags: safeJsonParse(row.tags || "[]", []),
212
- createdAt: row.created_at,
213
- });
214
- }
215
- return updated;
216
- }
217
- export function checkRequirements(abilityId, characterId) {
218
- const ability = getAbility(abilityId);
219
- if (!ability)
220
- return null;
221
- const character = getCharacter(characterId);
222
- if (!character)
223
- return null;
224
- const missing = {};
225
- for (const [key, required] of Object.entries(ability.requirements)) {
226
- // Check attributes first, then status
227
- const actual = character.attributes[key]
228
- ?? character.status[key]
229
- ?? 0;
230
- if (actual < required) {
231
- missing[key] = { required, actual };
232
- }
233
- }
234
- return {
235
- meetsRequirements: Object.keys(missing).length === 0,
236
- missing,
237
- };
238
- }
@@ -1,13 +0,0 @@
1
- import type { Combat } from "../types/index.js";
2
- export declare function startCombat(params: {
3
- gameId: string;
4
- locationId: string;
5
- participantIds: string[];
6
- }): Combat;
7
- export declare function getCombat(id: string): Combat | null;
8
- export declare function getActiveCombat(gameId: string): Combat | null;
9
- export declare function nextTurn(combatId: string): Combat | null;
10
- export declare function addCombatLog(combatId: string, entry: string): Combat | null;
11
- export declare function removeParticipant(combatId: string, characterId: string): Combat | null;
12
- export declare function endCombat(combatId: string): Combat | null;
13
- export declare function getCurrentCombatant(combatId: string): string | null;
@@ -1,195 +0,0 @@
1
- import { v4 as uuidv4 } from "uuid";
2
- import { getDatabase } from "../db/connection.js";
3
- import { safeJsonParse } from "../utils/json.js";
4
- import { gameEvents } from "../events/emitter.js";
5
- import { validateGameExists } from "./game.js";
6
- import { getCharacter } from "./character.js";
7
- import { roll } from "./dice.js";
8
- import { getRules } from "./rules.js";
9
- export function startCombat(params) {
10
- // Validate game exists to prevent orphaned records
11
- validateGameExists(params.gameId);
12
- const db = getDatabase();
13
- const id = uuidv4();
14
- const rules = getRules(params.gameId);
15
- // Validate all participants exist before processing (prevents race conditions)
16
- const characters = params.participantIds.map((charId) => {
17
- const character = getCharacter(charId);
18
- if (!character) {
19
- throw new Error(`Character '${charId}' not found. Cannot start combat with missing participants.`);
20
- }
21
- return { charId, character };
22
- });
23
- // Roll initiative for each validated participant
24
- const participants = characters.map(({ charId, character }) => {
25
- let initiative = 0;
26
- if (rules) {
27
- // Simple initiative based on a d20 roll
28
- // The DM can configure this in combat rules
29
- const initRoll = roll("1d20");
30
- // Add dexterity modifier if available
31
- const dexMod = character.attributes.dexterity
32
- ? Math.floor((character.attributes.dexterity - 10) / 2)
33
- : 0;
34
- initiative = initRoll.total + dexMod;
35
- }
36
- else {
37
- initiative = roll("1d20").total;
38
- }
39
- return {
40
- characterId: charId,
41
- initiative,
42
- isActive: true,
43
- };
44
- });
45
- // Sort by initiative (highest first)
46
- participants.sort((a, b) => b.initiative - a.initiative);
47
- const stmt = db.prepare(`
48
- INSERT INTO combats (id, game_id, location_id, participants, current_turn, round, status, log)
49
- VALUES (?, ?, ?, ?, 0, 1, 'active', '[]')
50
- `);
51
- stmt.run(id, params.gameId, params.locationId, JSON.stringify(participants));
52
- const combat = {
53
- id,
54
- gameId: params.gameId,
55
- locationId: params.locationId,
56
- participants,
57
- currentTurn: 0,
58
- round: 1,
59
- status: "active",
60
- log: [],
61
- };
62
- // Emit realtime event
63
- gameEvents.emit({
64
- type: "combat:started",
65
- gameId: params.gameId,
66
- entityId: id,
67
- entityType: "combat",
68
- timestamp: new Date().toISOString(),
69
- data: { participantCount: participants.length },
70
- });
71
- return combat;
72
- }
73
- export function getCombat(id) {
74
- const db = getDatabase();
75
- const stmt = db.prepare(`SELECT * FROM combats WHERE id = ?`);
76
- const row = stmt.get(id);
77
- if (!row)
78
- return null;
79
- return {
80
- id: row.id,
81
- gameId: row.game_id,
82
- locationId: row.location_id,
83
- participants: safeJsonParse(row.participants, []),
84
- currentTurn: row.current_turn,
85
- round: row.round,
86
- status: row.status,
87
- log: safeJsonParse(row.log, []),
88
- };
89
- }
90
- export function getActiveCombat(gameId) {
91
- const db = getDatabase();
92
- const stmt = db.prepare(`SELECT * FROM combats WHERE game_id = ? AND status = 'active' LIMIT 1`);
93
- const row = stmt.get(gameId);
94
- if (!row)
95
- return null;
96
- return {
97
- id: row.id,
98
- gameId: row.game_id,
99
- locationId: row.location_id,
100
- participants: safeJsonParse(row.participants, []),
101
- currentTurn: row.current_turn,
102
- round: row.round,
103
- status: row.status,
104
- log: safeJsonParse(row.log, []),
105
- };
106
- }
107
- export function nextTurn(combatId) {
108
- const combat = getCombat(combatId);
109
- if (!combat || combat.status !== "active")
110
- return null;
111
- const db = getDatabase();
112
- // Find next active participant
113
- let nextTurn = combat.currentTurn;
114
- let round = combat.round;
115
- let attempts = 0;
116
- const maxAttempts = combat.participants.length;
117
- do {
118
- nextTurn = (nextTurn + 1) % combat.participants.length;
119
- if (nextTurn === 0) {
120
- round++;
121
- }
122
- attempts++;
123
- } while (!combat.participants[nextTurn].isActive &&
124
- attempts < maxAttempts);
125
- // If no active participants, end combat
126
- if (attempts >= maxAttempts) {
127
- return endCombat(combatId);
128
- }
129
- const stmt = db.prepare(`
130
- UPDATE combats SET current_turn = ?, round = ? WHERE id = ?
131
- `);
132
- stmt.run(nextTurn, round, combatId);
133
- return {
134
- ...combat,
135
- currentTurn: nextTurn,
136
- round,
137
- };
138
- }
139
- export function addCombatLog(combatId, entry) {
140
- const combat = getCombat(combatId);
141
- if (!combat)
142
- return null;
143
- const db = getDatabase();
144
- const log = [...combat.log, entry];
145
- const stmt = db.prepare(`UPDATE combats SET log = ? WHERE id = ?`);
146
- stmt.run(JSON.stringify(log), combatId);
147
- return {
148
- ...combat,
149
- log,
150
- };
151
- }
152
- export function removeParticipant(combatId, characterId) {
153
- const combat = getCombat(combatId);
154
- if (!combat)
155
- return null;
156
- const db = getDatabase();
157
- const participants = combat.participants.map((p) => p.characterId === characterId ? { ...p, isActive: false } : p);
158
- const stmt = db.prepare(`UPDATE combats SET participants = ? WHERE id = ?`);
159
- stmt.run(JSON.stringify(participants), combatId);
160
- // Check if combat should end
161
- const activeCount = participants.filter((p) => p.isActive).length;
162
- if (activeCount <= 1) {
163
- return endCombat(combatId);
164
- }
165
- return {
166
- ...combat,
167
- participants,
168
- };
169
- }
170
- export function endCombat(combatId) {
171
- const combat = getCombat(combatId);
172
- if (!combat)
173
- return null;
174
- const db = getDatabase();
175
- const stmt = db.prepare(`UPDATE combats SET status = 'resolved' WHERE id = ?`);
176
- stmt.run(combatId);
177
- // Emit realtime event
178
- gameEvents.emit({
179
- type: "combat:ended",
180
- gameId: combat.gameId,
181
- entityId: combatId,
182
- entityType: "combat",
183
- timestamp: new Date().toISOString(),
184
- });
185
- return {
186
- ...combat,
187
- status: "resolved",
188
- };
189
- }
190
- export function getCurrentCombatant(combatId) {
191
- const combat = getCombat(combatId);
192
- if (!combat || combat.status !== "active")
193
- return null;
194
- return combat.participants[combat.currentTurn]?.characterId || null;
195
- }
@@ -1,23 +0,0 @@
1
- import type { DiceRoll, CheckResult } from "../types/index.js";
2
- export declare function roll(expression: string): DiceRoll;
3
- export declare function check(params: {
4
- gameId: string;
5
- characterId: string;
6
- skill?: string;
7
- attribute?: string;
8
- difficulty: number;
9
- bonusModifier?: number;
10
- }): CheckResult;
11
- export declare function contest(params: {
12
- gameId: string;
13
- attackerId: string;
14
- defenderId: string;
15
- attackerSkill?: string;
16
- defenderSkill?: string;
17
- attackerAttribute?: string;
18
- defenderAttribute?: string;
19
- }): {
20
- attackerResult: CheckResult;
21
- defenderResult: CheckResult;
22
- winner: "attacker" | "defender" | "tie";
23
- };
@@ -1,111 +0,0 @@
1
- import { getRules } from "./rules.js";
2
- import { getCharacter } from "./character.js";
3
- // Maximum limits to prevent DoS attacks
4
- const MAX_DICE_COUNT = 100;
5
- const MAX_DICE_SIDES = 1000;
6
- // Parse and roll dice expressions like "2d6+3", "1d20-2", "3d8"
7
- export function roll(expression) {
8
- const regex = /^(\d+)?d(\d+)([+-]\d+)?$/i;
9
- const match = expression.replace(/\s/g, "").match(regex);
10
- if (!match) {
11
- throw new Error(`Invalid dice expression: ${expression}. Expected format: NdX+M (e.g., 2d6+3)`);
12
- }
13
- const count = match[1] ? parseInt(match[1], 10) : 1;
14
- const sides = parseInt(match[2], 10);
15
- const modifier = match[3] ? parseInt(match[3], 10) : 0;
16
- // Validate bounds to prevent DoS
17
- if (count < 1 || count > MAX_DICE_COUNT) {
18
- throw new Error(`Dice count must be between 1 and ${MAX_DICE_COUNT}, got: ${count}`);
19
- }
20
- if (sides < 1 || sides > MAX_DICE_SIDES) {
21
- throw new Error(`Dice sides must be between 1 and ${MAX_DICE_SIDES}, got: ${sides}`);
22
- }
23
- const rolls = [];
24
- for (let i = 0; i < count; i++) {
25
- rolls.push(Math.floor(Math.random() * sides) + 1);
26
- }
27
- const total = rolls.reduce((sum, r) => sum + r, 0) + modifier;
28
- return {
29
- expression,
30
- rolls,
31
- modifier,
32
- total,
33
- };
34
- }
35
- // Perform a skill/ability check using game rules
36
- export function check(params) {
37
- const rules = getRules(params.gameId);
38
- if (!rules) {
39
- throw new Error(`No rules set for game ${params.gameId}`);
40
- }
41
- const character = getCharacter(params.characterId);
42
- if (!character) {
43
- throw new Error(`Character ${params.characterId} not found`);
44
- }
45
- // Calculate modifier from character stats
46
- let modifier = params.bonusModifier || 0;
47
- if (params.skill && character.skills[params.skill] !== undefined) {
48
- modifier += character.skills[params.skill];
49
- }
50
- if (params.attribute && character.attributes[params.attribute] !== undefined) {
51
- // Common formula: (attribute - 10) / 2, but we'll just add the raw value
52
- // The DM agent should configure how modifiers work in the rules
53
- modifier += Math.floor((character.attributes[params.attribute] - 10) / 2);
54
- }
55
- // Roll the base dice
56
- const diceRoll = roll(rules.checkMechanics.baseDice);
57
- const total = diceRoll.total + modifier;
58
- // Determine success
59
- const success = total >= params.difficulty;
60
- const criticalSuccess = rules.checkMechanics.criticalSuccess !== undefined &&
61
- diceRoll.rolls[0] >= rules.checkMechanics.criticalSuccess;
62
- const criticalFailure = rules.checkMechanics.criticalFailure !== undefined &&
63
- diceRoll.rolls[0] <= rules.checkMechanics.criticalFailure;
64
- return {
65
- roll: diceRoll,
66
- modifier,
67
- total,
68
- difficulty: params.difficulty,
69
- success: criticalFailure ? false : criticalSuccess ? true : success,
70
- criticalSuccess,
71
- criticalFailure,
72
- margin: total - params.difficulty,
73
- };
74
- }
75
- // Opposed check between two characters
76
- export function contest(params) {
77
- const rules = getRules(params.gameId);
78
- if (!rules) {
79
- throw new Error(`No rules set for game ${params.gameId}`);
80
- }
81
- // Both roll against difficulty 0, we compare totals
82
- const attackerResult = check({
83
- gameId: params.gameId,
84
- characterId: params.attackerId,
85
- skill: params.attackerSkill,
86
- attribute: params.attackerAttribute,
87
- difficulty: 0,
88
- });
89
- const defenderResult = check({
90
- gameId: params.gameId,
91
- characterId: params.defenderId,
92
- skill: params.defenderSkill,
93
- attribute: params.defenderAttribute,
94
- difficulty: 0,
95
- });
96
- let winner;
97
- if (attackerResult.total > defenderResult.total) {
98
- winner = "attacker";
99
- }
100
- else if (defenderResult.total > attackerResult.total) {
101
- winner = "defender";
102
- }
103
- else {
104
- winner = "tie";
105
- }
106
- return {
107
- attackerResult,
108
- defenderResult,
109
- winner,
110
- };
111
- }
@@ -1,34 +0,0 @@
1
- import type { Quest, QuestObjective } from "../types/index.js";
2
- export declare function createQuest(params: {
3
- gameId: string;
4
- name: string;
5
- description: string;
6
- objectives: Omit<QuestObjective, "id">[];
7
- rewards?: string;
8
- }): Quest;
9
- export declare function getQuest(id: string): Quest | null;
10
- export declare function updateQuest(id: string, updates: {
11
- name?: string;
12
- description?: string;
13
- status?: Quest["status"];
14
- rewards?: string;
15
- }): Quest | null;
16
- /**
17
- * Modify quest objectives - add new objectives and/or complete existing ones in a single call.
18
- */
19
- export declare function modifyObjectives(questId: string, params: {
20
- add?: Array<{
21
- description: string;
22
- optional?: boolean;
23
- }>;
24
- complete?: string[];
25
- }): {
26
- quest: Quest;
27
- added: QuestObjective[];
28
- completed: string[];
29
- } | null;
30
- export declare function deleteQuest(id: string): boolean;
31
- export declare function listQuests(gameId: string, filter?: {
32
- status?: Quest["status"];
33
- }): Quest[];
34
- export declare function getActiveQuests(gameId: string): Quest[];