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

searching attributes

August 24 (3 years ago)

Edited August 24 (3 years ago)

Hi.

I want to know if there's a syntax that allows me to search attributes based on a partial string, for grouping macros. For example, say I'm adding new specific injuries to each character using chatsetattr,  All new injury attributes begin with the string "inj" and I want to have them all send to chat so a character can view all of their current injuries without looking at their character sheet. The relevant added attributes might be @{injhead}, @{injlefthand}, and @{injrightbigtoe}. I want to have a macro (or api) that sends all of them at once with their current levels to chat, but leaves out any attribute that doesn't start with "inj". A character can just check their sheet of course, but I'm hopeful that there's a syntax that allows me to create an ability for a player, to check their current injury status from chat.

Thanks.

August 24 (3 years ago)
timmaugh
Pro
API Scripter

InsertArg can do that. You can build a menu of the injuries, and then output a "card" that would let them read the contents. See Keith's post in that thread for more information on the technique.

August 24 (3 years ago)
David M.
Pro
API Scripter

Does the InsertArgs "card" require the specific names of the attributes to be defined at runtime? Sounded kinda like the OP was looking for a "give me all attributes (and values, presumably) that start with the string "inj"

August 24 (3 years ago)

Edited August 24 (3 years ago)
timmaugh
Pro
API Scripter

Oh, yeah, it works to do that, exactly. To Narrator's specific case... I added three injuries to a character, making sure they all began with "inj". Then I ran this macro (while speaking as that character):

!ia --menu --title#puttext{{!!a#getme{{!!r#n}} !!b#` Injuries`}} --row#getrow{{!!t#Injuries !!c#ffffff !!s#getattrs{{!!c#getme{{}} !!op#br !!f#^f#inj !!frmt#fr#inj#``|uc}}}}

And I got this output:


Each button would whisper the injury to the player:

Note that although the attributes all start with "inj", I executed a find/replace to remove that portion of the name, just to make the button text more readable.

Alternatively, you could have the text of the injuries all report in that same menu (without having to click on a button):

!ia --menu --title#puttext{{!!a#getme{{!!r#n}} !!b#` Injuries`}} --row#getrow{{!!r#elem !!f#.7 !!s#getattrs{{!!c#getme{{}} !!op#lve !!f#^f#inj !!frmt#fr#inj#``|uc}}}}

Produces...

And, for a more advanced usage, you could have a more complex naming scheme to have sections to your menu. Maybe that is by location... or maybe it is by effect:

inj_movement_rightfoot
inj_bleeding_chest
inj_bleeding_rightarm
inj_modifier_bleeding_head

Whatever your classifications are (predefined list), they can become organizational structure to your menu. Given the list above, you'd want the Movement section to have one attribute, Bleeding to have 3, and Modifier to have one. Also, the head should show for both Bleeding and Modifier sections:


That was produced by this command line:

!ia --menu --title#puttext{{!!a#getme{{!!r#n}} !!b#` Injuries`}} --^^row#getrow{{!!t#MOVEMENT !!c#ffffff !!s#getattrs{{!!c#getme{{}} !!op#br !!f#^f#inj_|^f^#movement_ !!frmt#fr#inj_#``|fr#movement_#``|fr#bleeding_#``|fr#modifier_#``|uc}}}} --^^row#getrow{{!!t#BLEEDING !!c#ffffff !!s#getattrs{{!!c#getme{{}} !!op#br !!f#^f#inj_|^f^#bleeding_ !!frmt#fr#inj_#``|fr#movement_#``|fr#bleeding_#``|fr#modifier_#``|uc}}}} --row#getrow{{!!t#MODIFIER !!c#ffffff !!s#getattrs{{!!c#getme{{}} !!op#br !!f#^f#inj_|^f^#modifier_ !!frmt#fr#inj_#``|fr#movement_#``|fr#bleeding_#``|fr#modifier_#``|uc}}}}

Just a few examples of what InsertArg can do to solve this usage case. Post back if you want a breakdown on what the lines are doing, or if you have trouble tweaking to your game setup.

