@lippelt/srd-core 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -99,6 +99,39 @@ function validateSystem(sys) {
99
99
  }
100
100
  });
101
101
  }
102
+ if (sys?.partyResources !== void 0) {
103
+ if (!Array.isArray(sys.partyResources)) {
104
+ errors.push("partyResources deve ser um array");
105
+ } else {
106
+ const seen = /* @__PURE__ */ new Set();
107
+ sys.partyResources.forEach((r, i) => {
108
+ check(isNonEmptyString(r?.key), `partyResources[${i}].key ausente ou vazio`);
109
+ check(isNonEmptyString(r?.label), `partyResources[${i}].label ausente ou vazio`);
110
+ if (isNonEmptyString(r?.key)) {
111
+ check(!seen.has(r.key), `partyResources: key duplicada "${r.key}"`);
112
+ seen.add(r.key);
113
+ }
114
+ if (r?.owner !== void 0) {
115
+ check(
116
+ r.owner === "party" || r.owner === "gm",
117
+ `partyResources[${i}] (${r?.key ?? "?"}): owner inv\xE1lido "${r.owner}"`
118
+ );
119
+ }
120
+ const { min, max, default: def } = r ?? {};
121
+ if (typeof min === "number" && typeof max === "number") {
122
+ check(min <= max, `partyResources[${i}] (${r.key}): min (${min}) > max (${max})`);
123
+ }
124
+ if (typeof def === "number") {
125
+ if (typeof min === "number") {
126
+ check(def >= min, `partyResources[${i}] (${r.key}): default (${def}) < min (${min})`);
127
+ }
128
+ if (typeof max === "number") {
129
+ check(def <= max, `partyResources[${i}] (${r.key}): default (${def}) > max (${max})`);
130
+ }
131
+ }
132
+ });
133
+ }
134
+ }
102
135
  return { valid: errors.length === 0, errors };
103
136
  }
