Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 210 additions & 0 deletions WelcomePackage/1.4/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
const WelcomePackage = (() => {
'use strict';

const CREATE_CHARACTER_CMD = '!welcomePackageCreateCharacter';

const observers = [];
let isReady = false;

/**
* Report an error to the GM and log its stack trace.
* @param err The error.
*/
function _error(err) {
log(`WelcomePackage ERROR: ${err.message}`);
log(err.stack);
sendChat('WelcomePackage API',
`/w gm ERROR: ${err.message} --- See API console log for details.`);
}

/**
* Event handler for when a player logs into the game.
* @private
* @param {Player} player
*/
function _handlePlayerOnline(player) {
if (player.get('_online') && !playerIsGM(player.get('_id')))
createPlayerCharacter(player);
}

/**
* Registers a function to be notified when a character is created
* @param {function} func
*/
function onAddCharacter(func){
if('function' === typeof func){
observers.push(func);
}
}

/**
* Notifies all registered functions when a character is created
* @param {Character} character
*/
function notifyAddCharacter(character){
observers.forEach((f)=>f(character));
}

/**
* Creates a character creation macro for a player if they don't already
* have the macro.
* @param {Player} player
*/
function addCharacterCreateMacro() {
const macroName = 'CreateACharacter';

let allPlayers = findObjs({
_type: 'player'
});
_.each(allPlayers, player => {
let playerId = player.get('_id');

let macro = findObjs({
_type: 'macro',
_playerid: playerId,
name: macroName
})[0];
if(!macro) {
log(`WelcomePackage: Creating "CreateACharacter" macro for player ` +
`${player.get('_displayname')}`);
createObj('macro', {
_playerid: playerId,
name: macroName,
action: `${CREATE_CHARACTER_CMD} ?{Character Name:}`
});
}
});
}

/**
* Creates a character for a player if they don't already have any characters.
* @param {Player} player
* @param {string} [name] The name of the character. If this is provided,
* the character will be created regardless of whether
* the player has a character already.
*/
function createPlayerCharacter(player, name) {
let playerId = player.get('_id');
let who = player.get('_displayname');

// Check if there are any characters already controlled by the player.
let characters = findObjs({
_type: 'character'
}).filter(character => {
return character.get('controlledby').includes(playerId);
});

// Create the new character if there are none, or if a name has been
// provided for a character being explicitly created through the macro.
if(characters.length === 0 || name) {
if(!name) {
log(`WelcomePackage: Creating first-time character for player ` +
`${player.get('_displayname')}`);
name = `${who}'s character`;
}

let character = createObj('character', {
controlledby: playerId,
inplayerjournals: 'all',
name
});

// Disable the Charactermancer for the new character by creating
// the "version" attribute. This will be set to its correct value later
// by the character sheet's worker.
/*
createObj('attribute', {
name: 'mancer_confirm_flag',
characterid: character.id,
current: '1'
});
createObj('attribute', {
name: 'l1mancer_status',
characterid: character.id,
current: 'completed'
});
*/

setTimeout(() => {
notifyAddCharacter(character);
showCharacterLink(who, character);
}, 1000);
}
}

/**
* Shows a player the link to their new character with a welcoming message.
* @param {string} who The player's display name.
* @param {Character} character
*/
function showCharacterLink(who, character) {
const html = `
<div class="menu" style="background: #fff; border: solid 1px #a88cd5; border-radius: 5px; font-weight: bold; margin-bottom: 1em; overflow: hidden;">
<div class="menuHeader" style="background: #a88cd5 ; color: #fff ; text-align: center;">Welcome!</div>
<div class="menuBody" style="padding: 5px; text-align: center">
<div>A blank character has been created for you to start building: </div>
<a href="http://journal.roll20.net/character/${character.get('_id')}" style="color: #a08;">${character.get('name')}
</div>
</div>
`;
sendChat('Welcome Package', '/w ' + who + ' ' + html);
}

// When a player logs in, create a character for them if they don't have one.
on('change:player:_online', player => {
if(isReady)
_handlePlayerOnline(player);
});

on('ready', () => {
try {
// Create the global macro for the script (visible to all players)
// if it doesn't already exist.
addCharacterCreateMacro();

log('*** Initialized Welcome Package v1.3.3 ***');
isReady = true;

// Wait some amount of time to give other scripts a chance to finish
// loading. Then process any pending logged in players.
setTimeout(() => {
try {
// Once we're loaded, create a character for any player that doesn't
// have one.
let players = findObjs({
_type: 'player'
});
_.each(players, player => {
_handlePlayerOnline(player);
});
}
catch (err) {
_error(err);
}
}, 5000);
}
catch (err) {
_error(err);
}
});

/**
* Process chat commands.
*/
on('chat:message', msg => {
let playerId = msg.playerid;

if(msg.content.startsWith(CREATE_CHARACTER_CMD)) {
let player = getObj('player', playerId);
let argv = msg.content.split(' ');
let name = argv.slice(1).join(' ');
createPlayerCharacter(player, name);
}
});

return {
OnAddCharacter: onAddCharacter,
onAddCharacter
};
})();
_.noop(WelcomePackage);
17 changes: 13 additions & 4 deletions WelcomePackage/script.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
{
"name": "Welcome Package",
"script": "script.js",
"version": "1.3.2",
"previousversions": ["1.3.1", "1.3", "1.2", "1.1", "1.0"],
"version": "1.4",
"previousversions": [
"1.3.2",
"1.3.1",
"1.3",
"1.2",
"1.1",
"1.0"
],
"description": "# Welcome Package\r\rThis script welcomes new players to your game and creates a blank new character\rfor them to begin building immediately.\r\rNormally, this would be a back and forth process with various steps depending the schedules of you and your players:\r* Player joins your campaign, can't do anything, and logs off.\r* You login, create a blank character for the player, and then log off.\r* The player eventually gets back on and builds their character.\r\rWith this script there is only one step:\r* Player joins your campaign and can immediately start building their character.\r\rThe script also installs a macro for each player named \"CreateACharacter\"\rwhich allows the players to create additional new characters with a\rspecified name.\r\r## Help\r\rMy scripts are provided 'as-is', without warranty of any kind, expressed or implied.\r\rThat said, if you experience any issues while using this script,\rneed help using it, or if you have a neat suggestion for a new feature,\rplease shoot me a PM:\rhttps://app.roll20.net/users/46544/ada-l\r\rWhen messaging me about an issue, please be sure to include any error messages that\rappear in your API Console Log, any configurations you've got set up for the\rscript in the VTT, and any options you've got set up for the script on your\rgame's API Scripts page. The more information you provide me, the better the\rchances I'll be able to help.\r\r## Show Support\r\rIf you would like to show your appreciation and support for the work I do in writing,\rupdating, maintaining, and providing tech support my API scripts,\rplease consider buying one of my art packs from the Roll20 marketplace:\r\rhttps://marketplace.roll20.net/browse/publisher/165/ada-lindberg\r",
"authors": "Ada Lindberg",
"roll20userid": 46544,
"useroptions": [],
"dependencies": ["HTML Builder"],
"dependencies": [
"HTML Builder"
],
"modifies": {},
"conflicts": []
}
}
46 changes: 13 additions & 33 deletions WelcomePackage/src/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,6 @@ const WelcomePackage = (() => {

const CREATE_CHARACTER_CMD = '!welcomePackageCreateCharacter';

const CSS = {
'menu': {
'background': '#fff',
'border': 'solid 1px #a88cd5',
'border-radius': '5px',
'font-weight': 'bold',
'margin-bottom': '1em',
'overflow': 'hidden'
},
'menuBody': {
'padding': '5px',
'text-align': 'center'
},
'menuHeader': {
'background': '#a88cd5',
'color': '#fff',
'text-align': 'center'
}
};

const observers = [];
let isReady = false;

Expand Down Expand Up @@ -132,6 +112,7 @@ const WelcomePackage = (() => {
// Disable the Charactermancer for the new character by creating
// the "version" attribute. This will be set to its correct value later
// by the character sheet's worker.
/*
createObj('attribute', {
name: 'mancer_confirm_flag',
characterid: character.id,
Expand All @@ -142,6 +123,7 @@ const WelcomePackage = (() => {
characterid: character.id,
current: 'completed'
});
*/

setTimeout(() => {
notifyAddCharacter(character);
Expand All @@ -156,17 +138,15 @@ const WelcomePackage = (() => {
* @param {Character} character
*/
function showCharacterLink(who, character) {
let menu = new HtmlBuilder('.menu');
menu.append('.menuHeader', 'Welcome!');
let content = menu.append('.menuBody');
content.append('div', 'A blank character has been created for you to start building: ');
content.append('a', character.get('name'), {
href: 'http://journal.roll20.net/character/' + character.get('_id'),
style: {
color: '#a08'
}
});
let html = menu.toString(CSS);
const html = `
<div class="menu" style="background: #fff; border: solid 1px #a88cd5; border-radius: 5px; font-weight: bold; margin-bottom: 1em; overflow: hidden;">
<div class="menuHeader" style="background: #a88cd5 ; color: #fff ; text-align: center;">Welcome!</div>
<div class="menuBody" style="padding: 5px; text-align: center">
<div>A blank character has been created for you to start building: </div>
<a href="http://journal.roll20.net/character/${character.get('_id')}" style="color: #a08;">${character.get('name')}
</div>
</div>
`;
sendChat('Welcome Package', '/w ' + who + ' ' + html);
}

Expand All @@ -182,7 +162,7 @@ const WelcomePackage = (() => {
// if it doesn't already exist.
addCharacterCreateMacro();

log('*** Initialized Welcome Package vSCRIPT_VERSION ***');
log('*** Initialized Welcome Package v1.3.3 ***');
isReady = true;

// Wait some amount of time to give other scripts a chance to finish
Expand Down Expand Up @@ -227,4 +207,4 @@ const WelcomePackage = (() => {
onAddCharacter
};
})();
_.noop(WelcomePackage);
_.noop(WelcomePackage);
Loading