Advertisement
buttonpushertv

Buttonpusher's Mod of Freeze's Speedfactor Initiative Macro

Jul 1st, 2022
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.21 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.  
  11. //List of actions with their relative bonuses
  12. var actions = {
  13. "Medium Action (+0)" : +0,
  14. "Melee, Heavy Weapon (-2)" : -2,
  15. "Melee, Light or Finesse Weapon (+2)" : +2,
  16. "Melee, Two-Handed Weapon (-2)" : -2,
  17. "Ranged, Loading Weapon (-5)" : -5,
  18. "Spellcasting, 1st level (-1)" : -1,
  19. "Spellcasting, 2nd level (-2)" : -2,
  20. "Spellcasting, 3rd level (-3)" : -3,
  21. "Spellcasting, 4th level (-4)" : -4,
  22. "Spellcasting, 5th level (-5)" : -5,
  23. "Spellcasting, 6th level (-6)" : -6,
  24. "Spellcasting, 7th level (-7)" : -7,
  25. "Spellcasting, 8th level (-8)" : -8,
  26. "Spellcasting, 9th level (-9)" : -9,
  27. //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
  28. "Very Slow Action (-5)" : -5,
  29. "Slow Action (-2)" : -2,
  30. "Fast Action (+2)" : +2,
  31. "Very Fast Action (+5)" : +5
  32. };
  33.  
  34. // 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:
  35. // var disableTexts = ''
  36. var disableTexts = '';
  37.  
  38.  
  39. // list of sizes present in 5e, optionally it's possible to modify the bonuses (but not the size names "tiny", "sm", etc)
  40. var sizes = {
  41. "tiny" : +5,
  42. "sm" : +2,
  43. "med" : +0,
  44. "lg" : -2,
  45. "huge" : -5,
  46. "grg" : -8
  47. };
  48.  
  49. var options = new Array ();
  50. for (var key in actions) {
  51. options.push(key);
  52. }
  53.  
  54. if (canvas.tokens.controlled.length >= 1) {
  55. (async ()=>{
  56. for (let token of canvas.tokens.controlled) {
  57. let combatant = token.combatant;
  58. if (!combatant){
  59. console.log(token.name + " is not in combat");
  60. } else {
  61. let data = [
  62. {type : `text`, label : `Base modifier : `, options : `${token.actor.data.data.attributes.init.total}` },
  63. {type : `text`, label : `Size modifier : `, options : `${sizes[token.actor.data.data.traits.size]}` },
  64. {type : `select`, label : `Action : `, options},
  65. {type: `text`, label: `Note:`, options: ""}
  66. ];
  67. let rv = await quick_dialog({data}, combatant.name);
  68. rollInit(token, rv);
  69. }
  70. }
  71. })();
  72. } else {
  73. (async ()=>{
  74. if (game.user.character == null){
  75. console.log("player has no player selected in player configuration menu");
  76. } else {
  77. for (let token of game.user.character.getActiveTokens()) {
  78. let combatant = token.combatant;
  79. if (combatant == null){
  80. console.log(token.name + " is not in combat");
  81. } else {
  82. let data = [
  83. {type : `text`, label : `Base modifier : `, options : `${token.actor.data.data.attributes.init.total}` },
  84. {type : `text`, label : `Size modifier : `, options : `${sizes[token.actor.data.data.traits.size]}` },
  85. {type : `select`, label : `Action : `, options},
  86. {type: `text`, label: `Note:`, options: ""}
  87. ];
  88. let rv = await quick_dialog({data}, combatant.name);
  89. await rollInit(token, rv);
  90. }
  91. }
  92. }
  93. })();
  94. }
  95.  
  96.  
  97.  
  98. async function quick_dialog({data} = {}, name)
  99. {
  100. data = data instanceof Array ? data : [data];
  101. let title = `Select your action for `;
  102. let value = await new Promise((resolve) => {
  103. let content = `
  104. <table style="width:100%">
  105. ${data.map(({type, label, options}, i)=> {
  106. if(type.toLowerCase() === `select`)
  107. {
  108. 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>`;
  109. }else{
  110. 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>`;
  111. }
  112. }).join(``)}
  113. </table>`;
  114.  
  115. new Dialog({
  116. title : title + name,
  117. content,
  118. buttons : {
  119. Ok : { label : `Roll Initiative!`, callback : (html) => {
  120. resolve(Array(data.length).fill().map((e,i)=>{
  121. let {type} = data[i];
  122. if(type.toLowerCase() === `select`)
  123. {
  124. return html.find(`select#${i}qd`).val();
  125. }else{
  126. return html.find(`input#${i}qd`)[0].value;
  127. }
  128. }));
  129. }}
  130. }
  131. }).render(true);
  132. });
  133. return value;
  134. }
  135.  
  136. async function rollInit(selectedToken, initBonus){
  137. let combatant = selectedToken.combatant;//game.combats.active.combatants.find(c => c.tokenId === selectedToken.id)
  138. var formula = '';
  139. if (selectedToken.actor.data.flags != null && selectedToken.actor.data.flags.dnd5e != null && selectedToken.actor.data.flags.dnd5e.initiativeAdv){
  140. formula = '2d20kh + @dexBonus + @sizemod + @init';
  141. } else {
  142. formula = '1d20 + @dexBonus + @sizemod + @init';
  143. }
  144. let r= await new Roll(formula, {dexBonus : initBonus[0], sizemod: initBonus[1], init: actions[initBonus[2]]}).roll();
  145.  
  146. //await r.toMessage({flavor : `${combatant.name} chooses ${initBonus[2]} and rolls for Initiative!`});
  147.  
  148. if(!game.user.isGM) {
  149. await r.toMessage({flavor : `${combatant.name} chooses ${initBonus[2]} and rolls for Initiative! <br>NOTE: ${initBonus[3]}`}, {rollMode: CONST.DICE_ROLL_MODES.PUBLIC});
  150. }
  151. else {
  152. if (selectedToken.document._actor.type = 'npc'){
  153. isNPC = true
  154. } else {
  155. isNPC = false
  156. }
  157. await r.toMessage({flavor : `${combatant.name} chooses ${initBonus[2]} and rolls for Initiative! <br>NOTE: ${initBonus[3]}`}, {rollMode: isNPC ? CONST.DICE_ROLL_MODES.PRIVATE : CONST.DICE_ROLL_MODES.PUBLIC});
  158. }
  159. await game.combat.updateEmbeddedDocuments("Combatant", [{_id: combatant.id, initiative: r.total}]);
  160. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement