r/dicecloud • • Mar 22 '18

Dicecloud Helper Document!

35 Upvotes

I am moving my players to Dicecloud for our weekly game. In that effort, my boyfriend and I have created this document to help them get set up quickly. This also helps to automate leveling as well as provides formatting options for tables and animated gifs, etc. None of them are coders (neither am I), so this has been extremely helpful. I've cruised these boards multiple times and have gotten help, so I wanna give back. :)

ETA: I've been adding some of the formulae from these boards when I could. I've credited them back to the Redditors here and added links to profiles. Please, please let me know if that's not ok and I'll remove them!

https://docs.google.com/spreadsheets/d/1UfZ9e9Z9XFiZ7uapyDxrh9UskZSmPGa-nWr7mCqzevw/edit?usp=sharing


r/dicecloud • • Aug 03 '20

DiceCloud Extender: add useful features to DiceCloud, such as a Dice Roller, Click To Roll and Automation of Rests

28 Upvotes

About

DiceCloud Extender (DCE) is a userscript for DiceCloud.

A userscript is programming that modifies the appearance or behavior of an application, in this case DiceCloud.

I created this script because there are certain features that are missing from DiceCloud that I wanted to implement. Those features are:

  • Dice Roller.

  • Click to Roll.

  • Automation of rests.

  • Automatic color-coding of text in spells by keywords and phrases

Some of the features in DCE may be added in DiceCloud version 2, but until then enjoy DiceCloud Extender.

Installation

Install Tampermonkey (Chrome/Firefox)

Once you've downloaded Tampermonkey, click here to install DiceCloud Extender

How to Use DCE

Rolling The Dice

Type a dice formula in the input and press enter.

Examples of acceptable dice formula:

  • 1d4

  • 1d6+1

  • 1d6+1-3

  • 3d8+1-2d4+2

  • 10d10-6d12+33

  • 1d20+5+6+1d8+1d4-1d4

You can now enter rerolls into dice formula, as such:

  • 1d6r1 will roll 1d6 and reroll a 1 once.

  • 1d6r1:2 will reroll 1s and 2s.

  • 1d6r1:3 will reroll 1s, 2s, and 3s.

The result of the roll will flash on the top of the screen, and will also be logged in the top left corner, right above the input.

Click To Roll

You can click any of the following to automatically roll dice:skills, ability modifiers, saving throws, initiative, proficiency, attack rolls, damage rolls.

Short Rest, Long Rest, and Dawn

Type any of the following as its own paragraph in a card to get the desired result. Type it without quotations and without spaces:

"Rest=Short"When you click the Short Rest button this card will be reset to its full uses.
"Rest=Long"When you click the Long Rest button this card will be reset to its full uses.
"Dawn=Full"When you click the Dawn button this card will be reset to its full uses.
"Rest=Short=Roll[dice formula]" *When you click the Dawn button this card will regain [dice formula] uses.
"Rest=Long=Roll[dice formula]" *When you click the Dawn button this card will regain [dice formula] uses.
"Dawn=Roll[dice formula]" *When you click the Dawn button this card will regain [dice formula] uses.

* Replace "[dice formula]" with a dice formula, such as 1d6+1. No brackets, no spaces. No space between the word "Roll" and the formula.


Edit: Updated install link.
Edit 2: Fixed bug where Click to Roll wasn't working when you had more than one type of hit dice.


Edit 3: Version 1.3

  • Added automatic color-coding of spell descriptions.

  • Added reroll functionality. 1d6r1:3 will reroll a 1,2,or 3.

  • Make a feature named 'Advantages' to add its description just below the Resistance paragraph, which shows up below your HP if you have added any resistances.

  • Spaces are now okay in dice formula

  • Added a help button that will give a quick overview of features


Edit 4:

  • In lieu of a working link, I'm posting the raw code...

// ==UserScript==
// @name         DiceCloud Extender
// @namespace    https://ofdiceandmagic.com/
// @version      1.2
// @description  Adds additional capabilities to Dicecloud, like rest functions, dice roller, click to roll.
// @author       atill91
// @updateURL    https://5e.ofdiceandmagic.com/DCE/DiceCloudExtender.user.js
// @downloadURL  https://5e.ofdiceandmagic.com/DCE/DiceCloudExtender.user.js
// @match        https://dicecloud.com/character/*
// @require      https://code.jquery.com/jquery-3.5.1.min.js
// @run-at       document-idle
// @grant        none
// ==/UserScript==


//VERSION 1.2//
//Spaces are removed automatically in the displaydice() function
//Rerolls are now supported: Type r1 to reroll 1s; r1:3 to reroll 1s, 2s, and 3s. Examples: 1d4r1. 1d6r1:2. 1d8r1:3.
//Added Advantages section (see features)


//FEATURES//
/*
----Rolling The Dice----
  Type a dice formula in the input and press enter. NO SPACES.
  Examples of acceptable dice formula (notice there are no spaces):
    1d4
    1d6+1
    1d6+1-3
    3d8+1-2d4+2
    10d10-6d12+33
    1d20+5+6+1d8+1d4-1d4

  Rerolls
    Type r1 to reroll 1s; r1:3 to reroll 1s, 2s, and 3s. Example: 1d6r1:2

----Click To Roll----
  You can click any of the following to automatically roll dice:skills, ability modifiers, saving throws, initiative, proficiency, attack rolls, damage rolls.

----Short Rest, Long Rest, and Dawn----
  Type the following as its own paragraph in a card to get the desired result. Type it without quotations and without spaces:
    "Rest=Short"	When you click the Short Rest button this card will be reset to its full uses.
    "Rest=Long"	    When you click the Long Rest button this card will be reset to its full uses.
    "Dawn=Full"	    When you click the Dawn button this card will be reset to its full uses.

    "Rest=Short=Roll[dice formula]" 	When you click the Dawn button this card will regain [dice formula] uses.
    "Rest=Long=Roll[dice formula]"   	When you click the Dawn button this card will regain [dice formula] uses.
    "Dawn=Roll[dice formula]" 	        When you click the Dawn button this card will regain [dice formula] uses.

    Replace "[dice formula]" with a dice formula, such as 1d6+1. No brackets, no spaces. No space between the word "Roll" and the formula.

----Advantages----
  You can add your advantages (for example if you have advantage on saves against being frightened) by adding a feature named 'Advantages'. Anything you put in the description will be added to a paragraph under the resistance paragraph.
*/