104
137
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/validate.ts"],"sourcesContent":["/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n SystemNpcHooks,\n DicePreset,\n ConditionDef,\n TrackerField,\n RollResult,\n} from './types.js'\n\nexport { validateSystem } from './validate.js'\nexport type { SystemValidationResult } from './validate.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n","/**\n * Validação de integridade de um `System`.\n *\n * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:\n * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de\n * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não\n * registra nada nem toca em estado global.\n *\n * Serve tanto para o consumidor (validar na hora de `register`) quanto como\n * rede de segurança nos testes de cada pacote de sistema.\n */\nimport type { System } from './types.js'\n\nexport interface SystemValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// Ids estáveis: minúsculas, dígitos, hífen e ponto (ex.: 'dnd-3.5',\n// 'pathfinder-2e', 'lancer'). Sem espaços nem maiúsculas.\nconst ID_RE = /^[a-z0-9][a-z0-9.-]*$/\nconst TRACKER_KINDS = new Set(['integer', 'maxCurrent', 'boolean'])\n\nconst isNonEmptyString = (v: unknown): v is string =>\n typeof v === 'string' && v.length > 0\n\nexport function validateSystem(sys: System): SystemValidationResult {\n const errors: string[] = []\n const check = (ok: boolean, msg: string) => {\n if (!ok) errors.push(msg)\n }\n\n // --- Identidade ---\n check(isNonEmptyString(sys?.id), 'id ausente ou vazio')\n if (isNonEmptyString(sys?.id)) {\n check(ID_RE.test(sys.id), `id \"${sys.id}\" deve ser minúsculo (a-z 0-9 . -), sem espaços`)\n }\n check(isNonEmptyString(sys?.name), 'name ausente ou vazio')\n check(isNonEmptyString(sys?.ruleVersion), 'ruleVersion ausente ou vazio')\n\n // --- Dice presets (id único; id/label/notation obrigatórios) ---\n if (!Array.isArray(sys?.dicePresets)) {\n errors.push('dicePresets deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.dicePresets.forEach((p, i) => {\n check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`)\n check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`)\n check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`)\n if (isNonEmptyString(p?.id)) {\n check(!seen.has(p.id), `dicePresets: id duplicado \"${p.id}\"`)\n seen.add(p.id)\n }\n })\n }\n\n // --- Conditions (id único; id/label obrigatórios) ---\n if (!Array.isArray(sys?.conditions)) {\n errors.push('conditions deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.conditions.forEach((c, i) => {\n check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`)\n check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`)\n if (isNonEmptyString(c?.id)) {\n check(!seen.has(c.id), `conditions: id duplicado \"${c.id}\"`)\n seen.add(c.id)\n }\n })\n }\n\n // --- Tracker fields (key única; kind válido; min ≤ default ≤ max) ---\n if (!Array.isArray(sys?.trackerFields)) {\n errors.push('trackerFields deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.trackerFields.forEach((f, i) => {\n check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`)\n check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`)\n check(\n TRACKER_KINDS.has(f?.kind as string),\n `trackerFields[${i}] (${f?.key ?? '?'}): kind inválido \"${f?.kind}\"`,\n )\n if (isNonEmptyString(f?.key)) {\n check(!seen.has(f.key), `trackerFields: key duplicada \"${f.key}\"`)\n seen.add(f.key)\n }\n const { min, max, default: def } = f ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n\n return { valid: errors.length === 0, errors }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/validate.ts"],"sourcesContent":["/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n SystemNpcHooks,\n NpcGenFamily,\n D20AttackModel,\n NpcGenInput,\n NpcPoolBlock,\n DicePreset,\n ConditionDef,\n TrackerField,\n PartyResourceDef,\n RollResult,\n} from './types.js'\n\nexport { validateSystem } from './validate.js'\nexport type { SystemValidationResult } from './validate.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n","/**\n * Validação de integridade de um `System`.\n *\n * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:\n * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de\n * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não\n * registra nada nem toca em estado global.\n *\n * Serve tanto para o consumidor (validar na hora de `register`) quanto como\n * rede de segurança nos testes de cada pacote de sistema.\n */\nimport type { System } from './types.js'\n\nexport interface SystemValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// Ids estáveis: minúsculas, dígitos, hífen e ponto (ex.: 'dnd-3.5',\n// 'pathfinder-2e', 'lancer'). Sem espaços nem maiúsculas.\nconst ID_RE = /^[a-z0-9][a-z0-9.-]*$/\nconst TRACKER_KINDS = new Set(['integer', 'maxCurrent', 'boolean'])\n\nconst isNonEmptyString = (v: unknown): v is string =>\n typeof v === 'string' && v.length > 0\n\nexport function validateSystem(sys: System): SystemValidationResult {\n const errors: string[] = []\n const check = (ok: boolean, msg: string) => {\n if (!ok) errors.push(msg)\n }\n\n // --- Identidade ---\n check(isNonEmptyString(sys?.id), 'id ausente ou vazio')\n if (isNonEmptyString(sys?.id)) {\n check(ID_RE.test(sys.id), `id \"${sys.id}\" deve ser minúsculo (a-z 0-9 . -), sem espaços`)\n }\n check(isNonEmptyString(sys?.name), 'name ausente ou vazio')\n check(isNonEmptyString(sys?.ruleVersion), 'ruleVersion ausente ou vazio')\n\n // --- Dice presets (id único; id/label/notation obrigatórios) ---\n if (!Array.isArray(sys?.dicePresets)) {\n errors.push('dicePresets deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.dicePresets.forEach((p, i) => {\n check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`)\n check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`)\n check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`)\n if (isNonEmptyString(p?.id)) {\n check(!seen.has(p.id), `dicePresets: id duplicado \"${p.id}\"`)\n seen.add(p.id)\n }\n })\n }\n\n // --- Conditions (id único; id/label obrigatórios) ---\n if (!Array.isArray(sys?.conditions)) {\n errors.push('conditions deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.conditions.forEach((c, i) => {\n check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`)\n check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`)\n if (isNonEmptyString(c?.id)) {\n check(!seen.has(c.id), `conditions: id duplicado \"${c.id}\"`)\n seen.add(c.id)\n }\n })\n }\n\n // --- Tracker fields (key única; kind válido; min ≤ default ≤ max) ---\n if (!Array.isArray(sys?.trackerFields)) {\n errors.push('trackerFields deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.trackerFields.forEach((f, i) => {\n check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`)\n check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`)\n check(\n TRACKER_KINDS.has(f?.kind as string),\n `trackerFields[${i}] (${f?.key ?? '?'}): kind inválido \"${f?.kind}\"`,\n )\n if (isNonEmptyString(f?.key)) {\n check(!seen.has(f.key), `trackerFields: key duplicada \"${f.key}\"`)\n seen.add(f.key)\n }\n const { min, max, default: def } = f ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n\n // --- Party resources (opcional; key única; owner válido; min ≤ default ≤ max) ---\n if (sys?.partyResources !== undefined) {\n if (!Array.isArray(sys.partyResources)) {\n errors.push('partyResources deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.partyResources.forEach((r, i) => {\n check(isNonEmptyString(r?.key), `partyResources[${i}].key ausente ou vazio`)\n check(isNonEmptyString(r?.label), `partyResources[${i}].label ausente ou vazio`)\n if (isNonEmptyString(r?.key)) {\n check(!seen.has(r.key), `partyResources: key duplicada \"${r.key}\"`)\n seen.add(r.key)\n }\n if (r?.owner !== undefined) {\n check(\n r.owner === 'party' || r.owner === 'gm',\n `partyResources[${i}] (${r?.key ?? '?'}): owner inválido \"${r.owner}\"`,\n )\n }\n const { min, max, default: def } = r ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `partyResources[${i}] (${r.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `partyResources[${i}] (${r.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `partyResources[${i}] (${r.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n }\n\n return { valid: errors.length === 0, errors }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -54,6 +54,36 @@ interface TrackerField {
54
54
  /** Descrição/tooltip. */
55
55
  description?: string;
56
56
  }
