var MarchingOrder = (() => { 'use strict'; const MENU_CMD = '!showMarchingOrderMenu'; const FOLLOW_CMD = '!marchingOrderFollow'; /** * Makes tokens follow each other in order of some compass direction. * @param {Graphic[]} tokens * @param {String} direction */ function _cmdFollowDirection(tokens, direction) { tokens.sort((a,b) => { let aX = parseFloat(a.get("left")); let bX = parseFloat(b.get("left")); let aY = parseFloat(a.get("top")); let 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); } /** * 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 {Graphic} leader */ function _cmdFollowTargetToken(playerid, follower, leader) { // Can't follow self. if(follower === leader) return; // Include the follower's previous followers in the marching order. let tokens = [follower]; let next = follower.follower; while(next) { if(next === leader) throw new Error('Cyclical marching orders are not allowed!'); tokens.push(next); next = next.follower; } tokens.unshift(leader); setMarchingOrder(tokens); } /** * Makes a token's followers move to the token's previous position. * @param {Graphic} leader */ function _doFollowMovement(leader) { let 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); if(typeof CustomStatusMarkers !== 'undefined') CustomStatusMarkers.repositionStatusMarkers(follower); } /** * Makes a token follow another token. * @param {Graphic} leader * @param {Graphic} follower */ function follow(leader, follower) { if(!leader || !follower) return; // unbind all of follower's following links. unfollow(follower); let prevFollower = leader.follower; follower.leader = leader; follower.follower = prevFollower; leader.follower = follower; if(prevFollower) prevFollower.leader = follower; } /** * 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. */ function _parseDirection(msgTxt) { if(msgTxt.includes('north')) return "north"; else if(msgTxt.includes('south')) return "south"; else if(msgTxt.includes('west')) return "west"; else if(msgTxt.includes('east')) return "east"; else return null; } /** * Sets a marching order for an array of tokens, with the token at index 0 * being the leader. * @param {Graphic[]} */ function setMarchingOrder(tokens) { _.each(_.range(tokens.length-1), i => { let leader = tokens[i]; let 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(playerId) { let html = ''; // Menu options let actionsHtml = '
| [North](' + FOLLOW_CMD + ' north) | ||
| [West](' + FOLLOW_CMD + ' west) | [East](' + FOLLOW_CMD + ' east) | |
| [South](' + FOLLOW_CMD + ' south) |