Character Vault
Any Concept / Any System
Compendium
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools

Difference between revisions of "Script:Marking Conditions"

From Roll20 Wiki

Jump to: navigation, search
(Code)
 
(10 intermediate revisions by one user not shown)
Line 1: Line 1:
The following script creates the API command <code>!mark</code>
+
{{script overview
 +
|name=Marking Conditions
 +
|author={{user profile|235259|Brian}}
 +
|dependencies={{api repository link|splitArgs}}
 +
|version=3.3
 +
|lastmodified=2015-03-26}}
  
==== Syntax ====
+
'''Marking Conditions''' creates the API commands <code>!mark</code>, <code>!unmark</code>, and <code>!clearmark</code>
<blockquote style="border:1px #0088ee solid;background:#eee;padding:0.5em">!mark ''tokenset'' [''status'' [''type'']]</blockquote>
+
<br clear="all">
 +
 
 +
=== Syntax ===
 +
{{syntaxbox top|formal=true|Marking Conditions}}
 +
{{API command|mark}} {{API parameter|name=tokenid}} {{API parameter|name=status</em> {{API parameter|name=type|optional=true}}<em>|optional=true}}<br>
 +
{{API command|unmark}} {{API parameter|name=tokenid}} {{API parameter|optional=true|name=status</em> {{API parameter|optional=true|name=type}}<em>}}<br>
 +
{{API command|clearmark}} {{API parameter|name=tokenid}}
 +
{{Formal API command|
 +
{{token|S}} {{rarr}} {{API command|mark}} {{token|tokenid}} {{token|status|-}}
 +
{{token|S}} {{rarr}} {{API command|unmark}} {{token|tokenid}} {{token|status|-}}
 +
{{token|S}} {{rarr}} {{API command|clearmark}} {{token|tokenid|-}}
 +
{{token|tokenid}} {{rarr}} {{string|-}}
 +
{{token|status}} {{rarr}} {{epsilon}}
 +
{{token|status}} {{rarr}} {{string}}{{token|damage|-}}
 +
{{token|damage}} {{rarr}} {{epsilon}}
 +
{{token|damage}} {{rarr}} acid<br>
 +
{{token|damage}} {{rarr}} cold<br>
 +
{{token|damage}} {{rarr}} fire<br>
 +
{{token|damage}} {{rarr}} force<br>
 +
{{token|damage}} {{rarr}} lightning<br>
 +
{{token|damage}} {{rarr}} necrotic<br>
 +
{{token|damage}} {{rarr}} poison<br>
 +
{{token|damage}} {{rarr}} psychic<br>
 +
{{token|damage}} {{rarr}} radiant<br>
 +
{{token|damage}} {{rarr}} thunder
 +
}}
 +
{{syntaxbox end}}
 +
 
 +
{{param description top}}
 +
{{param description|name=tokenid|value=ID of a token object. This can be obtained with <code>@{target{{!}}token_id}</code> or <code>@{selected{{!}}token_id}</code>.}}
 +
{{param description|name=status|value=Optional. Either the name of a [[API:Objects#Graphic (Token/Map/Card/Etc.)|statusmarker icon]], or else one of many aliases to D&D 4e conditions.
  
{| class="wikitable"
 
|-
 
! Parameter
 
! Values
 
|-
 
| ''tokenset''
 
| Defines the set of tokens on the map to mark. One of:
 
* The name of a token
 
* !all
 
* !key=value[,key=value[,key=value...etc]]
 
|-
 
| ''status''
 
| (Optional) A D&D 4e status (except for dying, helpless, unconscious, insubstantial, or surprised) or the name of a [[API:Objects#Graphic (Token/Map/Card/Etc.)|statusmarker icon]]. The script has several aliases for the statuses. For example, immobilized, immobile, and immob all correspond to the same marker.
 
  
If ''status'' is not specified, the purple statusmarker will be used (which corresponds to the Marked status).
+
If ''status'' is not specified, the purple statusmarker will be used.}}
|-
+
{{param description|name=type|value=Optional. A D&D 4e damage type. Only used if ''status'' is "ongoing", "damage", or "dam". If supplied, should be one of:
| ''type''
+
| (Optional) A D&D 4e damage type. Only used if ''status'' is ''ongoing'', ''damage'', or ''dam''. One of:
+
 
* acid
 
* acid
 
* cold
 
* cold
Line 32: Line 52:
 
* radiant
 
* radiant
 
* thunder
 
* thunder
If ''type'' is not specified, a statusmarker to represent untyped damage will be used.
+
If ''type'' is not specified, a statusmarker to represent untyped damage will be used.}}
|}
+
{{param description bottom}}
  
==== The ''tokenset'' Parameter ====
+
The <code>!mark</code> command will set a marker, while the <code>!unmark</code> command will clear it. <code>!clearmark</code> will clear all markers from the token.
The ''tokenset'' parameter requires some additional notice. If a token's name is used, obviously that token will be the only token in the set. Alternatively, if <code>!all</code> is used, all tokens on the map will be in the set. The value that requires explanation is the <code>!key=value</code> list.
+
  
''key'' may be one of:
+
==== Conditions and Aliases ====
* distance
+
The available ''status'' aliases and the D&D 4e conditions they map to are listed below.
* controlledby
+
* bar1
+
* bar2
+
* bar3
+
  
Values for the <code>distance</code> key may be:
+
{| class="wikitable"
* nearest
+
|-
* furthest
+
! Condition
* ''N''
+
! Aliases
* ''>N''
+
! Condition
* ''<N''
+
! Aliases
 
+
|- style="vertical-align:top"
If you use any <code>distance</code> key, you must have a token selected, and that token will not be part of the <code>tokenset</code>. ''N'' looks for tokens '''exactly''' N squares from the selected token. ''>N'' and ''<N'' look for tokens N or more, or else N or less squares away from the selected token, as appropriate. ''nearest'' and ''furthest'' calculate the rest of the <code>tokenset</code>, and then select the nearest or furthest tokens within that set. (There might be multiple results, if there are multiple equidistant tokens.)
+
| style="width:100px" | '''Blinded'''
 
+
| style="width:200px" | blinded<br>blind
Values for the <code>controlledby</code> key may be:
+
| style="width:100px" | '''Prone'''
* none
+
| style="width:200px" | prone
* ''name''
+
|- style="vertical-align:top"
 
+
|| '''Dazed'''
If you use <code>none</code>, the <code>tokenset</code> will include tokens with no controlling player, or which represent characters with no controlling player (generally, NPC tokens). Otherwise, the mark will look for a token controlled by a player named ''name'', or a token representing a character named ''name''.
+
|| dazed<br>daze
 
+
|| '''Restrained'''
Values for the <code>barN</code> keys may be:
+
|| restrained
* ''N''
+
|- style="vertical-align:top"
* ''>N''
+
|| '''Deafened'''
* ''<N''
+
|| deafened<br>deaf
 
+
|| '''Slowed'''
If ''N'' is used as the value, the <code>tokenset</code> will look for tokens with a current value of exactly N; the token does not need a maximum value set. Otherwise, N should be a value in the [0..1] range, the token needs both current and maximum values, and the <code>tokenset</code> will search for tokens with the relevant bar at or above (or at or below) the given percentage.
+
|| slowed<br>slow
 
+
|- style="vertical-align:top"
==== Code ====
+
|| '''Dominated'''
<pre data-language="javascript">
+
|| dominated<br>dominate
/**
+
|| '''Stunned'''
* Provides commands for marking enemies.
+
|| stunned<br>stun
*/
+
|- style="vertical-align:top"
var conditions = conditions || {};
+
|| '''Immobilized'''
conditions.markingCharacters = [];
+
|| immobilized<br>immobile<br>immob
on("chat:message", function(msg) {
+
|| '''Weakened'''
    if(msg.type != 'api' || msg.content.toLowerCase().indexOf('!mark') != 0) return;
+
|| weakened<br>weak
   
+
|- style="vertical-align:top"
    var args = msg.content.toLowerCase().split(' ');
+
|| '''Marked'''
    args.shift();
+
|| marked<br>mark
   
+
|| '''Ongoing Damage'''
    var mark = 'purple'; // default to defender's "mark" condition
+
|| ongoing<br>damage<br>dam
    if(args[1]) switch(args[1])
+
|- style="vertical-align:top"
    {
+
|| '''Petrified'''
        case 'blinded':
+
|| petrified<br>petrify<br>stone
        case 'blind':
+
|| '''Dying<br>Helpless<br>Unconscious<br>Insubstantial<br>Surprised'''
            mark = 'bleeding-eye';
+
| style="width:200px" | '''''Marking Conditions''' explicitly does not handle these statuses, and will generate an error message if you try to use one.''
            break;
+
|}
        case 'dazed':
+
        case 'daze':
+
            mark = 'pummeled';
+
            break;
+
        case 'deafened':
+
        case 'deaf':
+
            mark = 'screaming';
+
            break;
+
        case 'dominated':
+
        case 'dominate':
+
            mark = 'chained-heart';
+
            break;
+
        case 'immobilized':
+
        case 'immobile':
+
        case 'immob':
+
            mark = 'fishing-net';
+
            break;
+
        case 'marked':
+
        case 'mark':
+
            mark = 'purple';
+
            break;
+
        case 'petrified':
+
        case 'petrify':
+
        case 'stone':
+
            mark = 'white-tower';
+
            break;
+
        case 'prone':
+
            mark = 'back-pain';
+
            break;
+
        case 'restrained':
+
            mark = 'aura';
+
            break;
+
        case 'slowed':
+
        case 'slow':
+
            mark = 'snail';
+
            break;
+
        case 'stunned':
+
        case 'stun':
+
            mark = 'lightning-helix';
+
            break;
+
        case 'weakened':
+
        case 'weak':
+
            mark = 'broken-heart';
+
            break;
+
        case 'ongoing':
+
        case 'damage':
+
        case 'dam':
+
            if(args[2]) switch(args[2])
+
            {
+
                case 'acid':
+
                    mark = 'chemical-bolt';
+
                    break;
+
                case 'cold':
+
                    mark = 'frozen-orb';
+
                    break;
+
                case 'fire':
+
                    mark = 'half-haze';
+
                    break;
+
                case 'force':
+
                    mark = 'blue';
+
                    break;
+
                case 'lightning':
+
                    mark = 'edge-crack';
+
                    break;
+
                case 'necrotic':
+
                    mark = 'death-zone';
+
                    break;
+
                case 'poison':
+
                    mark = 'skull';
+
                    break;
+
                case 'psychic':
+
                    mark = 'pink';
+
                    break;
+
                case 'radiant':
+
                    mark = 'angel-outfit';
+
                    break;
+
                case 'thunder':
+
                    mark = 'yellow';
+
                    break;
+
                default:
+
                    sendChat('ERROR', '/w ' + msg.who + ' No damage type called ' + args[2]
+
                            + '. If the damage has no type, do not include a type!');
+
                    return;
+
            }
+
            else mark = 'all-for-one'; // untyped ongoing damage
+
            break;
+
        case 'dying':
+
        case 'helpless':
+
        case 'unconscious':
+
        case 'insubstantial':
+
        case 'surprised':
+
            sendChat('ERROR', '/w ' + msg.who + ' The ' + args[1]
+
                            + ' status is not implemented for the !mark command.');
+
            return;
+
            break;
+
        default:
+
            mark = args[1]; // allows for direct status setting
+
            break;
+
    }
+
   
+
    var so = msg.selected || {};
+
    var tgtList = conditions.targetList(args[0], so, msg.who);
+
    if(mark == 'none') conditions.unmarkTokens(tgtList, msg.who);
+
    else conditions.markTokens(tgtList, msg.who, mark);
+
});
+
 
+
/**
+
* Parses the input to search for tokens which need to be marked (or unmarked).
+
* The tokens are returned as an array. The descriptor begins with an
+
* exclamation point to differentiate it from polling a single token, and is a
+
* comma-separated set of key=value pairs. All pairs will be true for each
+
* token selected. For example, !distance=<1,controlledby=none,bar1=<.5 would
+
* find only those tokens which are within 1 square of the currently selected
+
* token, are controlled by nobody (ie, NPCs), and have 50% or less remaining
+
* on bar1.
+
*
+
* all                  All tokens on the current page
+
* distance=N          A token exactly N squares from the currently selected token
+
* distance=<N          A token N squares or less from the currently selected token
+
* distance=>N          A token N squares or more from the currently selected token
+
* distance=nearest    The nearest token to the currently selected token
+
* distance=furthest    The furthest token from the currently selected token
+
* controlledby=none    A token not controlled by any player -- generally, the option to use for finding NPCs
+
* controlledby=player  A token controlled by the player named `player'
+
* bar1=N              A token whose current bar1 value is N
+
* bar1=<N              A token whose current bar1 value is N% or less
+
* bar1=>N              A token whose current bar1 value is N% or more
+
* bar2=N              A token whose current bar2 value is N
+
* bar2=<N              A token whose current bar2 value is N% or less
+
* bar2=>N              A token whose current bar2 value is N% or more
+
* bar3=N              A token whose current bar3 value is N
+
* bar3=<N              A token whose current bar3 value is N% or less
+
* bar3=>N              A token whose current bar3 value is N% or more
+
*
+
* The `distance' options will never return the currently selected token, only
+
* other tokens based on their distance from the currently selected token.
+
*
+
* The `all' option does not take any value, is ignored if it isn't the first
+
* option, and ignores all other options if it's first. It's a loner, used
+
* mostly for cleaning things up (eg, !mark !all none to clear all marks on the
+
* page).
+
*
+
* @param descriptor    arg0 of the user input. This should be either a
+
*                      formatted search for tokens, or the name of a single
+
*                      token.
+
* @param selectedObjs  an array of selected objects
+
* @param who          the player to send whispers about errors
+
* @return  an array of token objects which will have their statusmarkers modified
+
*/
+
conditions.targetList = function(descriptor, selectedObjs, who)
+
{
+
    var selected;
+
    var targets = [];
+
   
+
    for(var i = 0; i < selectedObjs.length; i++)
+
    {
+
        if(selectedObjs[i]._type == 'graphic')
+
        {
+
            var tmp = getObj(selectedObjs[i]._type, selectedObjs[i]._id);
+
            if(tmp && tmp.get('_subtype') == 'token')
+
            {
+
                selected = tmp; // use the first token we find as reference for 'nearest'/'furthest'
+
                break;
+
            }
+
        }
+
    }
+
   
+
    if(descriptor.indexOf('!') == 0) // descriptor describes a group of tokens
+
    {
+
        var parts = descriptor.substring(1).split(',');
+
        var filters = [];
+
        var error = false;
+
       
+
        if(parts[0] == 'all') filters.push(function(tgt) { return true; });
+
        else parts.forEach(function(kvp) {
+
            var key = kvp.substring(0, kvp.indexOf('='));
+
            var value = kvp.substring(kvp.indexOf('=')+1);
+
            var func;
+
           
+
            switch(key)
+
            {
+
                case 'distance':
+
                    if(!selected)
+
                    {
+
                        sendChat('ERROR', '/w ' + who + ' There is no token selected.');
+
                        error = true;
+
                        return;
+
                    }
+
                    var sL = selected.get('left');
+
                    var sT = selected.get('top');
+
                   
+
                    if(value == 'nearest' || value == 'furthest') func = function(tgt) {
+
                        // near/far can't be decided until after all other filters have run;
+
                        // using dumy function until then
+
                        return tgt != selected;
+
                    };
+
                    else if(value.indexOf('<') == 0) func = function(tgt) {
+
                        // find tokens <= value spaces away
+
                        var squares = (+value.substring(1)) * 70;
+
                        var distL = Math.abs(sL - tgt.get('left'));
+
                        var distT = Math.abs(sT - tgt.get('top'));
+
                       
+
                        return tgt != selected && distL <= squares && distT <= squares;
+
                    }
+
                    else if(value.indexOf('>') == 0) func = function(tgt) {
+
                        // find tokens >= value spaces away
+
                        var squares = (+value.substring(1)) * 70;
+
                        var distL = Math.abs(sL - tgt.get('left'));
+
                        var distT = Math.abs(sT - tgt.get('top'));
+
                       
+
                        return tgt != selected && (distL >= squares || distT >= squares);
+
                    }
+
                    else func = function(tgt) {
+
                        // find tokens exactly value spaces away
+
                        var squares = (+value) * 70;
+
                        var distL = Math.abs(sL - tgt.get('left'));
+
                        var distT = Math.abs(sT - tgt.get('top'));
+
                       
+
                        return tgt != selected && ((distL == squares && distT == squares)
+
                                                || (distL == squares && distT < squares)
+
                                                || (distL < squares && distT == squares));
+
                    }
+
                    break;
+
                case 'controlledby':
+
                    if(value == 'none') func = function(tgt) {
+
                        // find NPC tokens
+
                        if(tgt.get('_represents') == '')
+
                            return tgt.get('controlledby') == '';
+
                        else
+
                        {
+
                            var character = getObj('character', tgt.get('_represents'));
+
                            return character.get('controlledby') == '';
+
                        }
+
                    }
+
                    else func = function(tgt) {
+
                        // find tokens controlled by value
+
                        var players = findObjs({_type: 'player', _displayname: value},
+
                                                {caseInsensitive: true});
+
                        if(players[0]) return tgt.get('controlledby').indexOf(players[0].id) != -1;
+
                        players = findObjs({_type: 'player', _displayname: value.replace('-', ' ')},
+
                                            {caseInsensitive: true});
+
                        if(players[0]) return tgt.get('controlledby').indexOf(players[0].id) != -1;
+
                       
+
                        var characters = findObjs({_type: 'character', name: value},
+
                                                    {caseInsensitive: true});
+
                        if(characters[0]) return tgt.get('_represents') == characters[0].id;
+
                        characters = findObjs({_type: 'character', name: value.replace('-', ' ')},
+
                                                {caseInsensitive: true});
+
                        if(characters[0]) return tgt.get('_represents') == characters[0].id;
+
                       
+
                        return false;
+
                    }
+
                    break;
+
                case 'bar1':
+
                case 'bar2':
+
                case 'bar3':
+
                    if(value.indexOf('<') == 0) func = function(tgt) {
+
                        // find tokens with bar# at or below value%
+
                        var barCur = tgt.get(key+'_value');
+
                        var barMax = tgt.get(key+'_max');
+
                        var percent = barCur / barMax;
+
                        if(barMax == NaN || barCur == NaN) return false;
+
                       
+
                        return percent <= (+value.substring(1));
+
                    }
+
                    else if(value.indexOf('>') == 0) func = function(tgt) {
+
                        // find tokens with bar# at or above value%
+
                        var barCur = tgt.get(key+'_value');
+
                        var barMax = tgt.get(key+'_max');
+
                        var percent = barCur / barMax;
+
                        if(barMax == NaN || barCur == NaN) return false;
+
                       
+
                        return percent >= (+value.substring(1));
+
                    }
+
                    else func = function(tgt) {
+
                        // find tokens with bar# at value
+
                        var barCur = tgt.get(key+'_value');
+
                        if(barCur == NaN) return false;
+
                       
+
                        return barCur == (+value);
+
                    }
+
                    break;
+
                default:
+
                    sendChat('ERROR', '/w ' + who + ' ' + key + ' is not a valid token filter key.');
+
                    return;
+
            }
+
           
+
            filters.push(func);
+
        });
+
       
+
        if(error) return [];
+
       
+
        targets = filterObjs(function(obj) {
+
            if(obj.get('_pageid') != Campaign().get('playerpageid')) return false;
+
            if(obj.get('_type') != 'graphic') return false;
+
            if(obj.get('_subtype') != 'token') return false;
+
           
+
            var matchAll = filters.length > 0;
+
            filters.forEach(function(f) {
+
                if(!matchAll) return;
+
                if(!f(obj)) matchAll = false;
+
            });
+
           
+
            return matchAll;
+
        });
+
       
+
        // if we have distance=nearest or distance=furthest, trim `targets' as appropriate
+
        // do nothing if $selected is null
+
        if(selected)
+
        parts.forEach(function(kvp) {
+
            var key = kvp.substring(0, kvp.indexOf('='));
+
            var value = kvp.substring(kvp.indexOf('=')+1);
+
           
+
            if(key == 'distance')
+
            {
+
                var sL = selected.get('left');
+
                var sT = selected.get('top');
+
                   
+
                if(value == 'nearest')
+
                {
+
                    var minDist = -1;
+
                    var toKeep = [];
+
                    targets.forEach(function(tgt) {
+
                        var distL = Math.abs(tgt.get('left') - sL);
+
                        var distT = Math.abs(tgt.get('top') - sT);
+
                       
+
                        var distance = Math.max(distL, distT);
+
                        if(minDist == -1 || minDist > distance)
+
                        {
+
                            toKeep = [tgt];
+
                            minDist = distance;
+
                        }
+
                        else if(minDist == distance)
+
                        {
+
                            toKeep.push(tgt);
+
                        }
+
                    });
+
                   
+
                    targets = toKeep;
+
                }
+
                else if(value == 'furthest')
+
                {
+
                    var maxDist = -1;
+
                    var toKeep = [];
+
                    targets.forEach(function(tgt) {
+
                        var distL = Math.abs(sL - tgt.get('left'));
+
                        var distT = Math.abs(sT - tgt.get('top'));
+
                       
+
                        var distance = Math.max(distL, distT);
+
                        if(maxDist == -1 || maxDist < distance)
+
                        {
+
                            toKeep = [tgt];
+
                            maxDist = distance;
+
                        }
+
                        else if(maxDist == distance)
+
                        {
+
                            toKeep.push(tgt);
+
                        }
+
                    });
+
                   
+
                    targets = toKeep;
+
                }
+
            }
+
        });
+
    }
+
    else // descriptor is a token name
+
    {
+
        var target = findObjs({
+
            _type: 'graphic',
+
            name: descriptor,
+
            _pageid: Campaign().get('playerpageid')
+
        }, {caseInsensitive: true})[0];
+
        if(!target)
+
        {
+
            sendChat('ERROR', '/w ' + who + ' Cannot find a token named ' + args[0] + '.');
+
            return;
+
        }
+
       
+
        targets.push(target);
+
    }
+
   
+
    return targets;
+
}
+
 
+
/**
+
* Marks all given targets and keeps track of who marked it.
+
*
+
* @param targets  an array of target token objects to mark
+
* @param character the character performing the mark
+
* @param mark      optional. The type of statusmarker to use for the mark.
+
*/
+
conditions.markTokens = function(targets, character, mark)
+
{
+
    targets.forEach(function(tgt) { // tgt is a token object
+
        tgt.set('status_'+mark, true);
+
    });
+
}
+
 
+
/**
+
* Removes all marks on the target tokens that were placed there by the calling
+
* player.
+
*
+
* @param targets  an array of target token objects to clean up
+
* @param character the player who's removing marks -- only marks placed by the player will be removed
+
*/
+
conditions.unmarkTokens = function(targets, character)
+
{
+
    targets.forEach(function(tgt) {
+
        tgt.set('statusmarkers', '');
+
    });
+
}
+
</pre>
+
 
+
==== Examples ====
+
'''!mark !distance=nearest,bar1<.5 brown'''
+
<blockquote>This will set the brown marker on the nearest token with 50% or less of its bar1.</blockquote>
+
 
+
'''!mark !distance=<1,controlledby=none immob'''
+
<blockquote>This will set the 'immobilize' icon to all NPC tokens 1 square away (or closer!)</blockquote>
+
 
+
'''!mark Wulfgar none'''
+
<blockquote>This will remove all statusmarkers from the token named Wulfgar</blockquote>
+
  
[[Category:User API Scripts|Marking Conditions]]
+
=== Changelog ===
[[Category:API Commands|Marking Conditions]]
+
{{changelog version|3.3|2015-03-26|* [bugfix] fixed bugs reported by {{user profile|376031|Ron}}}}
 +
{{changelog version|3.2|2015-01-24|* [bugfix] no-arg crash}}
 +
{{changelog version|3.1|2015-01-22|* Fixed transcription error}}
 +
{{changelog version|3.0|2015-01-09|* Release}}

Latest revision as of 01:00, 27 March 2015

API ScriptAuthor: Brian
Version: 3.3
Last Modified: 2015-03-26
Code: Marking Conditions
Dependencies: splitArgs
Conflicts: None

Marking Conditions creates the API commands !mark, !unmark, and !clearmark

[edit] Syntax

!mark <tokenid> [status [type]]
!unmark <tokenid> [status [type]]
!clearmark <tokenid>
Formally:

S → !mark tokenid status
S → !unmark tokenid status
S → !clearmark tokenid
tokenidstring
status → ε
statusstringdamage
damage → ε
damage → acid
damage → cold
damage → fire
damage → force
damage → lightning
damage → necrotic
damage → poison
damage → psychic
damage → radiant
damage → thunder

Parameter Values
tokenid ID of a token object. This can be obtained with @{target|token_id} or @{selected|token_id}.
status Optional. Either the name of a statusmarker icon, or else one of many aliases to D&D 4e conditions.


If status is not specified, the purple statusmarker will be used.

type Optional. A D&D 4e damage type. Only used if status is "ongoing", "damage", or "dam". If supplied, should be one of:
  • acid
  • cold
  • fire
  • force
  • lightning
  • necrotic
  • poison
  • psychic
  • radiant
  • thunder

If type is not specified, a statusmarker to represent untyped damage will be used.

The !mark command will set a marker, while the !unmark command will clear it. !clearmark will clear all markers from the token.

[edit] Conditions and Aliases

The available status aliases and the D&D 4e conditions they map to are listed below.

Condition Aliases Condition Aliases
Blinded blinded
blind
Prone prone
Dazed dazed
daze
Restrained restrained
Deafened deafened
deaf
Slowed slowed
slow
Dominated dominated
dominate
Stunned stunned
stun
Immobilized immobilized
immobile
immob
Weakened weakened
weak
Marked marked
mark
Ongoing Damage ongoing
damage
dam
Petrified petrified
petrify
stone
Dying
Helpless
Unconscious
Insubstantial
Surprised
Marking Conditions explicitly does not handle these statuses, and will generate an error message if you try to use one.

[edit] Changelog

v3.3 (2015-03-26)

  • [bugfix] fixed bugs reported by Ron


v3.2 (2015-01-24)

  • [bugfix] no-arg crash


v3.1 (2015-01-22)

  • Fixed transcription error


v3.0 (2015-01-09)

  • Release