57
+ /**
58
+ * Definição de um recurso compartilhado de nível de party/sessão
59
+ * (ex.: Wrath & Glory: Glory e Ruin). Diferente de `TrackerField`, que é
60
+ * por-combatente — estes são pools únicos da mesa, exibidos num painel
61
+ * próprio (não na ficha de cada combatente).
62
+ */
63
+ interface PartyResourceDef {
64
+ /** Chave estável (ex.: 'glory', 'ruin'). */
65
+ key: string;
66
+ /** Rótulo de exibição (ex.: 'Glory', 'Ruin'). */
67
+ label: string;
68
+ /** Valor mínimo (default 0). */
69
+ min?: number;
70
+ /** Valor máximo (default 10). */
71
+ max?: number;
72
+ /** Valor inicial (default = `min` ou 0). */
73
+ default?: number;
74
+ /** Cor CSS opcional do contador. */
75
+ color?: string;
76
+ /** Descrição/tooltip. */
77
+ description?: string;
78
+ /**
79
+ * Dono do recurso:
80
+ * - `'party'`: pool dos jogadores (ex.: Glory) — também exibido na 2ª tela.
81
+ * - `'gm'`: pool do mestre (ex.: Ruin) — restrito ao painel de controle,
82
+ * oculto da tela dos jogadores.
83
+ * Default: `'party'`.
84
+ */
85
+ owner?: 'party' | 'gm';
86
+ }
57
87
  interface RollResult {
58
88
  /** Rolagens individuais (todos os dados antes de filtragem). */
59
89
  rolls: number[];
@@ -82,15 +112,71 @@ interface SystemRules {
82
112
  notes?: string[];
83
113
  };
84
114
  }
115
+ /** Família de geração de NPC. */
116
+ type NpcGenFamily = 'd20' | 'pool';
117
+ /** Modelo de matemática d20 (proficiência tipo 5e/PF2 vs BAB tipo 3.5/PF1). */
118
+ type D20AttackModel = 'proficiency' | 'bab';
119
+ /** Entrada que o npcgen passa a um gerador de pool externo (hook). */
120
+ interface NpcGenInput {
121
+ systemId: string;
122
+ level: number;
123
+ name?: string;
124
+ creatureType: string;
125
+ creatureSize: string;
126
+ }
127
+ /**
128
+ * Bloco que um `generatePool` retorna — as partes específicas do sistema. O
129
+ * npcgen acopla o restante (criatura, família, systemId) ao redor disto.
130
+ */
131
+ interface NpcPoolBlock {
132
+ /** Papel/arquétipo (string livre por sistema). */
133
+ role: string;
134
+ /** Tier/nível (1..4). */
135
+ tier: number;
136
+ /** Nome (se o gerador quiser definir; senão o npcgen gera). */
137
+ name?: string;
138
+ /** Tracks principais (vida/estresse/sanidade/etc). */
139
+ tracks: Record<string, {
140
+ current: number;
141
+ max: number;
142
+ }>;
143
+ /** Ataques/ações principais. */
144
+ attacks: {
145
+ name: string;
146
+ damage: string;
147
+ range?: string;
148
+ notes?: string[];
149
+ }[];
150
+ /** Stats específicos do sistema (formato livre). */
151
+ extra?: Record<string, unknown>;
152
+ }
85
153
  /**
86
154
  * Hooks opcionais para refinar a geração de NPCs por sistema. Quando o
87
155
  * `@lippelt/srd-npcgen` encontra um destes preenchidos em `System.npc`,
88
- * usa em vez dos defaults genéricos da família d20.
156
+ * usa em vez dos defaults genéricos.
89
157
  *
90
- * Cada hook é puro e independente — implemente só os que fizerem sentido
91
- * pra mecânica do seu sistema.
158
+ * Cada hook é puro e independente — implemente só os que fizerem sentido pra
159
+ * mecânica do seu sistema. Sistemas FORA das famílias embutidas (d20 e os
160
+ * pools daggerheart/candela/gumshoe) se plugam declarando `family` e, para
161
+ * pool, um `generatePool` — o npcgen público nunca precisa conhecer o id.
92
162
  */
