Riley, unless something changed recently, "token" is a subtype of the "graphic" _type. And "findObjects" isn't an available function (use findObjs). Ryan, API commands must begin with an exclamation mark (eg, !hwind). Additionally, if we assume that the GM hasn't assigned a controller to the enemy tokens, then we can perform the entire script without listing all of the targets. var healing_wind = healing_wind || {}; on('chat:message', function(msg) {
if(msg.type != 'api') return; // We're only deal with API commands
var parts = msg.content.toLowerCase().split(' ');
var command = parts.shift().substring(1); var who = getObj('player', msg.playerid).get('displayname');
if(command != 'hwind') return; // We're only dealing with the !hwind command
var page = getObj('page', Campaign().get('playerpageid')); var scale = page.get('scale_number'); var dist = Math.round(10 / scale * 70); // 10m / meters per square * 70 pixels per square;
var caster; var allTokens = findObjs({ _type: 'graphic', _pageid: page.id, subtype: 'token' });
if(msg.selected && msg.selected.length == 1 && msg.selected[0]._type == 'graphic') // Caster token is selected { caster = getObj('graphic', msg.selected[0]._id); if(caster.get('subtype') != 'token') // Selected obj isn't a token { sendChat('SYSTEM', '/w '+who+' Selected object isn't a token.'); return; } } else if(msg.who != who) // Player is posting command as their character; find corresponding token to cast from { var character = findObjs({ _type: 'character', name: who })[0]; caster = findObjs({ _type: 'graphic', represents: character.id })[0]; if(!caster) // No token exists for the character the player is speaking as { sendChat('SYSTEM', '/w '+who+' No token exists for '+msg.who+'.'); return; } } else // Try to find a character controlled by the player, cast from it { var character = findObjs({ _type: 'character', controlledby: msg.playerid })[0]; // Assume: One character if(!character) // Player is not controlling any character { sendChat('SYSTEM', '/w '+who+' You do not control any characters.'); return; } caster = findObjs({ _type: 'graphic', _pageid: page.id, represents: character.id })[0]; if(!caster) { sendChat('SYSTEM', '/w '+who+' No token exists for '+character.get('name')+'.'); return; } } if(+caster.get('bar2_value') < 5) // Caster doesn't have enough power to cast { sendChat('SYSTEM', '/w '+who+' You do not have enough power to cast that spell.'); return; } var targetList = healing_wind.findToks(allTokens, caster, dist); // List of tokens hit by the spell _.each(targetList, function(tok) { var curHP = +tok.get('bar1_value'); var maxHP = +tok.get('bar1_max'); curHP = Math.min(curHP + 30, maxHP); tok.set('bar1_value', ''+curHP); }); var curPW = +caster.get('bar2_value'); caster.set('bar2_value', ''+(curPW - 5));
}); healing_wind.findToks = function(allTokens, caster, dist) { targetList = []; _.each(allTokens, function(tok) { if(tok.id == caster.id) return; // Caster is not healed
if(tok.get('controlledby') == '') return; // Assumption: Allied tokens are controlled, enemies aren't
var distX = Math.abs(tok.get('left') - caster.get('left'));
var distY = Math.abs(tok.get('top') - caster.get('top'));
if(distX > dist || distY > dist) return; // Assuming range for spell is square; use pythag. if circular
// Gets a little complicated if diagonals = 1.5 squares
targetList.push(tok);
}); return targetList; }; This script is untested, but assuming there's no bugs in it (and the assumptions in the comments are correct), it's complete. To use this script, simply type "!hwind". If you have a single token selected, that token will be used as the caster. If you have no token selected but you're speaking as a character (and there is a token on the current page representing that character), that character's token will be used as the caster. If you're speaking as yourself, it will try to pick the first character you control, and find a token representing that character, which will become the casting token. All controlled tokens within range (10m -- however many squares that is based on the page settings and assuming the distance measurement is in meters) will be healed, and the caster will lose 5 pts from bar2 (if the caster doesn't have 5 pts, the spell fizzles). The distance calculation is assuming a square area (eg, D&D 4e). If a circular area is required, you need to modify the findToks function to use the Pythagorean Theorem. If diagonal distance is 1.5 squares (eg, D&D 3.5), the distance calculation is a bit more complicated, and I'd have to think about it instead of writing off the top of my head.