-
- Name
- Species
- Type
-
-
- Nature
- Held Item
-
+
-
-
-
-
- | {{move-name}} |
-
-
- | [{{character-name}}](https://journal.roll20.net/character/{{character-id}}" name="name-link") |
-
+
+
+
+
+ | {{move-name}} |
+
+
+ | [{{character-name}}](https://journal.roll20.net/character/{{character-id}}" name="name-link") |
+
-
-
- | Accuracy Check: |
-
- {{accuracy}}
- {{#target}}
- vs {{target}}
- {{/target}}
- |
-
-
- {{#^rollTotal() effectiveness-roll 2}}
-
-
- |
-
-
- {{#rollTotal() effectiveness-roll 0}}
- It was *really* ineffective...
- {{/rollTotal() effectiveness-roll 0}}
-
- {{#rollTotal() effectiveness-roll 1}}
- It wasn't very effective...
- {{/rollTotal() effectiveness-roll 1}}
-
- {{#rollTotal() effectiveness-roll 3}}
- It was super effective!
- {{/rollTotal() effectiveness-roll 3}}
-
- {{#rollTotal() effectiveness-roll 4}}
- It was extremely effective!
- {{/rollTotal() effectiveness-roll 4}}
-
- |
-
- {{/^rollTotal() effectiveness-roll 2}}
-
-
-
- {{#rollWasCrit() accuracy}}
- {{#rollGreater() critical-damage 0}}
-
- | {{move-type}} Damage: |
-
-
- {{critical-damage}}
-
- Critical Hit!
-
-
- |
-
- {{/rollGreater() critical-damage 0}}
- {{/rollWasCrit() accuracy}}
-
-
- {{#^rollWasCrit() accuracy}}
- {{#rollGreater() critical-damage 0}}
-
- {{#rollTotal() effect1_roll 99}}
- {{#^rollLess() accuracy effect1_threshold}}
-
- | {{move-type}} Damage: |
-
-
- {{critical-damage}}
-
- Critical Hit!
-
-
- |
-
- {{/^rollLess() accuracy effect1_threshold}}
-
-
- {{#rollLess() accuracy effect1_threshold}}
-
- | {{move-type}} Damage: |
-
-
- {{damage}}
-
- |
-
- {{/rollLess() accuracy effect1_threshold}}
- {{/rollTotal() effect1_roll 99}}
-
- {{/rollGreater() critical-damage 0}}
- {{/^rollWasCrit() accuracy}}
-
-
- {{#^rollWasCrit() accuracy}}
- {{#rollGreater() damage 0}}
- {{#rollLess() effect1_roll 99}}
-
- | {{move-type}} Damage: |
-
-
- {{damage}}
-
- |
-
- {{/rollLess() effect1_roll 99}}
- {{/rollGreater() damage 0}}
- {{/^rollWasCrit() accuracy}}
-
-
- {{#rollBetween() effect1_roll 1 10}}
- {{#^rollLess() accuracy effect1_threshold}}
-
- |
- The opponent was {{effect1_name}}
- |
-
- {{/^rollLess() accuracy effect1_threshold}}
- {{/rollBetween() effect1_roll 1 10}}
-
- {{#rollBetween() effect2_roll 1 10}}
- {{#^rollLess() accuracy effect2_threshold}}
-
- |
- The opponent was {{effect2_name}}
- |
-
- {{/^rollLess() accuracy effect2_threshold}}
- {{/rollBetween() effect2_roll 1 10}}
-
-
- {{#notes}}
-
- | {{notes}} |
-
- {{/notes}}
-
-
-
+
+
+ | Accuracy Check: |
+
+ {{accuracy}} {{#target}}
+ vs {{target}}
+ {{/target}}
+ |
+
+
+ {{#^rollTotal() effectiveness-roll 2}}
+
+
+ |
+
+
+ {{#rollTotal() effectiveness-roll 0}} It was *really* ineffective... {{/rollTotal() effectiveness-roll 0}}
+
+ {{#rollTotal() effectiveness-roll 1}} It wasn't very effective... {{/rollTotal() effectiveness-roll 1}}
+
+ {{#rollTotal() effectiveness-roll 3}} It was super effective! {{/rollTotal() effectiveness-roll 3}}
+
+ {{#rollTotal() effectiveness-roll 4}} It was extremely effective! {{/rollTotal() effectiveness-roll 4}}
+
+ |
+
+ {{/^rollTotal() effectiveness-roll 2}}
-
-
-
-
- | {{skill-name}} |
-
-
- | [{{character-name}}](https://journal.roll20.net/character/{{character-id}}" name="name-link") |
-
+
+
+ {{#rollWasCrit() accuracy}} {{#rollGreater() critical-damage 0}}
+
+ | {{move-type}} Damage: |
+
+
+ {{critical-damage}}
+ Critical Hit!
+
+ |
+
+ {{/rollGreater() critical-damage 0}} {{/rollWasCrit() accuracy}}
-
-
- | Skill Check: |
- {{skill-roll}} |
-
-
-
-
+
+ {{#^rollWasCrit() accuracy}} {{#rollGreater() critical-damage 0}} {{#rollTotal() effect1_roll 99}} {{#^rollLess() accuracy
+ effect1_threshold}}
+
+ | {{move-type}} Damage: |
+
+
+ {{critical-damage}}
+ Critical Hit!
+
+ |
+
+ {{/^rollLess() accuracy effect1_threshold}}
+
+
+ {{#rollLess() accuracy effect1_threshold}}
+
+ | {{move-type}} Damage: |
+
+ {{damage}}
+ |
+
+ {{/rollLess() accuracy effect1_threshold}} {{/rollTotal() effect1_roll 99}} {{/rollGreater() critical-damage 0}} {{/^rollWasCrit()
+ accuracy}}
+
+
+ {{#^rollWasCrit() accuracy}} {{#rollGreater() damage 0}} {{#rollLess() effect1_roll 99}}
+
+ | {{move-type}} Damage: |
+
+ {{damage}}
+ |
+
+ {{/rollLess() effect1_roll 99}} {{/rollGreater() damage 0}} {{/^rollWasCrit() accuracy}}
+
+
+ {{#rollBetween() effect1_roll 1 10}} {{#^rollLess() accuracy effect1_threshold}}
+
+ |
+ The opponent was {{effect1_name}}
+ |
+
+ {{/^rollLess() accuracy effect1_threshold}} {{/rollBetween() effect1_roll 1 10}} {{#rollBetween() effect2_roll 1 10}} {{#^rollLess()
+ accuracy effect2_threshold}}
+
+ |
+ The opponent was {{effect2_name}}
+ |
+
+ {{/^rollLess() accuracy effect2_threshold}} {{/rollBetween() effect2_roll 1 10}}
+
+
+ {{#notes}}
+
+ | {{notes}} |
+
+ {{/notes}}
+
+
+
+
+
+
+
+
+ | {{skill-name}} |
+
+
+ | [{{character-name}}](https://journal.roll20.net/character/{{character-id}}" name="name-link") |
+
+
+
+
+ | Skill Check: |
+ {{skill-roll}} |
+
+
+
+
\ No newline at end of file
+ );
+
+ // Handling Move Accuracy Bonuses
+ categoryAccuracyModifiers = ["", "ATKMOD", "SPATKMOD", "SPDMOD"];
+ on("change:ATKMOD change:SPATKMOD change:SPDMOD sheet:opened", function (eventInfo) {
+ getSectionIDs("repeating_moves", function (idArray) {
+ const rowNames = idArray.map((id) => `repeating_moves_${id}`);
+ const categories = idArray.map((id) => `repeating_moves_${id}_move_category`);
+ const accuracyMods = idArray.map((id) => `repeating_moves_${id}_move_acmod`);
+
+ getAttrs([`ATKMOD`, `SPATKMOD`, `SPDMOD`, ...categories, ...accuracyMods], function (values) {
+ const rows = rowNames.reduce((obj, rowName) => {
+ const category = parseInt(values[rowName + `_move_category`]) || 0;
+ const accuracy = parseInt(values[rowName + `_move_acmod`]) || 0;
+
+ const categoryModifier = parseInt(values[`${categoryAccuracyModifiers[category]}`]) || 0;
+ const total = categoryModifier + accuracy;
+ const roll = `d20 ${total < 0 ? "" : "+ "}${total}`;
+
+ obj[rowName + "_move_totalaccuracy"] = total;
+ obj[rowName + "_move_totalaccuracy_display"] = roll;
+ return obj;
+ }, {});
+ if (rows) setAttrs(rows);
+ });
+ });
+ });
+
+ on("change:repeating_moves:move_category change:repeating_moves:move_acmod", function (eventInfo) {
+ getAttrs([`ATKMOD`, `SPATKMOD`, `SPDMOD`, `repeating_moves_move_category`, `repeating_moves_move_acmod`], function (values) {
+ const category = parseInt(values.repeating_moves_move_category) || 0;
+ const accuracy = parseInt(values.repeating_moves_move_acmod) || 0;
+
+ const categoryModifier = parseInt(values[`${categoryAccuracyModifiers[category]}`]) || 0;
+ const total = categoryModifier + accuracy;
+ const roll = `d20 ${total < 0 ? "" : "+ "}${total}`;
+
+ setAttrs({
+ repeating_moves_move_totalaccuracy: total,
+ repeating_moves_move_totalaccuracy_display: roll,
+ });
+ });
+ });
+
+ // Skills Sheet Workers
+
+ // Acrobatics
+ on("change:SPDMOD change:acrobaticstalent1 change:acrobaticstalent2 change:acrobatics sheet:opened", function (eventInfo) {
+ getAttrs([`SPDMOD`, `acrobaticstalent1`, `acrobaticstalent2`, `acrobatics`, `acrobatics_total`], function (values) {
+ const stat = parseInt(values.SPDMOD) || 0;
+ const talent1 = parseInt(values.acrobaticstalent1) || 0;
+ const talent2 = parseInt(values.acrobaticstalent2) || 0;
+ const total = parseInt(values.acrobatics_total) || -1;
+ const userBonus = parseInt(values.acrobatics) || 0;
+
+ assignSkillTotal("acrobatics_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Athletics
+ on("change:ATKMOD change:athleticstalent1 change:athleticstalent2 change:athletics sheet:opened", function (eventInfo) {
+ getAttrs([`ATKMOD`, `athleticstalent1`, `athleticstalent2`, `athletics`, `athletics_total`], function (values) {
+ const stat = parseInt(values.ATKMOD) || 0;
+ const talent1 = parseInt(values.athleticstalent1) || 0;
+ const talent2 = parseInt(values.athleticstalent2) || 0;
+ const total = parseInt(values.athletics_total) || -1;
+ const userBonus = parseInt(values.athletics) || 0;
+
+ assignSkillTotal("athletics_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Bluff/Deception
+ on("change:SPDEFMOD change:blufftalent1 change:blufftalent2 change:bluff sheet:opened", function (eventInfo) {
+ getAttrs([`SPDEFMOD`, `blufftalent1`, `blufftalent2`, `bluff`, `bluff_total`], function (values) {
+ const stat = parseInt(values.SPDEFMOD) || 0;
+ const talent1 = parseInt(values.blufftalent1) || 0;
+ const talent2 = parseInt(values.blufftalent2) || 0;
+ const total = parseInt(values.bluff_total) || -1;
+ const userBonus = parseInt(values.bluff) || 0;
+
+ assignSkillTotal("bluff_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Concentration
+ on("change:DEFMOD change:concentrationtalent1 change:concentrationtalent2 change:concentration sheet:opened", function (eventInfo) {
+ getAttrs([`DEFMOD`, `concentrationtalent1`, `concentrationtalent2`, `concentration`, `concentration_total`], function (values) {
+ const stat = parseInt(values.DEFMOD) || 0;
+ const talent1 = parseInt(values.concentrationtalent1) || 0;
+ const talent2 = parseInt(values.concentrationtalent2) || 0;
+ const total = parseInt(values.concentration_total) || -1;
+ const userBonus = parseInt(values.concentration) || 0;
+
+ assignSkillTotal("concentration_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Constitution
+ on("change:DEFMOD change:constitutiontalent1 change:constitutiontalent2 change:constitution sheet:opened", function (eventInfo) {
+ getAttrs([`DEFMOD`, `constitutiontalent1`, `constitutiontalent2`, `constitution`, `constitution_total`], function (values) {
+ const stat = parseInt(values.DEFMOD) || 0;
+ const talent1 = parseInt(values.constitutiontalent1) || 0;
+ const talent2 = parseInt(values.constitutiontalent2) || 0;
+ const total = parseInt(values.constitution_total) || -1;
+ const userBonus = parseInt(values.constitution) || 0;
+
+ assignSkillTotal("constitution_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Diplomacy/Persuasion
+ on("change:SPDEFMOD change:diplomacytalent1 change:diplomacytalent2 change:diplomacy sheet:opened", function (eventInfo) {
+ getAttrs([`SPDEFMOD`, `diplomacytalent1`, `diplomacytalent2`, `diplomacy`, `diplomacy_total`], function (values) {
+ const stat = parseInt(values.SPDEFMOD) || 0;
+ const talent1 = parseInt(values.diplomacytalent1) || 0;
+ const talent2 = parseInt(values.diplomacytalent2) || 0;
+ const total = parseInt(values.diplomacy_total) || -1;
+ const userBonus = parseInt(values.diplomacy) || 0;
+
+ assignSkillTotal("diplomacy_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Engineering/Operation
+ on("change:SPATKMOD change:engineeringtalent1 change:engineeringtalent2 change:engineering sheet:opened", function (eventInfo) {
+ getAttrs([`SPATKMOD`, `engineeringtalent1`, `engineeringtalent2`, `engineering`, `engineering_total`], function (values) {
+ const stat = parseInt(values.SPATKMOD) || 0;
+ const talent1 = parseInt(values.engineeringtalent1) || 0;
+ const talent2 = parseInt(values.engineeringtalent2) || 0;
+ const total = parseInt(values.engineering_total) || -1;
+ const userBonus = parseInt(values.engineering) || 0;
+
+ assignSkillTotal("engineering_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // History
+ on("change:SPATKMOD change:historytalent1 change:historytalent2 change:history sheet:opened", function (eventInfo) {
+ getAttrs([`SPATKMOD`, `historytalent1`, `historytalent2`, `history`, `history_total`], function (values) {
+ const stat = parseInt(values.SPATKMOD) || 0;
+ const talent1 = parseInt(values.historytalent1) || 0;
+ const talent2 = parseInt(values.historytalent2) || 0;
+ const total = parseInt(values.history_total) || -1;
+ const userBonus = parseInt(values.history) || 0;
+
+ assignSkillTotal("history_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Insight
+ on("change:SPDEFMOD change:insighttalent1 change:insighttalent2 change:insight sheet:opened", function (eventInfo) {
+ getAttrs([`SPDEFMOD`, `insighttalent1`, `insighttalent2`, `insight`, `insight_total`], function (values) {
+ const stat = parseInt(values.SPDEFMOD) || 0;
+ const talent1 = parseInt(values.insighttalent1) || 0;
+ const talent2 = parseInt(values.insighttalent2) || 0;
+ const total = parseInt(values.insight_total) || -1;
+ const userBonus = parseInt(values.insight) || 0;
+
+ assignSkillTotal("insight_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Investigate
+ on("change:SPATKMOD change:investigatetalent1 change:investigatetalent2 change:investigate sheet:opened", function (eventInfo) {
+ getAttrs([`SPATKMOD`, `investigatetalent1`, `investigatetalent2`, `investigate`, `investigate_total`], function (values) {
+ const stat = parseInt(values.SPATKMOD) || 0;
+ const talent1 = parseInt(values.investigatetalent1) || 0;
+ const talent2 = parseInt(values.investigatetalent2) || 0;
+ const total = parseInt(values.investigate_total) || -1;
+ const userBonus = parseInt(values.investigate) || 0;
+
+ assignSkillTotal("investigate_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Medicine
+ on("change:SPATKMOD change:medicinetalent1 change:medicinetalent2 change:medicine sheet:opened", function (eventInfo) {
+ getAttrs([`SPATKMOD`, `medicinetalent1`, `medicinetalent2`, `medicine`, `medicine_total`], function (values) {
+ const stat = parseInt(values.SPATKMOD) || 0;
+ const talent1 = parseInt(values.medicinetalent1) || 0;
+ const talent2 = parseInt(values.medicinetalent2) || 0;
+ const total = parseInt(values.medicine_total) || -1;
+ const userBonus = parseInt(values.medicine) || 0;
+
+ assignSkillTotal("medicine_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Nature
+ on("change:SPATKMOD change:naturetalent1 change:naturetalent2 change:nature sheet:opened", function (eventInfo) {
+ getAttrs([`SPATKMOD`, `naturetalent1`, `naturetalent2`, `nature`, `nature_total`], function (values) {
+ const stat = parseInt(values.SPATKMOD) || 0;
+ const talent1 = parseInt(values.naturetalent1) || 0;
+ const talent2 = parseInt(values.naturetalent2) || 0;
+ const total = parseInt(values.nature_total) || -1;
+ const userBonus = parseInt(values.nature) || 0;
+
+ assignSkillTotal("nature_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Perception
+ on("change:SPDEFMOD change:perceptiontalent1 change:perceptiontalent2 change:perception sheet:opened", function (eventInfo) {
+ getAttrs([`SPDEFMOD`, `perceptiontalent1`, `perceptiontalent2`, `perception`, `perception_total`], function (values) {
+ const stat = parseInt(values.SPDEFMOD) || 0;
+ const talent1 = parseInt(values.perceptiontalent1) || 0;
+ const talent2 = parseInt(values.perceptiontalent2) || 0;
+ const total = parseInt(values.perception_total) || -1;
+ const userBonus = parseInt(values.perception) || 0;
+
+ assignSkillTotal("perception_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Perform
+ on("change:SPDEFMOD change:performtalent1 change:performtalent2 change:perform sheet:opened", function (eventInfo) {
+ getAttrs([`SPDEFMOD`, `performtalent1`, `performtalent2`, `perform`, `perform_total`], function (values) {
+ const stat = parseInt(values.SPDEFMOD) || 0;
+ const talent1 = parseInt(values.performtalent1) || 0;
+ const talent2 = parseInt(values.performtalent2) || 0;
+ const total = parseInt(values.perform_total) || -1;
+ const userBonus = parseInt(values.perform) || 0;
+
+ assignSkillTotal("perform_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Pokémon Handling
+ on("change:SPDEFMOD change:handlingtalent1 change:handlingtalent2 change:handling sheet:opened", function (eventInfo) {
+ getAttrs([`SPDEFMOD`, `handlingtalent1`, `handlingtalent2`, `handling`, `handling_total`], function (values) {
+ const stat = parseInt(values.SPDEFMOD) || 0;
+ const talent1 = parseInt(values.handlingtalent1) || 0;
+ const talent2 = parseInt(values.handlingtalent2) || 0;
+ const total = parseInt(values.handling_total) || -1;
+ const userBonus = parseInt(values.handling) || 0;
+
+ assignSkillTotal("handling_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Programming
+ on("change:SPATKMOD change:programmingtalent1 change:programmingtalent2 change:programming sheet:opened", function (eventInfo) {
+ getAttrs([`SPATKMOD`, `programmingtalent1`, `programmingtalent2`, `programming`, `programming_total`], function (values) {
+ const stat = parseInt(values.SPATKMOD) || 0;
+ const talent1 = parseInt(values.programmingtalent1) || 0;
+ const talent2 = parseInt(values.programmingtalent2) || 0;
+ const total = parseInt(values.programming_total) || -1;
+ const userBonus = parseInt(values.programming) || 0;
+
+ assignSkillTotal("programming_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Sleight of Hand
+ on("change:SPDMOD change:sleightofhandtalent1 change:sleightofhandtalent2 change:sleightofhand sheet:opened", function (eventInfo) {
+ getAttrs([`SPDMOD`, `sleightofhandtalent1`, `sleightofhandtalent2`, `sleightofhand`, `sleightofhand_total`], function (values) {
+ const stat = parseInt(values.SPDMOD) || 0;
+ const talent1 = parseInt(values.sleightofhandtalent1) || 0;
+ const talent2 = parseInt(values.sleightofhandtalent2) || 0;
+ const total = parseInt(values.sleightofhand_total) || -1;
+ const userBonus = parseInt(values.sleightofhand) || 0;
+
+ assignSkillTotal("sleightofhand_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Stealth
+ on("change:SPDMOD change:stealthtalent1 change:stealthtalent2 change:stealth sheet:opened", function (eventInfo) {
+ getAttrs([`SPDMOD`, `stealthtalent1`, `stealthtalent2`, `stealth`, `stealth_total`], function (values) {
+ const stat = parseInt(values.SPDMOD) || 0;
+ const talent1 = parseInt(values.stealthtalent1) || 0;
+ const talent2 = parseInt(values.stealthtalent2) || 0;
+ const total = parseInt(values.stealth_total) || -1;
+ const userBonus = parseInt(values.stealth) || 0;
+
+ assignSkillTotal("stealth_total", stat, talent1, talent2, total, userBonus);
+ });
+ });
+
+ // Capture
+ on("change:SPDMOD change:capture sheet:opened", function (eventInfo) {
+ getAttrs([`SPDMOD`, `capture_total`], function (values) {
+ const stat = parseInt(values.SPDMOD) || 0;
+ const total = parseInt(values.capture_total) || -1;
+
+ assignSkillTotal("capture_total", stat, 0, 0, total, 0);
+ });
+ });
+
+ function assignSkillTotal(skillName, stat, leftTalent, rightTalent, oldTotal, userBonus) {
+ const talentAccumulator = leftTalent + rightTalent == 4 ? 1 : 0;
+ const talent = leftTalent + rightTalent + talentAccumulator;
+
+ const newBonus = stat + talent + userBonus;
+ const attrs = { [skillName]: newBonus };
+ if (newBonus != oldTotal) setAttrs(attrs);
+ }
+