This is just a little script I threw together for a new game I'm starting. It simplifies adding new characters for new players. I know there are a few others out there, this one just works the way I wanted. =D When a new player joins, it creates them a character and sends them a message: Existing players that join get a list of their existing characters: The Green + adds a new character. Note that nothing shows up for players that are GMs. Script: on('ready',()=>{
const IN_PLAYER_JOURNALS = true;
const TIME_TO_CHECK = 1000;
const styles = {
box: 'display: block; border: 1px solid #999; border-radius: .3em; padding: .3em; background-color: white; box-shadow: 0 0 25px 2px #999; margin: 1em 0 1em 0;',
charRow: 'display: block; border-top: 1px solid #ccc; margin: .2em;',
img: 'max-width: 2em; max-height: 3em;width:auto;height:auto;border:1px solid #999;float:left;margin: .1em; display: inline-block;',
link: 'color: #07c; border: 1px solid #999; border-radius: .3em; padding: .3em 1em; background-color:#ccc;font-weight: bold;display: inline-block;float: right;margin: .1em;',
addBtn: 'color: #fff; border: 1px solid #9f9; border-radius: .3em; padding: .3em 1em; background-color:#3c3;font-weight: bold;display: inline-block;float: right;margin: .1em;'
};
const defaultImg = '<a href="https://app.roll20.net/images/character.png" rel="nofollow">https://app.roll20.net/images/character.png</a>';
const clear = ()=>`<div style="clear:both"></div>`;
const GetCharImage = (c) => c.get('avatar')||defaultImg;
const GetShowCharacter = (c) => `<div style="${styles.charRow}"><a style="${styles.link}" href="<a href="http://journal.roll20.net/character/${c.id}">Open</a><img" rel="nofollow">http://journal.roll20.net/character/${c.id}">Open</a><img</a> style="${styles.img}" src="${GetCharImage(c)}"/>${c.get('name')}${clear()}</div>`;
const AddButton = () => `<a style="${styles.addBtn}" href="!add-player-character">+</a>`;
const AddPlayerCharacter = (player) => {
let c = createObj('character',{
controlledby: player.id,
name: `${player.get('displayname')}'s New Character`,
inplayerjournals: (IN_PLAYER_JOURNALS ? 'all' : '')
});
return c;
};
const ShowPlayerCharacters = (player,chars)=>{
chars = chars||findObjs({
type: 'character',
archived: false
}).filter(c=>c.get('controlledby').split(/\s*,\s*/).includes(player.id));
sendChat('',`/w "${player.get('displayname')}" <div style="${styles.box}"><div>${AddButton()}Your Characters:${clear()}</div>${chars.map(GetShowCharacter).join('')}</div>`);
};
const CheckPlayerCharacters = (player) => {
if(playerIsGM(player.id)){
return;
}
let chars = findObjs({
type: 'character',
archived: false
}).filter(c=>c.get('controlledby').split(/\s*,\s*/).includes(player.id));
if( ! chars.length){
chars.push(AddPlayerCharacter(player));
}
ShowPlayerCharacters(player,chars);
};
on('chat:message', (msg) => {
if('api' === msg.type && /^!add-player-character\b/i.test(msg.content)){
let player = getObj('player',msg.playerid);
if(player){
AddPlayerCharacter(player);
ShowPlayerCharacters(player);
}
}
});
const checkAll = () => {
findObjs({
type: 'player'
}).forEach(CheckPlayerCharacters);
};
setTimeout(()=>{
checkAll();
on('change:player:_online',(obj)=>{
if(true === obj.get('online')){
setTimeout(()=>CheckPlayerCharacters(obj),TIME_TO_CHECK);
}
});
},
TIME_TO_CHECK
);
});