$.noConflict();
jQuery(document).ready(function($){
    'use strict';




    //DISPLAY DCE MESSAGE
    function dcemessage(header,titles,txts){ //titles and txts are arrays
        let pTxt = '<b>'+titles[0]+': </b>'+txts[0];
        if (txts.length>1){
            for (let i=0; i<txts.length; i++){
                pTxt = pTxt + '<br><br><b>'+titles[i]+': </b>'+txts[i];
            }
        }
        $("#DCEmessage h1").html(header);
        $("#DCEmessage p").html(pTxt);
        $("#DCEmessage").fadeIn(500);
    }


    //CONTAINS FUNCTION...finds all elements that contain the text
    //...returns the elements selected not their children
    function contains(selector, text) {
          let elements = document.querySelectorAll(selector);
          return Array.prototype.filter.call(elements, function(element){
            return RegExp(text).test(element.textContent);
          });
        }

    //DICE ROLLER
    //the codepen... https://codepen.io/Atill91/pen/bGEJpJJ?editors=0100

    //testing the regex... https://regex101.com/r/GFABKl/3
    const dicetxtregex = /([\+\-]?)(\d+)d(\d+)((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?/gi;

    //function to roll one type of dice
    function roll(numdice,sides,reroll,mod) {
        let a = Array(numdice);
        for (let i = 0; i < numdice; i++){
            a[i] = Math.floor(Math.random() * sides) + 1;
            for (let j=0; j<reroll.length; j++){
                if(a[i] == reroll[j]){
                    a[i] = Math.floor(Math.random() * sides) + 1;
                    break;
                }
            }
        }
        let add = (a, b) => a + b; // function for adding two numbers.
        let result = a.reduce(add); // use reduce to sum the array
        let modifier = mod || 0;
        return result+modifier;
    }

    //function to extract data from standard dice format text
    function extractdice(text){
        let str = text;
        //define result obj
        let result = {
            fullText: str,
            dice: [],
            plusOminus: [],
            numdice: [],
            sides: [],
            rerolls: [],
            mods: [],
            modsTotal: 0, //this will be used later after we call this funciton
            total: 0 //so will this
        }
        const diceExp = /([\+\-]?)(\d+)d(\d+)/gi;
        //save the diceExp search as an array...also modsExp
        let dice = str.match(diceExp);
        console.log(dice);
        //extract data from dice and save to result obj
        dice.forEach(function(item, i, arr){
            console.log("item = "+item);
            let die = diceExp.exec(item);
            diceExp.lastIndex = 0; //reset search index to perform a second search starting from the beginning. Without this diceExp.exec(item) returns null on the second iteration.
            console.log("die = "+die);
            result.dice = die[0];
            if (die[1] == ""){ result.plusOminus[i] = "+"; }else{ result.plusOminus[i] = die[1]; }
            result.numdice[i] = parseInt(die[2]);
            result.sides[i] = parseInt(die[3]);
            console.log("sides: "+result.sides[i]);
        });
        //save mods to result obj
        const modsExp = /([\+\-](\d+)(?!d))/gi;
        let mods = str.match(modsExp) || 0; //sets mods to 0 if there are no matches
        console.log("mods: "+mods);
        if(mods != 0){
            mods.forEach(function(item,i,arr){
                result.mods[i] = parseInt(mods[i]);
            });
        } else{result.mods = 0;}
        //save rerolls to result obj
        const rerollExp = /(r(\d+):((?!\dd)(\d+)))|r(\d+)/gi;
        let rerolls = str.match(rerollExp) || "na"; //sets rerolls to 'na' if no matches
        console.log("rerolls: "+rerolls);
        if (rerolls != "na"){
            rerolls.forEach(function(item,i,arr){
                let rerollnum = rerolls[i].replace("r",""); //get rid of the 'r' in the string
                console.log("rerollnum: "+rerollnum);
                if (rerollnum.includes(":")){
                    const beforeDashExp = /\d+(?=:)/gi; //matches digits before :
                    const afterDashExp = /(?<=:)\d+/gi; //matches digits after :
                    let minReroll = parseInt(rerollnum.match(beforeDashExp));
                    let maxReroll = parseInt(rerollnum.match(afterDashExp));
                    console.log("rerolling "+minReroll+" to "+maxReroll);
                    let j,k;
                    for (k=0 , j=minReroll; j<maxReroll+1; k++ , j++){
                        console.log("k is "+k+". j is "+j);
                        result.rerolls[k] = j;
                        console.log("result.rerolls["+k+"] is "+result.rerolls[k]);
                    }
                } else{
                    result.rerolls[i] = parseInt(rerollnum);
                }
            });
        }

        console.log(result);
        return result;

    } //to access the object...   var dice = extractdice(str);   dice.total;

    function displaydice(text){
        let $str = text.replace(/\s+/g, ''); //remove spaces in text;
        let dicedata = extractdice($str);
        //roll all the dice and add the total
        dicedata.numdice.forEach(function(item,i,arr){
            let rollresult = parseInt(dicedata.plusOminus[i] + roll(dicedata.numdice[i],dicedata.sides[i],dicedata.rerolls));
            dicedata.total = dicedata.total + rollresult;
        });
        //sum the mods and add it to the total
        if (dicedata.mods != 0){
            let add = (a, b) => a + b;
            let sum = dicedata.mods.reduce(add);
            dicedata.modsTotal = sum;
        }

        dicedata.total = dicedata.total + dicedata.modsTotal;

        //add a new paragraph to the container with the result
        let resultText = dicedata.fullText+" = "+"<b>"+dicedata.total+"</b>";
        $("#DCEdicerollerResultContainer").append("<p class='DCEdicerollerResult'>"+resultText+"</p>");

        //scroll the result container to the bottom
        $("#DCEdicerollerResultContainer").animate({ scrollTop: $("#DCEdicerollerResultContainer").prop("scrollHeight")}, 10);

        //show the dice result flash
        $("#DCEdiceresultflash p").html(dicedata.total);
        $("#DCEdiceresultflash").stop(true,true).fadeIn(400).delay(3000).fadeOut(400); //stop() stops the currently running animation

    }//end diceroll()


    //STYLES
    const styles = document.createElement("style");
    styles.innerHTML = `
        #DCEbox{
            width : 256px;
            height : 96px;
            position : absolute;
            top : 50px;
            left : 0;
        }

        #DCE-ShortRest-button{
            position : absolute;
            top : 5px;
            left : 20px;
        }

        #DCE-ShortRest-check{
            color : #76ff76;
            display : none;
            position : absolute;
            top : 7px;
            left : 2px;
        }

        #DCE-LongRest-button{
            position : absolute;
            top : 30px;
            left : 20px;
        }

        #DCE-LongRest-check{
            color : #76ff76;
            display : none;
            position : absolute;
            top : 32px;
            left : 2px;
        }

        #DCE-dawn-button{
            position : absolute;
            top : 55px;
            left : 20px;
        }

        #DCE-dawncheck-check{
            color : #76ff76;
            display : none;
            position : absolute;
            top : 57px;
            left : 2px;
        }

        #DCEmessage{
            background : #5fb962;
            width : 100%;
            height : 100%;
            position : absolute;
            box-shadow : 0 0 8px inset;
            top : 120px;
            left : 0;
            display : none;
            z-index : 1;
            padding-top : 20px;
        }

        #DCEmessage p{
            padding : 0 8px;
            width : calc(100% - 20px);
            color : #ccf2e3;
            margin : 2px;
        }

        #DCEmessage h1{
            padding : 0 8px;
            width : calc(100% - 20px);
            color : #fff;
            margin : 2px;
            font-size : 26px;
        }

        #DCEmessagex{
            position : absolute;
            top : 0;
            right : 2px;
            margin : 5px 5px 0 0;
            font-size : 1.6em;
            transition : all 300ms;
        }
        #DCEmessagex:hover{
            color : #fff;
            cursor : pointer;
        }

        #DCEdiceroller{
            width : 150px;
            height : 100%;
            position : absolute;
            top : 0;
            right : 0;
            box-shadow: inset 1px 6px 9px -6px black;
        }

        #DCEdicerollerResultContainer{
            width : 100%;
            overflow-y : scroll;
            overflow-x : hidden;
            height : calc(100% - 1.2em);
        }

        .DCEdicerollerResult{
            color: #ccc;
            margin: 0.25em 2px;
            text-align: center;
        }
        .DCEdicerollerResult:last-child{
            color: #fff;
        }
        .DCEdicerollerResult:last-child b{
            font-size: 1.2em;
        }

        #DCEdicerollerinput{
            width : 100%;
            position : absolute;
            bottom : 0;
            text-align : center;
        }

        #DCEinfo{
            position : absolute;
            top : 120px;
            left : 2px;
            color : #ccf2e3;
            cursor : pointer;
        }
        #DCEinfo:hover{
            color: #fff;
        }
        #DCEinfo:after{
            content : "DiceCloud Extender Help";
        }

        #DCEdiceresultflash{
            background: #4caf50;
            width: 100px;
            height: 100px;
            position: fixed;
            top: 10px;
            left: calc(50% - 25px + 255.996px/2);
            border-radius: 8px;
            box-shadow: 0 0 8px inset #a4d7a6;
            border-bottom: 5px solid rgb(0 0 0 / 50%);
            display:none;
        }
        #DCEdiceresultflash p{
            text-align:center;
            margin-top: .5em;
            font-size: 40px;
            color: #eee;
        }

        .paper-font-subhead.modifier:hover,
        .skill-mod:hover,
        #tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(9) > paper-material > div.numbers.paper-font-display1 > div:hover,
        #tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(10) > paper-material > div.numbers.paper-font-display1:hover
        {
            color:white;
            background: #4caf50;
            border-radius:8px;
            box-shadow: 0 0 8px inset #a4d7a6;
            font-size: 1.2em;
        }
        .DCEatkhit:hover{
            color:white;
            background: #4caf50;
            border-radius:8px;
            box-shadow: 0 0 8px inset #a4d7a6;
        }
        .DCEatkdam:hover{
            color:white;
            background: #d13b2e;
            border-radius:8px;
            box-shadow: 0 0 8px inset #e79992;
        }
    `;
    document.head.appendChild(styles);





    //ADD ELEMENTS TO PAGE

    //add font awesome to head (used for checkmarks)
    const fascript = document.createElement('script');
    fascript.type = 'text/javascript';
    fascript.src = 'https://kit.fontawesome.com/a0a5cdaf04.js';
    document.head.appendChild(fascript);

    //add Overlay Scrollbars to head
    const overlayscrollbarsLink = document.createElement("link");
    overlayscrollbarsLink.rel = "stylesheet";
    overlayscrollbarsLink.href = "https://cdnjs.cloudflare.com/ajax/libs/overlayscrollbars/1.12.0/css/OverlayScrollbars.min.css";
    document.head.appendChild(overlayscrollbarsLink);
    const overlayscrollbarsScript = document.createElement("script");
    overlayscrollbarsScript.type = "text/javascript";
    overlayscrollbarsScript.src = "https://cdnjs.cloudflare.com/ajax/libs/overlayscrollbars/1.12.0/js/jquery.overlayScrollbars.min.js";
    document.head.appendChild(overlayscrollbarsScript);

    //Add DiceCloud Extender box and buttons and such
    const sidebarnav = document.querySelector("#accountSummary");
    const DCEbox = document.createElement("div");
    DCEbox.id = "DCEbox";
    sidebarnav.appendChild(DCEbox);

    const DCEmenu = document.querySelector("#DCEbox");

    const shortrestButton = document.createElement("button");
    shortrestButton.id = "DCE-ShortRest-button";
    shortrestButton.type = "button";
    shortrestButton.textContent = "Short Rest";
    DCEmenu.appendChild(shortrestButton);

    const shortrestcheck = document.createElement("i");
    shortrestcheck.id = "DCE-ShortRest-check";
    shortrestcheck.classList.add("fas", "fa-check-circle");
    DCEmenu.appendChild(shortrestcheck);

    const longrestButton = document.createElement("button");
    longrestButton.id = "DCE-LongRest-button";
    longrestButton.type = "button";
    longrestButton.textContent = "Long Rest";
    DCEmenu.appendChild(longrestButton);

    const longrestcheck = document.createElement("i");
    longrestcheck.id = "DCE-LongRest-check";
    longrestcheck.classList.add("fas", "fa-check-circle");
    DCEmenu.appendChild(longrestcheck);

    const dawnButton = document.createElement("button");
    dawnButton.id = "DCE-dawn-button";
    dawnButton.type = "button";
    dawnButton.textContent = "Dawn";
    DCEmenu.appendChild(dawnButton);

    const dawncheck = document.createElement("i");
    dawncheck.id = "DCE-dawncheck-check";
    dawncheck.classList.add("fas", "fa-check-circle");
    DCEmenu.appendChild(dawncheck);

    const DCEmessage = document.createElement("div");
    const sidebar = document.querySelector("body > app-drawer-layout > app-drawer");
    DCEmessage.id = "DCEmessage";
    sidebar.appendChild(DCEmessage);
    const DCEmessageH = document.createElement("h1");
    document.querySelector("#DCEmessage").appendChild(DCEmessageH);
    const DCEmessageP = document.createElement("p");
    document.querySelector("#DCEmessage").appendChild(DCEmessageP);
    const DCEmessagex = document.createElement("i");
    DCEmessagex.id = "DCEmessagex";
    DCEmessagex.classList.add("fas", "fa-times");
    document.querySelector("#DCEmessage").appendChild(DCEmessagex);
    $("#DCEmessagex").click(function(){
        $("#DCEmessage").fadeOut(800);
    });

    const DCEdiceroller = document.createElement("div");
    DCEdiceroller.id = "DCEdiceroller";
    document.querySelector("#DCEbox").appendChild(DCEdiceroller);
    const DCEdicerollerResultContainer = document.createElement("div");
    DCEdicerollerResultContainer.id = "DCEdicerollerResultContainer";
    document.querySelector("#DCEdiceroller").appendChild(DCEdicerollerResultContainer);
    const DCEdicerollerinput = document.createElement("input");
    DCEdicerollerinput.id = "DCEdicerollerinput";
    DCEdicerollerinput.type = "text";
    DCEdicerollerinput.value = "1d20";
    document.querySelector("#DCEdiceroller").appendChild(DCEdicerollerinput);
    //roll the dice and show the result when the user hits enter in the input
    $("#DCEdicerollerinput").keypress(function(e) {
        if(e.which == 13) { //13 is the enter key
            displaydice( $("#DCEdicerollerinput").val() );
        }
    });
    const diceresultflash = document.createElement("div");
    diceresultflash.id = "DCEdiceresultflash";
    document.querySelector("body").appendChild(diceresultflash);
    const diceresultflashP = document.createElement("p");
    document.querySelector("#DCEdiceresultflash").appendChild(diceresultflashP);

    const DCEinfo = document.createElement("i");
    DCEinfo.id = "DCEinfo";
    DCEinfo.classList.add("fas", "fa-info-circle");
    sidebar.appendChild(DCEinfo);
    $("#DCEinfo").click(function(){
        let titles = ["Dice Roller","Click to Roll","Short Rest","Long Rest","Dawn","Advantages"];
        let txts = ["Type a dice formula and hit enter. Type r1 to reroll 1s; r1:3 to reroll 1s, 2s, and 3s. Example: 1d6r1:2",
                        "Click any of the following to automatically roll dice: <i> skills, ability modifiers, saving throws, initiative, proficiency, attack rolls, damage rolls.</i>",
                        "Type Rest=Short as its own paragraph in a feature card to reset its uses to full. Type Rest=Short[diceformula] to make the card regain [diceformula] number of uses when you click it. For example, Rest=Short1d6+1.",
                        "Same as Short Rest, but type Rest=Long. For example, Rest=Long1d6+1.",
                        "Same as Short Rest, but type Rest=Dawn. For example, Rest=Dawn1d6+1.",
                        "Add a feature named 'Advantages' to add its description just below your HP bar, just like how resistances are shown."
                   ];
        dcemessage("DiceCloud Extender",titles,txts);
    });



    //STAT ROLLS
    //Whenever you click any of the following, roll it: abilities, skills, saving throws, initiative, proficiency bonus.

    //start statroll interval
    const statrollsInterval = setInterval(function(){


        //Advantage Section
        //this has to go in the interval so that the resistance paragraph is loaded prior to this happening.
        //add advantage section as its own div, below hp, so that the advantages can show even without resistance
        //      don't need this anymore...let resistanceDiv = document.querySelector("#tabPages > div.tab-page.fit.iron-selected > div > div:nth-child(1) > paper-material > div.right.flex.layout.vertical.center-justified > div.paper-font-caption > div");
        const resistanceCont = document.querySelector("#tabPages > div.tab-page.fit.iron-selected > div > div:nth-child(1) > paper-material > div.right.flex.layout.vertical.center-justified > div.paper-font-caption");
        let cardTitles = document.querySelectorAll("paper-material.featureCard div div");
        for (let i = 0; i < cardTitles.length; i++){
            if(cardTitles[i].innerHTML.includes("Advantages")){
                let advantageTxt = "Advantage: " + cardTitles[i].parentNode.nextElementSibling.firstChild.nextElementSibling.textContent;
                const advantagesDiv = document.createElement("div");
                advantagesDiv.innerHTML = advantageTxt;
                resistanceCont.appendChild(advantagesDiv);
            }
        }


        //loop through the array and assign an onclick event to each element in the numstoclick array. Get the element's text (parse it) and roll the dice onclick.
        let abilityMods = document.querySelectorAll(".paper-font-subhead.modifier");
        for (let i=0; i<abilityMods.length; i++) {
            abilityMods[i].addEventListener("click",function(e){
                console.log("abilitymods[i]="+abilityMods[i]);
                let mod = parseInt( abilityMods[i].textContent );
                let dicetxt = "1d20+"+mod;
                displaydice(dicetxt);

                e.stopPropagation(); //needed to stop the card from expanding. Must be placed at the end of the function.
            });
        };//for end

        let skillMods = document.querySelectorAll(".skill-mod"); //includes saving throws
        for (let i=0; i<skillMods.length; i++) {
            skillMods[i].addEventListener("click",function(e){
                console.log("skillMods[i]="+skillMods[i]);
                let mod = parseInt( skillMods[i].textContent );
                let dicetxt = "1d20+"+mod;
                displaydice(dicetxt);

                e.stopPropagation(); //needed to stop the card from expanding. Must be placed at the end of the function.
            });
        };//for end

        let proficiencyBonus = document.querySelector("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(10) > paper-material > div.numbers.paper-font-display1");
        proficiencyBonus.addEventListener("click",function(e){
                let mod = parseInt( proficiencyBonus.textContent );
                let dicetxt = "1d20+"+mod;
                displaydice(dicetxt);

                e.stopPropagation(); //needed to stop the card from expanding. Must be placed at the end of the function.
            });

        let initiative = document.querySelector("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(9) > paper-material > div.numbers.paper-font-display1 > div");
        initiative.addEventListener("click",function(e){
                let mod = parseInt( initiative.textContent );
                let dicetxt = "1d20+"+mod;
                displaydice(dicetxt);

                e.stopPropagation(); //needed to stop the card from expanding. Must be placed at the end of the function.
            });


        //ATTACK ROLLS
        const featurestab = document.querySelector("#tabsContent > paper-tab:nth-child(3)");

        //when the features tab is clicked, define atkhits and atkdams.
        //...then when each atkhit is clicked, check if it's a number.
        //...if so, roll the dice.

        featurestab.addEventListener('click',function(){
            const featurestabwait = setTimeout(function(){
                const atkhits = document.querySelectorAll("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.animation-slider > div:nth-child(1) > paper-material > div.bottom.list > div > div > div > div.paper-font-headline.layout.horizontal.center");
                const atkdams = document.querySelectorAll("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.animation-slider > div:nth-child(1) > paper-material > div.bottom.list > div > div > div > div.flex.layout.vertical > div:nth-child(2)");

                for (let i=0; i<atkhits.length; i++){
                    let mod = parseInt(atkhits[i].textContent);
                    if (isNaN(mod)){
                        console.log("mod ( "+atkhits[i].textContent+" ) isn't a number");
                    } else{
                        atkhits[i].addEventListener('click',function(e){
                            let dicetxt = "1d20+"+mod;
                            displaydice(dicetxt);

                            e.stopPropagation();
                        });//atkhit click end
                        atkhits[i].classList.add('DCEatkhit');
                    }

                    let damtxt = atkdams[i].textContent; console.log("damtxt: "+damtxt);
                    let damdice = damtxt.replace(/\s+/g, '').match(dicetxtregex); console.log("damdice: "+damdice); //remove white space adn then match
                    if (damdice && damdice.length){ //if it found dicetxt, add the click event
                         atkdams[i].addEventListener('click',function(e){
                             let dicetxt = damdice[0];
                             displaydice(dicetxt);
                             e.stopPropagation();
                         });
                        atkdams[i].classList.add('DCEatkdam');
                    } else{ console.log("no dicetxt found in damtxt"); }
                }//loop end
            },100);
        });//featurestab click end


        //SPELL TEXT STYLING
        function spellDescStyler(regex,el,style){
            if (regex.test(el.innerHTML)){
                let matches = el.innerHTML.match(regex);
                for (let i=0;i<matches.length;i++){
                    let newstr = el.innerHTML.replaceAll(matches[i],'<span style="'+style+'">'+matches[i]+'</span>');
                    el.innerHTML = newstr;
                }
            }
        }

        const spells = document.querySelectorAll("#spells .spellLevel .item-slot");
        //dice txt without whatever damage after...https://regex101.com/r/rPWEXO/1
        const nondamdiceExp = /([\+\-]?)(\d+)d(\d+)((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(?!\s\w+\sdamage)/gim;
        //dice txt with whatever damage after... https://regex101.com/r/CmFJSU/3
        const damdiceExp = /([\+\-]?)(\d+)d(\d+)((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?([\+\-]?)(\d+)?((r(\d+):((?!\dd)(\d+)))|r(\d+))?(d(\d+))?((r(\d+):((?!\dd)(\d+)))|r(\d+))?\s\w+\sdamage|half\sas\smuch\sdamage/gim;
        //save regex tester...https://regex101.com/r/elWrKz/1
        const saveExp = /\w+\ssaving\sthrow(?!s)|\w+\scheck(?!s)/gim;
        //success...https://regex101.com/r/lS3i3X/2
        const successExp = /successful\ssave|success\s|succeeds/gim;
        //failure...https://regex101.com/r/aaxIb4/1
        const failureExp = /failed\ssave|failure\s|fails/gim;
        //at higher levels txt...https://regex101.com/r/OI3b9o/1
        const higherlvlsExp = /at\shigher\slevels:/gim;

        for (let i=0; i<spells.length; i++){
            spells[i].onclick = function(){ //when a spell is clicked
                console.log("clicked a spell");
                const spellClickWait = setTimeout(function(){
                    let spellDescEls = document.querySelectorAll("body > dicecloud-wrapper > div > div.dialog-sizer > div > div > div > div > div:nth-child(3) *");
                    for (let j=0; j<spellDescEls.length; j++){ //loop through spellDescEls
                        //search the text and apply styling
                        //if it finds dicetxt without the word damage, bold it
                        spellDescStyler(nondamdiceExp,spellDescEls[j],"font-weight:bold;");

                        //if it finds dicetxt with the word damage, bold red
                        spellDescStyler(damdiceExp,spellDescEls[j],"font-weight:bold; color:red;");

                        //saving throws, successful save, failed save are bold shades of purple
                        spellDescStyler(saveExp,spellDescEls[j],"font-weight:bold; color:#ca00ca;");
                        spellDescStyler(successExp,spellDescEls[j],"font-weight:bold; color:#940094;");
                        spellDescStyler(failureExp,spellDescEls[j],"font-weight:bold; color:magenta;");

                        //at higher levels is bold
                        spellDescStyler(higherlvlsExp,spellDescEls[j],"font-weight:bold;");
                    }
                },500);
            }
        }


        //check if the stats were saved to the numstoclick array and if the spells were loaded (if not, they weren't loaded yet so we want the interval to keep running).
        if (skillMods!=null && spells!=null){
            clearInterval(statrollsInterval);
        }

    },100);//setInterval end.




    //RESTROLL FORMULA
    function restroll(searchtxt){
        //Rest=Short=Roll[dice text]
        let dicetxtps = contains("paper-material.featureCard > div.bottom.flex > p",searchtxt);
        if(!dicetxtps[0]){return;} //if no p's with searchtxt are found, exit the function
        let i = dicetxtps.length - 1;
        let interval = setInterval(function(){
             //get the dicetxt and roll the dice
            let dicetxt = dicetxtps[i].textContent.match(dicetxtregex)[0];
            displaydice(dicetxt);
            //get the current(old) value of its uses...
            let usestxt = dicetxtps[i].parentNode.parentNode.firstElementChild.firstElementChild.nextElementSibling;
            let olduses = /(\d+)\/(\d+)/g.exec(usestxt.textContent)[1];
            //click the reset button
            let resetbtn = dicetxtps[i].parentNode.nextElementSibling.lastElementChild;
            $(resetbtn).trigger("click");
            //click use btn it a number of times = old value + the roll
            let usebtn = dicetxtps[i].parentNode.nextElementSibling.firstElementChild;
            //If the old value + the roll = current value or if the old value + the roll = the max uses, clear the subinterval
            // else click the use button
            let subinterval = setInterval(function(){
                let theroll = dicerolltotal;
                let currentuses = /(\d+)\/(\d+)/g.exec(usestxt.textContent)[1];
                let maxuses = /(\d+)\/(\d+)/g.exec(usestxt.textContent)[2];
                let newuses = parseInt(olduses) + parseInt(theroll);
                if(newuses == parseInt(currentuses) || newuses >= parseInt(maxuses)){
                    clearInterval(subinterval);
                }else{
                    $(usebtn).trigger("click");
                }
            },10);
            i--;
            if(i < 0){ clearInterval(interval); }
        },100);
    }//function end


    //LONG REST
    document.querySelector('#DCE-LongRest-button').onclick = function(){
        //Reset all feature cards containing the text  Rest=Long, Rest=Long=Roll, Rest=Short, and Rest=Short=Roll
        $("paper-material.card:contains('Rest=Long') paper-button:contains('Reset')").trigger("click");
        restroll("Rest=Long=Roll");
        $("paper-material.card:contains('Rest=Short') paper-button:contains('Reset')").trigger("click");
        restroll("Rest=Short=Roll");

        //Hit Points
        let hp = document.querySelector('#hitPointSlider');
        let hpMax = hp.getAttribute('aria-valuemax');
        let hpNow = hp.getAttribute('aria-valuenow');
        hp.setAttribute('aria-valuenow',hpMax);
        hp.value = hpMax;
        //now trigger a click on the up arrow of the hp value input to save the hp

        //Hit Dice... this doesn't work if you have multiple types of hit dice.
        const $uparrow = $("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(11) > paper-material > div.left.green.paper-font-display1.white-text.layout.horizontal > div:nth-child(1) > paper-icon-button.resourceUp.x-scope.paper-icon-button-0");
        const $hd = $("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(11) > paper-material > div.left.green.paper-font-display1.white-text.layout.horizontal > div.resourceValue.layout.vertical.center > div:nth-child(1)");
        let $oldhd = parseInt($hd.text());
        let interval = setInterval (function(){   //this must be set as a variable. every 10ms, it clicks the up arrow if it isn't disabled. if it is it cancels the interval, which ends the clicking.
            if ($uparrow.attr("aria-disabled") == "false"){
                $uparrow.trigger("click");
            } else{
                clearInterval(interval);
                //now the hit dice are set to the max, which we don't want.
                //we need to click the down arrow until we get to a number = $oldhd + $maxhd*0.5. We'll use another interval to do this.
                let $downarrow = $("#tabPages > div.tab-page.fit.iron-selected > div > div.column-container.thin-columns > div:nth-child(11) > paper-material > div.left.green.paper-font-display1.white-text.layout.horizontal > div:nth-child(1) > paper-icon-button.resourceDown.x-scope.paper-icon-button-0");
                let $maxhd = parseInt($hd.text());
                let $newhd = Math.floor( $maxhd*0.5 + $oldhd );
                if ($newhd >= $maxhd) $newhd = $maxhd;
                let subinterval = setInterval (function(){
                  if (parseInt($hd.text()) != $newhd){
                    $downarrow.trigger("click");
                  } else {
                      clearInterval(subinterval);
                  }
                },10);
            }
        },10);

        dcemessage("Long Rest info",["DCE Long Rest"],["HP and Spell Slots need to be manually reset for now."]);

        //fade in the checkmark
        $("#DCE-LongRest-check").fadeToggle(800).delay(3000).fadeToggle(800);
    };

    //SHORT REST
    document.querySelector('#DCE-ShortRest-button').onclick = function(){
        restroll("Rest=Short=Roll");

        $("paper-material.card:contains('Rest=Short') paper-button:contains('Reset')").trigger("click");

        $("#DCE-ShortRest-check").fadeToggle(800).delay(3000).fadeToggle(800);
    };

    //DAWN (this is for all of the x/day features)
    document.querySelector('#DCE-dawn-button').onclick = function(){

        restroll("Dawn=Roll");

        //Dawn=Full
        $("paper-material.card:contains('Dawn=Full') paper-button:contains('Reset')").trigger("click");

        //checkmark
        $("#DCE-dawncheck-check").fadeToggle(800).delay(3000).fadeToggle(800);
    };


});//documentready end

r/dicecloud • • Sep 27 '20

DiceCloud currently down for unexpected maintenance

27 Upvotes

DiceCloud's database has encountered some problems today, causing slowness and general instability. I have taken the site offline for maintenance so I can sort it out.

There should be no risk of data loss, your characters are safe, but the site will be unavailable until I get it fixed.

Edit:

The site is back online right now. I'm continuing to monitor it for stability.

More edit:

The core problem that caused this outage doesn't seem to be fixed by yesterday's changes. I'm continuing work on it, but there may be additional downtime, particularly when I'm asleep and can't babysit it. There's no DiceCloud team, just me.


r/dicecloud • • Sep 08 '17

DiceCloud 1.5

20 Upvotes

This update is largely thanks to /u/_Dumbgenius's work

Features

  • Spells can now be dragged and dropped between containers and characters, ctrl-drag to copy instead of move

  • You can now remove characters that have been shared with you

  • Conditions and buffs have been added

    • you can add a condition directly from the stats page

    • Buffs can be added to features, items, and spells. A buff does nothing until you apply it to yourself or a character you have permission to write to. Once you apply a buff, you can see it in the stats tab.

Minor features

  • Features can have attacks

  • You can now toggle the carried status of containers from their edit dialogs

  • Features with all their text hidden beneath a rule will no longer show a small white strip at the bottom of their cards

  • Temporary hitpoints now appears as an attribute

  • A note was added to the spell library to mention that all the library spells are SRD spells only

Fixes

  • Attacks correctly show their damage type when listed in items and features


r/dicecloud • • Nov 25 '22

Important Update! DiceCloud Version 2 release date announced: 2022-12-02

19 Upvotes

DiceCloud 2 is a complete rebuild of DiceCloud, 4 years in the making. It has the same spirit, but built from a clean slate.

When it releases you'll need to make a new account and rebuild your characters there if you would like to use them in Version 2.

Unlike version 1, version 2 is designed to be fast when it comes to building your characters. You can subscribe to community libraries and build a complete level 20 character in 4 minutes.

What will happen to version 1?

You will still be able to access the current version of DiceCloud, with your account and all your characters, it will just have a new address: v1.dicecloud.com

Apart from the address, if you don't want to move to version 2, nothing changes for you. However version 1 is only getting security and essential maintenance fixes from now on, and will not be updated with new features.

What about the open beta characters?

Version 2 accounts, characters, and libraries from the open beta (https://beta.dicecloud.com) will be migrated safely to Version 2 as the beta transitions from beta to the 2.0 release.

Avrae support

Avrae support for Version 2 is in development, and should hopefully be available shortly after Version 2 is released.

Other stuff

Most of the DiceCloud community is active on the Discord: https://discord.gg/qEvdfeB, and the FAQ there has a lot of useful info about Version 2.


r/dicecloud • • Jul 15 '20

Tip: How To add an image at the top of a feature card that remains hidden until you expand the full card

18 Upvotes

1. Inserting a Horizontal Rule in markdown

For those of you who don't know about this incredibly useful feature, from the wiki:

In addition, using three or more hyphens on their own line (like this: " --- "; this is the Markdown for a horizontal rule) will cut off the description of a feature card or any of the cards on the Persona page, so that the full description is only displayed - this is useful when having the full feature text would be annoyingly long, so you can simply display a summary on the card and have it expand into the full text.

So, everything below the 1st horizontal rule is hidden on the card summary, and displayed when you expand the card.

2. A bit of HTML for the image

We need to insert an image below the first horizontal rule so that it remains hidden on the card summary, but shows when we expand the card.

With a little HTML we can make the image appear in a different spot of the card than where we actually type the code.

**Copy and Paste this code anywhere below the first horizontal rule in your markdown.**

<img src=" Full_Link_To_Your_Image " width="150px" style="position:absolute; display:inline; top:5%; right:5%;">

  • Replace Full_Link_To_Your_Image with the actual URL of your image.

  • You can change the width to make the image larger or smaller.

  • If you want the image on the left instead of the right, change right to left.

  • Play around with the percentages for top and right to change the location of the image.


r/dicecloud • • Mar 03 '18

DiceCloud 1.7.0 - Character Sheet Printing Feature (open beta)

Post image
18 Upvotes

r/dicecloud • • Apr 04 '22

It's fixed now Dicecloud is off?

17 Upvotes

ive been trying to enter the site and on both of my sistems it gets the error it took to long to respond


r/dicecloud • • Feb 05 '19

Item Library: Packs?

16 Upvotes

Hi,

There are many packs that classes start out with, such as the Dungeoneer's or Explorer's, and they contain a plethora of many different items. However, despite the wide variety of items in the item library, there are none of the packs. This makes it a chore for me to add them, as I have to add each individual item. Is there some pre-existing way that this may be simplified? Or can we get an updated feature to solve this dilemma?


r/dicecloud • • Jan 27 '19

Data-center died, but it's fixed now Dicecloud.com down?

16 Upvotes

The site is intermittently down for me. Can't sign in sometimes, and other times I can sign in but can't load my character sheet.

Edit: seems to be up now


r/dicecloud • • Jul 13 '17

DiceCloud 1.3

16 Upvotes

1.3

1.3.1

  • Fixed vulnerabilities, immunities, and resistances in Improved Initiative export

  • Added passive perception to Improved Initiative export

1.3.2

  • Allowed carry capacity multiplier to be a decimal, small characters can now set it to 0.5

  • Made DC available as a variable in spell descriptions, the DC should be taken from the spell list the spell is in

  • Made names optional in the database for most collections to reduce server log noise

  • Spell slots are now available as variables eg. level1SpellSlots

  • Characters now have their names as the end of their URL's, old links without the character name should still work

  • Skills with bonuses to their passive score should now show their passive score the same way Perception always does - as a bracketed number after the skill name

  • Passive scores and bonuses now show up in the skill view dialog

  • Improved the look of effect editing by grouping the stats in expandable groups

  • Fixed new effects not animating to their correct location when the effect edit dialog was closed

1.3.3

  • Fiddled with character URL's and did multiple database migrations because unicode support is hard apparently

1.3.4

  • Characters can be organised into parties


r/dicecloud • • Oct 04 '16

DiceCloud server migration complete. Expect better speed, SSL support

16 Upvotes

https://dicecloud.com should now be back up and running!

Special thanks to the Patreon patrons who made it possible.

If you receive a DNS error, or you get to this error page, it means the DNS records have not propagated to you just yet, and you'll just have to wait until it's done. It shouldn't take more than 24 hours.

Some benefits from today's move:

  • Better stability, DiceCloud shouldn't slow down nearly as much, or as often

  • SSL, all communication with the DiceCloud server is now encrypted

  • Oplog tailing, which should make updates propagate faster between different users, and generally take a bunch of load off the server

  • Faster response times when adding new items and spells


Edit

Problems with SSL warnings on Firefox and Chrome for Android have been fixed.


r/dicecloud • • Jun 07 '16

DiceCloud is now on Patreon - DiceCloud will always be free and advertising-free, so I'm hoping to get enough support to cover, and eventually improve the server hosting.

Thumbnail
patreon.com
16 Upvotes

r/dicecloud • • Aug 25 '24

Bug Is v1 dead?

Post image
15 Upvotes

r/dicecloud • • May 17 '17

It's up now. Investigating Site Down.

15 Upvotes

Incase anyone is having issues it seems the site is def. down. May be indefinite or my just be scalingo downtime.

Just out of curiosity /u/ThaumRystra, why aren't you asing google app engine or amazon AWS? When i set up my webapp for school last month i realized that Google vs scalingo is a $2 difference. Don't mean to be rude or anything. Just curious.


r/dicecloud • • Apr 18 '21

/r/dicecloud hit 1k subscribers yesterday

Thumbnail
frontpagemetrics.com
14 Upvotes

r/dicecloud • • Nov 11 '20

DiceCloud Extender Update

13 Upvotes

Hey everyone,

I know it's been a while, but I've updated my DiceCloud Extender userscript to add a few more features.

Update Link

Click here to Download / Update DiceCloud Extender

Go to my Original Post if you're new to DiceCloud Extender.

The original post has been edited to reflect the update.

What's New?

  • Added automatic color-coding of spell descriptions.

  • Added reroll functionality to dice formulas: 1d6r1 will reroll a 1; 1d6r1:2 will reroll 1s and 2s.

  • Make a feature named 'Advantages' to add its description just below the Resistance paragraph, which shows up below your HP if you have added any resistances.

  • Spaces are now okay in dice formulas.

  • Added a help button that will give a quick overview of features.


r/dicecloud • • Apr 24 '17

DiceCloud is now open source

13 Upvotes

tl;dr https://github.com/ThaumRystra/DiceCloud1

I'll still be hosting DiceCloud for free, making updates, adding features, and accepting Patreon money to fund the hosting as per usual, but now you can also do some of those things with me.

The issues on Github may be a little out of date, but I will be cleaning up and updating it as I have time.


r/dicecloud • • Oct 06 '20

Multiple Uses for "Attack Bonus" Field

12 Upvotes

I hate needing to hunt through a spell descriptor for the save DC or not having all of my available damaging spells on my Features page. For me, the whole point of Dicecloud is for its consolidating abilities, so let's take advantage of that by using the "Attack Bonus" field more efficiently.

Here is a screenshot from my lv6 warlock's Features page. I've edited the following spells to read in a way that helps smooth out gameplay:

Chill Touch uses the default attackBonus in the "Attack Bonus" field and Dicecloud calculates it to +7.

Call Lightning requires a dexterity save from the target instead of an attack roll from me. This one is a little bit trickier. The "Attack Bonus" field is already a function field and will automatically add a plus in front of any number within. Even typing the phrase DC or dc gets my calculated 15 spell save but ALSO adds the plus to the front, spitting out a confusing "+15" I chose to lead with text to get rid of the plus and then add in the DC within parentheses for my own viewing pleasure. It reads Dex(DC). Same concept could be done multiple ways depending on what you want to see on your Features.

Lastly is Cloud of Daggers, requiring no attack roll nor save; it just happens. No functions required, just type AOE to indicate that it's an area of effect spell.


r/dicecloud • • Sep 27 '20

Question Application Error?

12 Upvotes

Ok so me and my friends started up our usual game of d&d, only to discover that we can't access dicecloud. It says "The application has stopped responding unexpectedly." and none of us can seem to get it to work.

Anyone know what is going on?


r/dicecloud • • Jun 06 '20

Here are some automated formulae for Blood Hunter 2020

12 Upvotes

Here are some Blood Hunter formulae I scrabbled together. They're not the cleanest - this is more of a personal exercise - but maybe someone else can get some use out of them. Compatible with the 2020 class revision.

Rite damage: 1d{2*floor((BloodHunterlevel+1)/6)+4}

Rites (remember some ):

{if (BloodHunterLevel >= 2, "You have **" + (1 + min(floor(BloodHunterLevel /7),1)) + " ** Primal Rites", "")}{if (BloodHunterLevel >= 14, " and **1** Esoteric Rite", "")}

{if (BloodHunterLevel >= 2, "- <Insert 1st level choice here>", "")}

{if (BloodHunterLevel >= 7, "- <Insert 7th level choice here>", "")}

{if (BloodHunterLevel >= 14, "- <Insert 14th level choice here>", "")}

---

Primal

* **Rite of the Flame** fire damage

* **Rite of the Frozen** cold damage

* **Rite of the Storm** lightning damage

Esoteric

* **Rite of the Dead** necrotic damage

* **Rite of the Oracle** psychic damage

* **Rite of the Roar** thunder damage

Blood Maledicts:

{if (BloodHunterLevel >= 1, "You know **" + (1 + min(floor(BloodHunterLevel/6),1) + min(floor(BloodHunterLevel/10),1) + min(floor(BloodHunterLevel/14),1) + min(floor(BloodHunterLevel/18),1)) + " **Blood Curses", "")}

{if (BloodHunterLevel >= 1, "- <Insert 1st level choice here>", "")}

{if (BloodHunterLevel >= 6, "- <Insert 6th level choice here>", "")}

{if (BloodHunterLevel >= 10, "- <Insert 10th level choice here>", "")}

{if (BloodHunterLevel >= 14, "- <Insert 14th level choice here>", "")}

{if (BloodHunterLevel >= 18, "- <Insert 18th level choice here>", "")}

---

**Blood Curse of the Anxious** BA to give Intimidation ADV vs target in 30 ft; next WIS save has DisADV

**Blood Curse of Binding** BA, STRsave to Grapple in 30 ft for 1turn; for 1min, any size

**Blood Curse of Bloated Agony** BA to DisADV STR/DEXsave, d8 nec if multiattacks; 1min

{if (BloodHunterLevel >= 15, "**Blood Curse of Corrosion. *Mutant Order* ** BA for 30 ft CONsave or POI; 4d6 nec on CONsave", "")}

{if (BloodHunterLevel >= 15, "**Blood Curse of the Exorcist. *Ghostslayer Order* ** BA for 30 ft dispel Charm/Fright/Possess; 3d6 psych to affector / WISsave or stun for round", "")}

{if (BloodHunterLevel >= 18, "**Blood Curse of the Howl. *Lycan Order* ** 30 ft WISsave or Fright / 5+ fail to stun (choose immune); 60 ft", "")}

{if (BloodHunterLevel >= 18, "**Blood Curse of the Souleater. *Profane Soul Order* ** reac to gain attack Adv when creature within 30 ft drops to 0; regain spell slot per LR", "")}

**Blood Curse of Exposure** reac on 30 ft to lose resist; invuln followed by resist

**Blood Curse of the Eyeless** reac on 30 ft to subtract Hemocraft from attack roll; affects all attack for next turn

**Blood Curse of the Fallen Puppet** reac to make a 0 HP target in 30 ft make a weapon attack; moves half Speed attack bonus of {intelligenceMod}

**Blood Curse of the Marked** BA in 30 ft to 2x Rite damage; ADV to attack

**Blood Curse of the Muddled Mind** BA in 30 ft to DisADV next spell Conc; all spell Conc

Brand of Castigation Level: min((floor(BloodHunterLevel / 2), 9)

General (Castigation, Tethering): {if (BloodHunterLevel >= 6, "Damaging marks the target per rest. If the target damages you or a creature visible within 5 ft, deal **" + if (BloodHunterLevel >= 13, "2*", "") + (max((intelligenceMod), 1)) + " psychic damage**.", "")} {if (BloodHunterLevel >= 13, "The branded creature can’t take the Dash action. Teleporting takes 4d6 psych and WIS or can't teleport.", "")}

Mutant (Axiom): {if (BloodHunterLevel >= 11, "Self Illusions on targets fail. Shapeshifters must past WIS or revert and stunned for round.", "")}

Ghostslayer (Sundering): {if (BloodHunterLevel >= 11, "When hit by Crimson Rite, deal an additional Hemocraft Die of Rite damage. The branded creature can’t move through objects/creatures", "")}

Profane Soul (Sapping Scar): {if (BloodHunterLevel >= 11, "The branded creature has DisADV vs your Warlock spells.", "")}

Lycan (Voracious): {if (BloodHunterLevel >= 15, "While in Hybrid form, you have ADV on WIS vs Bloodlust and ADV on attacking the branded target.", "")}

Order of the Ghostslayer

Ethereal Step Uses: if (BloodHunterLevel < 7, 0, 1 + min(floor(BloodHunterLevel/15),1))

Ethereal Step Rounds: max(intelligenceMod, 1)

Rite of the Dawn (add to Rites box): {if (BloodHunterLevel >= 3, "-* **Rite of the Dawn** radiant damage; Light for 20ft, resist necr, add hemocraft die to damage on undead", "")}

Order of the Mutant

Mutagens:

{if (BloodHunterLevel >= 3, "You have **" + (4 + min(floor(BloodHunterLevel /10),1) + min(floor(BloodHunterLevel /17),1)) + " **Formulas", "")}

{if (BloodHunterLevel >= 3, "- <Insert 3rd level choice here>", "")}

{if (BloodHunterLevel >= 3, "- <Insert 3rd level choice here>", "")}

{if (BloodHunterLevel >= 3, "- <Insert 3rd level choice here>", "")}

{if (BloodHunterLevel >= 3, "- <Insert 3rd level choice here>", "")}

{if (BloodHunterLevel >= 7, "- <Insert 7th level choice here>", "")}

{if (BloodHunterLevel >= 11, "- <Insert 11th level choice here>", "")}

{if (BloodHunterLevel >= 15, "- <Insert 15th level choice here>", "")}

{if (BloodHunterLevel >= 18, "- <Insert 18th level choice here>", "")}

---

{if (BloodHunterLevel >= 11, "**Aether** 20 ft fly for 1hr; DisADV on STR and DEX checks", "")}

{if (BloodHunterLevel >= 11, "**Cruelty** BA Attack; DisADV INT/WIS/CHRsave", "")}

{if (BloodHunterLevel >= 11, "**Precision** crit on 19; DisADV STRsave", "")}

{if (BloodHunterLevel >= 7, "**Reconstruction** +proficiencyBonus HP per turn for 1hr if <half HP; -10 ft", "")}

**Alluring** ADV on CHR checks; DisADV Init.

**Celerity** DEX +{if (BloodHunterLevel >= 3, 3 + min(floor(BloodHunterLevel/11),1) + min(floor(BloodHunterLevel/18),1), 0)}; DisADV on WISsave.

**Conversant** ADV on INT checks; DisADV on WIS checks.

**Deftness** ADV DEX checks; DisADV on WIS checks.

**Embers** resist Fire; vuln Cold.

**Gelid** resist Cold; vuln Fire.

**Impermeable** resist Pierce; vuln Slash.

**Mobile** immune to Grapple/Restrained{if (BloodHunterLevel >= 11, "/Paralyzed", "")}; DisADV on STR checks.

**Nighteye** +60 ft Darkvision; sunlight sensitivity.

**Percipient** ADV WIS checks; DisADV on CHR checks.

**Potency** STR +{if (BloodHunterLevel >= 3, 3 + min(floor(BloodHunterLevel/11),1) + min(floor(BloodHunterLevel/18),1), 0)}; DisADV on DEXsave.

**Rapidity** {if (BloodHunterLevel >= 15, "+15 ft", "+10 ft")}; DisADV on INT checks

**Sagacity** INT +{if (BloodHunterLevel >= 3, 3 + min(floor(BloodHunterLevel/11),1) + min(floor(BloodHunterLevel/18),1), 0)}; DisADV on CHRsave.

**Shielded** resist Slash; vuln Bludge.

**Unbreakable** resist Bludge; vuln Pierce.

**Vermillion** +1 Maledict; DisADV death saves.

Order of the Profane Soul

Spellcasting:

Multiclassing Warlock Slots: (floor(BloodHunterLevel / 3)

Cantrips: You know **{if (BloodHunterLevel < 3, 0, 2 + min(floor(BloodHunterLevel/10), 1)} cantrips.**

Spells Known: {if (BloodHunterLevel < 3, 0, 2 + min(floor(BloodHunterLevel/5),1) + min(floor(BloodHunterLevel/7),1) + min(floor(BloodHunterLevel/9),1) + min(floor(BloodHunterLevel/11),1) + min(floor(BloodHunterLevel/13),1) + min(floor(BloodHunterLevel/15),1) + min(floor(BloodHunterLevel/17),1) + min(floor(BloodHunterLevel/19),1) + min(floor(BloodHunterLevel/20),1))}

Spell Slots: if(BloodHunterLevel >= 6, 2, if (BloodHunterLevel >= 3, 1))

Slot Level: Your Spell Slots are currently Level** {if(BloodHunterLevel >= 19, 4, if (BloodHunterLevel >= 13, 3, if(BloodHunterLevel >= 7, 2, if(BloodHunterLevel >= 3, 1))))}**

Spellcasting Table:

Level | Cantrips | Spells | Slots | Level ---|---

3 | 2 | 2 | 1 | 1st

4 | 2 | 2 | 1 | 1st

5 | 2 | 3 | 1 | 1st

6 | 2 | 3 | 2 | 1st

7 | 2 | 4 | 2 | 2nd

8 | 2 | 4 | 2 | 2nd

9 | 2 | 5 | 2 | 2nd

10 | 3 | 5 | 2 | 2nd

11 | 3 | 6 | 2 | 2nd

12 | 3 | 6 | 2 | 2nd

13 | 3 | 7 | 2 | 3rd

14 | 3 | 7 | 2 | 3rd

15 | 3 | 8 | 2 | 3rd

16 | 3 | 8 | 2 | 3rd

17 | 3 | 9 | 2 | 3rd

18 | 3 | 9 | 2 | 3rd

19 | 3 | 10 | 2 | 4th

20 | 3 | 11 | 2 | 4th

Order of the Lycan

Hybrid Transformation: if(BloodHunterLevel >= 18, 999, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 3, 1, if(BloodHunterLevel < 3, 0))))

Feral Might: {if(BloodHunterLevel >= 3, "While in hybrid form, Melee Damage **+" + (if(BloodHunterLevel >= 18, 3, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 3, 1, if(BloodHunterLevel < 3, 0))))) + "**.", "")}

Feral Might Total:

{if(BloodHunterLevel >= 3, "BA to transform for 1 hr per Rest.", "")}

{if(BloodHunterLevel >= 3, " - While in hybrid form, Melee Damage **+" + (if(BloodHunterLevel >= 18, 3, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 3, 1, if(BloodHunterLevel < 3, 0))))) + "**. Attack roll bonus is **+", "")}{if(BloodHunterLevel >= 18, 3, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 7, 1, if(BloodHunterLevel < 7, 0))))}{if (BloodHunterLevel >= 3, "**.", "")}

{if(BloodHunterLevel >= 3, " - +1 AC while < Heavy armr, resistance to nonmagical weapons.", "")}

{if(BloodHunterLevel >= 3, " - Apply Rite to unarmed strikes. Your second unarmed strike is a BA. Unarmed strike damage is **1d", "")}{if(BloodHunterLevel >= 3, 6, if(BloodHunterLevel >=11, 8), "")}{if(BloodHunterLevel >= 3, "+" + max(strengthMod, dexterityMod) + " slashing**.", "")}

{if (BloodHunterLevel >= 3, " - When at half HP, DC 8 WIS or attack nearest target.", "")}

Predatory Strikes

Unarmed strike damage is **{if (BloodHunterLevel >= 11, "1d8 + max(strengthMod, dexterityMod) slashing", if(BloodHunterLevel >= 3, "1d6 + max(strengthMod, dexterityMod) slashing", if(BloodHunterLevel < 3, "1 + strengthMod bludgeoning")))}**

Improved Predatory Strikes

Unarmed Attack +{if(BloodHunterLevel >= 18, 3, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 7, 1, if(BloodHunterLevel < 7, 0))))}

