Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Blind Checks API problem

I'm using this API: Link

But it's not working as it's supposed to. First of all this is what appears when I used it with a test character:

As you can see Almost all of the first rolls are '9' and then almost all of the second rolls are '21'. It's weird.

Second of all this is what the Mod Output Console says:

{"who":"error","type":"error","content":"Unable to find a player or character with name: \"\""}

I don't really know what I'm doing wrong here.

July 26 (2 years ago)
vÍnce
Pro
Sheet Author

Curious, if you tab through each of your attributes(str, dex, con, etc.) and skills on the sheet, and re-run the blind check, do you see any change?

July 26 (2 years ago)

Edited July 26 (2 years ago)


vÍnce said:

Curious, if you tab through each of your attributes(str, dex, con, etc.) and skills on the sheet, and re-run the blind check, do you see any change?


So I did this and there is a change. Now rather than whole columns being the same number this is happening:

So at first glance these might look a bit normal... But I ran the script 25+ times or more and no matter what one whole column is over 10 and the other column is 10 or lower. I used the script so many times because it just felt odd that no matter what everything on one side was just higher than the other even though it should just be rolling two dice for advantage/disadvantage and the numbers should be more random.

Another thing, when I test the script using the test character I don't get the message "Secret roll to DM. I'm sure it's fine." like I'm supposed to. But when I test the script as the DM it gives both the DM and the player the message but the script doesn't run. When I do it this way the error message in the Mod Output Console doesn't appear for some reason.

July 27 (2 years ago)

Edited July 27 (2 years ago)
vÍnce
Pro
Sheet Author

I believe that tabbing through(or editing) the sheet's fields "exposes" their actual values to the API, otherwise the api doesn't see a value and assumes "0" even if there should be a modifier that isn't 0. I'm not sure why(programmatically) the API isn't able to see some of the sheet's attributes.  Maybe they were values generated by charactermancer, another api script(chatsetattr), sheetworkers, or...?  IDK.

As far as the advantage/disadvantage rolls go;  The two 20's rolled are shown at the top of the chat output. So it should be real easy to check.  In the images above, one of the rolls was below 10 on each.  So, it looks correct for those examples at least.  Not denying there may be an issue.

If you check the original thread you linked, I believe I posted something about the whisper function not working and how I modified the script to work for a Pathfinder version of the script that I modded. 

You might send Stephen S. a polite request to see if he would be willing have a quick look. 

July 27 (2 years ago)
The Aaron
Roll20 Production Team
API Scripter

Try this version:

/*jshint esversion: 9 */
// OPen and Blind Checks for the 5th Edition OGL by Roll20
// Create a token action macro called "OpenChecks" with the action "!OpenChecks"
// Create a token action macro called "BlindChecks" with the action "!BlindChecks"
// Give all your players access to both.
const OpenBlindChecks = (() => { // eslint-disable-line no-unused-vars

    const buildTable = (values) => {
        let getMod = (g) => {
            return g ? g.mod : -5;
        };

        let s = {
            div: `display: block; ` +
                `min-height:60px; ` +
                `margin: 5px 0px 0px -30px; ` +
                `padding:0px 5px 0px 5px; ` +
                `border: 0px none; ` +
                `border-radius: 6px 6px 6px 6px; ` +
                `box-shadow: 2px 2px 4px 2px #000; ` +
                `background-color: #fff; ` +
                `background-image: url('${values.blind ? "https://i.imgur.com/UCIUXyr.jpg" : "https://i.imgur.com/vjL1blE.jpg" }'); ` + //https://i.imgur.com/UCIUXyr.jpg  https://i.imgur.com/vjL1blE.jpg
                `text-align: left; ` +
                `white-space: pre-wrap;`,
            tbl_top: `width: 90%; margin: auto;`,
            img: `background-color: transparent; ` +
                `border: none ;` +
                `max-height: 60px; ` +
                `padding: 5px; ` +
                `margin: auto; !important`,
            name: `font-weight: bold; ` +
                `font-size: 120%; ` +
                `font-style: italic; ` +
                `text-align: center; ` +
                `line-height: 18px; ` +
                `padding: 0px 5px 0px;`,
            blurb: `font-style: italic; ` +
                `text-align: center; ` +
                `line-height:18px; ` +
                `padding: 0px 5px 0px;`,
            rolls: `text-align: center; ` +
                `line-height:18px; ` +
                `padding: 0px 5px 0px;`,
            inlinestyle: `display: inline-block; ` +
                `min-width:18px; ` +
                `min-height:18px; ` +
                `background: white; ` +
                `border: 1px solid black; ` +
                `font-style: normal; ` +
                `text-align: center;  ` +
                `line-height:18px;  ` +
                `padding: 0px:` +
                `color: black;`,
            inlineclass: `inlinerollresult showtip tipsy-n-right`,
            tbl_abl: `width: 90%; margin: auto;`,
            th: `font-weight: bold; ` +
                `text-align: center; ` +
                `line-height:18px; ` +
                `padding: 0px 5px 0px;`,
            td: `text-align: center; ` +
                `line-height:18px; ` +
                `padding: 0px 5px 0px;"`,
            tbl_skl: `width: 90%; margin: auto;`,
            tr_even: `background-color: ${values.blind ? "#cfd2d0" : "#e0e5c1" };`, //cfd2d0 //e0e5c1 ${values.blind ? "cfd2d0" : "e0e5c1" }
            tr_odd: `background-color: ${values.blind ? "#eeeeee" : "#ffffff" };` //transparent #ffffff ${values.blind ? "#eeeeee" : "#ffffff" }
        };

        let passive = `Passive Wisdom: ` +
            `<span class="${s.inlineclass}" style="${s.inlinestyle}" title="10 + ${getMod(values.mods.perception_bonus)}">` +
                `${10 + getMod(values.mods.perception_bonus)}` +
            `</span>`;

        let inlineRoll = (props) => {
            return `<span class="${s.inlineclass}" style="${s.inlinestyle}" title="${props.t1}">${props.r1}</span>&#171;-&#187;<span class="${s.inlineclass}" style="${s.inlinestyle}" title="${props.t2}">${props.r2}</span>`;
        };

        let rawRoll = inlineRoll({
            t1: `Rolling 1d20(${values.frst})`,
            r1: values.frst,
            t2: `Rolling 1d20(${values.scnd})`,
            r2: values.scnd});

        let abilityRow = (oe, l, m, sa) => {
            return `<tr style="${oe}">` +
                    `<td style="${s.td}">` +
                        `${l}` +
                    `</td>` +
                    `<td style="${s.rolls}">` +
                        `${inlineRoll({
                            t1: `Rolling 1d20(${values.frst})+${m}`, 
                            r1: values.frst + m,
                            t2: `Rolling 1d20(${values.scnd})+${m}`,
                            r2: values.scnd + m
                        })}` +
                    `</td>` +
                    `<td style="${s.rolls}">` + 
                        `${inlineRoll({
                            t1: `Rolling 1d20(${values.frst})+${sa}`, 
                            r1: values.frst + sa,
                            t2: `Rolling 1d20(${values.scnd})+${sa}`,
                            r2: values.scnd + sa
                        })}` +
                    `</td>` +
                `</tr>`;
        };

        let abilityList = [
            {oddeven: s.tr_even, label: 'Strength', mod: getMod(values.mods.strength_mod), save: getMod(values.mods.strength_save_bonus)},
            {oddeven: s.tr_odd, label: 'Dexterity', mod: getMod(values.mods.dexterity_mod), save: getMod(values.mods.dexterity_save_bonus)},
            {oddeven: s.tr_even, label: 'Constitution', mod: getMod(values.mods.constitution_mod), save: getMod(values.mods.constitution_save_bonus)},
            {oddeven: s.tr_odd, label: 'Intelligence', mod: getMod(values.mods.intelligence_mod), save: getMod(values.mods.intelligence_save_bonus)},
            {oddeven: s.tr_even, label: 'Wisdom', mod: getMod(values.mods.wisdom_mod), save: getMod(values.mods.wisdom_save_bonus)},
            {oddeven: s.tr_odd, label: 'Charisma', mod: getMod(values.mods.charisma_mod), save: getMod(values.mods.charisma_save_bonus)}
        ];

        let skillRow = (oe, l, m /*, sa*/) => {
            return `<tr style="${oe}">` +
                    `<td style="${s.td}">` +
                        `${l}` + 
                    `</td>` +
                    `<td style="${s.rolls}">` + 
                        `${inlineRoll({
                            t1: `Rolling 1d20(${values.frst})+${m}`, 
                            r1: values.frst + m,
                            t2: `Rolling 1d20(${values.scnd})+${m}`,
                            r2: values.scnd + m
                        })}` +
                    `</td>` +
                `</tr>`;
        };

        let skillList = [
            {oddeven: s.tr_even, label: 'Athletics', mod: getMod(values.mods.athletics_bonus)},
            {oddeven: s.tr_odd, label: 'Acrobatics', mod: getMod(values.mods.acrobatics_bonus)},
            {oddeven: s.tr_even, label: 'Animal Handling', mod: getMod(values.mods.animal_handling_bonus)},
            {oddeven: s.tr_odd, label: 'Arcana', mod: getMod(values.mods.arcana_bonus)},
            {oddeven: s.tr_even, label: 'Deception', mod: getMod(values.mods.deception_bonus)},
            {oddeven: s.tr_odd, label: 'History', mod: getMod(values.mods.history_bonus)},
            {oddeven: s.tr_even, label: 'Insight', mod: getMod(values.mods.insight_bonus)},
            {oddeven: s.tr_odd, label: 'Intimidation', mod: getMod(values.mods.intimidation_bonus)},
            {oddeven: s.tr_even, label: 'Investigation', mod: getMod(values.mods.investigation_bonus)},
            {oddeven: s.tr_odd, label: 'Medicine', mod: getMod(values.mods.medicine_bonus)},
            {oddeven: s.tr_even, label: 'Nature', mod: getMod(values.mods.nature_bonus)},
            {oddeven: s.tr_odd, label: 'Perception', mod: getMod(values.mods.perception_bonus)},
            {oddeven: s.tr_even, label: 'Performance', mod: getMod(values.mods.performance_bonus)},
            {oddeven: s.tr_odd, label: 'Persuasion', mod: getMod(values.mods.persuasion_bonus)},
            {oddeven: s.tr_even, label: 'Religion', mod: getMod(values.mods.religion_bonus)},
            {oddeven: s.tr_odd, label: 'Sleight of Hand', mod: getMod(values.mods.sleight_of_hand_bonus)},
            {oddeven: s.tr_even, label: 'Stealth', mod: getMod(values.mods.stealth_bonus)},
            {oddeven: s.tr_odd, label: 'Survival', mod: getMod(values.mods.survival_bonus)}
        ];

        values.message = `` +
            `<div style="${s.div}">` +
                `<table style="${s.tbl_top}">` + 
                    `<tr>` +
                        `<td rowspan="3">` +
                            `<img style="${s.img}" src="${values.url}">` +
                        `</td>` +
                        `<td style="${s.name}">` +
                            `${values.name}` +
                        `</td>` +
                    `</tr>` +
                    `<tr>` +
                        `<td style="${s.blurb}">` +
                            `${passive}` +
                        `</td>` +
                    `</tr>` +
                    `<tr>` +
                        `<td style="${s.rolls}">` + 
                            `${rawRoll}` +
                        `</td>` +
                    `</tr>` +
                `</table>` +
                `<br>` +
                `<table style="${s.tbl_abl}">` +
                    `<tr>` +
                        `<td style="${s.th}">` +
                            `Ability` + 
                        `</td><td style="${s.th}">` +
                            `Check` +
                        `</td>` +
                        `<td style="${s.th}">` +
                            `Save` +
                        `</td>` +
                    `</tr>`;

        abilityList.forEach( (row) => {
            values.message = values.message + abilityRow(row.oddeven, row.label, row.mod, row.save);
        });

        values.message = values.message + `</table>` +
                `<br>` +
                `<table style="${s.tbl_abl}">` +
                    `<tr>` +
                        `<td style="${s.th}">` +
                            `Ability` + 
                        `</td><td style="${s.th}">` +
                            `Check` +
                        `</td>` +
                    `</tr>`;

        skillList.forEach( (row) => {
            values.message = values.message + skillRow(row.oddeven, row.label, row.mod);
        });

        values.message = values.message + `</table>` +
                `<br>` +
            `</div>`;
        
        return values.message;
    };
 
    const getAttributes = (values) => {
        let attrNames = [
            'strength_mod',
            'dexterity_mod',
            'constitution_mod',
            'intelligence_mod',
            'wisdom_mod',
            'charisma_mod',
            'strength_save_bonus',
            'dexterity_save_bonus',
            'constitution_save_bonus',
            'intelligence_save_bonus',
            'wisdom_save_bonus',
            'charisma_save_bonus',
            'athletics_bonus',
            'acrobatics_bonus',
            'animal_handling_bonus',
            'arcana_bonus',
            'deception_bonus',
            'history_bonus',
            'insight_bonus',
            'intimidation_bonus',
            'investigation_bonus',
            'medicine_bonus',
            'nature_bonus',
            'perception_bonus',
            'performance_bonus',
            'persuasion_bonus',
            'religion_bonus',
            'sleight_of_hand_bonus',
            'stealth_bonus',
            'survival_bonus',
            'passive_wisdom'
        ];

        values.mods = attrNames.reduce((m,n)=>({...m,[n]:{
          key: n,
          mod: (Number(getAttrByName(values.cid,n))||~~(getAttrByName(values.cid,n))) || 0,
          lbl: n.replace(/_mod/gi,'').replace(/_bonus/gi,'').replace(/_/g, ' ')
        }}),{});

        
        sendChat('QuantumRoll', '[[2d20]]', function(qr) {
            values.frst = qr[0].inlinerolls[0].results.rolls[0].results[0].v;

            values.scnd = qr[0].inlinerolls[0].results.rolls[0].results[1].v;

            buildTable(values);
            
            if (values.blind) {

                sendChat(values.who, `/w gm ${values.message}`);

                sendChat('API - QuantumRoll', `/w "${values.who}" Secret roll sent to GM. I'm sure its fine.`);
                
            }else{

                sendChat(values.who, values.message);

            }

        });        
    };

    const handleInput = (msg) => {

        let values = {};

        values.msg = msg;

        values.tok = getObj(
            values.msg.selected[0]._type,
            values.msg.selected[0]._id);

        values.cha = getObj(
            'character',
            values.tok.get('represents'));

        if (values.cha) {

            values.cid = values.cha.get('id');

            let imgsrc = values.tok.get('imgsrc');

            values.url = imgsrc === '/images/character.png' ?
                'https://i.imgur.com/MpqETqe.png' :
                imgsrc;

            values.name = values.cha.get('name');

            values.blind = msg.content.startsWith("!BlindChecks");

            values.who = values.msg.who
                .substring(0, values.msg.who.indexOf(' (GM)'));
        }
        
        getAttributes(values);

    };

    on("ready",() => {

        on('chat:message', (msg_orig) => {

            if (msg_orig.type === 'api' &&
                (msg_orig.content.startsWith("!OpenChecks") ||
                msg_orig.content.startsWith("!BlindChecks")) &&
                msg_orig.selected && msg_orig.selected.length == 1 )
            {
                handleInput(_.clone(msg_orig));
            }

        });
    });

    return {
    };
})();