@swrpg-online/dice 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.cjs.js +2 -0
- package/dist/bundle.cjs.js.map +1 -0
- package/dist/bundle.esm.js +2 -0
- package/dist/bundle.esm.js.map +1 -0
- package/dist/bundle.umd.js +2 -0
- package/dist/bundle.umd.js.map +1 -0
- package/dist/cli.js +37 -1
- package/dist/dice.d.ts +14 -0
- package/dist/dice.js +73 -11
- package/dist/hints.js +8 -3
- package/dist/types.d.ts +16 -0
- package/package.json +33 -14
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e="ADVANTAGE",s="THREAT",t="TRIUMPH",a="DESPAIR",r=[{description:"Recover one strain (may be applied more than once).",cost:{[e]:1,[t]:1}},{description:"Add a boost die to the next allied active character's check.",cost:{[e]:1,[t]:1}},{description:"Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.",cost:{[e]:1,[t]:1}},{description:"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).",cost:{[e]:1,[t]:1}},{description:"Activate a weapon quality (Advantage cost may vary).",cost:{[e]:1,[t]:1}},{description:"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.",cost:{[e]:2,[t]:1}},{description:"Add a setback die to the targeted character's next check.",cost:{[e]:2,[t]:1}},{description:"Add a boost die to any allied character's next check, including that of the active character.",cost:{[e]:2,[t]:1}},{description:"Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.",cost:{[e]:3,[t]:1}},{description:"Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.",cost:{[e]:3,[t]:1}},{description:"When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.",cost:{[e]:3,[t]:1}},{description:"Gain + 1 melee or ranged defense until the end of the active character's next turn.",cost:{[e]:3,[t]:1}},{description:"Force the target to drop a melee or ranged weapon they are wielding.",cost:{[e]:3,[t]:1}},{description:"Upgrade the difficulty of the targeted character's next check.",cost:{[t]:1}},{description:"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.",cost:{[t]:1}},{description:"Upgrade any allied character's next check, including that of the current active character.",cost:{[t]:1}},{description:"When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.",cost:{[t]:2}},{description:"The active character suffers 1 strain.",cost:{[s]:1,[a]:1}},{description:"The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.",cost:{[s]:1,[a]:1}},{description:"An opponent may immediately perform one free maneuver in response to the active character's check.",cost:{[s]:2,[a]:1}},{description:"Add a boost die to the targeted character's next check.",cost:{[s]:1,[a]:1}},{description:"The active character or an allied character suffers a setback die on their next action.",cost:{[s]:2,[a]:1}},{description:"The active character falls prone.",cost:{[s]:3,[a]:1}},{description:"The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.",cost:{[s]:3,[a]:1}},{description:"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.",cost:{[a]:1}},{description:"Upgrade the difficulty of an allied character's next check, including that of the current active character.",cost:{[a]:1}},{description:"The tool or melee weapon the character is using becomes damaged.",cost:{[a]:1}}];const i=e=>Math.floor(Math.random()*e)+1,c=e=>{switch(e){case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},d=e=>{switch(e){case 3:case 4:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:case 6:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},n=e=>{switch(e){case 2:case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:return{successes:2,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},h=e=>{switch(e){case 2:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 3:return{successes:0,failures:2,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:case 6:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:return{successes:0,failures:0,advantages:0,threats:2,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:return{successes:0,failures:1,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},o=e=>{switch(e){case 2:case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:return{successes:2,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:case 8:case 9:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 10:case 11:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:1,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},u=e=>{switch(e){case 2:case 3:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:return{successes:0,failures:2,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:case 7:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:case 9:return{successes:0,failures:1,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 10:case 11:return{successes:0,failures:0,advantages:0,threats:2,triumphs:0,despair:0,lightSide:0,darkSide:0};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:1,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},l=e=>{switch(e){case 1:case 2:case 3:case 4:case 5:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:1,darkSide:0};case 6:case 7:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:2,darkSide:0};case 8:case 9:case 10:case 11:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:1};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:2};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}};exports.createCombatCheck=(e,s,t=0)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s),boostDice:Math.max(0,t)}),exports.createDifficultyPool=(e,s=0)=>({difficultyDice:Math.max(0,e),challengeDice:Math.max(0,s)}),exports.createOpposedCheck=(e,s,t,a=0)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s),difficultyDice:Math.max(0,t),challengeDice:Math.max(0,a)}),exports.createSkillCheck=(e,s)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s)}),exports.roll=(e,s)=>{var t,a,p,g,f,m,v,S,k;const y=null!==(t=e.boostDice)&&void 0!==t?t:0,b=null!==(a=e.abilityDice)&&void 0!==a?a:0,x=null!==(p=e.proficiencyDice)&&void 0!==p?p:0,M=null!==(g=e.setBackDice)&&void 0!==g?g:0,w=null!==(f=e.difficultyDice)&&void 0!==f?f:0,D=null!==(m=e.challengeDice)&&void 0!==m?m:0,T=null!==(v=e.forceDice)&&void 0!==v?v:0,$=null!==(S=null==s?void 0:s.maxDicePerType)&&void 0!==S?S:100,A=null!==(k=null==s?void 0:s.maxTotalDice)&&void 0!==k?k:500,C=Math.max(0,Math.min(y,$)),j=Math.max(0,Math.min(b,$)),O=Math.max(0,Math.min(x,$)),P=Math.max(0,Math.min(M,$)),E=Math.max(0,Math.min(w,$)),G=Math.max(0,Math.min(D,$)),I=Math.max(0,Math.min(T,$)),R=y>$||b>$||x>$||M>$||w>$||D>$||T>$,N=C+j+O+P+E+G+I;if(N>A)throw new Error(`Total dice count (${N}) exceeds maximum allowed (${A}). Please reduce the number of dice in your pool.`);if(R&&(null==s?void 0:s.throwOnLimitExceeded)){const e=[];throw y>$&&e.push(`boost: ${y}`),b>$&&e.push(`ability: ${b}`),x>$&&e.push(`proficiency: ${x}`),M>$&&e.push(`setback: ${M}`),w>$&&e.push(`difficulty: ${w}`),D>$&&e.push(`challenge: ${D}`),T>$&&e.push(`force: ${T}`),new Error(`Dice counts exceed per-type limit (${$}): ${e.join(", ")}. Dice counts have been capped to the maximum.`)}const U=[];for(let e=0;e<C;e++){const e=i(6);U.push({type:"boost",roll:e,result:c(e)})}for(let e=0;e<j;e++){const e=i(8);U.push({type:"ability",roll:e,result:n(e)})}for(let e=0;e<O;e++){const e=i(12);U.push({type:"proficiency",roll:e,result:o(e)})}for(let e=0;e<P;e++){const e=i(6);U.push({type:"setback",roll:e,result:d(e)})}for(let e=0;e<E;e++){const e=i(8);U.push({type:"difficulty",roll:e,result:h(e)})}for(let e=0;e<G;e++){const e=i(12);U.push({type:"challenge",roll:e,result:u(e)})}for(let e=0;e<I;e++){const e=i(12);U.push({type:"force",roll:e,result:l(e)})}const q=(e=>{const s=e.reduce((e,s)=>({successes:e.successes+s.successes,failures:e.failures+s.failures,advantages:e.advantages+s.advantages,threats:e.threats+s.threats,triumphs:e.triumphs+s.triumphs,despair:e.despair+s.despair,lightSide:e.lightSide+(s.lightSide||0),darkSide:e.darkSide+(s.darkSide||0)}),{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0});let t=0,a=0;return s.successes===s.failures?(t=0,a=0):s.successes>s.failures?t=s.successes-s.failures:a=s.failures-s.successes,{successes:t,failures:a,advantages:s.advantages,threats:s.threats,triumphs:s.triumphs,despair:s.despair,lightSide:s.lightSide,darkSide:s.darkSide}})(U.map(e=>e.result));if(null==s?void 0:s.hints){const e=r.filter(e=>{const{cost:s}=e;return Object.entries(s).some(([e,s])=>{const t=e.toLowerCase()+"s",a=q[t];return"number"==typeof a&&(void 0!==s&&s>0&&a>=s)})});q.hints=e.map(e=>`${function(e){if(!e.cost||0===Object.keys(e.cost).length)return"No cost";const s=Object.entries(e.cost).filter(([e,s])=>s&&s>0).map(([e,s])=>`${s} ${e.charAt(0).toUpperCase()+e.toLowerCase().slice(1)}${s>1?"s":""}`);return s.length>1?s.join(" OR "):s.length>0?s[0]:"No cost"}(e)} - ${e.description}`)}return{results:U,summary:q}};
|
|
2
|
+
//# sourceMappingURL=bundle.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.cjs.js","sources":["../src/types.ts","../src/hints.ts","../src/dice.ts","../src/pools.ts"],"sourcesContent":["export type DicePool = {\n boostDice?: number;\n abilityDice?: number;\n proficiencyDice?: number;\n setBackDice?: number;\n difficultyDice?: number;\n challengeDice?: number;\n forceDice?: number;\n};\n\nexport type DiceResult = {\n successes: number;\n failures: number;\n advantages: number;\n threats: number;\n triumphs: number;\n despair: number;\n lightSide: number;\n darkSide: number;\n hints?: string[];\n};\n\nexport type DieType =\n | \"boost\"\n | \"ability\"\n | \"proficiency\"\n | \"setback\"\n | \"difficulty\"\n | \"challenge\"\n | \"force\";\n\nexport type DetailedDieResult = {\n type: DieType;\n roll: number;\n result: DiceResult;\n};\n\nexport type RollResult = {\n results: DetailedDieResult[];\n summary: DiceResult;\n};\n\nexport const SYMBOLS = {\n SUCCESS: \"SUCCESS\" as const,\n FAILURE: \"FAILURE\" as const,\n ADVANTAGE: \"ADVANTAGE\" as const,\n THREAT: \"THREAT\" as const,\n TRIUMPH: \"TRIUMPH\" as const,\n DESPAIR: \"DESPAIR\" as const,\n LIGHT: \"LIGHT\" as const,\n DARK: \"DARK\" as const,\n} as const;\n\nexport type Symbol = keyof typeof SYMBOLS;\n\nexport type RollOptions = {\n hints?: boolean;\n /**\n * Maximum number of dice allowed per die type.\n * Default: 100\n */\n maxDicePerType?: number;\n /**\n * Maximum total number of dice allowed in a single roll.\n * Default: 500\n */\n maxTotalDice?: number;\n /**\n * Whether to throw an error when dice limits are exceeded.\n * If false, dice counts will be silently capped to the maximum.\n * Default: false\n */\n throwOnLimitExceeded?: boolean;\n};\n","import { SYMBOLS, type Symbol } from \"./types\";\n\n// 1 advantage or 1 triumph\nconst recoverOneStrain = \"Recover one strain (may be applied more than once).\";\nconst addBoostDieToActiveAlly =\n \"Add a boost die to the next allied active character's check.\";\nconst noticeImportantPoint =\n \"Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.\";\nconst inflictCriticalInjury =\n \"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).\";\nconst activateWeaponQuality =\n \"Activate a weapon quality (Advantage cost may vary).\";\n\n// 2 advantage or 1 triumph\nconst performManeuver =\n \"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.\";\nconst addSetbackDie =\n \"Add a setback die to the targeted character's next check.\";\nconst addBoostDieToAnyAlly =\n \"Add a boost die to any allied character's next check, including that of the active character.\";\n\n// 3 advantage or 1 triumph\nconst negateEnemy =\n \"Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.\";\nconst ignoreEnvironment =\n \"Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.\";\nconst disableOpponent =\n \"When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.\";\nconst gainDefense =\n \"Gain + 1 melee or ranged defense until the end of the active character's next turn.\";\nconst dropWeapon =\n \"Force the target to drop a melee or ranged weapon they are wielding.\";\n\n// 1 triumph\nconst upgradeDifficultyTargetedCharacter =\n \"Upgrade the difficulty of the targeted character's next check.\";\nconst doSomethingVital =\n \"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.\";\nconst upgradeAnyAllyCheck =\n \"Upgrade any allied character's next check, including that of the current active character.\";\n\n// 2 triumph\nconst destroyEquipment =\n \"When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.\";\n\n// 1 threat or 1 despair\nconst sufferStrain = \"The active character suffers 1 strain.\";\nconst loseManeuverBenefit =\n \"The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.\";\n\n// 2 threat or 1 despair\nconst freeManeuver =\n \"An opponent may immediately perform one free maneuver in response to the active character's check.\";\nconst addBoostDieToTargetedCharacter =\n \"Add a boost die to the targeted character's next check.\";\nconst sufferSetback =\n \"The active character or an allied character suffers a setback die on their next action.\";\n\n// 3 threat or 1 despair\nconst fallProne = \"The active character falls prone.\";\nconst gainSignificantAdvantage =\n \"The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.\";\n\n// 1 despair\nconst outOfAmmo =\n \"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.\";\nconst upgradeDifficultyAlliedCharacter =\n \"Upgrade the difficulty of an allied character's next check, including that of the current active character.\";\nconst damagedItem =\n \"The tool or melee weapon the character is using becomes damaged.\";\n\nexport type CostType = {\n [key in Symbol]?: number;\n};\n\ntype Hint = {\n description: string;\n cost: CostType;\n};\n\nexport const hints: Hint[] = [\n // 1 advantage or 1 triumph\n {\n description: recoverOneStrain,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addBoostDieToActiveAlly,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: noticeImportantPoint,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: inflictCriticalInjury,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: activateWeaponQuality,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 2 advantage or 1 triumph\n {\n description: performManeuver,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addSetbackDie,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addBoostDieToAnyAlly,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 3 advantage or 1 triumph\n {\n description: negateEnemy,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: ignoreEnvironment,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: disableOpponent,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: gainDefense,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: dropWeapon,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 1 triumph\n {\n description: upgradeDifficultyTargetedCharacter,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: doSomethingVital,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: upgradeAnyAllyCheck,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 2 triumph\n {\n description: destroyEquipment,\n cost: {\n [SYMBOLS.TRIUMPH]: 2,\n },\n },\n // 1 threat or 1 despair\n {\n description: sufferStrain,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: loseManeuverBenefit,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 2 threat or 1 despair\n {\n description: freeManeuver,\n cost: {\n [SYMBOLS.THREAT]: 2,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: addBoostDieToTargetedCharacter,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: sufferSetback,\n cost: {\n [SYMBOLS.THREAT]: 2,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 3 threat or 1 despair\n {\n description: fallProne,\n cost: {\n [SYMBOLS.THREAT]: 3,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: gainSignificantAdvantage,\n cost: {\n [SYMBOLS.THREAT]: 3,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 1 despair\n {\n description: outOfAmmo,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: upgradeDifficultyAlliedCharacter,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: damagedItem,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n];\n\nexport function hintCostDisplayText(hint: Hint): string {\n if (!hint.cost || Object.keys(hint.cost).length === 0) {\n return \"No cost\";\n }\n const parts = Object.entries(hint.cost)\n .filter(([_, count]) => count && count > 0)\n .map(([symbol, count]) => {\n const symbolName =\n symbol.charAt(0).toUpperCase() + symbol.toLowerCase().slice(1);\n const plural = count > 1 ? \"s\" : \"\";\n return `${count} ${symbolName}${plural}`;\n });\n\n // Use \"OR\" in uppercase for clarity when multiple options exist\n if (parts.length > 1) {\n return parts.join(\" OR \");\n }\n return parts.length > 0 ? parts[0] : \"No cost\";\n}\n","import { hintCostDisplayText, hints } from \"./hints\";\nimport {\n DicePool,\n RollResult,\n DiceResult,\n DetailedDieResult,\n RollOptions,\n} from \"./types\";\n\n// Default dice limits for performance and security\nexport const DEFAULT_MAX_DICE_PER_TYPE = 100;\nexport const DEFAULT_MAX_TOTAL_DICE = 500;\n\nconst rollDie = (sides: number): number =>\n Math.floor(Math.random() * sides) + 1;\n\nconst boostDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst setBackDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 3:\n case 4:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst abilityDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n return {\n successes: 2,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst difficultyDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 3:\n return {\n successes: 0,\n failures: 2,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 2,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst proficiencyDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n return {\n successes: 2,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n case 8:\n case 9:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 1,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst challengeDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n return {\n successes: 0,\n failures: 2,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n case 9:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 2,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 1,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst forceDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 1:\n case 2:\n case 3:\n case 4:\n case 5:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 1,\n darkSide: 0,\n };\n case 6:\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 2,\n darkSide: 0,\n };\n case 8:\n case 9:\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 1,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 2,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst sumResults = (\n results: DiceResult[],\n options?: RollOptions,\n): DiceResult => {\n const sums = results.reduce(\n (acc, curr) => ({\n successes: acc.successes + curr.successes,\n failures: acc.failures + curr.failures,\n advantages: acc.advantages + curr.advantages,\n threats: acc.threats + curr.threats,\n triumphs: acc.triumphs + curr.triumphs,\n despair: acc.despair + curr.despair,\n lightSide: acc.lightSide + (curr.lightSide || 0),\n darkSide: acc.darkSide + (curr.darkSide || 0),\n }),\n {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n },\n );\n\n let netSuccesses = 0;\n let netFailures = 0;\n\n if (sums.successes === sums.failures) {\n netSuccesses = 0;\n netFailures = 0;\n } else if (sums.successes > sums.failures) {\n netSuccesses = sums.successes - sums.failures;\n } else {\n netFailures = sums.failures - sums.successes;\n }\n\n const result: DiceResult = {\n successes: netSuccesses,\n failures: netFailures,\n advantages: sums.advantages,\n threats: sums.threats,\n triumphs: sums.triumphs,\n despair: sums.despair,\n lightSide: sums.lightSide,\n darkSide: sums.darkSide,\n };\n\n return result;\n};\n\n/**\n * Rolls a dice pool and returns the results.\n *\n * @param pool - The dice pool to roll\n * @param options - Optional roll configuration including dice limits\n * @returns The roll results with detailed die information and summary\n * @throws {Error} If dice counts exceed configured limits\n *\n * Default limits:\n * - Max dice per type: 100 (configurable via options.maxDicePerType)\n * - Max total dice: 500 (configurable via options.maxTotalDice)\n */\nexport const roll = (pool: DicePool, options?: RollOptions): RollResult => {\n const boostCount = pool.boostDice ?? 0;\n const abilityCount = pool.abilityDice ?? 0;\n const proficiencyCount = pool.proficiencyDice ?? 0;\n const setBackCount = pool.setBackDice ?? 0;\n const difficultyCount = pool.difficultyDice ?? 0;\n const challengeCount = pool.challengeDice ?? 0;\n const forceCount = pool.forceDice ?? 0;\n\n // Get limits from options or use defaults\n const maxDicePerType = options?.maxDicePerType ?? DEFAULT_MAX_DICE_PER_TYPE;\n const maxTotalDice = options?.maxTotalDice ?? DEFAULT_MAX_TOTAL_DICE;\n\n // Ensure all dice counts are non-negative and apply per-type limits\n const sanitizedPool = {\n boostDice: Math.max(0, Math.min(boostCount, maxDicePerType)),\n abilityDice: Math.max(0, Math.min(abilityCount, maxDicePerType)),\n proficiencyDice: Math.max(0, Math.min(proficiencyCount, maxDicePerType)),\n setBackDice: Math.max(0, Math.min(setBackCount, maxDicePerType)),\n difficultyDice: Math.max(0, Math.min(difficultyCount, maxDicePerType)),\n challengeDice: Math.max(0, Math.min(challengeCount, maxDicePerType)),\n forceDice: Math.max(0, Math.min(forceCount, maxDicePerType)),\n };\n\n // Check if any dice counts exceeded the per-type limit\n const exceedsPerTypeLimit =\n boostCount > maxDicePerType ||\n abilityCount > maxDicePerType ||\n proficiencyCount > maxDicePerType ||\n setBackCount > maxDicePerType ||\n difficultyCount > maxDicePerType ||\n challengeCount > maxDicePerType ||\n forceCount > maxDicePerType;\n\n // Calculate total dice count\n const totalDice =\n sanitizedPool.boostDice +\n sanitizedPool.abilityDice +\n sanitizedPool.proficiencyDice +\n sanitizedPool.setBackDice +\n sanitizedPool.difficultyDice +\n sanitizedPool.challengeDice +\n sanitizedPool.forceDice;\n\n // Check total dice limit\n if (totalDice > maxTotalDice) {\n throw new Error(\n `Total dice count (${totalDice}) exceeds maximum allowed (${maxTotalDice}). ` +\n `Please reduce the number of dice in your pool.`,\n );\n }\n\n // Warn if per-type limits were exceeded (but continue with capped values)\n if (exceedsPerTypeLimit && options?.throwOnLimitExceeded) {\n const exceeded = [];\n if (boostCount > maxDicePerType) exceeded.push(`boost: ${boostCount}`);\n if (abilityCount > maxDicePerType)\n exceeded.push(`ability: ${abilityCount}`);\n if (proficiencyCount > maxDicePerType)\n exceeded.push(`proficiency: ${proficiencyCount}`);\n if (setBackCount > maxDicePerType)\n exceeded.push(`setback: ${setBackCount}`);\n if (difficultyCount > maxDicePerType)\n exceeded.push(`difficulty: ${difficultyCount}`);\n if (challengeCount > maxDicePerType)\n exceeded.push(`challenge: ${challengeCount}`);\n if (forceCount > maxDicePerType) exceeded.push(`force: ${forceCount}`);\n\n throw new Error(\n `Dice counts exceed per-type limit (${maxDicePerType}): ${exceeded.join(\", \")}. ` +\n `Dice counts have been capped to the maximum.`,\n );\n }\n\n const detailedResults: DetailedDieResult[] = [];\n\n // Roll boost dice\n for (let i = 0; i < sanitizedPool.boostDice; i++) {\n const roll = rollDie(6);\n detailedResults.push({\n type: \"boost\",\n roll,\n result: boostDieResult(roll),\n });\n }\n\n // Roll ability dice\n for (let i = 0; i < sanitizedPool.abilityDice; i++) {\n const roll = rollDie(8);\n detailedResults.push({\n type: \"ability\",\n roll,\n result: abilityDieResult(roll),\n });\n }\n\n // Roll proficiency dice\n for (let i = 0; i < sanitizedPool.proficiencyDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"proficiency\",\n roll,\n result: proficiencyDieResult(roll),\n });\n }\n\n // Roll setback dice\n for (let i = 0; i < sanitizedPool.setBackDice; i++) {\n const roll = rollDie(6);\n detailedResults.push({\n type: \"setback\",\n roll,\n result: setBackDieResult(roll),\n });\n }\n\n // Roll difficulty dice\n for (let i = 0; i < sanitizedPool.difficultyDice; i++) {\n const roll = rollDie(8);\n detailedResults.push({\n type: \"difficulty\",\n roll,\n result: difficultyDieResult(roll),\n });\n }\n\n // Roll challenge dice\n for (let i = 0; i < sanitizedPool.challengeDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"challenge\",\n roll,\n result: challengeDieResult(roll),\n });\n }\n\n // Roll force dice\n for (let i = 0; i < sanitizedPool.forceDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"force\",\n roll,\n result: forceDieResult(roll),\n });\n }\n\n const summary = sumResults(detailedResults.map((r) => r.result));\n\n if (options?.hints) {\n const applicableHints = hints.filter((hint) => {\n const { cost } = hint;\n // For OR conditions: at least one option must be fully satisfied\n // Each entry in cost represents an alternative way to pay for the hint\n return Object.entries(cost).some(([symbol, required]) => {\n const summaryKey = (symbol.toLowerCase() + \"s\") as keyof typeof summary;\n const value = summary[summaryKey];\n if (typeof value !== \"number\") return false;\n // Check if we have enough of this symbol type to afford the hint\n return required !== undefined && required > 0 && value >= required;\n });\n });\n summary.hints = applicableHints.map(\n (hint) => `${hintCostDisplayText(hint)} - ${hint.description}`,\n );\n }\n\n return {\n results: detailedResults,\n summary: summary,\n };\n};\n","import { DicePool } from \"./types\";\n\n/**\n * Creates a basic skill check dice pool\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @returns DicePool configured for a basic skill check\n */\nexport const createSkillCheck = (\n ability: number,\n proficiency: number,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n});\n\n/**\n * Creates a combat check dice pool with optional boost die\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @param boost Number of boost (blue) dice\n * @returns DicePool configured for a combat check\n */\nexport const createCombatCheck = (\n ability: number,\n proficiency: number,\n boost: number = 0,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n boostDice: Math.max(0, boost),\n});\n\n/**\n * Creates an opposed check dice pool\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @param difficulty Number of difficulty (purple) dice\n * @param challenge Number of challenge (red) dice\n * @returns DicePool configured for an opposed check\n */\nexport const createOpposedCheck = (\n ability: number,\n proficiency: number,\n difficulty: number,\n challenge: number = 0,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n difficultyDice: Math.max(0, difficulty),\n challengeDice: Math.max(0, challenge),\n});\n\n/**\n * Creates a difficulty check dice pool\n * @param difficulty Number of difficulty (purple) dice\n * @param challenge Number of challenge (red) dice\n * @returns DicePool configured for a pure difficulty check\n */\nexport const createDifficultyPool = (\n difficulty: number,\n challenge: number = 0,\n): DicePool => ({\n difficultyDice: Math.max(0, difficulty),\n challengeDice: Math.max(0, challenge),\n});\n"],"names":["SYMBOLS","hints","description","cost","SYMBOLS_ADVANTAGE","SYMBOLS_TRIUMPH","SYMBOLS_THREAT","SYMBOLS_DESPAIR","rollDie","sides","Math","floor","random","boostDieResult","roll","successes","failures","advantages","threats","triumphs","despair","lightSide","darkSide","setBackDieResult","abilityDieResult","difficultyDieResult","proficiencyDieResult","challengeDieResult","forceDieResult","ability","proficiency","boost","abilityDice","max","proficiencyDice","boostDice","difficulty","challenge","difficultyDice","challengeDice","pool","options","boostCount","_a","abilityCount","_b","proficiencyCount","_c","setBackCount","_d","setBackDice","difficultyCount","_e","challengeCount","_f","forceCount","_g","forceDice","maxDicePerType","_h","maxTotalDice","_j","sanitizedPool","min","exceedsPerTypeLimit","totalDice","Error","throwOnLimitExceeded","exceeded","push","join","detailedResults","i","type","result","summary","results","sums","reduce","acc","curr","netSuccesses","netFailures","sumResults","map","r","applicableHints","filter","hint","Object","entries","some","symbol","required","summaryKey","toLowerCase","value","undefined","keys","length","parts","_","count","charAt","toUpperCase","slice","hintCostDisplayText"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e="ADVANTAGE",s="THREAT",t="TRIUMPH",a="DESPAIR",r=[{description:"Recover one strain (may be applied more than once).",cost:{[e]:1,[t]:1}},{description:"Add a boost die to the next allied active character's check.",cost:{[e]:1,[t]:1}},{description:"Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.",cost:{[e]:1,[t]:1}},{description:"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).",cost:{[e]:1,[t]:1}},{description:"Activate a weapon quality (Advantage cost may vary).",cost:{[e]:1,[t]:1}},{description:"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.",cost:{[e]:2,[t]:1}},{description:"Add a setback die to the targeted character's next check.",cost:{[e]:2,[t]:1}},{description:"Add a boost die to any allied character's next check, including that of the active character.",cost:{[e]:2,[t]:1}},{description:"Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.",cost:{[e]:3,[t]:1}},{description:"Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.",cost:{[e]:3,[t]:1}},{description:"When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.",cost:{[e]:3,[t]:1}},{description:"Gain + 1 melee or ranged defense until the end of the active character's next turn.",cost:{[e]:3,[t]:1}},{description:"Force the target to drop a melee or ranged weapon they are wielding.",cost:{[e]:3,[t]:1}},{description:"Upgrade the difficulty of the targeted character's next check.",cost:{[t]:1}},{description:"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.",cost:{[t]:1}},{description:"Upgrade any allied character's next check, including that of the current active character.",cost:{[t]:1}},{description:"When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.",cost:{[t]:2}},{description:"The active character suffers 1 strain.",cost:{[s]:1,[a]:1}},{description:"The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.",cost:{[s]:1,[a]:1}},{description:"An opponent may immediately perform one free maneuver in response to the active character's check.",cost:{[s]:2,[a]:1}},{description:"Add a boost die to the targeted character's next check.",cost:{[s]:1,[a]:1}},{description:"The active character or an allied character suffers a setback die on their next action.",cost:{[s]:2,[a]:1}},{description:"The active character falls prone.",cost:{[s]:3,[a]:1}},{description:"The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.",cost:{[s]:3,[a]:1}},{description:"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.",cost:{[a]:1}},{description:"Upgrade the difficulty of an allied character's next check, including that of the current active character.",cost:{[a]:1}},{description:"The tool or melee weapon the character is using becomes damaged.",cost:{[a]:1}}];const i=e=>Math.floor(Math.random()*e)+1,c=e=>{switch(e){case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},d=e=>{switch(e){case 3:case 4:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:case 6:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},n=e=>{switch(e){case 2:case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:return{successes:2,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},h=e=>{switch(e){case 2:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 3:return{successes:0,failures:2,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:case 6:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:return{successes:0,failures:0,advantages:0,threats:2,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:return{successes:0,failures:1,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},u=e=>{switch(e){case 2:case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:return{successes:2,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:case 8:case 9:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 10:case 11:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:1,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},o=e=>{switch(e){case 2:case 3:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:return{successes:0,failures:2,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:case 7:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:case 9:return{successes:0,failures:1,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 10:case 11:return{successes:0,failures:0,advantages:0,threats:2,triumphs:0,despair:0,lightSide:0,darkSide:0};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:1,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},l=e=>{switch(e){case 1:case 2:case 3:case 4:case 5:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:1,darkSide:0};case 6:case 7:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:2,darkSide:0};case 8:case 9:case 10:case 11:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:1};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:2};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},p=(e,s)=>{var t,a,p,g,f,m,v,S,k;const y=null!==(t=e.boostDice)&&void 0!==t?t:0,b=null!==(a=e.abilityDice)&&void 0!==a?a:0,x=null!==(p=e.proficiencyDice)&&void 0!==p?p:0,M=null!==(g=e.setBackDice)&&void 0!==g?g:0,w=null!==(f=e.difficultyDice)&&void 0!==f?f:0,D=null!==(m=e.challengeDice)&&void 0!==m?m:0,T=null!==(v=e.forceDice)&&void 0!==v?v:0,$=null!==(S=null==s?void 0:s.maxDicePerType)&&void 0!==S?S:100,A=null!==(k=null==s?void 0:s.maxTotalDice)&&void 0!==k?k:500,j=Math.max(0,Math.min(y,$)),E=Math.max(0,Math.min(b,$)),G=Math.max(0,Math.min(x,$)),I=Math.max(0,Math.min(M,$)),R=Math.max(0,Math.min(w,$)),C=Math.max(0,Math.min(D,$)),N=Math.max(0,Math.min(T,$)),O=y>$||b>$||x>$||M>$||w>$||D>$||T>$,P=j+E+G+I+R+C+N;if(P>A)throw new Error(`Total dice count (${P}) exceeds maximum allowed (${A}). Please reduce the number of dice in your pool.`);if(O&&(null==s?void 0:s.throwOnLimitExceeded)){const e=[];throw y>$&&e.push(`boost: ${y}`),b>$&&e.push(`ability: ${b}`),x>$&&e.push(`proficiency: ${x}`),M>$&&e.push(`setback: ${M}`),w>$&&e.push(`difficulty: ${w}`),D>$&&e.push(`challenge: ${D}`),T>$&&e.push(`force: ${T}`),new Error(`Dice counts exceed per-type limit (${$}): ${e.join(", ")}. Dice counts have been capped to the maximum.`)}const U=[];for(let e=0;e<j;e++){const e=i(6);U.push({type:"boost",roll:e,result:c(e)})}for(let e=0;e<E;e++){const e=i(8);U.push({type:"ability",roll:e,result:n(e)})}for(let e=0;e<G;e++){const e=i(12);U.push({type:"proficiency",roll:e,result:u(e)})}for(let e=0;e<I;e++){const e=i(6);U.push({type:"setback",roll:e,result:d(e)})}for(let e=0;e<R;e++){const e=i(8);U.push({type:"difficulty",roll:e,result:h(e)})}for(let e=0;e<C;e++){const e=i(12);U.push({type:"challenge",roll:e,result:o(e)})}for(let e=0;e<N;e++){const e=i(12);U.push({type:"force",roll:e,result:l(e)})}const q=(e=>{const s=e.reduce((e,s)=>({successes:e.successes+s.successes,failures:e.failures+s.failures,advantages:e.advantages+s.advantages,threats:e.threats+s.threats,triumphs:e.triumphs+s.triumphs,despair:e.despair+s.despair,lightSide:e.lightSide+(s.lightSide||0),darkSide:e.darkSide+(s.darkSide||0)}),{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0});let t=0,a=0;return s.successes===s.failures?(t=0,a=0):s.successes>s.failures?t=s.successes-s.failures:a=s.failures-s.successes,{successes:t,failures:a,advantages:s.advantages,threats:s.threats,triumphs:s.triumphs,despair:s.despair,lightSide:s.lightSide,darkSide:s.darkSide}})(U.map(e=>e.result));if(null==s?void 0:s.hints){const e=r.filter(e=>{const{cost:s}=e;return Object.entries(s).some(([e,s])=>{const t=e.toLowerCase()+"s",a=q[t];return"number"==typeof a&&(void 0!==s&&s>0&&a>=s)})});q.hints=e.map(e=>`${function(e){if(!e.cost||0===Object.keys(e.cost).length)return"No cost";const s=Object.entries(e.cost).filter(([e,s])=>s&&s>0).map(([e,s])=>`${s} ${e.charAt(0).toUpperCase()+e.toLowerCase().slice(1)}${s>1?"s":""}`);return s.length>1?s.join(" OR "):s.length>0?s[0]:"No cost"}(e)} - ${e.description}`)}return{results:U,summary:q}},g=(e,s)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s)}),f=(e,s,t=0)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s),boostDice:Math.max(0,t)}),m=(e,s,t,a=0)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s),difficultyDice:Math.max(0,t),challengeDice:Math.max(0,a)}),v=(e,s=0)=>({difficultyDice:Math.max(0,e),challengeDice:Math.max(0,s)});export{f as createCombatCheck,v as createDifficultyPool,m as createOpposedCheck,g as createSkillCheck,p as roll};
|
|
2
|
+
//# sourceMappingURL=bundle.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.esm.js","sources":["../src/types.ts","../src/hints.ts","../src/dice.ts","../src/pools.ts"],"sourcesContent":["export type DicePool = {\n boostDice?: number;\n abilityDice?: number;\n proficiencyDice?: number;\n setBackDice?: number;\n difficultyDice?: number;\n challengeDice?: number;\n forceDice?: number;\n};\n\nexport type DiceResult = {\n successes: number;\n failures: number;\n advantages: number;\n threats: number;\n triumphs: number;\n despair: number;\n lightSide: number;\n darkSide: number;\n hints?: string[];\n};\n\nexport type DieType =\n | \"boost\"\n | \"ability\"\n | \"proficiency\"\n | \"setback\"\n | \"difficulty\"\n | \"challenge\"\n | \"force\";\n\nexport type DetailedDieResult = {\n type: DieType;\n roll: number;\n result: DiceResult;\n};\n\nexport type RollResult = {\n results: DetailedDieResult[];\n summary: DiceResult;\n};\n\nexport const SYMBOLS = {\n SUCCESS: \"SUCCESS\" as const,\n FAILURE: \"FAILURE\" as const,\n ADVANTAGE: \"ADVANTAGE\" as const,\n THREAT: \"THREAT\" as const,\n TRIUMPH: \"TRIUMPH\" as const,\n DESPAIR: \"DESPAIR\" as const,\n LIGHT: \"LIGHT\" as const,\n DARK: \"DARK\" as const,\n} as const;\n\nexport type Symbol = keyof typeof SYMBOLS;\n\nexport type RollOptions = {\n hints?: boolean;\n /**\n * Maximum number of dice allowed per die type.\n * Default: 100\n */\n maxDicePerType?: number;\n /**\n * Maximum total number of dice allowed in a single roll.\n * Default: 500\n */\n maxTotalDice?: number;\n /**\n * Whether to throw an error when dice limits are exceeded.\n * If false, dice counts will be silently capped to the maximum.\n * Default: false\n */\n throwOnLimitExceeded?: boolean;\n};\n","import { SYMBOLS, type Symbol } from \"./types\";\n\n// 1 advantage or 1 triumph\nconst recoverOneStrain = \"Recover one strain (may be applied more than once).\";\nconst addBoostDieToActiveAlly =\n \"Add a boost die to the next allied active character's check.\";\nconst noticeImportantPoint =\n \"Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.\";\nconst inflictCriticalInjury =\n \"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).\";\nconst activateWeaponQuality =\n \"Activate a weapon quality (Advantage cost may vary).\";\n\n// 2 advantage or 1 triumph\nconst performManeuver =\n \"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.\";\nconst addSetbackDie =\n \"Add a setback die to the targeted character's next check.\";\nconst addBoostDieToAnyAlly =\n \"Add a boost die to any allied character's next check, including that of the active character.\";\n\n// 3 advantage or 1 triumph\nconst negateEnemy =\n \"Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.\";\nconst ignoreEnvironment =\n \"Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.\";\nconst disableOpponent =\n \"When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.\";\nconst gainDefense =\n \"Gain + 1 melee or ranged defense until the end of the active character's next turn.\";\nconst dropWeapon =\n \"Force the target to drop a melee or ranged weapon they are wielding.\";\n\n// 1 triumph\nconst upgradeDifficultyTargetedCharacter =\n \"Upgrade the difficulty of the targeted character's next check.\";\nconst doSomethingVital =\n \"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.\";\nconst upgradeAnyAllyCheck =\n \"Upgrade any allied character's next check, including that of the current active character.\";\n\n// 2 triumph\nconst destroyEquipment =\n \"When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.\";\n\n// 1 threat or 1 despair\nconst sufferStrain = \"The active character suffers 1 strain.\";\nconst loseManeuverBenefit =\n \"The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.\";\n\n// 2 threat or 1 despair\nconst freeManeuver =\n \"An opponent may immediately perform one free maneuver in response to the active character's check.\";\nconst addBoostDieToTargetedCharacter =\n \"Add a boost die to the targeted character's next check.\";\nconst sufferSetback =\n \"The active character or an allied character suffers a setback die on their next action.\";\n\n// 3 threat or 1 despair\nconst fallProne = \"The active character falls prone.\";\nconst gainSignificantAdvantage =\n \"The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.\";\n\n// 1 despair\nconst outOfAmmo =\n \"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.\";\nconst upgradeDifficultyAlliedCharacter =\n \"Upgrade the difficulty of an allied character's next check, including that of the current active character.\";\nconst damagedItem =\n \"The tool or melee weapon the character is using becomes damaged.\";\n\nexport type CostType = {\n [key in Symbol]?: number;\n};\n\ntype Hint = {\n description: string;\n cost: CostType;\n};\n\nexport const hints: Hint[] = [\n // 1 advantage or 1 triumph\n {\n description: recoverOneStrain,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addBoostDieToActiveAlly,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: noticeImportantPoint,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: inflictCriticalInjury,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: activateWeaponQuality,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 2 advantage or 1 triumph\n {\n description: performManeuver,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addSetbackDie,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addBoostDieToAnyAlly,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 3 advantage or 1 triumph\n {\n description: negateEnemy,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: ignoreEnvironment,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: disableOpponent,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: gainDefense,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: dropWeapon,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 1 triumph\n {\n description: upgradeDifficultyTargetedCharacter,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: doSomethingVital,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: upgradeAnyAllyCheck,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 2 triumph\n {\n description: destroyEquipment,\n cost: {\n [SYMBOLS.TRIUMPH]: 2,\n },\n },\n // 1 threat or 1 despair\n {\n description: sufferStrain,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: loseManeuverBenefit,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 2 threat or 1 despair\n {\n description: freeManeuver,\n cost: {\n [SYMBOLS.THREAT]: 2,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: addBoostDieToTargetedCharacter,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: sufferSetback,\n cost: {\n [SYMBOLS.THREAT]: 2,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 3 threat or 1 despair\n {\n description: fallProne,\n cost: {\n [SYMBOLS.THREAT]: 3,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: gainSignificantAdvantage,\n cost: {\n [SYMBOLS.THREAT]: 3,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 1 despair\n {\n description: outOfAmmo,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: upgradeDifficultyAlliedCharacter,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: damagedItem,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n];\n\nexport function hintCostDisplayText(hint: Hint): string {\n if (!hint.cost || Object.keys(hint.cost).length === 0) {\n return \"No cost\";\n }\n const parts = Object.entries(hint.cost)\n .filter(([_, count]) => count && count > 0)\n .map(([symbol, count]) => {\n const symbolName =\n symbol.charAt(0).toUpperCase() + symbol.toLowerCase().slice(1);\n const plural = count > 1 ? \"s\" : \"\";\n return `${count} ${symbolName}${plural}`;\n });\n\n // Use \"OR\" in uppercase for clarity when multiple options exist\n if (parts.length > 1) {\n return parts.join(\" OR \");\n }\n return parts.length > 0 ? parts[0] : \"No cost\";\n}\n","import { hintCostDisplayText, hints } from \"./hints\";\nimport {\n DicePool,\n RollResult,\n DiceResult,\n DetailedDieResult,\n RollOptions,\n} from \"./types\";\n\n// Default dice limits for performance and security\nexport const DEFAULT_MAX_DICE_PER_TYPE = 100;\nexport const DEFAULT_MAX_TOTAL_DICE = 500;\n\nconst rollDie = (sides: number): number =>\n Math.floor(Math.random() * sides) + 1;\n\nconst boostDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst setBackDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 3:\n case 4:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst abilityDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n return {\n successes: 2,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst difficultyDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 3:\n return {\n successes: 0,\n failures: 2,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 2,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst proficiencyDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n return {\n successes: 2,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n case 8:\n case 9:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 1,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst challengeDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n return {\n successes: 0,\n failures: 2,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n case 9:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 2,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 1,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst forceDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 1:\n case 2:\n case 3:\n case 4:\n case 5:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 1,\n darkSide: 0,\n };\n case 6:\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 2,\n darkSide: 0,\n };\n case 8:\n case 9:\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 1,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 2,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst sumResults = (\n results: DiceResult[],\n options?: RollOptions,\n): DiceResult => {\n const sums = results.reduce(\n (acc, curr) => ({\n successes: acc.successes + curr.successes,\n failures: acc.failures + curr.failures,\n advantages: acc.advantages + curr.advantages,\n threats: acc.threats + curr.threats,\n triumphs: acc.triumphs + curr.triumphs,\n despair: acc.despair + curr.despair,\n lightSide: acc.lightSide + (curr.lightSide || 0),\n darkSide: acc.darkSide + (curr.darkSide || 0),\n }),\n {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n },\n );\n\n let netSuccesses = 0;\n let netFailures = 0;\n\n if (sums.successes === sums.failures) {\n netSuccesses = 0;\n netFailures = 0;\n } else if (sums.successes > sums.failures) {\n netSuccesses = sums.successes - sums.failures;\n } else {\n netFailures = sums.failures - sums.successes;\n }\n\n const result: DiceResult = {\n successes: netSuccesses,\n failures: netFailures,\n advantages: sums.advantages,\n threats: sums.threats,\n triumphs: sums.triumphs,\n despair: sums.despair,\n lightSide: sums.lightSide,\n darkSide: sums.darkSide,\n };\n\n return result;\n};\n\n/**\n * Rolls a dice pool and returns the results.\n *\n * @param pool - The dice pool to roll\n * @param options - Optional roll configuration including dice limits\n * @returns The roll results with detailed die information and summary\n * @throws {Error} If dice counts exceed configured limits\n *\n * Default limits:\n * - Max dice per type: 100 (configurable via options.maxDicePerType)\n * - Max total dice: 500 (configurable via options.maxTotalDice)\n */\nexport const roll = (pool: DicePool, options?: RollOptions): RollResult => {\n const boostCount = pool.boostDice ?? 0;\n const abilityCount = pool.abilityDice ?? 0;\n const proficiencyCount = pool.proficiencyDice ?? 0;\n const setBackCount = pool.setBackDice ?? 0;\n const difficultyCount = pool.difficultyDice ?? 0;\n const challengeCount = pool.challengeDice ?? 0;\n const forceCount = pool.forceDice ?? 0;\n\n // Get limits from options or use defaults\n const maxDicePerType = options?.maxDicePerType ?? DEFAULT_MAX_DICE_PER_TYPE;\n const maxTotalDice = options?.maxTotalDice ?? DEFAULT_MAX_TOTAL_DICE;\n\n // Ensure all dice counts are non-negative and apply per-type limits\n const sanitizedPool = {\n boostDice: Math.max(0, Math.min(boostCount, maxDicePerType)),\n abilityDice: Math.max(0, Math.min(abilityCount, maxDicePerType)),\n proficiencyDice: Math.max(0, Math.min(proficiencyCount, maxDicePerType)),\n setBackDice: Math.max(0, Math.min(setBackCount, maxDicePerType)),\n difficultyDice: Math.max(0, Math.min(difficultyCount, maxDicePerType)),\n challengeDice: Math.max(0, Math.min(challengeCount, maxDicePerType)),\n forceDice: Math.max(0, Math.min(forceCount, maxDicePerType)),\n };\n\n // Check if any dice counts exceeded the per-type limit\n const exceedsPerTypeLimit =\n boostCount > maxDicePerType ||\n abilityCount > maxDicePerType ||\n proficiencyCount > maxDicePerType ||\n setBackCount > maxDicePerType ||\n difficultyCount > maxDicePerType ||\n challengeCount > maxDicePerType ||\n forceCount > maxDicePerType;\n\n // Calculate total dice count\n const totalDice =\n sanitizedPool.boostDice +\n sanitizedPool.abilityDice +\n sanitizedPool.proficiencyDice +\n sanitizedPool.setBackDice +\n sanitizedPool.difficultyDice +\n sanitizedPool.challengeDice +\n sanitizedPool.forceDice;\n\n // Check total dice limit\n if (totalDice > maxTotalDice) {\n throw new Error(\n `Total dice count (${totalDice}) exceeds maximum allowed (${maxTotalDice}). ` +\n `Please reduce the number of dice in your pool.`,\n );\n }\n\n // Warn if per-type limits were exceeded (but continue with capped values)\n if (exceedsPerTypeLimit && options?.throwOnLimitExceeded) {\n const exceeded = [];\n if (boostCount > maxDicePerType) exceeded.push(`boost: ${boostCount}`);\n if (abilityCount > maxDicePerType)\n exceeded.push(`ability: ${abilityCount}`);\n if (proficiencyCount > maxDicePerType)\n exceeded.push(`proficiency: ${proficiencyCount}`);\n if (setBackCount > maxDicePerType)\n exceeded.push(`setback: ${setBackCount}`);\n if (difficultyCount > maxDicePerType)\n exceeded.push(`difficulty: ${difficultyCount}`);\n if (challengeCount > maxDicePerType)\n exceeded.push(`challenge: ${challengeCount}`);\n if (forceCount > maxDicePerType) exceeded.push(`force: ${forceCount}`);\n\n throw new Error(\n `Dice counts exceed per-type limit (${maxDicePerType}): ${exceeded.join(\", \")}. ` +\n `Dice counts have been capped to the maximum.`,\n );\n }\n\n const detailedResults: DetailedDieResult[] = [];\n\n // Roll boost dice\n for (let i = 0; i < sanitizedPool.boostDice; i++) {\n const roll = rollDie(6);\n detailedResults.push({\n type: \"boost\",\n roll,\n result: boostDieResult(roll),\n });\n }\n\n // Roll ability dice\n for (let i = 0; i < sanitizedPool.abilityDice; i++) {\n const roll = rollDie(8);\n detailedResults.push({\n type: \"ability\",\n roll,\n result: abilityDieResult(roll),\n });\n }\n\n // Roll proficiency dice\n for (let i = 0; i < sanitizedPool.proficiencyDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"proficiency\",\n roll,\n result: proficiencyDieResult(roll),\n });\n }\n\n // Roll setback dice\n for (let i = 0; i < sanitizedPool.setBackDice; i++) {\n const roll = rollDie(6);\n detailedResults.push({\n type: \"setback\",\n roll,\n result: setBackDieResult(roll),\n });\n }\n\n // Roll difficulty dice\n for (let i = 0; i < sanitizedPool.difficultyDice; i++) {\n const roll = rollDie(8);\n detailedResults.push({\n type: \"difficulty\",\n roll,\n result: difficultyDieResult(roll),\n });\n }\n\n // Roll challenge dice\n for (let i = 0; i < sanitizedPool.challengeDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"challenge\",\n roll,\n result: challengeDieResult(roll),\n });\n }\n\n // Roll force dice\n for (let i = 0; i < sanitizedPool.forceDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"force\",\n roll,\n result: forceDieResult(roll),\n });\n }\n\n const summary = sumResults(detailedResults.map((r) => r.result));\n\n if (options?.hints) {\n const applicableHints = hints.filter((hint) => {\n const { cost } = hint;\n // For OR conditions: at least one option must be fully satisfied\n // Each entry in cost represents an alternative way to pay for the hint\n return Object.entries(cost).some(([symbol, required]) => {\n const summaryKey = (symbol.toLowerCase() + \"s\") as keyof typeof summary;\n const value = summary[summaryKey];\n if (typeof value !== \"number\") return false;\n // Check if we have enough of this symbol type to afford the hint\n return required !== undefined && required > 0 && value >= required;\n });\n });\n summary.hints = applicableHints.map(\n (hint) => `${hintCostDisplayText(hint)} - ${hint.description}`,\n );\n }\n\n return {\n results: detailedResults,\n summary: summary,\n };\n};\n","import { DicePool } from \"./types\";\n\n/**\n * Creates a basic skill check dice pool\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @returns DicePool configured for a basic skill check\n */\nexport const createSkillCheck = (\n ability: number,\n proficiency: number,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n});\n\n/**\n * Creates a combat check dice pool with optional boost die\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @param boost Number of boost (blue) dice\n * @returns DicePool configured for a combat check\n */\nexport const createCombatCheck = (\n ability: number,\n proficiency: number,\n boost: number = 0,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n boostDice: Math.max(0, boost),\n});\n\n/**\n * Creates an opposed check dice pool\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @param difficulty Number of difficulty (purple) dice\n * @param challenge Number of challenge (red) dice\n * @returns DicePool configured for an opposed check\n */\nexport const createOpposedCheck = (\n ability: number,\n proficiency: number,\n difficulty: number,\n challenge: number = 0,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n difficultyDice: Math.max(0, difficulty),\n challengeDice: Math.max(0, challenge),\n});\n\n/**\n * Creates a difficulty check dice pool\n * @param difficulty Number of difficulty (purple) dice\n * @param challenge Number of challenge (red) dice\n * @returns DicePool configured for a pure difficulty check\n */\nexport const createDifficultyPool = (\n difficulty: number,\n challenge: number = 0,\n): DicePool => ({\n difficultyDice: Math.max(0, difficulty),\n challengeDice: Math.max(0, challenge),\n});\n"],"names":["SYMBOLS","hints","description","cost","SYMBOLS_ADVANTAGE","SYMBOLS_TRIUMPH","SYMBOLS_THREAT","SYMBOLS_DESPAIR","rollDie","sides","Math","floor","random","boostDieResult","roll","successes","failures","advantages","threats","triumphs","despair","lightSide","darkSide","setBackDieResult","abilityDieResult","difficultyDieResult","proficiencyDieResult","challengeDieResult","forceDieResult","pool","options","boostCount","_a","boostDice","abilityCount","_b","abilityDice","proficiencyCount","_c","proficiencyDice","setBackCount","_d","setBackDice","difficultyCount","_e","difficultyDice","challengeCount","_f","challengeDice","forceCount","_g","forceDice","maxDicePerType","_h","maxTotalDice","_j","sanitizedPool","max","min","exceedsPerTypeLimit","totalDice","Error","throwOnLimitExceeded","exceeded","push","join","detailedResults","i","type","result","summary","results","sums","reduce","acc","curr","netSuccesses","netFailures","sumResults","map","r","applicableHints","filter","hint","Object","entries","some","symbol","required","summaryKey","toLowerCase","value","undefined","keys","length","parts","_","count","charAt","toUpperCase","slice","hintCostDisplayText","createSkillCheck","ability","proficiency","createCombatCheck","boost","createOpposedCheck","difficulty","challenge","createDifficultyPool"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?s(exports):"function"==typeof define&&define.amd?define(["exports"],s):s((e="undefined"!=typeof globalThis?globalThis:e||self).SwrpgDice={})}(this,function(e){"use strict";const s="ADVANTAGE",t="THREAT",a="TRIUMPH",r="DESPAIR",i=[{description:"Recover one strain (may be applied more than once).",cost:{[s]:1,[a]:1}},{description:"Add a boost die to the next allied active character's check.",cost:{[s]:1,[a]:1}},{description:"Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.",cost:{[s]:1,[a]:1}},{description:"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).",cost:{[s]:1,[a]:1}},{description:"Activate a weapon quality (Advantage cost may vary).",cost:{[s]:1,[a]:1}},{description:"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.",cost:{[s]:2,[a]:1}},{description:"Add a setback die to the targeted character's next check.",cost:{[s]:2,[a]:1}},{description:"Add a boost die to any allied character's next check, including that of the active character.",cost:{[s]:2,[a]:1}},{description:"Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.",cost:{[s]:3,[a]:1}},{description:"Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.",cost:{[s]:3,[a]:1}},{description:"When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.",cost:{[s]:3,[a]:1}},{description:"Gain + 1 melee or ranged defense until the end of the active character's next turn.",cost:{[s]:3,[a]:1}},{description:"Force the target to drop a melee or ranged weapon they are wielding.",cost:{[s]:3,[a]:1}},{description:"Upgrade the difficulty of the targeted character's next check.",cost:{[a]:1}},{description:"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.",cost:{[a]:1}},{description:"Upgrade any allied character's next check, including that of the current active character.",cost:{[a]:1}},{description:"When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.",cost:{[a]:2}},{description:"The active character suffers 1 strain.",cost:{[t]:1,[r]:1}},{description:"The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.",cost:{[t]:1,[r]:1}},{description:"An opponent may immediately perform one free maneuver in response to the active character's check.",cost:{[t]:2,[r]:1}},{description:"Add a boost die to the targeted character's next check.",cost:{[t]:1,[r]:1}},{description:"The active character or an allied character suffers a setback die on their next action.",cost:{[t]:2,[r]:1}},{description:"The active character falls prone.",cost:{[t]:3,[r]:1}},{description:"The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.",cost:{[t]:3,[r]:1}},{description:"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.",cost:{[r]:1}},{description:"Upgrade the difficulty of an allied character's next check, including that of the current active character.",cost:{[r]:1}},{description:"The tool or melee weapon the character is using becomes damaged.",cost:{[r]:1}}];const c=e=>Math.floor(Math.random()*e)+1,d=e=>{switch(e){case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},n=e=>{switch(e){case 3:case 4:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:case 6:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},h=e=>{switch(e){case 2:case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:return{successes:2,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 5:case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},o=e=>{switch(e){case 2:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 3:return{successes:0,failures:2,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:case 6:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:return{successes:0,failures:0,advantages:0,threats:2,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:return{successes:0,failures:1,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},u=e=>{switch(e){case 2:case 3:return{successes:1,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:return{successes:2,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:return{successes:0,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 7:case 8:case 9:return{successes:1,failures:0,advantages:1,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 10:case 11:return{successes:0,failures:0,advantages:2,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:1,despair:0,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},l=e=>{switch(e){case 2:case 3:return{successes:0,failures:1,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 4:case 5:return{successes:0,failures:2,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0};case 6:case 7:return{successes:0,failures:0,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 8:case 9:return{successes:0,failures:1,advantages:0,threats:1,triumphs:0,despair:0,lightSide:0,darkSide:0};case 10:case 11:return{successes:0,failures:0,advantages:0,threats:2,triumphs:0,despair:0,lightSide:0,darkSide:0};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:1,lightSide:0,darkSide:0};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}},p=e=>{switch(e){case 1:case 2:case 3:case 4:case 5:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:1,darkSide:0};case 6:case 7:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:2,darkSide:0};case 8:case 9:case 10:case 11:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:1};case 12:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:2};default:return{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0}}};e.createCombatCheck=(e,s,t=0)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s),boostDice:Math.max(0,t)}),e.createDifficultyPool=(e,s=0)=>({difficultyDice:Math.max(0,e),challengeDice:Math.max(0,s)}),e.createOpposedCheck=(e,s,t,a=0)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s),difficultyDice:Math.max(0,t),challengeDice:Math.max(0,a)}),e.createSkillCheck=(e,s)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,s)}),e.roll=(e,s)=>{var t,a,r,g,f,m,v,S,k;const y=null!==(t=e.boostDice)&&void 0!==t?t:0,b=null!==(a=e.abilityDice)&&void 0!==a?a:0,x=null!==(r=e.proficiencyDice)&&void 0!==r?r:0,M=null!==(g=e.setBackDice)&&void 0!==g?g:0,w=null!==(f=e.difficultyDice)&&void 0!==f?f:0,D=null!==(m=e.challengeDice)&&void 0!==m?m:0,T=null!==(v=e.forceDice)&&void 0!==v?v:0,$=null!==(S=null==s?void 0:s.maxDicePerType)&&void 0!==S?S:100,A=null!==(k=null==s?void 0:s.maxTotalDice)&&void 0!==k?k:500,j=Math.max(0,Math.min(y,$)),C=Math.max(0,Math.min(b,$)),O=Math.max(0,Math.min(x,$)),P=Math.max(0,Math.min(M,$)),E=Math.max(0,Math.min(w,$)),G=Math.max(0,Math.min(D,$)),I=Math.max(0,Math.min(T,$)),R=y>$||b>$||x>$||M>$||w>$||D>$||T>$,N=j+C+O+P+E+G+I;if(N>A)throw new Error(`Total dice count (${N}) exceeds maximum allowed (${A}). Please reduce the number of dice in your pool.`);if(R&&(null==s?void 0:s.throwOnLimitExceeded)){const e=[];throw y>$&&e.push(`boost: ${y}`),b>$&&e.push(`ability: ${b}`),x>$&&e.push(`proficiency: ${x}`),M>$&&e.push(`setback: ${M}`),w>$&&e.push(`difficulty: ${w}`),D>$&&e.push(`challenge: ${D}`),T>$&&e.push(`force: ${T}`),new Error(`Dice counts exceed per-type limit (${$}): ${e.join(", ")}. Dice counts have been capped to the maximum.`)}const U=[];for(let e=0;e<j;e++){const e=c(6);U.push({type:"boost",roll:e,result:d(e)})}for(let e=0;e<C;e++){const e=c(8);U.push({type:"ability",roll:e,result:h(e)})}for(let e=0;e<O;e++){const e=c(12);U.push({type:"proficiency",roll:e,result:u(e)})}for(let e=0;e<P;e++){const e=c(6);U.push({type:"setback",roll:e,result:n(e)})}for(let e=0;e<E;e++){const e=c(8);U.push({type:"difficulty",roll:e,result:o(e)})}for(let e=0;e<G;e++){const e=c(12);U.push({type:"challenge",roll:e,result:l(e)})}for(let e=0;e<I;e++){const e=c(12);U.push({type:"force",roll:e,result:p(e)})}const q=(e=>{const s=e.reduce((e,s)=>({successes:e.successes+s.successes,failures:e.failures+s.failures,advantages:e.advantages+s.advantages,threats:e.threats+s.threats,triumphs:e.triumphs+s.triumphs,despair:e.despair+s.despair,lightSide:e.lightSide+(s.lightSide||0),darkSide:e.darkSide+(s.darkSide||0)}),{successes:0,failures:0,advantages:0,threats:0,triumphs:0,despair:0,lightSide:0,darkSide:0});let t=0,a=0;return s.successes===s.failures?(t=0,a=0):s.successes>s.failures?t=s.successes-s.failures:a=s.failures-s.successes,{successes:t,failures:a,advantages:s.advantages,threats:s.threats,triumphs:s.triumphs,despair:s.despair,lightSide:s.lightSide,darkSide:s.darkSide}})(U.map(e=>e.result));if(null==s?void 0:s.hints){const e=i.filter(e=>{const{cost:s}=e;return Object.entries(s).some(([e,s])=>{const t=e.toLowerCase()+"s",a=q[t];return"number"==typeof a&&(void 0!==s&&s>0&&a>=s)})});q.hints=e.map(e=>`${function(e){if(!e.cost||0===Object.keys(e.cost).length)return"No cost";const s=Object.entries(e.cost).filter(([e,s])=>s&&s>0).map(([e,s])=>`${s} ${e.charAt(0).toUpperCase()+e.toLowerCase().slice(1)}${s>1?"s":""}`);return s.length>1?s.join(" OR "):s.length>0?s[0]:"No cost"}(e)} - ${e.description}`)}return{results:U,summary:q}},Object.defineProperty(e,"__esModule",{value:!0})});
|
|
2
|
+
//# sourceMappingURL=bundle.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.umd.js","sources":["../src/types.ts","../src/hints.ts","../src/dice.ts","../src/pools.ts"],"sourcesContent":["export type DicePool = {\n boostDice?: number;\n abilityDice?: number;\n proficiencyDice?: number;\n setBackDice?: number;\n difficultyDice?: number;\n challengeDice?: number;\n forceDice?: number;\n};\n\nexport type DiceResult = {\n successes: number;\n failures: number;\n advantages: number;\n threats: number;\n triumphs: number;\n despair: number;\n lightSide: number;\n darkSide: number;\n hints?: string[];\n};\n\nexport type DieType =\n | \"boost\"\n | \"ability\"\n | \"proficiency\"\n | \"setback\"\n | \"difficulty\"\n | \"challenge\"\n | \"force\";\n\nexport type DetailedDieResult = {\n type: DieType;\n roll: number;\n result: DiceResult;\n};\n\nexport type RollResult = {\n results: DetailedDieResult[];\n summary: DiceResult;\n};\n\nexport const SYMBOLS = {\n SUCCESS: \"SUCCESS\" as const,\n FAILURE: \"FAILURE\" as const,\n ADVANTAGE: \"ADVANTAGE\" as const,\n THREAT: \"THREAT\" as const,\n TRIUMPH: \"TRIUMPH\" as const,\n DESPAIR: \"DESPAIR\" as const,\n LIGHT: \"LIGHT\" as const,\n DARK: \"DARK\" as const,\n} as const;\n\nexport type Symbol = keyof typeof SYMBOLS;\n\nexport type RollOptions = {\n hints?: boolean;\n /**\n * Maximum number of dice allowed per die type.\n * Default: 100\n */\n maxDicePerType?: number;\n /**\n * Maximum total number of dice allowed in a single roll.\n * Default: 500\n */\n maxTotalDice?: number;\n /**\n * Whether to throw an error when dice limits are exceeded.\n * If false, dice counts will be silently capped to the maximum.\n * Default: false\n */\n throwOnLimitExceeded?: boolean;\n};\n","import { SYMBOLS, type Symbol } from \"./types\";\n\n// 1 advantage or 1 triumph\nconst recoverOneStrain = \"Recover one strain (may be applied more than once).\";\nconst addBoostDieToActiveAlly =\n \"Add a boost die to the next allied active character's check.\";\nconst noticeImportantPoint =\n \"Notice a single important point in the ongoing conflict, such as the location of a blast door's control panel or a weak point on an attack speeder.\";\nconst inflictCriticalInjury =\n \"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).\";\nconst activateWeaponQuality =\n \"Activate a weapon quality (Advantage cost may vary).\";\n\n// 2 advantage or 1 triumph\nconst performManeuver =\n \"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.\";\nconst addSetbackDie =\n \"Add a setback die to the targeted character's next check.\";\nconst addBoostDieToAnyAlly =\n \"Add a boost die to any allied character's next check, including that of the active character.\";\n\n// 3 advantage or 1 triumph\nconst negateEnemy =\n \"Negate the targeted enemy's defensive bonuses (such as the defense gained from cover, equipment, or performing the Guarded Stance maneuver) util the end of the current round.\";\nconst ignoreEnvironment =\n \"Ignore penalizing environmental effects such as inclement weather, zero gravity, or similar circumstances until the end of the active character's next turn.\";\nconst disableOpponent =\n \"When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain. This could include hobbling them temporarily with a shot to the leg, or disabling their comlink. This should be agreed upon by the player and the GM, and the effects are up to the GM (although Table 6-10: Critical Injury Result is a god resource to consult for possible effects). The effects should be temporary and not too excessive.\";\nconst gainDefense =\n \"Gain + 1 melee or ranged defense until the end of the active character's next turn.\";\nconst dropWeapon =\n \"Force the target to drop a melee or ranged weapon they are wielding.\";\n\n// 1 triumph\nconst upgradeDifficultyTargetedCharacter =\n \"Upgrade the difficulty of the targeted character's next check.\";\nconst doSomethingVital =\n \"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.\";\nconst upgradeAnyAllyCheck =\n \"Upgrade any allied character's next check, including that of the current active character.\";\n\n// 2 triumph\nconst destroyEquipment =\n \"When dealing damage to a target, have the attack destroy a piece of equipment the target is using, such as blowing up his blaster or destroying a personal shield generator.\";\n\n// 1 threat or 1 despair\nconst sufferStrain = \"The active character suffers 1 strain.\";\nconst loseManeuverBenefit =\n \"The active character loses the benefits of a prior maneuver (such as from taking cover or assuming a Guarded Stance) until they perform the maneuver again.\";\n\n// 2 threat or 1 despair\nconst freeManeuver =\n \"An opponent may immediately perform one free maneuver in response to the active character's check.\";\nconst addBoostDieToTargetedCharacter =\n \"Add a boost die to the targeted character's next check.\";\nconst sufferSetback =\n \"The active character or an allied character suffers a setback die on their next action.\";\n\n// 3 threat or 1 despair\nconst fallProne = \"The active character falls prone.\";\nconst gainSignificantAdvantage =\n \"The active character grants the enemy a significant advantage in the ongoing encounter, such as accidentally blasting the controls to a bridge the active character was planning to use for their escape.\";\n\n// 1 despair\nconst outOfAmmo =\n \"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.\";\nconst upgradeDifficultyAlliedCharacter =\n \"Upgrade the difficulty of an allied character's next check, including that of the current active character.\";\nconst damagedItem =\n \"The tool or melee weapon the character is using becomes damaged.\";\n\nexport type CostType = {\n [key in Symbol]?: number;\n};\n\ntype Hint = {\n description: string;\n cost: CostType;\n};\n\nexport const hints: Hint[] = [\n // 1 advantage or 1 triumph\n {\n description: recoverOneStrain,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addBoostDieToActiveAlly,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: noticeImportantPoint,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: inflictCriticalInjury,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: activateWeaponQuality,\n cost: {\n [SYMBOLS.ADVANTAGE]: 1,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 2 advantage or 1 triumph\n {\n description: performManeuver,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addSetbackDie,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: addBoostDieToAnyAlly,\n cost: {\n [SYMBOLS.ADVANTAGE]: 2,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 3 advantage or 1 triumph\n {\n description: negateEnemy,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: ignoreEnvironment,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: disableOpponent,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: gainDefense,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: dropWeapon,\n cost: {\n [SYMBOLS.ADVANTAGE]: 3,\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 1 triumph\n {\n description: upgradeDifficultyTargetedCharacter,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: doSomethingVital,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n {\n description: upgradeAnyAllyCheck,\n cost: {\n [SYMBOLS.TRIUMPH]: 1,\n },\n },\n // 2 triumph\n {\n description: destroyEquipment,\n cost: {\n [SYMBOLS.TRIUMPH]: 2,\n },\n },\n // 1 threat or 1 despair\n {\n description: sufferStrain,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: loseManeuverBenefit,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 2 threat or 1 despair\n {\n description: freeManeuver,\n cost: {\n [SYMBOLS.THREAT]: 2,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: addBoostDieToTargetedCharacter,\n cost: {\n [SYMBOLS.THREAT]: 1,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: sufferSetback,\n cost: {\n [SYMBOLS.THREAT]: 2,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 3 threat or 1 despair\n {\n description: fallProne,\n cost: {\n [SYMBOLS.THREAT]: 3,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: gainSignificantAdvantage,\n cost: {\n [SYMBOLS.THREAT]: 3,\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n // 1 despair\n {\n description: outOfAmmo,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: upgradeDifficultyAlliedCharacter,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n {\n description: damagedItem,\n cost: {\n [SYMBOLS.DESPAIR]: 1,\n },\n },\n];\n\nexport function hintCostDisplayText(hint: Hint): string {\n if (!hint.cost || Object.keys(hint.cost).length === 0) {\n return \"No cost\";\n }\n const parts = Object.entries(hint.cost)\n .filter(([_, count]) => count && count > 0)\n .map(([symbol, count]) => {\n const symbolName =\n symbol.charAt(0).toUpperCase() + symbol.toLowerCase().slice(1);\n const plural = count > 1 ? \"s\" : \"\";\n return `${count} ${symbolName}${plural}`;\n });\n\n // Use \"OR\" in uppercase for clarity when multiple options exist\n if (parts.length > 1) {\n return parts.join(\" OR \");\n }\n return parts.length > 0 ? parts[0] : \"No cost\";\n}\n","import { hintCostDisplayText, hints } from \"./hints\";\nimport {\n DicePool,\n RollResult,\n DiceResult,\n DetailedDieResult,\n RollOptions,\n} from \"./types\";\n\n// Default dice limits for performance and security\nexport const DEFAULT_MAX_DICE_PER_TYPE = 100;\nexport const DEFAULT_MAX_TOTAL_DICE = 500;\n\nconst rollDie = (sides: number): number =>\n Math.floor(Math.random() * sides) + 1;\n\nconst boostDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst setBackDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 3:\n case 4:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst abilityDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n return {\n successes: 2,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst difficultyDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 3:\n return {\n successes: 0,\n failures: 2,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 2,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst proficiencyDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 1,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n return {\n successes: 2,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n return {\n successes: 0,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 7:\n case 8:\n case 9:\n return {\n successes: 1,\n failures: 0,\n advantages: 1,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 2,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 1,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst challengeDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 2:\n case 3:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 4:\n case 5:\n return {\n successes: 0,\n failures: 2,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 6:\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 8:\n case 9:\n return {\n successes: 0,\n failures: 1,\n advantages: 0,\n threats: 1,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 2,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 1,\n lightSide: 0,\n darkSide: 0,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst forceDieResult = (roll: number): DiceResult => {\n switch (roll) {\n case 1:\n case 2:\n case 3:\n case 4:\n case 5:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 1,\n darkSide: 0,\n };\n case 6:\n case 7:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 2,\n darkSide: 0,\n };\n case 8:\n case 9:\n case 10:\n case 11:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 1,\n };\n case 12:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 2,\n };\n default:\n return {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n };\n }\n};\n\nconst sumResults = (\n results: DiceResult[],\n options?: RollOptions,\n): DiceResult => {\n const sums = results.reduce(\n (acc, curr) => ({\n successes: acc.successes + curr.successes,\n failures: acc.failures + curr.failures,\n advantages: acc.advantages + curr.advantages,\n threats: acc.threats + curr.threats,\n triumphs: acc.triumphs + curr.triumphs,\n despair: acc.despair + curr.despair,\n lightSide: acc.lightSide + (curr.lightSide || 0),\n darkSide: acc.darkSide + (curr.darkSide || 0),\n }),\n {\n successes: 0,\n failures: 0,\n advantages: 0,\n threats: 0,\n triumphs: 0,\n despair: 0,\n lightSide: 0,\n darkSide: 0,\n },\n );\n\n let netSuccesses = 0;\n let netFailures = 0;\n\n if (sums.successes === sums.failures) {\n netSuccesses = 0;\n netFailures = 0;\n } else if (sums.successes > sums.failures) {\n netSuccesses = sums.successes - sums.failures;\n } else {\n netFailures = sums.failures - sums.successes;\n }\n\n const result: DiceResult = {\n successes: netSuccesses,\n failures: netFailures,\n advantages: sums.advantages,\n threats: sums.threats,\n triumphs: sums.triumphs,\n despair: sums.despair,\n lightSide: sums.lightSide,\n darkSide: sums.darkSide,\n };\n\n return result;\n};\n\n/**\n * Rolls a dice pool and returns the results.\n *\n * @param pool - The dice pool to roll\n * @param options - Optional roll configuration including dice limits\n * @returns The roll results with detailed die information and summary\n * @throws {Error} If dice counts exceed configured limits\n *\n * Default limits:\n * - Max dice per type: 100 (configurable via options.maxDicePerType)\n * - Max total dice: 500 (configurable via options.maxTotalDice)\n */\nexport const roll = (pool: DicePool, options?: RollOptions): RollResult => {\n const boostCount = pool.boostDice ?? 0;\n const abilityCount = pool.abilityDice ?? 0;\n const proficiencyCount = pool.proficiencyDice ?? 0;\n const setBackCount = pool.setBackDice ?? 0;\n const difficultyCount = pool.difficultyDice ?? 0;\n const challengeCount = pool.challengeDice ?? 0;\n const forceCount = pool.forceDice ?? 0;\n\n // Get limits from options or use defaults\n const maxDicePerType = options?.maxDicePerType ?? DEFAULT_MAX_DICE_PER_TYPE;\n const maxTotalDice = options?.maxTotalDice ?? DEFAULT_MAX_TOTAL_DICE;\n\n // Ensure all dice counts are non-negative and apply per-type limits\n const sanitizedPool = {\n boostDice: Math.max(0, Math.min(boostCount, maxDicePerType)),\n abilityDice: Math.max(0, Math.min(abilityCount, maxDicePerType)),\n proficiencyDice: Math.max(0, Math.min(proficiencyCount, maxDicePerType)),\n setBackDice: Math.max(0, Math.min(setBackCount, maxDicePerType)),\n difficultyDice: Math.max(0, Math.min(difficultyCount, maxDicePerType)),\n challengeDice: Math.max(0, Math.min(challengeCount, maxDicePerType)),\n forceDice: Math.max(0, Math.min(forceCount, maxDicePerType)),\n };\n\n // Check if any dice counts exceeded the per-type limit\n const exceedsPerTypeLimit =\n boostCount > maxDicePerType ||\n abilityCount > maxDicePerType ||\n proficiencyCount > maxDicePerType ||\n setBackCount > maxDicePerType ||\n difficultyCount > maxDicePerType ||\n challengeCount > maxDicePerType ||\n forceCount > maxDicePerType;\n\n // Calculate total dice count\n const totalDice =\n sanitizedPool.boostDice +\n sanitizedPool.abilityDice +\n sanitizedPool.proficiencyDice +\n sanitizedPool.setBackDice +\n sanitizedPool.difficultyDice +\n sanitizedPool.challengeDice +\n sanitizedPool.forceDice;\n\n // Check total dice limit\n if (totalDice > maxTotalDice) {\n throw new Error(\n `Total dice count (${totalDice}) exceeds maximum allowed (${maxTotalDice}). ` +\n `Please reduce the number of dice in your pool.`,\n );\n }\n\n // Warn if per-type limits were exceeded (but continue with capped values)\n if (exceedsPerTypeLimit && options?.throwOnLimitExceeded) {\n const exceeded = [];\n if (boostCount > maxDicePerType) exceeded.push(`boost: ${boostCount}`);\n if (abilityCount > maxDicePerType)\n exceeded.push(`ability: ${abilityCount}`);\n if (proficiencyCount > maxDicePerType)\n exceeded.push(`proficiency: ${proficiencyCount}`);\n if (setBackCount > maxDicePerType)\n exceeded.push(`setback: ${setBackCount}`);\n if (difficultyCount > maxDicePerType)\n exceeded.push(`difficulty: ${difficultyCount}`);\n if (challengeCount > maxDicePerType)\n exceeded.push(`challenge: ${challengeCount}`);\n if (forceCount > maxDicePerType) exceeded.push(`force: ${forceCount}`);\n\n throw new Error(\n `Dice counts exceed per-type limit (${maxDicePerType}): ${exceeded.join(\", \")}. ` +\n `Dice counts have been capped to the maximum.`,\n );\n }\n\n const detailedResults: DetailedDieResult[] = [];\n\n // Roll boost dice\n for (let i = 0; i < sanitizedPool.boostDice; i++) {\n const roll = rollDie(6);\n detailedResults.push({\n type: \"boost\",\n roll,\n result: boostDieResult(roll),\n });\n }\n\n // Roll ability dice\n for (let i = 0; i < sanitizedPool.abilityDice; i++) {\n const roll = rollDie(8);\n detailedResults.push({\n type: \"ability\",\n roll,\n result: abilityDieResult(roll),\n });\n }\n\n // Roll proficiency dice\n for (let i = 0; i < sanitizedPool.proficiencyDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"proficiency\",\n roll,\n result: proficiencyDieResult(roll),\n });\n }\n\n // Roll setback dice\n for (let i = 0; i < sanitizedPool.setBackDice; i++) {\n const roll = rollDie(6);\n detailedResults.push({\n type: \"setback\",\n roll,\n result: setBackDieResult(roll),\n });\n }\n\n // Roll difficulty dice\n for (let i = 0; i < sanitizedPool.difficultyDice; i++) {\n const roll = rollDie(8);\n detailedResults.push({\n type: \"difficulty\",\n roll,\n result: difficultyDieResult(roll),\n });\n }\n\n // Roll challenge dice\n for (let i = 0; i < sanitizedPool.challengeDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"challenge\",\n roll,\n result: challengeDieResult(roll),\n });\n }\n\n // Roll force dice\n for (let i = 0; i < sanitizedPool.forceDice; i++) {\n const roll = rollDie(12);\n detailedResults.push({\n type: \"force\",\n roll,\n result: forceDieResult(roll),\n });\n }\n\n const summary = sumResults(detailedResults.map((r) => r.result));\n\n if (options?.hints) {\n const applicableHints = hints.filter((hint) => {\n const { cost } = hint;\n // For OR conditions: at least one option must be fully satisfied\n // Each entry in cost represents an alternative way to pay for the hint\n return Object.entries(cost).some(([symbol, required]) => {\n const summaryKey = (symbol.toLowerCase() + \"s\") as keyof typeof summary;\n const value = summary[summaryKey];\n if (typeof value !== \"number\") return false;\n // Check if we have enough of this symbol type to afford the hint\n return required !== undefined && required > 0 && value >= required;\n });\n });\n summary.hints = applicableHints.map(\n (hint) => `${hintCostDisplayText(hint)} - ${hint.description}`,\n );\n }\n\n return {\n results: detailedResults,\n summary: summary,\n };\n};\n","import { DicePool } from \"./types\";\n\n/**\n * Creates a basic skill check dice pool\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @returns DicePool configured for a basic skill check\n */\nexport const createSkillCheck = (\n ability: number,\n proficiency: number,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n});\n\n/**\n * Creates a combat check dice pool with optional boost die\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @param boost Number of boost (blue) dice\n * @returns DicePool configured for a combat check\n */\nexport const createCombatCheck = (\n ability: number,\n proficiency: number,\n boost: number = 0,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n boostDice: Math.max(0, boost),\n});\n\n/**\n * Creates an opposed check dice pool\n * @param ability Number of ability (green) dice\n * @param proficiency Number of proficiency (yellow) dice\n * @param difficulty Number of difficulty (purple) dice\n * @param challenge Number of challenge (red) dice\n * @returns DicePool configured for an opposed check\n */\nexport const createOpposedCheck = (\n ability: number,\n proficiency: number,\n difficulty: number,\n challenge: number = 0,\n): DicePool => ({\n abilityDice: Math.max(0, ability),\n proficiencyDice: Math.max(0, proficiency),\n difficultyDice: Math.max(0, difficulty),\n challengeDice: Math.max(0, challenge),\n});\n\n/**\n * Creates a difficulty check dice pool\n * @param difficulty Number of difficulty (purple) dice\n * @param challenge Number of challenge (red) dice\n * @returns DicePool configured for a pure difficulty check\n */\nexport const createDifficultyPool = (\n difficulty: number,\n challenge: number = 0,\n): DicePool => ({\n difficultyDice: Math.max(0, difficulty),\n challengeDice: Math.max(0, challenge),\n});\n"],"names":["SYMBOLS","hints","description","cost","SYMBOLS_ADVANTAGE","SYMBOLS_TRIUMPH","SYMBOLS_THREAT","SYMBOLS_DESPAIR","rollDie","sides","Math","floor","random","boostDieResult","roll","successes","failures","advantages","threats","triumphs","despair","lightSide","darkSide","setBackDieResult","abilityDieResult","difficultyDieResult","proficiencyDieResult","challengeDieResult","forceDieResult","ability","proficiency","boost","abilityDice","max","proficiencyDice","boostDice","difficulty","challenge","difficultyDice","challengeDice","pool","options","boostCount","_a","abilityCount","_b","proficiencyCount","_c","setBackCount","_d","setBackDice","difficultyCount","_e","challengeCount","_f","forceCount","_g","forceDice","maxDicePerType","_h","maxTotalDice","_j","sanitizedPool","min","exceedsPerTypeLimit","totalDice","Error","throwOnLimitExceeded","exceeded","push","join","detailedResults","i","type","result","summary","results","sums","reduce","acc","curr","netSuccesses","netFailures","sumResults","map","r","applicableHints","filter","hint","Object","entries","some","symbol","required","summaryKey","toLowerCase","value","undefined","keys","length","parts","_","count","charAt","toUpperCase","slice","hintCostDisplayText"],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -15,10 +15,31 @@ function parseDiceNotation(input) {
|
|
|
15
15
|
challengeDice: 0,
|
|
16
16
|
forceDice: 0,
|
|
17
17
|
};
|
|
18
|
-
const
|
|
18
|
+
const warnings = [];
|
|
19
|
+
const parts = input
|
|
20
|
+
.toLowerCase()
|
|
21
|
+
.trim()
|
|
22
|
+
.split(" ")
|
|
23
|
+
.filter((p) => p.length > 0);
|
|
19
24
|
for (const part of parts) {
|
|
20
25
|
const count = parseInt(part);
|
|
26
|
+
// Check if parseInt returned NaN
|
|
27
|
+
if (isNaN(count)) {
|
|
28
|
+
warnings.push(`Invalid dice notation: "${part}" - number not found`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
// Check for non-integer values
|
|
32
|
+
if (part.includes(".") || part.includes(",")) {
|
|
33
|
+
warnings.push(`Invalid dice notation: "${part}" - dice count must be a whole number`);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
21
36
|
const color = part.slice(String(count).length).toLowerCase();
|
|
37
|
+
// Skip if no color specified
|
|
38
|
+
if (!color) {
|
|
39
|
+
warnings.push(`Invalid dice notation: "${part}" - no dice color specified`);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
let recognized = true;
|
|
22
43
|
switch (color) {
|
|
23
44
|
// y/pro = Yellow / Proficiency
|
|
24
45
|
case "y":
|
|
@@ -75,8 +96,15 @@ function parseDiceNotation(input) {
|
|
|
75
96
|
case "f":
|
|
76
97
|
pool.forceDice = count;
|
|
77
98
|
break;
|
|
99
|
+
default:
|
|
100
|
+
recognized = false;
|
|
101
|
+
warnings.push(`Invalid dice color: "${color}" in "${part}"`);
|
|
78
102
|
}
|
|
79
103
|
}
|
|
104
|
+
// Print warnings to stderr
|
|
105
|
+
if (warnings.length > 0) {
|
|
106
|
+
warnings.forEach((warning) => console.error(`Warning: ${warning}`));
|
|
107
|
+
}
|
|
80
108
|
return pool;
|
|
81
109
|
}
|
|
82
110
|
const formatResult = (result) => {
|
|
@@ -123,6 +151,14 @@ const main = () => {
|
|
|
123
151
|
process.exit(1);
|
|
124
152
|
}
|
|
125
153
|
const pool = parseDiceNotation(diceNotation);
|
|
154
|
+
// Check if the pool is empty (all zeros) which might indicate invalid input
|
|
155
|
+
const hasAnyDice = Object.values(pool).some((count) => count > 0);
|
|
156
|
+
if (!hasAnyDice) {
|
|
157
|
+
console.error("\nError: No valid dice found in the notation.");
|
|
158
|
+
console.error("Please check your input and ensure it follows the format: <count><color>");
|
|
159
|
+
console.error("Example: '2y 1g' for 2 yellow and 1 green dice\n");
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
126
162
|
const result = (0, dice_1.roll)(pool, { hints: showHints });
|
|
127
163
|
console.log((0, exports.formatResult)(result));
|
|
128
164
|
};
|
package/dist/dice.d.ts
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
import { DicePool, RollResult, RollOptions } from "./types";
|
|
2
|
+
export declare const DEFAULT_MAX_DICE_PER_TYPE = 100;
|
|
3
|
+
export declare const DEFAULT_MAX_TOTAL_DICE = 500;
|
|
4
|
+
/**
|
|
5
|
+
* Rolls a dice pool and returns the results.
|
|
6
|
+
*
|
|
7
|
+
* @param pool - The dice pool to roll
|
|
8
|
+
* @param options - Optional roll configuration including dice limits
|
|
9
|
+
* @returns The roll results with detailed die information and summary
|
|
10
|
+
* @throws {Error} If dice counts exceed configured limits
|
|
11
|
+
*
|
|
12
|
+
* Default limits:
|
|
13
|
+
* - Max dice per type: 100 (configurable via options.maxDicePerType)
|
|
14
|
+
* - Max total dice: 500 (configurable via options.maxTotalDice)
|
|
15
|
+
*/
|
|
2
16
|
export declare const roll: (pool: DicePool, options?: RollOptions) => RollResult;
|
package/dist/dice.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.roll = void 0;
|
|
3
|
+
exports.roll = exports.DEFAULT_MAX_TOTAL_DICE = exports.DEFAULT_MAX_DICE_PER_TYPE = void 0;
|
|
4
4
|
const hints_1 = require("./hints");
|
|
5
|
+
// Default dice limits for performance and security
|
|
6
|
+
exports.DEFAULT_MAX_DICE_PER_TYPE = 100;
|
|
7
|
+
exports.DEFAULT_MAX_TOTAL_DICE = 500;
|
|
5
8
|
const rollDie = (sides) => Math.floor(Math.random() * sides) + 1;
|
|
6
9
|
const boostDieResult = (roll) => {
|
|
7
10
|
switch (roll) {
|
|
@@ -528,8 +531,20 @@ const sumResults = (results, options) => {
|
|
|
528
531
|
};
|
|
529
532
|
return result;
|
|
530
533
|
};
|
|
534
|
+
/**
|
|
535
|
+
* Rolls a dice pool and returns the results.
|
|
536
|
+
*
|
|
537
|
+
* @param pool - The dice pool to roll
|
|
538
|
+
* @param options - Optional roll configuration including dice limits
|
|
539
|
+
* @returns The roll results with detailed die information and summary
|
|
540
|
+
* @throws {Error} If dice counts exceed configured limits
|
|
541
|
+
*
|
|
542
|
+
* Default limits:
|
|
543
|
+
* - Max dice per type: 100 (configurable via options.maxDicePerType)
|
|
544
|
+
* - Max total dice: 500 (configurable via options.maxTotalDice)
|
|
545
|
+
*/
|
|
531
546
|
const roll = (pool, options) => {
|
|
532
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
547
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
533
548
|
const boostCount = (_a = pool.boostDice) !== null && _a !== void 0 ? _a : 0;
|
|
534
549
|
const abilityCount = (_b = pool.abilityDice) !== null && _b !== void 0 ? _b : 0;
|
|
535
550
|
const proficiencyCount = (_c = pool.proficiencyDice) !== null && _c !== void 0 ? _c : 0;
|
|
@@ -537,16 +552,60 @@ const roll = (pool, options) => {
|
|
|
537
552
|
const difficultyCount = (_e = pool.difficultyDice) !== null && _e !== void 0 ? _e : 0;
|
|
538
553
|
const challengeCount = (_f = pool.challengeDice) !== null && _f !== void 0 ? _f : 0;
|
|
539
554
|
const forceCount = (_g = pool.forceDice) !== null && _g !== void 0 ? _g : 0;
|
|
540
|
-
//
|
|
555
|
+
// Get limits from options or use defaults
|
|
556
|
+
const maxDicePerType = (_h = options === null || options === void 0 ? void 0 : options.maxDicePerType) !== null && _h !== void 0 ? _h : exports.DEFAULT_MAX_DICE_PER_TYPE;
|
|
557
|
+
const maxTotalDice = (_j = options === null || options === void 0 ? void 0 : options.maxTotalDice) !== null && _j !== void 0 ? _j : exports.DEFAULT_MAX_TOTAL_DICE;
|
|
558
|
+
// Ensure all dice counts are non-negative and apply per-type limits
|
|
541
559
|
const sanitizedPool = {
|
|
542
|
-
boostDice: Math.max(0, boostCount),
|
|
543
|
-
abilityDice: Math.max(0, abilityCount),
|
|
544
|
-
proficiencyDice: Math.max(0, proficiencyCount),
|
|
545
|
-
setBackDice: Math.max(0, setBackCount),
|
|
546
|
-
difficultyDice: Math.max(0, difficultyCount),
|
|
547
|
-
challengeDice: Math.max(0, challengeCount),
|
|
548
|
-
forceDice: Math.max(0, forceCount),
|
|
560
|
+
boostDice: Math.max(0, Math.min(boostCount, maxDicePerType)),
|
|
561
|
+
abilityDice: Math.max(0, Math.min(abilityCount, maxDicePerType)),
|
|
562
|
+
proficiencyDice: Math.max(0, Math.min(proficiencyCount, maxDicePerType)),
|
|
563
|
+
setBackDice: Math.max(0, Math.min(setBackCount, maxDicePerType)),
|
|
564
|
+
difficultyDice: Math.max(0, Math.min(difficultyCount, maxDicePerType)),
|
|
565
|
+
challengeDice: Math.max(0, Math.min(challengeCount, maxDicePerType)),
|
|
566
|
+
forceDice: Math.max(0, Math.min(forceCount, maxDicePerType)),
|
|
549
567
|
};
|
|
568
|
+
// Check if any dice counts exceeded the per-type limit
|
|
569
|
+
const exceedsPerTypeLimit = boostCount > maxDicePerType ||
|
|
570
|
+
abilityCount > maxDicePerType ||
|
|
571
|
+
proficiencyCount > maxDicePerType ||
|
|
572
|
+
setBackCount > maxDicePerType ||
|
|
573
|
+
difficultyCount > maxDicePerType ||
|
|
574
|
+
challengeCount > maxDicePerType ||
|
|
575
|
+
forceCount > maxDicePerType;
|
|
576
|
+
// Calculate total dice count
|
|
577
|
+
const totalDice = sanitizedPool.boostDice +
|
|
578
|
+
sanitizedPool.abilityDice +
|
|
579
|
+
sanitizedPool.proficiencyDice +
|
|
580
|
+
sanitizedPool.setBackDice +
|
|
581
|
+
sanitizedPool.difficultyDice +
|
|
582
|
+
sanitizedPool.challengeDice +
|
|
583
|
+
sanitizedPool.forceDice;
|
|
584
|
+
// Check total dice limit
|
|
585
|
+
if (totalDice > maxTotalDice) {
|
|
586
|
+
throw new Error(`Total dice count (${totalDice}) exceeds maximum allowed (${maxTotalDice}). ` +
|
|
587
|
+
`Please reduce the number of dice in your pool.`);
|
|
588
|
+
}
|
|
589
|
+
// Warn if per-type limits were exceeded (but continue with capped values)
|
|
590
|
+
if (exceedsPerTypeLimit && (options === null || options === void 0 ? void 0 : options.throwOnLimitExceeded)) {
|
|
591
|
+
const exceeded = [];
|
|
592
|
+
if (boostCount > maxDicePerType)
|
|
593
|
+
exceeded.push(`boost: ${boostCount}`);
|
|
594
|
+
if (abilityCount > maxDicePerType)
|
|
595
|
+
exceeded.push(`ability: ${abilityCount}`);
|
|
596
|
+
if (proficiencyCount > maxDicePerType)
|
|
597
|
+
exceeded.push(`proficiency: ${proficiencyCount}`);
|
|
598
|
+
if (setBackCount > maxDicePerType)
|
|
599
|
+
exceeded.push(`setback: ${setBackCount}`);
|
|
600
|
+
if (difficultyCount > maxDicePerType)
|
|
601
|
+
exceeded.push(`difficulty: ${difficultyCount}`);
|
|
602
|
+
if (challengeCount > maxDicePerType)
|
|
603
|
+
exceeded.push(`challenge: ${challengeCount}`);
|
|
604
|
+
if (forceCount > maxDicePerType)
|
|
605
|
+
exceeded.push(`force: ${forceCount}`);
|
|
606
|
+
throw new Error(`Dice counts exceed per-type limit (${maxDicePerType}): ${exceeded.join(", ")}. ` +
|
|
607
|
+
`Dice counts have been capped to the maximum.`);
|
|
608
|
+
}
|
|
550
609
|
const detailedResults = [];
|
|
551
610
|
// Roll boost dice
|
|
552
611
|
for (let i = 0; i < sanitizedPool.boostDice; i++) {
|
|
@@ -615,12 +674,15 @@ const roll = (pool, options) => {
|
|
|
615
674
|
if (options === null || options === void 0 ? void 0 : options.hints) {
|
|
616
675
|
const applicableHints = hints_1.hints.filter((hint) => {
|
|
617
676
|
const { cost } = hint;
|
|
677
|
+
// For OR conditions: at least one option must be fully satisfied
|
|
678
|
+
// Each entry in cost represents an alternative way to pay for the hint
|
|
618
679
|
return Object.entries(cost).some(([symbol, required]) => {
|
|
619
680
|
const summaryKey = (symbol.toLowerCase() + "s");
|
|
620
681
|
const value = summary[summaryKey];
|
|
621
682
|
if (typeof value !== "number")
|
|
622
683
|
return false;
|
|
623
|
-
|
|
684
|
+
// Check if we have enough of this symbol type to afford the hint
|
|
685
|
+
return required !== undefined && required > 0 && value >= required;
|
|
624
686
|
});
|
|
625
687
|
});
|
|
626
688
|
summary.hints = applicableHints.map((hint) => `${(0, hints_1.hintCostDisplayText)(hint)} - ${hint.description}`);
|
package/dist/hints.js
CHANGED
|
@@ -239,8 +239,13 @@ function hintCostDisplayText(hint) {
|
|
|
239
239
|
const parts = Object.entries(hint.cost)
|
|
240
240
|
.filter(([_, count]) => count && count > 0)
|
|
241
241
|
.map(([symbol, count]) => {
|
|
242
|
-
const symbolName = symbol.charAt(0) + symbol.toLowerCase().slice(1);
|
|
243
|
-
|
|
242
|
+
const symbolName = symbol.charAt(0).toUpperCase() + symbol.toLowerCase().slice(1);
|
|
243
|
+
const plural = count > 1 ? "s" : "";
|
|
244
|
+
return `${count} ${symbolName}${plural}`;
|
|
244
245
|
});
|
|
245
|
-
|
|
246
|
+
// Use "OR" in uppercase for clarity when multiple options exist
|
|
247
|
+
if (parts.length > 1) {
|
|
248
|
+
return parts.join(" OR ");
|
|
249
|
+
}
|
|
250
|
+
return parts.length > 0 ? parts[0] : "No cost";
|
|
246
251
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -41,4 +41,20 @@ export declare const SYMBOLS: {
|
|
|
41
41
|
export type Symbol = keyof typeof SYMBOLS;
|
|
42
42
|
export type RollOptions = {
|
|
43
43
|
hints?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Maximum number of dice allowed per die type.
|
|
46
|
+
* Default: 100
|
|
47
|
+
*/
|
|
48
|
+
maxDicePerType?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Maximum total number of dice allowed in a single roll.
|
|
51
|
+
* Default: 500
|
|
52
|
+
*/
|
|
53
|
+
maxTotalDice?: number;
|
|
54
|
+
/**
|
|
55
|
+
* Whether to throw an error when dice limits are exceeded.
|
|
56
|
+
* If false, dice counts will be silently capped to the maximum.
|
|
57
|
+
* Default: false
|
|
58
|
+
*/
|
|
59
|
+
throwOnLimitExceeded?: boolean;
|
|
44
60
|
};
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swrpg-online/dice",
|
|
3
|
+
"version": "1.3.0",
|
|
3
4
|
"description": "A TypeScript library that creates dice rolls using the narrative dice system for the Star Wars Roleplaying Game by Fantasy Flight Games and Edge Studio.",
|
|
4
5
|
"keywords": [
|
|
5
6
|
"swrpg",
|
|
@@ -28,13 +29,27 @@
|
|
|
28
29
|
"license": "MIT",
|
|
29
30
|
"author": "@swrpg-online",
|
|
30
31
|
"contributors": [],
|
|
31
|
-
"main": "dist/
|
|
32
|
+
"main": "dist/bundle.cjs.js",
|
|
33
|
+
"module": "dist/bundle.esm.js",
|
|
34
|
+
"browser": "dist/bundle.umd.js",
|
|
35
|
+
"types": "dist/index.d.ts",
|
|
32
36
|
"bin": {
|
|
33
37
|
"swrpg-dice": "dist/cli.js"
|
|
34
38
|
},
|
|
35
39
|
"exports": {
|
|
36
|
-
".":
|
|
37
|
-
|
|
40
|
+
".": {
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
42
|
+
"import": "./dist/bundle.esm.js",
|
|
43
|
+
"require": "./dist/bundle.cjs.js",
|
|
44
|
+
"browser": "./dist/bundle.umd.js",
|
|
45
|
+
"default": "./dist/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./cli": "./dist/cli.js",
|
|
48
|
+
"./bundle": {
|
|
49
|
+
"import": "./dist/bundle.esm.js",
|
|
50
|
+
"require": "./dist/bundle.cjs.js",
|
|
51
|
+
"browser": "./dist/bundle.umd.js"
|
|
52
|
+
}
|
|
38
53
|
},
|
|
39
54
|
"directories": {
|
|
40
55
|
"test": "tests"
|
|
@@ -45,25 +60,30 @@
|
|
|
45
60
|
"scripts": {
|
|
46
61
|
"test": "npx jest --verbose",
|
|
47
62
|
"ci:test": "tsc --noEmit && npx jest --verbose",
|
|
48
|
-
"build": "tsc &&
|
|
63
|
+
"build": "tsc && npm run bundle",
|
|
64
|
+
"bundle": "rollup -c",
|
|
49
65
|
"prepare": "npm run build && husky install"
|
|
50
66
|
},
|
|
51
|
-
"dependencies": {
|
|
52
|
-
"@types/jest": "^29.5.14",
|
|
53
|
-
"@types/node": "^22.10.0",
|
|
54
|
-
"jest": "^29.7.0",
|
|
55
|
-
"ts-jest": "^29.2.5",
|
|
56
|
-
"typescript": "^5.7.2"
|
|
57
|
-
},
|
|
58
67
|
"devDependencies": {
|
|
68
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
69
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
70
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
59
71
|
"@semantic-release/changelog": "^6.0.3",
|
|
60
72
|
"@semantic-release/git": "^10.0.1",
|
|
61
73
|
"@semantic-release/github": "^11.0.1",
|
|
62
74
|
"@semantic-release/npm": "^12.0.1",
|
|
75
|
+
"@types/jest": "^29.5.14",
|
|
76
|
+
"@types/node": "^22.10.0",
|
|
63
77
|
"husky": "^8.0.3",
|
|
78
|
+
"jest": "^29.7.0",
|
|
64
79
|
"lint-staged": "^15.2.10",
|
|
65
80
|
"prettier": "3.4.1",
|
|
66
|
-
"
|
|
81
|
+
"rollup": "^2.79.2",
|
|
82
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
83
|
+
"semantic-release": "^24.2.0",
|
|
84
|
+
"ts-jest": "^29.4.1",
|
|
85
|
+
"tslib": "^2.8.1",
|
|
86
|
+
"typescript": "^5.7.2"
|
|
67
87
|
},
|
|
68
88
|
"repository": {
|
|
69
89
|
"type": "git",
|
|
@@ -74,6 +94,5 @@
|
|
|
74
94
|
},
|
|
75
95
|
"lint-staged": {
|
|
76
96
|
"**/*": "prettier --write --ignore-unknown"
|
|
77
|
-
}
|
|
78
|
-
"version": "1.2.2"
|
|
97
|
+
}
|
|
79
98
|
}
|