That's a bit harder proposition. There are a few problems to solve to make it happen: You need the player id. Humans don't do well with ids, so translation from a player name is needed. controlledby is determined first by the list on the character the token represents, then by the list on the token if it doesn't represent a character. Setting it means you have to set it on the character if there is one, or on the token if there isn't. on('ready',()=>{
const buildArgs = (str) => {
let firstWhitespace = str.search(/\s/);
if(-1 === firstWhitespace){
return [str];
}
return [str.slice(0,firstWhitespace),str.slice(firstWhitespace+1)];
};
const keyFormat = (text) => (text && text.toLowerCase().replace(/\s+/g,'')) || undefined;
const fuzzyNameMatch = (p,n) => RegExp(`${keyFormat(p)}`,'i').test(keyFormat(n));
const getPlayerByName = (n) => findObjs({type:"player"}).filter(p=>fuzzyNameMatch(n,p.get("_displayname")))[0];
const setControlledBy = (t,pid) => {
let c = getObj('character',t.get('represents'));
if(c) {
let cb = c.get('controlledby');
c.set('controlledby',[...new Set([...(cb?cb.split(/,/):[]),pid])].join(','));
} else {
let cb = t.get('controlledby');
t.set('controlledby',[...new Set([...(cb?cb.split(/,/):[]),pid])].join(','));
}
};
on('chat:message',msg=>{
if('api'===msg.type && /^!add-player-control(\b\s|$)/i.test(msg.content) && playerIsGM(msg.playerid)){
let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
let args = buildArgs(msg.content).slice(1);
if(args.length){
let p = getPlayerByName(args[0]);
if(p){
(msg.selected || [])
.map(o=>getObj('graphic',o._id))
.filter(g=>undefined !== g)
.forEach(t=> setControlledBy(t,p.id) )
;
} else {
sendChat('',`/w "${who}" <div><code><b>Error:</b> No player found that matches "${args[0]}".</code></div>`);
}
} else {
sendChat('',`/w "${who}" <div><b>Usage:</b> <code>!add-player-control &lt;Player Name Fragment&gt;</code></div>`);
}
}
});
});
The above script will first try to find a player that matches the fragment passed in, like this: !add-player-control bob the slayer then for each selected token, it will add that player to the controlled by list. The controlled by list is stored as a comma delimited string of ids, and the special value 'all'. The bolded function does the work of finding where to set it, and building the list based on what's already there. The Set() makes sure an id only appears once.