
Power Cards
What are they? They are simply macro's formatted using tags that are interpreted by the script to apply html and css to contents of the macro. This string is then sent to the chat window via the API using /direct to allow the html and css formatting to work.
What this is not! This is not a script meant to automate combat in any kind of RPG. It is simply a way to format the output of a macro in a more aesthetically pleasing manner and to facilitate multiple attack rolls within the same macro. This has the benefit of reducing the spam in the chat window (while admittedly creating a new kind of spam) and reduces the number of macros needed.
What this is not! This is not a script meant to automate combat in any kind of RPG. It is simply a way to format the output of a macro in a more aesthetically pleasing manner and to facilitate multiple attack rolls within the same macro. This has the benefit of reducing the spam in the chat window (while admittedly creating a new kind of spam) and reduces the number of macros needed.
Updates
- December 30th, 2014 ~ 1:40 pm eastern: Minor bugfix for sendChat issues and the random colon fix from earlier...
- December 30th, 2014 ~ 7:00 am eastern:
- Fixed the random colon appearing when using custom emotes.
- Added a version check into the script for bug tracking. Simply type !power_version in chat and the script will whisper you which version of the script your GM is currently using.
- October 18th, 2014 ~ 3:40 pm eastern: Added ability to parse URLS/Links
- Format: @@url||link text@@
- Example: @@http://www.google.com||Google@@
- You must enable this explicitly in the script itself using ALLOW_URLS and ALLOW_HIDDEN_URLS. This option is a use at your own risk kind of option since I'm not great at making sure input is sanitized or idiot proof.
- September 16th, 2014 ~ 9:00 am eastern: Minor but important bugfixes for indents.
- September 2nd, 2014 ~ 1:40 am eastern: Minor bugfix... indents no longer break the left hand side of the power card.
- If you want to fix this yourself without replacing the whole script, go to lines 219 and 221 and add the following in front of padding: 5px
- margin: 0px 0px 0px -10px;
- September 1st, 2014 ~ 4:30 pm eastern: Minor bugfix... avatars in custom emotes now work in chrome.
- September 1st, 2014 ~ 6:30 am eastern: Added a custom emote option that is triggered by adding --charid|@{character_id} to your emote. This will grab the avatar from your character sheet and prefix the contents of the --emote| tag with that image and format it without the colored background and italicize the text. See examples further down in this thread. If you want to use the new emote without an image, add a single ! exclamation mark at the start of the content of the emote tag to prevent the image from showing.
- Example: --emote|Leaps into the fray. shows the avatar of the character... --emote|!Leaps into the fray. does not show the avatar...
- Removed --lb| from list of tags. Do not use.
- Removed --desc| from list of tags. Do not use.
- August 21st, 2014 ~ 2:00 pm eastern: Bugfix... moved odd/even row default colors into the PowerCardScript.Process function to prevent macros from overriding these values and carrying over to other macros.
- August 21st, 2014 ~ 12:40 pm eastern: I have added four new tags... which let you further customize the appearance of the power cards. These colors can also be set for all power cards at the top of the script.
- --orowbg|#000 defines the background color of odd rows
- --orowtx|#000 defines the text color of odd rows
- --erowbg|#000 defines the background color of even rows
- --erowtx|#000 defines the text color of even rows
- August 20th, 2014 ~ 11:30 pm eastern: Tables now work... for one roll tables only. For example, a table named HitLocation would work if you used the following inline roll: [[ 1t[HitLocation ]] but would NOT work if you used [[ 2t[HitLocation] ]]
- August 17th, 2014 ~ 9:00 am eastern: Added a variety of new features. Most important however, is that --lb for line breaks is being deprecated and will be removed in the near future. The updates are as follows...
- --text| tag that can be used to display text only, without the tag. The text tag can also be used with multiple characters after the tag like: --text1|Stuff --text2|Stuff so that you can have multiple text tags in the same power card.
- Power Cards can now be sent via whispers to the person who triggers the card or the gm. --whisper|self will send the card to the person that triggers the macro. Anything else will send it to the gm instead.
- Line breaks are now handled inline instead of as a tag. Simply use ^^ to insert a line break.
- Double * (asterisk) around a word or set of words will bold those words.
- Double _ (underscore) will italicize words.
- ^* will insert a 1em space into the text. It could be used at the beginning of a paragraph to indent the first line.
- August 6th, 2014 ~ 11:45 pm eastern: The inline tag [NH] now works and disables highlighting of low and high rolls for that inline roll.
- August 2nd, 2014 ~ 3:30 am eastern: Added config options to set a default format for macros (this really only affects the attack/damage tags). Added an option to show Attack/Hit tags if show attack tag is true and format is dnd4e. No clue on how to fix the +[[#]] bug with multirolls yet (RobJ). Put in another config option to turn off inline roll highlighting completely for power cards. [NH] inline tag does not work still...
- August 1st, 2014 ~ 5:15 am eastern: Added options to define the colors for inline roll highlighting. These are global for all players and the GM. You can find them at the top of the script. The names should be pretty self explanatory. Number only inline rolls now work... [[3]] will show... 3! Am-aaaa-zing! I know.
- July 31st, 2014 ~ 10:30 pm eastern: Added config option to turn off roll highlighting globally. Added skeleton framework for defining custom highlighting colors. This is not fully implemented yet. Ran out of time during my break at work. Will update this during lunch.
Using Tags
The previous Power Card script was created specifically for Dungeons & Dragons 4th edition and did not allow for custom tags. This new version has many more features, including using custom names for tags and indenting tags. Tags will show up in the power card in the order of their use in the macro. There is one restriction... and that is that you cannot use the same tag name twice. Only the content of the second tag will be used.
Tag Format -- --Tag|Content
- This will show up as [ Tag: Content ] in the chat window.
- You MUST use this format or it will break your macro/api script.
- GOOD: --Effect|This is an effect.
- GOOD: --A Custom Tag|This is a custom tag.
- BAD: effect | This is a bad tag.
- BAD: -BadTag| This is also a bad tag.
--emote| If used, an emote will show up before the power card is displayed. This emote does NOT start with your Speaking As name.
--name| Name of the power. It shows up on the title of the power card.
--usage| Good for defining how often the power can be used. Ignored if both usage and action are not used. DEPRECATED: Use --leftsub| instead.
--action| Defines the type of action it is. Ignored if both usage and action are not used. DEPRECATED: Use --rightsub| instead.
--attack| Defines the attack roll. If you put a number after attack, such as --attack3| it will roll 3 attacks. You can use ?{Number of Attacks|1} as well.
--defense| Defines the target number or defense of the attack.
--damage| Creates a damage roll. You can now put a number after damage, such as --damage3| and it will roll three damage rolls now.
--txcolor| Determines the color of the text in the title of the power card.
--bgcolor| Sets the color of the background of the power card title.
--leftsub| This tag sets the text to the left of the diamond in the title of the powercard.
--rightsub| This tag sets the text to the right of the diamond in the title of the powercard.
--desc| This tag should not be used with --emote| since it sends a blank /desc to the chat window before the power card. DEPRECATED! Do not use.
--format| Use dnd4e dnd5e to tell the script what game rules you're using. It focuses entirely on --attack| output formatting for those editions of D&D
--title| This tag sets a tooltip on the title of the power card
--whisper| This tag sends the power card to the GM instead of the chat window. Use --whisper|self to send the powercard to your self instead.
--orowbg| This tag sets the background color of odd rows in the power card.
--orowtx| This tag sets the text color of odd rows in the power card.
--erowbg| This tag sets the background color of even rows in the power card.
--erowtx| This tag sets the text color of even rows in the power card.
Inline Tags - These tags are used inside inline rolls with square brackets surrounding them. Example: [[[LR2] 1d6]]--name| Name of the power. It shows up on the title of the power card.
--usage| Good for defining how often the power can be used. Ignored if both usage and action are not used. DEPRECATED: Use --leftsub| instead.
--action| Defines the type of action it is. Ignored if both usage and action are not used. DEPRECATED: Use --rightsub| instead.
--attack| Defines the attack roll. If you put a number after attack, such as --attack3| it will roll 3 attacks. You can use ?{Number of Attacks|1} as well.
--defense| Defines the target number or defense of the attack.
--damage| Creates a damage roll. You can now put a number after damage, such as --damage3| and it will roll three damage rolls now.
--txcolor| Determines the color of the text in the title of the power card.
--bgcolor| Sets the color of the background of the power card title.
--leftsub| This tag sets the text to the left of the diamond in the title of the powercard.
--rightsub| This tag sets the text to the right of the diamond in the title of the powercard.
--desc| This tag should not be used with --emote| since it sends a blank /desc to the chat window before the power card. DEPRECATED! Do not use.
--format| Use dnd4e dnd5e to tell the script what game rules you're using. It focuses entirely on --attack| output formatting for those editions of D&D
--title| This tag sets a tooltip on the title of the power card
--whisper| This tag sends the power card to the GM instead of the chat window. Use --whisper|self to send the powercard to your self instead.
--orowbg| This tag sets the background color of odd rows in the power card.
--orowtx| This tag sets the text color of odd rows in the power card.
--erowbg| This tag sets the background color of even rows in the power card.
--erowtx| This tag sets the text color of even rows in the power card.
[LR#] - Highlights in RED any roll equal to or less than the number.
[HR#] - Highlights in GREEN any roll greater than or equal to the number.
[NH] - Disables highlighting of min/max rolls for this roll.
Example: [[ [HR18] 1d20+1d20]] would highlight a roll of 18 or higher on the first d20 but not the second. To do that you would need to use another inline tag before the second roll like this... [[ [HR18] 1d20 + [HR18] 1d20]].
Inline Text Formatting - Use the following character combinations to indent a line or bold/italicize text.[HR#] - Highlights in GREEN any roll greater than or equal to the number.
[NH] - Disables highlighting of min/max rolls for this roll.
Example: [[ [HR18] 1d20+1d20]] would highlight a roll of 18 or higher on the first d20 but not the second. To do that you would need to use another inline tag before the second roll like this... [[ [HR18] 1d20 + [HR18] 1d20]].
**Bold**
__Italics__
^*Indent
Indenting - You can now indent a section by using ^ or ^# in front of a tag, such as --^1Secondary Attack|Make a second attack against a different enemy. The number determines the level of indenting up to a maximum of nine, though anything past three levels of indenting makes it difficult to read. If you want to remove the indenting for the next line, use ^0 in front of the tag (added by Rob J.). This indents entire sections of the powercard and all following sections. If you want to only indent one line, use ^* in the content instead of the tag.__Italics__
^*Indent
Contributors
I'm sure I missed someone somewhere... but here is a short list of the people who have helped make this script a reality: Alex L., Chris N, Brian, Rob J., Aaron, and others (I'll add the rest when I have more time to look through the old thread and my private messages).The Script
// VERSION INFO var PowerCards_Version = "1.0"; // VARIABLE & FUNCTION DECLARATIONS -- DO NOT ALTER!! var PowerCardScript = PowerCardScript || {}; var getBrightness = getBrightness || {}; var hexDec = hexDec || {}; // USER CONFIGUATION var POWERCARD_DEFAULT_FORMAT = ""; var POWERCARD_CUSTOM_EMOTE = true; var POWERCARD_USE_PLAYER_COLOR = false; var POWERCARD_SHOW_ATTACK_DAMAGE_TAGS = true; var POWERCARD_SHOW_ATTACK_DAMAGE_INFO = true; var POWERCARD_INLINE_ROLL_NO_HIGHLIGHT = false; var POWERCARD_INLINE_ROLL_COLOR_OVERRIDE = true; // ALLOW URLS IN POWERCARDS var ALLOW_URLS = false; var ALLOW_HIDDEN_URLS = false; // DEFINE SIZE & COLOR OF POWERCARD BORDER AND IF ROUNDED var POWERCARD_BORDER_SIZE = 1; var POWERCARD_BORDER_COLOR = "#000000"; var POWERCARD_ROUNDED_CORNERS = true; // DEFINE IF CORNER OF INLINE ROLLS ARE ROUNDED var POWERCARD_ROUNDED_INLINE_ROLLS = true; // DEFINE COLORS FOR STANDARD INLINE ROLLS var POWERCARD_INLINE_BASE_BORDER = "#87850A"; var POWERCARD_INLINE_BASE_BACKGROUND = "#FFFEA2"; var POWERCARD_INLINE_BASE_TEXT_COLOR = "#000000"; // DEFINE COLORS FOR MAXIMUM VALUE ROLLS var POWERCARD_INLINE_CRIT_BORDER = "#004400"; var POWERCARD_INLINE_CRIT_BACKGROUND = "#88CC88"; var POWERCARD_INLINE_CRIT_TEXT_COLOR = "#004400"; // DEFINE COLOR FOR MINIMUM VALUE ROLLS var POWERCARD_INLINE_FAIL_BORDER = "#660000"; var POWERCARD_INLINE_FAIL_BACKGROUND = "#FFAAAA"; var POWERCARD_INLINE_FAIL_TEXT_COLOR = "#660000"; // DEFINE COLORS FOR A ROLL WITH BOTH MINIMUM AND MAXIMUM VALUES IN THE ROLL var POWERCARD_INLINE_BOTH_BORDER = "#061539"; var POWERCARD_INLINE_BOTH_BACKGROUND = "#8FA4D4"; var POWERCARD_INLINE_BOTH_TEXT_COLOR = "#061539"; on("chat:message", function (msg) { // Exit if not an api command if (msg.type != "api") return; // Get the API Chat Command msg.who = msg.who.replace(" (GM)", ""); msg.content = msg.content.replace("(GM) ", ""); var command = msg.content.split(" ", 1)[0]; if (command === "!power") { PowerCardScript.Process(msg); } if (command === "!power_version") { sendChat("HoneyBadger", "/w " + msg.who + " You are using version " + PowerCards_Version + " of this script.") } }); PowerCardScript.Process = function(msg){ // DEFINE VARIABLES var n = msg.content.split(" --"); var PowerCard = {}; var DisplayCard = ""; var NumberOfAttacks = 1; var NumberOfDmgRolls = 1; var NumberOfRolls = 1; var Tag = ""; var Content = ""; var Character = ""; // MORE USER CONFIGURATION // DEFINE COLORS FOR ODD/EVEN ROWS var POWERCARD_ODD_ROW_BGCOLOR = "#CEC7B6"; // #CEC7B6 - Default light brown var POWERCARD_ODD_ROW_TXCOLOR = "#000000"; var POWERCARD_EVEN_ROW_BGCOLOR = "#B6AB91"; // #B6AB91 - Default darker brown var POWERCARD_EVEN_ROW_TXCOLOR = "#000000"; // SHOW AVATAR/IMAGE IN CUSTOM EMOTES var POWERCARD_SHOW_AVATAR = true; // SET THE DEFAULT FORMAT... Override with --format| in macro PowerCard.format = POWERCARD_DEFAULT_FORMAT; // CREATE POWERCARD OBJECT ARRAY n.shift(); n.forEach(function(token){ Tag = token.substring(0, token.indexOf("|")); Content = token.substring(token.indexOf("|") + 1); if (Tag.substring(0, 6).toLowerCase() === "attack") { var attacks = parseInt(Tag.substring(6)); if(attacks && attacks >= NumberOfAttacks) { NumberOfAttacks = attacks; Tag = "attack"; } } else if (Tag.substring(0, 6).toLowerCase() === "damage") { var dmgs = parseInt(Tag.substring(6)); if(dmgs && dmgs >= NumberOfDmgRolls) { NumberOfDmgRolls = dmgs; Tag = "damage"; } } else if (Tag.substring(0, 9).toLowerCase() === "multiroll") { var mrolls = parseInt(Tag.substring(9)); if(mrolls && mrolls >= NumberOfRolls) { NumberOfRolls = mrolls; Tag = "multiroll"; } } else if (Tag.substring(0,5).toLowerCase() === "emote" && Content.charAt(0) === "!") { POWERCARD_SHOW_AVATAR = false; Content = Content.replace("!", ""); } // PARSE FOR INLINE FORMATTING var f; // LINE BREAK if (Content.indexOf("^^") != -1) Content = Content.replace(/\^\^/g, "<br><br>"); // INDENT FIRST LINE if (Content.indexOf("^*") != -1) Content = Content.replace(/\^\*/g, "<span style='margin-left: 1em;'></span>"); // BOLD if (Content.indexOf("**") != -1) { // Do stuff... f = 1; while (Content.indexOf("**") != -1) { Content = (f % 2 == 1) ? Content.replace("**", "<b>") : Content.replace("**", "</b>"); f++; } } // ITALICS if (Content.indexOf("__") != -1) { // Do stuff... f = 1; while (Content.indexOf("__") != -1) { Content = (f % 2 == 1) ? Content.replace("__", "<i>") : Content.replace("__", "</i>"); f++; } } // URL if (Content.indexOf("@@") != -1 && ALLOW_URLS) { if (ALLOW_HIDDEN_URLS) { f = 1; while (Content.indexOf("@@") != -1) { Content = (f % 2 == 1) ? Content.replace("@@", "<a href='") : Content.replace("@@", "</a>"); if (f % 2 == 1) { Content = Content.replace("@@", "<a href='"); Content = Content.replace("||", "' style='color:#000; text-decoration: underline;'>"); } f++; } } else { while (Content.indexOf("@@") != -1) { Content = (f % 2 == 1) ? Content.replace("@@", "<a>") : Content.replace("@@", "</a>"); f++; } } } PowerCard[Tag] = Content; }); // ERROR CATCH FOR EMPTY EMOTE if (PowerCard.emote === "") PowerCard.emote = '" "'; // CREATE CUSTOM EMOTE if (PowerCard.charid !== undefined && PowerCard.emote !== undefined && POWERCARD_CUSTOM_EMOTE) { Character = getObj("character", PowerCard.charid); if (POWERCARD_SHOW_AVATAR) { PowerCard.emote = "<div style='display: table-cell; width: 50px;'><img src='" + Character.get("avatar") + "' style='height: 50px; width: 50px;'></img></div><div style='display:table-cell; width: calc(100%-50px); vertical-align: middle; font-size: 12px; font-style: italic; text-align: center;'>" + PowerCard.emote + "</div>"; } else { PowerCard.emote = "<div style='display:block; width: 100%; vertical-align: middle; font-size: 12px; font-style: italic; text-align: center;'>" + PowerCard.emote + "</div>"; } } // CREATE WHISPER TARGET var WhisperTarget = ""; if (PowerCard.whisper !== undefined) { WhisperTarget = (PowerCard.whisper.toLowerCase() == "self") ? msg.who : "gm"; } // CREATE TITLE STYLE var TitleStyle = " font-family: Georgia; font-size: medium; font-weight: normal; letter-spacing: 0.25px; text-align: center; vertical-align: middle; padding: 2px 0px; margin: 0px 0px 0px -10px; border: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + ";"; // ROUNDED CORNERS ON TOP OF POWER CARD TitleStyle += (POWERCARD_ROUNDED_CORNERS) ? " border-radius: 10px 10px 0px 0px;" : ""; // LIST OF PRE-SET TITLE TEXT & BACKGROUND COLORS FOR D&D 4E var AtWill = " color: #FFF; background-color: #040;"; var Encounter = " color: #FFF; background-color: #400;"; var Daily = " color: #FFF; background-color: #444;"; var Item = " color: #FFF; background-color: #e58900;"; var Recharge = " color: #FFF; background-color: #004;"; // SET PowerCard.bgcolor TO PLAYER'S COLOR IF .bgcolor IS EQUAL TO PLAYER // THIS OVERRIDES TXCOLOR if (PowerCard.bgcolor == "player") { PowerCard.bgcolor = getObj("player", msg.playerid).get("color"); PowerCard.txcolor = (getBrightness(PowerCard.bgcolor) < (255/2)) ? "#FFF" : "#000"; } // CHECK FOR PRESET TITLE COLORS if (!POWERCARD_USE_PLAYER_COLOR) { if (PowerCard.usage !== undefined && PowerCard.txcolor === undefined && PowerCard.bgcolor === undefined) { // PRESET TITLE COLORS TitleStyle += AtWill; if (PowerCard.usage.toLowerCase().indexOf("encounter") != -1) TitleStyle += Encounter; if (PowerCard.usage.toLowerCase().indexOf("daily") != -1) TitleStyle += Daily; if (PowerCard.usage.toLowerCase().indexOf("item") != -1) TitleStyle += Item; if (PowerCard.usage.toLowerCase().indexOf("recharge") != -1) TitleStyle += Recharge; } else { // CUSTOM TITLECARD TEXT & BACKGROUND COLORS TitleStyle += (PowerCard.txcolor !== undefined) ? " color: " + PowerCard.txcolor + ";" : " color: #FFF;"; TitleStyle += (PowerCard.bgcolor !== undefined) ? " background-color: " + PowerCard.bgcolor + ";" : " background-color: #040;"; } } else { // SET TITLE BGCOLOR TO PLAYER COLOR --- OVERRIDES ALL OTHER COLOR OPTIONS --- var PlayerBGColor = getObj("player", msg.playerid).get("color"); var PlayerTXColor = (getBrightness(PlayerBGColor) < (255/2)) ? "#FFF" : "#000"; TitleStyle += " color: " + PlayerTXColor + "; background-color: " + PlayerBGColor + ";"; } // DEFINE .leftsub and .rightsub if (PowerCard.leftsub === undefined) PowerCard.leftsub = (PowerCard.usage !== undefined) ? PowerCard.usage : ""; if (PowerCard.rightsub === undefined) PowerCard.rightsub = (PowerCard.action !== undefined) ? PowerCard.action : ""; var PowerCardDiamond = (PowerCard.leftsub === "" || PowerCard.rightsub === "") ? "" : " ♦ "; // BEGIN DISPLAYCARD CREATION PowerCard.title = PowerCard.title ? PowerCard.title.split("|").join("&" + "#013;") : PowerCard.title; DisplayCard += "<div style='" + TitleStyle + "' title='" + PowerCard.title + "'>" + PowerCard.name; DisplayCard += (PowerCard.leftsub !== "" || PowerCard.rightsub !== "") ? "<br><span style='font-family: Tahoma; font-size: small; font-weight: normal;'>" + PowerCard.leftsub + PowerCardDiamond + PowerCard.rightsub + "</span></div>" : "</div>"; // ROW STYLE VARIABLES if (PowerCard.orowbg !== undefined) POWERCARD_ODD_ROW_BGCOLOR = PowerCard.orowbg; if (PowerCard.orowtx !== undefined) POWERCARD_ODD_ROW_TXCOLOR = PowerCard.orowtx; if (PowerCard.erowbg !== undefined) POWERCARD_EVEN_ROW_BGCOLOR = PowerCard.erowbg; if (PowerCard.erowtx !== undefined) POWERCARD_EVEN_ROW_TXCOLOR = PowerCard.erowtx; var OddRow = " background-color: " + POWERCARD_ODD_ROW_BGCOLOR + "; color: " + POWERCARD_ODD_ROW_TXCOLOR + ";"; var EvenRow = " background-color: " + POWERCARD_EVEN_ROW_BGCOLOR + "; color: " + POWERCARD_EVEN_ROW_TXCOLOR + ";"; var RowStyle = " margin: 0px 0px 0px -10px; padding: 5px; border-left: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + "; border-right: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + "; border-radius: 0px;"; var RowBackground = OddRow; var RowNumber = 1; var Indent = 0; var KeyCount = 0; // KEY LOOP var Keys = Object.keys(PowerCard); var ReservedTags = "attack, damage, multiroll, text"; var IgnoredTags = "format, emote, name, usage, action, defense, txcolor, bgcolor, leftsub, rightsub, ddn, desc, crit, title, whisper, orowbg, orowtx, erowbg, erowtx, charid, playercolor"; Keys.forEach(function(Tag){ Content = PowerCard[Tag]; if (Tag.charAt(0) === "^") { Indent = (parseInt(Tag.charAt(1)) >= 0) ? Tag.charAt(1) : 1; Tag = (parseInt(Tag.charAt(1)) >= 0) ? Tag.substring(2) : Tag.substring(1); // Reset indent to 0 if ^0 is used... (Thanks to Rob J. on Roll20) if (Indent === "0") { RowStyle = " margin: 0px 0px 0px -10px; padding: 5px; border-left: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + "; border-right: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + "; border-radius: 0px;"; } else { RowStyle = " margin: 0px 0px 0px -10px; padding: 5px; border-left: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + "; border-right: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + "; border-radius: 0px; padding-left: " + (Indent * 1.5) + "em;"; } } // CHECK FOR RESERVED & IGNORED TAGS if (ReservedTags.indexOf(Tag) != -1) { // ATTACK ROLLS if (Tag.toLowerCase() == "attack") { for(var AttackCount = 0; AttackCount < NumberOfAttacks; AttackCount++){ RowBackground = (RowNumber % 2 == 1) ? OddRow : EvenRow; RowNumber += 1; switch (PowerCard.format) { case "dnd4e": { if (AttackCount === 0) { PowerCard[Tag] = PowerCard[Tag].replace("]]", "]] vs " + PowerCard.defense + " "); DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + (POWERCARD_SHOW_ATTACK_DAMAGE_TAGS ? "<b>Attack:</b> " : "") + PowerCard[Tag] + "</div>"; } else DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + (POWERCARD_SHOW_ATTACK_DAMAGE_TAGS ? "<b>Attack:</b> " : "") + "$[a" + AttackCount + "] vs " + PowerCard.defense + " </div>"; break; } case "dnd5e": case "ddn": { DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + (POWERCARD_SHOW_ATTACK_DAMAGE_TAGS ? "<b>Attack:</b> " : "") + PowerCard[Tag] + " vs Armor Class</div>"; break; } default: { if (AttackCount === 0) DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + (POWERCARD_SHOW_ATTACK_DAMAGE_TAGS ? "<b>Attack:</b> " : "") + PowerCard[Tag] + "</div>"; else DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + (POWERCARD_SHOW_ATTACK_DAMAGE_TAGS ? "<b>Attack:</b> " : "") + "$[a" + AttackCount + "]</div>"; } } } } // DAMAGE ROLLS if (Tag.toLowerCase() == "damage") { for (var DamageCount = 0; DamageCount < NumberOfDmgRolls; DamageCount++) { RowBackground = (RowNumber % 2 == 1) ? OddRow : EvenRow; RowNumber += 1; if (DamageCount === 0) DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + (POWERCARD_SHOW_ATTACK_DAMAGE_TAGS ? "<b>Hit:</b> " : "") + PowerCard[Tag] + "</div>"; else DisplayCard += "<div style='" + RowStyle + RowBackground + "'>$[d" + DamageCount + "]</div>"; } } // MULTIROLLS if (Tag.toLowerCase() == "multiroll") { for (var MultiRoll = 0; MultiRoll < NumberOfRolls; MultiRoll++) { RowBackground = (RowNumber % 2 == 1) ? OddRow : EvenRow; RowNumber += 1; if (MultiRoll === 0) DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + PowerCard[Tag] + "</div>"; else DisplayCard += "<div style='" + RowStyle + RowBackground + "'>$[m" + MultiRoll + "]</div>"; } } } else if (IgnoredTags.indexOf(Tag.toLowerCase()) != -1) { // Do nothing } else { if (Tag.toLowerCase().substring(0,4) == "text") { RowBackground = (RowNumber % 2 == 1) ? OddRow : EvenRow; RowNumber += 1; DisplayCard += "<div style='" + RowStyle + RowBackground + "'>" + Content + "</div>"; } else { RowBackground = (RowNumber % 2 == 1) ? OddRow : EvenRow; RowNumber += 1; DisplayCard += "<div style='" + RowStyle + RowBackground + "'><b>" + Tag + ":</b> " + Content + "</div>"; } } KeyCount++; }); // ADD ROUNDED CORNERS & BORDER TO BOTTOM OF POWER CARD if (POWERCARD_ROUNDED_CORNERS && KeyCount == (Keys.length)) DisplayCard = DisplayCard.replace(/border-radius: 0px;(?!.*border-radius: 0px;)/g, "border-radius: 0px 0px 10px 10px; border-bottom: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + ";"); if (!POWERCARD_ROUNDED_CORNERS && POWERCARD_BORDER_SIZE) DisplayCard = DisplayCard.replace(/border-radius: 0px;(?!.*border-radius: 0px;)/g, "border-bottom: " + POWERCARD_BORDER_SIZE + "px solid " + POWERCARD_BORDER_COLOR + ";"); // INLINE ROLLS REPLACEMENT if (msg.inlinerolls !== undefined) { // Process inline rolls... for (var i = 0; i < msg.inlinerolls.length; i++){ var inlinerollValue = buildinline(msg.inlinerolls[i], PowerCard.crit); DisplayCard = DisplayCard.replace("$[[" + i + "]]", inlinerollValue); } // Process multirolls... var content = PowerCard.attack; var idx = content ? content.substring(content.indexOf("$[[") + 3, content.indexOf("]]")) : false; var exp = idx && msg.inlinerolls[idx] ? msg.inlinerolls[idx].expression : undefined; var attExp = buildExpression(NumberOfAttacks, "a", exp); content = PowerCard.damage; idx = content ? content.substring(content.indexOf("$[[") + 3, content.indexOf("]]")) : false; exp = idx && msg.inlinerolls[idx] ? msg.inlinerolls[idx].expression : undefined; var dmgExp = buildExpression(NumberOfDmgRolls, "d", exp); content = PowerCard.multiroll; idx = content ? content.substring(content.indexOf("$[[") + 3, content.indexOf("]]")) : false; exp = idx && msg.inlinerolls[idx] ? msg.inlinerolls[idx].expression : undefined; var mltExp = buildExpression(NumberOfRolls, "m", exp); // Process multiroll results... var rollExp = attExp + ";" + dmgExp + ";" + mltExp; sendChat("", rollExp, function(m){ var i; var inlinerollValue; for (i = 1; i < NumberOfAttacks; i++){ inlinerollValue = buildinline(m[0].inlinerolls[i], PowerCard.crit); DisplayCard = DisplayCard.replace("$[a" + i + "]", inlinerollValue); } var dIndex = 1; for (i = NumberOfAttacks; i < NumberOfAttacks + NumberOfDmgRolls-1 ; i++){ inlinerollValue = buildinline(m[0].inlinerolls[i], PowerCard.crit); DisplayCard = DisplayCard.replace("$[d" + dIndex++ + "]", inlinerollValue); } var mIndex = 1; for (i = NumberOfAttacks + NumberOfDmgRolls-1; i < NumberOfAttacks+NumberOfDmgRolls+NumberOfRolls-2 ; i++){ inlinerollValue = buildinline(m[0].inlinerolls[i], PowerCard.crit); DisplayCard = DisplayCard.replace("$[m" + mIndex++ + "]", inlinerollValue); } // SEND OUTPUT TO CHAT if (PowerCard.whisper !== undefined) { if (PowerCard.emote !== undefined && PowerCard.charid !== undefined && POWERCARD_CUSTOM_EMOTE) { sendChat("", "/desc "); sendChat("", "/direct " + PowerCard.emote); } else if (PowerCard.emote !== undefined) { sendChat(msg.who, "/emas " + PowerCard.emote); } sendChat("Power Card Script", "/w " + WhisperTarget + " " + DisplayCard); } else { if (PowerCard.emote !== undefined && PowerCard.charid !== undefined && POWERCARD_CUSTOM_EMOTE) { sendChat("", "/desc "); sendChat("", "/direct " + PowerCard.emote + DisplayCard); } else if (PowerCard.emote !== undefined) { sendChat(msg.who, "/emas " + PowerCard.emote); sendChat("", "/direct " + DisplayCard); } else { sendChat("", "/direct " + DisplayCard); } } }); } else { // NO INLINE ROLLS if (PowerCard.whisper !== "no" && PowerCard.whisper !== undefined) { if (PowerCard.emote !== undefined && PowerCard.charid !== undefined && POWERCARD_CUSTOM_EMOTE) { sendChat("", "/desc "); sendChat("", "/direct " + PowerCard.emote); } else if (PowerCard.emote !== undefined) { sendChat(msg.who, "/emas " + PowerCard.emote); } sendChat("Power Card Script", "/w " + WhisperTarget + " " + DisplayCard); } else { if (PowerCard.emote !== undefined && PowerCard.charid !== undefined && POWERCARD_CUSTOM_EMOTE) { sendChat("", "/desc "); sendChat("", "/direct " + PowerCard.emote + DisplayCard); } else if (PowerCard.emote !== undefined) { sendChat(msg.who, "/emas " + PowerCard.emote); sendChat("", "/direct " + DisplayCard); } } } }; function buildinline(inlineroll){ var InlineBorderRadius = (POWERCARD_ROUNDED_INLINE_ROLLS) ? 5 : 0; var InlineColorOverride = ""; var values = []; var critRoll = false; var failRoll = false; var critCheck = false; var failCheck = false; var highRoll = false; var lowRoll = false; var noHighlight = false; inlineroll.results.rolls.forEach(function(roll){ var result = processRoll(roll, critRoll, failRoll, highRoll, lowRoll, noHighlight); if (result.value.toString().indexOf("critsuccess") != -1) critCheck = true; if (result.value.toString().indexOf("critfail") != -1) failCheck = true; values.push(result.value); critRoll = result.critRoll; failRoll = result.failRoll; highRoll = result.highRoll; lowRoll = result.lowRoll; noHighlight = result.noHighlight; }); // Overrides the default coloring of the inline rolls... if (POWERCARD_INLINE_ROLL_COLOR_OVERRIDE) { if (critCheck && failCheck) { InlineColorOverride = " background-color: " + POWERCARD_INLINE_BOTH_BACKGROUND + "; border-color: " + POWERCARD_INLINE_BOTH_BORDER + "; color: " + POWERCARD_INLINE_BOTH_TEXT_COLOR + ";"; } else if (critCheck && !failCheck) { InlineColorOverride = " background-color: " + POWERCARD_INLINE_CRIT_BACKGROUND + "; border-color: " + POWERCARD_INLINE_CRIT_BORDER + "; color: " + POWERCARD_INLINE_CRIT_TEXT_COLOR + ";"; } else if (!critCheck && failCheck) { InlineColorOverride = " background-color: " + POWERCARD_INLINE_FAIL_BACKGROUND + "; border-color: " + POWERCARD_INLINE_FAIL_BORDER + "; color: " + POWERCARD_INLINE_FAIL_TEXT_COLOR + ";"; } else { InlineColorOverride = " background-color: " + POWERCARD_INLINE_BASE_BACKGROUND + "; border-color: " + POWERCARD_INLINE_BASE_BORDER + "; color: " + POWERCARD_INLINE_BASE_TEXT_COLOR + ";"; } } // Temporary kludge to get table result... if (inlineroll.results.rolls[0].table !== undefined) inlineroll.results.total = inlineroll.results.rolls[0].results[0].tableItem.name; var rollOut = '<span style="text-align: center; vertical-align: text-middle; display: inline-block; min-width: 1.75em; border-radius: ' + InlineBorderRadius + 'px; padding: 0px 2px; ' + InlineColorOverride + '" title="Rolling ' + inlineroll.expression + ' = ' + values.join(""); rollOut += '" class="a inlinerollresult showtip tipsy-n'; rollOut += (critCheck && failCheck ? ' importantroll' : (critCheck ? ' fullcrit' : (failCheck ? ' fullfail' : ''))) + '">' + inlineroll.results.total + '</span>'; return rollOut; } function buildExpression(numRolls, tag, expression){ var rolls = []; for (var i = 1; i < numRolls; i++){ rolls.push("[[" + expression +"]]"); } return tag + ":" + rolls.join(" "); } function processRoll(roll, critRoll, failRoll, highRoll, lowRoll, noHighlight){ if (roll.type === "C") { return {value: " " + roll.text + " "}; } else if (roll.type === "L") { if (roll.text.indexOf("HR") != -1) highRoll = parseInt(roll.text.substring(2)); else highRoll = false; if (roll.text.indexOf("LR") != -1) lowRoll = parseInt(roll.text.substring(2)); else lowRoll = false; if (roll.text.indexOf("NH") != -1) { // Blocks highlight on an individual roll... noHighlight = true; } // Remove inline tags to reduce clutter... roll.text = roll.text.replace(/HR(\d+)/g, ""); roll.text = roll.text.replace(/LR(\d+)/g, ""); roll.text = roll.text.replace(/NH/g, ""); if (roll.text !== "") roll.text = " [" + roll.text + "] "; return {value: roll.text, highRoll:highRoll, lowRoll:lowRoll, noHighlight:noHighlight}; } else if (roll.type === "M") { roll.expr = roll.expr.toString().replace(/\+/g, " + "); return {value: roll.expr}; } else if (roll.type === "R") { var rollValues = []; roll.results.forEach(function(result){ if (result.tableItem !== undefined) { rollValues.push(result.tableItem.name); } else { // Reset critRoll and failRoll for next roll... critRoll = false; failRoll = false; // Turn off highlighting if true... if (POWERCARD_INLINE_ROLL_NO_HIGHLIGHT || noHighlight) { critRoll = false; failRoll = false; } else { if (highRoll !== false && result.v >= highRoll || result.v === roll.sides) critRoll = true; else if (lowRoll !== false && result.v <= lowRoll || result.v === 1) failRoll = true; } result.v = "<span class='basicdiceroll" + (critRoll ? ' critsuccess' : (failRoll ? ' critfail' : '')) + "'>" + result.v + "</span>"; rollValues.push(result.v); } }); return {value: "(" + rollValues.join(" + ") + ")", critRoll:critRoll, failRoll:failRoll, highRoll:highRoll, lowRoll:lowRoll, noHighlight:noHighlight}; } else if (roll.type === "G") { var grollVal = []; roll.rolls.forEach(function(groll){ groll.forEach(function(groll2){ var result = processRoll(groll2, highRoll, lowRoll, noHighlight); grollVal.push(result.value); critRoll = critRoll || result.critRoll; failRoll = failRoll || result.failRoll; highRoll = highRoll || result.highRoll; lowRoll = lowRoll || result.lowRoll; noHighlight = noHighlight || result.noHighlight; }); }); return {value: "{" + grollVal.join(" ") + "}", critRoll:critRoll, failRoll:failRoll, highRoll:highRoll, lowRoll:lowRoll, noHighlight:noHighlight}; } } function getBrightness(hex) { hex = hex.replace('#', ''); var c_r = hexDec(hex.substr(0, 2)); var c_g = hexDec(hex.substr(2, 2)); var c_b = hexDec(hex.substr(4, 2)); return ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000; } function hexDec(hex_string) { hex_string = (hex_string + '').replace(/[^a-f0-9]/gi, ''); return parseInt(hex_string, 16); }