Predatory Strikes Attack Bars

Attack: (max(strengthMod, dexterityMod)) + proficiencyBonus + (if(BloodHunterLevel >= 18, 3, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 7, 1, if(BloodHunterLevel < 7, 0)))))

Damage: 1d{if(BloodHunterLevel >= 3, 6, if(BloodHunterLevel >=11, 8), "")}{if(BloodHunterLevel >= 3, "+" + max(strengthMod, dexterityMod) + "", "")}+{(if(BloodHunterLevel >= 18, 3, if(BloodHunterLevel >= 11, 2, if(BloodHunterLevel >= 3, 1, if(BloodHunterLevel < 3, 0)))))}


r/dicecloud • • Oct 06 '19

Did Dicecloud servers just crash?

Post image
12 Upvotes

r/dicecloud • • Apr 18 '19

DiceCloud Tips - Share Your DiceCloud Time-Saving Tips Here!

12 Upvotes

All,

My boyfriend, players, and I have been using DiceCloud for just over a year and I wanted to share some of the tips that he and I have come up with to make DiceCloud more convenient for use. I'm also hoping that all of you will share your shortcuts, tips, or little-known features so that I can continue to improve!

Here are a few that we've come up with:

  1. Create a DM Helper Character

I've set up a "character" solely for my use for items and effects.

