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

Error with "Marching Order" API

1507913842

Edited 1508247874
[SOLVED: Fix posted by script author] Fixed Script I've been having an issue with the Marching Order API. I originally installed it with a bunch of other APIs and thought maybe there was a conflict, but then I discovered I was able to repeat the problem 100% of the time with these steps. Bug:   Marching Order API only works on the "start" page of any game. Steps to Reproduce:   Create a new game (settings to the game should be irrelevant) Install "Marching Order" API Place Tokens on "start" page Use the marching order macro and apply it to the selected tokens (this should work as normal, and provide feedback in the chat that it worked) Create a new page Put tokens on that new page Use the marching order macro to apply it to the selected tokens (nothing should happen) You can move, rename, resize, and do anything to the "start" page and it should still only work on that page. If anyone knows of a fix or maybe can't reproduce it, I can be more specific. It should work in all instances of any game created that marching order only works on the "start" page from when the game is made.
Did you move the "players" to the new page?
Jim W. said: Did you move the "players" to the new page? Copying or moving the players manually disables the marching order. The only page that works is the "start" page, all other pages will not work with marching order.
1507917377
The Aaron
Pro
API Scripter
I think he means, are you dragging the player ribbon to the new page.
That did the trick, thank you. I wish it didn't work like that though, I would like to set up marching order of some things before I move the ribbon. I use it for more than just the players themselves, like lines of marching soldiers and such. It's just not designed for that I guess.
1507918304
The Aaron
Pro
API Scripter
If I did it correctly, this should fix that: /**  * A script with a command for specifying tokens to follow other tokens.  * Simply select the tokens in the marching order and enter the "!follow"  * commandwith either a direction for the marching order of the selected tokens  * or the name of a token for the selected tokens to follow behind.  *  * E.G. "!follow west" will make the selected tokens follow each other in order  * from east to west, with the westmost token being the leader and the eastmost  * token being the caboose.  * Alternatively if we want the selected tokens to follow a character named  * "Drizt", enter the command "!follow Drizt".  *  * !follow [north|south|east|west|name of leader token]  *  * To make a token stop following the token in front of it, just manually move  * the token anywhere.  */ var MarchingOrder = (function() {   var MENU_CMD = '!showMarchingOrderMenu';   var FOLLOW_CMD = '!marchingOrderFollow';   /**    * Makes tokens follow each other in order of some compass direction.    * @param {Graphic[]} tokens    * @param {String} direction    */   var _cmdFollowDirection = function(tokens, direction) {       tokens.sort(function(a,b) {           var aX = parseFloat(a.get("left"));           var bX = parseFloat(b.get("left"));           var aY = parseFloat(a.get("top"));           var bY = parseFloat(b.get("top"));           if(direction === "north")               return (aY - bY);           else if(direction === "south")               return (bY - aY);           else if(direction === "west")               return (aX - bX);           else // east               return (bX - aX);       });       setMarchingOrder(tokens);   };   const pageForPlayer = (playerid) => playerIsGM(playerid)        ? getObj('player',playerid).get('lastpage')        : Campaign().get('playerspecificpages')[playerid]         || Campaign().get('playerpageid') ;   /**    * Makes the tokens follow a token with the specified name.    * The tokens behind the leader form a line in no particular order.    * @param {Graphic[]} tokens    * @param {String} leaderName    */   var _cmdFollowNamedToken = function(tokens, leaderName, playerid) {       var curPageID = pageForPlayer(playerid);       var leader = findObjs({           name: leaderName,           _pageid: curPageID       })[0];       if(leader) {           tokens.unshift(leader);           setMarchingOrder(tokens);       }   };   /**    * Makes a token's followers move to the token's previous position.    * @param {Graphic} leader    */   var _doFollowMovement = function(leader) {       var follower = leader.follower;       follower.prevLeft = follower.get("left");       follower.prevTop = follower.get("top");       follower.prevRotation = follower.get("rotation");       follower.set("left",leader.prevLeft);       follower.set("top",leader.prevTop);       follower.set("rotation", leader.prevRotation);   };   /**    * Makes a token follow another token.    * @param {Graphic} leader    * @param {Graphic} follower    */   var follow = function(leader, follower) {       if(!leader || !follower)           return;       // unbind all of follower's following links.       unfollow(follower);       var prevFollower = leader.follower;       follower.leader = leader;       follower.follower = prevFollower;       leader.follower = follower;       if(prevFollower) {           prevFollower.leader = follower;       }   };   /**    * Gets the argument of the API command.    * @param {Msg} msg    * @return {String}    */   var _getCmdArg = function(msg) {       var msgTxt = msg.content;       var index = msgTxt.indexOf(' ');       if(index >= 0) {           index++;           return msgTxt.substring(index);       }       else {           return null;       }   };     /**      * Returns a list of the tokens selected by the player.      * @param {Msg} msg      * @return {Graphic[]}      */     var _getSelectedTokens = function(msg) {         var tokens = [];         var curPageID = Campaign().get("playerpageid");         var selected = msg.selected; // Not actually tokens.         for(var i=0; i<selected.length; i++) {           var token = findObjs({               _id: selected[i]._id,               _pageid: curPageID           })[0];           if(token)               tokens.push(token);         }         return tokens;     };     /**      * Checks if the chat message starts with some API command.      * @param {Msg} msg   The chat message for the API command.      * @param {String} cmdName      * @return {Boolean}      */     var _msgStartsWith = function(msg, cmdName) {         var msgTxt = msg.content;         return (msg.type == 'api' && msgTxt.indexOf(cmdName) !== -1);     };     /**      * Tries to parse an API command argument as a compass direction.      * @param {String} msgTxt      * @return {String} The compass direction, or null if it couldn't be parsed.      */     var _parseDirection = function(msgTxt) {         if(msgTxt.indexOf("north") !== -1) {             return "north";         }         else if(msgTxt.indexOf("south") !== -1) {             return "south";         }         else if(msgTxt.indexOf("west") !== -1) {             return "west";         }         else if(msgTxt.indexOf("east") !== -1) {             return "east";         }         else {             return null;         }     };     /**      * Sends a message back to the player who used the command about how to      * use this script.      * @param {Msg} msg      */     var _replyHowToMessage = function(msg) {         _whisper(msg.who, " Invalid " +                 "command. After the command enter either north, south," +                 " east, or west for the direction of the marching order, " +                 "or the name of a character to follow.");     };     /**      * Sets a marching order for an array of tokens, with the token at index 0      * being the leader.      * @param {Graphic[]}      */     var setMarchingOrder = function(tokens) {         for(var i=0; i<tokens.length - 1; i++) {             var leader = tokens[i];             var follower = tokens[i+1];             sendChat("Marching Order", follower.get("name") + " is following " + leader.get("name"));             follow(leader, follower);         }     };     /**      * Shows the menu for Marching Order in the chat.      */     function _showMenu(who, playerId) {       // List of saved markers       var html = '';       // Menu options       var actionsHtml = '<div style="text-align: center;">[Follow](' + FOLLOW_CMD + ' ?{Follow: Who should I follow?})</div>';       // Cardinal directions (GM only)       if(playerIsGM(playerId)) {         actionsHtml += '<div style="text-align: center;">March in order:</div>';         actionsHtml += '<div><table style="width: 100%;">';         actionsHtml += '<tr><td></td><td>[North](' + FOLLOW_CMD + ' north)</td><td></td></tr>';         actionsHtml += '<tr><td>[West](' + FOLLOW_CMD + ' west)</td><td></td><td>[East](' + FOLLOW_CMD + ' east)</td></tr>';         actionsHtml += '<tr><td></td><td>[South](' + FOLLOW_CMD + ' south)</td><td></td></tr>';         actionsHtml += '</table></div>';       }       html += _showMenuPanel('Menu Actions', actionsHtml);       _whisper(who, html);     }     function _showMenuPanel(header, content) {       var html = '<div style="background: #fff; border: solid 1px #000; border-radius: 5px; font-weight: bold; margin-bottom: 1em; overflow: hidden;">';       html += '<div style="background: #000; color: #fff; text-align: center;">' + header + '</div>';       html += '<div style="padding: 5px;">' + content + '</div>';       html += '</div>';       return html;     }     /**      * Makes a token stop following other tokens.      * @param {Graphic} token      */     var unfollow = function(token) {         if(token.leader) {             token.leader.follower = token.follower;         }         if(token.follower) {             token.follower.leader = token.leader;         }         token.leader = null;         token.follower = null;     };     /**      * @private      * Whispers a Marching Order message to someone.      */     function _whisper(who, msg) {       var name = who.replace(/\(GM\)/, '').trim();       sendChat('Marching Order', '/w "' + name + '" ' + msg);     }     // When the API is loaded, install the Custom Status Marker menu macro     // if it isn't already installed.     on('ready', function() {       var macro = findObjs({         _type: 'macro',         name: 'MarchingOrderMenu'       })[0];       if(!macro) {         var players = findObjs({           _type: 'player'         });         var gms = _.filter(players, function(player) {           return playerIsGM(player.get('_id'));         });         _.each(gms, function(gm) {           createObj('macro', {             _playerid: gm.get('_id'),             name: 'MarchingOrderMenu',             action: MENU_CMD           });         });       }     });     /**      * Set up our chat command handler.      */     on("chat:message", function(msg) {         if(_msgStartsWith(msg, FOLLOW_CMD)) {             var arg = _getCmdArg(msg);             var tokens = _getSelectedTokens(msg);             var direction = _parseDirection(arg);             if(direction)                 _cmdFollowDirection(tokens, direction);             else if(arg)                 _cmdFollowNamedToken(tokens, arg, msg.playerid);             else                 _replyHowToMessage(msg);         }         else if(_msgStartsWith(msg, MENU_CMD)) {             _showMenu(msg.who, msg.playerid);         }     });     /**      * Set up an event handler to do the marching order effect when the      * leader tokens move!      */     on("change:graphic", function(obj, prev) {         var leader = obj;         leader.prevLeft = prev["left"];         leader.prevTop = prev["top"];         leader.prevRotation = prev["rotation"];         // Only move the followers if there was a change in either the leader's         // left or top attributes.         if(leader.get("left") != leader.prevLeft || leader.get("top") != leader.prevTop) {             // We stepped out of line. Stop following the guy in front of us.             if(leader.leader) {                 unfollow(leader);             }           // move everyone to the previous position of the token in front of them.           while(leader.follower) {               _doFollowMovement(leader);               leader = leader.follower;               // avoid cycles.               if(leader == obj) {                  return;               }           }         }     });     // The exposed API.     return {         follow: follow,         set: setMarchingOrder,         unfollow: unfollow     }; })();
That didn't appear to work, but thank you for your effort. It does appear to keep the marching order on all the pages though so just setting them up before hand works too.
1507936446
Ada L.
Marketplace Creator
Sheet Author
API Scripter
This new version of the script should fix the issue: <a href="https://raw.githubusercontent.com/Cazra/roll20-api-scripts/a0313fc077eccea4ee19f6b9409270dec8e854cd/MarchingOrder/2.2/marchingOrder.js" rel="nofollow">https://raw.githubusercontent.com/Cazra/roll20-api-scripts/a0313fc077eccea4ee19f6b9409270dec8e854cd/MarchingOrder/2.2/marchingOrder.js</a>
Stephen L. said: This new version of the script should fix the issue: <a href="https://raw.githubusercontent.com/Cazra/roll20-api-scripts/a0313fc077eccea4ee19f6b9409270dec8e854cd/MarchingOrder/2.2/marchingOrder.js" rel="nofollow">https://raw.githubusercontent.com/Cazra/roll20-api-scripts/a0313fc077eccea4ee19f6b9409270dec8e854cd/MarchingOrder/2.2/marchingOrder.js</a> That fixed it, Thanks Stephen! Love your scripts. Using the custom status markers too! Something that is bugging me though is that together they don't work very well. <a href="https://i.gyazo.com/6f0f67cbed96d26b024103c081da2c17.gif" rel="nofollow">https://i.gyazo.com/6f0f67cbed96d26b024103c081da2c17.gif</a>
1508161788
Ada L.
Marketplace Creator
Sheet Author
API Scripter
Thanks for pointing that out. I put in a fix for it: <a href="https://raw.githubusercontent.com/Cazra/roll20-api" rel="nofollow">https://raw.githubusercontent.com/Cazra/roll20-api</a>...
Stephen L. said: Thanks for pointing that out. I put in a fix for it: <a href="https://raw.githubusercontent.com/Cazra/roll20-api" rel="nofollow">https://raw.githubusercontent.com/Cazra/roll20-api</a>... That did the trick! Thanks, love the scripts! Very useful!
Will that update get pushed through to the Library?
1508333843
Ada L.
Marketplace Creator
Sheet Author
API Scripter
Yes, in fact it's already merged into the One-Click library.
got to say i love all the API i have been gobbling up. now where was that carry token api i saw... goes looking in closet im sure its in here :D&nbsp;