{ "name": "Eclipse Phase Alternate Companion Script", "script": "ep-script.js", "version": "1.0.2", "previousversions": ["1.0.1", "1.0.2"], "description": "Eclipse Phase 1E Companion Script\r\n=================================\r\n\r\nThis is a companion script to the [Eclipse Phase 1E sheet](https:\/\/github.com\/Bathtor\/EPSheet) for use with the API on [Roll20](http:\/\/roll20.net). The vast majority of its features will not work with any other sheet and no such support is planned\/considered.\r\n\r\n**Note**: If you are using this script with Roll20's 1-Click install, be aware that sometimes inconsistent updates between the sheet and the script can leave things not working, and you have little to no control over this (and neither have I, really). If you want a more reliable experience, install both sheet and script manually instead of using Roll20's automatic systems.\r\n\r\nContents\r\n--------\r\n\r\n\r\n\r\n\r\n\r\n- [Command Overview](#command-overview)\r\n- [Installation](#installation)\r\n - [Prerequisites](#prerequisites)\r\n - [Installation](#installation-1)\r\n - [EPCompendium](#epcompendium)\r\n - [Updating](#updating)\r\n- [Command Descriptions](#command-descriptions)\r\n - [Battle Manager](#battle-manager)\r\n - [Usage](#usage)\r\n - [Recommended Macros](#recommended-macros)\r\n - [Character Cleaner](#character-cleaner)\r\n - [Usage](#usage-1)\r\n - [Recommended Macros](#recommended-macros-1)\r\n - [Character Tools](#character-tools)\r\n - [Usage](#usage-2)\r\n - [Recommended Macros](#recommended-macros-2)\r\n - [GM Tools](#gm-tools)\r\n - [Usage](#usage-3)\r\n - [Recommended Macros](#recommended-macros-3)\r\n - [Group Rolls](#group-rolls)\r\n - [Usage](#usage-4)\r\n - [Recommended Macros](#recommended-macros-4)\r\n - [Special Rolls](#special-rolls)\r\n - [Usage](#usage-5)\r\n - [Recommended Macros](#recommended-macros-5)\r\n - [Token Setup](#token-setup)\r\n - [Usage](#usage-6)\r\n - [Recommended Macros](#recommended-macros-6)\r\n - [Compendium](#compendium)\r\n - [Usage](#usage-7)\r\n - [Recommended Macros](#recommended-macros-7)\r\n\r\n\r\n\r\nCommand Overview\r\n----------------\r\nIn this section we give a quick overview over all available commands. They describe in detail in later individual sections.\r\n\r\n**Note**: You can always run `! --help` in Roll20 chat to get a quick description of the options available for each ``.\r\n\r\n\r\n- **Battle Manager** (`!epbattleman`) manages Action Turns and Action Phases based on character speed, as well as rerolls iniative for everyone at the beginning of a new turn automatically.\r\n- **Character Cleaner** (`!epclean`) resets or empties certain sections on the character sheet, in order to automate backups, or egocasts.\r\n- **Character Tools** (`!epchar`) applies damage, wounds, stress, and traumas automatically, taking armour into account as appropriate.\r\n- **GM Tools** (`!epgmtools`) can be configured to show skills for a whole party, in order to easily roll Perception checks, for example.\r\n- **Group Rolls** (`!epgroup-roll`) can be used to roll EP specific common rolls like *Fray\/2*, *Initiative*, or simply an arbitrary skill check, for a group of selected tokens.\r\n- **Special Rolls** (`!epspecialroll`) is a script that manages rolling common EP rolls, without involving a character sheet. Convenient for the improvising GM, who doesn't have an NPC ready to import, but still needs it to shoot something, for example.\r\n- **Token Setup** (`!eptoken`) generate token abilities for skills, *Fray\/2*, or *Initiative*.\r\n- **Compendium** manages data from the [Eclipse Phase Compendium](https:\/\/github.com\/Bathtor\/EPCompendium):\r\n\t- *Data* (`!epcompendium-data`) manages search, lookups, and display of compendium data to the chat.\r\n\t- *Export* (`!epcompendium-export`) can export custom morphs in a Compendium-compatible format, so they can be imported into other character sheets.\r\n\t- *Import* (`!epcompendium-import`) manages character, trait, morph, and item imports.\r\n\r\nInstallation\r\n------------\r\n\r\n### Prerequisites\r\n\r\n- You must be a **Pro** subscriber of Roll20 to use API scripts in general, and this script in particular.\r\n- You'll need a recent version of the [Eclipse Phase 1E sheet](https:\/\/github.com\/Bathtor\/EPSheet). I'll try to be clear in the documentation, which script version works with which sheet version, but generally the latest release of each should always work together. And if you picked the wrong versions, it should complain and not break anything.\r\n\r\n### Installation\r\n\r\n- Open the **raw** text of the latest release of the script. At the time of writing that is [v1.0.2](https:\/\/github.com\/Bathtor\/EPSheet\/releases\/download\/script-v1.0.2\/ep-script.js).\r\n- Copy *all* the text -- **Ctrl+A** followed by **Ctrl+C** (**Cmd+A**, **Cmd+C** on a Mac)\r\n- Go to the API Script page for your Roll20 campaign\r\n- Paste the text into a new script, or override an older version if updating. Don't forget to give it a sensible name, e.g. `epscript.js`!\r\n- Save the script\r\n- Leave the Roll20 API Script page open, and open up your campaign view in a different tab\/window. That should cause your sandbox to spin up. If no errors are reported, you should be good to go.\r\n\r\n#### EPCompendium\r\nIf you would like access to the EPCompendium-related features, you must also install the data script for the compendium. Follow the same procedure as above for the latest release of the EPCompendium, [v6.0.0](https:\/\/github.com\/Bathtor\/EPCompendium\/releases\/tag\/v6.0.0) at the time of writing. Each Compendium release also contains a number of macros prepared to use with the script that you can just c&p into your campaign.\r\n\r\n**Note** that there's a load time dependency between the compendium script and the companion script, so make sure that the compendium script's tab is to the right of the companion script's.\r\n\r\n#### Updating\r\nIf you need to update one of the script installed above, simply follow the same instructions as for a normal installation. Do make sure, that you always override old script versions, and never have two versions running in parallel!\r\n\r\nCommand Descriptions\r\n--------------------\r\n\r\n### Battle Manager\r\n**Command**: `!epbattleman`\r\n\r\nThe EP Battle Manager deals with EP's hierarchical combat timing structure based on *Action Turns* and *Action Phases* in Roll20's Turn Order mechanism. Each *Action Turn* begins by rolling iniative. Then every participant may take perform actions in the iniative order in the first *Action Phase*. For participants with `speed > 1` more *Action Phases* are added using the same initiative order, until no participant is left with `speed` greater than the current *Action Phase* number. Then the process starts over with rolling of new iniative and starting a new *Action Turn*.\r\n\r\n#### Usage\r\n1. Add tokens to the *Turn Order* in any manner you prefer.\r\n2. Run `!epbattleman --start` to inialise the Battle Manager. This will sort the *Turn Order* and create marker entries for *Action Phase* and *Action Turn* boundaries. These have the form `|Round x|Phase y|`. *From now on, do NOT use any of the Roll20 Turn Order functions anymore, as they will interfere the Battle Manager's state!*\r\n3. Proceed from character to character using `!epbattleman --next`. Characters without sufficient `speed` for the next *Action Phase* whill be dropped from the *Turn Order* as you go, but they are stored internally by the Battle Manager and will be added again at the beginning of the next *Action Turn*. At the beginning of the next *Action Turn* the Battle Manager will automatically roll new *Initiative* for all Tokens that have a Character Sheet associated with them.\r\n4. Once the battle is over, run `!epbattleman --end` to clear the Battle Manager's state. It will also tell you how long the battle took in realtime, as well as the number of rounds and phases.\r\n\r\nIf you need to **add** or **remove** charaters during an ongoing battle, you *must* use the the commands `!epbattleman --add` or `!epbattleman --drop` respectively. Using any other mechanism will pollute the Battle Managers internal state and you will see some strange behaviour.\r\n\r\nIf you accidentally use the normal `Next` button or manually add or remove tokens from an ongoing battle, the script will output a warning message to the chat. This warning message also contains a `reset` button, which you can use to invoke `!epbattleman --reset`, thereby undoing your inconsistency-introducing change.\r\n\r\n#### Recommended Macros\r\n\r\n- **BStart**: `!epbattleman --start`\r\n- **BNext**: `!epbattleman --next`\r\n- **BEnd**: `!epbattleman --end`\r\n- **BAdd**: `!epbattleman --add`\r\n- **BDrop**: `!epbattleman --drop`\r\n\r\n*In [Roll20 ES](https:\/\/github.com\/SSStormy\/roll20-enhancement-suite) Format*:\r\n```json\r\n{\r\n \"schema_version\": 2,\r\n \"macros\": [\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epbattleman --start\",\r\n \"istokenaction\": false,\r\n \"name\": \"BStart\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epbattleman --next\",\r\n \"istokenaction\": false,\r\n \"name\": \"BNext\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epbattleman --end\",\r\n \"istokenaction\": false,\r\n \"name\": \"BEnd\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epbattleman --add\",\r\n \"istokenaction\": false,\r\n \"name\": \"BAdd\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epbattleman --drop\",\r\n \"istokenaction\": false,\r\n \"name\": \"BDrop\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n }\r\n ]\r\n}\r\n```\r\n\r\n### Character Cleaner\r\n**Command**: `!epclean`\r\n\r\nThe Character Cleaner removes or resets sections of a Character Sheet that are not taken along during the **Egocast** or **Backup** procedure. This includes *Active Morph*, *Gear* (except *Software*), and *Armour* totals, as well as *Damage* and *Wounds*. *Egocast* and *Backup* behave similar in every way, except that during a backup the Character Sheet is renamed in order to differentiate it from the \"live\" sheet. You *should*, thus, run the *backup* command on a **copy** of the \"live\" sheet!\r\n\r\n#### Usage\r\n\r\n##### Egocast\r\n1. Select a token representing the *target* Character Sheet.\r\n2. Run `!epclean --egocast`.\r\n\r\n##### Backup\r\n1. Create a copy of the *target* Character Sheet.\r\n2. Drag the copy onto a map to get a token for it. *(Double check that the token actually points to the new sheet, not the old one!)*\r\n3. Select that token.\r\n4. Run `!epclean --backup`.\r\n5. Delete the token from the map and archive the backup sheet.\r\n\r\nOptionally, you can also change the **prefix** the *backup* commands adds to the sheet name. To do so, invoke the backup command like `!epclean --backup --prefix ` instead.\r\n\r\nAs an alternative to using the UI for duplicating the sheet, the following API script (found on [Roll20 Forums](https:\/\/app.roll20.net\/forum\/post\/5687127\/duplicate-character-sheet-plus-linked-token-script\/?pageforid=5687407)) also works, and has the advantage that it properly relinks the token to the new sheet. Invoke it with `!dup-char-by-token`.\r\n```javascript\r\non('ready',()=>{\r\n const simpleObj = (o)=>JSON.parse(JSON.stringify(o));\r\n const getCleanImgsrc = (imgsrc) => {\r\n let parts = imgsrc.match(\/(.*\\\/images\\\/.*)(thumb|med|original|max)([^?]*)(\\?[^?]+)?$\/);\r\n if(parts) {\r\n return parts[1]+'thumb'+parts[3]+(parts[4]?parts[4]:`?${Math.round(Math.random()*9999999)}`);\r\n }\r\n return;\r\n };\r\n const resetAttrs = {\"damage\": 0, \"wounds\": 0};\r\n const duplicateCharacter = (o) => {\r\n let c = simpleObj(o.character);\r\n let oldCid = o.character.id;\r\n delete c.id;\r\n c.name=`(COPY) ${c.name}`;\r\n c.avatar=getCleanImgsrc(c.avatar)||'';\r\n\r\n let newC = createObj('character',c);\r\n \r\n _.each(findObjs({type:'attribute',characterid:oldCid}),(a)=>{\r\n let sa = simpleObj(a);\r\n delete sa.id;\r\n delete sa._type;\r\n delete sa._characterid;\r\n sa.characterid = newC.id;\r\n if (sa.name in resetAttrs) {\r\n sa.current = resetAttrs[sa.name];\r\n }\r\n createObj('attribute',sa);\r\n });\r\n _.each(findObjs({type:'ability',characterid:oldCid}),(a)=>{\r\n let sa = simpleObj(a);\r\n delete sa.id;\r\n delete sa._type;\r\n delete sa._characterid;\r\n sa.characterid = newC.id;\r\n createObj('ability',sa);\r\n });\r\n let oldBar1 = o.token.get('bar1_link');\r\n \/\/log(\"Bar1 \" + oldBar1);\r\n let oldBar2 = o.token.get('bar2_link');\r\n \/\/log(\"Bar2 \" + oldBar2);\r\n let oldBar3 = o.token.get('bar3_link');\r\n \/\/log(\"Bar3 \" + oldBar3);\r\n let findNewAttr = (oldBar) => {\r\n if (oldBar != undefined) {\r\n if (oldBar.startsWith(\"sheetattr\")) {\r\n return oldBar; \/\/ somehow this works in Roll20\r\n } else {\r\n let barAttr = getObj('attribute', oldBar);\r\n let name = barAttr.get('name');\r\n let r = findObjs({type: 'attribute', characterid: newC.id, name: name});\r\n if (r != undefined && r.length != 0) {\r\n let id = r[0].id;\r\n return id;\r\n } else {\r\n log(\"Could not find attribute \"+name+\" in char \" + newC.id);\r\n return undefined;\r\n }\r\n }\r\n } else {\r\n log(\"Original attribute was undefined!\");\r\n return undefined;\r\n }\r\n };\r\n let newBar1 = findNewAttr(oldBar1);\r\n let newBar2 = findNewAttr(oldBar2);\r\n let newBar3 = findNewAttr(oldBar3); \r\n o.token.set('represents',newC.id);\r\n o.token.set('bar1_link', newBar1);\r\n o.token.set('bar2_link', newBar2);\r\n o.token.set('bar3_link', newBar3); \r\n setDefaultTokenForCharacter(newC,o.token);\r\n o.token.set('represents',oldCid);\r\n o.token.set('bar1_link', oldBar1);\r\n o.token.set('bar2_link', oldBar2);\r\n o.token.set('bar3_link', oldBar3);\r\n };\r\n\r\n on('chat:message',(msg)=>{\r\n if('api'===msg.type && playerIsGM(msg.playerid) && \/^!dup-char-by-token\\b\/.test(msg.content)){\r\n if(msg.selected){\r\n _.chain(msg.selected)\r\n .map((o)=>getObj('graphic',o._id))\r\n .reject(_.isUndefined)\r\n .map(o=>({token: o, character: getObj('character',o.get('represents'))}))\r\n .reject(o=>_.isUndefined(o.character))\r\n .tap(o=>{\r\n if(!o.length){\r\n sendChat('',`\/w gm
Please select one or more tokens which represent characters.<\/div>`);\r\n } else {\r\n sendChat('',`\/w gm
Duplicating: ${o.map((obj)=>obj.character.get('name')).join(', ')}<\/div>`);\r\n }\r\n })\r\n .each(duplicateCharacter);\r\n } else {\r\n sendChat('',`\/w gm
Please select one or more tokens.<\/div>`);\r\n }\r\n }\r\n });\r\n});\r\n```\r\n\r\n#### Recommended Macros\r\n\r\n- **Copy**: `!dup-char-by-token`\r\n- **Backup**: `!epclean --backup --prefix ?{Prefix}`\r\n- **Egocast**: `!epclean --egocast`\r\n\r\n*In [Roll20 ES](https:\/\/github.com\/SSStormy\/roll20-enhancement-suite) Format*:\r\n```json\r\n{\r\n \"schema_version\": 2,\r\n \"macros\": [\r\n {\r\n \"attributes\": {\r\n \"action\": \"!dup-char-by-token\",\r\n \"istokenaction\": false,\r\n \"name\": \"Copy\",\r\n \"visibleto\": \"\"\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epclean --backup --prefix ?{Prefix}\",\r\n \"istokenaction\": false,\r\n \"name\": \"Backup\",\r\n \"visibleto\": \"\"\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epclean --egocast\",\r\n \"istokenaction\": false,\r\n \"name\": \"Egocast\",\r\n \"visibleto\": \"\"\r\n }\r\n }\r\n ]\r\n}\r\n```\r\n\r\n### Character Tools\r\n**Command**: `!epchar`\r\n\r\nThe Character Tools script deals with *Damage* (DV) and *Stress* (SV) application. It automaticaly applies wounds and traumas, and reduces DV by armour taking *Armour Penetration* (AP) into account. It also outputs information on whether or not a character needs to roll to resist knockdown or unconsciouness, if the morph is bleeding out, if new derangements are acquired, and so on.\r\n\r\n#### Usage\r\n\r\n##### Damage\r\n1. Select the token you want to apply damage to.\r\n2. Determine DV (``), applicable armour if any (`` from *Kinetic*, *Energy*, *Untyped*, e.g. Psi Damage, *None*, e.g. a critical success), and AP if any (``).\r\n3. Run `!epchar --damage --armour --ap ` or, if you want only the GM to see the output, `!epchar --damage --armour --ap --output GM`, replacing the variables as determined in step 2.\r\n4. Sometimes the response of the script will tell you to roll something else, based on the result of damage application. In that case you should do so, by clicking the provided roll-button.\r\n\r\n##### Stress\r\n1. Select the token you want to apply stress to.\r\n2. Determine SV (``).\r\n3. Run `!epchar --stress ` or, if you want only the GM to see the output, `!epchar --stress --output GM`, replacing the variables as determined in step 2.\r\n4. Sometimes the response of the script will tell you to pick new derangements or upgrade existing ones, as well as roll something else, all which you should do.\r\n\r\n#### Recommended Macros\r\n\r\n- **DV**: `!epchar --damage ?{DV} --armour ?{Apply Armour|None|Energy|Kinetic|Untyped} --ap ?{AP|0}`\r\n- **GMDV**: `!epchar --damage ?{DV} --armour ?{Apply Armour|None|Energy|Kinetic|Untyped} --ap ?{AP|0} --output GM`\r\n- **SV**: `!epchar --stress ?{SV}`\r\n\r\n*In [Roll20 ES](https:\/\/github.com\/SSStormy\/roll20-enhancement-suite) Format*:\r\n```json\r\n{\r\n \"schema_version\": 2,\r\n \"macros\": [\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epchar --damage ?{DV} --armour ?{Apply Armour|None|Energy|Kinetic|Untyped} --ap ?{AP|0}\",\r\n \"istokenaction\": true,\r\n \"name\": \"DV\",\r\n \"visibleto\": \"all\"\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epchar --stress ?{SV}\",\r\n \"istokenaction\": true,\r\n \"name\": \"SV\",\r\n \"visibleto\": \"all\"\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epchar --damage ?{DV} --armour ?{Apply Armour|None|Energy|Kinetic|Untyped} --ap ?{AP|0} --output GM\",\r\n \"istokenaction\": true,\r\n \"name\": \"GMDV\",\r\n \"visibleto\": \"\"\r\n }\r\n }\r\n ]\r\n}\r\n```\r\n\r\n### GM Tools\r\n**Command**: `!epgmtools`\r\n\r\nA very simple command that collects information about skill values of a set of characters and sends them to the GM in sorted order. While in more static games like D&D simple bookkeeping would be sufficient to keep track of common skills like Perception, in EP those values are affected by traumas and wounds. Thus is can be convenient to get a quick snapshot of the state of your party with respect to certain skills. Particularly Perception and Kinesics are good candidates for this as they could be used in a \"passive\" manner without the players necessarily knowing about a failed check.\r\n\r\n#### Usage\r\n\r\n##### On Tokens\r\n1. Select all relevant tokens (e.g., all player tokens).\r\n2. Run `!epgmtools --best-mod --skill-name `, replacing `` with `Perception` or `Kinesics, for example.`\r\n\r\n##### By Name\r\nSee macro below.\r\nYou can also specify character ids instead of names as trailing arguments, but it's not quite as convenient, perhaps.\r\n\r\n#### Recommended Macros\r\n\r\n- **CharSkill**: `!epgmtools --best-mod --skill-name ?{Skill Name|Perception|Kinesics}` and append one instance of `--char-name ` for each player character in your group with name ``\r\n\r\n### Group Rolls\r\n**Command**: `!epgroup-roll`\r\n\r\nThe Group Rolls scripts enables rolling basic EP rolls like *Fray\/2* or *Initiative*, as well as arbitrary *Active Skills*, for a group of selected token. For all rolls, a modifier to the roll must also be specified.\r\n\r\n#### Usage\r\n\r\n##### Fray\/2\r\n1. Select all relevant tokens.\r\n2. Run `!epgmtools --fray-halved --mod `, with `` the GM's modifier on the roll.\r\n\r\n##### Skill\r\n1. Select all relevant tokens.\r\n2. Run `!epgmtools --skill --mod `, with `` the name of the skill to roll, `` the GM's modifier on the roll.\r\n\r\n##### Initiative\r\n1. Select all relevant tokens.\r\n2. Run `!epgmtools --ini`.\r\n\r\nRolled results go to the tracker automatically.\r\n\r\n\r\n#### Recommended Macros\r\n\r\n- **GroupIni**: `!epgroup-roll --ini`\r\n- **GroupFray\/2**: `!epgroup-roll --fray-halved --mod ?{Mod|0}`\r\n- **GroupSkill**: `!epgroup-roll --skill ?{Skill|Fray} --mod ?{Mod|0}`\r\n\r\n*In [Roll20 ES](https:\/\/github.com\/SSStormy\/roll20-enhancement-suite) Format*:\r\n```json\r\n{\r\n \"schema_version\": 2,\r\n \"macros\": [\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epgroup-roll --ini\",\r\n \"istokenaction\": false,\r\n \"name\": \"GroupIni\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epgroup-roll --fray-halved --mod ?{Mod|0}\",\r\n \"istokenaction\": false,\r\n \"name\": \"GroupFray\/2\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n },\r\n {\r\n \"attributes\": {\r\n \"action\": \"!epgroup-roll --skill ?{Skill|Fray} --mod ?{Mod|0}\",\r\n \"istokenaction\": false,\r\n \"name\": \"GroupSkill\",\r\n \"visibleto\": \"\"\r\n },\r\n \"macrobar\": {\r\n \"color\": null,\r\n \"name\": null\r\n }\r\n }\r\n ]\r\n}\r\n```\r\n\r\n### Special Rolls\r\n**Command**: `!epspecialroll`\r\n\r\nThe Special Rolls script allows EP *Success* or *Damage* rolls, without involving a character sheet. While this is mostly meant for being used via buttons generated from *EPCompendium* output, one could also create macros for custom weapons or custom rolls, for example.\r\n\r\n#### Usage\r\n\r\n##### Success\r\nThe Success template has the form\r\n```text\r\n\r\n-----------\r\n