August 24 (3 years ago)

Edited August 24 (3 years ago)
David M.
Pro
API Scripter

EDIT - cross-posted! Tim's solution is prettier :)  - Hey, at least I got some experience messing with attributes

Well, I had 40min to kill at work while waiting for some test results (and I wanted to eventually play with some attribute-related stuff for another script I'm working on since I hadn't worked with them in the API before), so I went ahead and put this script together.

Syntax

!injuries --CharName

Looks for all attributes starting with "inj" (case insensitive) and displays the attribute name with the "inj" prefix removed. Has conditional output for current and max values, if exists.

The script

const InjuryReport = (() => { 
    const version = '0.1.0';
   
    const checkInstall = () =>  {
        log('-=> InjuryReport v'+version);
    };
    
    const handleInput = (msg) => {
        if(msg.type=="api" && msg.content.indexOf("!injuries") === 0 ) {
            try {
                who = getObj('player',msg.playerid).get('_displayname');
                let charName = msg.content.split(/--/)[1].trim();
                
                let char = findObjs({                              
                  _type: "character",
                  name: charName
                });
                
                if (char[0] !== undefined) {
                    var attrs = findObjs({                              
                      _type: "attribute",
                      _characterid: char[0].get('_id')
                    }, {caseInsensitive: true});
                    
                    attrs = attrs.filter(att => att.get('name').toLowerCase().indexOf("inj") === 0);
                } else {
                    sendChat('API', `/w "${who}"" Unable to find character named ${charName}`);
                    return;
                }
                
                let output = `/w "${who}" &{template:default} {{name=${charName} Injury Report}} `;
                
                if (attrs.length === 0) {
                    output = output + '{{N/A=}}';
                } else {
                    attrs.forEach(att => {
                        let name = att.get('name').replace(/inj/i, "");
                        let current = att.get('current');
                        let max = att.get('max');
                        
                        if (max !== "") {
                            output = output + `{{${name}=${current} / ${max}}}`;
                        } else {
                            output = output + `{{${name}=${current}}}`;
                        }
                    });
                }
                
                
                sendChat('API', output);
            }
            catch(err) {
              sendChat('API',`/w "${who}" Error: ${err.message}`);
            }
        };
    };
    const registerEventHandlers = () => {
        on('chat:message', handleInput);
    };
    on('ready', () => {
        checkInstall();
        registerEventHandlers();
    });
})();
Example output (BigToe has current and max, Head only has current, and Tuchus contains a text string). The next character is uninjured.

August 24 (3 years ago)
timmaugh
Pro
API Scripter

Don't contrast and compare! =D

That's impressive work for 45 minutes, David! Mine took me several months to code up.

August 24 (3 years ago)
David M.
Pro
API Scripter

Ha! I was just saying that the output looked really nice with that custom css.  I just re-used another scriplet I wrote months ago - there's probably only 15-ish lines of original code there, and most of the rest was stolen from Aaron's template, haha.

I must admit I still haven't delved into InsertArgs yet. Looks so powerful, but the syntax seems the most intimidating to me of all the meta-scripts. 

August 24 (3 years ago)
timmaugh
Pro
API Scripter

Yeah... IA is a bit of a misfit. And the syntax is... something else. It never quite made it to true meta-speed, either (because certain command lines require a roll query, etc.). I have plans to pull a lot of the pieces out as metascripts of their own (like a script that gets attributes for you: get me these attributes, filter them like this, format them like that, and leave THIS in the command line of the housing script). It all just takes time! =D

September 07 (3 years ago)

Edited September 07 (3 years ago)

David M, your script is amazing, especially for basically being a brief exercise during a break at work. It really does exactly what you said it does. I noticed that the syntax only uses character name. What do I change so that it uses selected instead of name? That would enable a macro for all players to check their injuries.




September 07 (3 years ago)
David M.
Pro
API Scripter

Try using 

!injuries --@{selected|character_name}


September 07 (3 years ago)

Gracias.