@swrpg-online/dice
Version:
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.
3 lines (2 loc) • 13.6 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).SwrpgDice={})}(this,function(e){"use strict";const t={SUCCESS:"SUCCESS",FAILURE:"FAILURE",ADVANTAGE:"ADVANTAGE",THREAT:"THREAT",TRIUMPH:"TRIUMPH",DESPAIR:"DESPAIR",LIGHT:"LIGHT",DARK:"DARK"},a=[{description:"Recover one strain (may be applied more than once).",cost:{[t.ADVANTAGE]:1,[t.TRIUMPH]:1}},{description:"Add a boost die to the next allied active character's check.",cost:{[t.ADVANTAGE]:1,[t.TRIUMPH]: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:{[t.ADVANTAGE]:1,[t.TRIUMPH]:1}},{description:"Inflict a Critical Injury with a successful attack that deals damage past soak (Advantage cost may vary).",cost:{[t.ADVANTAGE]:1,[t.TRIUMPH]:1}},{description:"Activate a weapon quality (Advantage cost may vary).",cost:{[t.ADVANTAGE]:1,[t.TRIUMPH]:1}},{description:"Perform an immediate free maneuver that does not exceed the two maneuver per turn limit.",cost:{[t.ADVANTAGE]:2,[t.TRIUMPH]:1}},{description:"Add a setback die to the targeted character's next check.",cost:{[t.ADVANTAGE]:2,[t.TRIUMPH]:1}},{description:"Add a boost die to any allied character's next check, including that of the active character.",cost:{[t.ADVANTAGE]:2,[t.TRIUMPH]: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:{[t.ADVANTAGE]:3,[t.TRIUMPH]: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:{[t.ADVANTAGE]:3,[t.TRIUMPH]: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:{[t.ADVANTAGE]:3,[t.TRIUMPH]:1}},{description:"Gain + 1 melee or ranged defense until the end of the active character's next turn.",cost:{[t.ADVANTAGE]:3,[t.TRIUMPH]:1}},{description:"Force the target to drop a melee or ranged weapon they are wielding.",cost:{[t.ADVANTAGE]:3,[t.TRIUMPH]:1}},{description:"Upgrade the difficulty of the targeted character's next check.",cost:{[t.TRIUMPH]:1}},{description:"Do something vital, such as shooting the controls to the nearby blast doors to seal them shut.",cost:{[t.TRIUMPH]:1}},{description:"Upgrade any allied character's next check, including that of the current active character.",cost:{[t.TRIUMPH]: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.TRIUMPH]:2}},{description:"The active character suffers 1 strain.",cost:{[t.THREAT]:1,[t.DESPAIR]: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.THREAT]:1,[t.DESPAIR]:1}},{description:"An opponent may immediately perform one free maneuver in response to the active character's check.",cost:{[t.THREAT]:2,[t.DESPAIR]:1}},{description:"Add a boost die to the targeted character's next check.",cost:{[t.THREAT]:1,[t.DESPAIR]:1}},{description:"The active character or an allied character suffers a setback die on their next action.",cost:{[t.THREAT]:2,[t.DESPAIR]:1}},{description:"The active character falls prone.",cost:{[t.THREAT]:3,[t.DESPAIR]: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.THREAT]:3,[t.DESPAIR]:1}},{description:"The character's ranged weapon imediately runs out of ammunition and may not be used for the remainder of the encounter.",cost:{[t.DESPAIR]:1}},{description:"Upgrade the difficulty of an allied character's next check, including that of the current active character.",cost:{[t.DESPAIR]:1}},{description:"The tool or melee weapon the character is using becomes damaged.",cost:{[t.DESPAIR]:1}}];const s={1:{},2:{},3:{successes:1},4:{successes:1,advantages:1},5:{advantages:2},6:{advantages:1}},i={1:{},2:{},3:{failures:1},4:{failures:1},5:{threats:1},6:{threats:1}},r={1:{},2:{successes:1},3:{successes:1},4:{successes:2},5:{advantages:1},6:{advantages:1},7:{successes:1,advantages:1},8:{advantages:2}},c={1:{},2:{failures:1},3:{failures:2},4:{threats:1},5:{threats:1},6:{threats:1},7:{threats:2},8:{failures:1,threats:1}},o={1:{},2:{successes:1},3:{successes:1},4:{successes:2},5:{successes:2},6:{advantages:1},7:{successes:1,advantages:1},8:{successes:1,advantages:1},9:{successes:1,advantages:1},10:{advantages:2},11:{advantages:2},12:{triumphs:1}},n={1:{},2:{failures:1},3:{failures:1},4:{failures:2},5:{failures:2},6:{threats:1},7:{threats:1},8:{failures:1,threats:1},9:{failures:1,threats:1},10:{threats:2},11:{threats:2},12:{despairs:1}},d={1:{darkSide:1},2:{darkSide:1},3:{darkSide:1},4:{darkSide:1},5:{darkSide:1},6:{darkSide:1},7:{darkSide:2},8:{lightSide:1},9:{lightSide:1},10:{lightSide:2},11:{lightSide:2},12:{lightSide:2}},l={boost:s,setback:i,ability:r,difficulty:c,proficiency:o,challenge:n,force:d},u={[t.SUCCESS]:"successes",[t.FAILURE]:"failures",[t.ADVANTAGE]:"advantages",[t.THREAT]:"threats",[t.TRIUMPH]:"triumphs",[t.DESPAIR]:"despair",[t.LIGHT]:"lightSide",[t.DARK]:"darkSide"},h=e=>Math.floor(Math.random()*e)+1,p=e=>{const t=s[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}},f=e=>{const t=i[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}},g=e=>{const t=r[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}},m=e=>{const t=c[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}},A=e=>{const t=o[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}},v=e=>{const t=n[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}},S=e=>{const t=d[e];return{successes:t.successes||0,failures:t.failures||0,advantages:t.advantages||0,threats:t.threats||0,triumphs:t.triumphs||0,despair:t.despairs||0,lightSide:t.lightSide||0,darkSide:t.darkSide||0}};e.ABILITY_DIE_FACES=r,e.BOOST_DIE_FACES=s,e.CHALLENGE_DIE_FACES=n,e.DICE_FACES=l,e.DIFFICULTY_DIE_FACES=c,e.FORCE_DIE_FACES=d,e.PROFICIENCY_DIE_FACES=o,e.SETBACK_DIE_FACES=i,e.SYMBOLS=t,e.applyTalentModifiers=(e,t)=>({...e,automaticSuccesses:(e.automaticSuccesses||0)+(t.automaticSuccesses||0),automaticFailures:(e.automaticFailures||0)+(t.automaticFailures||0),automaticAdvantages:(e.automaticAdvantages||0)+(t.automaticAdvantages||0),automaticThreats:(e.automaticThreats||0)+(t.automaticThreats||0),automaticTriumphs:(e.automaticTriumphs||0)+(t.automaticTriumphs||0),automaticDespairs:(e.automaticDespairs||0)+(t.automaticDespairs||0),upgradeAbility:(e.upgradeAbility||0)+(t.upgradeAbility||0),upgradeDifficulty:(e.upgradeDifficulty||0)+(t.upgradeDifficulty||0),downgradeProficiency:(e.downgradeProficiency||0)+(t.downgradeProficiency||0),downgradeChallenge:(e.downgradeChallenge||0)+(t.downgradeChallenge||0)}),e.createCombatCheck=(e,t,a=0,s)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,t),boostDice:Math.max(0,a),...s}),e.createDifficultyPool=(e,t=0,a)=>({difficultyDice:Math.max(0,e),challengeDice:Math.max(0,t),...a}),e.createOpposedCheck=(e,t,a,s=0,i)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,t),difficultyDice:Math.max(0,a),challengeDice:Math.max(0,s),...i}),e.createSkillCheck=(e,t,a)=>({abilityDice:Math.max(0,e),proficiencyDice:Math.max(0,t),...a}),e.roll=(e,t)=>{var s,i,r,c,o,n,d,l,y;const D=(e=>{const t={...e};if(e.upgradeAbility&&e.upgradeAbility>0){let a=e.upgradeAbility;const s=t.abilityDice||0,i=Math.min(s,a);t.abilityDice=s-i,t.proficiencyDice=(t.proficiencyDice||0)+i,a-=i,a>0&&(t.proficiencyDice=(t.proficiencyDice||0)+a)}if(e.upgradeDifficulty&&e.upgradeDifficulty>0){let a=e.upgradeDifficulty;const s=t.difficultyDice||0,i=Math.min(s,a);t.difficultyDice=s-i,t.challengeDice=(t.challengeDice||0)+i,a-=i,a>0&&(t.challengeDice=(t.challengeDice||0)+a)}if(e.downgradeProficiency&&e.downgradeProficiency>0){const a=t.proficiencyDice||0,s=Math.min(a,e.downgradeProficiency);t.proficiencyDice=a-s,t.abilityDice=(t.abilityDice||0)+s}if(e.downgradeChallenge&&e.downgradeChallenge>0){const a=t.challengeDice||0,s=Math.min(a,e.downgradeChallenge);t.challengeDice=a-s,t.difficultyDice=(t.difficultyDice||0)+s}return t})(e),T=null!==(s=D.boostDice)&&void 0!==s?s:0,E=null!==(i=D.abilityDice)&&void 0!==i?i:0,b=null!==(r=D.proficiencyDice)&&void 0!==r?r:0,k=null!==(c=D.setBackDice)&&void 0!==c?c:0,I=null!==(o=D.difficultyDice)&&void 0!==o?o:0,M=null!==(n=D.challengeDice)&&void 0!==n?n:0,R=null!==(d=D.forceDice)&&void 0!==d?d:0,P=null!==(l=null==t?void 0:t.maxDicePerType)&&void 0!==l?l:100,x=null!==(y=null==t?void 0:t.maxTotalDice)&&void 0!==y?y:500,C=Math.max(0,Math.min(T,P)),H=Math.max(0,Math.min(E,P)),w=Math.max(0,Math.min(b,P)),U=Math.max(0,Math.min(k,P)),G=Math.max(0,Math.min(I,P)),N=Math.max(0,Math.min(M,P)),F=Math.max(0,Math.min(R,P)),_=T>P||E>P||b>P||k>P||I>P||M>P||R>P,V=C+H+w+U+G+N+F;if(V>x)throw new Error(`Total dice count (${V}) exceeds maximum allowed (${x}). Please reduce the number of dice in your pool.`);if(_&&(null==t?void 0:t.throwOnLimitExceeded)){const e=[];throw T>P&&e.push(`boost: ${T}`),E>P&&e.push(`ability: ${E}`),b>P&&e.push(`proficiency: ${b}`),k>P&&e.push(`setback: ${k}`),I>P&&e.push(`difficulty: ${I}`),M>P&&e.push(`challenge: ${M}`),R>P&&e.push(`force: ${R}`),new Error(`Dice counts exceed per-type limit (${P}): ${e.join(", ")}. Dice counts have been capped to the maximum.`)}const $=[];for(let e=0;e<C;e++){const e=h(6);$.push({type:"boost",roll:e,result:p(e)})}for(let e=0;e<H;e++){const e=h(8);$.push({type:"ability",roll:e,result:g(e)})}for(let e=0;e<w;e++){const e=h(12);$.push({type:"proficiency",roll:e,result:A(e)})}for(let e=0;e<U;e++){const e=h(6);$.push({type:"setback",roll:e,result:f(e)})}for(let e=0;e<G;e++){const e=h(8);$.push({type:"difficulty",roll:e,result:m(e)})}for(let e=0;e<N;e++){const e=h(12);$.push({type:"challenge",roll:e,result:v(e)})}for(let e=0;e<F;e++){const e=h(12);$.push({type:"force",roll:e,result:S(e)})}const L={successes:e.automaticSuccesses,failures:e.automaticFailures,advantages:e.automaticAdvantages,threats:e.automaticThreats,triumphs:e.automaticTriumphs,despairs:e.automaticDespairs,lightSide:e.automaticLightSide,darkSide:e.automaticDarkSide},O=((e,t)=>{const a=e.reduce((e,t)=>({successes:e.successes+t.successes+t.triumphs,failures:e.failures+t.failures+t.despair,advantages:e.advantages+t.advantages,threats:e.threats+t.threats,triumphs:e.triumphs+t.triumphs,despair:e.despair+t.despair,lightSide:e.lightSide+(t.lightSide||0),darkSide:e.darkSide+(t.darkSide||0)}),{successes:((null==t?void 0:t.successes)||0)+((null==t?void 0:t.triumphs)||0),failures:((null==t?void 0:t.failures)||0)+((null==t?void 0:t.despairs)||0),advantages:(null==t?void 0:t.advantages)||0,threats:(null==t?void 0:t.threats)||0,triumphs:(null==t?void 0:t.triumphs)||0,despair:(null==t?void 0:t.despairs)||0,lightSide:(null==t?void 0:t.lightSide)||0,darkSide:(null==t?void 0:t.darkSide)||0});let s=0,i=0;a.successes===a.failures?(s=0,i=0):a.successes>a.failures?s=a.successes-a.failures:i=a.failures-a.successes;let r=0,c=0;return a.advantages===a.threats?(r=0,c=0):a.advantages>a.threats?r=a.advantages-a.threats:c=a.threats-a.advantages,{successes:s,failures:i,advantages:r,threats:c,triumphs:a.triumphs,despair:a.despair,lightSide:a.lightSide,darkSide:a.darkSide}})($.map(e=>e.result),L);if(null==t?void 0:t.hints){const e=a.filter(e=>{const{cost:t}=e;return Object.entries(t).some(([e,t])=>{const a=u[e];if(!a)return!1;const s=O[a];return"number"==typeof s&&(void 0!==t&&t>0&&s>=t)})});O.hints=e.map(e=>`${function(e){if(!e.cost||0===Object.keys(e.cost).length)return"No cost";const t=Object.entries(e.cost).filter(([e,t])=>t&&t>0).map(([e,t])=>`${t} ${e.charAt(0).toUpperCase()+e.toLowerCase().slice(1)}${t>1?"s":""}`);return t.length>1?t.join(" OR "):t.length>0?t[0]:"No cost"}(e)} - ${e.description}`)}return{results:$,summary:O}},Object.defineProperty(e,"__esModule",{value:!0})});
//# sourceMappingURL=bundle.umd.js.map