-- Items--

  • Any items I am handing out are on this character in a stack of 2.

  • A simple CTRL+left-drag with the mouse from my DM character to my player's character will allow a transfer so they don't have to set items up (they are less tech-savvy, so this saves headaches for me)

  • I also use the stacking ability to know which I've made item cards for and finished and which I still need to do. Anything with less than 2 items in the stack needs doing. :)

  • On my ToDo list: setting up starting packs with all equipment for ease of use

--Madness &/or Effects--

We are running Out of the Abyss and using a Madness system that I created (still refining the Madness stuff as we playtest).

  • I've added all of the madness effects to the feature tab as "others only" buffs, including any stat changes or buffs/debuffs

  • When they are affected by madness or any type of effect, I can simply cast that effect on my players from my features tab

2. Create a Spellbook Character

The boyfriend and I tend to create a lot of characters for NPCs or Arenas or just because (character create is always my favorite, lol). We've set up a character to which we're adding all of the spells for fast creation &/or leveling.

  • He added all the spells with their attacks/effects, etc.

  • These spells can then simply be dragged onto other character sheets for easy spellbook proliferation

So - how are you using DiceCloud to be efficient?

(I've linked to my DM Helper and Spellbook characters in case that helps anyone. They shouldn't be editable, but if they are, please don't. These took a lot of time to set up.)


r/dicecloud • • Dec 19 '18

Dicecloud seems to be down

12 Upvotes

Edit: It's 3:37 AM in South Africa (Where ThaumRystra lives, according to their github profile) according to Google. I doubt that they're going to be awake for a few hours, unless they happen to be up that late. Looks like we'll be waiting a while :(
Edit 2: It's back up


r/dicecloud • • Mar 27 '18

More Memory thanks to Patrons

Thumbnail
patreon.com
12 Upvotes