Here are those functions: const getActivePages = () => [...new Set([
Campaign().get('playerpageid'),
...Object.values(Campaign().get('playerspecificpages')),
...findObjs({
type: 'player',
online: true
})
.filter((p)=>playerIsGM(p.id))
.map((p)=>p.get('lastpage'))
])
];
const getPageForPlayer = (playerid) => {
let player = getObj('player',playerid);
if(playerIsGM(playerid)){
return player.get('lastpage');
}
let psp = Campaign().get('playerspecificpages');
if(psp[playerid]){
return psp[playerid];
}
return Campaign().get('playerpageid');
};
getActivePages() returns an array of page ids that players are on. Often, the page id is sufficient and the lowest cost to retrieve. For example, if you only wanted to make updates on Graphics that players can see, you could use the array as a lookup for the pageid on a Graphic without having to load the full Page objects: let pages = getActivePages();
let graphics = getSomeGraphicsSomeHow()
.filter( g => pages.includes(g.get('pageid'))); Something I meant to mention earlier: when referring to the properties of a Roll20 object, you should leave off the leading _. The _ specifies that the property is readonly, but isn't required for the lookup. By leaving off the leading _, you allow your script to work in the future if the property should become readwrite, which has happened a few times. The only exception to this is events. For example, if you want to observe players logging on, you must have the leading _ on _online: on('change:player:_online', ...); in order for the event to trigger. If you need the page objects, it's a simple map operation to load them in: let pageObjs = getActivePages()
.map(id => getObj('page',id))
.filter(p => undefined !== p); getPageForPlayer() will give you the page id for a given player, which is great for doing things in response to a command they issue. let ppageid = getPageForPlayer(msg.playerid);
let playerTokens = findObjs({
type: 'graphic',
subtype: 'token',
pageid: ppageid
})
.filter(t=>playerCanControl(t,msg.playerid)); Freebie since I used it in the example: const playerCanControl = (obj, playerid='any') => {
const playerInControlledByList = (list, playerid) => list.includes('all') || list.includes(playerid) || ('any'===playerid && list.length);
let players = obj.get('controlledby')
.split(/,/)
.filter(s=>s.length);
if(playerInControlledByList(players,playerid)){
return true;
}
if('' !== obj.get('represents') ) {
players = (getObj('character',obj.get('represents')) || {get: function(){return '';} } )
.get('controlledby').split(/,/)
.filter(s=>s.length);
return playerInControlledByList(players,playerid);
}
return false;
};
playerCanControl() takes a graphic object, and tells you if a player can control it. With just the graphic, it tells you if any player can control it: let anyPlayerController = playerCanControl(graphic); With a player id, it tells you if that player can control it: let specificPlayerController = playerCanControl(graphic, msg.playerid); or you can specify the special id "all" to see if it is controllable by all players (meaning, assigned the "all players" control, not that every player happens to be on it): let allPlayerController = playerCanControl(graphic, 'all'); Cheers!