93
163
  interface SystemNpcHooks {
164
+ /**
165
+ * Família de geração. Opcional pros sistemas embutidos (o npcgen já sabe);
166
+ * obrigatória pra um sistema externo/privado fora das listas embutidas.
167
+ */
168
+ family?: NpcGenFamily;
169
+ /**
170
+ * Modelo de matemática pra um sistema d20 externo (quando `family` é 'd20'
171
+ * e o id não é embutido). Ignorado pros embutidos.
172
+ */
173
+ model?: D20AttackModel;
174
+ /**
175
+ * Gerador de NPC de pool do próprio sistema. Quando `family` é 'pool' e o
176
+ * sistema não é embutido, o npcgen chama isto e acopla criatura/metadata em
177
+ * volta — mantendo a separação (o npcgen público não importa o pacote).
178
+ */
179
+ generatePool?: (input: NpcGenInput) => NpcPoolBlock;
94
180
  /**
95
181
  * Override da progressão de ataque (default 5e: prof = 2 + ⌊(lvl−1)/4⌋).
96
182
  *
@@ -135,6 +221,12 @@ interface System {
135
221
  conditions: ConditionDef[];
136
222
  /** Campos extras do tracker (além de initiative/hp genéricos). */
137
223
  trackerFields: TrackerField[];
224
+ /**
225
+ * Recursos compartilhados de party/sessão (ex.: Glory e Ruin em W&G).
226
+ * Opcional — a maioria dos sistemas não tem. Exibidos num painel próprio,
227
+ * separado do tracker por-combatente.
228
+ */
229
+ partyResources?: PartyResourceDef[];
138
230
  /** Regras automatizáveis (opcionais). */
139
231
  rules?: SystemRules;
140
232
  /** Hooks pra refinar a geração de NPCs (consumidos pelo @lippelt/srd-npcgen). */
@@ -184,4 +276,4 @@ declare function listRegisteredSystems(): SystemId[];
184
276
  /** Remove todos os registros. Útil em testes; raro em produção. */
185
277
  declare function clearRegistry(): void;
186
278
 
187
- export { type ConditionDef, type DicePreset, type RollResult, type System, type SystemId, type SystemNpcHooks, type SystemRules, type SystemValidationResult, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register, validateSystem };
279
+ export { type ConditionDef, type D20AttackModel, type DicePreset, type NpcGenFamily, type NpcGenInput, type NpcPoolBlock, type PartyResourceDef, type RollResult, type System, type SystemId, type SystemNpcHooks, type SystemRules, type SystemValidationResult, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register, validateSystem };
package/dist/index.d.ts CHANGED
@@ -54,6 +54,36 @@ interface TrackerField {
54
54
  /** Descrição/tooltip. */
55
55
  description?: string;
56
56
  }
57
+ /**
58
+ * Definição de um recurso compartilhado de nível de party/sessão
59
+ * (ex.: Wrath & Glory: Glory e Ruin). Diferente de `TrackerField`, que é
60
+ * por-combatente — estes são pools únicos da mesa, exibidos num painel
61
+ * próprio (não na ficha de cada combatente).
62
+ */
63
+ interface PartyResourceDef {
64
+ /** Chave estável (ex.: 'glory', 'ruin'). */
65
+ key: string;
66
+ /** Rótulo de exibição (ex.: 'Glory', 'Ruin'). */
67
+ label: string;
68
+ /** Valor mínimo (default 0). */
69
+ min?: number;
70
+ /** Valor máximo (default 10). */
71
+ max?: number;
72
+ /** Valor inicial (default = `min` ou 0). */
73
+ default?: number;
74
+ /** Cor CSS opcional do contador. */
75
+ color?: string;
76
+ /** Descrição/tooltip. */
77
+ description?: string;
78
+ /**
79
+ * Dono do recurso:
80
+ * - `'party'`: pool dos jogadores (ex.: Glory) — também exibido na 2ª tela.
81
+ * - `'gm'`: pool do mestre (ex.: Ruin) — restrito ao painel de controle,
82
+ * oculto da tela dos jogadores.
83
+ * Default: `'party'`.
84
+ */
85
+ owner?: 'party' | 'gm';
86
+ }
57
87
  interface RollResult {
58
88
  /** Rolagens individuais (todos os dados antes de filtragem). */
59
89
  rolls: number[];
@@ -82,15 +112,71 @@ interface SystemRules {
82
112
  notes?: string[];
83
113
  };
84
114
  }
115
+ /** Família de geração de NPC. */
116
+ type NpcGenFamily = 'd20' | 'pool';
117
+ /** Modelo de matemática d20 (proficiência tipo 5e/PF2 vs BAB tipo 3.5/PF1). */
118
+ type D20AttackModel = 'proficiency' | 'bab';
119
+ /** Entrada que o npcgen passa a um gerador de pool externo (hook). */
120
+ interface NpcGenInput {
121
+ systemId: string;
122
+ level: number;
123
+ name?: string;
124
+ creatureType: string;
125
+ creatureSize: string;
126
+ }
127
+ /**
128
+ * Bloco que um `generatePool` retorna — as partes específicas do sistema. O
129
+ * npcgen acopla o restante (criatura, família, systemId) ao redor disto.
130
+ */
131
+ interface NpcPoolBlock {
132
+ /** Papel/arquétipo (string livre por sistema). */
133
+ role: string;
134
+ /** Tier/nível (1..4). */
135
+ tier: number;
136
+ /** Nome (se o gerador quiser definir; senão o npcgen gera). */
137
+ name?: string;
138
+ /** Tracks principais (vida/estresse/sanidade/etc). */
139
+ tracks: Record<string, {
140
+ current: number;
141
+ max: number;
142
+ }>;
143
+ /** Ataques/ações principais. */
144
+ attacks: {
145
+ name: string;
146
+ damage: string;
147
+ range?: string;
148
+ notes?: string[];
149
+ }[];
150
+ /** Stats específicos do sistema (formato livre). */
151
+ extra?: Record<string, unknown>;
152
+ }
85
153
  /**
86
154
  * Hooks opcionais para refinar a geração de NPCs por sistema. Quando o
87
155
  * `@lippelt/srd-npcgen` encontra um destes preenchidos em `System.npc`,
88
- * usa em vez dos defaults genéricos da família d20.
156
+ * usa em vez dos defaults genéricos.
89
157
  *
90
- * Cada hook é puro e independente — implemente só os que fizerem sentido
91
- * pra mecânica do seu sistema.
158
+ * Cada hook é puro e independente — implemente só os que fizerem sentido pra
159
+ * mecânica do seu sistema. Sistemas FORA das famílias embutidas (d20 e os
160
+ * pools daggerheart/candela/gumshoe) se plugam declarando `family` e, para
161
+ * pool, um `generatePool` — o npcgen público nunca precisa conhecer o id.
92
162
  */
93
163
  interface SystemNpcHooks {
164
+ /**
165
+ * Família de geração. Opcional pros sistemas embutidos (o npcgen já sabe);
166
+ * obrigatória pra um sistema externo/privado fora das listas embutidas.
167
+ */
168
+ family?: NpcGenFamily;
169
+ /**
170
+ * Modelo de matemática pra um sistema d20 externo (quando `family` é 'd20'
171
+ * e o id não é embutido). Ignorado pros embutidos.
172
+ */
173
+ model?: D20AttackModel;
174
+ /**
175
+ * Gerador de NPC de pool do próprio sistema. Quando `family` é 'pool' e o
176
+ * sistema não é embutido, o npcgen chama isto e acopla criatura/metadata em
177
+ * volta — mantendo a separação (o npcgen público não importa o pacote).
178
+ */
179
+ generatePool?: (input: NpcGenInput) => NpcPoolBlock;
94
180
  /**
95
181
  * Override da progressão de ataque (default 5e: prof = 2 + ⌊(lvl−1)/4⌋).
96
182
  *
@@ -135,6 +221,12 @@ interface System {
135
221
  conditions: ConditionDef[];
136
222
  /** Campos extras do tracker (além de initiative/hp genéricos). */
137
223
  trackerFields: TrackerField[];
224
+ /**
225
+ * Recursos compartilhados de party/sessão (ex.: Glory e Ruin em W&G).
226
+ * Opcional — a maioria dos sistemas não tem. Exibidos num painel próprio,
227
+ * separado do tracker por-combatente.
228
+ */
229
+ partyResources?: PartyResourceDef[];
138
230
  /** Regras automatizáveis (opcionais). */
139
231
  rules?: SystemRules;
140
232
  /** Hooks pra refinar a geração de NPCs (consumidos pelo @lippelt/srd-npcgen). */
@@ -184,4 +276,4 @@ declare function listRegisteredSystems(): SystemId[];
184
276
  /** Remove todos os registros. Útil em testes; raro em produção. */
185
277
  declare function clearRegistry(): void;
186
278
 
187
- export { type ConditionDef, type DicePreset, type RollResult, type System, type SystemId, type SystemNpcHooks, type SystemRules, type SystemValidationResult, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register, validateSystem };
279
+ export { type ConditionDef, type D20AttackModel, type DicePreset, type NpcGenFamily, type NpcGenInput, type NpcPoolBlock, type PartyResourceDef, type RollResult, type System, type SystemId, type SystemNpcHooks, type SystemRules, type SystemValidationResult, type TrackerField, clearRegistry, getSystem, listRegisteredSystems, register, validateSystem };
package/dist/index.js CHANGED
@@ -69,6 +69,39 @@ function validateSystem(sys) {
69
69
  }
70
70
  });
