diff --git a/Star Wars FFG Alternate/README.md b/Star Wars FFG Alternate/README.md
new file mode 100644
index 0000000000..3ac09185cc
--- /dev/null
+++ b/Star Wars FFG Alternate/README.md
@@ -0,0 +1,18 @@
+# Roll20_FFG_StarWars_CharacterSheet
+Roll20 character sheet for FFG Star Wars; compatible with FFG-SWRPG-Dice-Roller
+
+**Developers**: Timothy Yuen, Aaron Lambers, Gene Eilebrecht
+
+**Playtesters**: Gene Eilebrecht, Ben Hamill, Aaron Lambers, Zack Morris, Brett Wilson, Timothy Yuen
+
+## Version 1.0.1
+
+* Requires manual initialization of fields. Make sure to set all number fields you want to use to a value with a manual keyboard input the first time you use that field. Not doing so may cause some odd behavior with calculations dependent on those fields receiving an "undefined" value. This includes all Characteristics, Vital Stats, Weapon and Armor stats, and Item encumbrance. There is code to auto-init fields, but it currently won't trigger until Roll20 fixes a bug with the sheet:opened event.
+
+---------
+
+This sheet is inspired by and an alternative to the [Star Wars FFG API-Compatible sheet](https://github.com/Roll20/roll20-character-sheets/tree/master/Star%20Wars%20FFG%20API-Compatible). When our small local tabletop FFG Star Wars gaming group moved online to Roll20 during the COVID-19 situation, we started with that sheet. As a GM, I saw an opportunity to taylor the sheet to my group's needs. As a web app interface designer by trade, I found it to be a compelling project during my downtime at home. Rather than branching the original project, I started fresh so I could really learn how the Roll20 sheets work from the ground up. I also saw the chance to utilize some CSS Grid techniques for layout (rather than tables) and take advantage of Roll20 Sheet Workers to power most of the calcs. Plus, there were many things we didn't really need in the short-term -- GM info, Vehicles, Companions, etc. This sheet is focused entirely on a single PC.
+
+Our group has only playtested this a handful of times so far and there are plenty bugs we haven't caught yet, I'm sure. But it seems to have it's legs underneath it after a couple hundred hours of development and is learning to walk.
+
+We also worked a custom branch of the [FFG-SWRPG-Dice-Roller](https://github.com/Roll20/roll20-api-scripts/tree/master/FFG-SWRPG-Dice-Roller) to integrate with the new sheet. Since it has references objects in this sheet in particular and may not be compatible with other sheets, we have kept our own version for now and haven't tried a PR to the main branch of the dice roller.
diff --git a/Star Wars FFG Alternate/Roll20_FFG_StarWars_CharacterSheet.css b/Star Wars FFG Alternate/Roll20_FFG_StarWars_CharacterSheet.css
new file mode 100644
index 0000000000..798aaf0923
--- /dev/null
+++ b/Star Wars FFG Alternate/Roll20_FFG_StarWars_CharacterSheet.css
@@ -0,0 +1,1889 @@
+/* ======================================== */
+/* ========== START SHEET STYLES ========== */
+/* ======================================== */
+
+/* Palette */
+/*
+Dark Red - #781114
+Turquoise - #74cddd
+Bluish Grey - #354457
+Grungy Green - #52644c
+Dull Tangerine- #C88C50
+Weird Flesh - #C38D8D
+Burnt Orange - #BC3F13
+Tan - #E9E9E7
+Darker Tan - #D0D0CE
+Grey Green - #97ABA9
+*/
+
+/* Fonts */
+@import url('https://fonts.googleapis.com/css?family=Nunito&display=swap');
+
+
+/* ==================== GLOBAL STYLES ==================== */
+
+.sheet-character_sheet {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+ box-sizing: border-box;
+ font-size: 14px;
+ font-family: 'Nunito', sans-serif;
+ margin-bottom: 2em;
+ min-width: 800px;
+}
+
+/* Font size selector */
+
+input[name="attr_settings_font_size"][value="8"] + .sheet-character_sheet {
+ font-size: 8px;
+}
+
+input[name="attr_settings_font_size"][value="10"] + .sheet-character_sheet {
+ font-size: 10px;
+}
+
+input[name="attr_settings_font_size"][value="12"] + .sheet-character_sheet {
+ font-size: 12px;
+}
+
+input[name="attr_settings_font_size"][value="14"] + .sheet-character_sheet {
+ font-size: 14px;
+}
+
+input[name="attr_settings_font_size"][value="16"] + .sheet-character_sheet {
+ font-size: 16px;
+}
+
+input[name="attr_settings_font_size"][value="18"] + .sheet-character_sheet {
+ font-size: 18px;
+}
+
+input[name="attr_settings_font_size"][value="20"] + .sheet-character_sheet {
+ font-size: 20px;
+}
+
+input[name="attr_settings_font_size"][value="22"] + .sheet-character_sheet {
+ font-size: 22px;
+}
+
+input[name="attr_settings_font_size"][value="24"] + .sheet-character_sheet {
+ font-size: 24px;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+/* Selectbox styles */
+.sheet-character_sheet select {
+ display: block;
+ font-size: 1em;
+ line-height: 1.3;
+ padding: .5em;
+ width: 100%;
+ height: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ margin: 0;
+ border-radius: .25em;
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ appearance: none;
+ background-color: #fff;
+ background-repeat: no-repeat, repeat;
+ background-position: right .7em top 50%, 0 0;
+ background-size: .65em auto, 100%;
+}
+.sheet-character_sheet select::-ms-expand {
+ display: none;
+}
+.sheet-character_sheet selects:hover {
+ border-color: #888;
+}
+
+.sheet-character_sheet select option {
+ font-weight:normal;
+}
+
+.sheet-character_sheet .sheet-select_wrapper {
+ position: relative;
+}
+
+.sheet-character_sheet .sheet-select_wrapper:after {
+ content: '▼';
+ font-size: 0.75em;
+ position: absolute;
+ top:1em;
+ right: 0.5em;
+ pointer-events: none;
+}
+
+/* Headings - h1, h2, h3, h4, h5 */
+
+.sheet-character_sheet h2 {
+ display: grid;
+ grid-template-columns: 1fr max-content;
+ align-items: center;
+ font-size: 1.5em;
+ font-weight: 700;
+ text-align: center;
+ background-color: #354457;
+ color: #ffffff;
+ padding: 0.25em 0;
+ border: 1px solid #354457;
+ border-radius: 1em 1em 0 0;
+ margin-top: 1em;
+}
+
+.sheet-character_sheet h3 {
+ display: grid;
+ grid-template-columns: 1fr max-content;
+ align-items: center;
+ font-size: 1.2em;
+ font-weight: 700;
+ margin: 0 -0.85em 0 -0.75em;
+ padding: 0.5em;
+ border-bottom: 1px dotted #aaaaaa;
+ background-color: #ccc;
+}
+
+/* The section boxes, topped by an h2 */
+
+.sheet-character_sheet .sheet-section {
+ background-color: #eaeaea;
+ border-radius: 0 0 1em 1em;
+ margin-bottom: 3em;
+ padding: 1em;
+}
+
+/* Global inputs and labels */
+
+.sheet-character_sheet label {
+ display: block;
+ font-weight: normal;
+ font-size: 1em;
+ margin: 0;
+}
+
+.sheet-character_sheet input {
+ width: 100%;
+ padding: 0.5em;
+ font-size: 1em;
+ margin: 0;
+ line-height: 1.15;
+}
+
+.sheet-character_sheet input[type="number"] {
+ text-align: center;
+ width: 100%;
+ padding: 0.5em;
+ margin: 0;
+}
+
+.sheet-character_sheet input[type="checkbox"]
+{
+ height: max-content;
+}
+
+.sheet-character_sheet input[type="checkbox"]:checked {
+ background-color: #7CC48A;
+}
+
+.sheet-centered_heading {
+ text-align: center;
+}
+
+/* Show/Hide sections */
+
+h2 button,
+h3 button {
+ border-radius: 0.5em;
+ border-width: 2px;
+ background: transparent;
+ width: max-content;
+ height: max-content;
+ margin-right: 2em;
+}
+
+input.sheet-show_section[value="true"] + .sheet-section {
+ display: grid;
+}
+
+input.sheet-show_section[value="false"] + .sheet-section {
+ display: none;
+}
+
+/* Grid styles */
+
+.sheet-cell_width_2 {
+ grid-column: span 2;
+}
+
+.sheet-cell_width_3 {
+ grid-column: span 3;
+}
+
+.sheet-cell_width_4 {
+ grid-column: span 4;
+}
+
+.sheet-cell_width_5 {
+ grid-column: span 5;
+}
+
+.sheet-cell_width_6 {
+ grid-column: span 6;
+}
+
+/* List headings for repeating sections */
+.sheet-list_heading {
+ padding-bottom: 0.5em;
+ border-bottom: 1px dotted #aaaaaa;
+ margin-bottom: 1em;
+}
+
+.sheet-list_heading div {
+ font-size: 0.85em;
+}
+
+
+/* ==================== SECTION STYLES ==================== */
+
+
+/* Pools - Dice and Destiny */
+
+.sheet-pools {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(700px, 1fr));
+ column-gap: 5em;
+}
+
+.sheet-dice_pool_grid {
+ display: grid;
+ grid-template-columns: 2fr 1fr 2fr;
+ background-color: #333333;
+ padding: 0 1em;
+ border-radius: 0 0 1em 1em;
+ column-gap: 2em;
+}
+
+.sheet-dice_pool input {
+ width: auto;
+ font-size: 1.25em;
+ border-radius: 0.5em;
+}
+
+.sheet-dice_pool img {
+ padding: 0.25em;
+}
+
+.sheet-three_dice {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ column-gap: 1.25em;
+ margin: 1em 0;
+}
+
+.sheet-three_dice div {
+ display: grid;
+ grid-template-columns: 1fr 2fr;
+}
+
+.sheet-upgrade_downgrade {
+ display: grid;
+ grid-template-columns: 3fr 2fr 2fr 3fr;
+ column-gap: 0.5em;
+ margin-bottom: 1em;
+}
+
+.sheet-upgrade_downgrade label {
+ color: #ffffff;
+ font-size: 0.85em;
+ padding: 0;
+ align-self: center;
+}
+
+.sheet-upgrade_label {
+ text-align: right;
+}
+
+.sheet-force_dice_dice_roll {
+ padding: 1em 0;
+}
+
+.sheet-force_dice {
+ display: grid;
+ grid-template-columns: 1fr 2fr;
+ padding: 0 2em;
+}
+
+.sheet-dice_roll {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 0.5em;
+ margin-top: 1em;
+}
+
+.sheet-character_sheet .sheet-dice_roll button.roll_DicePool,
+.sheet-character_sheet .sheet-dice_roll button.roll_ResetDicePool {
+ margin: 0;
+ height: 100%;
+ font-size: 2.5em;
+ padding: 0.5em;
+}
+
+.sheet-character_sheet .sheet-dice_roll button.roll_DicePool::before {
+ font-family: "dicefontd12";
+ content: "L";
+}
+
+.sheet-character_sheet .sheet-dice_roll button.roll_ResetDicePool::before {
+ font-family: "Pictos";
+ content: "r";
+}
+
+/* Hide GM Destiny Buttons */
+input[name="attr_gmdicepool"][value="1"]:checked ~ .sheet-character_sheet .sheet-destiny_pool .sheet-update_player_points,
+input[name="attr_gmdicepool"][value="1"]:checked ~ .sheet-character_sheet .sheet-destiny_pool .sheet-clear_pool,
+input[name="attr_gmdicepool"][value="1"]:checked ~ .sheet-character_sheet .sheet-destiny_pool .sheet-use_dark_side
+{
+ display: none;
+}
+
+/* Hide Player Destiny Buttons */
+input[name="attr_gmdicepool"][value="2"]:checked ~ .sheet-character_sheet .sheet-destiny_pool .sheet-sync_pool_with_gm,
+input[name="attr_gmdicepool"][value="2"]:checked ~ .sheet-character_sheet .sheet-destiny_pool .roll_destiny,
+input[name="attr_gmdicepool"][value="2"]:checked ~ .sheet-character_sheet .sheet-destiny_pool .sheet-use_light_side
+{
+ display: none;
+}
+
+.sheet-destiny_pool {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 5em;
+ padding: 1em;
+}
+
+.sheet-destiny_pool button[type="roll"] {
+ display: block;
+ padding: 0.5em;
+ border-radius: 0.5em;
+ font-size: 1em;
+ width: 100%;
+ text-align: center;
+ border: 3px solid #354457;
+}
+
+.sheet-destiny_pool button[type="roll"].sheet-use_dark_side {
+ background: #333333;
+ color: #ffffff;
+ border-color: #aaaaaa;
+ text-shadow: none;
+}
+
+.sheet-destiny_pool button[type="roll"].sheet-use_light_side::before {
+ content: '✧';
+ color: #BC3F13;
+ margin-right: 0.25em;
+ font-size: 1.2em;
+ line-height: 1;
+}
+
+.sheet-destiny_pool button[type="roll"].sheet-use_dark_side::before {
+ content: '☃';
+ margin-right: 0.25em;
+ font-size: 1em;
+ line-height: 1;
+}
+
+.sheet-destiny_pool button[type="roll"].sheet-sync_pool_with_gm::before,
+.sheet-destiny_pool button[type="roll"].sheet-update_player_points::before
+{
+ content: '⟳';
+ margin-right: 0.25em;
+ font-size: 1.5em;
+ line-height: 1;
+}
+
+.sheet-destiny_pool button[type="roll"].sheet-sync_pool_with_gm,
+.sheet-destiny_pool button[type="roll"].sheet-update_player_points
+{
+ margin-bottom: 0.5em;
+}
+
+.sheet-destiny_pool button[type="roll"].sheet-clear_pool::before
+{
+ content: '♺';
+ margin-right: 0.25em;
+ font-size: 1.5em;
+ line-height: 1;
+}
+
+.sheet-destiny_pool button[type="roll"].roll_destiny::before {
+ font-family: 'dicefontd12';
+ content: '0';
+ margin-right: 0.25em;
+ font-size: 1.5em;
+ line-height: 1;
+}
+
+.sheet-destiny_inputs {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ column-gap: 2em;
+}
+
+.sheet-destiny_inputs input {
+ font-size: 1.25em;
+ padding: 0.5em;
+ border-radius: 0.5em;
+}
+
+.sheet-destiny_inputs label {
+ text-align: center;
+ padding: 0.5em;
+}
+
+.sheet-destiny_inputs .sheet-destiny_dark {
+ background-color: #333333;
+ color: #ffffff;
+}
+
+/* Sheet Nagivation Tabs */
+
+.sheet-tab_navigation {
+ display: grid;
+ grid-template-columns: repeat(7, 1fr);
+ margin: 2em 0;
+}
+
+.sheet-tab_navigation button {
+ width: 100%;
+ font-size: 1.25em;
+ padding: 1em;
+ color: #ffffff;
+ border: 1px solid #a3bedf;
+ border-top-width: 0;
+ border-left-width: 0;
+ border-bottom-width: 0;
+ background: rgb(188,63,19);
+ background: linear-gradient(180deg, rgba(188,63,19,1) 38%, rgba(168,44,0,1) 100%);
+}
+
+.sheet-tab_navigation div:last-child button {
+ border-radius: 0 2em 2em 0;
+ border-color: #354457;
+}
+
+.sheet-tab_navigation div:first-child button {
+ border-radius: 2em 0 0 2em;
+}
+
+.sheet-tab_navigation span {
+ display: block;
+}
+
+.sheet-tab_navigation button:hover {
+ background: rgb(84,105,131);
+ background: radial-gradient(circle, rgba(84,105,131,1) 0%, rgba(53,68,87,1) 100%);
+}
+
+.sheet-tab_navigation span:hover {
+ text-shadow: 0px 0px 8px #ffffff;
+}
+
+.sheet-bio,
+.sheet-skills,
+.sheet-combat,
+.sheet-equipment,
+.sheet-talents,
+.sheet-force,
+.sheet-settings,
+.sheet-settings-gm {
+ display: none;
+}
+
+.sheet-tabstoggle[value="bio"] ~ div.sheet-bio,
+.sheet-tabstoggle[value="skills"] ~ div.sheet-skills,
+.sheet-tabstoggle[value="combat"] ~ div.sheet-combat,
+.sheet-tabstoggle[value="equipment"] ~ div.sheet-equipment,
+.sheet-tabstoggle[value="talents"] ~ div.sheet-talents,
+.sheet-tabstoggle[value="force"] ~ div.sheet-force,
+.sheet-tabstoggle[value="settings"] ~ div.sheet-settings {
+ display: block;
+}
+
+.sheet-tab_navigation [type="radio"] {
+ display: none;
+}
+
+.sheet-tab_navigation [type="radio"]:checked ~ button {
+ background: rgb(96,124,159);
+ background: radial-gradient(circle, rgba(96,124,159,1) 0%, rgba(53,68,87,1) 100%);
+}
+
+/* Bio */
+.sheet-name {
+ display: grid;
+ grid-template-columns: 2fr 3fr 2fr 3fr;
+ column-gap: 3em;
+ row-gap: 1em;
+}
+
+.sheet-bio label {
+ padding: 0.5em 0;
+ text-align: right;
+}
+
+.sheet-bio label::after {
+ content: ":";
+ text-align: right;
+}
+
+.sheet-name .sheet-specialization_trees_container select {
+ margin-bottom: 0.5em;
+}
+
+.sheet-xp_grid {
+ display: grid;
+ grid-template-columns: 1fr 1em 1fr;
+ column-gap: 1em;
+ align-items: center;
+ text-align: center;
+ height: max-content;
+}
+
+.sheet-xp_credits {
+ display: grid;
+ grid-template-columns: 2fr 3fr 2fr 3fr;
+ column-gap: 3em;
+ align-items: center;
+}
+
+.sheet-motivations_grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));
+ column-gap: 5em;
+}
+
+.sheet-obligation_total_grid,
+.sheet-duty_total_grid,
+.sheet-morality_total_grid {
+ display: grid;
+ grid-template-columns: max-content max-content;
+ column-gap: 1em;
+ align-items: center;
+ margin-bottom: 1em;
+}
+
+.sheet-morality {
+ display: grid;
+ grid-template-columns: 2fr 3fr 2fr 3fr;
+ column-gap: 3em;
+ row-gap: 1em;
+ align-items: center;
+}
+
+.sheet-obligation_item {
+ display: grid;
+ grid-template-columns: 2fr 1fr 2fr 4fr;
+ column-gap: 1em;
+}
+
+.sheet-duty_item {
+ display: grid;
+ grid-template-columns: 2fr 1fr 6fr;
+ column-gap: 1em;
+}
+
+.sheet-obligation_item textarea,
+.sheet-duty_item textarea {
+ padding: 1em;
+ height: 5em;
+}
+
+/* Body Stats - Wounds, Strain, Soak, Defense */
+
+.sheet-vital_stats {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
+ column-gap: 2em;
+ padding: 1em;
+}
+
+.sheet-vital_stats label {
+ padding: 0.5em;
+ margin: 0;
+ font-size: 0.75em;
+ text-align: center;
+ width: 100%;
+}
+
+.sheet-vital_stats input,
+.sheet-vital_stats span {
+ font-size: 1.5em;
+ border: none;
+}
+
+.sheet-vital_stats span {
+ text-align: center;
+ padding: 0.5em;
+ background-color: #ffffff;
+ display: block;
+}
+
+.sheet-vital_stats span.sheet-encumbrance_threshold {
+ background-color: #333333;
+ color: #ffffff;
+}
+
+.sheet-vital_stats_column {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: auto;
+ column-gap: 0.5em;
+}
+
+.sheet-vital_stats input,
+.sheet-vital_stats span {
+ width: 100%;
+ border-radius: 0.5em;
+}
+
+.sheet-vital_stats .sheet-stat_label {
+ background: rgb(120,17,20);
+ background: radial-gradient(circle, rgba(120,17,20,1) 0%, rgba(103,0,3,1) 62%);
+ color: #ffffff;
+ padding: 0.25em;
+ margin: 0.5em 0;
+ font-size: 1em;
+ text-align: center;
+ width: 100%;
+ border: 4px solid #354457;
+ border-radius: 1em;
+}
+
+.sheet-vital_stats input.sheet-wounds_threshold,
+.sheet-vital_stats input.sheet-strain_threshold {
+ background-color: #333333;
+ color: #ffffff;
+}
+
+.sheet-vital_stats input.sheet-wounds_current {
+ box-shadow: inset 0 0 0 5px #7CC48A;
+}
+
+.sheet-vital_stats input.sheet-strain_current {
+ box-shadow: inset 0 0 0 5px #B31D1D;
+}
+
+.sheet-stat_label span {
+ display: inline;
+ font-size: 1em;
+ background: none;
+ border: none;
+ padding: 0;
+}
+
+.sheet-stat_label .sheet-help_info {
+ position: absolute;
+ color: #000000;
+ right: 3em;
+ max-width: 50em;
+ font-weight: normal;
+}
+
+h2 .sheet-help_info {
+ position: absolute;
+ color: #000000;
+ right: 40%;
+ max-width: 50em;
+ font-weight: normal;
+}
+
+/* Characteristics - Brawn, Agility, Intellect, Cunning, Willpower, Presence */
+
+.sheet-characteristics {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
+ column-gap: 1em;
+ background-color: #eaeaea;
+ padding: 1em;
+ border-radius: 0 0 1em 1em;
+}
+
+.sheet-characteristics input {
+ width: 100%;
+ padding: 1em;
+ font-size: 1.5em;
+ border: 4px solid #354457;
+ border-radius: 50%;
+}
+
+.sheet-characteristics label {
+ background-color: #C88C50;
+ color: #ffffff;
+ padding: 0.25em;
+ margin: 0.5em 0;
+ font-size: 1em;
+ text-align: center;
+ width: 100%;
+ border: 4px solid #354457;
+ border-radius: 1em;
+}
+
+/* Skills */
+
+.sheet-skills_body {
+ background-color: #eaeaea;
+ padding: 0 1em;
+ border-radius: 0 0 1em 1em;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(700px, 1fr));
+ column-gap: 5em;
+}
+
+.sheet-skill {
+ display: grid;
+ grid-template-columns: 1fr 8em 4em 4em 10em 10em 3em;
+ column-gap: 1em;
+ padding: 0.5em 0;
+ border-bottom: 1px dotted #aaaaaa;
+}
+
+.sheet-skill label,
+.sheet-skill div,
+.sheet-skill input,
+.sheet-skill button {
+ align-self: center;
+}
+
+.sheet-skill_heading {
+ padding-top: 1em;
+}
+
+.sheet-skill_heading div {
+ font-size: 0.85em;
+}
+
+.sheet-skill_rank_boxes {
+ display: flex;
+ background-color: #ffffff;
+ padding: 0.15em 0.25em;
+}
+
+.sheet-gd + span {
+ color: #00b300;
+ font-size: 1.5em;
+ letter-spacing: 3px;
+ margin-left: 2px;
+}
+
+.sheet-gd[value="0"] + span::after
+{
+ content: "";
+}
+
+.sheet-gd[value="1"] + span::after
+{
+ content: "♦";
+}
+
+.sheet-gd[value="2"] + span::after
+{
+ content: "♦♦";
+}
+
+.sheet-gd[value="3"] + span::after
+{
+ content: "♦♦♦";
+}
+
+.sheet-gd[value="4"] + span::after
+{
+ content: "♦♦♦♦";
+}
+
+.sheet-gd[value="5"] + span::after
+{
+ content: "♦♦♦♦♦";
+}
+
+.sheet-gd[value="6"] + span::after
+{
+ content: "♦♦♦♦♦♦";
+}
+
+.sheet-gd[value="7"] + span::after
+{
+ content: "♦♦♦♦♦♦♦";
+}
+
+.sheet-yd + span {
+ color: #c9cc00;
+ font-size: 1.5em;
+ line-height: 1.2;
+}
+
+.sheet-yd[value="0"] + span::after
+{
+ content: "";
+}
+
+.sheet-yd[value="1"] + span::after
+{
+ content: "◈";
+}
+
+.sheet-yd[value="2"] + span::after
+{
+ content: "◈◈";
+}
+
+.sheet-yd[value="3"] + span::after
+{
+ content: "◈◈◈";
+}
+
+.sheet-yd[value="4"] + span::after
+{
+ content: "◈◈◈◈";
+}
+
+.sheet-yd[value="5"] + span::after
+{
+ content: "◈◈◈◈◈";
+}
+
+.sheet-yd[value="6"] + span::after
+{
+ content: "◈◈◈◈◈◈";
+}
+
+.sheet-yd[value="7"] + span::after
+{
+ content: "◈◈◈◈◈◈◈";
+}
+
+.sheet-skill input[type="checkbox"],
+.sheet-skill input[type="number"]
+{
+ text-align: center;
+}
+
+.sheet-skill select {
+ margin: 0;
+ height: 100%;
+}
+
+.sheet-skills_general .sheet-skill:last-child,
+.sheet-skills_combat .sheet-skill:last-child,
+.sheet-skills_knowledge .sheet-skill:last-child {
+ border-bottom: none;
+}
+
+/* Roll button */
+
+.sheet-character_sheet button.roll_button {
+ font-size: 1.5em;
+ font-family: "dicefontd12";
+ color: #555555;
+ padding: 0.25em;
+ cursor: pointer;
+}
+
+.sheet-character_sheet button.roll_button::before {
+ font-family: "dicefontd12";
+ content: "L";
+}
+
+/* Combat */
+
+.sheet-criticals {
+ background-color: #eaeaea;
+ padding: 0 1em 1em 1em;
+ border-radius: 0 0 1em 1em;
+}
+
+.sheet-rolla_critical {
+ display: grid;
+ grid-template-columns: 1fr 1fr 3fr;
+ column-gap: 1em;
+ padding: 1em;
+ align-items: center;
+}
+
+.sheet-rolla_critical label {
+ text-align: right;
+}
+
+.sheet-rolla_critical label::after {
+ content: ':';
+}
+
+.sheet-rolla_critical button[type="roll"] {
+ padding: 0.25em;
+}
+
+.sheet-rolla_critical button[type="roll"]::before {
+ font-family: 'dicefontd10';
+ content: 'CC';
+ font-size: 1.5em;
+ margin-right: 0.25em;
+}
+
+.sheet-criticals h3 {
+ margin-bottom: 1em;
+}
+
+.sheet-current_crit {
+ display: grid;
+ grid-template-columns: 4fr 1fr;
+ column-gap: 1em;
+ row-gap: 1em;
+ padding: 1em;
+ align-items: center;
+ border-radius: 0.5em;
+ margin: 2em 0;
+ color: #ffffff;
+}
+
+.sheet-disabled_option {
+ font-style: italic;
+ color: #cccccc;
+}
+
+.sheet-current_crit_severity_input[value="Easy (1 ♦)"] + .sheet-current_crit {
+ background: rgb(168,54,57);
+ background: radial-gradient(circle, rgba(168,54,57,0.1) 38%, rgba(120,17,20,0.1) 100%);
+ border: 3px solid #781114;
+ color: #000000;
+}
+
+.sheet-current_crit_severity_input[value="Average (2 ♦♦)"] + .sheet-current_crit {
+ background: rgb(168,54,57);
+ background: radial-gradient(circle, rgba(168,54,57,0.3) 38%, rgba(120,17,20,0.3) 100%);
+ border: 3px solid #781114;
+ color: #000000;
+}
+
+.sheet-current_crit_severity_input[value="Hard (3 ♦♦♦)"] + .sheet-current_crit {
+ background: rgb(168,54,57);
+ background: radial-gradient(circle, rgba(168,54,57,0.7) 38%, rgba(120,17,20,0.7) 100%);
+ border: 3px solid #781114;
+}
+
+.sheet-current_crit_severity_input[value="Daunting (4 ♦♦♦♦)"] + .sheet-current_crit {
+ background: rgb(168,54,57);
+ background: radial-gradient(circle, rgba(168,54,57,1) 38%, rgba(120,17,20,1) 100%);
+ border: 3px solid #781114;
+}
+
+.sheet-current_crit_severity_input[value="DEAD"] + .sheet-current_crit {
+ background: #000000;
+ border: 3px solid #000000;
+ color: #ccc;
+}
+
+.sheet-current_crit_container {
+ display: grid;
+ grid-template-columns: 1fr 3fr;
+ column-gap: 2em;
+ row-gap: 1em;
+ align-items: center;
+}
+
+.sheet-current_crit .sheet-current_crit_type {
+ font-weight: bold;
+}
+
+.sheet-current_crit .sheet-current_crit_description {
+ font-size: 1em;
+}
+
+.sheet-current_crit button {
+ border: 5px solid #2c3947;
+ font-size: 1em;
+ border-radius: 0.5em;
+ height: 100%;
+ background: rgb(35,140,0);
+ background: radial-gradient(circle, rgba(35,140,0,1) 38%, rgba(82,100,76,1) 100%);
+ color: #ffffff;
+}
+
+/* Weapons */
+
+.sheet-weapons .repcontainer {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(700px, 1fr));
+ column-gap: 10em;
+}
+
+.sheet-weapon {
+ padding-bottom: 1em;
+ margin-bottom: 2em;
+}
+
+.sheet-weapon_stats {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
+ column-gap: 2em;
+ padding: 1em;
+}
+
+.sheet-character_sheet h3.sheet-weapon_name {
+ background: rgb(82,100,76);
+ background: radial-gradient(circle, rgba(82,100,76,1) 38%, rgba(54,64,51,1) 100%);
+ color: #ffffff;
+ text-align: center;
+}
+
+.sheet-weapon_stats label {
+ background: rgb(82,100,76);
+background: radial-gradient(circle, rgba(82,100,76,1) 38%, rgba(54,64,51,1) 100%);
+ color: #ffffff;
+ padding: 0.25em;
+ margin: 0.5em 0;
+ font-size: 1em;
+ text-align: center;
+ width: 100%;
+ border: 4px solid #354457;
+ border-radius: 1em;
+}
+
+.sheet-weapon_stats input {
+ text-align: center;
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.5em;
+ font-size: 1.5em;
+}
+
+.sheet-weapon_stats button[type="roll"] {
+ place-self: center;
+ font-size: 2.5em;
+ padding: 0.5em;
+}
+
+.sheet-weapon_stats button[type="roll"]::before {
+ font-family: "dicefontd12";
+ content: "L";
+}
+
+.sheet-weapon_critical_bonus,
+.sheet-weapon_damage_bonus {
+ display: grid;
+ grid-template-columns: 2fr 3fr;
+ column-gap: 1em;
+ align-items: center;
+}
+
+.sheet-weapon_bonus_text {
+ text-align: right;
+ padding: 0.25em;
+}
+
+.sheet-critical_damage_cell {
+ align-self: start;
+}
+
+.sheet-weapon_critical_bonus_vicious,
+.sheet-weapon_damage_bonus_superior,
+.sheet-weapon_damage_bonus_inferior {
+ display: none;
+}
+
+.sheet-weapon_critical_bonus_vicious:not([value="0"]) + div,
+.sheet-weapon_quality_superior_bonus_damage:not([value="0"]) + div,
+.sheet-weapon_quality_inferior_penalty_damage:not([value="0"]) + div {
+ display: grid;
+}
+
+.sheet-weapon_critical_bonus_total,
+.sheet-weapon_damage_bonus_total {
+ border-top: 1px dotted #aaaaaa;
+ margin-top: 0.5em;
+ padding-top: 0.5em;
+}
+
+.sheet-from_vicious_text,
+.sheet-from_superior_inferior_text {
+ font-size: 0.85em;
+ padding: 0 0.25em;
+}
+
+.sheet-weapon_info {
+ display: grid;
+ grid-template-columns: 2fr 3fr 2fr 3fr;
+ column-gap: 1em;
+ row-gap: 0.5em;
+ padding: 1em;
+ align-items: center;
+}
+
+.sheet-weapon_info input[type="number"] {
+ border-radius: 0.5em;
+}
+
+.sheet-weapon_qualities_cell {
+ grid-column: span 3;
+}
+
+.sheet-character_sheet .sheet-weapon_qualities_header {
+ display: flex;
+ align-items: center;
+}
+
+.sheet-weapon_mods_negative_message {
+ margin: 1em 0;
+ background-color: #B31D1D;
+ color: #ffffff;
+ padding: 1em;
+ display: none;
+}
+
+.sheet-weapon_mods_negative_message::before {
+ font-family: 'Pictos';
+ content: '!';
+ margin-right: 0.5em;
+}
+
+.sheet-weapon_mods_negative[value='true'] + .sheet-weapon_mods_negative_message {
+ display: block;
+}
+
+.sheet-weapon_mods_table_header {
+ display: grid;
+ grid-template-columns: 4fr 1fr 8fr;
+ column-gap: 1em;
+ padding: 1em 0 0.5em 0;
+ border-bottom: 1px dotted #aaaaaa;
+}
+
+.sheet-weapon_mods_table_header > * {
+ font-size: 0.85em;
+}
+
+.sheet-weapon_mod {
+ display: grid;
+ grid-template-columns: 4fr 1fr 8fr;
+ column-gap: 1em;
+ padding: 1em 0 0.5em 0;
+ border-bottom: 1px dotted #aaaaaa;
+}
+
+.sheet-weapon_mod:last-child {
+ border: none;
+}
+
+.sheet-weapon_mod > * {
+ font-size: 0.85em;
+}
+
+.sheet-weapon_mod > textarea {
+ padding: 1em;
+ height: 6em;
+}
+
+.sheet-weapon_mod > input,
+.sheet-weapon_mod > select {
+ height: max-content;
+ font-size: 0.85em;
+}
+
+.sheet-character_sheet h3 span.sheet-weapon_qualities_activation_icon {
+ background-image: url('https://imgsrv.roll20.net/?src=https%3A//i.imgur.com/Gav94H2.png');
+ background-repeat: repeat-x;
+ background-size: 1em;
+ width: 2em;
+ height: 1em;
+ display: block;
+ margin: 0 0.25em 0 1.5em;
+}
+
+.sheet-character_sheet h3 span.sheet-weapon_qualities_activation {
+ font-size: 0.75em;
+ font-weight: 500;
+ display: block;
+}
+
+.sheet-weapon_qualities {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr 4em);
+ column-gap: 1em;
+ row-gap: 0.5em;
+ margin-top: 1em;
+ padding: 1em;
+ align-items: center;
+ font-size: 0.85em;
+}
+
+.sheet-weapon_qualities input,
+.sheet-weapon_qualities select {
+ width: 100%;
+ height: 100%;
+ padding: 0.25em;
+ margin: 0;
+}
+
+.sheet-weapon_info label,
+.sheet-weapon_qualities label {
+ text-align: right;
+ position: relative;
+ padding: 0.25em;
+}
+
+.sheet-weapon_info label::after,
+.sheet-weapon_qualities label::after {
+ content: ":";
+}
+
+.sheet-weapon_notes {
+ padding: 1em;
+ margin: 1em 0;
+}
+
+.sheet-weapon_carried_grid {
+ display: grid;
+ grid-template-columns: max-content max-content;
+ column-gap: 0.5em;
+ align-items: center;
+}
+
+.sheet-weapon_carried_grid input {
+ width: max-content;
+}
+
+/* Armor */
+
+.sheet-armor_item {
+ display: grid;
+ grid-template-columns: 3fr repeat(5, 5em) 2fr;
+ column-gap: 1em;
+ row-gap: 0.5em;
+ margin-bottom: 1em;
+ align-items: center;
+}
+
+.sheet-armor_heading {
+ margin-top: 1em;
+ border-bottom: 1px dotted #aaaaaa;
+ padding-bottom: 0.5em;
+}
+
+.sheet-armor_heading div {
+ font-size: 0.85em;
+}
+
+.sheet-armor_item label {
+ text-align: right;
+}
+
+.sheet-armor_item label::after {
+ content: ':';
+}
+
+.sheet-armor_item textarea {
+ height: 4em;
+ padding: 0.5em;
+ font-size: 1em;
+}
+
+.sheet-armor strong {
+ color: #c9cc00;
+ font-style: italic;
+}
+
+/* Gear */
+
+.sheet-gear_containers_grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(700px, 1fr));
+ column-gap: 5em;
+}
+
+.sheet-gear_item {
+ display: grid;
+ grid-template-columns: 4fr 1fr minmax(5em, 1fr) 8fr;
+ column-gap: 1em;
+ row-gap: 1em;
+}
+
+.sheet-gear_heading {
+ padding-bottom: 0.5em;
+ border-bottom: 1px dotted #aaaaaa;
+ margin-bottom: 1em;
+}
+
+.sheet-gear_heading div {
+ font-size: 0.85em;
+}
+
+.sheet-gear_item input {
+ height: max-content;
+}
+
+.sheet-gear_item textarea {
+ padding: 1em;
+ height: 5em;
+}
+
+/* Containers */
+
+.sheet-container {
+ display: grid;
+ grid-template-columns: 3fr 3fr 8fr;
+ column-gap: 1em;
+ row-gap: 1em;
+}
+
+.sheet-container_heading {
+ padding-bottom: 0.5em;
+ border-bottom: 1px dotted #aaaaaa;
+ margin-bottom: 1em;
+}
+
+.sheet-container_heading div {
+ font-size: 0.85em;
+}
+
+.sheet-container input {
+ height: max-content;
+}
+
+.sheet-container textarea {
+ padding: 1em;
+ height: 5em;
+}
+
+/* Cybernetics */
+
+.sheet-cyber {
+ display: grid;
+ grid-template-columns: 1fr 3fr;
+ column-gap: 1em;
+ row-gap: 1em;
+}
+
+.sheet-cybernetics_heading {
+ padding-bottom: 0.5em;
+ border-bottom: 1px dotted #aaaaaa;
+ margin-bottom: 1em;
+}
+
+.sheet-cybernetics_heading div {
+ font-size: 0.85em;
+}
+
+.sheet-cybernetics input {
+ height: max-content;
+}
+
+.sheet-cybernetics textarea {
+ padding: 1em;
+ height: 5em;
+}
+
+/* Talents */
+
+.sheet-combat_talent,
+.sheet-non_combat_talent {
+ display: grid;
+ grid-template-columns: 4fr 1fr 1fr 8fr;
+ column-gap: 1em;
+ row-gap: 1em;
+}
+
+.sheet-combat_talents_heading,
+.sheet-non_combat_talents_heading {
+ padding-bottom: 0.5em;
+ border-bottom: 1px dotted #aaaaaa;
+ margin-bottom: 1em;
+}
+
+.sheet-combat_talents_heading div,
+.sheet-non_combat_talents_heading div {
+ font-size: 0.85em;
+}
+
+.sheet-combat_talent input,
+.sheet-non_combat_talent input {
+ height: max-content;
+}
+
+.sheet-combat_talent input[type="checkbox"],
+.sheet-non_combat_talent input[type="checkbox"],
+.sheet-gear_item input[type="checkbox"] {
+ transform: scale(1.5);
+ margin-top: 0.5em;
+ width: max-content;
+ justify-self: center;
+}
+
+.sheet-combat_talent textarea,
+.sheet-non_combat_talent textarea {
+ padding: 1em;
+ height: 5em;
+}
+
+.sheet-combat_talent_checkbox_container,
+.sheet-non_combat_talent_checkbox_container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 0.25em;
+}
+
+.sheet-combat_talent .sheet-icon_active,
+.sheet-non_combat_talent .sheet-icon_active {
+ display: none;
+}
+
+.sheet-combat_talent .sheet-icon_passive,
+.sheet-non_combat_talent .sheet-icon_passive {
+ display: block;
+ font-size: 1.5em;
+}
+
+.sheet-combat_talent_active_checkbox:checked ~ .sheet-icon_active,
+.sheet-non_combat_talent_active_checkbox:checked ~ .sheet-icon_active {
+ display: block;
+ font-size: 1.5em;
+}
+
+.sheet-combat_talent_active_checkbox:checked ~ .sheet-icon_passive,
+.sheet-non_combat_talent_active_checkbox:checked ~ .sheet-icon_passive {
+ display: none;
+}
+
+/* The Force */
+
+.sheet-force-power {
+ border-bottom: 1px dotted #aaaaaa;
+ padding-bottom: 2em;
+ margin-bottom: 2em;
+}
+
+.sheet-force_powers .repcontainer {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(700px, 1fr));
+ column-gap: 5em;
+}
+
+.sheet-force-power h3 {
+ background: rgb(226,161,96);
+ background: radial-gradient(circle, rgba(226,161,96,1) 38%, rgba(200,140,80,1) 100%);
+ color: #000000;
+ padding: 0.5em;
+ margin: 1em 0;
+ font-size: 1.5em;
+ text-align: center;
+ border-radius: 0.5em;
+ text-shadow: 0px 0px 15px #ffffff;
+}
+
+.sheet-force_rating {
+ width: 38%;
+ text-align: center;
+ margin: 0 auto 2em auto;
+}
+
+.sheet-force_rating label {
+ background: rgb(120,17,20);
+ background: radial-gradient(circle, rgba(120,17,20,1) 0%, rgba(103,0,3,1) 62%);
+ color: #ffffff;
+ padding: 0.25em;
+ margin: 0.5em 0;
+ font-size: 1em;
+ text-align: center;
+ border: 4px solid #354457;
+ border-radius: 1em;
+}
+
+.sheet-force_rating input[type="number"] {
+ padding: 0.5em;
+ font-size: 1.5em;
+ text-align: center;
+ border-radius: 0.5em;
+}
+
+.sheet-force-power-roll {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 2em;
+ align-items: center;
+ padding-bottom: 2em;
+}
+
+.sheet-force-power button.roll_force_die {
+ margin: 0;
+ font-size: 1.5em;
+ padding: 0.5em;
+ border: 3px solid #354457;
+ border-radius: 0.5em;
+ width: 100%;
+}
+
+.sheet-force-power button[type="roll"].roll_force_die::before {
+ font-family: "dicefontd12";
+ content: "0";
+ margin-right: 0.25em;
+}
+
+.sheet-force-power-levels {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ column-gap: 1em;
+ row-gap: 1em;
+}
+
+.sheet-force-power-levels label {
+ background: rgb(106,136,133);
+ background: radial-gradient(circle, rgba(106,136,133,1) 38%, rgba(74,112,108,1) 100%);
+ color: #ffffff;
+ padding: 0.25em;
+ margin: 0.5em 0;
+ font-size: 1em;
+ text-align: center;
+ width: 100%;
+ border: 4px solid #354457;
+ border-radius: 1em;
+}
+
+.sheet-force-power-levels input[type="number"],
+.sheet-force-power textarea {
+ border-radius: 0.5em;
+ padding: 0.5em;
+ margin-bottom: 0.25em;
+ font-size: 1em;
+}
+
+.sheet-force-power-name {
+ padding: 1em 0;
+ text-align: center;
+}
+
+.sheet-force-power-basic,
+.sheet-force-power-mastery{
+ padding: 1em 0;
+}
+
+.sheet-force-power-basic label::before {
+ content: '❖';
+ font-size: 1.25em;
+ padding-right: 0.25em;
+ color: #e2a160;
+}
+
+.sheet-force-power-mastery label::before {
+ content: '✬';
+ font-size: 1.25em;
+ padding-right: 0.25em;
+ color: #e2a160;
+}
+
+.sheet-force-power-basic label,
+.sheet-force-power-mastery label {
+ margin-bottom: 0.5em;
+ font-weight: bold;
+}
+
+.sheet-force-power-basic label + textarea,
+.sheet-force-power-mastery label + textarea {
+ min-height: 4em;
+ max-height: 7em;
+}
+
+/* Tooltips */
+
+.sheet-icon_help {
+ position: relative;
+ display: inline-block;
+}
+
+.sheet-icon_help .sheet-help_info,
+.sheet-icon_help .sheet-help_info_left {
+ display: none;
+ width: 20em;
+ background-color: rgba(0, 0, 0, 0.85);
+ color: #ffffff;
+ text-align: left;
+ padding: 1em;
+ border-radius: 0.5em;
+ position: absolute;
+ z-index: 1;
+}
+
+.sheet-icon_help .sheet-help_info {
+ top: 125%;
+ left: 50%;
+ margin-left: -10em;
+}
+
+.sheet-icon_help .sheet-help_info::after {
+ content: " ";
+ position: absolute;
+ bottom: 100%;
+ left: 50%;
+ margin-left: -0.25em;
+ border-width: 0.5em;
+ border-style: solid;
+ border-color: transparent transparent rgba(0, 0, 0, 0.85) transparent;
+}
+
+.sheet-icon_help .sheet-help_info_left {
+ top: 0;
+ right: 105%;
+}
+
+.sheet-icon_help .sheet-help_info_left::after {
+ content: " ";
+ position: absolute;
+ top: 5%;
+ left: 100%;
+ margin-left: -0.25em;
+ border-width: 0.5em;
+ border-style: solid;
+ border-color: transparent transparent transparent rgba(0, 0, 0, 0.85);
+}
+
+.sheet-icon_help:hover .sheet-help_info,
+.sheet-icon_help:hover .sheet-help_info_left {
+ display: block;
+}
+
+.sheet-icon_help::after {
+ font-family: 'Pictos';
+ content: '?';
+ color: #555555;
+ padding: 0.25em;
+}
+
+h2 .sheet-icon_help::after {
+ color: #cccccc;
+ font-size: 0.75em;
+}
+
+.sheet-stat_label .sheet-icon_help::after {
+ color: #aaaaaa;
+}
+
+.sheet-icon_active::after {
+ font-family: 'Pictos';
+ content: '9';
+ color: #781114;
+ padding-left: 0.25em;
+}
+
+.sheet-icon_passive::after {
+ font-family: 'Pictos';
+ content: 't';
+ color: #74cddd;
+ padding-left: 0.25em;
+}
+
+.sheet-icon_remove::after {
+ font-family: 'Pictos';
+ content: 'D';
+ color: #781114;
+ padding-left: 0.25em;
+ font-size: 1.25em;
+ cursor: pointer;
+}
+
+.sheet-help_info p {
+ margin-bottom: 1em;
+}
+
+
+/* GM Settings */
+
+
+input[name="attr_gmdicepool"][value="2"]:checked ~ .sheet-character_sheet .sheet-settings-gm {
+ display: block;
+}
+
+.sheet-settings_grid {
+ display: grid;
+ grid-template-columns: 1fr 2fr;
+ column-gap: 1em;
+ row-gap: 1em;
+ padding: 2em;
+ align-items: center;
+}
+
+.sheet-settings_grid input {
+ padding: 0.5em;
+ margin: 0;
+ font-size: 1.25em;
+ border-radius: 0.5em;
+}
+
+.sheet-settings_grid label {
+ text-align: right;
+}
+
+.sheet-settings_grid label::after {
+ content: ':';
+}
+
+/* Roll Template Formatting - Critical */
+
+.sheet-rolltemplate-critical table {
+ width: 100%;
+ border: 1px solid;
+ color: black;
+ font-size: 1em;
+ font-family: "Helvetica Neue", Helvetica, sans-serif;
+}
+
+.sheet-rolltemplate-critical th {
+ border-radius: 3px;
+ background-image: -webkit-linear-gradient(top, #ff0505, #000000);
+ background-image: -moz-linear-gradient(top, #ff0505, #000000);
+ background-image: -o-linear-gradient(top, #ff0505, #000000);
+ background-image: linear-gradient(to bottom, #ff0505, #000000);
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ color: #ffffff;
+ padding: 0.5em;
+ line-height: 1.6em;
+ font-size: 1.2em;
+}
+
+.sheet-rolltemplate-critical .sheet-subheader {
+ font-size: 0.8em;
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-critical .sheet-tcat-header {
+ background-image: -webkit-linear-gradient(top, #ff0505, #000000);
+ background-image: -moz-linear-gradient(top, #ff0505, #000000);
+ background-image: -o-linear-gradient(top, #ff0505, #000000);
+ background-image: linear-gradient(to bottom, #ff0505, #000000);
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ color: #ffffff;
+ padding: 0.5em;
+ line-height: 1.2em;
+ font-size: 0.8em;
+}
+
+.sheet-rolltemplate-critical td {
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-critical .sheet-tcat {
+ font-weight: bold;
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-critical .sheet-flavor {
+ font-style: italic;
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-critical tr:nth-child(odd) {
+ background-color: rgba(217, 217, 214, 1);
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-critical tr:nth-child(even) {
+ background-color: rgba(233, 233, 233, 1);
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-critical h4
+{
+ padding: 0 0.5em;
+}
+
+.sheet-rolltemplate-critical p
+{
+ padding: 0.5em;
+}
+
+/* End Roll Template Formatting - Critical */
+
+/* Roll Template Formatting */
+
+.sheet-rolltemplate-base{
+ font-size: 16px;
+}
+
+.sheet-rolltemplate-base table, .sheet-rolltemplate-suggestion table {
+ width: 100%;
+ border: 1px solid;
+ color: black;
+ font-size: 1em;
+ font-family: 'Nunito', sans-serif;
+}
+
+.sheet-rolltemplate-base th, .sheet-rolltemplate-suggestion th {
+ /* Starfield */
+ background-image: -webkit-linear-gradient(top, #485a6d, #2c3947);
+ background-image: -moz-linear-gradient(top, #485a6d, #2c3947);
+ background-image: -o-linear-gradient(top, #485a6d, #2c3947);
+ background-image: linear-gradient(to bottom, #485a6d, #2c3947);
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ color: #ffffff;
+ padding: 0.5em;
+ line-height: 1.6em;
+ font-size: 1.2em;
+}
+
+.sheet-rolltemplate-base .sheet-subheader, .sheet-rolltemplate-suggestion .sheet-subheader {
+ font-size: 0.8em;
+ padding-left: 2em;
+}
+
+.sheet-rolltemplate-base .sheet-tcat-header, .sheet-rolltemplate-suggestion .sheet-tcat-header {
+ /* Starfield */
+ background-image: -webkit-linear-gradient(top, #485a6d, #2c3947);
+ background-image: -moz-linear-gradient(top, #485a6d, #2c3947);
+ background-image: -o-linear-gradient(top, #485a6d, #2c3947);
+ background-image: linear-gradient(to bottom, #485a6d, #2c3947);
+ -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px rgba(255, 255, 255, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
+ color: #ffffff;
+ padding: 0.5em;
+ line-height: 1.2em;
+ font-size: 1em;
+}
+
+.sheet-rolltemplate-base td, .sheet-rolltemplate-suggestion td {
+ padding: 0.25em;
+}
+
+.sheet-rolltemplate-suggestion td {
+ width: 71px;
+}
+
+.sheet-rolltemplate-base .sheet-tcat, .sheet-rolltemplate-suggestion .sheet-tcat {
+ font-weight: bold;
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-base .sheet-flavor, .sheet-rolltemplate-suggestion .sheet-flavor {
+ font-style: italic;
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-base tr:nth-child(odd), .sheet-rolltemplate-suggestion tr:nth-child(odd) {
+ background-color: rgba(217, 217, 214, 1);
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-base tr:nth-child(even), .sheet-rolltemplate-suggestion tr:nth-child(even) {
+ background-color: rgba(233, 233, 233, 1);
+ padding: 0.5em;
+}
+
+.sheet-rolltemplate-base .sheet-dice_roll_icons {
+ padding: 0.5em;
+}
+
+/* End Roll Template Formatting - Base */
\ No newline at end of file
diff --git a/Star Wars FFG Alternate/Roll20_FFG_StarWars_CharacterSheet.html b/Star Wars FFG Alternate/Roll20_FFG_StarWars_CharacterSheet.html
new file mode 100644
index 0000000000..041d36a366
--- /dev/null
+++ b/Star Wars FFG Alternate/Roll20_FFG_StarWars_CharacterSheet.html
@@ -0,0 +1,3520 @@
+
+
+
+
+
+
+
+
Dice Pool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Upgrade :
+
+
+ : Downgrade
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Upgrade :
+
+
+ : Downgrade
+
+
+
+
+
+
+
Destiny Pool
+
+
+
+
+ Sync Pool with GM
+ Roll Destiny
+ Update Player Points
+ Clear Pool
+
+
+
+
+
+
Vital Stats
+
+
+
+
+
+
Defense
+
+
+
+
+ Ranged
+
+
+
+
+ Melee
+
+
+
+
+
+
+
Encumbrance
+
+
+
The Encumbrance threshold is calculated by Brawn + 5 + Container threshold.
+
The current Encumbrance takes into account weapons, armor, and other gear that have an Encumbrance stat set. If things get out of sync, just reset this field to match what it should be.
+
+
+
+
+
+
+
+ Threshold
+
+
+
+ Current
+
+
+
+
+
+
+
+
Name, Species, and Career
+
+
+
+
Character Name
+
+
Player Name
+
+
Species
+
+
+
+ Aleena
+ Anx
+ Aqualish (Aquala)
+ Aqualish (Quara)
+ Aqualish (Ualaq)
+ Arcona
+ Arkanian
+ Bardottan
+ Besalisk
+ Bothan
+ Caamasi
+ Cerean
+ Chadra-Fan
+ Chagrian
+ Chevin
+ Chiss
+ Clawdite
+ Clone
+ Corellian Human
+ Cosian
+ Dathomirian
+ Devaronian
+ Dowutin
+ Drall
+ Dressellian (Primitive)
+ Dressellian (Non-Primitive)
+ Droid
+ Dug
+ Duros
+ Elom
+ Elomin
+ Ewok
+ Falleen
+ Gand (With Lungs)
+ Gand (Without Lungs)
+ Gank
+ Geonosian
+ Gigoran
+ Gossam
+ Gotal
+ Gran
+ Gungan
+ Harch
+ Human
+ Hutt
+ Iakaru
+ Iktotchi
+ Ishi Tib
+ Ithorian
+ Jawa
+ Kalleran
+ Kaminoan
+ Karkarodon
+ Kel Dor
+ Klatooinian
+ Kubaz
+ Kyuzo
+ Lannik
+ Lasat
+ Mandalorian Human
+ Melitto
+ Mikkian
+ Mirialan
+ Mon Calamari
+ Mustafarian (Northern)
+ Mustafarian (Southern)
+ Muun
+ Nautolan
+ Neimodian
+ Nikto (Green)
+ Nikto (Mountain)
+ Nikto (Pale)
+ Nikto (Red)
+ Nikto (Southern)
+ Pantoran
+ Pau'an
+ Phydolon
+ Polis Massan (With Vocal Chords)
+ Polis Massan (Without Vocal Chords)
+ Quarren
+ Quermian
+ Rodian
+ Sakiyan
+ Sathari
+ Selonian
+ Shistavanen
+ Skakoans
+ Sullustan
+ Thisspiasian
+ Tholothian
+ Tognath
+ Togruta
+ Toydarian
+ Trandosian
+ Tusken Raider
+ Twi'lek
+ Umbaran
+ Verpine
+ Vurk
+ Weequay
+ Whiphid
+ Wookiee
+ Xexto
+ Zabrak
+
+
+
Career
+
+
+
+
+ Bounty Hunter
+ Colonist
+ Explorer
+ Hired Gun
+ Smuggler
+ Technican
+
+
+ Ace
+ Commander
+ Diplomat
+ Engineer
+ Soldier
+ Spy
+
+
+ Consular
+ Guardian
+ Mystic
+ Seeker
+ Sentinel
+ Warrior
+
+
+ Clone Soldier
+ Jedi
+
+
+ Universal
+
+
+
+
Specializations
+
+
+
+
+
+
+ Assassin
+ Gadgeteer
+ Martial Artist
+ Operator
+ Skip Tracer
+ Survivalist
+
+
+ Doctor
+ Politico
+ Scholar
+ Entrepreneur
+ Marshal
+ Performer
+
+
+ Scout
+ Fringer
+ Driver
+ Archaeologist
+ Big-Game Hunter
+ Trader
+
+
+ Bodyguard
+ Demolitionist
+ Enforcer
+ Heavy
+ Marauder
+ Mercenary Soldier
+
+
+ Pilot
+ Scoundrel
+ Thief
+ Charmer
+ Gambler
+ Gunslinger
+
+
+ Mechanic
+ Outlaw Tech
+ Slicer
+ Cyber Tech
+ Droid Tech
+ Modder
+
+
+
+ Driver
+ Pilot
+ Gunner
+ Rigger
+ Hotshot
+ Beast Rider
+
+
+ Commodore
+ Squadron Leader
+ Tactician
+ Figurehead
+ Instructor
+ Strategist
+
+
+ Ambassador
+ Agitator
+ Quartermaster
+ Analyst
+ Advocate
+ Propagandist
+
+
+ Droid Specialist
+ Mechanic
+ Saboteur
+ Sapper
+ Scientist
+ Shipwright
+
+
+ Medic
+ Sharpshooter
+ Commando
+ Heavy
+ Trailblazer
+ Vanguard
+
+
+ Courier
+ Infiltrator
+ Interrogator
+ Scout
+ Sleeper Agent
+ Slicer
+
+
+
+ Arbiter
+ Ascetic
+ Healer
+ Niman Disciple
+ Sage
+ Teacher
+
+
+ Armorer
+ Peace Keeper
+ Protector
+ Soresu Defender
+ Warden
+ Warleader
+
+
+ Advisor
+ Alchemist
+ Magus
+ Makashi Duelist
+ Prophet
+ Seer
+
+
+ Ataru Striker
+ Executioner
+ Hermit
+ Hunter
+ Navigator
+ Pathfinder
+
+
+ Artisan
+ Investigator
+ Racer
+ Sentry
+ Shadow
+ Shien Expert
+
+
+ Aggressor
+ Colossus
+ Juyo Berserker
+ Shii-Cho Knight
+ Starfighter Ace
+ Steel Hand Adept
+
+
+
+ Clone Trooper
+ Clone Pilot
+ Clone Officer
+ ARC Trooper
+ Clone Commander
+ Clone Veteran
+
+
+ Padawan
+ Knight
+ General
+ Master
+
+
+ Death Watch Warrior
+ Force Adherent
+ Force Sensitive Emergent
+ Force Sensitive Exile
+ Force Sensitive Outcast
+ Imperial Academy Cadet
+ Nightsister
+ Padawan Survivor
+ Pirate
+ Recruit
+ Republic Navy Officer
+ Republic Representative
+ Retired Clone Trooper
+ Scavenger
+ Senator
+ Separatist Commander
+ Ship Captain
+
+
+
+
+
+
+
XP and Credits
+
+
+
+
XP Total / Current
+
+
Credits
+
+
+
+
+
Obligation
+
+
+
+
+ Total Obligation
+
+
+
+
+
Type
+
Amount
+
Source
+
Notes
+
+
+
+
+
+
+
+
+
+
+
+
+
Duty
+
+
+
+
+ Contribution Rank
+
+
+
+
Type
+
Amount
+
Notes
+
+
+
+
+
+
+
+
+
+
+
+
+
Notes
+
+
+
+
+
+
+
+
Characteristics
+
+
+
+
Skills
+
+
+
+
+
General Skills
+
+
Skill
+
Characteristic
+
Career
+
Ranks
+
Dice
+
Modifiers
+
Roll
+
+
+
Astrogation
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Athletics
+
(Bra )
+
+
+
+
+
+
+
+
+
+
+
+
+
Charm
+
(Pr )
+
+
+
+
+
+
+
+
+
+
+
+
+
Coercion
+
(Wil )
+
+
+
+
+
+
+
+
+
+
+
+
+
Computers
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Cool
+
(Pr )
+
+
+
+
+
+
+
+
+
+
+
+
+
Coordination
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
Deception
+
(Cun )
+
+
+
+
+
+
+
+
+
+
+
+
+
Discipline
+
(Wil )
+
+
+
+
+
+
+
+
+
+
+
+
+
Leadership
+
(Pr )
+
+
+
+
+
+
+
+
+
+
+
+
+
Mechanics
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Medicine
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Negotiation
+
(Pr )
+
+
+
+
+
+
+
+
+
+
+
+
+
Perception
+
(Cun )
+
+
+
+
+
+
+
+
+
+
+
+
+
Piloting - Planetary
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
Piloting - Space
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
Resilience
+
(Bra )
+
+
+
+
+
+
+
+
+
+
+
+
+
Skullduggery
+
(Cun )
+
+
+
+
+
+
+
+
+
+
+
+
+
Stealth
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
Streetwise
+
(Cun )
+
+
+
+
+
+
+
+
+
+
+
+
+
Survival
+
(Cun )
+
+
+
+
+
+
+
+
+
+
+
+
+
Vigilance
+
(Wil )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Combat Skills
+
+
Skill
+
Characteristic
+
Career
+
Ranks
+
Dice
+
Modifiers
+
Roll
+
+
+
Brawl
+
(Bra )
+
+
+
+
+
+
+
+
+
+
+
+
+
Melee
+
(Bra )
+
+
+
+
+
+
+
+
+
+
+
+
+
Gunnery
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
Lightsaber
+
+
+ Brawn
+ Agility
+ Intellect
+ Cunning
+ Willpower
+ Presence
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Ranged - Light
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
Ranged - Heavy
+
(Ag )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Knowledge Skills
+
+
Skill
+
Characteristic
+
Career
+
Ranks
+
Dice
+
Modifiers
+
Roll
+
+
+
Core Worlds
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Education
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Lore
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Outer Rim
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Underworld
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Warfare
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
Xenology
+
(Int )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Initiative
+
+
+
+
+
Cool (if prepared)
+
(Pr )
+
+
+
+
+
+
+
+
+
+
+
Vigilance (if unexpected)
+
(Wil )
+
+
+
+
+
+
+
+
+
+
+
+
+
Criticals
+
+
+
+
Roll a Critical (for any target)
+
+ Critical Bonus
+
+
+ Roll Critical
+
+
Your Current Critical Injuries
+
+
+
+
+
+
+
+
+ Crit Roll
+
+ 1 - 5
+ 6 - 10
+ 11 - 15
+ 16 - 20
+ 21 - 25
+ 26 - 30
+ 31 - 35
+ 36 - 40
+
+
+ 41 - 45
+ 46 - 50
+ 51 - 55
+ 56 - 60
+ 61 - 65
+ 66 - 70
+ 71 - 75
+ 76 - 80
+ 81 - 85
+ 86 - 90
+
+
+ 91 - 95
+ 96 - 100
+ 101 - 105
+ 106 - 110
+ 111 - 115
+ 116 - 120
+ 121 - 125
+
+
+ 126 - 130
+ 131 - 140
+ 141 - 150
+
+
+ 151+
+
+
+
+
+
+
Heal this wound
+
+
+
+
+
+
Weapons
+
+
+
+
+
+
Make/Model
+
+
+
Make-Model
+
+
Carried?
+
+
+
+
+
Check this box if the character is currently carrying this weapon. Carried weapons count toward total encumbrance.
+
+
+
+
Skill
+
+
+
+ Brawl
+ Melee
+ Gunnery
+ Ranged - Light
+ Ranged - Heavy
+ Lightsaber
+
+
+ Mechanics
+ Medicine
+ Resilience
+
+
+
+
+
+
+
+
+
+
+
+
Range
+
+
+ Engaged
+ Short
+ Medium
+ Long
+ Extreme
+
+
+
Condition
+
+
+ Undamaged
+ Minor
+ Moderate
+ Major
+ Destroyed
+
+
+
Critical Bonus
+
+
+
+
+
from Other
+
+
+
Include a critical bonus for this weapon from a source other than Vicious, such as a weapon attachment/mod or a talent. It is added to a roll when activating a critical injury with this weapon.
+
+
+
+
+
+
+
+
+
+
from Vicious
+
+
+
This shows the critical bonus added to the weapon due to a Vicious quality. It is automatically added to a roll when activating a critical injury with this weapon.
+
+
+
+
+
+
+
Damage Bonus
+
+
+
+
+
from Other
+
+
+
Include a damage bonus for this weapon from a source other than Superior or Inferior, such as a weapon attachment/mod or a talent. It is added to a roll when calculating damage with this weapon.
+
+
+
+
+
+
+
+
+
+
from Superior
+
+
+
This shows the damage bonus added to the weapon due to a Superior quality. It is automatically added to a roll when calculating damage with this weapon.
+
+
+
+
+
+
+
-
+
+
from Inferior
+
+
+
This shows the damage subtracted from the weapon due to an Inferior quality. It is automatically subtracted from a roll when calculating damage with this weapon.
+
+
+
+
+
+
+
Weapon Qualities
+
+
+
+
+
+
+
+
+
+
+
+
Accurate
+
+
+
Accurate weapons are easier to aim or wield, whether through design or technology. For each level of this trait, the attacker adds 1 blue to their attack dice pools while using this weapon.
+
+
+
+
+
Auto-Fire
+
+
+
A weapon with Auto-fire can be set to shoot in rapid succession and potentially spray an area with bolts, flechettes, slugs, or other types of projectiles. The advantage in using Auto-fire is that it has the chance to hit multiple targets or hit a single target multiple times.
+
Attacking with a weapon on Auto-fire is generally less accurate, and the attacker must increase the difficulty of the attack check by 1 purple die. The user may choose to not use the Auto-fire quality on a weapon; in this case, they cannot trigger the quality but also does not suffer the aforementioned penalty.
+
If the attack hits, the attacker can trigger Auto-fire by spending 2 Advantages Auto-fire can be triggered multiple times. Each time the attacker triggers Autofire, it deals an additional hit to the target. Each of these counts as an additional hit from that weapon, and each hit deals base damage plus the number of uncanceled success on the check.
+
These additional hits can be allocated to the target, or to other targets within range of the weapon. If the attacker wishes to hit multiple targets, they must decide to do so before making the check. Furthermore, if they wish to hit multiple targets, their initial target must always be the target with the highest difficulty and highest defense (if this is two separate targets, the GM chooses which target is the initial target). The initial hit must always be against the initial target. Subsequent hits generated can be allocated to any of the other designated targets.
+
Auto-fire weapons can also activate one Critical Injury for each hit generated on the attack per the normal cost; the Critical must target the target of the specific hit.
+
+
+
+
+
+ No
+ Yes
+
+
+
Blast
+
+
+
The weapon has a large spread, an explosive blast, or similar area of effect, like the detonation of a grenade or a warhead fired from a missile launcher. If the attack is successful and Blast activates, each character (friend or foe) engaged with the original target suffers damage equal to the weapon's Blast rating (plus an additional wound per success as usual).
+
In a relatively small and enclosed area, the Game Master might decide that everyone in the room suffers damage.
+
If the Blast quality doesn't activate, the ordnance still detonates, but bad luck or poor aim on the part of the firer (or quick reactions on the part of the victims) means the explosion may not catch anyone else in its radius. However, the user may also trigger Blast if the attack misses by spending 3 advantages. In this case, the original target and every target engaged with the original target suffers damage equal to the Blast rating of the weapon.
+
+
+
+
+
Breach
+
+
+
Weapons with Breach burn through the toughest armor, and are often heavy weapons or starship weapons.
+
Breach weapons ignore one point of armor for every rating of Breach (meaning they also ignore 10 points of soak for every rating of Breach).
+
+
+
+
+
Burn
+
+
+
Weapons with Burn inflict damage over time. If the attack is successful, the target continues to suffer the weapon's base damage each round for a number of rounds equal to the weapon's Burn rating. Damage is applied at the start of each of the target's turns.
+
A victim might be able to stop the damage by rolling around on the ground and making an Agility check as an action. This is an Average (2 purple dice) Coordination check on hard surfaces such as the hall of a spaceship, or an Easy (1 purple die) Coordination check on grass or soft ground. Jumping into a body of water stops the damage immediately. Both situations assume the flame is from actual combustion rather than a chemical reaction. With the latter, there is usually little the victim can do.
+
+
+
+
+
Concussive
+
+
+
The weapon's attack can leave the target shell-shocked from mighty blows or punishing Shockwaves, unable to perform any but the most basic actions. The target is staggered for a number of rounds equal to the weapon's Concussive rating. A staggered target cannot perform actions.
+
+
+
+
+
Cortosis
+
+
+
Cortosis is an ore principally found in the Outer Rim. It is extremely rare and valuable, and was used primarily during the Clone Wars against the Jedi Knights. There are two varieties of Cortosis ore. The rarest versions can actually short out a lightsaber's blade, causing it to fail temporarily. The far more common Cortosis ore is still a miraculous substance, because when molded into armor, it forms an interlocking molecular bond that is extremely resistant to energy weapons.
+
Weapons with the Cortosis quality are immune to the Sunder quality. Armor with the Cortosis quality makes the wearer's soak immune to the Pierce and Breach qualities.
+
+
+
+
+
+ No
+ Yes
+
+
+
Cumbersome
+
+
+
A Cumbersome weapon is large, unwieldy, awkward, or heavy. To wield a Cumbersome weapon properly, the character needs a Brawn characteristic equal to or greater than the weapon's Cumbersome rating. For each point of Brawn by which the character is deficient, they must increase the difficulty of all checks made while using the weapon by one.
+
+
+
+
+
+
Defensive
+
+
+
Defensive weapons are particularly good at fending off incoming melee attacks. A character wielding a weapon with the Defensive quality increases their melee defense by the weapon's Defensive rating.
+
+
+
+
+
Deflection
+
+
+
An item with the Deflection quality increases the wearer's ranged defense equal to its Deflection rating.
+
+
+
+
+
Disorient
+
+
+
A weapon with Disorient can daze an opponent. When Disorient is triggered, the target is disoriented for a number of rounds equal to the weapon's Disorient rating. (A disoriented target adds 1 black die to all skill checks they perform.)
+
+
+
+
+
Ensnare
+
+
+
A weapon with Ensnare binds a foe and restricts their movements. When Ensnare is triggered, the target is immobilized for a number of rounds equal to the weapon's Ensnare rating. An Ensnared target may attempt a Hard (3 purple dice) Athletics check as their action on their turn to break free from the effect. (An immobilized target cannot perform maneuvers.)
+
+
+
+
+
Guided
+
+
+
Certain types of projectiles, such as guided missiles, may benefit from course alterations after being fired. If a character misses while firing a Guided weapon and if Guided is activated, they may make an attack check at the end of the round. The difficulty of the check is calculated by comparing the weapon's silhouette of 0 to the silhouette of the target, and the check's green die equal the weapon's Guided rating. If the test is successful, the weapon strikes the target, and damage is dealt normally.
+
Guided requires 3 advantages to activate, unless otherwise specified in the weapon's description. Remember, the Guided effect can activate on its subsequent attacks, representing the projectile continuing to track the target.
+
"Spoofing" is a countermeasure designed to work against a particular type of projectile, such as flares designed to draw off infrared missiles. Spoofing directly increases the defense of the target against attacks with the Guided quality.
+
+
+
+
+
Knockdown
+
+
+
When knockdown triggers, the target is knocked prone. Unless specified otherwise, Knockdown requires 2 advantages to trigger, plus one additional advantage per silhouette of the target beyond one.
+
+
+
+
+
+ No
+ Yes
+
+
+
Inaccurate
+
+
+
Inaccurate weapons are weapons of a shoddy or inferior construction, which means they are less likely to be accurate or precise. Alternatively, the weapon's nature may inhibit accuracy. Inaccurate weapons add 1 black die to the attacker's dice pool equal to their Inaccurate rating.
+
+
+
+
+
Inferior
+
+
+
An Inferior item is a lackluster example of its kind, representing shoddy and poor craftsmanship. An Inferior weapon generates automatic 1 threat on all checks related to its use, and has its base damage decreased by one. Inferior armor has its encumbrance increased by one and its defense decreased by one. If it does not have defense, decrease its soak value by one, to a minimum of zero.
+
+
+
+
+
+
+ No
+ Yes
+
+
+
Ion
+
+
+
Ion weapons are designed to affect electrical systems instead of dealing raw damage. They are fitted to ships to knock out opponents' shields, sensors, and engines. They are shorter range than laser weapons and deal larger amounts of damage, but their damage is dealt to the target (usually a vehicle) as system strain. The damage is still reduced by armor and soak. Droids are affected by ion weapons, taking damage to their strain threshold.
+
+
+
+
+
+ No
+ Yes
+
+
+
Limited Ammo
+
+
+
Some weapons fire particularly large or complex projectiles that cost significant numbers of credits or are themselves a complete weapon that, once launched, is expended. A weapon with the Limited Ammo quality may be used to make a number of attacks equal to its Limited Ammo rating before it must be reloaded with a maneuver. In addition, each shot expends one of a limited number of rounds of ammo, which, once used, must be purchased or otherwise obtained before firing the weapon again. This also applies to grenades and other "one use" weapons that have the Limited Ammo 1 quality (here, the user is not "reloading" the grenade, but drawing another to use—but mechanically they are equivalent).
+
+
+
+
+
Linked
+
+
+
Some weapons, like the laser cannons fitted to the X-wing, are designed to fire together at the same target. This increases the possibility of a hit as well as the damage dealt. When firing a linked weapon, on a successful attack, the weapon deals one hit. The wielder may spend 2 advantages to gain an additional hit, and may do so a number of times equal to the weapon's Linked rating. Additional hits from the Linked weapon being used may only be applied against the original target. Each hit deals the weapon's base damage plus the total uncanceled successes scored on the check.
+
+
+
+
+
+ No
+ Yes
+
+
+
Pierce
+
+
+
An attack made with this weapon ignores one point of soak for each rank of Pierce. If the weapon has more ranks of Pierce than the target's total soak, it completely ignores the target's soak. For example. Pierce 3 against a soak of 2 ignores 2 points of soak, but the extra "point" of Pierce has no further effect.
+
+
+
+
+
Prepare
+
+
+
Weapons with this quality require time to set up before being used. The user must perform a number of preparation maneuvers equal to the weapon's Prepare rating before making attacks with that weapon.
+
+
+
+
+
Slow-Firing
+
+
+
Slow-Firing weapons tend to be large, heavy, emplacement-mounted weapons like the turbolasers found on capital ships or planetary defense ion cannons. While they deal incredible damage, they need time to recharge or cool down between shots. A weapon's Slow-Firing rating dictates how quickly the weapon can be fired after an attack. For example, a heavy turbolaser with Slow-Firing 2 must wait two rounds after being fired before it can be fired again.
+
+
+
+
+
Stun
+
+
+
Some weapons deal Stun damage instead of regular damage. In this case, the weapon deals damage as strain instead of wounds. This damage is still reduced by a target's soak.
+
A variant of this is a Stun setting. As an incidental, the wielder can choose to switch the setting of their weapon to "Stun." In this case, it does Stun damage as described above. When weapons with a Stun setting are used to deal Stun damage, their range changes to short and cannot be increased.
+
+
+
+
+
+ No
+ Yes
+
+
+
Sunder
+
+
+
When activated, the attacker chooses one item openly wielded by the target (such as a weapon, shield, or item on a belt). That item is damaged one step: to minor if undamaged, from minor to moderate, or from moderate to major. If a weapon already suffering major damage is the target of a successful Sunder, it is destroyed.
+
Sunder requires 1 advantage to activate. If activated multiple times in the same attack, each activation can be applied against the same weapon, potentially taking a weapon from undamaged to destroyed in a single attack.
+
+
+
+
+
+ No
+ Yes
+
+
+
Superior
+
+
+
A Superior item is a sterling example of its kind, representing masterful craftsmanship. A Superior weapon generates automatic 1 advantage on all checks related to its use, and has its base damage increased by one. Superior armor has its encumbrance reduced by one and its soak value increased by one.
+
+
+
+
+
+
+ No
+ Yes
+
+
+
Unwieldy
+
+
+
An Unwieldy weapon is large, awkward, or heavy. To wield an Unwieldy weapon properly, the character needs an Agility characteristic equal to or greater than the weapon's Unwieldy rating. For each point of Agility by which the character is deficient, they must increase the difficulty of all checks made while using the weapon by one.
+
+
+
+
+
+
Vicious
+
+
+
When this weapon scores a Critical Injury or Hit, the character adds ten times the Vicious rating to the Critical roll. With Vicious 3, for example, the victim adds + 30 to their Critical Hit result.
+
+
+
+
+
+
+ Attachments / Mods
+
+
+
+
The total hard points for attachments has exceeded the weapon's available hard points.
+
+
+
+
+ Notes
+
+
+
+
+
+
+
+
+
+
+
+
+
Combat Talents
+
+
+
+
+
Name
+
Ranks
+
Active?
+
Description
+
+
+
+
+
+
+
+
Armor
+
+
+
+
+
Name
+
Ranged
+
+
+
This bonus is automatically added to the character's total Defense - Ranged value.
+
+
+
+
Melee
+
+
+
This bonus is automatically added to the character's total Defense - Melee value.
+
+
+
+
Soak
+
+
+
This bonus is automatically added to the character's total Soak value.
+
+
+
+
Encum
+
+
+
This bonus is automatically added to the character's current Encumbrance value.
+
+
+
+
HP
+
+
+
The current amount of hard points available for this armor. Automatically lowered for each attachment.
+
+
+
+
Quality
+
+
+
Quality of the armor affects the Defense, Encumbrance, and possibly Soak values.
+
Make sure the Defense, Encumbrance, and Soak values are set on Normal quality before selecting Superior or Inferior.
+
Superior armor has its encumbrance reduced by one and its soak value increased by one.
+
Inferior armor has its encumbrance increased by one and its defense decreased by one. If it does not have defense, decrease its soak value by one, to a minimum of zero.
+
+
+
+
+
+
+
+
+
+
+
+
Gear
+
+
+
+
+
Name
+
Encum
+
+
Carried?
+
+
+
Check this box if the character is currently carrying this item. Carried items count toward total encumbrance.
+
+
+
+
Description
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Containers
+
+
+
Gear that adds Encumbrance threshold - backpacks, utility belts, etc.
+
+
+
+
+
+
+
+
+
+
+
+
+
Cybernetics
+
+
+
The number of cybernetic enhancements is limited to your Brawn rating, or 6 for Droids.
+
+
+
+
+
+
+
+
+
+
+
Non-combat Talents
+
+
+
+
+
Name
+
Ranks
+
Active?
+
Description
+
+
+
+
+
+
Signature Abilities
+
+
+
+
+
+
+
+
+
+
Force Powers
+
+
+
+
+ Force Rating
+
+
+
+
+
+
+
+
+
+ Alter
+ Battle Meditation
+ Bind
+ Conjure
+ Ebb / Flow
+ Endure
+ Enhance
+ Farsight
+ Foresee
+ Heal / Harm
+ Imbue
+ Influence
+ Manipulate
+ Misdirect
+ Move
+ Protect / Unleash
+ Seek
+ Sense
+ Supress
+ Warde's Foresight
+
+
+
+ Roll
+
+
+
+ Basic
+
+
+
+
+ Mastery
+
+
+
+
+
+
+
+
+
General Settings
+
+ Change font size / zoom
+
+
+
+
+
+
+
Roll Result Suggestions
+
+
Setting
+
Option
+
Skill Suggestions Display
+
+
+ None
+ Whisper GM
+ Show Suggestions Button
+ Display in Skill
+
+
+
Enable Combat Suggestions?
+
+
+ No
+ Yes
+
+
+
Enable General Suggestions?
+
+
+ No
+ Yes
+
+
+
Fear Check?
+
+
+ No
+ Yes
+
+
+
+
+
+
+
+
+
+ {{title}} {{#subtitle}} {{/subtitle}}
+ {{#flavor}}
+ {{flavor}}
+ {{/flavor}}
+ {{#prewide}}
+ {{prewide}}
+ {{/prewide}}
+ {{#header}}
+
+ {{/header}}
+ {{#allprops() title flavor wide roll results subtitle header item prewide wide2 wide3 wide4 wide5}}
+ {{key}} {{value}}
+ {{/allprops() title flavor wide roll results subtitle header item prewide wide2 wide3 wide4 wide5}}
+ {{#wide}}
+ {{wide}}
+ {{/wide}}
+ {{#wide2}}
+ {{wide2}}
+ {{/wide2}}
+ {{#wide3}}
+ {{wide3}}
+ {{/wide3}}
+ {{#wide4}}
+ {{wide4}}
+ {{/wide4}}
+ {{#wide5}}
+ {{wide5}}
+ {{/wide5}}
+ {{#roll}}
+ Dice Roll
+ {{roll}}
+ {{/roll}}
+ {{#results}}
+ Results
+ {{results}}
+ {{/results}}
+
+
+
+
+
+ {{title}} {{#subtitle}} {{/subtitle}}
+ {{#flavor}}
+ {{flavor}}
+ {{/flavor}}
+ {{#prewide}}
+ {{prewide}}
+ {{/prewide}}
+ {{#header}}
+
+ {{/header}}
+ {{#allprops() title flavor wide roll results subtitle header item prewide wide2 wide3 wide4 wide5}}
+ {{key}} {{value}}
+ {{/allprops() title flavor wide roll results subtitle header item prewide wide2 wide3 wide4 wide5}}
+ {{#wide}}
+ {{wide}}
+ {{/wide}}
+ {{#wide2}}
+ {{wide2}}
+ {{/wide2}}
+ {{#wide3}}
+ {{wide3}}
+ {{/wide3}}
+ {{#wide4}}
+ {{wide4}}
+ {{/wide4}}
+ {{#wide5}}
+ {{wide5}}
+ {{/wide5}}
+ {{#roll}}
+ Dice Roll
+ {{roll}}
+ {{/roll}}
+ {{#results}}
+ Results
+ {{results}}
+ {{/results}}
+
+
+
+
+
+ {{title}} {{#subtitle}} {{/subtitle}}
+ {{#flavor}}
+ {{flavor}}
+ {{/flavor}}
+ {{#prewide}}
+ {{prewide}}
+ {{/prewide}}
+ {{#header}}
+
+ {{/header}}
+ {{#allprops() title flavor roll results subtitle header item suggestionsExist success advantage triumph failure threat despair 1advantage1triumph 2advantage1triumph 3advantage1triumph 1triumph 2triumph 1threat1despair 2threat1despair 3threat1despair 1despair 2despair}}
+ {{key}} {{value}}
+ {{/allprops() title flavor roll results subtitle header item suggestionsExist success advantage triumph failure threat despair 1advantage1triumph 2advantage1triumph 3advantage1triumph 1triumph 2triumph 1threat1despair 2threat1despair 3threat1despair 1despair 2despair}}
+ {{#wide}}
+ {{wide}}
+ {{/wide}}
+ {{#wide2}}
+ {{wide2}}
+ {{/wide2}}
+ {{#wide3}}
+ {{wide3}}
+ {{/wide3}}
+ {{#wide4}}
+ {{wide4}}
+ {{/wide4}}
+ {{#wide5}}
+ {{wide5}}
+ {{/wide5}}
+ {{#roll}}
+ Dice Roll
+ {{roll}}
+ {{/roll}}
+ {{#results}}
+ Results
+ {{results}}
+ {{/results}}
+ {{#suggestionsExist}}
+ Spending Suggestions
+ {{/suggestionsExist}}
+ {{#success}}
+ Success {{success}}
+ {{/success}}
+ {{#advantage}}
+ Advantage {{advantage}}
+ {{/advantage}}
+ {{#triumph}}
+ Triumph {{triumph}}
+ {{/triumph}}
+ {{#failure}}
+ Failure {{failure}}
+ {{/failure}}
+ {{#threat}}
+ Threat {{threat}}
+ {{/threat}}
+ {{#despair}}
+ Despair {{despair}}
+ {{/despair}}
+ {{#1advantage1triumph}}
+ or {{1advantage1triumph}}
+ {{/1advantage1triumph}}
+ {{#2advantage1triumph}}
+ or {{2advantage1triumph}}
+ {{/2advantage1triumph}}
+ {{#3advantage1triumph}}
+ or {{3advantage1triumph}}
+ {{/3advantage1triumph}}
+ {{#1triumph}}
+ {{1triumph}}
+ {{/1triumph}}
+ {{#2triumph}}
+ {{2triumph}}
+ {{/2triumph}}
+ {{#1threat1despair}}
+ or {{1threat1despair}}
+ {{/1threat1despair}}
+ {{#2threat1despair}}
+ or {{2threat1despair}}
+ {{/2threat1despair}}
+ {{#3threat1despair}}
+ or {{3threat1despair}}
+ {{/3threat1despair}}
+ {{#1despair}}
+ {{1despair}}
+ {{/1despair}}
+ {{#2despair}}
+ {{2despair}}
+ {{/2despair}}
+
+
+
+
+
+
+
+
+
+
diff --git a/Star Wars FFG Alternate/diceroller.js b/Star Wars FFG Alternate/diceroller.js
new file mode 100644
index 0000000000..3a6d534e0a
--- /dev/null
+++ b/Star Wars FFG Alternate/diceroller.js
@@ -0,0 +1,4784 @@
+/*
+ Current Version: 6.3.1
+ Last updated: 04.06.2020
+ Character Sheet and Script Maintained by: Samuel T.
+ Older Verions: https://github.com/dayst/StarWarsEdgeOfTheEmpire_Dice
+
+ 6.3.1: Added rollRandomCritical
+
+ Credits:
+ Original creator: Konrad J.
+ Helped with Dice specs: Alicia G. and Blake the Lake
+ Dice graphics hosted by Alicia G. at galacticcampaigns.com
+ Dice graphics borrowed from the awesome google+ hangouts EotE Dice App
+ Basic Character Sheet and Advanced Dice Roller: Steve Day
+ GM Sheet Campaign Details design inspiration: www.reddit.com/user/JohnSquiggleton
+ Sheet Autocreator: www.reddit.com/user/lowdownfool
+ New Tab Labels: Steve D., GM Knowledge Rhino, and Loki
+ Skill Description by: Gribble - https://dl.dropboxusercontent.com/u/9077657/SW-EotE-Reference-Sheets.pdf
+ Critical Descriptions by: Gribble - https://dl.dropboxusercontent.com/u/9077657/SW-EotE-Reference-Sheets.pdf
+ Debugger: Arron
+ Basic Roll Templates for basic rolls: Josh A.
+ Initiative Roller: Andrew H.
+ Opposed Roller: Tom F.
+ Method to hide depreciated Vehicle Tabs: Phil B.
+ Work done by GM Knowledge Rhino:
+ Group Tab
+ Companion Tab
+ GM Resources
+ Redesign of Vehicle Tab
+ Riding Beast Display
+ Roll Template Code Fixes
+ Roll Templates integrated with all Rolls
+ Overencumbrance roll notification
+ Work done by Samuel T.:
+ Versions 4.0.10.0 - 6.3.0 b5
+ SuggestionEngine
+ NPC Sheet
+ Initiative fix
+ Label generation fix
+ Semantic Versioning
+ Consolidated the Dice Ppol and Destiny Sections
+ Collapsing sections
+ Optgroups for dropdowns
+
+ API Chat Commands
+ Settings:
+ Log
+ * default: 'on' and 'single'
+ * Description: Sets the visual output in the chat window for the dice rolls
+ * Command: !eed log on|off|multi|single
+
+ Graphics
+ * default: 'on' and 'm'
+ * Description: Sets chat window dice output as graphic, small, medium, or large if "on" or as text if "off"
+ * Command: !eed graphics on|off|s|m|l
+
+ Test
+ * Description: Output every side of every die to the chat window
+ * !eed test
+
+ Debug
+ * default: 'off'
+ * DescriptionL Sets the logging level of the script in the API console. If you are having issues with the
+ * script rolling incorrect dice, turn on debug logging and post the result in the forums. No need to restart the
+ * script with this command.
+ * Command: !eed debug on|off
+
+ GM Sheet Settings:
+ SuggestionDisplay
+ * Description: Sets the state of the skill_suggestion_setting_display status on the DicePool
+ * Command: !eed suggestionDisplay none|whisper|always
+
+ Fear
+ * Description: Sets the state of the Fear check status on the DicePool
+ * Command: !eed fear on|off
+
+ Roll:
+ Label
+ * default: null
+ * Description: set the skill name of the roll
+ * Command: !eed label(Name of Skill)
+
+ Initiative
+ * default: false
+ * Description: Set NPC/PC initiative true
+ * Command: !eed npcinit or pcinit and #b #g #y #blk #p #r #w
+
+ Skill
+ * default:
+ * Description: create the ability and proficiency dice for a skill check
+ * Command: !eed skill(char_value|skill_value)
+
+ Opposed
+ * default:
+ * Description: create the difficulty and challenge dice for an opposed skill check
+ * Command: !eed opposed(char_value|skill_value|[NPC minion group size]|[Is skill a minion skill])
+
+ Dice
+ * default:
+ * Description: Loop thru the dice and adds or subtracts them from the dice object
+ * Command: !eed #g #y #b #blk #r #p #w #s #a
+
+ Upgrade
+ * default:
+ * Description: upgrades ability and difficulty dice
+ * Command: !eed upgrade(ability|#) or upgrade(difficulty|#)
+
+ Downgrade
+ * default:
+ * Description: downgrades proficiency and challenge dice
+ * Command: !eed downgrade(proficiency|#) or downgrade(challenge|#)
+
+ Destiny
+ * default:
+ * Description: Rolls 1w die and adds the result to the destiny pool
+ * Command: !eed #w destiny doRoll
+
+ Other:
+ Charsheet
+ * default:
+ * Description: Generates a blank character sheet and automatically makes it viewable and editable by the person calling the script.
+ * Command: !charsheet
+ */
+
+/* Define functions that may not always exist */
+if(!log) {
+ log = function(input) {
+ console.log(input);
+ }
+}
+
+if (!sendChat) {
+ sendChat = function (sender, msg) {
+ log(sender + " says " + msg);
+ }
+}
+/* End special function definitions*/
+
+
+/* Begin Sheet Character Sheet Auto Creator */
+var Charsheet = Charsheet || {};
+
+on('chat:message', function (msg) {
+ // Exit if not an api command
+ if (msg.type != "api") {
+ return;
+ }
+ if (msg.content.indexOf('!charsheet') != -1) {
+ Charsheet.Generate(msg);
+ }
+});
+
+Charsheet.Generate = function (msg) {
+ var player = msg.who;
+ var character_name = msg.who + Date.now();
+
+ var character = createObj('character', {
+ name: character_name,
+ inplayerjournals: msg.playerid,
+ controlledby: msg.playerid
+ });
+ /* Create attributes */
+ createObj('attribute', {
+ name: 'player_name',
+ current: player,
+ _characterid: character.id
+ });
+ createObj('attribute', {
+ name: 'name',
+ current: character_name,
+ _characterid: character.id
+ });
+ sendChat("Dice System", "/w " + msg.who + " a blank character sheet was created for you named \"" + character_name);
+ sendChat("GM", "/w " + "gm " + "A blank character sheet was created for " + msg.who);
+};
+
+if (!Date.now) {
+ Date.now = function now() {
+ return new Date().getTime();
+ };
+}
+/* End Sheet Character Sheet Auto Creator */
+
+function SuggestionEngine () {
+ var that = this;
+
+ var flags = {
+ displayOption: null,
+ generalSuggesting: true,
+ combatSuggesting: true,
+ combatType: null,
+ isFearCheck: false
+ };
+
+ function convertToBoolean (value) {
+ // will trap the following properly: false, true, "false", "true", 0, 1, "", and undefined
+ //noinspection RedundantConditionalExpressionJS
+ return !value || value == 1 || value === 'true';
+ }
+
+ this.suggestions = {
+ special: {
+ fear: {
+ allowedSkills: [
+ "Cool",
+ "Discipline"
+ ],
+ success: [
+ {
+ text: "The character avoids any fear effects, except those triggered by threats",
+ required: 1
+ }
+ ],
+ advantage: [
+ {text: "Gain $BOOST$ on the character's first check.", required: 1},
+ {
+ text: "If spending multiple $ADVANTAGE$, grant $BOOST$ to an additional player's first check.",
+ required: 2
+ }
+ ],
+ triumph: [
+ {
+ text: "Can be spent to cancel all previous penalties from fear checks, or",
+ required: 1
+ },
+ {
+ text: "Spent to ensure the character need not make any additional fear checks during the encounter, no matter the source.",
+ required: 1
+ }
+ ],
+ failure: [
+ {
+ text: "The character adds $SETBACK$ to each action he takes during the encounter.",
+ required: 1
+ }
+ ],
+ threat: [
+ {
+ text: "The character suffers a number of strain equal to the number of $FAILURE$.",
+ required: 1
+ },
+ {
+ text: "If the check generates $THREAT$$THREAT$$THREAT$+, the character can be staggered for his first turn, instead.",
+ required: 3
+ }
+ ],
+ despair: [
+ {
+ text: "The character is incredibly frightened and increases the difficulty of all checks until the end of the encounter by one.",
+ required: 1
+ }
+ ]
+ }
+ },
+ general: {
+ Astrogation: {
+ success: [
+ {
+ text: "Better target for the destination, e.g.: place vessel directly into orbit around target planet.",
+ required: 1
+ },
+ {text: "Reduce time spent calculating.", required: 1}
+ ],
+ advantage: [
+ {text: "Reduce travel time.", required: 1},
+ {text: "Identify convenient stopovers to resupply or conduct additional business.", required: 1}
+ ],
+ triumph: [
+ {text: "Complete calculations in minimum time.", required: 1},
+ {text: "Greatly reduce travel time.", required: 1},
+ {text: "Reveal highly valuable but previously unknown information.", required: 1}
+ ],
+ threat: [
+ {text: "Decrease accuracy of hyperspace jump.", required: 1},
+ {text: "Increase travel time.", required: 1},
+ {text: "Miss relevant details when analyzing hyperspace routes or galactic maps.", required: 1}
+ ],
+ despair: [
+ {text: "Greatly decrease accuracy of hyperspace jump.", required: 1},
+ {text: "Greatly increase travel time.", required: 1},
+ {
+ text: "Miss large amounts of relevant details when analyzing hyperspace routes or galactic maps.",
+ required: 1
+ },
+ {
+ text: "Trigger something truly awful happening, such as jumping out of hyperspace in the path of an asteroid.",
+ required: 1
+ }
+ ]
+ },
+ Athletics: {
+ success: [
+ {text: "Reduce time required.", required: 1},
+ {text: "Increase distance travelled.", required: 1}
+ ],
+ advantage: [
+ {
+ text: "Generate bonus on other physical checks performed later or by allies that turn.",
+ required: 1
+ },
+ {
+ text: "Spend $ADVANTAGE$$ADVANTAGE$ to grant additional maneuver during turn to move or perform physical activity.",
+ required: 2
+ }
+ ],
+ triumph: [
+ {text: "Perform the check with truly impressive results.", required: 1}
+ ],
+ threat: [
+ {text: "Small amounts cause strain.", required: 1},
+ {
+ text: "Larger amounts may cause character to fall prone, or even suffer a wound from sprains and bruises.",
+ required: 1
+ }
+ ],
+ despair: [
+ {
+ text: "Inflict a Critical Injury, which the GM can choose to be thematic or roll randomly.",
+ required: 1
+ }
+ ]
+ },
+ Charm: {
+ success: [
+ {
+ text: "Gain an extra scene in which target is willing to support you for each additional success.",
+ required: 1
+ }
+ ],
+ advantage: [
+ {text: "Affect unexpected subjects beyond the original target.", required: 1}
+ ],
+ triumph: [
+ {text: "Have target NPC become recurring character who remains predisposed to assist.", required: 1}
+ ],
+ threat: [
+ {text: "Reduce the number of people able to influence", required: 1},
+ {text: "Turn those affected negatively against character.", required: 1}
+ ],
+ despair: [
+ {text: "Turn NPC against character and make into a minor recurring adversary.", required: 1}
+ ]
+ },
+ Coercion: {
+ success: [
+ {text: "Spend 2 extra successes to inflict one strain on target. ", required: 2}
+ ],
+ advantage: [
+ {text: "Affect unexpected subjects beyond the original target.", required: 1}
+ ],
+ triumph: [
+ {text: "Shift allegiance of target.", required: 1}
+ ],
+ threat: [
+ {text: "Target has building resentment towards character.", required: 1}
+ ],
+ despair: [
+ {text: "Reveal something about goals and motivations to target.", required: 1}
+ ]
+ },
+ Computers: {
+ success: [
+ {text: "Reduce time required.", required: 1}
+ ],
+ advantage: [
+ {text: "Uncover additional information about the system.", required: 1}
+ ],
+ triumph: [
+ {
+ text: "Obfuscate actions taken, add a $CHALLENGE$ to any check to detect or identify the characters actions.",
+ required: 1
+ }
+ ],
+ threat: [
+ {
+ text: "The character does a poor job of concealing his presence in the system. Security systems are alerted, and add $BOOST$ to the check of any NPC attempting to discover evidence of his actions.",
+ required: 1
+ }
+ ],
+ despair: [
+ {
+ text: "Leave behind trace information of your own system in the system being sliced. Add $BOOST$ to the check of any NPC using the target system to slice the character's system.",
+ required: 1
+ }
+ ]
+ },
+ Cool: {
+ advantage: [
+ {text: "Gain an additional insight into the situation at hand.", required: 1}
+ ],
+ triumph: [
+ {text: "Heal 3 strain.", required: 1}
+ ],
+ threat: [
+ {text: "Miss a vital detail or event.", required: 1}
+ ],
+ despair: [
+ {text: "The character is overwhelmed by the chaos and is stunned for one round.", required: 1}
+ ]
+ },
+ Coordination: {
+ success: [
+ {text: "Reduce time required.", required: 1},
+ {text: "Increase distance travelled by 25%, (maximum 100% increase).", required: 1}
+ ],
+ advantage: [
+ {text: "Spend $ADVANTAGE$$ADVANTAGE$ to grant additional maneuver during turn.", required: 2}
+ ],
+ triumph: [
+ {text: "Perform the check with truly impressive results.", required: 1}
+ ],
+ threat: [
+ {text: "Lose free maneuver for one round.", required: 1}
+ ],
+ despair: [
+ {text: "Suffer a wound", required: 1},
+ {text: "Lose a vital piece of equipment.", required: 1}
+ ]
+ },
+ Deception: {
+ success: [
+ {text: "Extend duration of Deceit action.", required: 1}
+ ],
+ advantage: [
+ {text: "Increase the value of any goods or services gained through the action.", required: 1}
+ ],
+ triumph: [
+ {
+ text: "Fool the target into believing the character is trustworthy - future Deceit checks against target do not require an opposed check.",
+ required: 1
+ }
+ ],
+ threat: [
+ {text: "Give away a portion of the lie, making target suspicious.", required: 1}
+ ],
+ despair: [
+ {
+ text: "Target realises he has been lied to and spreads word of his deceit to harm his reputation or uses the situation to his advantage.",
+ required: 1
+ }
+ ]
+ },
+ Discipline: {
+ success: [
+ {text: "Downgrade difficulty of the dice pool for next action (max. 1).", required: 1}
+ ],
+ advantage: [
+ {text: "Gain an additional insight into the situation at hand.", required: 1}
+ ],
+ triumph: [
+ {
+ text: "Add $BOOST$ to any Discipline checks made by allies during the following round.",
+ required: 1
+ }
+ ],
+ threat: [
+ {
+ text: "Undermine the characters resolve, perhaps inflicting a penalty on further actions in distressing circumstances.",
+ required: 1
+ }
+ ],
+ despair: [
+ {
+ text: "The character is overwhelmed entirely and is unable to perform more than one maneuver next round.",
+ required: 1
+ }
+ ]
+ },
+ Leadership: {
+ success: [
+ {text: "Extend target's support for additional scenes.", required: 1},
+ {text: "Increase efficiency or effectiveness of target during ordered actions.", required: 1}
+ ],
+ advantage: [
+ {text: "Affect bystanders in addition to target.", required: 1}
+ ],
+ triumph: [
+ {
+ text: "Have target NPC become recurring character who decides to faithfully follow the acting character.",
+ required: 1
+ }
+ ],
+ threat: [
+ {
+ text: "Decrease the efficiency of ordered actions, causing them to take longer or be done poorly.",
+ required: 1
+ }
+ ],
+ despair: [
+ {
+ text: "Undermine the character's authority, damaging the characters ability to command target or those who witnessed the attempt.",
+ required: 1
+ },
+ {
+ text: "With multiple $DESPAIR$ the target may become a recurring thorn in the character's side,refusing future orders or turning others against the character.",
+ required: 2
+ }
+ ]
+ },
+ Mechanics: {
+ success: [
+ {text: "Reduce time required by 10-20%", required: 1}
+ ],
+ advantage: [
+ {
+ text: "Grant $BOOST$ on checks when using repaired item, or even the Superior quality, for a session.",
+ required: 1
+ }
+ ],
+ triumph: [
+ {text: "Give device additional single use function.", required: 1}
+ ],
+ threat: [
+ {
+ text: "Particularly shoddy repairs or temporary measures, the GM may spend $THREAT$ to cause the target object or system to malfunction shortly after check completed.",
+ required: 1
+ }
+ ],
+ despair: [
+ {text: "Cause further harm to target object or system.", required: 1},
+ {text: "Cause other components of target to malfunction.", required: 1}
+ ]
+ },
+ Medicine: {
+ success: [
+ {text: "Target recovers one additional wound.", required: 1},
+ {text: "Reduce healing time by one hour.", required: 1}
+ ],
+ advantage: [
+ {text: "Eliminate one strain from target.", required: 1}
+ ],
+ triumph: [
+ {
+ text: "Heal additional wounds while attempting to heal Critical Injury, or vice versa.",
+ required: 1
+ }
+ ],
+ threat: [
+ {text: "Inflict strain on the target due to shock of procedure.", required: 1},
+ {text: "Increase time procedure takes.", required: 1}
+ ],
+ despair: [
+ {text: "A truly terrible accident, perhaps inflicting further wounds on target.", required: 1}
+ ]
+ },
+ Negotiation: {
+ success: [
+ {text: "Increase acting character's profit by 5%.", required: 1},
+ {text: "Modify scope of agreement.", required: 1}
+ ],
+ advantage: [
+ {
+ text: "Earn unrelated boons from target, concessions if failed or extra perks if passed.",
+ required: 1
+ }
+ ],
+ triumph: [
+ {text: "Have target NPC become regular client or specialist vendor.", required: 1}
+ ],
+
+ threat: [
+ {text: "Increase cost of goods purchased.", required: 1},
+ {text: "Decrease value of goods sold.", required: 1},
+ {text: "Shorten contracts negotiated.", required: 1}
+ ],
+ despair: [
+ {
+ text: "Seriously sabotage goals during the interaction, perhaps receive counterfeit goods or payment, or agree to terms entirely beyond scope of negotiation.",
+ required: 1
+ }
+ ]
+ },
+ Perception: {
+ success: [
+ {text: "Reveal additional details.", required: 1}
+ ],
+ advantage: [
+ {text: "Recall additional information associated with object noticed.", required: 1}
+ ],
+ triumph: [
+ {
+ text: "Notice details that can be useful later to gain $BOOST$ on future interactions with noticed object.",
+ required: 1
+ }
+ ],
+ threat: [
+ {text: "Conceal a vital detail about situation or environment.", required: 1}
+ ],
+ despair: [
+ {text: "Obtain false information about surroundings or target.", required: 1}
+ ]
+ },
+ PilotingPlanetary: {
+ success: [
+ {text: "Gain insights into situation.", required: 1},
+ {text: "Deduce way to modify vehicle to make it more effective in future.", required: 1}
+ ],
+ advantage: [
+ {
+ text: "Reveal vulnerability in opponent's piloting style or vehicle, giving benefit in later rounds.",
+ required: 1
+ }
+ ],
+ triumph: [
+ {text: "Grant additional maneuver while continuing to pilot vehicle.", required: 1}
+ ],
+ threat: [
+ {
+ text: "Spend $THREAT$$THREAT$ to give opponents $BOOST$ on checks against character and vehicle due to momentary malfunction in system.",
+ required: 2
+ }
+ ],
+ despair: [
+ {
+ text: "Deal damage to vehicle as character strains systems throughout vehicle during check.",
+ required: 1
+ }
+ ]
+ },
+ PilotingSpace: {
+ success: [
+ {text: "Gain insights into situation.", required: 1},
+ {text: "Deduce way to modify vehicle to make it more effective in future.", required: 1}
+ ],
+ advantage: [
+ {
+ text: "Reveal vulnerability in opponent's piloting style or vehicle, giving benefit in later rounds.",
+ required: 1
+ }
+ ],
+ triumph: [
+ {text: "Grant additional maneuver while continuing to pilot vehicle.", required: 1}
+ ],
+ threat: [
+ {
+ text: "Spend $THREAT$$THREAT$ to give opponents $BOOST$ on checks against character and vehicle due to momentary malfunction in system.",
+ required: 2
+ }
+ ],
+ despair: [
+ {
+ text: "Deal damage to vehicle as character strains systems throughout vehicle during check.",
+ required: 1
+ }
+ ]
+ },
+ Resilience: {
+ success: [
+ {text: "Extend effects of the success to increase time between checks.", required: 1}
+ ],
+ advantage: [
+ {text: "Identify way to reduce difficulty of future checks against same threat.", required: 1}
+ ],
+ triumph: [
+ {text: "Recover 3 strain.", required: 1}
+ ],
+ threat: [
+ {text: "Overburden the character, inflicting penalties on subsequent checks.", required: 1}
+ ],
+ despair: [
+ {
+ text: "Inflict a wound or minor Critical Injury on character, as they succumb to harsh conditions.",
+ required: 1
+ }
+ ]
+ },
+ Skulduggery: {
+ success: [
+ {text: "Gain additional insights about nature of opposition.", required: 1}
+ ],
+ advantage: [
+ {text: "Identify additional potential target.", required: 1}
+ ],
+ triumph: [
+ {text: "Earn an unexpected boon.", required: 1}
+ ],
+ threat: [
+ {
+ text: "Opportunity to catch character immediately after act, number of $THREAT$ determine immediacy of discovery and ensuing danger.",
+ required: 1
+ }
+ ],
+ despair: [
+ {text: "Leave behind evidence of larceny.", required: 1}
+ ]
+ },
+ Stealth: {
+ success: [
+ {text: "Assist allied character infiltrating at same time.", required: 1}
+ ],
+ advantage: [
+ {text: "Decrease time taken to perform action while hidden.", required: 1}
+ ],
+ triumph: [
+ {text: "Identify way to completely distract opponent for duration of scene.", required: 1}
+ ],
+ threat: [
+ {text: "Increase time taken to perform action while hidden by 20%.", required: 1}
+ ],
+ despair: [
+ {text: "Leave behind evidence of passing, concerning identity and possibly motive.", required: 1}
+ ]
+ },
+ Streetwise: {
+ success: [
+ {text: "Reduce time or funds required to obtain item, information or service.", required: 1}
+ ],
+ advantage: [
+ {text: "Reveal additional rumours or alternative sources.", required: 1}
+ ],
+ triumph: [
+ {text: "Gain semi-permanent contact on street.", required: 1}
+ ],
+ threat: [
+ {text: "Seed gathered information with minor falsehoods.", required: 1}
+ ],
+ despair: [
+ {text: "Character lets slip details about self or information sought.", required: 1}
+ ]
+ },
+ Survival: {
+ success: [
+ {text: "Assist other character in surviving.", required: 1},
+ {text: "Stockpile goods to increase time between checks.", required: 1}
+ ],
+ advantage: [
+ {text: "Gain insight into environment to make future checks simpler.", required: 1},
+ {
+ text: "When tracking, learn significant detail about target, such as number, species or how recently tracks were made.",
+ required: 1
+ }
+ ],
+ triumph: [
+ {
+ text: "When handling domesticated animal, predispose animal towards character earning loyal companion.",
+ required: 1
+ },
+ {text: "When tracking, learn vital clue about target.", required: 1}
+ ],
+ threat: [
+ {text: "Spend vital resources (food, fuel, etc.) during check.", required: 1}
+ ],
+ despair: [
+ {text: "Inflict wounds, Critical Injuries or large amounts of strain on character.", required: 1}
+ ]
+ },
+ Vigilance: {
+ success: [
+ {text: "Character is particularly well prepared.", required: 1}
+ ],
+ advantage: [
+ {text: "Notice key environmental factor.", required: 1}
+ ],
+ triumph: [
+ {text: "Gain extra maneuver during first round of combat.", required: 1}
+ ],
+ threat: [
+ {text: "Miss key piece of information about situation or environment.", required: 1}
+ ],
+ despair: [
+ {
+ text: "The character is unable to perform more than one maneuver during first round of combat.",
+ required: 1
+ }
+ ]
+ }
+ },
+ combat: {
+ /*TODO continue working on the combat skill suggestions*/
+ personal: {
+ AllowedSkills: [
+ "RangedLight",
+ "RangedHeavy",
+ "Melee",
+ "Brawl",
+ "Lightsaber",
+ "Gunnery"
+ ],
+ '1advantage1triumph': [
+ {text: "Recover 1 strain", advantage: 1, triumph: 1},
+ {text: "Add $BOOST$ to the next allied active character's next check.", advantage: 1, triumph: 1},
+ {text: "Notice a single important point in the ongoing conflict.", advantage: 1, triumph: 1},
+ {
+ text: "Inflict a Critical Injury with a successful attack that deals damage past soak. ($ADVANTAGE$ cost may vary)",
+ advantage: 1,
+ triumph: 1,
+ crit: true
+ }
+ ],
+ '2advantage1triumph': [
+ {text: "Activate a weapon quality ($ADVANTAGE$ cost may vary)", advantage: 2, triumph: 1},
+ {
+ text: "Perform an immediate free maneuver that does not exceed the two maneuver per turn limit",
+ advantage: 2,
+ triumph: 1
+ },
+ {text: "Add $SETBACK$ to the targeted character's next check.", advantage: 2, triumph: 1},
+ {
+ text: "Add $BOOST$ to any allied character's next check, including that of the active character.",
+ advantage: 2,
+ triumph: 1
+ }
+ ],
+ '3advantage1triumph': [
+ {
+ text: "Negate the targeted enemy's defensive bonuses until the end of turn",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "Ignore penalizing environmental effects until the end of the active character's next turn.",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "When dealing damage to a target, have the attack disable the opponent or one piece of gear rather than dealing wounds or strain.",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "Gain +1 melee or ranged defense until the end of the active character's next turn",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "Force the target to drop a melee or ranged weapon they are wielding.",
+ advantage: 3,
+ triumph: 1
+ }
+ ],
+ '1triumph': [
+ {text: "Upgrade the difficulty of the targeted character's next check.", triumph: 1},
+ {
+ text: "Upgrade any allied character's next check, including that of the current active character.",
+ triumph: 1
+ },
+ {text: "Do something vital, such as shooting the controls to the nearby blast doors.", triumph: 1}
+ ],
+ '2triumph': [
+ {
+ text: "When dealing damage to a target, had the attack destroyed a piece of equipment the target is using.",
+ triumph: 2
+ }
+ ],
+ '1threat1despair': [
+ {text: "The active character suffers 1 strain", threat: 1, despair: 1},
+ {text: "The active character looses the benefits of a prior maneuver", threat: 1, despair: 1}
+ ],
+ '2threat1despair': [
+ {text: "An opponent may immediately perform one free maneuver.", threat: 2, despair: 1},
+ {text: "Add $BOOST$ to the targeted character's next check", threat: 2, despair: 1},
+ {
+ text: "The active character or an allied character suffers a $SETBACK$ on their next action.",
+ threat: 2,
+ despair: 1
+ }
+ ],
+ '3threat1despair': [
+ {text: "The active character falls prone.", threat: 3, despair: 1},
+ {
+ text: "The active character grants the enemy a significant advantage in the ongoing encounter.",
+ threat: 3,
+ despair: 1
+ }
+ ],
+ '1despair': [
+ {text: "The character's ranged weapon immediately runs out of ammunition.", despair: 1},
+ {
+ text: "Upgrade the difficulty of an allied character's next check, including the active character.",
+ despair: 1
+ },
+ {text: "The tool or melee weapon the character is using becomes damaged.", despair: 1}
+ ]
+ },
+ vehicle: {
+ AllowedSkills: [
+ "RangedHeavy",
+ "Gunnery",
+ "PilotingSpace",
+ "PilotingPlanetary"
+
+ ],
+ '1advantage1triumph': [
+ {
+ text: "Add $BOOST$ to the next allied active character's Piloting, Gunnery, Computers, or Mechanics check.",
+ advantage: 1,
+ triumph: 1
+ },
+ {text: "Notice a single important point in the ongoing conflict.", advantage: 1, triumph: 1},
+ {
+ text: "Inflict a Critical Hit with successful attack that deals damage past armor ($ADVANTAGE$ cost may vary)",
+ advantage: 1,
+ triumph: 1,
+ crit: true
+ }
+ ],
+ '2advantage1triumph': [
+ {text: "Activate a weapon quality ($ADVANTAGE$ cost may vary", advantage: 2, triumph: 1},
+ {
+ text: "Perform an immediate free maneuver, provided the active character has not already performed two maneuvers in that turn.",
+ advantage: 2,
+ triumph: 1
+ },
+ {
+ text: "Add $SETBACK$ to the targeted character's next Piloting or Gunnery check.",
+ advantage: 2,
+ triumph: 1
+ },
+ {
+ text: "Add $BOOST$ to any allied character's next Piloting, Gunnery, Computers or Mechanics check, including the active character,",
+ advantage: 2,
+ triumph: 1
+ }
+ ],
+ '3advantage1triumph': [
+ {
+ text: "When dealing damage to an opposing vehicle or ship, have the shot temporarily damage a component of the attacker's choice rather than deal hull damage or system strain.",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "Ignore penalizing terrain or stellar phenomena until the end of the active character's next turn.",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "If piloting the ship, perform one free Pilot Only maneuver (provided it does not break the limit of maximum number of Pilot Only maneuvers in a turn).",
+ advantage: 3,
+ triumph: 1
+ },
+ {
+ text: "Force the target ship or vehicle to veer off, breaking any Aim or Stay on Target maneuvers.",
+ advantage: 3,
+ triumph: 1
+ }
+ ],
+ '1triumph': [
+ {
+ text: "Upgrade the difficulty of the targeted character's next Piloting or Gunnery check.",
+ triumph: 1
+ },
+ {
+ text: "Upgrade any allied character's next Piloting, Gunnery, Computers or Mechanics check.",
+ triumph: 1
+ }
+ ],
+ '2triumph': [
+ {text: "Destroy an important component when dealing damage.", triumph: 2}
+ ],
+ '1threat1despair': [
+ {
+ text: "If piloting a ship, sudden maneuvers force the ship to slow down by 1 point of speed.",
+ threat: 1,
+ despair: 1
+ },
+ {text: "The active character looses the benefits of a prior maneuver.", threat: 1, despair: 1},
+ {
+ text: "The character's active ship suffers 1 system strain. (This option may be selected multiple times)",
+ threat: 1,
+ despair: 1
+ }
+ ],
+ '2threat1despair': [
+ {text: "An opponent may immediately perform one free maneuver.", threat: 2, despair: 1},
+ {
+ text: "Add $BOOST$ to the targeted character's next Piloting or Gunnery Check",
+ threat: 2,
+ despair: 1
+ },
+ {
+ text: "The active character or allied character suffers $SETBACK$ on their next action.",
+ threat: 2,
+ despair: 1
+ }
+ ],
+ '3threat1despair': [
+ {
+ text: "The initiative currently being used drops below the last slot in the round.",
+ threat: 3,
+ despair: 1
+ },
+ {text: "The enemy gains a significant advantage in the ongoing encounter.", threat: 3, despair: 1},
+ {
+ text: "The primary weapon system of the active character's ship (or weapon the character is manning if acting as a gunner) suffers a Component Critical Hit.",
+ despair: 1
+ }
+ ],
+ '1despair': [
+ {
+ text: "Upgrade the difficulty of an allied character's next Gunnery, Piloting, computers or Mechanics check.",
+ despair: 1
+ },
+ {
+ text: "The active character's ship suffers a minor collision either with one of their opponents within close range or with the terrain around them.",
+ despair: 1
+ },
+ {
+ text: "The active character's ship suffers a major collision either with one of their opponents within close range or with the terrain around them.",
+ despair: 1,
+ failed: true
+ }
+ ]
+ }
+ }
+ };
+
+ this.enum = {
+ types: {
+ general: {number:0, text:"general"},
+ combat: {number:1, text:"combat"}
+ },
+ displayOptions: {
+ none: {number:0, text:"none"}, // Suggestions are not displayed
+ whisper: {number:1, text:"whisper"}, // Suggestions are whispered to the GM
+ always: {number:2, text:"always"} // Suggestions are included in the dice roll result
+ },
+ combatType: {
+ personal: {number:0, text:"personal"},
+ vehicle: {number:1, text:"vehicle"}
+ }
+ };
+
+ this.setDisplayOption = function (input) {
+ if (input == null || input === "")
+ return;
+
+ var flag = null;
+ if (flag = that.enum.isValidInput(input, that.enum.displayOptions))
+ flags.displayOption = flag;
+ };
+
+ this.getDisplayOption = function () {
+ return flags.displayOption;
+ };
+
+ this.setGeneralSuggestions = function (input) {
+ if (input == null || input === "")
+ return;
+ log("input="+input);
+
+ flags.generalSuggesting = convertToBoolean(input);
+ log("flags.generalSuggesting="+flags.generalSuggesting);
+ };
+
+ this.getGeneralSuggesting = function () {
+ return flags.generalSuggesting;
+ };
+
+ this.setCombatSuggestions = function (input) {
+ if (input == null || input === "")
+ return;
+ log("input="+input);
+ flags.combatSuggesting = convertToBoolean(input);
+ log("flags.combatSuggesting="+flags.combatSuggesting);
+ };
+
+ this.getCombatSuggesting = function () {
+ return flags.combatSuggesting;
+ };
+
+ this.setIsFearCheck = function (input) {
+ if (input == null || input === "")
+ return;
+
+ flags.isFearCheck = convertToBoolean(input);
+ };
+
+ this.getIsFearCheck = function () {
+ return flags.isFearCheck;
+ };
+
+ this.setCombatType = function (input) {
+ if (input == null || input === "") {
+ flags.combatType = null;
+ return;
+ }
+
+ var flag = null;
+ if (flag = that.enum.isValidInput(input, that.enum.combatType))
+ flags.combatType = flag;
+ };
+
+ this.getCombatType = function () {
+ return flags.combatType;
+ };
+
+ this.enum.isValidInput = function (input, enumToUse) {
+ if (input == null || input === "" || !enumToUse)
+ return;
+
+ var retVal = null;
+
+ Object.keys(enumToUse).some(function(key) {
+ var object = enumToUse[key];
+
+ if (input == object || input === object.text || input === object.number) {
+ return retVal = object;
+ }
+ });
+
+ return retVal;
+ };
+
+ this.enum.mapTextToNumber = function (input, enumToUse) {
+ if (input == null || input === "")
+ return;
+
+ var flag = null;
+ if (flag = that.enum.isValidInput(input, enumToUse))
+ return flag.number;
+ };
+
+ this.enum.mapNumberToText = function (input, enumToUse) {
+ if (input == null || input === "")
+ return;
+
+ var flag = null;
+ if (flag = that.enum.isValidInput(input, enumToUse))
+ return flag.text;
+ };
+
+
+ /* Suggestion Handling */
+ function addSkillSuggestionsFromArray (diceObj, array, key, rollResultForSymbol, suggestionsType) {
+ for (var i = 0; i < array.length; i++) {
+ if (array[i].required <= rollResultForSymbol) {
+ suggestionsType[key] += "" + array[i].text + " ";
+ diceObj.vars.suggestions.suggestionsExist = true;
+ }
+ }
+ return diceObj;
+ }
+
+ function buildSuggestionSet (suggestionSet, symbol, rollResultForSymbol, suggestionJSON) {
+ if (suggestionSet == null)
+ suggestionSet = new Set();
+
+ var item = {};
+ for (var i = 0; i < suggestionJSON.length; i++) {
+ item = suggestionJSON[i];
+ if (item.hasOwnProperty(symbol) && item[symbol] <= rollResultForSymbol) {
+ suggestionSet.add(item.text);
+ }
+ }
+
+ return suggestionSet;
+ }
+
+ function buildCombatSuggestions (diceObj, symbol, rollResultForSymbol, suggestionJSON) {
+ var suggestionSet = null;
+ var spendingSuggestions = diceObj.vars.suggestions;
+ Object.keys(suggestionJSON).forEach(function(property) {
+ if (property === "AllowedSkills")
+ return;
+
+ suggestionSet = spendingSuggestions.combat[property];
+ suggestionSet = buildSuggestionSet(suggestionSet, symbol, rollResultForSymbol, suggestionJSON[property]);
+
+ if (suggestionSet.size > 0) {
+ spendingSuggestions.suggestionsExist = true;
+ spendingSuggestions.combat[property] = suggestionSet;
+ }
+ });
+
+ return diceObj;
+ }
+
+ function buildRollTemplateItem (key, value) {
+ return "{{" + key + "=}}";
+ }
+
+ function generateSuggestions (diceObj, symbol, rollResultForSymbol) {
+ var skillName = diceObj.vars.skillName;
+
+ var combatType = flags.combatType;
+ if (flags.combatSuggesting && combatType) {
+ var combatSkills = that.suggestions.combat;
+ var personal = that.enum.combatType.personal;
+ var vehicle = that.enum.combatType.vehicle;
+ if (combatType == personal)
+ {
+ diceObj = buildCombatSuggestions(diceObj, symbol, rollResultForSymbol, combatSkills.personal);
+ }
+ else if (combatType == vehicle)
+ {
+ diceObj = buildCombatSuggestions(diceObj, symbol, rollResultForSymbol, combatSkills.vehicle);
+ }
+ } else if (flags.generalSuggesting) {
+ var generalSkills = that.suggestions.general;
+ if (generalSkills.hasOwnProperty(skillName)) {
+ var skill = generalSkills[skillName];
+ var fearJSON = (diceObj.vars.isFearCheck ? that.suggestions.special.fear : null);
+
+ if (skill.hasOwnProperty(symbol)) {
+ diceObj = addSkillSuggestionsFromArray(diceObj, skill[symbol], symbol, rollResultForSymbol, diceObj.vars.suggestions.general);
+ }
+
+ if (fearJSON && fearJSON.allowedSkills.indexOf(skillName)) {
+ diceObj = addSkillSuggestionsFromArray(diceObj, fearJSON[symbol], symbol, rollResultForSymbol, diceObj.vars.suggestions.general);
+ }
+ }
+ }
+ return diceObj;
+ }
+
+ this.processSuggestions = function(diceObj) {
+ if (flags.displayOption === that.enum.displayOptions.none)
+ return diceObj;
+
+ diceObj.vars.suggestions = {
+ general: {
+ success: "",
+ advantage: "",
+ triumph: "",
+ failure: "",
+ threat: "",
+ despair: ""
+ },
+ combat: {
+ '1advantage1triumph': null,
+ '2advantage1triumph': null,
+ '3advantage1triumph': null,
+ '1triumph': null,
+ '2triumph': null,
+ '1threat1despair': null,
+ '2threat1despair': null,
+ '3threat1despair': null,
+ '1despair': null,
+ '2despair': null
+ },
+ suggestionsExist: false
+ };
+
+
+ var failedCheck = !diceObj.totals.success > 0;
+ Object.keys(diceObj.totals).forEach(function(key) {
+ var rollResultForSymbol = diceObj.totals[key];
+ if (rollResultForSymbol > 0) {
+ diceObj = generateSuggestions(diceObj, key, rollResultForSymbol, failedCheck);
+ }
+ });
+
+ return diceObj;
+ };
+
+ this.buildSuggestionsRollTemplate = function (diceObj) {
+ var suggestions = diceObj.vars.suggestions;
+ var suggestionsRollTemplate = "";
+
+ // display results shown to character owners and GM
+ Object.keys(suggestions).forEach(function (property) {
+ if (property === "suggestionsExist")
+ return;
+
+ var propertyObject = suggestions[property];
+ Object.keys(propertyObject).forEach(function(symbol) {
+ var object = propertyObject[symbol];
+
+ if (!object)
+ return;
+
+ if (typeof object === "string")
+ suggestionsRollTemplate += buildRollTemplateItem(symbol, object);
+ else if (object.size > 0) {
+ var suggestionList = "";
+ object.forEach(function (value) {
+ suggestionList += "" + value + " ";
+ });
+ suggestionsRollTemplate += buildRollTemplateItem(symbol, suggestionList);
+ }
+ });
+ });
+ return suggestionsRollTemplate;
+ }
+}
+
+/*TODO refactor eote to be swrpg*/
+var eote = {};
+
+eote.init = function () {
+ eote.setCharacterDefaults();
+ eote.createGMDicePool();
+ eote.events();
+ convertTokensToTags(suggestionEngine.suggestions, eote.defaults.graphics.SymbolicReplacement);
+ attemptRegisterGMObj();
+};
+
+
+eote.defaults = {
+ globalVars: {
+ diceLogChat: true,
+ diceGraphicsChat: true,
+ diceGraphicsChatSize: 30,//medium size
+ diceTextResult: "",
+ diceTextResultLog: "",
+ diceGraphicResult: "",
+ diceGraphicResultLog: "",
+ diceTestEnabled: false,
+ diceLogRolledOnOneLine: true,
+ scriptDebug: false
+ },
+ '-DicePoolID': '',
+ GMSheet: {
+ obj: null,
+ name: "-DicePool"
+ },
+ character: {
+ attributes: [
+ /* Don't need to update characterID
+ *
+ *{
+ name : "characterID",
+ current : "UPDATES TO CURRENT ID",
+ max : "",
+ update : false
+ }*/
+ ],
+ abilities: []
+ },
+ graphics: {
+ SIZE: {
+ SMALL: 20,
+ MEDIUM: 30,
+ LARGE: 40
+ },
+ ABILITY: {
+ BLANK: "https://i.imgur.com/g3hoJRG.png",
+ A: "https://i.imgur.com/VG7HnFE.png",
+ AA: "https://i.imgur.com/ynn0deR.png",
+ S: "https://i.imgur.com/HnweiQT.png",
+ SA: "https://i.imgur.com/iVXuNKP.png",
+ SS: "https://i.imgur.com/IVDgDKo.png"
+ },
+ BOOST: {
+ BLANK: "https://i.imgur.com/nlIAfJx.png",
+ A: "https://i.imgur.com/d6X6QEs.png",
+ AA: "https://i.imgur.com/EqMcrlF.png",
+ S: "https://i.imgur.com/vrt51oP.png",
+ SA: "https://i.imgur.com/r9xl3CP.png"
+ },
+ CHALLENGE: {
+ BLANK: "https://i.imgur.com/GInMHEN.png",
+ F: "https://i.imgur.com/zKdsTV9.png",
+ FF: "https://i.imgur.com/QcZXdpS.png",
+ FT: "https://i.imgur.com/wxV072J.png",
+ T: "https://i.imgur.com/n2rgehM.png",
+ TT: "https://i.imgur.com/SaWvZMV.png",
+ DESPAIR: "https://i.imgur.com/5EppLES.png"
+ },
+ DIFFICULTY: {
+ BLANK: "https://i.imgur.com/oxbKghK.png",
+ F: "https://i.imgur.com/rujbVt9.png",
+ FF: "https://i.imgur.com/VUj86X2.png",
+ FT: "https://i.imgur.com/l8rUPCX.png",
+ T: "https://i.imgur.com/2gLDiqq.png",
+ TT: "https://i.imgur.com/4wqEJsa.png"
+ },
+ FORCE: {
+ D: "https://i.imgur.com/8kBnDI1.png",
+ DD: "https://i.imgur.com/eki6Bnc.png",
+ L: "https://i.imgur.com/JCI7Mgm.png",
+ LL: "https://i.imgur.com/Z58SAHI.png"
+ },
+ PROFICIENCY: {
+ BLANK: "https://i.imgur.com/4bQ0dY8.png",
+ A: "https://i.imgur.com/PU7pp3w.png",
+ S: "https://i.imgur.com/jXGG6L1.png",
+ SA: "https://i.imgur.com/oQMDNdm.png",
+ SS: "https://i.imgur.com/UDW3jYZ.png",
+ AA: "https://i.imgur.com/jUA6PVw.png",
+ TRIUMPH: "https://i.imgur.com/7zrDoEN.png"
+ },
+ SETBACK: {
+ BLANK: "https://i.imgur.com/n9W07Lp.png",
+ F: "https://i.imgur.com/jMV5VOB.png",
+ T: "https://i.imgur.com/TYgM9LP.png"
+ },
+ SYMBOLS: {
+ A: "https://i.imgur.com/Gav94H2.png",
+ S: "https://i.imgur.com/z79ieDp.png",
+ T: "https://i.imgur.com/o8EQ4z6.png",
+ F: "https://i.imgur.com/y2qABhW.png",
+ TRIUMPH: "https://i.imgur.com/1lJCfnB.png",
+ DESPAIR: "https://i.imgur.com/rOEJlCc.png",
+ L: "https://i.imgur.com/j5bV12H.png",
+ D: "https://i.imgur.com/AZ3lzVj.png"
+ },
+ SymbolicReplacement: {}
+ },
+ regex: {
+ cmd: /!eed/,
+ log: /log (on|multi|single|off)/,
+ debug: /debug (on|off)/,
+ graphics: /graphics (on|off|s|m|l)/,
+ test: /test/,
+ resetdice: /(resetgmdice|resetdice)/,
+ initiative: /\bnpcinit|\bpcinit/,
+ characterID: /characterID\((.*?)\)/,
+ rollPlayer: /rollPlayer(\(.*?\))/,
+ label: /label\((.*?)\)/,
+ skill: /skill\((.*?)\)/g,
+ fear: /fear (on|off)/,
+ suggestionDisplay: /suggestionDisplay (none|whisper|always)/,
+ opposed: /opposed\((.*?)\)/g,
+ upgrade: /upgrade\((.*?)\)/g,
+ downgrade: /downgrade\((.*?)\)/g,
+ gmdice: /\(gmdice\)/,
+ encum: /encum\((.*?)\)/g,
+ dice: /(-?\d{1,2}blk)\b|(-?\d{1,2}b)\b|(-?\d{1,2}g)\b|(-?\d{1,2}y)\b|(-?\d{1,2}p)\b|(-?\d{1,2}r)\b|(-?\d{1,2}w)\b|(-?\d{1,2}a)\b|(-?\d{1,2}s)|(-?\d{1,2}t)\b|(-?\d{1,2}f)/g,
+ crit: /crit\((.*?)\)/,
+ critShip: /critship\((.*?)\)/,
+ unusable: /unusableWeapon/,
+ destiny: /destiny (useDark|useLight|registerPlayer|sendUpdate|doRoll|clearPool)/,
+ combat: /combat\(personal|vehicle\)/,
+ calculateDamage: /calculateDamage\((.*?)\)/,
+ rollEnemyCritical: /rollEmemyCritical/,
+ rollRandomCritical: /rollRandomCritical/
+ },
+ destinyListeners: []
+};
+
+var GMSheet = eote.defaults.GMSheet;
+var suggestionEngine = new SuggestionEngine();
+
+function buildReplacementObject (title, src, size) {
+ return {matcher: new RegExp("\\$" + title.toUpperCase() + "\\$","g"), replacer: ' '};
+}
+
+// dice symbols
+eote.defaults.graphics.SymbolicReplacement.success = buildReplacementObject("success", eote.defaults.graphics.SYMBOLS.S, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.advantage = buildReplacementObject("advantage", eote.defaults.graphics.SYMBOLS.A, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.triumph = buildReplacementObject("triumph", eote.defaults.graphics.SYMBOLS.TRIUMPH, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.failure = buildReplacementObject("failure", eote.defaults.graphics.SYMBOLS.F, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.threat = buildReplacementObject("threat", eote.defaults.graphics.SYMBOLS.T, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.despair = buildReplacementObject("despair", eote.defaults.graphics.SYMBOLS.DESPAIR, eote.defaults.graphics.SIZE.SMALL);
+
+// dice icons
+eote.defaults.graphics.SymbolicReplacement.ability = buildReplacementObject("ability", eote.defaults.graphics.ABILITY.BLANK, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.boost = buildReplacementObject("boost", eote.defaults.graphics.BOOST.BLANK, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.proficiency = buildReplacementObject("proficiency", eote.defaults.graphics.PROFICIENCY.BLANK, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.difficulty = buildReplacementObject("difficulty", eote.defaults.graphics.DIFFICULTY.BLANK, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.setback = buildReplacementObject("setback", eote.defaults.graphics.SETBACK.BLANK, eote.defaults.graphics.SIZE.SMALL);
+eote.defaults.graphics.SymbolicReplacement.challenge = buildReplacementObject("challenge", eote.defaults.graphics.CHALLENGE.BLANK, eote.defaults.graphics.SIZE.SMALL);
+
+function attemptRegisterGMObj() {
+ var GMObj = GMSheet.obj;
+
+ // if the GMObj is null then it means that this is the first time this version of the script is being run on this campaign.
+ if (!GMObj) {
+ GMObj = findObjs({
+ _type: "character",
+ name: GMSheet.name
+ });
+ if (GMObj.length > 0) {
+ GMSheet.obj = GMObj[0];
+ eote.process.logger("attemptRegisterGMObj", "Registering of GMObj successful");
+ }
+ else {
+ var msg = "The character sheet called " + GMSheet.name + " was not found in your campaign.";
+ eote.process.logger("attemptRegisterGMObj", msg);
+ sendChat("System", "/w gm " + msg);
+ }
+ } else {
+ eote.process.logger("attemptRegisterGMObj", "GMObj previously registered.");
+ }
+}
+
+eote.createGMDicePool = function () {
+
+ var charObj_DicePool = findObjs({ _type: "character", name: "-DicePool" })[0];
+ var attrObj_DicePool = [
+ {
+ name: 'pcgm',
+ current: 3,
+ max: '',
+ update: true
+ },
+ {
+ name: 'gmdicepool',
+ current: 2,
+ max: '',
+ update: true
+ }
+ ];
+ //create character -DicePool
+ if (!charObj_DicePool) {
+ charObj_DicePool = createObj("character", {
+ name: GMSheet.name,
+ bio: "GM Dice Pool"
+ });
+ }
+ eote.defaults['-DicePoolID'] = charObj_DicePool.id;
+ GMSheet.obj = charObj_DicePool;
+ eote.updateAddAttribute(charObj_DicePool, attrObj_DicePool);
+};
+
+eote.createObj = function () {//Create Object Fix - Firebase.set failed
+ var obj = createObj.apply(this, arguments);
+ var id = obj.id;
+ var characterID = obj.get('characterid');
+ var type = obj.get('type');
+ if (obj && !obj.fbpath && obj.changed) {
+ obj.fbpath = obj.changed._fbpath.replace(/([^\/]*\/){4}/, "/");
+ } else if (obj && !obj.changed && type == 'attribute') { //fix for dynamic attribute after in character created in game
+ obj.fbpath = '/char-attribs/char/' + characterID + '/' + id;
+ // /char-attribs/char/characterID/attributeID
+ }
+ return obj;
+};
+
+eote.setCharacterDefaults = function (characterObj) {
+
+ var charObj = [characterObj];
+
+ if (!characterObj) {
+ charObj = findObjs({ _type: "character" });
+ }
+ //add/update characterID field
+ _.each(charObj, function (charObj) {
+ //updates default attr:CharacterID to current character id
+ //_.findWhere(eote.defaults.character.attributes, {'name':'characterID'}).current = charObj.id;
+
+ //Attributes
+ eote.updateAddAttribute(charObj, eote.defaults.character.attributes);//Update Add Attribute defaults
+ //Abilities
+ });
+};
+
+eote.updateListeners = function (attributes) {
+
+ _.each(eote.defaults.destinyListeners, function (charID) {
+
+ var charObj = findObjs({
+ _type: "character",
+ _id: charID
+ });
+ //add/update characterID field
+ _.each(charObj, function (charObj) {
+ //Attributes
+ eote.updateAddAttribute(charObj, attributes); //Update Add Attribute defaults
+ });
+ });
+ //Update GM
+ var GMObj = findObjs({
+ _type: "character",
+ name: GMSheet.name
+ });
+ GMSheet.obj = GMSheet.obj || GMObj;
+ eote.updateAddAttribute(GMObj, attributes);
+};
+
+eote.updateAddAttribute = function (charactersObj, updateAddAttributesObj) { // charactersObj = object or array objects, updateAddAttributesObj = object or array objects
+ if (!charactersObj) {
+ log("error: charactersObj passed into eote.updateAddAttribute is not set");
+ return;
+ }
+
+ //check if object or array
+ if (!_.isArray(charactersObj)) {
+ charactersObj = [charactersObj];
+ }
+ if (!_.isArray(updateAddAttributesObj)) {
+ updateAddAttributesObj = [updateAddAttributesObj];
+ }
+ _.each(charactersObj, function (characterObj) {//loop characters
+
+ var characterName = '';
+
+ if (characterObj.name) {
+ characterName = characterObj.name;
+ } else {
+ characterName = characterObj.get('name');
+ }
+ //find attribute via character ID
+ var characterAttributesObj = findObjs({ _type: "attribute", characterid: characterObj.id });
+
+ if (updateAddAttributesObj.length != 0) {
+
+ log('UPDATE/ADD ATTRIBUTES FOR:----------------------->' + characterName);
+
+ _.each(updateAddAttributesObj, function (updateAddAttrObj) { //loop attributes to update / add
+
+ attr = _.find(characterAttributesObj, function (a) {
+ return (a.get('name') === updateAddAttrObj.name);
+ });
+ if (attr) {
+ if (updateAddAttrObj.update) {
+ log('Update Attr: ' + updateAddAttrObj.name);
+ attr.set({ current: updateAddAttrObj.current });
+ attr.set({ max: updateAddAttrObj.max ? updateAddAttrObj.max : '' });
+ }
+ } else {
+ // log('Add Attr: '+ updateAddAttrObj.name);
+ eote.createObj('attribute', {
+ characterid: characterObj.id,
+ name: updateAddAttrObj.name,
+ current: updateAddAttrObj.current,
+ max: updateAddAttrObj.max ? updateAddAttrObj.max : ''
+ });
+ }
+ });
+ }
+ });
+};
+
+/* DICE PROCESS
+*
+* Matches the different regex commands and runs that dice processing step
+* The order of step should not be change or dice could be incorrectly rolled.
+* example: All dice needs to be 'upgraded" before it can be 'downgraded'
+* ---------------------------------------------------------------- */
+
+eote.defaults.dice = function () {
+ this.vars = {
+ characterName: '',
+ characterID: '',
+ playerName: '',
+ playerID: '',
+ label: '',
+ suggestions: {},
+ skillName: '',
+ isFearCheck: false,
+ combatCheck: false
+ };
+ this.totals = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0
+ };
+ this.graphicsLog = {
+ Boost: '',
+ Ability: '',
+ Proficiency: '',
+ SetBack: '',
+ Difficulty: '',
+ Challenge: '',
+ Force: '',
+ Success: '',
+ Advantage: '',
+ Threat: '',
+ Failure: ''
+ };
+ this.textLog = {
+ Boost: '',
+ Ability: '',
+ Proficiency: '',
+ SetBack: '',
+ Difficulty: '',
+ Challenge: '',
+ Force: '',
+ Success: '',
+ Advantage: '',
+ Threat: '',
+ Failure: ''
+ };
+ this.count = {
+ boost: 0,
+ ability: 0,
+ proficiency: 0,
+ setback: 0,
+ difficulty: 0,
+ challenge: 0,
+ force: 0,
+ success: 0,
+ advantage: 0,
+ threat: 0,
+ failure: 0
+ }
+};
+
+eote.process = {};
+
+eote.process.logger = function (functionName, cmd) {
+ if (eote.defaults.globalVars.debugScript) {
+ log(functionName + ' : ' + cmd);
+ }
+};
+
+eote.process.setup = function (cmd, playerName, playerID) {
+
+ if (!cmd.match(eote.defaults.regex.cmd)) { //check for api cmd !eed
+ return false;
+ }
+ var debugMatch = cmd.match(eote.defaults.regex.debug);
+ if (debugMatch) {
+ eote.process.debug(debugMatch);
+ return false;
+ }
+ var fearMatch = cmd.match(eote.defaults.regex.fear);
+ if (fearMatch) {
+ eote.process.fear(fearMatch);
+ return false;
+ }
+
+ var suggestionDisplayMatch = cmd.match(eote.defaults.regex.suggestionDisplay);
+ if (suggestionDisplayMatch) {
+ eote.process.suggestionDisplay(suggestionDisplayMatch);
+ return false;
+ }
+
+ eote.process.logger("eote.process.setup", "NEW ROLL");
+ eote.process.logger("eote.process.setup", "Original Command: " + cmd);
+
+ /* reset dice - test, might not need this */
+ var diceObj = new eote.defaults.dice();
+ diceObj.vars.playerName = playerName;
+ diceObj.vars.playerID = playerID;
+
+ /* Dice config
+ * Description: Change dice roller default config
+ * --------------------------------------------------------------*/
+ var logMatch = cmd.match(eote.defaults.regex.log);
+
+ if (logMatch) {
+ eote.process.log(logMatch);
+ return false; //Stop current roll and run test
+ }
+ var graphicsMatch = cmd.match(eote.defaults.regex.graphics);
+
+ if (graphicsMatch) {
+ eote.process.graphics(graphicsMatch);
+ return false; //Stop current roll and run test
+ }
+ var testMatch = cmd.match(eote.defaults.regex.test);
+
+ if (testMatch) {
+ eote.process.test(testMatch);
+ return false; //Stop current roll and run test
+ }
+ /* Roll information
+ * Description: Set default dice roll information Character Name and Skill Label
+ * --------------------------------------------------------------*/
+
+ var rollPlayerMatch = cmd.match(eote.defaults.regex.rollPlayer);
+
+ if (rollPlayerMatch) {
+ diceObj = eote.process.rollPlayer(rollPlayerMatch, diceObj);
+
+ if (!diceObj) {
+ return false;
+ }
+ }
+ var characterIDMatch = cmd.match(eote.defaults.regex.characterID);
+
+ if (characterIDMatch) {
+ diceObj = eote.process.characterID(characterIDMatch, diceObj);
+ //Once Character ID is parsed, remove it from the cmd.
+ //it is possible that the character ID could contain dice values
+ //for ex. characterID(-JMBFmYX1i0L259bjb-X) will add 59 blue dice to the pool
+ cmd = cmd.replace(characterIDMatch[0], '');
+ eote.process.logger("eote.process.setup.characterIDMatch", "New command: " + cmd);
+ }
+ var unusableMatch = cmd.match(eote.defaults.regex.unusable);
+
+ if (unusableMatch) {
+ eote.process.logger("eote.process.setup.unusableMatch", "Roll ended because of unusable weapon");
+ sendChat(diceObj.vars.characterName, "&{template:base} {{title=" + diceObj.vars.characterName + "}} {{wide=Weapon is too damaged to be used. Try repairing it.}}");
+ return false;
+ }
+ var labelMatch = cmd.match(eote.defaults.regex.label);
+
+ if (labelMatch) {
+ diceObj = eote.process.label(labelMatch, diceObj);
+ }
+ /* Dice rolls
+ * Description: Create dice pool before running any custom roll
+ * script commands that may need dice evaluated.
+ * --------------------------------------------------------------*/
+ var gmdiceMatch = cmd.match(eote.defaults.regex.gmdice);
+
+ if (gmdiceMatch) {
+ // Check to see if GM Dice pool is enabled for roll
+ var useGmDice = true;
+ var gmDiceSetting = findObjs({_type: "attribute",name: "use-gm-dice-pool-for-rolls",_characterid: eote.defaults['-DicePoolID']})[0];
+ if (typeof gmDiceSetting !== 'undefined') {
+ if (gmDiceSetting.get('current') == 0) {
+ useGmDice = false;
+ }
+ }
+ if (useGmDice) {
+ cmd = eote.process.gmdice(cmd); // update the cmd string to contain the gmdice
+ eote.process.logger("eote.process.setup.gmDice", "New command: " + cmd);
+ }
+ }
+ var encumMatch = cmd.match(eote.defaults.regex.encum);
+
+ if (encumMatch) {
+ diceObj = eote.process.encum(encumMatch, diceObj);
+ //eote.process.logger("eote.process.setup.encumMatch","New dice:" + diceObj);
+ }
+
+ var combatMatch = cmd.match(eote.defaults.regex.combat);
+ if (combatMatch) {
+ suggestionEngine.setCombatType(cmd[1]);
+ } else {
+ suggestionEngine.setCombatType(null);
+ }
+
+ var skillMatch = cmd.match(eote.defaults.regex.skill);
+ if (skillMatch) {
+ suggestionEngine.setIsFearCheck(getAttrByName(GMSheet.obj.id, "skill_suggestion_setting_fear"));
+ var CombatSuggestions = getAttrByName(GMSheet.obj.id, "skill_suggestion_setting_combat");
+ log("CombatSuggestions="+CombatSuggestions);
+ suggestionEngine.setCombatSuggestions(getAttrByName(GMSheet.obj.id, "skill_suggestion_setting_combat"));
+ var generalSuggestions = getAttrByName(GMSheet.obj.id, "skill_suggestion_setting_general");
+ log("generalSuggestions="+generalSuggestions);
+ suggestionEngine.setGeneralSuggestions(generalSuggestions);
+ suggestionEngine.setIsFearCheck(getAttrByName(GMSheet.obj.id, "skill_suggestion_setting_fear"));
+
+ suggestionEngine.setDisplayOption(getAttrByName(GMSheet.obj.id, "skill_suggestion_setting_display"));
+ diceObj = eote.process.skill(skillMatch, diceObj);
+ }
+
+ var opposedMatch = cmd.match(eote.defaults.regex.opposed);
+ if (opposedMatch) {
+ diceObj = eote.process.opposed(opposedMatch, diceObj);
+ }
+
+ var diceMatch = cmd.match(eote.defaults.regex.dice);
+ if (diceMatch) {
+ diceObj = eote.process.setDice(diceMatch, diceObj);
+ }
+
+ var upgradeMatch = cmd.match(eote.defaults.regex.upgrade);
+ if (upgradeMatch) {
+ diceObj = eote.process.upgrade(upgradeMatch, diceObj);
+ }
+
+ var downgradeMatch = cmd.match(eote.defaults.regex.downgrade);
+ if (downgradeMatch) {
+ diceObj = eote.process.downgrade(downgradeMatch, diceObj);
+ }
+
+ /* Roll dice and update success / fail
+ * ------------------------------------------------------------- */
+ diceObj = eote.process.rollDice(diceObj);
+
+ // process and display skill suggestions
+ if (diceObj.vars.skillName != null || suggestionEngine.getCombatType() != null) {
+ diceObj = suggestionEngine.processSuggestions(diceObj);
+ }
+
+ /* Custom rolls
+ * Description: Custom dice components have their own message, results and
+ * often will return false to not allow proceeding scripts to fire
+ * --------------------------------------------------------------*/
+ var resetdiceMatch = cmd.match(eote.defaults.regex.resetdice);
+
+ if (resetdiceMatch) {
+ eote.process.resetdice(resetdiceMatch, diceObj);
+ return false;
+ }
+ var initiativeMatch = cmd.match(eote.defaults.regex.initiative);
+
+ if (initiativeMatch) {
+ eote.process.initiative(initiativeMatch, diceObj);
+ //return false;
+ }
+ var destinyMatch = cmd.match(eote.defaults.regex.destiny);
+
+ if (destinyMatch) {
+ eote.process.logger("eote.process.setup.destiny", "Destiny Point Command");
+ var doRoll = eote.process.destiny(destinyMatch, diceObj);
+ if (!doRoll) {
+ return false;
+ }
+ }
+ var calculateDamageMatch = cmd.match(eote.defaults.regex.calculateDamage);
+
+ if (calculateDamageMatch) {
+ diceObj = eote.process.calculateDamage(calculateDamageMatch,diceObj);
+ }
+ var rollEnemyCritical = cmd.match(eote.defaults.regex.rollEnemyCritical);
+
+ if (rollEnemyCritical) {
+ eote.process.rollEnemyCritical(diceObj);
+ return false;
+ }
+
+ var rollRandomCritical = cmd.match(eote.defaults.regex.rollRandomCritical);
+
+ if (rollRandomCritical) {
+ eote.process.rollRandomCritical(diceObj);
+ return false;
+}
+
+ var critMatch = cmd.match(eote.defaults.regex.crit);
+
+ if (critMatch) {
+ eote.process.crit(critMatch, diceObj);
+ return false;
+ }
+ var critShipMatch = cmd.match(eote.defaults.regex.critShip);
+
+ if (critShipMatch) {
+ eote.process.crit(critShipMatch, diceObj);
+ return false;
+ }
+
+ /* Display dice output in chat window
+ * ------------------------------------------------------------- */
+ eote.process.diceOutput(diceObj, playerName, playerID);
+};
+
+/* DICE PROCESS FUNCTION
+*
+* ---------------------------------------------------------------- */
+
+
+
+eote.process.log = function (cmd) {
+
+ /* Log
+ * default: 'on' and 'single'
+ * Description: Sets the visual output in the chat window for the dice rolls
+ * Command: !eed log on|off|multi|single
+ * ---------------------------------------------------------------- */
+
+ switch (cmd[1]) {
+ case "on": //if 'on' outputs dice to chat window
+ eote.defaults.globalVars.diceLogChat = true;
+ sendChat("Dice System", 'Output rolled dice to chat window "On"');
+ break;
+ case "off": //if 'off' outputs only results to chat window
+ eote.defaults.globalVars.diceLogChat = false;
+ sendChat("Dice System", 'Output rolled dice to chat window "Off"');
+ break;
+ case "multi": //if 'multi' multiple sets dice per line
+ eote.defaults.globalVars.diceLogRolledOnOneLine = false;
+ sendChat("Dice System", 'Multiple line output "Off". NOTE: This setting can cause issues with the Roll Templates. Recommended setting is !eed log single');
+ break;
+ case "single": //if 'single' single set of dice per line
+ eote.defaults.globalVars.diceLogRolledOnOneLine = true;
+ sendChat("Dice System", 'Multiple line output "On"');
+ break;
+ }
+};
+
+eote.process.debug = function (cmd) {
+ switch (cmd[1]) {
+ case "on":
+ eote.defaults.globalVars.debugScript = true;
+ sendChat("Dice System", 'Debug Script "On"');
+ break;
+ case "off":
+ eote.defaults.globalVars.debugScript = false;
+ sendChat("Dice System", 'Debug Script "Off"');
+ break;
+ }
+};
+
+eote.process.fear = function (cmd) {
+
+ /* Fear
+ * Description: Sets the state of the Fear check status on the DicePool
+ * Command: !eed fear on|off
+ * ---------------------------------------------------------------- */
+
+ var value = null;
+ switch (cmd[1]) {
+ case "off":
+ value = 0;
+ break;
+ case "on":
+ value = 1;
+ break;
+ }
+
+ if (value != null) {
+ eote.updateAddAttribute(GMSheet.obj, {
+ name: "skill_suggestion_setting_fear",
+ current: value,
+ update: true
+ });
+ }
+};
+
+eote.process.suggestionDisplay = function (cmd) {
+
+ /* SuggestionDisplay
+ * Description: Sets the state of the skill_suggestion_setting_display check status on the DicePool
+ * Command: !eed suggestionDisplay none|whisper|always
+ * ---------------------------------------------------------------- */
+
+ /*TODO fix why suggestionDisplay is no longer working*/
+ var value = (suggestionEngine.enum.displayOptions.hasOwnProperty(cmd[1]) ? cmd[1] : null);
+
+ if (value != null) {
+ eote.updateAddAttribute(GMSheet.obj, {
+ name: "skill_suggestion_setting_display",
+ current: value,
+ update: true
+ });
+ } else {
+ sendChat("Error", "/w gm " + cmd[1] + " is not a valid argument for suggestionDisplay.");
+ }
+};
+
+eote.process.graphics = function (cmd) {
+
+ /* Graphics
+ * default: 'on' and 'm'
+ * Description: Sets chat window dice output as graphic, small, medium, or large if "on" or as text if "off"
+ * Command: !eed graphics on|off|s|m|l
+ * ---------------------------------------------------------------- */
+
+ //log(cmd[1]);
+ switch (cmd[1]) {
+ case "on":
+ eote.defaults.globalVars.diceGraphicsChat = true;
+ sendChat("Dice System", 'Chat graphics "On"');
+ break;
+ case "off":
+ eote.defaults.globalVars.diceGraphicsChat = false;
+ sendChat("Dice System", 'Chat graphics "Off"');
+ break;
+ case "s":
+ eote.defaults.globalVars.diceGraphicsChatSize = eote.defaults.graphics.SIZE.SMALL;
+ sendChat("Dice System", 'Chat graphics size "Small"');
+ break;
+ case "m":
+ eote.defaults.globalVars.diceGraphicsChatSize = eote.defaults.graphics.SIZE.MEDIUM;
+ sendChat("Dice System", 'Chat graphics size "Medium"');
+ break;
+ case "l":
+ eote.defaults.globalVars.diceGraphicsChatSize = eote.defaults.graphics.SIZE.LARGE;
+ sendChat("Dice System", 'Chat graphics size "Large"');
+ break;
+ }
+};
+
+eote.process.test = function (cmd) {
+
+ eote.process.logger("eote.process.test", cmd);
+
+ //Set test vars to true
+ eote.defaults.globalVars.diceTestEnabled = true;
+ tmpLogChat = eote.defaults.globalVars.diceLogChat;
+ tmpGraphicsChat = eote.defaults.globalVars.diceGraphicsChat;
+ eote.defaults.globalVars.diceLogChat = true;
+ eote.defaults.globalVars.diceGraphicsChat = true;
+
+ //Roll dice
+ eote.process.setup('!eed 1b 1g 1y 1blk 1p 1r 1w', 'GM', 'Dice Test');
+
+ //After test reset vars back
+ eote.defaults.globalVars.diceTestEnabled = false;
+ eote.defaults.globalVars.diceLogChat = tmpLogChat;
+ eote.defaults.globalVars.diceGraphicsChat = tmpGraphicsChat;
+};
+
+eote.process.rollPlayer = function (cmd, diceObj) {
+ //Build cmd string
+ //get characterID
+ //get skills
+ //get encum
+ //remove rollPlayer(xxxx) from string
+ var match = {
+ skill: /skill:(.*?)[\|\)]/,
+ encum: /encum/,
+ character: /character:(.*?)[\|\)]/
+ };
+ var characterMatch = cmd[1].match(match.character);
+
+ var companion = null;
+ var character = null;
+ if (characterMatch) {
+ var charObj = findObjs({ _type: "character", name: characterMatch[1] });
+
+ if (charObj.length > 0) {
+ diceObj.vars.characterName = charObj[0].get('name');
+ diceObj.vars.characterID = charObj[0].id;
+ }
+ else {
+ sendChat("Alert", "Can't find character. Please update character, or npc, name field to match sheet character name and try again.");
+ return false;
+ }
+ }
+ else {
+ sendChat("Alert", "Please update character, or npc, name field.");
+ return false;
+ }
+ var encumMatch = cmd[1].match(match.encum);
+ var attr_1 = null;
+ var attr_2 = null;
+ if (encumMatch) {
+ //encumbrance
+ attr_1 = getAttrByName(diceObj.vars.characterID, 'encumbrance', 'max');
+ attr_2 = getAttrByName(diceObj.vars.characterID, 'encumbrance');
+ var cmdEncum = ['encum(' + attr_1 + '|' + attr_2 + ')']; //["encum(3|5)"]
+
+ diceObj = eote.process.encum(cmdEncum, diceObj);
+ }
+ var skillMatch = cmd[1].match(match.skill);
+ if (eote.defaults.globalVars.debugScript) sendChat("Alert", "skillmatch=" + skillMatch.toString());
+
+ if (skillMatch) {
+
+ var attrArray = skillMatch[1].split(',');
+ attr_1 = getAttrByName(diceObj.vars.characterID, attrArray[0]);
+ attr_2 = getAttrByName(diceObj.vars.characterID, attrArray[1]);
+
+ if (eote.defaults.globalVars.debugScript) {
+ sendChat("Alert", "attr_1 = " + attr_1);
+ sendChat("Alert", "attr_2 = " + attr_2);
+ }
+
+ var cmdSkill;
+ if(!isNaN((parseFloat(attr_1)) && isFinite(attr_1))) { // is numeric
+ cmdSkill = ['skill(' + attr_1 + '|' + attr_2 + ')']; //['skill(0|2)']
+ } else {
+ var attr_3 = getAttrByName(diceObj.vars.characterID, attr_1.substr(2,attr_1.length-3));
+ cmdSkill = ['skill(' + attr_3 + '|' + attr_2 + ')']; //['skill(0|2)']
+ }
+
+ diceObj = eote.process.skill(cmdSkill, diceObj);
+ }
+ return diceObj;
+};
+
+eote.process.destiny = function (cmd, diceObj) {
+
+ var charObj_DicePool = findObjs({ _type: "character", name: "-DicePool" })[0];
+ var doRoll = false;
+
+ if (!charObj_DicePool) {
+ sendChat("GM", "/w " + "gm The DicePool character sheet could not be found! Re-save this script and it should be recreated. In the future do not rename the -DicePool Character Sheet.");
+ return doRoll;
+ }
+ //GM's Destiny Point Pool
+ var currentLightSidePoints = findObjs({
+ _characterid: charObj_DicePool.get("_id"),
+ _type: "attribute",
+ _name: "lightSidePoints"
+ });
+ var currentDarkSidePoints = findObjs({
+ _characterid: charObj_DicePool.get("_id"),
+ _type: "attribute",
+ _name: "darkSidePoints"
+ });
+ if (!currentDarkSidePoints[0] || !currentLightSidePoints[0]) {
+ sendChat("Dice System", "No Destiny Points Defined. The GM has been whispered with instructions to reset the Destiny Pool.");
+ sendChat("GM", "/w " + "gm The Destiny Pool system needs to be (or has been) reset. To fix this functionality, go to the -DicePool Character Sheet and add 1 dark side and 1 light side destiny point, then click the Force Player Update button. This should clear up the issue.");
+ return doRoll;
+ }
+ var darkSide = parseInt(currentDarkSidePoints[0].get("current"));
+ var lightSide = parseInt(currentLightSidePoints[0].get("current"));
+
+ var displayPool = '';
+ //noinspection FallThroughInSwitchStatementJS
+ switch (cmd[1]) {
+ case "useDark":
+ if (darkSide > 0) {
+ darkSide = darkSide - 1;
+ lightSide = lightSide + 1;
+
+ displayPool = '/direct &{template:base} {{title=' + 'The GM flips a Dark Side Destiny Point' + '}}';
+ displayPool = displayPool + '{{Dark Side points remaining=' + darkSide + '}}';
+ displayPool = displayPool + '{{New Light Side total=' + lightSide + '}}';
+
+ sendChat('Dice System', displayPool);
+ }
+ else {
+ sendChat("GM", "/w " + "gm There are no Dark Side points left in the Destiny Pool. Encourage your Players to use a Light Side Point." );
+ return doRoll;
+ }
+ break;
+ case "useLight":
+ if (lightSide > 0) {
+ lightSide = lightSide - 1;
+ darkSide = darkSide + 1;
+
+ displayPool = '/direct &{template:base} {{title=' + diceObj.vars.characterName + ' flips a Light Side Destiny Point' + '}}';
+ displayPool = displayPool + '{{New Dark Side total=' + darkSide + '}}';
+ displayPool = displayPool + '{{Light Side points remaining=' + lightSide + '}}';
+
+ sendChat('Dice System', displayPool);
+ }
+ else {
+ sendChat("Dice System", "/w " + diceObj.vars.characterName + " There are no Light Side points left in the Destiny Pool. Suggest to your GM to use a Dark Side point to make one available.");
+ return doRoll;
+ }
+ break;
+ case "doRoll":
+ sendChat(diceObj.vars.characterName, '/direct Rolling a Destiny Point.');
+ doRoll = true;
+ // falls through on purpose (I think) to sync automatically when destiny point is rolled
+ case "registerPlayer":
+ if (!doRoll) {
+ sendChat("Dice System", "/w " + diceObj.vars.characterName + '&{template:base} {{title=Syncing your Destiny Pool to the GM\'s}}');
+ }
+ darkSide = darkSide + diceObj.totals.dark;
+ lightSide = lightSide + diceObj.totals.light;
+
+ //Register
+ if (eote.defaults.destinyListeners.indexOf(diceObj.vars.characterID) == -1) {
+ eote.defaults.destinyListeners.push(diceObj.vars.characterID);
+ }
+ break;
+ case "sendUpdate":
+ sendChat("Dice System", "Updating Players Destiny Pools");
+ break;
+ case "clearPool":
+ sendChat("Dice System", '&{template:base} {{title=The GM cleared the Destiny Pool}}');
+ lightSide = 0;
+ darkSide = 0;
+ break;
+ }
+ var newDestPool = [
+ {
+ name: 'lightSidePoints',
+ current: lightSide,
+ max: '',
+ update: true
+ },
+ {
+ name: 'darkSidePoints',
+ current: darkSide,
+ max: '',
+ update: true
+ }
+ ];
+ eote.updateListeners(newDestPool);
+ return doRoll;
+};
+
+eote.process.characterID = function (cmd, diceObj) {
+
+ /* CharacterId
+ * default: null
+ * Description: looks up the characters name based on character ID
+ * Command: !eed characterID(##########)
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.characterID", cmd);
+
+ var characterID = cmd[1];
+
+ if (characterID) {
+
+ diceObj.vars.characterName = getObj("character", characterID).get('name');
+ diceObj.vars.characterID = characterID;
+ }
+ return diceObj;
+};
+
+eote.process.label = function (cmd, diceObj) {
+
+ /* Label
+ * default: null
+ * Description: set the skill name of the roll
+ * Command: !eed label(Name of Skill)
+ * ---------------------------------------------------------------- */
+ //log(cmd);
+
+ var label = cmd[1];
+
+ if (label) {
+
+ var labelStr = '';
+ var labelArray = label.split('|');
+
+ _.each(labelArray, function (labelVal) {
+ var labelArray = labelVal.split(':');
+ var label = labelArray[0];
+ var message = labelArray[1];
+ var labelTest = label.toLowerCase();
+
+ switch (labelTest) {
+ case 'skill':
+ labelStr = '{{title='+labelStr + message + '}}';
+ break;
+ case 'dice':
+ labelStr = '{{title='+labelStr + message + '}}';
+ break;
+ case 'weapon':
+ labelStr = '{{title='+labelStr + message + '}}';
+ break;
+ default:
+ labelStr = labelStr + '{{' + label + '=' + message + '}}';
+ }
+
+ });
+ diceObj.vars.label = labelStr;
+ }
+ return diceObj;
+};
+
+eote.process.resetdice = function (cmd, diceObj) {
+
+ var characterObj = [{ name: diceObj.vars.characterName, id: diceObj.vars.characterID }];
+ eote.process.logger("eote.process.resetdice", cmd);
+ var resetdice = [];
+
+ if (cmd[1] == 'resetdice') {
+ resetdice = [
+ {
+ name: "b",
+ current: 0,
+ update: true
+ },
+ {
+ name: "g",
+ current: 0,
+ update: true
+ },
+ {
+ name: "y",
+ current: 0,
+ update: true
+ },
+ {
+ name: "blk",
+ current: 0,
+ update: true
+ },
+ {
+ name: "r",
+ current: 0,
+ update: true
+ },
+ {
+ name: "p",
+ current: 0,
+ update: true
+ },
+ {
+ name: "w",
+ current: 0,
+ update: true
+ },
+ {
+ name: "upgradeAbility",
+ current: 0,
+ update: true
+ },
+ {
+ name: "downgradeProficiency",
+ current: 0,
+ update: true
+ },
+ {
+ name: "upgradeDifficulty",
+ current: 0,
+ update: true
+ },
+ {
+ name: "downgradeChallenge",
+ current: 0,
+ update: true
+ }
+ ];
+ }
+
+ if (cmd[1] == 'resetgmdice') {
+ resetdice = [
+ {
+ name: "bgm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "ggm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "ygm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "blkgm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "rgm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "pgm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "wgm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "upgradeAbilitygm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "downgradeProficiencygm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "upgradeDifficultygm",
+ current: 0,
+ update: true
+ },
+ {
+ name: "downgradeChallengegm",
+ current: 0,
+ update: true
+ }
+ ];
+ }
+ eote.updateAddAttribute(characterObj, resetdice);
+};
+
+eote.process.initiative = function (cmd, diceObj) {
+
+ /* initiative
+ * default: false
+ * Description: Set NPC/PC initiative true
+ * Command: !eed npcinit or pcinit
+ * ---------------------------------------------------------------- */
+
+ var type = '';
+ var NumSuccess = diceObj.totals.success;
+ var NumAdvantage = diceObj.totals.advantage;
+ var turnorder;
+
+ eote.process.logger("eote.process.initiative.diceObj", diceObj);
+ eote.process.logger("eote.process.initiative.NumSuccess", NumSuccess);
+ eote.process.logger("eote.process.initiativeNumAdvantage", NumAdvantage);
+
+ if (Campaign().get("turnorder") == "") turnorder = []; //NOTE: We check to make sure that the turnorder isn't just an empty string first. If it is treat it like an empty array.
+ else turnorder = JSON.parse(Campaign().get("turnorder"));
+
+ if (cmd[0] == 'pcinit') {
+ type = 'PC';
+ }
+
+ if (cmd[0] == 'npcinit') {
+ type = 'NPC';
+ }
+ //Add a new custom entry to the end of the turn order.
+ turnorder.push({
+ id: "-1",
+ pr: NumSuccess + ":" + NumAdvantage,
+ custom: type
+ });
+ turnorder.sort(function (x, y) {
+ // verify that x or y contains a colon, if it doesn't put it below
+ if (x.toString().indexOf(":") < 1 || y.toString().indexOf(":") < 1) {
+ return 1;
+ } else {
+ var a = x.pr.split(":");
+ var b = y.pr.split(":");
+
+ if (b[0] - a[0] != 0) {//First rank on successes
+ return b[0] - a[0];
+ } else if (b[1] - a[1] != 0) {//Then rank on Advantage
+ return b[1] - a[1];
+ } else { //If they are still tied, PC goes first
+
+ if (x.custom == y.custom) {
+ return 0;
+ } else if (x.custom == "NPC") {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ }
+ });
+ Campaign().set("turnorder", JSON.stringify(turnorder));
+};
+
+eote.process.calculateDamage = function (cmd, diceObj) {
+ var values = String(cmd[1]);
+ var splitCmd = values.split("|");
+ var baseDamage = parseInt(splitCmd[0]);
+ var critical = parseInt(splitCmd[1]);
+ var damageBonus = parseInt(splitCmd[2]);
+ if (isNaN(damageBonus)) {
+ damageBonus = 0;
+ }
+ var criticalBonus = parseInt(splitCmd[3]);
+ if (isNaN(criticalBonus)) {
+ criticalBonus = 0;
+ }
+ var i = 4;
+ while (i<17) {
+ var attachmentDamageBonus = parseInt(splitCmd[i]);
+ if ( ! isNaN(attachmentDamageBonus)) {
+ damageBonus += attachmentDamageBonus;
+ }
+ i = i+2;
+ }
+ var i = 5;
+ while (i<18) {
+ var attachmentCriticalBonus = parseInt(splitCmd[i]);
+ if ( ! isNaN(attachmentCriticalBonus)) {
+ criticalBonus += attachmentCriticalBonus;
+ }
+ i = i+2;
+ }
+
+ var globalDamageBonus = findObjs({_type: "attribute",name: "damage-bonus",_characterid: diceObj.vars.characterID})[0];
+ if (typeof globalDamageBonus !== 'undefined') {
+ globalDamageBonus = parseInt(globalDamageBonus.get('current'));
+ } else {
+ globalDamageBonus = 0;
+ }
+ var bonusText = "";
+ if (globalDamageBonus > 0 || damageBonus > 0) {
+ bonusText = " (after bonuses)";
+ }
+ var calculatedDamage = ((diceObj.totals.success + baseDamage) - 1) + damageBonus + globalDamageBonus;
+ if (diceObj.totals.success > 0) {
+ diceObj.vars.calculatedDamage = "{{Hit For=" + calculatedDamage + " " + bonusText + "}}";
+ } else {
+ diceObj.vars.calculatedDamage = "{{Hit For=0 }}";
+ }
+ if ((diceObj.totals.success > 0 ) && (diceObj.totals.advantage >= critical)) {
+ diceObj.vars.inflictedCritical = true;
+ diceObj.vars.calculatedDamage = diceObj.vars.calculatedDamage + "{{Critical Hit=Critical Hit! }}";
+ if (typeof criticalBonus !== 'undefined' && ! isNaN(criticalBonus) && criticalBonus > 0) {
+ diceObj.vars.weaponCriticalBonus = criticalBonus;
+ }
+ }
+ return diceObj;
+};
+
+var critTableLifeform = [
+ {
+ percent: '1 to 5',
+ severity: 1,
+ name: 'Minor Nick',
+ Result: 'Suffer 1 strain.'
+ },
+ {
+ percent: '6 to 10',
+ severity: 1,
+ name: 'Slowed Down',
+ Result: 'May only act during last allied Initiative slot on next turn.'
+ },
+ {
+ percent: '11 to 15',
+ severity: 1,
+ name: 'Sudden Jolt',
+ Result: 'May only act during last hero Initiative slot on next turn.'
+ },
+ {
+ percent: '16 to 20',
+ severity: 1,
+ name: 'Distracted',
+ Result: 'Cannot perform free maneuver on next turn.'
+ },
+ {
+ percent: '21 to 25',
+ severity: 1,
+ name: 'Off-Balance',
+ Result: 'Add 1 Setback die to next skill check.'
+ },
+ {
+ percent: '26 to 30',
+ severity: 1,
+ name: 'Discouraging Wound',
+ Result: 'Flip one light destiny to dark.'
+ },
+ {
+ percent: '31 to 35',
+ severity: 1,
+ name: 'Stunned',
+ Result: 'Staggered, cannot perform action on next turn.'
+ },
+ {
+ percent: '36 to 40',
+ severity: 1,
+ name: 'Stinger',
+ Result: 'Increase difficulty of next check by 1 Difficulty die.'
+ },
+ //----------------------------- Severity 2
+ {
+ percent: '41 to 45',
+ severity: 2,
+ name: 'Bowled Over',
+ Result: 'Knocked prone and suffer 1 strain.'
+ },
+ {
+ percent: '46 to 50',
+ severity: 2,
+ name: 'Head Ringer',
+ Result: 'Increase difficulty of all Intellect and Cunning checks by 1 Difficulty die until end of encounter.'
+ },
+ {
+ percent: '51 to 55',
+ severity: 2,
+ name: 'Fearsome Wound',
+ Result: 'Increase difficulty of all Presence and Willpower checks by 1 Difficulty die until end of encounter.'
+ },
+ {
+ percent: '56 to 60',
+ severity: 2,
+ name: 'Agonizing Wound',
+ Result: 'Increase difficulty of all Brawn and Agility checks by 1 Difficulty die until end of encounter.'
+ },
+ {
+ percent: '61 to 65',
+ severity: 2,
+ name: 'Slightly Dazed',
+ Result: 'Add 1 Setback die to all skill checks until end of encounter.'
+ },
+ {
+ percent: '66 to 70',
+ severity: 2,
+ name: 'Scattered Senses',
+ Result: 'Remove all Boost dice from all skill checks until end of encounter.'
+ },
+ {
+ percent: '71 to 75',
+ severity: 2,
+ name: 'Hamstrung',
+ Result: 'Lose free maneuver until end of encounter.'
+ },
+ {
+ percent: '76 to 80',
+ severity: 2,
+ name: 'Staggered',
+ Result: 'Attacker may immediately attempt another free attack against you using same dice pool as original attack.'
+ },
+ {
+ percent: '81 to 85',
+ severity: 2,
+ name: 'Winded',
+ Result: 'Cannot voluntarily suffer strain to activate abilities or gain additional maneuvers until end of encounter.'
+ },
+ {
+ percent: '86 to 90',
+ severity: 2,
+ name: 'Compromised',
+ Result: 'Increase difficulty of all skill checks by 1 Difficulty die until end of encounter.'
+ },
+ //---------------------------------------- Severity 3
+ {
+ percent: '91 to 95',
+ severity: 3,
+ name: 'At the Brink',
+ Result: 'Suffer 1 strain each time you perform an action.'
+ },
+ {
+ percent: '96 to 100',
+ severity: 3,
+ name: 'Crippled',
+ Result: 'Limb crippled until healed or replaced. Increase difficulty of all checks that use that limb by 1 Difficulty die.'
+ },
+ {
+ percent: '101 to 105',
+ severity: 3,
+ name: 'Maimed',
+ Result: 'Limb permanently lost. Unless you have a cybernetic replacement, cannot perform actions that use that limb. Add 1 Setback to all other actions.'
+ },
+ {
+ percent: '106 to 110',
+ severity: 3,
+ name: 'Horrific Injury',
+ Result: 'Roll 1d10 to determine one wounded characteristic -- roll results(1-3 = Brawn, 4-6 = Agility, 7 = Intellect, 8 = Cunning, 9 = Presence, 10 = Willpower. Until Healed, treat characteristic as one point lower.'
+ },
+ {
+ percent: '111 to 115',
+ severity: 3,
+ name: 'Temporarily Lame',
+ Result: 'Until healed, may not perform more than one maneuver each turn.'
+ },
+ {
+ percent: '116 to 120',
+ severity: 3,
+ name: 'Blinded',
+ Result: 'Can no longer see. Upgrade the difficulty of Perception and Vigilance checks three times, and all other checks twice.'
+ },
+ {
+ percent: '121 to 125',
+ severity: 3,
+ name: 'Knocked Senseless',
+ Result: 'You can no longer upgrade dice for checks.'
+ },
+ //---------------------------------------- Severity 4
+ {
+ percent: '126 to 130',
+ severity: 4,
+ name: 'Gruesome Injury',
+ Result: 'Roll 1d10 to determine one wounded characteristic -- roll results(1-3 = Brawn, 4-6 = Agility, 7 = Intellect, 8 = Cunning, 9 = Presence, 10 = Willpower. Characteristic is permanently one point lower.'
+ },
+ {
+ percent: '131 to 140',
+ severity: 4,
+ name: 'Bleeding Out',
+ Result: 'Suffer 1 wound and 1 strain every round at the beginning of turn. For every 5 wounds suffered beyond wound threshold, suffer one additional Critical Injury (ignore the details for any result below this result).'
+ },
+ {
+ percent: '141 to 150',
+ severity: 4,
+ name: 'The End is Nigh',
+ Result: 'Die after the last Initiative slot during the next round.'
+ },
+ {
+ percent: '151',
+ severity: 4,
+ name: 'Dead',
+ Result: 'Complete, absolute death.'
+ }
+];
+var critTableMachine = [
+ {
+ percent: '1 to 9',
+ severity: 1,
+ name: 'Mechanical Stress',
+ Result: 'Ship or vehicle suffers 1 system strain.'
+ },
+ {
+ percent: '10 to 18',
+ severity: 1,
+ name: 'Jostled',
+ Result: 'All crew members suffer 1 strain.'
+ },
+ {
+ percent: '19 to 27',
+ severity: 1,
+ name: 'Losing Power to Shields',
+ Result: 'Decrease defense in affected defense zone by 1 until repaired. If ship or vehicle has no defense, suffer 1 system strain.'
+ },
+ {
+ percent: '28 to 36',
+ severity: 1,
+ name: 'Knocked Off Course',
+ Result: 'On next turn, pilot cannot execute any maneuvers. Instead, must make a Piloting check to regain bearings and resume course. Difficulty depends on current speed.'
+ },
+ {
+ percent: '37 to 45',
+ severity: 1,
+ name: 'Tailspin',
+ Result: 'All firing from ship or vehicle suffers 2 setback dice until end of pilot\'s next turn.'
+ },
+ {
+ percent: '46 to 54',
+ severity: 1,
+ name: 'Component Hit',
+ Result: 'One component of the attacker\'s choice is knocked offline, and is rendered inoperable until the end of the following round. See page 245 CRB for Small/Large Vehicle and Ship Component tables. '
+ },
+ // --------------- severity : 2
+ {
+ percent: '55 to 63',
+ severity: 2,
+ name: 'Shields Failing',
+ Result: 'Decrease defense in all defense zones by 1 until repaired. If ship or vehicle has no defense, suffer 2 system strain.'
+ },
+ {
+ percent: '64 to 72',
+ severity: 2,
+ name: 'Hyperdrive or Navicomputer Failure',
+ Result: 'Cannot make any jump to hyperspace until repaired. If ship or vehicle has no hyperdrive, navigation systems fail leaving it unable to tell where it is or is going.'
+ },
+ {
+ percent: '73 to 81',
+ severity: 2,
+ name: 'Power Fluctuations',
+ Result: 'Pilot cannot voluntarily inflict system strain on the ship until repaired.'
+ },
+ // --------------- severity : 3
+ {
+ percent: '82 to 90',
+ severity: 3,
+ name: 'Shields Down',
+ Result: 'Decrease defense in affected defense zone to 0 and all other defense zones by 1 point until repaired. If ship or vehicle has no defense, suffer 4 system strain.'
+ },
+ {
+ percent: '91 to 99',
+ severity: 3,
+ name: 'Engine Damaged',
+ Result: 'Ship or vehicle\'s maximum speed reduced by 1, to a minimum of 1, until repaired.'
+ },
+ {
+ percent: '100 to 108',
+ severity: 3,
+ name: 'Shield Overload',
+ Result: 'Decrease defense in all defense zones to 0 until repaired. In addition, suffer 2 system strain. Cannot be repaired until end of encounter. If ship or vehicle has no defense, reduce armor by 1 until repaired.'
+ },
+ {
+ percent: '109 to 117',
+ severity: 3,
+ name: 'Engines Down',
+ Result: 'Ship or vehicle\'s maximum speed reduced to 0. In addition, ship or vehicle cannot execute maneuvers until repaired. Ship continues on course at current speed and cannot be stopped or course changed until repaired.'
+ },
+ {
+ percent: '118 to 126',
+ severity: 3,
+ name: 'Major System Failure',
+ Result: 'One component of the attacker\'s choice is heavily damages, and is inoperable until the critical hit is repaired. See page 245 CRB for Small/Large Vehicle and Ship Component tables. '
+ },
+ // --------------- severity : 4
+ {
+ percent: '127 to 133',
+ severity: 4,
+ name: 'Major Hull Breach',
+ Result: 'Ships and vehicles of silhouette 4 and smaller depressurize in a number of rounds equal to silhouette. Ships of silhouette 5 and larger don\'t completely depressurize, but parts do (specifics at GM discretion). Ships and vehicles operating in atmosphere instead suffer a Destabilized Critical.'
+ },
+ {
+ percent: '134 to 138',
+ severity: 4,
+ name: 'Destabilised',
+ Result: 'Reduce ship or vehicle\'s hull integrity threshold and system strain threshold to half original values until repaired.'
+ },
+ {
+ percent: '139 to 144',
+ severity: 4,
+ name: 'Fire!',
+ Result: 'Fire rages through ship or vehicle and it immediately takes 2 system strain. Fire can be extinguished with appropriate skill, Vigilance or Cool checks at GM\'s discretion. Takes one round per two silhouette to put out.'
+ },
+ {
+ percent: '145 to 153',
+ severity: 4,
+ name: 'Breaking Up',
+ Result: 'At the end of next round, ship is completely destroyed. Anyone aboard has one round to reach escape pod or bail out before they are lost.'
+ },
+ {
+ percent: '154+',
+ severity: 4,
+ name: 'Vaporized',
+ Result: 'The ship or Vehicle is completely destroyed.'
+ }
+];
+
+eote.process.crit = function (cmd, diceObj) {
+
+ /* Crit
+ * default:
+ * Description: Rolls critical injury table
+ * Command: !eed crit(roll) crit(roll|#) crit(heal|#)
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.crit", "");
+
+ var characterObj = [{ name: diceObj.vars.characterName, id: diceObj.vars.characterID }];
+ var critRoll = function (addCritNum, type) {
+ var openSlot = false;
+ var diceRoll = '';
+ var critMod = '';
+ var rollTotal = '';
+ var rollOffset = parseInt(getAttrByName(diceObj.vars.characterID, type + '-critAddOffset'));
+ rollOffset = rollOffset ? rollOffset : 0;
+ var totalcrits = parseInt(getAttrByName(diceObj.vars.characterID, type + '-critTotal'));
+ if(!totalcrits){
+ totalcrits = 0;
+ }
+
+ //roll random
+ if (!addCritNum) {
+ diceRoll = randomInteger(100);
+ critMod = (totalcrits * 10);
+ rollTotal = diceRoll + critMod + rollOffset;
+ rollTotal = rollTotal < 1 ? 1 : rollTotal;
+ eote.process.logger("critRoll", "diceRoll: " + diceRoll);
+ eote.process.logger("critRoll", "critMod: " + critMod);
+ eote.process.logger("critRoll", "rollTotal " + rollTotal);
+ } else {
+ rollTotal = parseInt(addCritNum);
+ }
+ //find crit in critical table
+ if(type=="character" || type=="npc" || type == "companion" || type=="beast"){
+ critTable = critTableLifeform;
+ }
+ if(type=="starship" || type=="vehicle"){
+ critTable = critTableMachine;
+ }
+ for (var key in critTable) {
+ var percent = critTable[key].percent.split(' to ');
+ var low = parseInt(percent[0]);
+ var high = percent[1] ? parseInt(percent[1]) : 1000;
+
+ if ((rollTotal >= low) && (rollTotal <= high)) {
+
+ critAttrs = [
+ {
+ name: type + '-critTotal',
+ current: totalcrits+1,
+ max: '',
+ update: true
+ },
+ ];
+ critAttrs2 = [
+ {
+ name: type + '-critName',
+ current: critTable[key].name,
+ max: '',
+ update: true
+ },
+ {
+ name: type + '-critSeverity' ,
+ current: critTable[key].severity,
+ max: '',
+ update: true
+ },
+ {
+ name: type + '-critRange',
+ current: critTable[key].percent,
+ max: '',
+ update: true
+ },
+ {
+ name: type + '-critSummary',
+ current: critTable[key].Result,
+ max: '',
+ update: true
+ },
+ ];
+ var chat = '/direct &{template:critical} {{title='+type.charAt(0).toUpperCase()+type.slice(1)+' Critical}} ';
+ chat = chat + '{{subtitle=' + diceObj.vars.characterName + '}}';
+ chat = chat + '{{Previous Criticals=' + totalcrits + ' x 10}}';
+ if (rollOffset) {
+ chat = chat + '{{Dice Roll Offset=' + rollOffset + '}}';
+ }
+ chat = chat + '{{Dice Roll=' + diceRoll + '}}';
+ chat = chat + '{{Total=' + rollTotal + '}}';
+ chat = chat + '{{wide=' + critTable[key].name + ' ';
+ chat = chat + critTable[key].Result + '
}}';
+
+ sendChat(diceObj.vars.characterName, chat);
+ }
+ }
+ eote.updateAddAttribute(characterObj, critAttrs);
+ eote.process.createRepeatingCrit(type,characterObj,critAttrs2);
+ };
+ var critHeal = function (critID, type) {
+ log(critID);
+ log(type);
+ var rowid = critID;
+ var regex = new RegExp('^repeating_.*?_' + rowid + '_.*?$');
+ var attrsInRow = filterObjs(function(obj) {
+ if (obj.get('type') !== 'attribute' || obj.get('characterid') !== diceObj.vars.characterID) return false;
+ return regex.test(obj.get('name'));
+ });
+ _.each(attrsInRow, function (attribute) {//loop characters
+ attribute.remove();
+ });
+ var totalcrits = parseInt(getAttrByName(diceObj.vars.characterID, type + '-critTotal'));
+ critAttrs = [
+ {
+ name: type + '-critTotal',
+ current: totalcrits-1,
+ max: '',
+ update: true
+ },
+
+ ];
+ eote.updateAddAttribute(characterObj, critAttrs);
+ };
+ var critArray = cmd[1].split('|');
+ var command = critArray[0];
+ var type = critArray[1] ? critArray[1] : null;
+ var input = critArray[2] ? critArray[2] : null;
+
+ if (type == null) {
+ sendChat("Alert", "Type not supplied. Needs character, companion or beast");
+ return;
+ }
+
+ if (command == 'heal') {
+ critHeal(input, type);
+ } else if (command == 'add') {
+ critRoll(input, type);
+ } else { // crit(roll)
+ critRoll(null, type);
+ }
+};
+eote.process.createRepeatingCrit = function(type,charactersObj,critAttrs) {
+ eote.process.logger("repeating","repeating");
+ eote.process.logger("type",type);
+ eote.process.logger("critAttrs",critAttrs);
+ var newId = eote.process.generateRowID();
+ //check if object or array
+ if (!_.isArray(charactersObj)) {
+ charactersObj = [charactersObj];
+ }
+ if (!_.isArray(critAttrs)) {
+ critAttrs = [critAttrs];
+ }
+ var characterId = "";
+ _.each(charactersObj, function (characterObj) {//loop characters
+
+ var characterName = '';
+
+ if (characterObj.name) {
+ characterName = characterObj.name;
+ } else {
+ characterName = characterObj.get('name');
+ }
+ characterId = characterObj.id;
+ //find attribute via character ID
+ var characterAttributesObj = findObjs({ _type: "attribute", characterid: characterObj.id });
+
+ if (critAttrs.length != 0) {
+
+ log('UPDATE/ADD ATTRIBUTES FOR:----------------------->' + characterName);
+
+ _.each(critAttrs, function (critAttr) { //loop attributes to update / add
+
+ attr = _.find(characterAttributesObj, function (a) {
+ return (a.get('name') === critAttr.name);
+ });
+ if (attr) {
+ if (critAttr.update) {
+ log('Update Attr: ' + critAttr.name);
+ attr.set({ current: critAttr.current });
+ attr.set({ max: critAttr.max ? critAttr.max : '' });
+ }
+ } else {
+ log('Add Attr: '+ critAttr.name);
+ log( 'Value: '+ critAttr.current);
+ eote.createObj('attribute', {
+ characterid: characterObj.id,
+ name: "repeating_crit"+type+"_" + newId + "_" + critAttr.name,
+ current: critAttr.current,
+ max: critAttr.max ? critAttr.max : ''
+ });
+ }
+ });
+ }
+ });
+ eote.createObj('attribute', {
+ characterid: characterId,
+ name: "repeating_crit"+type+"_" + newId + "_"+type+"-critId",
+ current: newId
+ });
+
+};
+
+
+
+eote.process.generateRowID = function () {
+ "use strict";
+ var a = 0, b = [];
+ var c = (new Date()).getTime() + 0, d = c === a;
+ a = c;
+ for (var e = new Array(8), f = 7; 0 <= f; f--) {
+ e[f] = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(c % 64);
+ c = Math.floor(c / 64);
+ }
+ c = e.join("");
+ if (d) {
+ for (f = 11; 0 <= f && 63 === b[f]; f--) {
+ b[f] = 0;
+ }
+ b[f]++;
+ } else {
+ for (f = 0; 12 > f; f++) {
+ b[f] = Math.floor(64 * Math.random());
+ }
+ }
+ for (f = 0; 12 > f; f++){
+ c += "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(b[f]);
+ }
+ return c.replace(/_/g, "Z");
+};
+
+
+eote.process.gmdice = function (cmd) {
+
+ /* gmdice
+ * default: g
+ * Description: Update CMD string to include -DicePool dice
+ * Command: (gmdice)
+ * ---------------------------------------------------------------- */
+
+ //var charObj = findObjs({ _type: "character", name: "-DicePool" });
+ var charID = eote.defaults['-DicePoolID'];//charObj[0].id;
+
+ var g = getAttrByName(charID, 'ggm');
+ var y = getAttrByName(charID, 'ygm');
+ var p = getAttrByName(charID, 'pgm');
+ var r = getAttrByName(charID, 'rgm');
+ var b = getAttrByName(charID, 'bgm');
+ var blk = getAttrByName(charID, 'blkgm');
+ var w = getAttrByName(charID, 'wgm');
+ var upAbility = getAttrByName(charID, 'upgradeAbilitygm');
+ var upDifficulty = getAttrByName(charID, 'upgradeDifficultygm');
+ var downProficiency = getAttrByName(charID, 'downgradeProficiencygm');
+ var downChallenge = getAttrByName(charID, 'downgradeChallengegm');
+
+ var gmdiceCMD = g + 'g ' + y + 'y ' + p + 'p ' + r + 'r ' + b + 'b ' + blk + 'blk ' + w + 'w upgrade(ability|' + upAbility + ') downgrade(proficiency|' + downProficiency + ') upgrade(difficulty|' + upDifficulty + ') downgrade(challenge|' + downChallenge + ')';
+
+ eote.process.logger("eote.process.gmDice.charID", charID);
+ cmd = cmd.replace('(gmdice)', gmdiceCMD);
+ //log(cmd);
+ return cmd;
+};
+
+eote.process.encum = function (cmd, diceObj) {
+
+ /* Encumberment
+ * default:
+ * Description: If the current encum is great than threshold add 1 setback per unit over current encum
+ * Command: !eed encum(encum_current|encum_threshold)
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.encum", cmd);
+
+ _.each(cmd, function (encum) {
+
+ var diceArray = encum.match(/\((.*?)\|(.*?)\)/);
+
+ if (diceArray && diceArray[1] && diceArray[2]) {
+
+ var num1 = eote.process.math(diceArray[1]);
+ var num2 = eote.process.math(diceArray[2]);
+ var setbackDice = diceObj.count.setback;
+
+ if (num2 > num1) {
+ diceObj.count.setback = setbackDice + (num2 - num1);
+ eote.process.logger("eote.process.encum.NewSetbackTotal", diceObj.count.setback + "blk");
+ //sendChat("Dice System", "/w " + diceObj.vars.characterName + " **Overencumbered** " + diceObj.count.setback + " Setbacks added");
+ }
+ else {
+ eote.process.logger("eote.process.encum", "No New Setback");
+ }
+ }
+ });
+ return diceObj;
+};
+
+eote.process.skill = function (cmd, diceObj) {
+
+ /* Skill
+ * default:
+ * Description: create the ability and proficiency dice for a skill check
+ * Command: !eed skill(char_value|skill_value|[NPC minion group size]|[Is minion skill])
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.skill", cmd);
+
+ _.each(cmd, function (skill) {
+ var matchers = {
+ matchNPCGroupWSkillName: /\((.*?)\|(.*?)\|(.*?)\|(.*?)\|(.*?)\)/,
+ matchNPCGroupWOSkillName: /\((.*?)\|(.*?)\|(.*?)\|(.*?)\)/,
+ matchRegSkillWSkillName: /\((.*?)\|(.*?)\|(.*?)\)/,
+ matchRegSkillWOSkillName: /\((.*?)\|(.*?)\)/
+ };
+ var diceArray = null;
+ Object.keys(matchers).some(function(key) {
+ if ((diceArray = skill.match(matchers[key])) != null) {
+ return true;
+ }
+ });
+
+ if (diceArray && diceArray[1] && diceArray[2]) {
+ var num1 = eote.process.math(diceArray[1]);
+ if (diceArray[3] && diceArray[4] && diceArray[4] === "1") {
+ num1 += (eote.process.math(diceArray[3]) - 1);
+ }
+ var num2 = eote.process.math(diceArray[2]);
+ var totalAbil = Math.abs(num1 - num2);
+ var totalProf = (num1 < num2 ? num1 : num2);
+ var abilityDice = diceObj.count.ability;
+ var proficiencyDice = diceObj.count.proficiency;
+
+ diceObj.count.ability = abilityDice + totalAbil;
+ diceObj.count.proficiency = proficiencyDice + totalProf;
+
+ // check for skill name
+ if (diceArray[5] || diceArray[3] && !diceArray[4]) {
+ var name = (diceArray[5] ? diceArray[5] : diceArray[3]);
+
+ /* remove all non-letter characters to bring the name in line with the JSON properties
+ * in order to have the closest chance in getting a match.
+ *
+ * does not guarantee a match.
+ */
+ name = name.replace(/[^A-Za-z]/g, "");
+
+ diceObj.vars.skillName = name;
+ } else {
+ diceObj.vars.skillName = null;
+ }
+
+ eote.process.logger("eote.process.skill.abilityTotal", diceObj.count.ability + "g");
+ eote.process.logger("eote.process.skill.proficiencyTotal", diceObj.count.proficiency + "y");
+ }
+
+ });
+ return diceObj;
+};
+
+eote.process.opposed = function (cmd, diceObj) {
+ /*Opposed
+ * default:
+ * Description: create the difficulty and challenge dice for an opposed skill check
+ * Command: !eed opposed(char_value|skill_value)
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.opposed", cmd);
+
+ _.each(cmd, function (opposed) {
+
+ var diceArray = opposed.match(/\((.*?)\|(.*?)\)/);
+
+ if (diceArray && diceArray[1] && diceArray[2]) {
+ var num1 = eote.process.math(diceArray[1]);
+ var num2 = eote.process.math(diceArray[2]);
+ var totalOppDiff = Math.abs(num1 - num2);
+ var totalOppChal = (num1 < num2 ? num1 : num2);
+ var opposeddifficultyDice = diceObj.count.difficulty;
+ var opposedchallengeDice = diceObj.count.challenge;
+ diceObj.count.difficulty = opposeddifficultyDice + totalOppDiff;
+ diceObj.count.challenge = opposedchallengeDice + totalOppChal;
+ }
+ });
+ return diceObj;
+};
+
+eote.process.setDice = function (cmd, diceObj) {
+
+ /* setDice
+ * default:
+ * Description: Loop thru the dice and adds or subtracts them from the dice object
+ * Command: !eed g# y# b# blk# r# p# w# or g#+# or g#-#
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.setDice", cmd);
+
+ _.each(cmd, function (dice) {
+
+ var diceArray = dice.match(/(-?\d{1,2})(\w{1,3})/);
+
+ if (diceArray && diceArray[1] && diceArray[2]) {
+
+ var diceQty = eote.process.math(diceArray[1]);
+ diceQty = (isNaN(diceQty) ? 0 : diceQty);
+
+ var abilityDice = diceObj.count.ability;
+ var proficiencyDice = diceObj.count.proficiency;
+ var difficultyDice = diceObj.count.difficulty;
+ var challengeDice = diceObj.count.challenge;
+ var boostDice = diceObj.count.boost;
+ var setbackDice = diceObj.count.setback;
+ var forceDice = diceObj.count.force;
+ var success = diceObj.count.success;
+ var advantage = diceObj.count.advantage;
+ var threat = diceObj.count.threat;
+ var failure = diceObj.count.failure;
+
+ switch (diceArray[2]) {
+ case 'b':
+ diceObj.count.boost = boostDice + diceQty;
+ break;
+ case 'g':
+ diceObj.count.ability = abilityDice + diceQty;
+ break;
+ case 'y':
+ diceObj.count.proficiency = proficiencyDice + diceQty;
+ break;
+ case 'blk':
+ diceObj.count.setback = setbackDice + diceQty;
+ break;
+ case 'p':
+ diceObj.count.difficulty = difficultyDice + diceQty;
+ break;
+ case 'r':
+ diceObj.count.challenge = challengeDice + diceQty;
+ break;
+ case 'w':
+ diceObj.count.force = forceDice + diceQty;
+ break;
+ case 's':
+ diceObj.count.success = success + diceQty;
+ break;
+ case 'a':
+ diceObj.count.advantage = advantage + diceQty;
+ break;
+ case 't':
+ diceObj.count.threat = threat + diceQty;
+ break;
+ case 'f':
+ diceObj.count.failure = failure + diceQty;
+ break;
+ }
+ }
+ });
+ diceObj = eote.process.checkNegative(diceObj);
+
+ eote.process.logger("eote.process.setDice.DiceToRoll", diceObj.count.boost + "b," + diceObj.count.ability + "g," + diceObj.count.proficiency + "y," + diceObj.count.setback + "blk," + diceObj.count.difficulty + "p," + diceObj.count.challenge + "r," + diceObj.count.force + "w," + diceObj.count.advantage + "a," + diceObj.count.threat + "t," + diceObj.count.failure + "f");
+
+ return diceObj;
+};
+
+eote.process.checkNegative = function (diceObj) {
+ if (diceObj.count.boost < 0) {
+ eote.process.logger("eote.process.checkNegative.boost", "Setting count to 0 for being negative.");
+ diceObj.count.boost = 0;
+ }
+ if (diceObj.count.ability < 0) {
+ eote.process.logger("eote.process.checkNegative.ability", "Setting count to 0 for being negative.");
+ diceObj.count.ability = 0;
+ }
+ if (diceObj.count.proficiency < 0) {
+ eote.process.logger("eote.process.checkNegative.proficiency", "Setting count to 0 for being negative.");
+ diceObj.count.proficiency = 0;
+ }
+ if (diceObj.count.setback < 0) {
+ eote.process.logger("eote.process.checkNegative.setback", "Setting count to 0 for being negative.");
+ diceObj.count.setback = 0;
+ }
+ if (diceObj.count.difficulty < 0) {
+ eote.process.logger("eote.process.checkNegative.difficulty", "Setting count to 0 for being negative.");
+ diceObj.count.difficulty = 0;
+ }
+ if (diceObj.count.challenge < 0) {
+ eote.process.logger("eote.process.checkNegative.challenge", "Setting count to 0 for being negative.");
+ diceObj.count.challenge = 0;
+ }
+ if (diceObj.count.force < 0) {
+ eote.process.logger("eote.process.checkNegative.force", "Setting count to 0 for being negative.");
+ diceObj.count.force = 0;
+ }
+ if (diceObj.count.success < 0) {
+ eote.process.logger("eote.process.checkNegative.success", "Setting count to 0 for being negative.");
+ diceObj.count.success = 0;
+ }
+ if (diceObj.count.advantage < 0) {
+ eote.process.logger("eote.process.checkNegative.advantage", "Setting count to 0 for being negative.");
+ diceObj.count.advantage = 0;
+ }
+ if (diceObj.count.threat < 0) {
+ eote.process.logger("eote.process.checkNegative.threat", "Setting count to 0 for being negative.");
+ diceObj.count.threat = 0;
+ }
+ if (diceObj.count.failure < 0) {
+ eote.process.logger("eote.process.checkNegative.failure", "Setting count to 0 for being negative.");
+ diceObj.count.failure = 0;
+ }
+ return diceObj;
+};
+
+eote.process.upgrade = function (cmd, diceObj) {
+
+ /* Upgrade
+ * default:
+ * Description: upgrades ability and difficulty dice
+ * Command: !eed upgrade(ability|#) or upgrade(difficulty|#)
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.upgrade", cmd);
+
+ _.each(cmd, function (dice) {
+
+ var diceArray = dice.match(/\((.*?)\|(.*?)\)/);
+
+ if (diceArray && diceArray[1] && diceArray[2]) {
+
+ var type = diceArray[1];
+ var upgradeVal = eote.process.math(diceArray[2]);
+ var abilityDice = diceObj.count.ability;
+ var proficiencyDice = diceObj.count.proficiency;
+ var difficultyDice = diceObj.count.difficulty;
+ var challengeDice = diceObj.count.challenge;
+
+ switch (type) {
+ case 'ability':
+
+ var totalProf = (upgradeVal < abilityDice ? upgradeVal : abilityDice);
+ var totalAbil = Math.abs(upgradeVal - abilityDice);
+
+ if (upgradeVal > abilityDice) {
+ totalProf = totalProf + Math.floor(totalAbil / 2);
+ totalAbil = totalAbil % 2;
+ }
+ diceObj.count.ability = totalAbil;
+ diceObj.count.proficiency = proficiencyDice + totalProf;
+
+ eote.process.logger("eote.process.upgrade.abilityTotal", diceObj.count.ability + "g");
+ eote.process.logger("eote.process.upgrade.proficiencyTotal", diceObj.count.proficiency + "y");
+
+ break;
+ case 'difficulty':
+
+ var totalChall = (upgradeVal < difficultyDice ? upgradeVal : difficultyDice);
+ var totalDiff = Math.abs(upgradeVal - difficultyDice);
+
+ if (upgradeVal > difficultyDice) {
+ totalChall = totalChall + Math.floor(totalDiff / 2);
+ totalDiff = totalDiff % 2;
+ }
+ diceObj.count.difficulty = totalDiff;
+ diceObj.count.challenge = challengeDice + totalChall;
+
+ eote.process.logger("eote.process.upgrade.difficultyTotal", diceObj.count.difficulty + "p");
+ eote.process.logger("eote.process.upgrade.challengeTotal", diceObj.count.challenge + "r");
+
+ break;
+ }
+ }
+ });
+ return diceObj;
+};
+
+eote.process.downgrade = function (cmd, diceObj) {
+
+ /* Downgrade
+ * default:
+ * Description: downgrades proficiency and challenge dice
+ * Command: !eed downgrade(proficiency|#) or downgrade(challenge|#)
+ * ---------------------------------------------------------------- */
+
+ eote.process.logger("eote.process.downgrade", cmd);
+
+ _.each(cmd, function (dice) {
+
+ var diceArray = dice.match(/\((.*?)\|(.*?)\)/);
+
+ if (diceArray && diceArray[1] && diceArray[2]) {
+
+ var type = diceArray[1];
+ var downgradeVal = eote.process.math(diceArray[2]);
+ var abilityDice = diceObj.count.ability;
+ var proficiencyDice = diceObj.count.proficiency;
+ var difficultyDice = diceObj.count.difficulty;
+ var challengeDice = diceObj.count.challenge;
+
+ switch (type) {
+ case 'proficiency':
+
+ var profConvertedToAbil = proficiencyDice * 2;
+
+ if (downgradeVal > (abilityDice + profConvertedToAbil)) {
+ diceObj.count.ability = 0;
+ diceObj.count.proficiency = 0;
+ } else if (downgradeVal > profConvertedToAbil) {
+ downgradeVal = Math.abs(downgradeVal - profConvertedToAbil);
+ diceObj.count.ability = Math.abs(downgradeVal - abilityDice);
+ diceObj.count.proficiency = 0;
+ } else {
+ diceObj.count.ability = abilityDice + (profConvertedToAbil - downgradeVal) % 2;
+ diceObj.count.proficiency = Math.floor((profConvertedToAbil - downgradeVal) / 2);
+ }
+ break;
+ case 'challenge':
+
+ var challConvertedToDiff = challengeDice * 2;
+
+ if (downgradeVal > (difficultyDice + challConvertedToDiff)) {
+ diceObj.count.difficulty = 0;
+ diceObj.count.challenge = 0;
+ } else if (downgradeVal > challConvertedToDiff) {
+ downgradeVal = Math.abs(downgradeVal - challConvertedToDiff);
+ diceObj.count.difficulty = Math.abs(downgradeVal - difficultyDice);
+ diceObj.count.challenge = 0;
+ } else {
+ diceObj.count.difficulty = difficultyDice + (challConvertedToDiff - downgradeVal) % 2;
+ diceObj.count.challenge = Math.floor((challConvertedToDiff - downgradeVal) / 2);
+ }
+ break;
+ }
+ }
+ });
+ return diceObj;
+};
+
+eote.process.math = function (expr) {
+
+ /* Math
+ * Returns: Number
+ * Description: Evaluates a mathematical expression (as a string) and return the result
+ * ---------------------------------------------------------------- */
+
+ var chars = expr.split("");
+ var n = [], op = [], index = 0, oplast = true;
+
+ n[index] = "";
+
+ // Parse the expression
+ for (var c = 0; c < chars.length; c++) {
+
+ if (isNaN(parseInt(chars[c])) && chars[c] !== "." && !oplast) {
+ op[index] = chars[c];
+ index++;
+ n[index] = "";
+ oplast = true;
+ } else {
+ n[index] += chars[c];
+ oplast = false;
+ }
+ }
+ // Calculate the expression
+ expr = parseFloat(n[0]);
+ for (var o = 0; o < op.length; o++) {
+ var num = parseFloat(n[o + 1]);
+ switch (op[o]) {
+ case "+":
+ expr = expr + num;
+ break;
+ case "-":
+ expr = expr - num;
+ break;
+ case "*":
+ expr = expr * num;
+ break;
+ case "/":
+ expr = expr / num;
+ break;
+ }
+ }
+ return expr;
+};
+
+eote.process.addDiceValues = function (diceTotalObj, diceResult) {
+
+ diceTotalObj.success = diceTotalObj.success + diceResult.success;
+ diceTotalObj.failure = diceTotalObj.failure + diceResult.failure;
+ diceTotalObj.advantage = diceTotalObj.advantage + diceResult.advantage;
+ diceTotalObj.threat = diceTotalObj.threat + diceResult.threat;
+ diceTotalObj.triumph = diceTotalObj.triumph + diceResult.triumph;
+ diceTotalObj.despair = diceTotalObj.despair + diceResult.despair;
+ diceTotalObj.light = diceTotalObj.light + diceResult.light;
+ diceTotalObj.dark = diceTotalObj.dark + diceResult.dark;
+
+ return diceTotalObj;
+};
+
+eote.process.totalDiceValues = function (diceTotalObj) {
+
+ var diceTS = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+
+ i = diceTotalObj.success - diceTotalObj.failure;
+
+ if (i >= 0) {
+ diceTS.success = i;
+ } else {
+ diceTS.failure = Math.abs(i);
+ }
+ i = diceTotalObj.advantage - diceTotalObj.threat;
+
+ if (i >= 0) {
+ diceTS.advantage = i;
+ } else {
+ diceTS.threat = Math.abs(i);
+ }
+ diceTS.triumph = diceTotalObj.triumph;
+ diceTS.despair = diceTotalObj.despair;
+ diceTS.light = diceTotalObj.light;
+ diceTS.dark = diceTotalObj.dark;
+
+ return diceTS;
+};
+
+eote.process.rollDice = function (diceObj) {
+
+ results = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: '',
+ diceTextLog: ''
+ };
+ eote.process.logger("eote.process.rollDice.FinalDiceToRoll", diceObj.count.boost + "b," + diceObj.count.ability + "g," + diceObj.count.proficiency + "y," + diceObj.count.setback + "blk," + diceObj.count.difficulty + "p," + diceObj.count.challenge + "r," + diceObj.count.force + "w," + diceObj.count.advantage + "a," + diceObj.count.threat + "t," + diceObj.count.failure + "f");
+
+ //Blue "Boost" die (d6)
+ if (diceObj.count.boost > 0) {
+ results = eote.roll.boost(diceObj.count.boost);
+ diceObj.graphicsLog.Boost = results.diceGraphicsLog;
+ diceObj.textLog.Boost = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //Green "Ability" die (d8)
+ if (diceObj.count.ability > 0) {
+ results = eote.roll.ability(diceObj.count.ability);
+ diceObj.graphicsLog.Ability = results.diceGraphicsLog;
+ diceObj.textLog.Ability = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //Yellow "Proficiency" die (d12)
+ if (diceObj.count.proficiency > 0) {
+ results = eote.roll.proficiency(diceObj.count.proficiency);
+ diceObj.graphicsLog.Proficiency = results.diceGraphicsLog;
+ diceObj.textLog.Proficiency = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //Black "SetBack" die (d6)
+ if (diceObj.count.setback > 0) {
+ results = eote.roll.setback(diceObj.count.setback);
+ diceObj.graphicsLog.SetBack = results.diceGraphicsLog;
+ diceObj.textLog.SetBack = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //Purple "Difficulty" die (d8)
+ if (diceObj.count.difficulty > 0) {
+ results = eote.roll.difficulty(diceObj.count.difficulty);
+ diceObj.graphicsLog.Difficulty = results.diceGraphicsLog;
+ diceObj.textLog.Difficulty = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //Red "Challenge" die (d12)
+ if (diceObj.count.challenge > 0) {
+ results = eote.roll.challenge(diceObj.count.challenge);
+ diceObj.graphicsLog.Challenge = results.diceGraphicsLog;
+ diceObj.textLog.Challenge = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //White "Force" die (d12)
+ if (diceObj.count.force > 0) {
+ results = eote.roll.force(diceObj.count.force);
+ diceObj.graphicsLog.Force = results.diceGraphicsLog;
+ diceObj.textLog.Force = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ // Free Successes (from skills)
+ if (diceObj.count.success > 0) {
+ results = eote.roll.success(diceObj.count.success);
+ diceObj.graphicsLog.Success = results.diceGraphicsLog;
+ diceObj.textLog.Success = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ // Free Advantage (from skills)
+ if (diceObj.count.advantage > 0) {
+ results = eote.roll.advantage(diceObj.count.advantage);
+ diceObj.graphicsLog.Advantage = results.diceGraphicsLog;
+ diceObj.textLog.Advantage = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //Free Threat (from skills)
+ if (diceObj.count.threat > 0) {
+ results = eote.roll.threat(diceObj.count.threat);
+ diceObj.graphicsLog.Threat = results.diceGraphicsLog;
+ diceObj.textLog.Threat = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ // Free Failure (from skills)
+ if (diceObj.count.failure > 0) {
+ results = eote.roll.failure(diceObj.count.failure);
+ diceObj.graphicsLog.Failure = results.diceGraphicsLog;
+ diceObj.textLog.Failure = results.diceTextLog;
+ diceObj.totals = eote.process.addDiceValues(diceObj.totals, results);
+ }
+ //finds the sum of each dice attribute
+ diceObj.totals = eote.process.totalDiceValues(diceObj.totals);
+ return diceObj;
+};
+
+eote.process.diceOutput = function (diceObj, playerName, playerID) {
+
+ //log(diceObj);
+ var s1 = ' ';
+ var chatGlobal = '';
+ var diceGraphicsResults = "";
+ var diceGraphicsRolled = "";
+ var diceTextRolled = "";
+ var diceTextResults = "";
+
+ diceTextResults = "[";
+ if (diceObj.totals.success > 0) {
+ diceTextResults = diceTextResults + " Success:" + diceObj.totals.success;
+ for (i = 1; i <= diceObj.totals.success; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.S + s2 + "Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.failure > 0) {
+ diceTextResults = diceTextResults + " Fail:" + diceObj.totals.failure;
+ for (i = 1; i <= diceObj.totals.failure; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.F + s2 + "Failure" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.advantage > 0) {
+ diceTextResults = diceTextResults + " Advant:" + diceObj.totals.advantage;
+ for (i = 1; i <= diceObj.totals.advantage; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.A + s2 + "Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.threat > 0) {
+ diceTextResults = diceTextResults + " Threat:" + diceObj.totals.threat;
+ for (i = 1; i <= diceObj.totals.threat; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.T + s2 + "Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.triumph > 0) {
+ diceTextResults = diceTextResults + " Triumph:" + diceObj.totals.triumph;
+ for (i = 1; i <= diceObj.totals.triumph; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.TRIUMPH + s2 + "Triumph" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.despair > 0) {
+ diceTextResults = diceTextResults + " Despair:" + diceObj.totals.despair;
+ for (i = 1; i <= diceObj.totals.despair; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.DESPAIR + s2 + "Despair" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.light > 0) {
+ diceTextResults = diceTextResults + " Light:" + diceObj.totals.light;
+
+ for (i = 1; i <= diceObj.totals.light; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.L + s2 + "Light" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ if (diceObj.totals.dark > 0) {
+ diceTextResults = diceTextResults + " Dark:" + diceObj.totals.dark;
+ for (i = 1; i <= diceObj.totals.dark; i++) {
+ diceGraphicsResults = diceGraphicsResults + s1 + eote.defaults.graphics.SYMBOLS.D + s2 + "Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ }
+ diceTextResults = diceTextResults + "]";
+ //------------------------------------>
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ characterPlayer = 'TEST';
+ } else if (diceObj.vars.characterName) {
+ characterPlayer = diceObj.vars.characterName;
+ } else {
+ characterPlayer = playerName;
+ }
+
+ var templateName = (diceObj.vars.suggestions.suggestionsExist
+ && suggestionEngine.getDisplayOption() == suggestionEngine.enum.displayOptions.always ? "suggestion" : "base");
+
+ /*Dice roll images work just fine when whispered*/
+ var label = diceObj.vars.label;
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ chatGlobal = "/direct 6b 8g 12y 6blk 8p 12r 12w ";
+ } else if (label) {
+ chatGlobal = "/direct &{template:" + templateName +"} " + diceObj.vars.label + "{{subtitle=" + characterPlayer + "}}";
+ } else {
+ chatGlobal = "/direct &{template:" + templateName +"} {{title=" + characterPlayer + "}}";
+ }
+ //------------------------------------>
+ if (eote.defaults.globalVars.diceLogChat === true) {
+ if (eote.defaults.globalVars.diceLogRolledOnOneLine === true) {
+
+ diceGraphicsRolled = diceObj.graphicsLog.Boost + diceObj.graphicsLog.Ability + diceObj.graphicsLog.Proficiency + diceObj.graphicsLog.SetBack + diceObj.graphicsLog.Difficulty + diceObj.graphicsLog.Challenge + diceObj.graphicsLog.Force + diceObj.graphicsLog.Success + diceObj.graphicsLog.Advantage + diceObj.graphicsLog.Failure + diceObj.graphicsLog.Threat;
+
+ if (diceObj.textLog.Boost != "") diceTextRolled = diceTextRolled + "Boost:" + diceObj.textLog.Boost;
+ if (diceObj.textLog.Ability != "") diceTextRolled = diceTextRolled + "Ability:" + diceObj.textLog.Ability;
+ if (diceObj.textLog.Proficiency != "") diceTextRolled = diceTextRolled + "Proficiency:" + diceObj.textLog.Proficiency;
+ if (diceObj.textLog.SetBack != "") diceTextRolled = diceTextRolled + "SetBack:" + diceObj.textLog.SetBack;
+ if (diceObj.textLog.Difficulty != "") diceTextRolled = diceTextRolled + "Difficulty:" + diceObj.textLog.Difficulty;
+ if (diceObj.textLog.Challenge != "") diceTextRolled = diceTextRolled + "Challenge:" + diceObj.textLog.Challenge;
+ if (diceObj.textLog.Force != "") diceTextRolled = diceTextRolled + "Force:" + diceObj.textLog.Force;
+ if (diceObj.textLog.Success != "") diceTextRolled = diceTextRolled + "Success:" + diceObj.textLog.Success;
+ if (diceObj.textLog.Advantage != "") diceTextRolled = diceTextRolled + "Advantage:" + diceObj.textLog.Advantage;
+ if (diceObj.textLog.Failure != "") diceTextRolled = diceGraphicsRolled + "Failure:" + diceObj.textLog.Failure;
+ if (diceObj.textLog.Threat != "") diceTextRolled = diceGraphicsRolled + "Threat:" + diceObj.textLog.Threat;
+
+ if (eote.defaults.globalVars.diceGraphicsChat === true) {
+ chatGlobal = chatGlobal + '{{roll=' + diceGraphicsRolled + '}}';
+ } else {
+ sendChat("", diceTextRolled);
+ }
+ } else {
+
+ if (eote.defaults.globalVars.diceGraphicsChat === true) {
+
+ if (diceObj.vars.label) {
+ sendChat(characterPlayer, "/direct " + diceObj.vars.label + ' ');
+ }
+ if (diceObj.graphicsLog.Boost != "") sendChat("", "/direct " + diceObj.graphicsLog.Boost);
+ if (diceObj.graphicsLog.Ability != "") sendChat("", "/direct " + diceObj.graphicsLog.Ability);
+ if (diceObj.graphicsLog.Proficiency != "") sendChat("", "/direct " + diceObj.graphicsLog.Proficiency);
+ if (diceObj.graphicsLog.SetBack != "") sendChat("", "/direct " + diceObj.graphicsLog.SetBack);
+ if (diceObj.graphicsLog.Difficulty != "") sendChat("", "/direct " + diceObj.graphicsLog.Difficulty);
+ if (diceObj.graphicsLog.Challenge != "") sendChat("", "/direct " + diceObj.graphicsLog.Challenge);
+ if (diceObj.graphicsLog.Force != "") sendChat("", "/direct " + diceObj.graphicsLog.Force);
+ if (diceObj.graphicsLog.Success != "") sendChat("", "/direct " + diceObj.graphicsLog.Success);
+ if (diceObj.graphicsLog.Advantage != "") sendChat("", "/direct " + diceObj.graphicsLog.Advantage);
+ if (diceObj.graphicsLog.Failure != "") sendChat("", "/direct " + diceObj.graphicsLog.Failure);
+ if (diceObj.graphicsLog.Threat != "") sendChat("", "/direct " + diceObj.graphicsLog.Threat);
+ } else {
+ if (diceObj.vars.label) {
+ sendChat(characterPlayer, "/direct " + diceObj.vars.label + ' ');
+ }
+ if (diceObj.textLog.Boost != "") sendChat("", "Boost:" + diceObj.textLog.Boost);
+ if (diceObj.textLog.Ability != "") sendChat("", "Ability:" + diceObj.textLog.Ability);
+ if (diceObj.textLog.Proficiency != "") sendChat("", "Proficiency:" + diceObj.textLog.Proficiency);
+ if (diceObj.textLog.SetBack != "") sendChat("", "SetBack:" + diceObj.textLog.SetBack);
+ if (diceObj.textLog.Difficulty != "") sendChat("", "Difficulty:" + diceObj.textLog.Difficulty);
+ if (diceObj.textLog.Challenge != "") sendChat("", "Challenge:" + diceObj.textLog.Challenge);
+ if (diceObj.textLog.Force != "") sendChat("", "Force:" + diceObj.textLog.Force);
+ if (diceObj.textLog.Success != "") sendChat("", "Success:" + diceObj.textLog.Success);
+ if (diceObj.textLog.Advantage != "") sendChat("", "Advantage:" + diceObj.textLog.Advantage);
+ if (diceObj.textLog.Failure != "") sendChat("", "Failure:" + diceObj.textLog.Failure);
+ if (diceObj.textLog.Threat != "") sendChat("", "Threat:" + diceObj.textLog.Threat);
+ }
+ }
+ }
+
+ var suggestions = suggestionEngine.buildSuggestionsRollTemplate(diceObj);
+ var suggestionStatus = suggestionEngine.enum.displayOptions;
+ var suggestionsFlag = suggestionEngine.getDisplayOption();
+ var suggestionsExist = diceObj.vars.suggestions.suggestionsExist;
+
+ if (suggestionsExist) {
+ switch (suggestionsFlag) {
+ case suggestionStatus.none:
+ // not really needed since the other checks won't allow a status of none to do anything
+ // but this prevents the default from yelling at you.
+ suggestions = null;
+ break;
+ case suggestionStatus.whisper:
+ suggestions = "&{template:base} {{title=Skill Suggestions}} " + suggestions;
+ break;
+ case suggestionStatus.always:
+ suggestions = " {{suggestionsExist=true}} " + suggestions;
+ break;
+ case null:
+ var msg = "No display option determined! Please set the display option on the " + eote.defaults.GMSheet.name;
+ log(msg);
+ sendChat("System", "/w gm " + msg);
+ break;
+ default:
+ // this should never be entered
+ log("Report Me! A suggestionFlag of '"+ suggestionsFlag +"' is not handled properly!");
+ }
+ }
+ if (diceObj.vars.calculatedDamage) {
+ diceTextResults += diceObj.vars.calculatedDamage;
+ }
+ if (eote.defaults.globalVars.diceGraphicsChat === true) {
+ chatGlobal = chatGlobal + '{{results=' + diceGraphicsResults + '}}';
+ if (suggestions && suggestionsFlag == suggestionStatus.always)
+ chatGlobal += " " + suggestions;
+ if (diceObj.vars.calculatedDamage) {
+ chatGlobal += diceObj.vars.calculatedDamage;
+ }
+ sendChat(characterPlayer, chatGlobal);
+ } else {
+ sendChat("Roll", diceTextResults);
+ }
+
+
+ if (suggestions && suggestionsFlag == suggestionStatus.whisper) {
+ sendChat("System", "/w gm " + suggestions);
+ }
+ eote.process.logger("eote.process.rollResult", diceTextResults);
+ if (diceObj.vars.inflictedCritical) {
+ eote.process.rollEnemyCritical(diceObj);
+ }
+};
+
+eote.process.rollEnemyCritical = function(diceObj)
+{
+ var targetType = findObjs({_type: "attribute",name: "target-type",_characterid: diceObj.vars.characterID})[0];
+ var criticalBonus = findObjs({_type: "attribute",name: "critical-bonus",_characterid: diceObj.vars.characterID})[0];
+ var bonus = 0;
+ if (typeof criticalBonus !== 'undefined') {
+ bonus = parseInt(criticalBonus.get('current'));
+ }
+ if (diceObj.vars.weaponCriticalBonus && diceObj.vars.weaponCriticalBonus > 0 && ! isNaN(parseInt(diceObj.vars.weaponCriticalBonus))) {
+ bonus += parseInt(diceObj.vars.weaponCriticalBonus);
+ }
+ var randomCrit = Math.floor(Math.random() * 100) + 1;
+
+ var criticalTable = critTableLifeform;
+ var targetTypeName = "NPC";
+ if(typeof targetType !== 'undefined') {
+ targetTypeName = targetType.get('current').toUpperCase();
+ }
+ if (targetTypeName == "VEHICLE" || targetTypeName == "STARSHIP") {
+ criticalTable = critTableMachine;
+ }
+ for (var key in criticalTable) {
+ var percent = criticalTable[key].percent.split(' to ');
+ var low = parseInt(percent[0]);
+ var high = percent[1] ? parseInt(percent[1]) : 1000;
+ var rollTotal = randomCrit;
+ var afterBonus = rollTotal;
+ if (! isNaN(bonus) && bonus > 0) {
+ afterBonus = bonus + rollTotal;
+ }
+
+ if ((afterBonus >= low) && (afterBonus <= high)) {
+ var chat = '/direct &{template:critical} {{title=' + targetTypeName + ' Critical}} ';
+ chat = chat + '{{flavor=Inflicted by ' + diceObj.vars.characterName + ' }}';
+ chat = chat + '{{Crit Dice Roll=' + rollTotal + '}}';
+ if (! isNaN(bonus) && bonus > 0) {
+ chat = chat + '{{Crit Bonus=' + bonus + '}}';
+ chat = chat + '{{Total Critical=' + (randomCrit + bonus) + '}}';
+ }
+ chat = chat + '{{wide=' + criticalTable[key].name + ' ';
+ chat = chat + criticalTable[key].Result + '
}}';
+
+ sendChat(diceObj.vars.characterName, chat);
+ }
+ }
+};
+
+eote.process.rollRandomCritical = function(diceObj)
+{
+ var criticalBonus = findObjs({_type: "attribute",name: "critical-bonus-standalone",_characterid: diceObj.vars.characterID})[0];
+ var bonus = 0;
+ if (typeof criticalBonus !== 'undefined') {
+ bonus = parseInt(criticalBonus.get('current'));
+ }
+ if (diceObj.vars.weaponCriticalBonus && diceObj.vars.weaponCriticalBonus > 0 && ! isNaN(parseInt(diceObj.vars.weaponCriticalBonus))) {
+ bonus += parseInt(diceObj.vars.weaponCriticalBonus);
+ }
+ var randomCrit = Math.floor(Math.random() * 100) + 1;
+
+ var criticalTable = critTableLifeform;
+ var targetTypeName = "Random";
+ for (var key in criticalTable) {
+ var percent = criticalTable[key].percent.split(' to ');
+ var low = parseInt(percent[0]);
+ var high = percent[1] ? parseInt(percent[1]) : 1000;
+ var rollTotal = randomCrit;
+ var afterBonus = rollTotal;
+ if (! isNaN(bonus) && bonus > 0) {
+ afterBonus = bonus + rollTotal;
+ }
+
+ if ((afterBonus >= low) && (afterBonus <= high)) {
+ var chat = '/direct &{template:critical} {{title=' + targetTypeName + ' Critical}} ';
+ chat = chat + '{{flavor=Rolled by ' + diceObj.vars.characterName + ' }}';
+ chat = chat + '{{Crit Dice Roll=' + rollTotal + '}}';
+ if (! isNaN(bonus) && bonus > 0) {
+ chat = chat + '{{Crit Bonus=' + bonus + '}}';
+ chat = chat + '{{Total Critical=' + (randomCrit + bonus) + '}}';
+ }
+ chat = chat + '{{wide=' + criticalTable[key].name + ' ';
+ chat = chat + criticalTable[key].Result + '
}}';
+
+ sendChat(diceObj.vars.characterName, chat);
+ }
+ }
+};
+
+eote.roll = {
+
+ boost: function (diceQty) {
+ //Blue "Boost" die (d6)
+ //1 Blank
+ //2 Blank
+ //3 Success
+ //4 Advantage
+ //5 Advantage + Advantage
+ //6 Success + Advantage
+ var roll = 0;
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 6;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ } else {
+ roll = randomInteger(6);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.BOOST.BLANK + s2 + "Boost Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.BOOST.BLANK + s2 + "Boost Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.BOOST.S + s2 + "Boost Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.BOOST.A + s2 + "Boost Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.BOOST.AA + s2 + "Boost Advantage x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 2;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success + Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.BOOST.SA + s2 + "Boost Success + Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ ability: function (diceQty) {
+ //Green "Ability" die (d8)
+ //1 Blank
+ //2 Success
+ //3 Success
+ //4 Advantage
+ //5 Advantage
+ //6 Success + Advantage
+ //7 Advantage + Advantage
+ //8 Success + Success
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 8;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ }
+ else {
+ roll = randomInteger(8);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.BLANK + s2 + "Ability Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.S + s2 + "Ability Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.S + s2 + "Ability Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.A + s2 + "Ability Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.A + s2 + "Ability Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success + Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.SA + s2 + "Ability Success + Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 7:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.AA + s2 + "Ability Advantage x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 2;
+ break;
+ case 8:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.ABILITY.SS + s2 + "Ability Success x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 2;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ proficiency: function (diceQty) {
+ //Yellow "Proficiency" die (d12)
+ //1 Blank
+ //2 Triumph
+ //3 Success
+ //4 Success
+ //5 Advantage
+ //6 Success + Advantage
+ //7 Success + Advantage
+ //8 Success + Advantage
+ //9 Success + Success
+ //10 Success + Success
+ //11 Advantage + Advantage
+ //12 Advantage + Advantage
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 12;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ }
+ else {
+ roll = randomInteger(12);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.BLANK + s2 + "Proficiency Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Triumph(+Success))";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.TRIUMPH + s2 + "Proficiency Triumph(+Success)" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.triumph = diceResult.triumph + 1;
+ diceResult.success = diceResult.success + 1;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.S + s2 + "Proficiency Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.S + s2 + "Proficiency Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.A + s2 + "Proficiency Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success + Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.SA + s2 + "Proficiency Success + Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 7:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success + Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.SA + s2 + "Proficiency Success + Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 8:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success + Advantage)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.SA + s2 + "Proficiency Success + Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 1;
+ diceResult.advantage = diceResult.advantage + 1;
+ break;
+ case 9:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.SS + s2 + "Proficiency Success x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 2;
+ break;
+ case 10:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Success x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.SS + s2 + "Proficiency Success x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.success = diceResult.success + 2;
+ break;
+ case 11:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.AA + s2 + "Proficiency Advantage x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 2;
+ break;
+ case 12:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Advantage x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.PROFICIENCY.AA + s2 + "Proficiency Advantage x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.advantage = diceResult.advantage + 2;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ setback: function (diceQty) {
+ //Black "Setback" die (d6)
+ //1 Blank
+ //2 Blank
+ //3 Failure
+ //4 Failure
+ //5 Threat
+ //6 Threat
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 6;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ }
+ else {
+ roll = randomInteger(6);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SETBACK.BLANK + s2 + "Setback Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SETBACK.BLANK + s2 + "Setback Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SETBACK.F + s2 + "Setback Failure" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SETBACK.F + s2 + "Setback Failure" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SETBACK.T + s2 + "Setback Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SETBACK.T + s2 + "Setback Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ difficulty: function (diceQty) {
+ //Purple "Difficulty" die (d8)
+ //1 Blank
+ //2 Failure
+ //3 Threat
+ //4 Threat
+ //5 Threat
+ //6 Failure + Failure
+ //7 Failure + Threat
+ //8 Threat + Threat
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 8;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ }
+ else {
+ roll = randomInteger(8);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.BLANK + s2 + "Difficulty Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.F + s2 + "Difficulty Failure" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.T + s2 + "Difficulty Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.T + s2 + "Difficulty Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.T + s2 + "Difficulty Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.FF + s2 + "Difficulty Failure x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 2;
+ break;
+ case 7:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure + Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.FT + s2 + "Difficulty Failure + Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 8:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.DIFFICULTY.TT + s2 + "Difficulty Threat x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 2;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ challenge: function (diceQty) {
+ //Red "Challenge" die (d12)
+ //1 Blank
+ //2 Despair
+ //3 Failure
+ //4 Failure
+ //5 Threat
+ //6 Threat
+ //7 Failure + Failure
+ //8 Failure + Failure
+ //9 Threat + Threat
+ //10 Threat + Threat
+ //11 Failure + Threat
+ //12 Failure + Threat
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 12;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ }
+ else {
+ roll = randomInteger(12);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Blank)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.BLANK + s2 + "Challenge Blank" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Despair)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.DESPAIR + s2 + "Challenge Despair" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.despair = diceResult.despair + 1;
+ diceResult.failure = diceResult.failure + 1;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.F + s2 + "Challenge Failure" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.F + s2 + "Challenge Failure" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.T + s2 + "Challenge Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.T + s2 + "Challenge Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 7:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.FF + s2 + "Challenge Failure x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 2;
+ break;
+ case 8:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.FF + s2 + "Challenge Failure x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 2;
+ break;
+ case 9:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.TT + s2 + "Challenge Threat x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 2;
+ break;
+ case 10:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Threat x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.TT + s2 + "Challenge Threat x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.threat = diceResult.threat + 2;
+ break;
+ case 11:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure + Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.FT + s2 + "Challenge Failure + Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ case 12:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Failure + Threat)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.CHALLENGE.FT + s2 + "Challenge Failure + Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.failure = diceResult.failure + 1;
+ diceResult.threat = diceResult.threat + 1;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ force: function (diceQty) {
+ //White "Force" die (d12)
+ //1 Light
+ //2 Light
+ //3 Light + Light
+ //4 Light + Light
+ //5 Light + Light
+ //6 Dark
+ //7 Dark
+ //8 Dark
+ //9 Dark
+ //10 Dark
+ //11 Dark
+ //12 Dark + Dark
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ var i = 0;
+ var s1 = ' ';
+
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ diceQty = 12;
+ }
+ for (i = 1; i <= diceQty; i++) {
+ if (eote.defaults.globalVars.diceTestEnabled === true) {
+ roll = roll + 1;
+ }
+ else {
+ roll = randomInteger(12);
+ }
+ switch (roll) {
+ case 1:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Light)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.L + s2 + "Force Light" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.light = diceResult.light + 1;
+ break;
+ case 2:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Light)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.L + s2 + "Force Light" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.light = diceResult.light + 1;
+ break;
+ case 3:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Light x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.LL + s2 + "Force Light x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.light = diceResult.light + 2;
+ break;
+ case 4:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Light x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.LL + s2 + "Force Light x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.light = diceResult.light + 2;
+ break;
+ case 5:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Light x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.LL + s2 + "Force Light x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.light = diceResult.light + 2;
+ break;
+ case 6:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.D + s2 + "Force Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 1;
+ break;
+ case 7:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.D + s2 + "Force Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 1;
+ break;
+ case 8:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.D + s2 + "Force Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 1;
+ break;
+ case 9:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.D + s2 + "Force Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 1;
+ break;
+ case 10:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.D + s2 + "Force Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 1;
+ break;
+ case 11:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.D + s2 + "Force Dark" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 1;
+ break;
+ case 12:
+ diceResult.diceTextLog = diceResult.diceTextLog + "(Dark x2)";
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.FORCE.DD + s2 + "Force Dark x2" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ diceResult.dark = diceResult.dark + 2;
+ break;
+ }
+ }
+ return diceResult;
+ },
+ success: function (diceQty) {
+ //Free Success
+ var i = 0;
+ var s1 = ' ';
+
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ diceResult.diceTextLog = diceTextLog + "(Success x" + diceQty + ")";
+ diceResult.success = diceResult.success + diceQty;
+ for (i = 0; i < diceQty; i++) {
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SYMBOLS.S + s2 + "Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ return diceResult;
+ },
+ advantage: function (diceQty) {
+ //Free Advantage
+ var i = 0;
+ var s1 = ' ';
+
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ diceResult.diceTextLog = diceTextLog + "(Advantage x" + diceQty + ")";
+ diceResult.advantage = diceResult.advantage + diceQty;
+ for (i = 0; i < diceQty; i++) {
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SYMBOLS.A + s2 + "Advantage" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ return diceResult;
+ },
+ threat: function (diceQty) {
+ //Free threat
+ var i = 0;
+ var s1 = ' ';
+
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ diceResult.diceTextLog = diceTextLog + "(Threat x" + diceQty + ")";
+ diceResult.threat = diceResult.threat + diceQty;
+ for (i = 0; i < diceQty; i++) {
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SYMBOLS.T + s2 + "Threat" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ return diceResult;
+ },
+ failure: function (diceQty) {
+ //Free Failure
+ var i = 0;
+ var s1 = ' ';
+
+ var roll = 0;
+ var diceTextLog = "";
+ var diceGraphicsLog = "";
+
+ var diceResult = {
+ success: 0,
+ failure: 0,
+ advantage: 0,
+ threat: 0,
+ triumph: 0,
+ despair: 0,
+ light: 0,
+ dark: 0,
+ diceGraphicsLog: "",
+ diceTextLog: ""
+ };
+ diceResult.diceTextLog = diceTextLog + "(Failure x" + diceQty + ")";
+ diceResult.failure = diceResult.failure + diceQty;
+ for (i = 0; i < diceQty; i++) {
+ diceResult.diceGraphicsLog = diceResult.diceGraphicsLog + s1 + eote.defaults.graphics.SYMBOLS.F + s2 + "Success" + s3 + eote.defaults.globalVars.diceGraphicsChatSize + s4 + eote.defaults.globalVars.diceGraphicsChatSize + s5;
+ }
+ return diceResult;
+ }
+};
+
+eote.events = function () {
+
+ //event listener Add character defaults to new characters
+ on("add:character", function (characterObj) {
+ eote.setCharacterDefaults(characterObj);
+ });
+ on("chat:message", function (msg) {
+
+ if (msg.type != 'api') {
+ return;
+ }
+ eote.process.setup(msg.content, msg.who, msg.playerid);
+ });
+};
+
+// this only runs once per initialization of the script in order to prevent this process from running too frequently
+// this converts any $\w$ token that matches a defined list of tokens into a html image tag.
+function convertTokensToTags(skillSuggestions, symReplace) {
+ Object.keys(skillSuggestions).forEach(function(categoryKey) {
+ var category = skillSuggestions[categoryKey];
+ Object.keys(category).forEach(function(categoryElemKey) {
+ var categoryElem = category[categoryElemKey];
+ Object.keys(categoryElem).forEach(function(symbolKey) {
+ var item = categoryElem[symbolKey];
+ for (var i = 0; i < item.length; i++)
+ {
+ var itemElem = item[i];
+ if (typeof itemElem == "object") {
+ if (itemElem.text.indexOf("$") > 0) {
+ Object.keys(symReplace).forEach(function (symReplaceKey) {
+ itemElem.text = itemElem.text.replace(symReplace[symReplaceKey].matcher, symReplace[symReplaceKey].replacer);
+ });
+ }
+ }
+ }
+ });
+ });
+ });
+ log("Finished converting tokens to tags");
+}
+
+on('ready', function() {
+ eote.init();
+});
\ No newline at end of file
diff --git a/Star Wars FFG Alternate/preview.png b/Star Wars FFG Alternate/preview.png
new file mode 100644
index 0000000000..bea50d0408
Binary files /dev/null and b/Star Wars FFG Alternate/preview.png differ
diff --git a/Star Wars FFG Alternate/sheet.json b/Star Wars FFG Alternate/sheet.json
new file mode 100644
index 0000000000..0601ad895c
--- /dev/null
+++ b/Star Wars FFG Alternate/sheet.json
@@ -0,0 +1,8 @@
+{
+ "html": "Roll20_FFG_StarWars_CharacterSheet.html",
+ "css": "Roll20_FFG_StarWars_CharacterSheet.css",
+ "authors": "Timothy Yuen",
+ "roll20userid": "1742255",
+ "preview": "preview.png",
+ "instructions": "Requires manual initialization of fields. Make sure to set all number fields you want to use to a value with a manual keyboard input the first time you use that field. Not doing so may cause some odd behavior with calculations dependent on those fields receiving an 'undefined' value. This includes all Characteristics, Vital Stats, Weapon and Armor stats, and Item encumbrance. There is code to auto-init fields, but it currently won't trigger until Roll20 fixes a bug with the sheet:opened event. [View full Readme](https://github.com/timothyyuen-ty/Roll20_FFG_StarWars_CharacterSheet/blob/master/README.md)"
+}
\ No newline at end of file
diff --git a/Star Wars FFG Alternate/translation.json b/Star Wars FFG Alternate/translation.json
new file mode 100644
index 0000000000..4f4630f4de
--- /dev/null
+++ b/Star Wars FFG Alternate/translation.json
@@ -0,0 +1 @@
+{"dice_pool":"Dice Pool","boost_die":"Boost Die","ability_die":"Ability Die","proficiency_die":"Proficiency Die","upgrade":"Upgrade :","downgrade":": Downgrade","force_die":"Force Die","roll_dice_pool":"Roll dice pool","reset_dice_pool":"Reset dice pool","setback_die":"Setback Die","difficulty_die":"Difficulty Die","challenge_die":"Challenge Die","destiny_pool":"Destiny Pool","sync_pool_with_gm":"Sync Pool with GM","roll_destiny":"Roll Destiny","update_player_points":"Update Player Points","clear_pool":"Clear Pool","light":"Light","use_dark_side":"Use Dark Side","use_light_side":"Use Light Side","dark":"Dark","vital_stats":"Vital Stats","soak":"Soak","defense":"Defense","ranged":"Ranged","melee":"Melee","wounds":"Wounds","threshold":"Threshold","current":"Current","strain":"Strain","encumbrance":"Encumbrance","bio":"Bio","skills":"Skills","combat":"Combat","equipment":"Equipment","talents":"Talents","the_force":"The Force","settings":"Settings","name_species_and_career":"Name, Species, and Career","character_name":"Character Name","player_name":"Player Name","species":"Species","aleena":"Aleena","anx":"Anx","aqualisha":"Aqualish (Aquala)","aqualishq":"Aqualish (Quara)","aqualishu":"Aqualish (Ualaq)","arcona":"Arcona","arkanian":"Arkanian","bardottan":"Bardottan","besalisk":"Besalisk","bothan":"Bothan","caamasi":"Caamasi","cerean":"Cerean","chadrafan":"Chadra-Fan","chagrian":"Chagrian","chevin":"Chevin","chiss":"Chiss","clawdite":"Clawdite","clone":"Clone","correllianhuman":"Corellian Human","cosian":"Cosian","dathomirian":"Dathomirian","devaronian":"Devaronian","dowutin":"Dowutin","drall":"Drall","dressellianp":"Dressellian (Primitive)","dresselliannp":"Dressellian (Non-Primitive)","droid":"Droid","dug":"Dug","duros":"Duros","elom":"Elom","elomin":"Elomin","ewok":"Ewok","falleen":"Falleen","gandl":"Gand (With Lungs)","gandnl":"Gand (Without Lungs)","gank":"Gank","geonosian":"Geonosian","gigoran":"Gigoran","gossam":"Gossam","gotal":"Gotal","gran":"Gran","gungan":"Gungan","harch":"Harch","human":"Human","hutt":"Hutt","iakaru":"Iakaru","iktochi":"Iktotchi","ishitib":"Ishi Tib","ithorian":"Ithorian","jawa":"Jawa","kalleran":"Kalleran","kaminoan":"Kaminoan","karkarodon":"Karkarodon","keldor":"Kel Dor","klatooinian":"Klatooinian","kubaz":"Kubaz","kyuzo":"Kyuzo","lannik":"Lannik","lasat":"Lasat","mandalorianhuman":"Mandalorian Human","melitto":"Melitto","mikkian":"Mikkian","mirialan":"Mirialan","moncalamari":"Mon Calamari","mustafariann":"Mustafarian (Northern)","mustafarians":"Mustafarian (Southern)","muun":"Muun","nautolan":"Nautolan","neimodian":"Neimodian","niktog":"Nikto (Green)","niktom":"Nikto (Mountain)","niktop":"Nikto (Pale)","niktor":"Nikto (Red)","niktos":"Nikto (Southern)","pantoran":"Pantoran","pauan":"Pau'an","phydolon":"Phydolon","polismassanvc":"Polis Massan (With Vocal Chords)","polismassannvc":"Polis Massan (Without Vocal Chords)","quarren":"Quarren","quermian":"Quermian","rodian":"Rodian","sakiyan":"Sakiyan","sathari":"Sathari","selonian":"Selonian","shistavanen":"Shistavanen","skakoans":"Skakoans","sullustan":"Sullustan","thisspiasian":"Thisspiasian","tholothian":"Tholothian","tognath":"Tognath","togruta":"Togruta","toydarian":"Toydarian","trandosian":"Trandosian","tuskenraider":"Tusken Raider","twilek":"Twi'lek","umbaran":"Umbaran","verpine":"Verpine","vurk":"Vurk","weekay":"Weequay","whipid":"Whiphid","wookie":"Wookiee","xexto":"Xexto","zabrak":"Zabrak","career":"Career","edgeoftheempire":"Edge of the Empire","bountyhunter":"Bounty Hunter","colonist":"Colonist","explorer":"Explorer","hiredgun":"Hired Gun","smuggler":"Smuggler","technician":"Technician","ageofrebellion":"Age of Rebellion","ace":"Ace","commander":"Commander","diplomat":"Diplomat","engineer":"Engineer","soldier":"Soldier","spy":"Spy","forceanddestiny":"Force and Destiny","consular":"Consular","guardian":"Guardian","mystic":"Mystic","seeker":"Seeker","sentinel":"Sentinel","warrior":"Warrior","clonewarsera":"Clone Wars Era","clonesoldier":"Clone Soldier","jedi":"Jedi","all":"All","universal":"Universal","specializations":"Specializations","assassin":"Assassin","gadgeteer":"Gadgeteer","martialartist":"Martial Artist","operator":"Operator","skiptracer":"Skip Tracer","survivalist":"Survivalist","doctor":"Doctor","politico":"Politico","scholar":"Scholar","entrepreneur":"Entrepreneur","marshal":"Marshal","performer":"Performer","scout":"Scout","fringer":"Fringer","driver":"Driver","archaeologist":"Archaeologist","biggamehunter":"Big-Game Hunter","trader":"Trader","bodyguard":"Bodyguard","demolitionist":"Demolitionist","enforcer":"Enforcer","heavy":"Heavy","marauder":"Marauder","mercenarysoldier":"Mercenary Soldier","pilot":"Pilot","scoundrel":"Scoundrel","thief":"Thief","charmer":"Charmer","gambler":"Gambler","gunslinger":"Gunslinger","mechanic":"Mechanic","outlawtech":"Outlaw Tech","slicer":"Slicer","cybertech":"Cyber Tech","droidtech":"Droid Tech","modder":"Modder","gunner":"Gunner","rigger":"Rigger","hotshot":"Hotshot","beastrider":"Beast Rider","squadronleader":"Squadron Leader","tactician":"Tactician","figurehead":"Figurehead","instructor":"Instructor","strategist":"Strategist","ambassador":"Ambassador","agitator":"Agitator","quartermester":"Quartermaster","analyst":"Analyst","advocate":"Advocate","propagandist":"Propagandist","droidspecialist":"Droid Specialist","saboteur":"Saboteur","sapper":"Sapper","scientist":"Scientist","shipwright":"Shipwright","medic":"Medic","sharpshooter":"Sharpshooter","commando":"Commando","trailblazer":"Trailblazer","vanguard":"Vanguard","courier":"Courier","infiltrator":"Infiltrator","interrogator":"Interrogator","sleeperagent":"Sleeper Agent","arbiter":"Arbiter","ascetic":"Ascetic","healer":"Healer","nimandisciple":"Niman Disciple","sage":"Sage","teacher":"Teacher","armorer":"Armorer","peacekeeper":"Peace Keeper","protector":"Protector","soresudefender":"Soresu Defender","warden":"Warden","warleader":"Warleader","advisor":"Advisor","alchemist":"Alchemist","magus":"Magus","makashiduelist":"Makashi Duelist","prophet":"Prophet","seer":"Seer","atarustriker":"Ataru Striker","executioner":"Executioner","hermit":"Hermit","hunter":"Hunter","navigator":"Navigator","pathfinder":"Pathfinder","artisan":"Artisan","investigator":"Investigator","racer":"Racer","sentry":"Sentry","shadow":"Shadow","shienexpert":"Shien Expert","aggressor":"Aggressor","colossus":"Colossus","juyoberserker":"Juyo Berserker","shiichoknight":"Shii-Cho Knight","starfighterace":"Starfighter Ace","steelhandadept":"Steel Hand Adept","clonetrooper":"Clone Trooper","clonepilot":"Clone Pilot","cloneofficer":"Clone Officer","arctrooper":"ARC Trooper","clonecommander":"Clone Commander","cloneveteran":"Clone Veteran","padawan":"Padawan","knight":"Knight","general":"General","master":"Master","deathwatchwarrior":"Death Watch Warrior","forceadherent":"Force Adherent","forcesensitiveemergent":"Force Sensitive Emergent","forcesensitiveexile":"Force Sensitive Exile","forcesensitiveoutcast":"Force Sensitive Outcast","imperialacademycadet":"Imperial Academy Cadet","nightsister":"Nightsister","padawansurvivor":"Padawan Survivor","pirate":"Pirate","recruit":"Recruit","republicnavyofficer":"Republic Navy Officer","republicrepresentative":"Republic Representative","retiredclonetrooper":"Retired Clone Trooper","scavenger":"Scavenger","senator":"Senator","separatistcommander":"Separatist Commander","shipcaptain":"Ship Captain","xp_credits":"XP and Credits","xp_total_current":"XP Total / Current","credits":"Credits","obligation":"Obligation","total_obligation":"Total Obligation","duty":"Duty","contribution_rank":"Contribution Rank","morality":"Morality","conflict":"Conflict","emotional_strength":"Emotional Strength","emotional_weakness":"Emotional Weakness","ambition":"Ambition","cause":"Cause","notes":"Notes","characteristics":"Characteristics","brawn":"Brawn","agility":"Agility","intellect":"Intellect","cunning":"Cunning","willpower":"Willpower","presence":"Presence","skill":"Skill","characteristic":"Characteristic","ranks":"Ranks","dice":"Dice","modifiers":"Modifiers","roll":"Roll","astrogation":"Astrogation","intellect_abbr":"Int","athletics":"Athletics","brawn_abbr":"Bra","charm":"Charm","presence_abbr":"Pr","coercion":"Coercion","willpower_abbr":"Wil","computers":"Computers","cool":"Cool","coordination":"Coordination","agility_abbr":"Ag","deception":"Deception","cunning_abbr":"Cun","discipline":"Discipline","leadership":"Leadership","mechanics":"Mechanics","medicine":"Medicine","negotiation":"Negotiation","perception":"Perception","piloting-planetary":"Piloting - Planetary","piloting-space":"Piloting - Space","resilience":"Resilience","skullduggery":"Skullduggery","stealth":"Stealth","streetwise":"Streetwise","survival":"Survival","vigilance":"Vigilance","brawl":"Brawl","gunnery":"Gunnery","lightsaber":"Lightsaber","ranged-light":"Ranged - Light","ranged-heavy":"Ranged - Heavy","core-worlds":"Core Worlds","education":"Education","lore":"Lore","outer-rim":"Outer Rim","underworld":"Underworld","warfare":"Warfare","xenology":"Xenology","initiative":"Initiative","cool_if_prepared":"Cool (if prepared)","vigilance_if_unexpected":"Vigilance (if unexpected)","criticals":"Criticals","roll_a_critical":"Roll a Critical (for any target)","critical_bonus":"Critical Bonus","roll_critical":"Roll Critical","your_current_critical_injuries":"Your Current Critical Injuries","heal_this_wound":"Heal this wound","weapons":"Weapons","damage":"Damage","critical":"Critical","encumbrance_abbr":"Encum","hard_points":"Hard Points","make_model":"Make-Model","carried_":"Carried?","combat_skills":"Combat Skills","general_skills":"General Skills","medecine":"Medicine","range":"Range","engaged":"Engaged","short":"Short","medium":"Medium","long":"Long","extreme":"Extreme","condition":"Condition","undamaged":"Undamaged","minor":"Minor","moderate":"Moderate","major":"Major","destroyed":"Destroyed","from_other":"from Other","from_vicious":"from Vicious","total_bonus":"Total Bonus","damage_bonus:":"Damage Bonus","from_superior":"from Superior","from_inferior":"from Inferior","weapon_qualities":"Weapon Qualities","two_advantage_to_activate":"Two Advantage to activate unless otherwise noted","accurate":"Accurate","passive":"Passive","auto_fire":"Auto-Fire","active":"Active","no":"No","yes":"Yes","blast":"Blast","breach":"Breach","burn":"Burn","concussive":"Concussive","cortosis":"Cortosis","cumbersome":"Cumbersome","defensive":"Defensive","deflection":"Deflection","disorient":"Disorient","ensnare":"Ensnare","guided":"Guided","knockdown":"Knockdown","inaccurate":"Inaccurate","inferior":"Inferior","ion":"Ion","limited_ammo":"Limited Ammo","linked":"Linked","pierce":"Pierce","prepare":"Prepare","slow_firing":"Slow-Firing","stun":"Stun","sunder":"Sunder","superior":"Superior","unwieldy":"Unwieldy","vicious":"Vicious","attachments_mods":"Attachments / Mods","name":"Name","hp":"HP","benefit":"Benefit","combat_talents":"Combat Talents","active_":"Active?","description":"Description","armor":"Armor","encum":"Encum","quality":"Quality","normal":"Normal","gear":"Gear","containers":"Containers","add_encum_threshold":"+ Encum Threshold","cybernetics":"Cybernetics","non_combat_talents":"Non-combat Talents","signature_abilities":"Signature Abilities","force_powers":"Force Powers","force_rating":"Force Rating","basic":"Basic","control":"Control","duration":"Duration","magnitude":"Magnitude","strength":"Strength","mastery":"Mastery","general_settings":"General Settings","change_font_size_zoom":"Change font size / zoom","roll_result_suggestions":"Roll Result Suggestions","setting":"Setting","option":"Option","select_skill_suggestions":"Change the handling for skill suggestions","skill_suggestions_display":"Skill Suggestions Display","none":"None","whisper_gm":"Whisper GM","show_suggestions_button":"Show Suggestions Button","display_inskill":"Display in Skill","select_combat_suggestions":"Enable suggestions for rolls made from the weapon combat section or vehicle sheet","enable_combat_suggestions":"Enable Combat Suggestions?","select_general_suggestions":"Enable suggestions for rolls made from the general skill list","enable_general_suggestions":"Enable General Suggestions?","select_fear_check":"Allows Discipline and Cool skill checks to pull suggestions from the fear suggestion list.","fear_check":"Fear Check?","diceroll":"Dice Roll","results":"Results","alter":"Alter","battle_meditation":"Battle Meditation","bind":"Bind","conjure":"Conjure","ebb-flow":"Ebb / Flow","endure":"Endure","enhance":"Enhance","farsight":"Farsight","foresee":"Foresee","heal-harm":"Heal / Harm","imbue":"Imbue","influence":"Influence","manipulate":"Manipulate","misdirect":"Misdirect","move":"Move","protect-unleash":"Protect / Unleash","seek":"Seek","sense":"Sense","supress":"Supress","wardes_foresight":"Warde's Foresight"}
\ No newline at end of file