Advertisement
buttonpushertv

Freeze's SpeedFactor Initiative js script

Jul 1st, 2022
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.98 KB | None | 0 0
  1. /*
  2. * this macro rolls initiative by using the rules for the optional rule "Speed factor initiative", available in the Dungeon Master's Guide at page 270
  3. * select the tokens for which you want to roll initiative and click the macro.
  4. * Alternatively, if you have an actor assigned and no token selected, the macro will roll initiative for your assigned actor
  5. * the macro does not roll initiative for actors not in combat
  6. * requires DnD5e Game System
  7. * created by Gabro#4634, with the invaluable help of Freeze#2689
  8. */
  9.  
  10. Hooks.on("updateCombat", async (combat, changed) => {
  11. if (!("round" in changed)) {
  12. return;
  13. }
  14. //List of actions with their relative bonuses
  15. const actions = {
  16. "Medium Action (+0)" : +0,
  17. "Melee, Heavy Weapon (-2)" : -2,
  18. "Melee, Light or Finesse Weapon (+2)" : +2,
  19. "Melee, Two-Handed Weapon (-2)" : -2,
  20. "Ranged, Loading Weapon (-5)" : -5,
  21. "Spellcasting, 1st level (-1)" : -1,
  22. "Spellcasting, 2nd level (-2)" : -2,
  23. "Spellcasting, 3rd level (-3)" : -3,
  24. "Spellcasting, 4th level (-4)" : -4,
  25. "Spellcasting, 5th level (-5)" : -5,
  26. "Spellcasting, 6th level (-6)" : -6,
  27. "Spellcasting, 7th level (-7)" : -7,
  28. "Spellcasting, 8th level (-8)" : -8,
  29. "Spellcasting, 9th level (-9)" : -9,
  30. //optional rules as suggested by AngryDM (https://theangrygm.com/fine-i-wrote-about-speed-factor-initiative-in-dd-5e/), remove them if you don't want them
  31. "Very Slow Action (-5)" : -5,
  32. "Slow Action (-2)" : -2,
  33. "Fast Action (+2)" : +2,
  34. "Very Fast Action (+5)" : +5
  35. }
  36.  
  37. // this option, as it is, disables the possibility to modify the box relative to the size and dex initiative bonus. If you want to modify them, change it to:
  38. // var disableTexts = ''
  39. const disableTexts = '';
  40.  
  41.  
  42. // list of sizes present in 5e, optionally it's possible to modify the bonuses (but not the size names "tiny", "sm", etc)
  43. const sizes = {
  44. "tiny" : +5,
  45. "sm" : +2,
  46. "med" : +0,
  47. "lg" : -2,
  48. "huge" : -5,
  49. "grg" : -8
  50. };
  51.  
  52. let options = new Array ()
  53. for (let key in actions) {
  54. options.push(key)
  55. }
  56.  
  57.  
  58. if(!game.user.isGM) {
  59. let data = [
  60. {type : `text`, label : `Base modifier : `, options : `${game.user.character.data.data.attributes.init.total}` },
  61. {type : `text`, label : `Size modifier : `, options : `${sizes[game.user.character.data.data.traits.size]}` },
  62. {type : `select`, label : `Action : `, options},
  63. {type: `text`, label: `Note:`, options: ""},
  64. ];
  65. let rv = await quick_dialog({data}, game.user.character.name);
  66. rollInit(game.user.character.getActiveTokens()[0], rv)
  67. }
  68. else {
  69. let combatants = combat.combatants.filter(c => !c.actor.hasPlayerOwner);
  70. for(let combatant of combatants) {
  71. let combActor = game.actors.get(combatant.data.actorId)
  72. let combToken = canvas.tokens.get(combatant.data.tokenId)
  73. let data = [
  74. {type : `text`, label : `Base modifier : `, options : `${combActor.data.data.attributes.init.total}` },
  75. {type : `text`, label : `Size modifier : `, options : `${sizes[combActor.data.data.traits.size]}` },
  76. {type : `select`, label : `Action : `, options},
  77. {type: `text`, label: `Note:`, options: ""},
  78. ];
  79. let rv = await quick_dialog({data}, combToken.name);
  80. await rollInit(combToken, rv)
  81. }
  82. }
  83.  
  84. async function quick_dialog({data, title = `Select your action for `} = {}, name)
  85. {
  86. data = data instanceof Array ? data : [data];
  87.  
  88. let value = await new Promise((resolve) => {
  89. let content = `
  90. <table style="width:100%">
  91. ${data.map(({type, label, options}, i)=> {
  92. if(type.toLowerCase() === `select`)
  93. {
  94. return `<tr><th style="width:50%"><label>${label}</label></th><td style="width:50%"><select id="${i}qd">${options.map((e,i)=> `<option value="${e}">${e}</option>`).join(``)}</td></tr>`;
  95. }else{
  96. return `<tr><th style="width:50%"><label>${label}</label></th><td style="width:50%"><input type="${type}" ${disableTexts} id="${i}qd" value="${options instanceof Array ? options[0] : options}"/></td></tr>`;
  97. }
  98. }).join(``)}
  99. </table>`;
  100.  
  101. new Dialog({
  102. title : title + name,
  103. content,
  104. buttons : {
  105. Ok : {
  106. label : `Roll Initiative!`,
  107. callback : (html) => {
  108. resolve(Array(data.length).fill().map((e,i)=>{
  109. let {type} = data[i];
  110. if(type.toLowerCase() === `select`)
  111. {
  112. return html.find(`select#${i}qd`).val();
  113. }else{
  114. return html.find(`input#${i}qd`)[0].value;
  115. }
  116. }));
  117. }
  118. }
  119. }
  120. }).render(true);
  121. });
  122. console.log(value);
  123. return value;
  124. }
  125.  
  126. async function rollInit(selectedToken, initBonus){
  127. let combatant = selectedToken.combatant;
  128. let formula = ''
  129. if (selectedToken.actor.data.flags != null && selectedToken.actor.data.flags.dnd5e != null && selectedToken.actor.data.flags.dnd5e.initiativeAdv){
  130. formula = '2d20kh + @dexBonus + @sizemod + @init'
  131. } else {
  132. formula = '1d20 + @dexBonus + @sizemod + @init'
  133. }
  134. let r = await new Roll(formula, {dexBonus : initBonus[0], sizemod: initBonus[1], init: actions[initBonus[2]]}).roll()
  135.  
  136. await r.toMessage({flavor : `${combatant.name} chooses ${initBonus[2]} and rolls for Initiative! <br>NOTE: ${initBonus[3]}`}, {rollMode: selectedToken.data.hidden ? CONST.DICE_ROLL_MODES.PRIVATE : CONST.DICE_ROLL_MODES.PUBLIC});
  137. await combat.updateEmbeddedDocuments("Combatant", [{_id: combatant.id, initiative: r.total}])
  138. }
  139. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement