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

Problem with Patrol script

I have been using the Patrol (Waypointpatrol) successfully, but suddenly it has started throwing an error in one game, but not in another... this is in response to clicking the 'Path' button. For reference, the error message generated was: TypeError: Cannot read property 'get' of undefined TypeError: Cannot read property 'get' of undefined at Object.WPP.ShowPatrolPaths (apiscript.js:2812:15) at Object.WPP.AddPatrolPath (apiscript.js:2734:30) at apiscript.js:3082:23 at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:143:34), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:143:34), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1393:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546) at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) at Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425) at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:400 I've double checked I am using all the same scripts in both games.  And a previous page where had used it still worked, only it now wouldnt display the paths even tho the tokens were following them. So I deleted that page in case it was having an effect, but no luck. Any assist is appreciated as I really like the script for pre-encounter flavour.
Further research, if I remove ChatSetAttr script I get: Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your scripts and click the "Save Script" button and we'll attempt to start running them again. More info... For reference, the error message generated was: SyntaxError: Unexpected token var So maybe something in that macro is causing a conflict?  But I use it in my other game without issue?
1477200718
Franky H.
Forum Champion
Try adding a semicolon to the end if each script in its own line. Sometimes codes interfere with each other, and the semi colon will make sure there's a cleen break between them
Did that, got rid of the second error, but not sure which one it was, however Patrols still refuses to work in the one game, but not the other.
1477208037
Franky H.
Forum Champion
Do you have all the dependant scripts installed in the non-functional campaign?
Yes. The patrol script had worked, as I mentioned. And it works in my other game which I have copied from to try to make it identical.  I can just not use it for now and see if things change with time... that has worked before.
I copied the campaign and reloaded everything, and it works fine.  Not sure what sort of campaign things you can corrupt but that must be what it is...
1477214898

Edited 1477214919
Franky H.
Forum Champion
Well, I'm unsure, but I'm very glad you got it working. Sorry I couldn't help more!
1477233311
The Aaron
Forum Champion
API Scripter
The issue is that you deleted a page that had paths on it and the pageid for that page persists in the state.  When you try to show paths, it creates those paths on that deleted page (which fails) and then tries to access them. Here's a version of the script that will fix that issue on startup: state.WaypointPatrol = state.WaypointPatrol || {'PatrolStatus': true}; var WPP = {}; WPP.Command        = '!wp'; WPP.SpeakAs        = 'Patrol'; WPP.RefreshRate    = 5;    // in seconds, minimum 1 WPP.RetainLastMove = true;  //save patrol moves as lastmove WPP.ShowPaths      = true;  //refresh visible paths on add or delete WPP.AddPatrolPath = function(selected, patrolname) {     //make sure the patrol name is provided     if (!patrolname || patrolname.trim() === '' ) { return 'Err: patrol name missing'; }     patrolname = patrolname.toLowerCase();     //verify only one token is selected     if (!selected) { return 'Err: no token selected'; }     if (selected.length !== 1) { return 'Err: multiple tokens selected'; }     if (!selected[0]['_type'] || selected[0]['_type'] !== 'graphic') { return 'Err: selected must be a graphic'; }     //get the token object     var token = getObj('graphic', selected[0]['_id']);     if (!token) { return 'Err: token not found'; }     //read the patrol path from token's last move     var lastmove = token.get('lastmove');      if (lastmove === '') { return 'Err: token missing last move'; }      lastmove = lastmove.split(',');     var pts = [];     while(lastmove.length > 0) {         pts.push({             'left': +lastmove.shift(),             'top' : +lastmove.shift(),         });     }     pts.push({         'left': token.get('left'),         'top' : token.get('top'),     });     //add patrol path to state if it doesn't already exist     var pageid = token.get('_pageid');     if (!state.WaypointPatrol['paths']) { state.WaypointPatrol['paths'] = {}; }     if (!state.WaypointPatrol['paths'][pageid]) { state.WaypointPatrol['paths'][pageid] = {}; }     if (state.WaypointPatrol['paths'][pageid][patrolname]) { return 'Err: name already exists'; }      state.WaypointPatrol['paths'][pageid][patrolname] = pts;     if (WPP.ShowPaths) { WPP.ShowPatrolPaths(); }     WPP.PatrolHelpMenu();     return 'Success: patrol path added'; }; WPP.DeletePatrolPath = function(patrolname) {     //make sure the patrol name is provided     if (!patrolname || patrolname.trim() === '' ) { return 'Err: patrol name missing'; }     patrolname = patrolname.toLowerCase();     //delete the patrol name if it exists     var pageid = Campaign().get('playerpageid');     if (!state.WaypointPatrol['paths'][pageid] || !state.WaypointPatrol['paths'][pageid][patrolname]) { return 'Err: patrol name does not exist for this map'; }     delete state.WaypointPatrol['paths'][pageid][patrolname];     if (WPP.ShowPaths) { WPP.ShowPatrolPaths(); }     WPP.PatrolHelpMenu();     return 'Success: patrol path deleted.'; }; WPP.PatrolHelpMenu = function() {     //create a bracketed list of avaialble patrols for the current map     var pageid = Campaign().get('playerpageid');     var paths = [];     if (state.WaypointPatrol['paths'] && state.WaypointPatrol['paths'][pageid] && _.size(state.WaypointPatrol['paths'][pageid]) > 0) {          paths = _.keys(state.WaypointPatrol['paths'][pageid]);     }     var code = encodeURIComponent(':');     var out = '';         out = '<div style="background-color: #FFF; border: 1px solid #000; border-radius: 0.5em; margin-left: 2px; margin-right: 2px; padding-top: 5px; padding-bottom: 5px;">'         + '<div style="font-weight: bold; text-align: center; border-bottom: 1px solid black; font-size: 100%">Map: ' + (getObj('page', pageid).get('name') || '(Untitled)') + '</div>'         + '<div style="padding-left: 5px; padding-right: 5px; overflow: hidden; font-size: 90%">';     if (paths.length > 0) {         out += '<div style="font-weight: bold; padding-top: 5px; padding-bottom: 5px;">Create a Patrol<a style="float: right; padding: 0px 5px 0px 5px; margin: 0px 5px 0px 5px; border: 1px solid black; border-radius: 0.5em; background-color: #999999; color: #FFF" href="' + WPP.Command + ' patrol path' + code +'?{Name of the path|'+ paths.join('|') + '} mode' + code + '?{Mode|Forward and Backwards,0|Forward Only,1|Backwards Only,-1} speed' + code + '?{Distance moved on each refresh|5} rotation' + code + '?{Angle modifier to face waypoint|Do Not Rotate,false|0 degrees,0|90 degrees,90|180 degrees,180|270 degrees,270}">Patrol</a></div>';         out += '<li style="padding-left: 10px;">Starts moving a token graphic along an existing patrol path.</li>';     } else {         out += '<div style="padding-top: 5px; padding-bottom: 5px;">You must add a path to this map from a token\'s last move before creating a patrol.</div>';         out += '<div style="padding-top: 5px; padding-bottom: 5px;">Place a token to where you want the patrol path to begin.  Move the token to where you want the patrol path to end.  You can press the space bar to create turns in the path as you\'re moving the token.  When the token is in the final position, click the \'Path\' button</div>'     }     out += '<div style="font-weight: bold; padding-top: 5px; padding-bottom: 5px;">Create a Path<a style="float: right; padding: 0px 5px 0px 5px; margin: 0px 5px 0px 5px; border: 1px solid black; border-radius: 0.5em; background-color: #999999; color: #FFF" href="' + WPP.Command + ' addpath ?{Name of the new path}">Path</a></div>';     out += '<li style="padding-left: 10px;">Saves a token\'s last move as a named patrol path for other tokens to follow.</li>';     if (paths.length > 0){         out += '<div style="font-weight: bold; padding-top: 5px; padding-bottom: 5px;">Delete a Path<a style="float: right; padding: 0px 5px 0px 5px; margin: 0px 5px 0px 5px; border: 1px solid black; border-radius: 0.5em; background-color: #999999; color: #FFF" href="' + WPP.Command + ' deletepath ?{Name of existing path to delete|' + paths.join('|') + '}">Delete</a></div>';         out += '<li style="padding-left: 10px;">Deletes an existing patrol path.</li>';         out += '<div style="font-weight: bold; padding-top: 5px; padding-bottom: 5px;">Show All Paths<a style="float: right; padding: 0px 5px 0px 5px; margin: 0px 5px 0px 5px; border: 1px solid black; border-radius: 0.5em; background-color: #999999; color: #FFF" href="' + WPP.Command + ' showpaths">Show</a></div>';         out += '<li style="padding-left: 10px;">Draws onto the GM layer all existing patrol paths and labels them.</li>';         out += '<div style="font-weight: bold; padding-top: 5px; padding-bottom: 5px;">Hide All Paths<a style="float: right; padding: 0px 5px 0px 5px; margin: 0px 5px 0px 5px; border: 1px solid black; border-radius: 0.5em; background-color: #999999; color: #FFF" href="' + WPP.Command + ' hidepaths">Hide</a></div>';         out += '<li style="padding-left: 10px;">Hides all drawn paths and labels.</li>';     }     out += '</div></div>';     sendChat(WPP.SpeakAs, '/w GM ' + out);     return; }; WPP.ShowPatrolPaths = function() {     WPP.HidePatrolPaths();     if (!state.WaypointPatrol['paths']) { return; }     state.WaypointPatrol['traces'] = state.WaypointPatrol['traces'] || [];     state.WaypointPatrol['labels'] = state.WaypointPatrol['labels'] || [];     for(pageid in state.WaypointPatrol['paths']) {         for(patrolname in state.WaypointPatrol['paths'][pageid]) {                 var pts = [];             var ul = {'left': Infinity, 'top': Infinity};             var lr = {'left': 0, 'top': 0};             for (var pt = 0; pt < state.WaypointPatrol['paths'][pageid][patrolname].length ; pt++) {                  var curr = state.WaypointPatrol['paths'][pageid][patrolname][pt];                 ul = {'left': Math.min(ul['left'],curr['left']), 'top': Math.min(ul['top'], curr['top'])};                 lr = {'left': Math.max(lr['left'],curr['left']), 'top': Math.max(lr['top'], curr['top'])};                 pts.push(['L', curr['left'], curr['top']]);             };              state.WaypointPatrol['traces'].push(createObj('path', {                 '_pageid'     : pageid,                 '_path'       : JSON.stringify(pts), //see notes                 'stroke'      : '#ff9900',                 'stroke_width': 14,                 'layer'       : 'gmlayer',                 'width'       : lr['left'] - ul['left'],                 'height'      : lr['top'] - ul['top'],                 'left'        : (lr['left'] - ul['left']) / 2 + ul['left'],                 'top'         : (lr['top'] - ul['top']) / 2 + ul['top'],             }).get('_id'));             for ( var pt = 0; pt < state.WaypointPatrol['paths'][pageid][patrolname].length - 1; pt++) {             var p1 = state.WaypointPatrol['paths'][pageid][patrolname][pt];             var p2 = state.WaypointPatrol['paths'][pageid][patrolname][pt + 1];             state.WaypointPatrol['labels'].push(createObj('text', {                 '_pageid'    : pageid,                 'text'       : 'path: ' + patrolname,                 'font_size'  : 14,                 'color'      : 'rgb(0,0,0)',                 'font_family': 'Arial',                 'layer'      : 'gmlayer',                 'left'       : Math.abs(p1['left']-p2['left']) / 2 + Math.min(p1['left'],p2['left']),                 'top'        : Math.abs(p1['top']-p2['top']) / 2 + Math.min(p1['top'],p2['top']),                 'rotation'   : ((p2['left'] < p1['left']) ? Math.atan2(p1['top'] - p2['top'], p1['left'] - p2['left']) : Math.atan2(p2['top'] - p1['top'], p2['left'] - p1['left'])) * 180 / Math.PI             }).get('_id'));             }         }     }       WPP.ShowPaths = true; }; WPP.HidePatrolPaths = function() {     if (state.WaypointPatrol['traces']) {          while (state.WaypointPatrol['traces'].length > 0) {             var path = getObj('path', state.WaypointPatrol['traces'].shift());             if (path) { path.remove(); }         }     }     if (state.WaypointPatrol['labels']) {         while (state.WaypointPatrol['labels'].length > 0) {             var text = getObj('text', state.WaypointPatrol['labels'].shift());             if (text) { text.remove(); }         }     }     WPP.ShowPaths = false; }; WPP.SetTokenToPatrol = function(selected, opts) {     //cehck to see if a token has been selected     if (!selected || selected.length === 0) { return 'Err: no token selected'; }     if (!state.WaypointPatrol['tokens']) { state.WaypointPatrol['tokens'] = {}; }     if (!opts || !opts['patrolname'] || opts['patrolname'].trim() === '' ) { return 'Err: patrol name missing'; }     opts['patrolname'] = opts['patrolname'].toLowerCase();     var pageid = getObj(selected[0]['_type'], selected[0]['_id']).get('_pageid');     if (!state.WaypointPatrol['paths'] || !state.WaypointPatrol['paths'][pageid] || !state.WaypointPatrol['paths'][pageid][opts['patrolname']]) { return 'Err: patrol name does not exist for this map'; }     var points = state.WaypointPatrol['paths'][pageid][opts['patrolname']];     for (i in selected) {         if (selected[i]['_type'] === 'graphic') {             state.WaypointPatrol['tokens'][selected[i]['_id']] = {                 'patrolname'   : opts['patrolname'],                 'active'       : opts['active'] || true,                 'patrolmode'   : opts['patrolmode'] || 0,                 'movementrate' : opts['movementrate'] || getObj('page', pageid).get('scale_number'),                 'rotation'     : isNaN(opts['rotation']) ? false : opts['rotation'],                 'random'       : opts['random'] || false,                 'phase'        : opts['phase'] || 0,             };             //move token to closest point on patrol path             var obj = getObj('graphic', selected[i]['_id']);             WPP.MoveTokenToPath(obj, points);         }     }     return 'Success: patrol added'; }; WPP.ModifyPatrollingToken = function(selected, opts) {     if(!selected || selected.length === 0) { return 'Err: no token selected'; }     var pageid = getObj(selected[0]['_type'], selected[0]['_id']).get('_pageid');     if('patrolname' in opts && !state.WaypointPatrol['paths'][pageid][opts['patrolname']]) { return 'Err: patrol name does not exist for this map';}     if (state.WaypointPatrol['tokens']) {         for (o in selected) {             if (state.WaypointPatrol['tokens'][selected[o]['_id']]) {                 for (opt in opts) {                     if (opts.hasOwnProperty(opt)) {                          state.WaypointPatrol['tokens'][selected[o]['_id']][opt] = opts[opt];                         switch(opt) {                             case 'patrolname':                                 WPP.MoveTokenToPath(getObj('graphic',selected[o]['_id']), state.WaypointPatrol['paths'][pageid][opts[opt]]);                                 break;                         }                     }                 }             }         }     }     return 'Success: patrol modified'; }; WPP.RemoveTokenFromPatrol = function(selected) {     if (!selected || selected.length === 0) { return 'Err: no token selected'; }     if (state.WaypointPatrol['tokens']) {          for (o in selected) {             if (selected[o]['_type'] == 'graphic') {                 delete state.WaypointPatrol['tokens'][selected[o]['_id']];             }         }     }     return 'Success: patrols removed'; }; WPP.MovePatrols = function() {     //loop through each token in state data, cleanup deleted     if(!state.WaypointPatrol['tokens']) { return; }     for (id in state.WaypointPatrol['tokens']) {         //validate object exists         var obj = getObj('graphic', id);         if (!obj) { delete state.WaypointPatrol['tokens'][id]; continue; }         //validate patrol exists         var pageid = obj.get('_pageid');         var patrolname = state.WaypointPatrol['tokens'][id]['patrolname'];         if (!patrolname || !state.WaypointPatrol['paths'][pageid] || !state.WaypointPatrol['paths'][pageid][patrolname]) {              obj.set({'layer':'objects'});             delete state.WaypointPatrol['tokens'][id];              continue;         }         //only patrol active units         if (!state.WaypointPatrol['tokens'][obj.get('_id')]['active']) { continue; }         //check for random movement, 20% chance the token doesn't move         if (state.WaypointPatrol['tokens'][obj.get('_id')]['random'] && Math.random() < 0.2) { continue; }         //set up the proper path         var points = state.WaypointPatrol['paths'][pageid][patrolname].slice(0);         switch(state.WaypointPatrol['tokens'][id]['patrolmode']) {             case 1:  //forward patrolling                 break;             case -1:   //reverse patrolling                 points.reverse();                 break;             default:  //back and forth patrolling                 points = points.concat(points.slice(0).reverse());                 break;         }         //set up control variables         var nextindex = state.WaypointPatrol['tokens'][id]['nextpointindex'] > points.length  -1 ? 0 : state.WaypointPatrol['tokens'][id]['nextpointindex'] ;         var moverate = state.WaypointPatrol['tokens'][id]['movementrate'] <= 0 ? 5 : state.WaypointPatrol['tokens'][id]['movementrate'];         var distremain = moverate * 70 / getObj('page', obj.get('_pageid')).get('scale_number');          var newpoint = {'left': obj.get('left'), 'top': obj.get('top')};         var lastmove = [newpoint['left'], newpoint['top']];         //move along the path based on the movement rate of the token         do {             var disttonext = WPP.Distance(newpoint, points[nextindex]);             if (distremain > disttonext) {                 newpoint = points[nextindex];                 lastmove.push(points[nextindex]['left'],points[nextindex]['top']);                 distremain -= disttonext;                 nextindex = (nextindex >= points.length - 1) ? 0 : nextindex + 1;             } else {                 var moveratio = distremain / disttonext;                 var newrotation = (state.WaypointPatrol['tokens'][id]['rotation'] === false) ?  obj.get('rotation') : Math.atan2(points[nextindex]['top'] - newpoint['top'], points[nextindex]['left'] - newpoint['left']) * 180 / Math.PI - 90 + state.WaypointPatrol['tokens'][id]['rotation'] ;;                 newpoint = {                     'left': moveratio * (points[nextindex]['left'] - newpoint['left']) + newpoint['left'],                     'top' : moveratio * (points[nextindex]['top'] - newpoint['top']) + newpoint['top'],                 };                 obj.set({                     'left'     : newpoint['left'],                     'top'      : newpoint['top'],                     'lastmove' : WPP.RetainLastMove ? lastmove.join(',') : '',                     'layer'    : Math.random() < state.WaypointPatrol['tokens'][id]['phase'] ? 'gmlayer' : 'objects' ,                     'rotation' : newrotation,                 });                 state.WaypointPatrol['tokens'][id]['nextpointindex'] = nextindex;                 distremain = 0;             }         } while (distremain > 0);     } }; WPP.Resume = function(selected) {     if(!selected || !state.WaypointPatrol['tokens']) { return; }     for (id in selected) {         if (state.WaypointPatrol['tokens'][selected[id]['_id']]) {              //set the token patrol status to active             state.WaypointPatrol['tokens'][selected[id]['_id']]['active'] = true;             //move token to the closest point on path             var obj = getObj('graphic', selected[id]['_id']);             WPP.MoveTokenToPath(obj, state.WaypointPatrol['paths'][obj.get('_pageid')][state.WaypointPatrol['tokens'][selected[id]['_id']]['patrolname']]);         }     } }; WPP.Distance = function(p1, p2) {     return Math.sqrt(Math.pow((p1['left'] - p2['left']),2) + Math.pow((p1['top'] - p2['top']),2));  }; WPP.MoveTokenToPath = function(obj, path) {     //set up control variables     var pt = {'left': obj.get('left'), 'top': obj.get('top')};     var newpt = pt;     var nextid = 0;     var delta = {'left': 0, 'top': 0};     var dmin = Infinity;     //loop through each path segment and find the closest point     for( var i = 0; i < path.length-1; i++) {         //get the next line segment in the path         var p1    = path[i];         var p2    = path[i+1];         //calculate the closest point on the segment to the token         var delta = {'left': p2['left'] - p1['left'], 'top': p2['top'] - p1['top']};         var u     = ((pt['left'] - p1['left']) * delta['left'] + (pt['top'] - p1['top']) * delta['top']) / (Math.pow(delta['left'], 2) + Math.pow(delta['top'], 2));         u = ( u > 1 ) ? 1 : (u < 0) ? 0 : u;         var testpt = {'left': p1['left'] + u * delta['left'], 'top': p1['top'] + u * delta['top']};         var d = WPP.Distance(testpt, pt);         //save point if it's the closest point of all segments         if (d < dmin) {             dmin = d;             nextid = i + 1;             newpt = JSON.parse(JSON.stringify(testpt));  //deep copy of obj         }     }     //move token to closest point     obj.set({         'left'     : newpt['left'],         'top'      : newpt['top'],         'lastmove' : obj.get('left') + ',' + obj.get('top'),     });     //set the next index patrol point for token     state.WaypointPatrol['tokens'][obj.get('_id')]['nextpointindex'] = nextid; }; WPP.CleanDeletedPagePaths = function(){     "use strict";     let pageids = _.map(findObjs({type:'page'}),p=>p.id),         textids = _.map(findObjs({type:'text'}),t=>t.id),         pathids = _.map(findObjs({type:'path'}),p=>p.id),         tokenids= _.map(findObjs({type:'graphic'}),t=>t.id),         dpageids = _.difference(_.keys(state.WaypointPatrol.paths),pageids),         dtextids = _.difference(state.WaypointPatrol.labels,textids),         dpathids = _.difference(state.WaypointPatrol.traces,pathids),         dtokenids= _.difference(state.WaypointPatrol.tokens,tokenids);     _.each(dpageids,(pid)=>delete state.WaypointPatrol.paths[pid]);     state.WaypointPatrol.labels=_.difference( state.WaypointPatrol.labels,dtextids);     state.WaypointPatrol.traces=_.difference( state.WaypointPatrol.traces,dpathids);     _.each(dtokenids,(tid)=>delete state.WaypointPatrol.tokens[tid]); }; on('chat:message', function(msg) {     var params = msg.content.split(' ');     if (msg.type !== 'api' || !playerIsGM(msg.playerid) || params.shift().toLowerCase() !== WPP.Command.toLowerCase() || params.length === 0) { return; }     var replyTo = '/w ' + msg.who.split(' ')[0] + ' ';     var cmd = params.shift().toLowerCase();     var out = undefined;     //set default parameters     var options = {};     function ReadParam(key) {         keys = {             'path'     : function(val) { options['patrolname'] = val; },             'random'   : function(val) { options['random'] = (val.toLowerCase() === 'true'); },             'phase'    : function(val) { options['phase'] = isNaN(val) ? 0 : Math.min(Math.max(0,val),100) / 100; },              'active'   : function(val) { options['active'] = (val.toLowerCase() === 'true'); },             'mode'     : function(val) { options['patrolmode'] = (val =='1' || val =='-1') ? parseInt(val) : 0; },             'speed'    : function(val) { options['movementrate'] = (isNaN(val) || val < 1) ? 1 : parseFloat(val); },             'rotation' : function(val) { options['rotation'] = isNaN(val) ? false : parseInt(val % 360); },             'default'  : function() { out = 'Err: Unknown parameter [' + key + ']'; },         };         return (keys[key.toLowerCase()] || keys['default']);      }     while (params.length > 0) {         var opt = decodeURIComponent(params.shift()).split(':');         switch (opt.length) {             case 1:                 if (options['patrolname']) { options['patrolname'] += ' ' + opt[0]; } else { options['patrolname'] = opt[0]; }                 break;             case 2:                 ReadParam(opt[0])(opt[1]);                 break;             default:                 out = 'Err: too many delimiters';                 break;         }     }      //exit if parameters are invalid     if (out) {          sendChat(WPP.SpeakAs, replyTo + out);          return;     }     switch(cmd) {         case 'on': case 'off':             state.WaypointPatrol['PatrolStatus'] = (cmd === 'on');             out = 'Patrolling ' + cmd.toUpperCase();             break;         case 'resume':             WPP.Resume(msg.selected);             break;         case 'help': case 'menu':             out = WPP.PatrolHelpMenu(); //ListPatrolPaths();             break;         case 'addpath':             out = WPP.AddPatrolPath(msg.selected, options['patrolname']);             break;         case 'deletepath':             out = WPP.DeletePatrolPath(options['patrolname']);             break;         case 'patrol':             out = WPP.SetTokenToPatrol(msg.selected, options);             break;         case 'modify':             out = WPP.ModifyPatrollingToken(msg.selected, options);             break;         case 'stoppatrol':             out = WPP.RemoveTokenFromPatrol(msg.selected);             break;         case 'showpaths':             WPP.ShowPatrolPaths();             break;         case 'hidepaths':             WPP.HidePatrolPaths();             break;         default:             out = 'Err: unknown command [' + cmd + ']';             break;     }     if (out) { sendChat(WPP.SpeakAs, replyTo + out); } }); on('change:graphic', function(obj, old) {     var id = obj.get('_id');     if (!state.WaypointPatrol['tokens'] || !state.WaypointPatrol['tokens'][id] || state.WaypointPatrol['tokens'][id]['active'] === false) return;     if (obj.get('left') === old['left'] && obj.get('top') === old['top'] && obj.get('height') === old['height'] && obj.get('width') === old['width'] && obj.get('rotation') === old['rotation']) { return; }     state.WaypointPatrol['tokens'][obj.get('_id')]['active'] = false; }); on('ready', function() {     WPP.CleanDeletedPagePaths();     setInterval(function() {         //do nothing if not enabled or initiative page is open         if (!state.WaypointPatrol['PatrolStatus'] || Campaign().get('initiativepage')) { return; }         WPP.MovePatrols();             }, Math.max(WPP.RefreshRate,1) * 1000);     log('Script loaded: Waypoint Patrols' + (state.WaypointPatrol['PatrolStatus'] ? ', actively patrolling' : '')); }); It will still probably have that issue when you delete a page if you don't clear the paths on that page first, but a restart will fix it.
Thank you, :)