71
71
  }
72
+ if (sys?.partyResources !== void 0) {
73
+ if (!Array.isArray(sys.partyResources)) {
74
+ errors.push("partyResources deve ser um array");
75
+ } else {
76
+ const seen = /* @__PURE__ */ new Set();
77
+ sys.partyResources.forEach((r, i) => {
78
+ check(isNonEmptyString(r?.key), `partyResources[${i}].key ausente ou vazio`);
79
+ check(isNonEmptyString(r?.label), `partyResources[${i}].label ausente ou vazio`);
80
+ if (isNonEmptyString(r?.key)) {
81
+ check(!seen.has(r.key), `partyResources: key duplicada "${r.key}"`);
82
+ seen.add(r.key);
83
+ }
84
+ if (r?.owner !== void 0) {
85
+ check(
86
+ r.owner === "party" || r.owner === "gm",
87
+ `partyResources[${i}] (${r?.key ?? "?"}): owner inv\xE1lido "${r.owner}"`
88
+ );
89
+ }
90
+ const { min, max, default: def } = r ?? {};
91
+ if (typeof min === "number" && typeof max === "number") {
92
+ check(min <= max, `partyResources[${i}] (${r.key}): min (${min}) > max (${max})`);
93
+ }
94
+ if (typeof def === "number") {
95
+ if (typeof min === "number") {
96
+ check(def >= min, `partyResources[${i}] (${r.key}): default (${def}) < min (${min})`);
97
+ }
98
+ if (typeof max === "number") {
99
+ check(def <= max, `partyResources[${i}] (${r.key}): default (${def}) > max (${max})`);
100
+ }
101
+ }
102
+ });
103
+ }
104
+ }
72
105
  return { valid: errors.length === 0, errors };
