Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Custom API for experience

Good morning, everyone. I am running a 2024 game and couldn't get any XP trackers to work. I developed a custom script that works to track and divide it by the play using chat push buttons; however, I couldn't get it to auto-push to the sheet like Lazy Experience does. It is a rudimentary script at best. I am hoping the community will find some use for it until API scripts are fully functional for 2024. on('ready', () => {     log("=== XP Splitter API with UI Buttons Ready ===");     const XP_ATTRIBUTE = "npc_xp";     const DEAD_MARKER = "dead";     function getTokenXP(token) {         const character = getObj('character', token.get('represents'));         if (!character) return 0;         const attr = findObjs({             type: 'attribute',             characterid: character.id,             name: XP_ATTRIBUTE         })[0];         return attr ? parseInt(attr.get('current'), 10) || 0 : 0;     }     // Function to send the main menu button for counting XP     function sendMainMenu() {         const menu = [             `/w gm <b>XP Splitter Menu</b>`,             `<a href="!xp-count"><b>Count XP from Dead NPCs</b></a>`         ].join('<br>');         sendChat('XP Splitter', menu);     }     // Function to send divide XP options menu with buttons     function sendDivideMenu(totalXP) {         let buttons = [];         // Add buttons for 2 to 6 players distribution         for (let i=2; i<=10; i++) {             buttons.push(`<a href="!xp-divide ${totalXP} ${i}">${i} Players</a>`);         }         // Button for custom input         buttons.push(`<a href="!xp-divide-prompt ${totalXP}">Custom Player Count</a>`);         const menu = [             `/w gm <b>Total XP: ${totalXP}</b>`,             'Divide XP among players:',             buttons.join(' | ')         ].join('<br>');         sendChat('XP Splitter', menu);     }     // Handler for chat commands     on('chat:message', (msg) => {         if (msg.type !== 'api') return;         let args = msg.content.split(' ');         let command = args[0];         if (command === '!xp-menu') {             sendMainMenu();             return;         }         if (command === '!xp-count') {             const pageId = Campaign().get('playerpageid');             let tokens = findObjs({ type: 'graphic', _pageid: pageId, subtype: 'token' });             let deadTokens = tokens.filter(token => token.get('status_' + DEAD_MARKER));             if (deadTokens.length === 0) {                 sendChat('XP Splitter', '/w gm No dead tokens found on the current page.');                 return;             }             let totalXP = 0;             deadTokens.forEach(token => {                 const xp = getTokenXP(token);                 if (xp > 0) {                     totalXP += xp;                     // Zero out so it won't be counted next time                     const character = getObj('character', token.get('represents'));                     const attr = findObjs({ type: 'attribute', characterid: character.id, name: XP_ATTRIBUTE })[0];                     if (attr) attr.set('current', 0);                 }             });             if (totalXP === 0) {                 sendChat('XP Splitter', '/w gm No XP values found on dead tokens.');                 return;             }             // Store totalXP in state for later use             state.XPSplitter = state.XPSplitter || {};             state.XPSplitter.totalXP = totalXP;             sendDivideMenu(totalXP);             return;         }         if (command === '!xp-divide') {             if (args.length < 3) {                 sendChat('XP Splitter', '/w gm Usage: !xp-divide [totalXP] [number_of_players]');                 return;             }             const totalXP = parseInt(args[1]);             const numPlayers = parseInt(args[2]);             if (isNaN(totalXP) || isNaN(numPlayers) || numPlayers <= 0) {                 sendChat('XP Splitter', '/w gm Invalid arguments for !xp-divide.');                 return;             }             // Confirm and whisper the division result             const each = Math.floor(totalXP / numPlayers);             const leftover = totalXP % numPlayers;             let message = `<b>Dividing ${totalXP} XP among ${numPlayers} players</b>:<br>`;             message += `Each player receives: ${each} XP.<br>`;             if (leftover > 0) {                 message += `Leftover XP: ${leftover}.`;             }             sendChat('XP Splitter', `/w gm ${message}`);             // Optionally, here you could automatically distribute XP             // by pushing via ChatSetAttr or your preferred method.             // Clear stored XP             delete state.XPSplitter.totalXP;             return;         }         if (command === "!xp-divide-prompt") {             // Custom player count prompt (if optional extra features desired)             if (args.length < 2) {                 sendChat('XP Splitter', '/w gm Usage: !xp-divide-prompt [totalXP]');                 return;             }             const totalXP = parseInt(args[1]);             if (isNaN(totalXP)) {                 sendChat('XP Splitter', '/w gm Invalid totalXP');                 return;             }             const prompt = `/w gm &{template:default} {{name=XP Divide Custom}} {{Total XP=${totalXP}}} {{How many players? ?{Number of players|1}}}`;             sendChat('XP Splitter', prompt);             return;         }     }); });
Code has stop working