diff --git a/WelcomePackage/1.4/script.js b/WelcomePackage/1.4/script.js new file mode 100644 index 000000000..8ce7b2be6 --- /dev/null +++ b/WelcomePackage/1.4/script.js @@ -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 = ` + + `; + 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); \ No newline at end of file diff --git a/WelcomePackage/script.json b/WelcomePackage/script.json index 5fac4371a..672a66c36 100644 --- a/WelcomePackage/script.json +++ b/WelcomePackage/script.json @@ -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": [] -} +} \ No newline at end of file diff --git a/WelcomePackage/src/script.js b/WelcomePackage/src/script.js index 593fec0cf..8ce7b2be6 100644 --- a/WelcomePackage/src/script.js +++ b/WelcomePackage/src/script.js @@ -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; @@ -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, @@ -142,6 +123,7 @@ const WelcomePackage = (() => { characterid: character.id, current: 'completed' }); + */ setTimeout(() => { notifyAddCharacter(character); @@ -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 = ` + + `; sendChat('Welcome Package', '/w ' + who + ' ' + html); } @@ -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 @@ -227,4 +207,4 @@ const WelcomePackage = (() => { onAddCharacter }; })(); -_.noop(WelcomePackage); +_.noop(WelcomePackage); \ No newline at end of file