73
106
  }
74
107
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/validate.ts","../src/index.ts"],"sourcesContent":["/**\n * Validação de integridade de um `System`.\n *\n * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:\n * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de\n * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não\n * registra nada nem toca em estado global.\n *\n * Serve tanto para o consumidor (validar na hora de `register`) quanto como\n * rede de segurança nos testes de cada pacote de sistema.\n */\nimport type { System } from './types.js'\n\nexport interface SystemValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// Ids estáveis: minúsculas, dígitos, hífen e ponto (ex.: 'dnd-3.5',\n// 'pathfinder-2e', 'lancer'). Sem espaços nem maiúsculas.\nconst ID_RE = /^[a-z0-9][a-z0-9.-]*$/\nconst TRACKER_KINDS = new Set(['integer', 'maxCurrent', 'boolean'])\n\nconst isNonEmptyString = (v: unknown): v is string =>\n typeof v === 'string' && v.length > 0\n\nexport function validateSystem(sys: System): SystemValidationResult {\n const errors: string[] = []\n const check = (ok: boolean, msg: string) => {\n if (!ok) errors.push(msg)\n }\n\n // --- Identidade ---\n check(isNonEmptyString(sys?.id), 'id ausente ou vazio')\n if (isNonEmptyString(sys?.id)) {\n check(ID_RE.test(sys.id), `id \"${sys.id}\" deve ser minúsculo (a-z 0-9 . -), sem espaços`)\n }\n check(isNonEmptyString(sys?.name), 'name ausente ou vazio')\n check(isNonEmptyString(sys?.ruleVersion), 'ruleVersion ausente ou vazio')\n\n // --- Dice presets (id único; id/label/notation obrigatórios) ---\n if (!Array.isArray(sys?.dicePresets)) {\n errors.push('dicePresets deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.dicePresets.forEach((p, i) => {\n check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`)\n check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`)\n check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`)\n if (isNonEmptyString(p?.id)) {\n check(!seen.has(p.id), `dicePresets: id duplicado \"${p.id}\"`)\n seen.add(p.id)\n }\n })\n }\n\n // --- Conditions (id único; id/label obrigatórios) ---\n if (!Array.isArray(sys?.conditions)) {\n errors.push('conditions deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.conditions.forEach((c, i) => {\n check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`)\n check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`)\n if (isNonEmptyString(c?.id)) {\n check(!seen.has(c.id), `conditions: id duplicado \"${c.id}\"`)\n seen.add(c.id)\n }\n })\n }\n\n // --- Tracker fields (key única; kind válido; min ≤ default ≤ max) ---\n if (!Array.isArray(sys?.trackerFields)) {\n errors.push('trackerFields deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.trackerFields.forEach((f, i) => {\n check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`)\n check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`)\n check(\n TRACKER_KINDS.has(f?.kind as string),\n `trackerFields[${i}] (${f?.key ?? '?'}): kind inválido \"${f?.kind}\"`,\n )\n if (isNonEmptyString(f?.key)) {\n check(!seen.has(f.key), `trackerFields: key duplicada \"${f.key}\"`)\n seen.add(f.key)\n }\n const { min, max, default: def } = f ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n\n return { valid: errors.length === 0, errors }\n}\n","/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n SystemNpcHooks,\n DicePreset,\n ConditionDef,\n TrackerField,\n RollResult,\n} from './types.js'\n\nexport { validateSystem } from './validate.js'\nexport type { SystemValidationResult } from './validate.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/validate.ts","../src/index.ts"],"sourcesContent":["/**\n * Validação de integridade de um `System`.\n *\n * Garante que um pacote de sistema cumpre o contrato antes de ser registrado:\n * campos obrigatórios presentes, ids/keys únicos e não-vazios, `kind` de\n * tracker válido e limites (min ≤ default ≤ max) coerentes. Pura — não\n * registra nada nem toca em estado global.\n *\n * Serve tanto para o consumidor (validar na hora de `register`) quanto como\n * rede de segurança nos testes de cada pacote de sistema.\n */\nimport type { System } from './types.js'\n\nexport interface SystemValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// Ids estáveis: minúsculas, dígitos, hífen e ponto (ex.: 'dnd-3.5',\n// 'pathfinder-2e', 'lancer'). Sem espaços nem maiúsculas.\nconst ID_RE = /^[a-z0-9][a-z0-9.-]*$/\nconst TRACKER_KINDS = new Set(['integer', 'maxCurrent', 'boolean'])\n\nconst isNonEmptyString = (v: unknown): v is string =>\n typeof v === 'string' && v.length > 0\n\nexport function validateSystem(sys: System): SystemValidationResult {\n const errors: string[] = []\n const check = (ok: boolean, msg: string) => {\n if (!ok) errors.push(msg)\n }\n\n // --- Identidade ---\n check(isNonEmptyString(sys?.id), 'id ausente ou vazio')\n if (isNonEmptyString(sys?.id)) {\n check(ID_RE.test(sys.id), `id \"${sys.id}\" deve ser minúsculo (a-z 0-9 . -), sem espaços`)\n }\n check(isNonEmptyString(sys?.name), 'name ausente ou vazio')\n check(isNonEmptyString(sys?.ruleVersion), 'ruleVersion ausente ou vazio')\n\n // --- Dice presets (id único; id/label/notation obrigatórios) ---\n if (!Array.isArray(sys?.dicePresets)) {\n errors.push('dicePresets deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.dicePresets.forEach((p, i) => {\n check(isNonEmptyString(p?.id), `dicePresets[${i}].id ausente ou vazio`)\n check(isNonEmptyString(p?.label), `dicePresets[${i}].label ausente ou vazio`)\n check(isNonEmptyString(p?.notation), `dicePresets[${i}].notation ausente ou vazio`)\n if (isNonEmptyString(p?.id)) {\n check(!seen.has(p.id), `dicePresets: id duplicado \"${p.id}\"`)\n seen.add(p.id)\n }\n })\n }\n\n // --- Conditions (id único; id/label obrigatórios) ---\n if (!Array.isArray(sys?.conditions)) {\n errors.push('conditions deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.conditions.forEach((c, i) => {\n check(isNonEmptyString(c?.id), `conditions[${i}].id ausente ou vazio`)\n check(isNonEmptyString(c?.label), `conditions[${i}].label ausente ou vazio`)\n if (isNonEmptyString(c?.id)) {\n check(!seen.has(c.id), `conditions: id duplicado \"${c.id}\"`)\n seen.add(c.id)\n }\n })\n }\n\n // --- Tracker fields (key única; kind válido; min ≤ default ≤ max) ---\n if (!Array.isArray(sys?.trackerFields)) {\n errors.push('trackerFields deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.trackerFields.forEach((f, i) => {\n check(isNonEmptyString(f?.key), `trackerFields[${i}].key ausente ou vazio`)\n check(isNonEmptyString(f?.label), `trackerFields[${i}].label ausente ou vazio`)\n check(\n TRACKER_KINDS.has(f?.kind as string),\n `trackerFields[${i}] (${f?.key ?? '?'}): kind inválido \"${f?.kind}\"`,\n )\n if (isNonEmptyString(f?.key)) {\n check(!seen.has(f.key), `trackerFields: key duplicada \"${f.key}\"`)\n seen.add(f.key)\n }\n const { min, max, default: def } = f ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `trackerFields[${i}] (${f.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `trackerFields[${i}] (${f.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `trackerFields[${i}] (${f.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n\n // --- Party resources (opcional; key única; owner válido; min ≤ default ≤ max) ---\n if (sys?.partyResources !== undefined) {\n if (!Array.isArray(sys.partyResources)) {\n errors.push('partyResources deve ser um array')\n } else {\n const seen = new Set<string>()\n sys.partyResources.forEach((r, i) => {\n check(isNonEmptyString(r?.key), `partyResources[${i}].key ausente ou vazio`)\n check(isNonEmptyString(r?.label), `partyResources[${i}].label ausente ou vazio`)\n if (isNonEmptyString(r?.key)) {\n check(!seen.has(r.key), `partyResources: key duplicada \"${r.key}\"`)\n seen.add(r.key)\n }\n if (r?.owner !== undefined) {\n check(\n r.owner === 'party' || r.owner === 'gm',\n `partyResources[${i}] (${r?.key ?? '?'}): owner inválido \"${r.owner}\"`,\n )\n }\n const { min, max, default: def } = r ?? {}\n if (typeof min === 'number' && typeof max === 'number') {\n check(min <= max, `partyResources[${i}] (${r.key}): min (${min}) > max (${max})`)\n }\n if (typeof def === 'number') {\n if (typeof min === 'number') {\n check(def >= min, `partyResources[${i}] (${r.key}): default (${def}) < min (${min})`)\n }\n if (typeof max === 'number') {\n check(def <= max, `partyResources[${i}] (${r.key}): default (${def}) > max (${max})`)\n }\n }\n })\n }\n }\n\n return { valid: errors.length === 0, errors }\n}\n","/**\n * @lippelt/srd-core — contrato + registry para sistemas RPG plugáveis.\n *\n * Padrão de uso (lado do consumidor):\n *\n * import { register, getSystem } from '@lippelt/srd-core'\n * import { dnd5e2014 } from '@lippelt/srd-dnd5e-2014'\n *\n * register(dnd5e2014)\n * const sys = getSystem('dnd5e-2014') // System | null\n */\n\nexport type {\n System,\n SystemId,\n SystemRules,\n SystemNpcHooks,\n NpcGenFamily,\n D20AttackModel,\n NpcGenInput,\n NpcPoolBlock,\n DicePreset,\n ConditionDef,\n TrackerField,\n PartyResourceDef,\n RollResult,\n} from './types.js'\n\nexport { validateSystem } from './validate.js'\nexport type { SystemValidationResult } from './validate.js'\n\nimport type { System, SystemId } from './types.js'\n\nconst registry = new Map<SystemId, System>()\n\n/**\n * Registra um sistema. Idempotente: registrar o mesmo `system` (mesma\n * referência) duas vezes é no-op. Registrar uma instância DIFERENTE com\n * id já existente lança erro — proteção contra conflitos.\n */\nexport function register(system: System): void {\n const existing = registry.get(system.id)\n if (existing && existing !== system) {\n throw new Error(\n `[gmcr-srd-core] sistema \"${system.id}\" já registrado por outra instância`,\n )\n }\n registry.set(system.id, system)\n}\n\n/** Resolve um sistema pelo id, ou null se não registrado. */\nexport function getSystem(id: SystemId): System | null {\n return registry.get(id) ?? null\n}\n\n/** Lista os ids de sistemas atualmente registrados. */\nexport function listRegisteredSystems(): SystemId[] {\n return [...registry.keys()]\n}\n\n/** Remove todos os registros. Útil em testes; raro em produção. */\nexport function clearRegistry(): void {\n registry.clear()\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lippelt/srd-core",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Plugin core for tabletop RPG system modules (types + registry). Each system ships in its own package.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",