@lippelt/srd-dnd5e-2014 0.1.1 → 0.1.3
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/README.md +12 -16
- package/dist/index.cjs +24 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,25 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Módulo Dungeons & Dragons 5ª Edição (2014) para [`@lippelt/srd-core`](../core).
|
|
4
4
|
|
|
5
|
-
> D&D® é trademark da Wizards of the Coast LLC. Este pacote usa mecânicas do [System Reference Document 5.1](https://dnd.wizards.com/resources/systems-reference-document) sob a [Creative Commons Attribution 4.0 International License (CC-BY 4.0)](https://creativecommons.org/licenses/by/4.0/legalcode).
|
|
5
|
+
> D&D® é trademark da Wizards of the Coast LLC. Este pacote usa mecânicas do [System Reference Document 5.1](https://dnd.wizards.com/resources/systems-reference-document) sob a [Creative Commons Attribution 4.0 International License (CC-BY 4.0)](https://creativecommons.org/licenses/by/4.0/legalcode). Termos em PT-BR seguem a tradução oficial Galápagos Jogos.
|
|
6
6
|
|
|
7
7
|
## O que inclui
|
|
8
8
|
|
|
9
|
-
- **d20 com vantagem/desvantagem** — `roll('check' | 'd20', { modifier, advantage?, disadvantage? })`. Vantagem e desvantagem se cancelam (regra SRD).
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
9
|
+
- **d20 com vantagem/desvantagem** — `roll('check' | 'd20', { modifier, advantage?, disadvantage? })`. Vantagem e desvantagem se cancelam (regra do SRD).
|
|
10
|
+
- **Rolagem de ataque vs CA** — `roll('attack', { modifier, targetAC?, advantage?, disadvantage? })`. 20 natural sempre acerta; 1 natural sempre erra.
|
|
11
|
+
- **Teste de resistência** — `roll('save', { modifier, dc?, advantage?, disadvantage? })`.
|
|
12
|
+
- **Rolagem de dano** — `roll('damage', { count, sides, modifier, critical? })`. `critical: true` dobra os dados.
|
|
13
|
+
- **Utilitários exportados:**
|
|
14
14
|
- `abilityMod(score)` — `floor((score - 10) / 2)`
|
|
15
15
|
- `spellSaveDC(proficiency, casterMod)` — `8 + prof + mod`
|
|
16
16
|
- `spellAttackBonus(proficiency, casterMod)` — `prof + mod`
|
|
17
|
-
- **20
|
|
18
|
-
- **3
|
|
19
|
-
- **9
|
|
20
|
-
|
|
21
|
-
## Não inclui
|
|
22
|
-
|
|
23
|
-
Spells, classes, races, monstros, items específicos — esse conteúdo deve vir do livro/SRD oficial ou de uma camada acima (compendium do consumidor). Este pacote modela só **mecânicas** (dice, condições, modificadores derivados).
|
|
17
|
+
- **20 condições** — Cego, Enfeitiçado, Surdo, Exaustão (níveis 1–6), Amedrontado, Agarrado, Incapacitado, Invisível, Paralisado, Petrificado, Envenenado, Caído, Contido, Atordoado, Inconsciente.
|
|
18
|
+
- **3 campos de status** — CA (Classe de Armadura), Mortes ✓, Mortes ✗.
|
|
19
|
+
- **9 presets de dados** — d20, d20 com vantagem/desvantagem, d4/d6/d8/d10/d12 (dano), d100.
|
|
24
20
|
|
|
25
21
|
## Uso
|
|
26
22
|
|
|
@@ -32,12 +28,12 @@ register(dnd5e2014)
|
|
|
32
28
|
|
|
33
29
|
const sys = getSystem('dnd5e-2014')!
|
|
34
30
|
|
|
35
|
-
//
|
|
31
|
+
// Ataque com vantagem contra CA 16
|
|
36
32
|
const atk = sys.rules!.roll!('attack', { modifier: 6, targetAC: 16, advantage: true })
|
|
37
33
|
// → { total: 24, notes: ['vantagem', 'acertou (CA 16)'], ... }
|
|
38
34
|
|
|
39
|
-
//
|
|
40
|
-
const
|
|
35
|
+
// CD de magia pra um warlock CAR 18 com proficiência +3
|
|
36
|
+
const cd = spellSaveDC(3, abilityMod(18)) // 14
|
|
41
37
|
```
|
|
42
38
|
|
|
43
39
|
## Testes determinísticos
|
package/dist/index.cjs
CHANGED
|
@@ -195,6 +195,26 @@ var RULES = {
|
|
|
195
195
|
return applyDndDamage(incoming, target);
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
|
+
var DND5E_2014_SKILLS = [
|
|
199
|
+
"acrobatics",
|
|
200
|
+
"animal-handling",
|
|
201
|
+
"arcana",
|
|
202
|
+
"athletics",
|
|
203
|
+
"deception",
|
|
204
|
+
"history",
|
|
205
|
+
"insight",
|
|
206
|
+
"intimidation",
|
|
207
|
+
"investigation",
|
|
208
|
+
"medicine",
|
|
209
|
+
"nature",
|
|
210
|
+
"perception",
|
|
211
|
+
"performance",
|
|
212
|
+
"persuasion",
|
|
213
|
+
"religion",
|
|
214
|
+
"sleight-of-hand",
|
|
215
|
+
"stealth",
|
|
216
|
+
"survival"
|
|
217
|
+
];
|
|
198
218
|
var dnd5e2014 = {
|
|
199
219
|
id: "dnd5e-2014",
|
|
200
220
|
name: "Dungeons & Dragons 5e (2014)",
|
|
@@ -203,7 +223,10 @@ var dnd5e2014 = {
|
|
|
203
223
|
dicePresets: DICE_PRESETS,
|
|
204
224
|
conditions: CONDITIONS,
|
|
205
225
|
trackerFields: TRACKER_FIELDS,
|
|
206
|
-
rules: RULES
|
|
226
|
+
rules: RULES,
|
|
227
|
+
npc: {
|
|
228
|
+
skills: DND5E_2014_SKILLS
|
|
229
|
+
}
|
|
207
230
|
};
|
|
208
231
|
// Annotate the CommonJS export names for ESM import in node:
|
|
209
232
|
0 && (module.exports = {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Dungeons & Dragons 5th Edition (2014).\n *\n * Conteúdo de regras (condições, ability scores, escala de DC) deriva do\n * System Reference Document 5.1, publicado pela Wizards of the Coast LLC\n * sob a Creative Commons Attribution 4.0 International License:\n * https://creativecommons.org/licenses/by/4.0/legalcode\n *\n * Esta implementação é original (não copia código de implementações\n * existentes). Referência conceitual: foundryvtt/dnd5e (MIT).\n */\n\nimport type {\n ConditionDef,\n DicePreset,\n RollResult,\n System,\n SystemRules,\n TrackerField,\n} from '@lippelt/srd-core'\n\n// ============================================================================\n// Random helper — extraído pra que os testes possam injetar uma fonte\n// determinística via `setRoller`.\n// ============================================================================\n\ntype Roller = (sides: number) => number\n\nlet roller: Roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n\n/** Substitui o gerador de dados (use em testes). Restaurar com `resetRoller`. */\nexport function setRoller(fn: Roller): void {\n roller = fn\n}\n\n/** Restaura o gerador padrão (Math.random). */\nexport function resetRoller(): void {\n roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n}\n\nfunction roll(sides: number, count = 1): number[] {\n const out: number[] = []\n for (let i = 0; i < count; i++) out.push(roller(sides))\n return out\n}\n\n// ============================================================================\n// Presets de dados — botões rápidos da UI\n// ============================================================================\n\nconst DICE_PRESETS: DicePreset[] = [\n { id: 'd20', label: 'd20', notation: '1d20', category: 'check' },\n { id: 'd20-adv', label: 'd20 (adv.)', notation: 'advantage', category: 'check', description: 'Rola 2d20 e pega o maior.' },\n { id: 'd20-dis', label: 'd20 (desv.)', notation: 'disadvantage', category: 'check', description: 'Rola 2d20 e pega o menor.' },\n { id: 'd4', label: 'd4', notation: '1d4', category: 'damage' },\n { id: 'd6', label: 'd6', notation: '1d6', category: 'damage' },\n { id: 'd8', label: 'd8', notation: '1d8', category: 'damage' },\n { id: 'd10', label: 'd10', notation: '1d10', category: 'damage' },\n { id: 'd12', label: 'd12', notation: '1d12', category: 'damage' },\n { id: 'd100', label: 'd100', notation: '1d100', category: 'special' },\n]\n\n// ============================================================================\n// Condições — SRD 5.1 (CC-BY 4.0)\n// ============================================================================\n\nconst CONDITIONS: ConditionDef[] = [\n { id: 'blinded', label: 'Blinded', summary: 'Cego: falha em testes que exigem visão; atacantes têm vantagem; o cego tem desvantagem.' },\n { id: 'charmed', label: 'Charmed', summary: 'Enfeitiçado: não pode atacar o encantador nem usar habilidades nocivas contra ele.' },\n { id: 'deafened', label: 'Deafened', summary: 'Surdo: falha em testes que dependem de audição.' },\n { id: 'exhaustion-1', label: 'Exhaustion 1', summary: 'Exaustão 1: desvantagem em testes de habilidade.' },\n { id: 'exhaustion-2', label: 'Exhaustion 2', summary: 'Exaustão 2: velocidade reduzida pela metade.' },\n { id: 'exhaustion-3', label: 'Exhaustion 3', summary: 'Exaustão 3: desvantagem em ataques e jogadas de resistência.' },\n { id: 'exhaustion-4', label: 'Exhaustion 4', summary: 'Exaustão 4: máximo de HP reduzido pela metade.' },\n { id: 'exhaustion-5', label: 'Exhaustion 5', summary: 'Exaustão 5: velocidade reduzida a 0.' },\n { id: 'exhaustion-6', label: 'Exhaustion 6', summary: 'Exaustão 6: morte.' },\n { id: 'frightened', label: 'Frightened', summary: 'Amedrontado: desvantagem se a fonte do medo estiver à vista; não pode se mover para perto dela.' },\n { id: 'grappled', label: 'Grappled', summary: 'Agarrado: velocidade 0; termina se o agarrador ficar incapacitado.' },\n { id: 'incapacitated', label: 'Incapacitated', summary: 'Incapacitado: não pode tomar ações nem reações.' },\n { id: 'invisible', label: 'Invisible', summary: 'Invisível: vantagem em ataques; atacantes têm desvantagem.' },\n { id: 'paralyzed', label: 'Paralyzed', summary: 'Paralisado: incapacitado, não pode se mover/falar; ataques a até 1,5m são automáticos críticos.' },\n { id: 'petrified', label: 'Petrified', summary: 'Petrificado: transformado em substância sólida; resistência a todo dano; imune a venenos e doenças.' },\n { id: 'poisoned', label: 'Poisoned', summary: 'Envenenado: desvantagem em ataques e testes de habilidade.' },\n { id: 'prone', label: 'Prone', summary: 'Caído: desvantagem em ataques; ataques corpo-a-corpo contra o alvo têm vantagem; à distância têm desvantagem.' },\n { id: 'restrained', label: 'Restrained', summary: 'Contido: velocidade 0; desvantagem em ataques e Dex saves; atacantes têm vantagem.' },\n { id: 'stunned', label: 'Stunned', summary: 'Atordoado: incapacitado; falha automaticamente em Str/Dex saves; atacantes têm vantagem.' },\n { id: 'unconscious', label: 'Unconscious', summary: 'Inconsciente: incapacitado, caído; ataques a até 1,5m são críticos automáticos.' },\n]\n\n// ============================================================================\n// Tracker fields — AC e death saves além de initiative/hp genéricos\n// ============================================================================\n\nconst TRACKER_FIELDS: TrackerField[] = [\n {\n key: 'ac',\n label: 'CA',\n kind: 'integer',\n min: 1,\n max: 30,\n default: 10,\n description: 'Classe de Armadura — DC para ser atingido por ataques.',\n },\n {\n key: 'deathSuccesses',\n label: 'M✓',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Sucessos em testes de resistência à morte (3 = estabilizado).',\n },\n {\n key: 'deathFailures',\n label: 'M✗',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Falhas em testes de resistência à morte (3 = morte).',\n },\n]\n\n// ============================================================================\n// Regras automatizadas\n// ============================================================================\n\n/** Modificador derivado da ability score: floor((score - 10) / 2). */\nexport function abilityMod(score: number): number {\n return Math.floor((score - 10) / 2)\n}\n\n/** DC de feitiço: 8 + proficiency + ability modifier. */\nexport function spellSaveDC(proficiency: number, casterMod: number): number {\n return 8 + proficiency + casterMod\n}\n\n/** Bônus de ataque por feitiço: proficiency + ability modifier. */\nexport function spellAttackBonus(proficiency: number, casterMod: number): number {\n return proficiency + casterMod\n}\n\ninterface D20Params {\n modifier?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Rola um d20 com possível advantage/disadvantage e modificador. */\nfunction rollD20({ modifier = 0, advantage = false, disadvantage = false }: D20Params): RollResult {\n // Vantagem e desvantagem se cancelam mutuamente (SRD 5.1).\n const cancelled = advantage && disadvantage\n const useAdv = advantage && !cancelled\n const useDis = disadvantage && !cancelled\n const count = useAdv || useDis ? 2 : 1\n const dice = roll(20, count)\n const picked = useAdv ? Math.max(...dice) : useDis ? Math.min(...dice) : dice[0]!\n const total = picked + modifier\n const notes: string[] = []\n if (cancelled) notes.push('vantagem/desvantagem se cancelaram')\n else if (useAdv) notes.push('vantagem')\n else if (useDis) notes.push('desvantagem')\n if (picked === 20) notes.push('crítico natural')\n if (picked === 1) notes.push('falha crítica')\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n const dStr = count === 2 ? `2d20${useAdv ? 'kh1' : 'kl1'}` : '1d20'\n return { rolls: dice, modifier, total, notation: `${dStr}${modStr}`, notes }\n}\n\ninterface AttackParams {\n modifier?: number\n targetAC?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/**\n * Rolagem de ataque contra AC. Se `targetAC` for fornecido, anota se acertou.\n * Crítico natural 20 sempre acerta; 1 sempre erra (SRD 5.1).\n */\nfunction rollAttack(params: AttackParams): RollResult {\n const result = rollD20(params)\n const d20 = result.rolls[result.rolls.length === 2\n ? (params.advantage && !params.disadvantage ? (result.rolls[0]! >= result.rolls[1]! ? 0 : 1) : (result.rolls[0]! <= result.rolls[1]! ? 0 : 1))\n : 0]!\n const notes = [...(result.notes ?? [])]\n if (params.targetAC !== undefined) {\n const natural20 = d20 === 20\n const natural1 = d20 === 1\n const hit = natural20 || (!natural1 && result.total >= params.targetAC)\n notes.push(hit ? (natural20 ? 'acerto crítico' : 'acertou') : (natural1 ? 'erro crítico' : 'errou'))\n }\n return { ...result, notes }\n}\n\ninterface SaveParams {\n modifier?: number\n dc: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Saving throw vs DC. Anota success/failure. */\nfunction rollSave(params: SaveParams): RollResult {\n const result = rollD20(params)\n const notes = [...(result.notes ?? [])]\n notes.push(result.total >= params.dc ? 'sucesso' : 'falha')\n return { ...result, notes: notes.concat([`DC ${params.dc}`]) }\n}\n\ninterface DamageParams {\n count: number\n sides: number\n modifier?: number\n critical?: boolean\n}\n\n/**\n * Rolagem de dano: NdM+K, com opção de crítico (rola o dobro dos dados,\n * mantém o modificador uma única vez — SRD 5.1).\n */\nfunction rollDamage({ count, sides, modifier = 0, critical = false }: DamageParams): RollResult {\n const totalDice = critical ? count * 2 : count\n const dice = roll(sides, totalDice)\n const sum = dice.reduce((a, b) => a + b, 0)\n const total = Math.max(0, sum + modifier)\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n return {\n rolls: dice,\n modifier,\n total,\n notation: `${totalDice}d${sides}${modStr}${critical ? ' (crit)' : ''}`,\n notes: critical ? ['dano crítico — dados dobrados'] : [],\n }\n}\n\ninterface DamageTarget {\n resistance?: string[]\n vulnerability?: string[]\n immunity?: string[]\n}\n\ninterface ApplyDamageInput {\n type?: string\n target?: DamageTarget\n}\n\n/**\n * Reduz dano pelas propriedades do alvo. Ordem (SRD 5.1):\n * 1. Imunidade zera o dano.\n * 2. Resistência metade (arredondar pra baixo).\n * 3. Vulnerabilidade dobra.\n * Se uma criatura tem múltiplas categorias para o mesmo tipo, apenas uma se aplica\n * (mas combinadas com outras categorias podem coexistir — aqui assumimos exclusividade).\n */\nfunction applyDndDamage(incoming: number, ctx: ApplyDamageInput): { final: number; notes: string[] } {\n const t = ctx.target\n const type = ctx.type\n if (!type || !t) return { final: Math.max(0, incoming), notes: [] }\n if (t.immunity?.includes(type)) return { final: 0, notes: [`imune a ${type}`] }\n if (t.resistance?.includes(type)) {\n return { final: Math.floor(incoming / 2), notes: [`resistência a ${type} (metade)`] }\n }\n if (t.vulnerability?.includes(type)) {\n return { final: incoming * 2, notes: [`vulnerabilidade a ${type} (dobro)`] }\n }\n return { final: Math.max(0, incoming), notes: [] }\n}\n\n// ============================================================================\n// Bundle do sistema\n// ============================================================================\n\nconst RULES: SystemRules = {\n roll(kind, params) {\n switch (kind) {\n case 'd20':\n case 'check':\n case 'ability':\n return rollD20(params as unknown as D20Params)\n case 'attack':\n return rollAttack(params as unknown as AttackParams)\n case 'save':\n return rollSave(params as unknown as SaveParams)\n case 'damage':\n return rollDamage(params as unknown as DamageParams)\n default:\n return null\n }\n },\n applyDamage(incoming, target) {\n return applyDndDamage(incoming, target as ApplyDamageInput)\n },\n}\n\nexport const dnd5e2014: System = {\n id: 'dnd5e-2014',\n name: 'Dungeons & Dragons 5e (2014)',\n ruleVersion: 'SRD 5.1',\n attribution:\n 'Contains material from the System Reference Document 5.1 by Wizards of the Coast LLC, licensed under CC-BY 4.0.',\n dicePresets: DICE_PRESETS,\n conditions: CONDITIONS,\n trackerFields: TRACKER_FIELDS,\n rules: RULES,\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Dungeons & Dragons 5th Edition (2014).\n *\n * Conteúdo de regras (condições, ability scores, escala de DC) deriva do\n * System Reference Document 5.1, publicado pela Wizards of the Coast LLC\n * sob a Creative Commons Attribution 4.0 International License:\n * https://creativecommons.org/licenses/by/4.0/legalcode\n *\n * Esta implementação é original (não copia código de implementações\n * existentes). Referência conceitual: foundryvtt/dnd5e (MIT).\n */\n\nimport type {\n ConditionDef,\n DicePreset,\n RollResult,\n System,\n SystemRules,\n TrackerField,\n} from '@lippelt/srd-core'\n\n// ============================================================================\n// Random helper — extraído pra que os testes possam injetar uma fonte\n// determinística via `setRoller`.\n// ============================================================================\n\ntype Roller = (sides: number) => number\n\nlet roller: Roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n\n/** Substitui o gerador de dados (use em testes). Restaurar com `resetRoller`. */\nexport function setRoller(fn: Roller): void {\n roller = fn\n}\n\n/** Restaura o gerador padrão (Math.random). */\nexport function resetRoller(): void {\n roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n}\n\nfunction roll(sides: number, count = 1): number[] {\n const out: number[] = []\n for (let i = 0; i < count; i++) out.push(roller(sides))\n return out\n}\n\n// ============================================================================\n// Presets de dados — botões rápidos da UI\n// ============================================================================\n\nconst DICE_PRESETS: DicePreset[] = [\n { id: 'd20', label: 'd20', notation: '1d20', category: 'check' },\n { id: 'd20-adv', label: 'd20 (adv.)', notation: 'advantage', category: 'check', description: 'Rola 2d20 e pega o maior.' },\n { id: 'd20-dis', label: 'd20 (desv.)', notation: 'disadvantage', category: 'check', description: 'Rola 2d20 e pega o menor.' },\n { id: 'd4', label: 'd4', notation: '1d4', category: 'damage' },\n { id: 'd6', label: 'd6', notation: '1d6', category: 'damage' },\n { id: 'd8', label: 'd8', notation: '1d8', category: 'damage' },\n { id: 'd10', label: 'd10', notation: '1d10', category: 'damage' },\n { id: 'd12', label: 'd12', notation: '1d12', category: 'damage' },\n { id: 'd100', label: 'd100', notation: '1d100', category: 'special' },\n]\n\n// ============================================================================\n// Condições — SRD 5.1 (CC-BY 4.0)\n// ============================================================================\n\nconst CONDITIONS: ConditionDef[] = [\n { id: 'blinded', label: 'Blinded', summary: 'Cego: falha em testes que exigem visão; atacantes têm vantagem; o cego tem desvantagem.' },\n { id: 'charmed', label: 'Charmed', summary: 'Enfeitiçado: não pode atacar o encantador nem usar habilidades nocivas contra ele.' },\n { id: 'deafened', label: 'Deafened', summary: 'Surdo: falha em testes que dependem de audição.' },\n { id: 'exhaustion-1', label: 'Exhaustion 1', summary: 'Exaustão 1: desvantagem em testes de habilidade.' },\n { id: 'exhaustion-2', label: 'Exhaustion 2', summary: 'Exaustão 2: velocidade reduzida pela metade.' },\n { id: 'exhaustion-3', label: 'Exhaustion 3', summary: 'Exaustão 3: desvantagem em ataques e jogadas de resistência.' },\n { id: 'exhaustion-4', label: 'Exhaustion 4', summary: 'Exaustão 4: máximo de HP reduzido pela metade.' },\n { id: 'exhaustion-5', label: 'Exhaustion 5', summary: 'Exaustão 5: velocidade reduzida a 0.' },\n { id: 'exhaustion-6', label: 'Exhaustion 6', summary: 'Exaustão 6: morte.' },\n { id: 'frightened', label: 'Frightened', summary: 'Amedrontado: desvantagem se a fonte do medo estiver à vista; não pode se mover para perto dela.' },\n { id: 'grappled', label: 'Grappled', summary: 'Agarrado: velocidade 0; termina se o agarrador ficar incapacitado.' },\n { id: 'incapacitated', label: 'Incapacitated', summary: 'Incapacitado: não pode tomar ações nem reações.' },\n { id: 'invisible', label: 'Invisible', summary: 'Invisível: vantagem em ataques; atacantes têm desvantagem.' },\n { id: 'paralyzed', label: 'Paralyzed', summary: 'Paralisado: incapacitado, não pode se mover/falar; ataques a até 1,5m são automáticos críticos.' },\n { id: 'petrified', label: 'Petrified', summary: 'Petrificado: transformado em substância sólida; resistência a todo dano; imune a venenos e doenças.' },\n { id: 'poisoned', label: 'Poisoned', summary: 'Envenenado: desvantagem em ataques e testes de habilidade.' },\n { id: 'prone', label: 'Prone', summary: 'Caído: desvantagem em ataques; ataques corpo-a-corpo contra o alvo têm vantagem; à distância têm desvantagem.' },\n { id: 'restrained', label: 'Restrained', summary: 'Contido: velocidade 0; desvantagem em ataques e Dex saves; atacantes têm vantagem.' },\n { id: 'stunned', label: 'Stunned', summary: 'Atordoado: incapacitado; falha automaticamente em Str/Dex saves; atacantes têm vantagem.' },\n { id: 'unconscious', label: 'Unconscious', summary: 'Inconsciente: incapacitado, caído; ataques a até 1,5m são críticos automáticos.' },\n]\n\n// ============================================================================\n// Tracker fields — AC e death saves além de initiative/hp genéricos\n// ============================================================================\n\nconst TRACKER_FIELDS: TrackerField[] = [\n {\n key: 'ac',\n label: 'CA',\n kind: 'integer',\n min: 1,\n max: 30,\n default: 10,\n description: 'Classe de Armadura — DC para ser atingido por ataques.',\n },\n {\n key: 'deathSuccesses',\n label: 'M✓',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Sucessos em testes de resistência à morte (3 = estabilizado).',\n },\n {\n key: 'deathFailures',\n label: 'M✗',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Falhas em testes de resistência à morte (3 = morte).',\n },\n]\n\n// ============================================================================\n// Regras automatizadas\n// ============================================================================\n\n/** Modificador derivado da ability score: floor((score - 10) / 2). */\nexport function abilityMod(score: number): number {\n return Math.floor((score - 10) / 2)\n}\n\n/** DC de feitiço: 8 + proficiency + ability modifier. */\nexport function spellSaveDC(proficiency: number, casterMod: number): number {\n return 8 + proficiency + casterMod\n}\n\n/** Bônus de ataque por feitiço: proficiency + ability modifier. */\nexport function spellAttackBonus(proficiency: number, casterMod: number): number {\n return proficiency + casterMod\n}\n\ninterface D20Params {\n modifier?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Rola um d20 com possível advantage/disadvantage e modificador. */\nfunction rollD20({ modifier = 0, advantage = false, disadvantage = false }: D20Params): RollResult {\n // Vantagem e desvantagem se cancelam mutuamente (SRD 5.1).\n const cancelled = advantage && disadvantage\n const useAdv = advantage && !cancelled\n const useDis = disadvantage && !cancelled\n const count = useAdv || useDis ? 2 : 1\n const dice = roll(20, count)\n const picked = useAdv ? Math.max(...dice) : useDis ? Math.min(...dice) : dice[0]!\n const total = picked + modifier\n const notes: string[] = []\n if (cancelled) notes.push('vantagem/desvantagem se cancelaram')\n else if (useAdv) notes.push('vantagem')\n else if (useDis) notes.push('desvantagem')\n if (picked === 20) notes.push('crítico natural')\n if (picked === 1) notes.push('falha crítica')\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n const dStr = count === 2 ? `2d20${useAdv ? 'kh1' : 'kl1'}` : '1d20'\n return { rolls: dice, modifier, total, notation: `${dStr}${modStr}`, notes }\n}\n\ninterface AttackParams {\n modifier?: number\n targetAC?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/**\n * Rolagem de ataque contra AC. Se `targetAC` for fornecido, anota se acertou.\n * Crítico natural 20 sempre acerta; 1 sempre erra (SRD 5.1).\n */\nfunction rollAttack(params: AttackParams): RollResult {\n const result = rollD20(params)\n const d20 = result.rolls[result.rolls.length === 2\n ? (params.advantage && !params.disadvantage ? (result.rolls[0]! >= result.rolls[1]! ? 0 : 1) : (result.rolls[0]! <= result.rolls[1]! ? 0 : 1))\n : 0]!\n const notes = [...(result.notes ?? [])]\n if (params.targetAC !== undefined) {\n const natural20 = d20 === 20\n const natural1 = d20 === 1\n const hit = natural20 || (!natural1 && result.total >= params.targetAC)\n notes.push(hit ? (natural20 ? 'acerto crítico' : 'acertou') : (natural1 ? 'erro crítico' : 'errou'))\n }\n return { ...result, notes }\n}\n\ninterface SaveParams {\n modifier?: number\n dc: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Saving throw vs DC. Anota success/failure. */\nfunction rollSave(params: SaveParams): RollResult {\n const result = rollD20(params)\n const notes = [...(result.notes ?? [])]\n notes.push(result.total >= params.dc ? 'sucesso' : 'falha')\n return { ...result, notes: notes.concat([`DC ${params.dc}`]) }\n}\n\ninterface DamageParams {\n count: number\n sides: number\n modifier?: number\n critical?: boolean\n}\n\n/**\n * Rolagem de dano: NdM+K, com opção de crítico (rola o dobro dos dados,\n * mantém o modificador uma única vez — SRD 5.1).\n */\nfunction rollDamage({ count, sides, modifier = 0, critical = false }: DamageParams): RollResult {\n const totalDice = critical ? count * 2 : count\n const dice = roll(sides, totalDice)\n const sum = dice.reduce((a, b) => a + b, 0)\n const total = Math.max(0, sum + modifier)\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n return {\n rolls: dice,\n modifier,\n total,\n notation: `${totalDice}d${sides}${modStr}${critical ? ' (crit)' : ''}`,\n notes: critical ? ['dano crítico — dados dobrados'] : [],\n }\n}\n\ninterface DamageTarget {\n resistance?: string[]\n vulnerability?: string[]\n immunity?: string[]\n}\n\ninterface ApplyDamageInput {\n type?: string\n target?: DamageTarget\n}\n\n/**\n * Reduz dano pelas propriedades do alvo. Ordem (SRD 5.1):\n * 1. Imunidade zera o dano.\n * 2. Resistência metade (arredondar pra baixo).\n * 3. Vulnerabilidade dobra.\n * Se uma criatura tem múltiplas categorias para o mesmo tipo, apenas uma se aplica\n * (mas combinadas com outras categorias podem coexistir — aqui assumimos exclusividade).\n */\nfunction applyDndDamage(incoming: number, ctx: ApplyDamageInput): { final: number; notes: string[] } {\n const t = ctx.target\n const type = ctx.type\n if (!type || !t) return { final: Math.max(0, incoming), notes: [] }\n if (t.immunity?.includes(type)) return { final: 0, notes: [`imune a ${type}`] }\n if (t.resistance?.includes(type)) {\n return { final: Math.floor(incoming / 2), notes: [`resistência a ${type} (metade)`] }\n }\n if (t.vulnerability?.includes(type)) {\n return { final: incoming * 2, notes: [`vulnerabilidade a ${type} (dobro)`] }\n }\n return { final: Math.max(0, incoming), notes: [] }\n}\n\n// ============================================================================\n// Bundle do sistema\n// ============================================================================\n\nconst RULES: SystemRules = {\n roll(kind, params) {\n switch (kind) {\n case 'd20':\n case 'check':\n case 'ability':\n return rollD20(params as unknown as D20Params)\n case 'attack':\n return rollAttack(params as unknown as AttackParams)\n case 'save':\n return rollSave(params as unknown as SaveParams)\n case 'damage':\n return rollDamage(params as unknown as DamageParams)\n default:\n return null\n }\n },\n applyDamage(incoming, target) {\n return applyDndDamage(incoming, target as ApplyDamageInput)\n },\n}\n\n/**\n * Hooks pra `@lippelt/srd-npcgen`. 5e usa proficiency bonus + ability mod\n * (default do npcgen já bate). Só listamos skills canônicas do SRD 5.1;\n * cantripDamageDice fica no default (1/5/11/17 → 1/2/3/4) que já segue 5e.\n */\nconst DND5E_2014_SKILLS = [\n 'acrobatics',\n 'animal-handling',\n 'arcana',\n 'athletics',\n 'deception',\n 'history',\n 'insight',\n 'intimidation',\n 'investigation',\n 'medicine',\n 'nature',\n 'perception',\n 'performance',\n 'persuasion',\n 'religion',\n 'sleight-of-hand',\n 'stealth',\n 'survival',\n] as const\n\nexport const dnd5e2014: System = {\n id: 'dnd5e-2014',\n name: 'Dungeons & Dragons 5e (2014)',\n ruleVersion: 'SRD 5.1',\n attribution:\n 'Contains material from the System Reference Document 5.1 by Wizards of the Coast LLC, licensed under CC-BY 4.0.',\n dicePresets: DICE_PRESETS,\n conditions: CONDITIONS,\n trackerFields: TRACKER_FIELDS,\n rules: RULES,\n npc: {\n skills: DND5E_2014_SKILLS,\n },\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -166,6 +166,26 @@ var RULES = {
|
|
|
166
166
|
return applyDndDamage(incoming, target);
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
|
+
var DND5E_2014_SKILLS = [
|
|
170
|
+
"acrobatics",
|
|
171
|
+
"animal-handling",
|
|
172
|
+
"arcana",
|
|
173
|
+
"athletics",
|
|
174
|
+
"deception",
|
|
175
|
+
"history",
|
|
176
|
+
"insight",
|
|
177
|
+
"intimidation",
|
|
178
|
+
"investigation",
|
|
179
|
+
"medicine",
|
|
180
|
+
"nature",
|
|
181
|
+
"perception",
|
|
182
|
+
"performance",
|
|
183
|
+
"persuasion",
|
|
184
|
+
"religion",
|
|
185
|
+
"sleight-of-hand",
|
|
186
|
+
"stealth",
|
|
187
|
+
"survival"
|
|
188
|
+
];
|
|
169
189
|
var dnd5e2014 = {
|
|
170
190
|
id: "dnd5e-2014",
|
|
171
191
|
name: "Dungeons & Dragons 5e (2014)",
|
|
@@ -174,7 +194,10 @@ var dnd5e2014 = {
|
|
|
174
194
|
dicePresets: DICE_PRESETS,
|
|
175
195
|
conditions: CONDITIONS,
|
|
176
196
|
trackerFields: TRACKER_FIELDS,
|
|
177
|
-
rules: RULES
|
|
197
|
+
rules: RULES,
|
|
198
|
+
npc: {
|
|
199
|
+
skills: DND5E_2014_SKILLS
|
|
200
|
+
}
|
|
178
201
|
};
|
|
179
202
|
export {
|
|
180
203
|
abilityMod,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Dungeons & Dragons 5th Edition (2014).\n *\n * Conteúdo de regras (condições, ability scores, escala de DC) deriva do\n * System Reference Document 5.1, publicado pela Wizards of the Coast LLC\n * sob a Creative Commons Attribution 4.0 International License:\n * https://creativecommons.org/licenses/by/4.0/legalcode\n *\n * Esta implementação é original (não copia código de implementações\n * existentes). Referência conceitual: foundryvtt/dnd5e (MIT).\n */\n\nimport type {\n ConditionDef,\n DicePreset,\n RollResult,\n System,\n SystemRules,\n TrackerField,\n} from '@lippelt/srd-core'\n\n// ============================================================================\n// Random helper — extraído pra que os testes possam injetar uma fonte\n// determinística via `setRoller`.\n// ============================================================================\n\ntype Roller = (sides: number) => number\n\nlet roller: Roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n\n/** Substitui o gerador de dados (use em testes). Restaurar com `resetRoller`. */\nexport function setRoller(fn: Roller): void {\n roller = fn\n}\n\n/** Restaura o gerador padrão (Math.random). */\nexport function resetRoller(): void {\n roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n}\n\nfunction roll(sides: number, count = 1): number[] {\n const out: number[] = []\n for (let i = 0; i < count; i++) out.push(roller(sides))\n return out\n}\n\n// ============================================================================\n// Presets de dados — botões rápidos da UI\n// ============================================================================\n\nconst DICE_PRESETS: DicePreset[] = [\n { id: 'd20', label: 'd20', notation: '1d20', category: 'check' },\n { id: 'd20-adv', label: 'd20 (adv.)', notation: 'advantage', category: 'check', description: 'Rola 2d20 e pega o maior.' },\n { id: 'd20-dis', label: 'd20 (desv.)', notation: 'disadvantage', category: 'check', description: 'Rola 2d20 e pega o menor.' },\n { id: 'd4', label: 'd4', notation: '1d4', category: 'damage' },\n { id: 'd6', label: 'd6', notation: '1d6', category: 'damage' },\n { id: 'd8', label: 'd8', notation: '1d8', category: 'damage' },\n { id: 'd10', label: 'd10', notation: '1d10', category: 'damage' },\n { id: 'd12', label: 'd12', notation: '1d12', category: 'damage' },\n { id: 'd100', label: 'd100', notation: '1d100', category: 'special' },\n]\n\n// ============================================================================\n// Condições — SRD 5.1 (CC-BY 4.0)\n// ============================================================================\n\nconst CONDITIONS: ConditionDef[] = [\n { id: 'blinded', label: 'Blinded', summary: 'Cego: falha em testes que exigem visão; atacantes têm vantagem; o cego tem desvantagem.' },\n { id: 'charmed', label: 'Charmed', summary: 'Enfeitiçado: não pode atacar o encantador nem usar habilidades nocivas contra ele.' },\n { id: 'deafened', label: 'Deafened', summary: 'Surdo: falha em testes que dependem de audição.' },\n { id: 'exhaustion-1', label: 'Exhaustion 1', summary: 'Exaustão 1: desvantagem em testes de habilidade.' },\n { id: 'exhaustion-2', label: 'Exhaustion 2', summary: 'Exaustão 2: velocidade reduzida pela metade.' },\n { id: 'exhaustion-3', label: 'Exhaustion 3', summary: 'Exaustão 3: desvantagem em ataques e jogadas de resistência.' },\n { id: 'exhaustion-4', label: 'Exhaustion 4', summary: 'Exaustão 4: máximo de HP reduzido pela metade.' },\n { id: 'exhaustion-5', label: 'Exhaustion 5', summary: 'Exaustão 5: velocidade reduzida a 0.' },\n { id: 'exhaustion-6', label: 'Exhaustion 6', summary: 'Exaustão 6: morte.' },\n { id: 'frightened', label: 'Frightened', summary: 'Amedrontado: desvantagem se a fonte do medo estiver à vista; não pode se mover para perto dela.' },\n { id: 'grappled', label: 'Grappled', summary: 'Agarrado: velocidade 0; termina se o agarrador ficar incapacitado.' },\n { id: 'incapacitated', label: 'Incapacitated', summary: 'Incapacitado: não pode tomar ações nem reações.' },\n { id: 'invisible', label: 'Invisible', summary: 'Invisível: vantagem em ataques; atacantes têm desvantagem.' },\n { id: 'paralyzed', label: 'Paralyzed', summary: 'Paralisado: incapacitado, não pode se mover/falar; ataques a até 1,5m são automáticos críticos.' },\n { id: 'petrified', label: 'Petrified', summary: 'Petrificado: transformado em substância sólida; resistência a todo dano; imune a venenos e doenças.' },\n { id: 'poisoned', label: 'Poisoned', summary: 'Envenenado: desvantagem em ataques e testes de habilidade.' },\n { id: 'prone', label: 'Prone', summary: 'Caído: desvantagem em ataques; ataques corpo-a-corpo contra o alvo têm vantagem; à distância têm desvantagem.' },\n { id: 'restrained', label: 'Restrained', summary: 'Contido: velocidade 0; desvantagem em ataques e Dex saves; atacantes têm vantagem.' },\n { id: 'stunned', label: 'Stunned', summary: 'Atordoado: incapacitado; falha automaticamente em Str/Dex saves; atacantes têm vantagem.' },\n { id: 'unconscious', label: 'Unconscious', summary: 'Inconsciente: incapacitado, caído; ataques a até 1,5m são críticos automáticos.' },\n]\n\n// ============================================================================\n// Tracker fields — AC e death saves além de initiative/hp genéricos\n// ============================================================================\n\nconst TRACKER_FIELDS: TrackerField[] = [\n {\n key: 'ac',\n label: 'CA',\n kind: 'integer',\n min: 1,\n max: 30,\n default: 10,\n description: 'Classe de Armadura — DC para ser atingido por ataques.',\n },\n {\n key: 'deathSuccesses',\n label: 'M✓',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Sucessos em testes de resistência à morte (3 = estabilizado).',\n },\n {\n key: 'deathFailures',\n label: 'M✗',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Falhas em testes de resistência à morte (3 = morte).',\n },\n]\n\n// ============================================================================\n// Regras automatizadas\n// ============================================================================\n\n/** Modificador derivado da ability score: floor((score - 10) / 2). */\nexport function abilityMod(score: number): number {\n return Math.floor((score - 10) / 2)\n}\n\n/** DC de feitiço: 8 + proficiency + ability modifier. */\nexport function spellSaveDC(proficiency: number, casterMod: number): number {\n return 8 + proficiency + casterMod\n}\n\n/** Bônus de ataque por feitiço: proficiency + ability modifier. */\nexport function spellAttackBonus(proficiency: number, casterMod: number): number {\n return proficiency + casterMod\n}\n\ninterface D20Params {\n modifier?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Rola um d20 com possível advantage/disadvantage e modificador. */\nfunction rollD20({ modifier = 0, advantage = false, disadvantage = false }: D20Params): RollResult {\n // Vantagem e desvantagem se cancelam mutuamente (SRD 5.1).\n const cancelled = advantage && disadvantage\n const useAdv = advantage && !cancelled\n const useDis = disadvantage && !cancelled\n const count = useAdv || useDis ? 2 : 1\n const dice = roll(20, count)\n const picked = useAdv ? Math.max(...dice) : useDis ? Math.min(...dice) : dice[0]!\n const total = picked + modifier\n const notes: string[] = []\n if (cancelled) notes.push('vantagem/desvantagem se cancelaram')\n else if (useAdv) notes.push('vantagem')\n else if (useDis) notes.push('desvantagem')\n if (picked === 20) notes.push('crítico natural')\n if (picked === 1) notes.push('falha crítica')\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n const dStr = count === 2 ? `2d20${useAdv ? 'kh1' : 'kl1'}` : '1d20'\n return { rolls: dice, modifier, total, notation: `${dStr}${modStr}`, notes }\n}\n\ninterface AttackParams {\n modifier?: number\n targetAC?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/**\n * Rolagem de ataque contra AC. Se `targetAC` for fornecido, anota se acertou.\n * Crítico natural 20 sempre acerta; 1 sempre erra (SRD 5.1).\n */\nfunction rollAttack(params: AttackParams): RollResult {\n const result = rollD20(params)\n const d20 = result.rolls[result.rolls.length === 2\n ? (params.advantage && !params.disadvantage ? (result.rolls[0]! >= result.rolls[1]! ? 0 : 1) : (result.rolls[0]! <= result.rolls[1]! ? 0 : 1))\n : 0]!\n const notes = [...(result.notes ?? [])]\n if (params.targetAC !== undefined) {\n const natural20 = d20 === 20\n const natural1 = d20 === 1\n const hit = natural20 || (!natural1 && result.total >= params.targetAC)\n notes.push(hit ? (natural20 ? 'acerto crítico' : 'acertou') : (natural1 ? 'erro crítico' : 'errou'))\n }\n return { ...result, notes }\n}\n\ninterface SaveParams {\n modifier?: number\n dc: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Saving throw vs DC. Anota success/failure. */\nfunction rollSave(params: SaveParams): RollResult {\n const result = rollD20(params)\n const notes = [...(result.notes ?? [])]\n notes.push(result.total >= params.dc ? 'sucesso' : 'falha')\n return { ...result, notes: notes.concat([`DC ${params.dc}`]) }\n}\n\ninterface DamageParams {\n count: number\n sides: number\n modifier?: number\n critical?: boolean\n}\n\n/**\n * Rolagem de dano: NdM+K, com opção de crítico (rola o dobro dos dados,\n * mantém o modificador uma única vez — SRD 5.1).\n */\nfunction rollDamage({ count, sides, modifier = 0, critical = false }: DamageParams): RollResult {\n const totalDice = critical ? count * 2 : count\n const dice = roll(sides, totalDice)\n const sum = dice.reduce((a, b) => a + b, 0)\n const total = Math.max(0, sum + modifier)\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n return {\n rolls: dice,\n modifier,\n total,\n notation: `${totalDice}d${sides}${modStr}${critical ? ' (crit)' : ''}`,\n notes: critical ? ['dano crítico — dados dobrados'] : [],\n }\n}\n\ninterface DamageTarget {\n resistance?: string[]\n vulnerability?: string[]\n immunity?: string[]\n}\n\ninterface ApplyDamageInput {\n type?: string\n target?: DamageTarget\n}\n\n/**\n * Reduz dano pelas propriedades do alvo. Ordem (SRD 5.1):\n * 1. Imunidade zera o dano.\n * 2. Resistência metade (arredondar pra baixo).\n * 3. Vulnerabilidade dobra.\n * Se uma criatura tem múltiplas categorias para o mesmo tipo, apenas uma se aplica\n * (mas combinadas com outras categorias podem coexistir — aqui assumimos exclusividade).\n */\nfunction applyDndDamage(incoming: number, ctx: ApplyDamageInput): { final: number; notes: string[] } {\n const t = ctx.target\n const type = ctx.type\n if (!type || !t) return { final: Math.max(0, incoming), notes: [] }\n if (t.immunity?.includes(type)) return { final: 0, notes: [`imune a ${type}`] }\n if (t.resistance?.includes(type)) {\n return { final: Math.floor(incoming / 2), notes: [`resistência a ${type} (metade)`] }\n }\n if (t.vulnerability?.includes(type)) {\n return { final: incoming * 2, notes: [`vulnerabilidade a ${type} (dobro)`] }\n }\n return { final: Math.max(0, incoming), notes: [] }\n}\n\n// ============================================================================\n// Bundle do sistema\n// ============================================================================\n\nconst RULES: SystemRules = {\n roll(kind, params) {\n switch (kind) {\n case 'd20':\n case 'check':\n case 'ability':\n return rollD20(params as unknown as D20Params)\n case 'attack':\n return rollAttack(params as unknown as AttackParams)\n case 'save':\n return rollSave(params as unknown as SaveParams)\n case 'damage':\n return rollDamage(params as unknown as DamageParams)\n default:\n return null\n }\n },\n applyDamage(incoming, target) {\n return applyDndDamage(incoming, target as ApplyDamageInput)\n },\n}\n\nexport const dnd5e2014: System = {\n id: 'dnd5e-2014',\n name: 'Dungeons & Dragons 5e (2014)',\n ruleVersion: 'SRD 5.1',\n attribution:\n 'Contains material from the System Reference Document 5.1 by Wizards of the Coast LLC, licensed under CC-BY 4.0.',\n dicePresets: DICE_PRESETS,\n conditions: CONDITIONS,\n trackerFields: TRACKER_FIELDS,\n rules: RULES,\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Dungeons & Dragons 5th Edition (2014).\n *\n * Conteúdo de regras (condições, ability scores, escala de DC) deriva do\n * System Reference Document 5.1, publicado pela Wizards of the Coast LLC\n * sob a Creative Commons Attribution 4.0 International License:\n * https://creativecommons.org/licenses/by/4.0/legalcode\n *\n * Esta implementação é original (não copia código de implementações\n * existentes). Referência conceitual: foundryvtt/dnd5e (MIT).\n */\n\nimport type {\n ConditionDef,\n DicePreset,\n RollResult,\n System,\n SystemRules,\n TrackerField,\n} from '@lippelt/srd-core'\n\n// ============================================================================\n// Random helper — extraído pra que os testes possam injetar uma fonte\n// determinística via `setRoller`.\n// ============================================================================\n\ntype Roller = (sides: number) => number\n\nlet roller: Roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n\n/** Substitui o gerador de dados (use em testes). Restaurar com `resetRoller`. */\nexport function setRoller(fn: Roller): void {\n roller = fn\n}\n\n/** Restaura o gerador padrão (Math.random). */\nexport function resetRoller(): void {\n roller = (sides: number) => Math.floor(Math.random() * sides) + 1\n}\n\nfunction roll(sides: number, count = 1): number[] {\n const out: number[] = []\n for (let i = 0; i < count; i++) out.push(roller(sides))\n return out\n}\n\n// ============================================================================\n// Presets de dados — botões rápidos da UI\n// ============================================================================\n\nconst DICE_PRESETS: DicePreset[] = [\n { id: 'd20', label: 'd20', notation: '1d20', category: 'check' },\n { id: 'd20-adv', label: 'd20 (adv.)', notation: 'advantage', category: 'check', description: 'Rola 2d20 e pega o maior.' },\n { id: 'd20-dis', label: 'd20 (desv.)', notation: 'disadvantage', category: 'check', description: 'Rola 2d20 e pega o menor.' },\n { id: 'd4', label: 'd4', notation: '1d4', category: 'damage' },\n { id: 'd6', label: 'd6', notation: '1d6', category: 'damage' },\n { id: 'd8', label: 'd8', notation: '1d8', category: 'damage' },\n { id: 'd10', label: 'd10', notation: '1d10', category: 'damage' },\n { id: 'd12', label: 'd12', notation: '1d12', category: 'damage' },\n { id: 'd100', label: 'd100', notation: '1d100', category: 'special' },\n]\n\n// ============================================================================\n// Condições — SRD 5.1 (CC-BY 4.0)\n// ============================================================================\n\nconst CONDITIONS: ConditionDef[] = [\n { id: 'blinded', label: 'Blinded', summary: 'Cego: falha em testes que exigem visão; atacantes têm vantagem; o cego tem desvantagem.' },\n { id: 'charmed', label: 'Charmed', summary: 'Enfeitiçado: não pode atacar o encantador nem usar habilidades nocivas contra ele.' },\n { id: 'deafened', label: 'Deafened', summary: 'Surdo: falha em testes que dependem de audição.' },\n { id: 'exhaustion-1', label: 'Exhaustion 1', summary: 'Exaustão 1: desvantagem em testes de habilidade.' },\n { id: 'exhaustion-2', label: 'Exhaustion 2', summary: 'Exaustão 2: velocidade reduzida pela metade.' },\n { id: 'exhaustion-3', label: 'Exhaustion 3', summary: 'Exaustão 3: desvantagem em ataques e jogadas de resistência.' },\n { id: 'exhaustion-4', label: 'Exhaustion 4', summary: 'Exaustão 4: máximo de HP reduzido pela metade.' },\n { id: 'exhaustion-5', label: 'Exhaustion 5', summary: 'Exaustão 5: velocidade reduzida a 0.' },\n { id: 'exhaustion-6', label: 'Exhaustion 6', summary: 'Exaustão 6: morte.' },\n { id: 'frightened', label: 'Frightened', summary: 'Amedrontado: desvantagem se a fonte do medo estiver à vista; não pode se mover para perto dela.' },\n { id: 'grappled', label: 'Grappled', summary: 'Agarrado: velocidade 0; termina se o agarrador ficar incapacitado.' },\n { id: 'incapacitated', label: 'Incapacitated', summary: 'Incapacitado: não pode tomar ações nem reações.' },\n { id: 'invisible', label: 'Invisible', summary: 'Invisível: vantagem em ataques; atacantes têm desvantagem.' },\n { id: 'paralyzed', label: 'Paralyzed', summary: 'Paralisado: incapacitado, não pode se mover/falar; ataques a até 1,5m são automáticos críticos.' },\n { id: 'petrified', label: 'Petrified', summary: 'Petrificado: transformado em substância sólida; resistência a todo dano; imune a venenos e doenças.' },\n { id: 'poisoned', label: 'Poisoned', summary: 'Envenenado: desvantagem em ataques e testes de habilidade.' },\n { id: 'prone', label: 'Prone', summary: 'Caído: desvantagem em ataques; ataques corpo-a-corpo contra o alvo têm vantagem; à distância têm desvantagem.' },\n { id: 'restrained', label: 'Restrained', summary: 'Contido: velocidade 0; desvantagem em ataques e Dex saves; atacantes têm vantagem.' },\n { id: 'stunned', label: 'Stunned', summary: 'Atordoado: incapacitado; falha automaticamente em Str/Dex saves; atacantes têm vantagem.' },\n { id: 'unconscious', label: 'Unconscious', summary: 'Inconsciente: incapacitado, caído; ataques a até 1,5m são críticos automáticos.' },\n]\n\n// ============================================================================\n// Tracker fields — AC e death saves além de initiative/hp genéricos\n// ============================================================================\n\nconst TRACKER_FIELDS: TrackerField[] = [\n {\n key: 'ac',\n label: 'CA',\n kind: 'integer',\n min: 1,\n max: 30,\n default: 10,\n description: 'Classe de Armadura — DC para ser atingido por ataques.',\n },\n {\n key: 'deathSuccesses',\n label: 'M✓',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Sucessos em testes de resistência à morte (3 = estabilizado).',\n },\n {\n key: 'deathFailures',\n label: 'M✗',\n kind: 'integer',\n min: 0,\n max: 3,\n default: 0,\n description: 'Falhas em testes de resistência à morte (3 = morte).',\n },\n]\n\n// ============================================================================\n// Regras automatizadas\n// ============================================================================\n\n/** Modificador derivado da ability score: floor((score - 10) / 2). */\nexport function abilityMod(score: number): number {\n return Math.floor((score - 10) / 2)\n}\n\n/** DC de feitiço: 8 + proficiency + ability modifier. */\nexport function spellSaveDC(proficiency: number, casterMod: number): number {\n return 8 + proficiency + casterMod\n}\n\n/** Bônus de ataque por feitiço: proficiency + ability modifier. */\nexport function spellAttackBonus(proficiency: number, casterMod: number): number {\n return proficiency + casterMod\n}\n\ninterface D20Params {\n modifier?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Rola um d20 com possível advantage/disadvantage e modificador. */\nfunction rollD20({ modifier = 0, advantage = false, disadvantage = false }: D20Params): RollResult {\n // Vantagem e desvantagem se cancelam mutuamente (SRD 5.1).\n const cancelled = advantage && disadvantage\n const useAdv = advantage && !cancelled\n const useDis = disadvantage && !cancelled\n const count = useAdv || useDis ? 2 : 1\n const dice = roll(20, count)\n const picked = useAdv ? Math.max(...dice) : useDis ? Math.min(...dice) : dice[0]!\n const total = picked + modifier\n const notes: string[] = []\n if (cancelled) notes.push('vantagem/desvantagem se cancelaram')\n else if (useAdv) notes.push('vantagem')\n else if (useDis) notes.push('desvantagem')\n if (picked === 20) notes.push('crítico natural')\n if (picked === 1) notes.push('falha crítica')\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n const dStr = count === 2 ? `2d20${useAdv ? 'kh1' : 'kl1'}` : '1d20'\n return { rolls: dice, modifier, total, notation: `${dStr}${modStr}`, notes }\n}\n\ninterface AttackParams {\n modifier?: number\n targetAC?: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/**\n * Rolagem de ataque contra AC. Se `targetAC` for fornecido, anota se acertou.\n * Crítico natural 20 sempre acerta; 1 sempre erra (SRD 5.1).\n */\nfunction rollAttack(params: AttackParams): RollResult {\n const result = rollD20(params)\n const d20 = result.rolls[result.rolls.length === 2\n ? (params.advantage && !params.disadvantage ? (result.rolls[0]! >= result.rolls[1]! ? 0 : 1) : (result.rolls[0]! <= result.rolls[1]! ? 0 : 1))\n : 0]!\n const notes = [...(result.notes ?? [])]\n if (params.targetAC !== undefined) {\n const natural20 = d20 === 20\n const natural1 = d20 === 1\n const hit = natural20 || (!natural1 && result.total >= params.targetAC)\n notes.push(hit ? (natural20 ? 'acerto crítico' : 'acertou') : (natural1 ? 'erro crítico' : 'errou'))\n }\n return { ...result, notes }\n}\n\ninterface SaveParams {\n modifier?: number\n dc: number\n advantage?: boolean\n disadvantage?: boolean\n}\n\n/** Saving throw vs DC. Anota success/failure. */\nfunction rollSave(params: SaveParams): RollResult {\n const result = rollD20(params)\n const notes = [...(result.notes ?? [])]\n notes.push(result.total >= params.dc ? 'sucesso' : 'falha')\n return { ...result, notes: notes.concat([`DC ${params.dc}`]) }\n}\n\ninterface DamageParams {\n count: number\n sides: number\n modifier?: number\n critical?: boolean\n}\n\n/**\n * Rolagem de dano: NdM+K, com opção de crítico (rola o dobro dos dados,\n * mantém o modificador uma única vez — SRD 5.1).\n */\nfunction rollDamage({ count, sides, modifier = 0, critical = false }: DamageParams): RollResult {\n const totalDice = critical ? count * 2 : count\n const dice = roll(sides, totalDice)\n const sum = dice.reduce((a, b) => a + b, 0)\n const total = Math.max(0, sum + modifier)\n const modStr = modifier === 0 ? '' : modifier > 0 ? `+${modifier}` : `${modifier}`\n return {\n rolls: dice,\n modifier,\n total,\n notation: `${totalDice}d${sides}${modStr}${critical ? ' (crit)' : ''}`,\n notes: critical ? ['dano crítico — dados dobrados'] : [],\n }\n}\n\ninterface DamageTarget {\n resistance?: string[]\n vulnerability?: string[]\n immunity?: string[]\n}\n\ninterface ApplyDamageInput {\n type?: string\n target?: DamageTarget\n}\n\n/**\n * Reduz dano pelas propriedades do alvo. Ordem (SRD 5.1):\n * 1. Imunidade zera o dano.\n * 2. Resistência metade (arredondar pra baixo).\n * 3. Vulnerabilidade dobra.\n * Se uma criatura tem múltiplas categorias para o mesmo tipo, apenas uma se aplica\n * (mas combinadas com outras categorias podem coexistir — aqui assumimos exclusividade).\n */\nfunction applyDndDamage(incoming: number, ctx: ApplyDamageInput): { final: number; notes: string[] } {\n const t = ctx.target\n const type = ctx.type\n if (!type || !t) return { final: Math.max(0, incoming), notes: [] }\n if (t.immunity?.includes(type)) return { final: 0, notes: [`imune a ${type}`] }\n if (t.resistance?.includes(type)) {\n return { final: Math.floor(incoming / 2), notes: [`resistência a ${type} (metade)`] }\n }\n if (t.vulnerability?.includes(type)) {\n return { final: incoming * 2, notes: [`vulnerabilidade a ${type} (dobro)`] }\n }\n return { final: Math.max(0, incoming), notes: [] }\n}\n\n// ============================================================================\n// Bundle do sistema\n// ============================================================================\n\nconst RULES: SystemRules = {\n roll(kind, params) {\n switch (kind) {\n case 'd20':\n case 'check':\n case 'ability':\n return rollD20(params as unknown as D20Params)\n case 'attack':\n return rollAttack(params as unknown as AttackParams)\n case 'save':\n return rollSave(params as unknown as SaveParams)\n case 'damage':\n return rollDamage(params as unknown as DamageParams)\n default:\n return null\n }\n },\n applyDamage(incoming, target) {\n return applyDndDamage(incoming, target as ApplyDamageInput)\n },\n}\n\n/**\n * Hooks pra `@lippelt/srd-npcgen`. 5e usa proficiency bonus + ability mod\n * (default do npcgen já bate). Só listamos skills canônicas do SRD 5.1;\n * cantripDamageDice fica no default (1/5/11/17 → 1/2/3/4) que já segue 5e.\n */\nconst DND5E_2014_SKILLS = [\n 'acrobatics',\n 'animal-handling',\n 'arcana',\n 'athletics',\n 'deception',\n 'history',\n 'insight',\n 'intimidation',\n 'investigation',\n 'medicine',\n 'nature',\n 'perception',\n 'performance',\n 'persuasion',\n 'religion',\n 'sleight-of-hand',\n 'stealth',\n 'survival',\n] as const\n\nexport const dnd5e2014: System = {\n id: 'dnd5e-2014',\n name: 'Dungeons & Dragons 5e (2014)',\n ruleVersion: 'SRD 5.1',\n attribution:\n 'Contains material from the System Reference Document 5.1 by Wizards of the Coast LLC, licensed under CC-BY 4.0.',\n dicePresets: DICE_PRESETS,\n conditions: CONDITIONS,\n trackerFields: TRACKER_FIELDS,\n rules: RULES,\n npc: {\n skills: DND5E_2014_SKILLS,\n },\n}\n"],"mappings":"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","names":[]}
|