forked from GitHub-Mirrors/foundry-sw5e
System 1.1.1 ** Requires Foundry 0.7.6
System main update to be inline with dnd5e 1.1.1 Added active effects to as many sheets as I thought applicable. Please check loot, I made an attempt but it may be broken All .less .css and actor .html updates were made to the old actors. New actors may be broken with this update removed templates\actors\oldActor\parts\actor-effects.html for newer templates\actors\parts\active-effects.html removed module\apps\cast-dialog, templates\apps\cast-cast.html, and templates\items\cast.html. I do not think they are used, I think they were deprecated when powers were treated as items, if not we can add them back in. **NOTE** REQUIRES Foundry 0.7.6
This commit is contained in:
parent
27f5fa3670
commit
68a1b6a9f0
58 changed files with 1417 additions and 1706 deletions
23
lang/en.json
23
lang/en.json
|
@ -263,6 +263,11 @@
|
||||||
"SW5E.FeatureActionRecharge": "Action Recharge",
|
"SW5E.FeatureActionRecharge": "Action Recharge",
|
||||||
"SW5E.Flaws": "Flaws",
|
"SW5E.Flaws": "Flaws",
|
||||||
|
|
||||||
|
"SW5E.EffectCreate": "Create Effect",
|
||||||
|
"SW5E.EffectToggle": "Toggle Effect",
|
||||||
|
"SW5E.EffectEdit": "Edit Effect",
|
||||||
|
"SW5E.EffectDelete": "Delete Effect",
|
||||||
|
|
||||||
"SW5E.ItemTypeArchetype": "Archetype",
|
"SW5E.ItemTypeArchetype": "Archetype",
|
||||||
"SW5E.ItemTypeBackground": "Background",
|
"SW5E.ItemTypeBackground": "Background",
|
||||||
"Sw5E.ItemTypeBackgroundPl": "Backgrounds",
|
"Sw5E.ItemTypeBackgroundPl": "Backgrounds",
|
||||||
|
@ -332,6 +337,12 @@
|
||||||
"SW5E.FlagsRemarkableAthleteHint": "Half-Proficiency (rounded-up) to physical Ability Checks and Initiative.",
|
"SW5E.FlagsRemarkableAthleteHint": "Half-Proficiency (rounded-up) to physical Ability Checks and Initiative.",
|
||||||
"SW5E.FlagsCritThreshold": "Critical Hit Threshold",
|
"SW5E.FlagsCritThreshold": "Critical Hit Threshold",
|
||||||
"SW5E.FlagsCritThresholdHint": "Allow for expanded critical range; for example Improved or Superior Critical",
|
"SW5E.FlagsCritThresholdHint": "Allow for expanded critical range; for example Improved or Superior Critical",
|
||||||
|
"SW5E.FlagsWeaponCritThreshold": "Weapon Critical Hit Threshold",
|
||||||
|
"SW5E.FlagsWeaponCritThresholdHint": "An expanded critical hit threshold for weapon attacks.",
|
||||||
|
"SW5E.FlagsPowerCritThreshold": "Power Critical Hit Threshold",
|
||||||
|
"SW5E.FlagsPowerCritThresholdHint": "An expanded critical hit threshold for power attacks.",
|
||||||
|
"SW5E.FlagsMeleeCriticalDice": "Melee Critical Damage Dice",
|
||||||
|
"SW5E.FlagsMeleeCriticalDiceHint": "A number of additional damage dice added to melee weapon critical hits.",
|
||||||
|
|
||||||
"SW5E.Flat": "Flat",
|
"SW5E.Flat": "Flat",
|
||||||
"SW5E.Formula": "Formula",
|
"SW5E.Formula": "Formula",
|
||||||
|
@ -582,6 +593,17 @@
|
||||||
"SW5E.RollMode": "Roll Mode",
|
"SW5E.RollMode": "Roll Mode",
|
||||||
"SW5E.RollSituationalBonus": "Situational Bonus?",
|
"SW5E.RollSituationalBonus": "Situational Bonus?",
|
||||||
"SW5E.Save": "Save",
|
"SW5E.Save": "Save",
|
||||||
|
|
||||||
|
"SW5E.MovementConfig": "Configure Movement Speed",
|
||||||
|
"SW5E.MovementConfigHint": "Configure the movement speed and special movement attributes of this creature.",
|
||||||
|
"SW5E.MovementWalk": "Walk",
|
||||||
|
"SW5E.MovementBurrow": "Burrow",
|
||||||
|
"SW5E.MovementClimb": "Climb",
|
||||||
|
"SW5E.MovementHover": "Hover",
|
||||||
|
"SW5E.MovementFly": "Fly",
|
||||||
|
"SW5E.MovementSwim": "Swim",
|
||||||
|
"SW5E.MovementUnits": "Units",
|
||||||
|
|
||||||
"SW5E.SheetClassCharacter": "Default Character Sheet",
|
"SW5E.SheetClassCharacter": "Default Character Sheet",
|
||||||
"SW5E.SheetClassCharacterOld": "Old Character Sheet",
|
"SW5E.SheetClassCharacterOld": "Old Character Sheet",
|
||||||
"SW5E.SheetClassNPC": "Default NPC Sheet",
|
"SW5E.SheetClassNPC": "Default NPC Sheet",
|
||||||
|
@ -836,6 +858,7 @@
|
||||||
"SW5E.available": "available",
|
"SW5E.available": "available",
|
||||||
"SW5E.description": "A comprehensive game system for running games of Star Wars 5th Edition in the Foundry VTT environment.",
|
"SW5E.description": "A comprehensive game system for running games of Star Wars 5th Edition in the Foundry VTT environment.",
|
||||||
"SW5E.of": "of",
|
"SW5E.of": "of",
|
||||||
|
"SW5E.per": "per",
|
||||||
"SW5E.power": "power",
|
"SW5E.power": "power",
|
||||||
"SETTINGS.5eAllowPolymorphingL": "Allow players to polymorph their own actors.",
|
"SETTINGS.5eAllowPolymorphingL": "Allow players to polymorph their own actors.",
|
||||||
"SETTINGS.5eAllowPolymorphingN": "Allow Polymorphing",
|
"SETTINGS.5eAllowPolymorphingN": "Allow Polymorphing",
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
.russoOne(14px);
|
.russoOne(14px);
|
||||||
color: @colorOlive;
|
color: @colorOlive;
|
||||||
border-bottom: 1px solid @colorFaint;
|
border-bottom: 1px solid @colorFaint;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
@ -142,6 +143,7 @@
|
||||||
font-family: "Signika", sans-serif;
|
font-family: "Signika", sans-serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,46 +415,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inventory item lists
|
||||||
.inventory-list {
|
.inventory-list {
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
overflow-y: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
color: @colorTan;
|
|
||||||
|
|
||||||
// Inventory Item
|
|
||||||
.item {
|
.item {
|
||||||
line-height: 30px;
|
|
||||||
padding: 0 2px; // to align with the header border
|
|
||||||
border-bottom: 1px solid @colorFaint;
|
|
||||||
&:last-child { border-bottom: none; }
|
|
||||||
|
|
||||||
// Item Header Name
|
|
||||||
.item-name {
|
.item-name {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
max-height: 30px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.item-image {
|
|
||||||
flex: 0 0 30px;
|
|
||||||
background-size: 30px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rollable:hover .item-image {
|
&.rollable:hover .item-image {
|
||||||
background-image: url("../../icons/svg/d20-grey.svg") !important;
|
background-image: url("../../icons/svg/d20-grey.svg") !important;
|
||||||
}
|
}
|
||||||
&.rollable .item-image:hover {
|
&.rollable .item-image:hover {
|
||||||
background-image: url("../../icons/svg/d20-black.svg") !important;
|
background-image: url("../../icons/svg/d20-black.svg") !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.attuned {
|
i.attuned {
|
||||||
color: @colorTan;
|
color: @colorTan;
|
||||||
}
|
}
|
||||||
|
@ -474,49 +448,26 @@
|
||||||
flex: 0 0 80px;
|
flex: 0 0 80px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: @colorTan;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inventory Header
|
// Inventory Header
|
||||||
.inventory-header {
|
.inventory-header {
|
||||||
margin: 2px 0;
|
|
||||||
padding: 0;
|
|
||||||
align-items: center;
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
border: @borderGroove;
|
|
||||||
font-weight: bold;
|
|
||||||
line-height: 24px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0 -5px 0 0;
|
|
||||||
padding-left: 5px;
|
|
||||||
.russoOne();
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-controls a.item-create {
|
.item-controls a.item-create {
|
||||||
flex: 0 0 100%;
|
flex: 0 0 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item names
|
|
||||||
.item-name {
|
|
||||||
color: @colorDark;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Item Detail Sections
|
// Item Detail Sections
|
||||||
.item-detail {
|
.item-detail {
|
||||||
flex: 0 0 70px;
|
flex: 0 0 70px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: @colorTan;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-right: 1px solid @colorFaint;
|
border-right: 1px solid @colorFaint;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&:last-child { border-right: none; }
|
&:last-child { border-right: none; }
|
||||||
&.item-action {flex: 0 0 100px}
|
&.item-action {flex: 0 0 100px}
|
||||||
}
|
}
|
||||||
|
@ -527,24 +478,9 @@
|
||||||
border-right: 1px solid @colorFaint;
|
border-right: 1px solid @colorFaint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Item Control Buttons
|
// Item Control Buttons
|
||||||
.item-controls {
|
.item-controls {
|
||||||
flex: 0 0 44px;
|
flex: 0 0 44px;
|
||||||
.flexrow();
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
a {
|
|
||||||
flex: 0 0 22px;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
color: @colorTan;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item Dropdown Summary
|
// Item Dropdown Summary
|
||||||
|
@ -553,6 +489,7 @@
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
|
color: @colorDark;
|
||||||
border-top: 1px solid @colorFaint;
|
border-top: 1px solid @colorFaint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,44 +630,6 @@
|
||||||
// Empty powerbook controls
|
// Empty powerbook controls
|
||||||
.powerbook-empty .item-controls { flex: 1; }
|
.powerbook-empty .item-controls { flex: 1; }
|
||||||
|
|
||||||
/* ----------------------------------------- */
|
|
||||||
/* Active Effects */
|
|
||||||
/* ----------------------------------------- */
|
|
||||||
|
|
||||||
.effects {
|
|
||||||
.effect-name{
|
|
||||||
flex: 2;
|
|
||||||
align-items: center;
|
|
||||||
color: @colorDark;
|
|
||||||
h4 { margin: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect-icon {
|
|
||||||
flex: 0 0 30px;
|
|
||||||
height: 30px;
|
|
||||||
margin-right: 5px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect-source,
|
|
||||||
.effect-duration {
|
|
||||||
text-align: center;
|
|
||||||
border-left: 1px solid @colorFaint;
|
|
||||||
border-right: 1px solid @colorFaint;
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect-controls {
|
|
||||||
flex: 0 0 60px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect {
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid @colorFaint;
|
|
||||||
&:last-child { border-bottom: none; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* TinyMCE */
|
/* TinyMCE */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
@ -739,3 +638,18 @@
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#actor-flags {
|
||||||
|
.window-content {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
form {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.form-body {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
|
@ -362,6 +362,108 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Items Lists */
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
|
||||||
|
.items-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
color: @colorTan;
|
||||||
|
|
||||||
|
// Child lists
|
||||||
|
.item-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual Item
|
||||||
|
.item {
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 2px; // to align with the header border
|
||||||
|
border-bottom: 1px solid @colorFaint;
|
||||||
|
&:last-child { border-bottom: none; }
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
color: @colorDark;
|
||||||
|
.item-image {
|
||||||
|
flex: 0 0 30px;
|
||||||
|
height: 30px;
|
||||||
|
background-size: 30px;
|
||||||
|
border: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section Header
|
||||||
|
.items-header {
|
||||||
|
height: 28px;
|
||||||
|
margin: 2px 0;
|
||||||
|
padding: 0;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
border: @borderGroove;
|
||||||
|
font-weight: bold;
|
||||||
|
> * {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.item-name {
|
||||||
|
padding-left: 5px;
|
||||||
|
.modesto();
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item Name
|
||||||
|
.item-name {
|
||||||
|
flex: 2;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: left;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control Buttons
|
||||||
|
.item-controls {
|
||||||
|
flex: 0 0 60px;
|
||||||
|
justify-content: space-between;
|
||||||
|
a {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Active Effects */
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
|
||||||
|
.effects .item {
|
||||||
|
.effect-source,
|
||||||
|
.effect-duration,
|
||||||
|
.effect-controls {
|
||||||
|
text-align: center;
|
||||||
|
border-left: 1px solid @colorFaint;
|
||||||
|
border-right: 1px solid @colorFaint;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.effect-controls {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -116,17 +116,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group.uses-per {
|
.form-group.uses-per {
|
||||||
|
.form-fields {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
input {
|
input {
|
||||||
flex: 1;
|
flex: 0 0 32px;
|
||||||
}
|
}
|
||||||
span {
|
span {
|
||||||
flex: 0 0 16px;
|
flex: 0 0 16px;
|
||||||
}
|
margin: 0 4px 0 0;
|
||||||
select {
|
|
||||||
flex: 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span.sep {
|
span.sep {
|
||||||
flex: 0 0 8px;
|
flex: 0 0 8px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import AbilityTemplate from "../pixi/ability-template.js";
|
||||||
import {SW5E} from '../config.js';
|
import {SW5E} from '../config.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the base Actor class to implement additional logic specialized for SW5e.
|
* Extend the base Actor class to implement additional system-specific logic for SW5e.
|
||||||
*/
|
*/
|
||||||
export default class Actor5e extends Actor {
|
export default class Actor5e extends Actor {
|
||||||
|
|
||||||
|
@ -20,48 +20,6 @@ export default class Actor5e extends Actor {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* TODO: This becomes unnecessary after 0.7.x is released
|
|
||||||
*/
|
|
||||||
initialize() {
|
|
||||||
try {
|
|
||||||
this.prepareData();
|
|
||||||
} catch(err) {
|
|
||||||
console.error(`Failed to initialize data for ${this.constructor.name} ${this.id}:`);
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* TODO: This becomes unnecessary after 0.7.x is released
|
|
||||||
*/
|
|
||||||
prepareData() {
|
|
||||||
const is07x = !isNewerVersion("0.7.1", game.data.version);
|
|
||||||
if ( is07x ) this.data = duplicate(this._data);
|
|
||||||
if (!this.data.img) this.data.img = CONST.DEFAULT_TOKEN;
|
|
||||||
if ( !this.data.name ) this.data.name = "New " + this.entity;
|
|
||||||
this.prepareBaseData();
|
|
||||||
this.prepareEmbeddedEntities();
|
|
||||||
if ( is07x ) this.applyActiveEffects();
|
|
||||||
this.prepareDerivedData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* TODO: This becomes unnecessary after 0.7.x is released
|
|
||||||
*/
|
|
||||||
applyActiveEffects() {
|
|
||||||
if (!isNewerVersion("0.7.1", game.data.version)) return super.applyActiveEffects();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
prepareBaseData() {
|
prepareBaseData() {
|
||||||
switch ( this.data.type ) {
|
switch ( this.data.type ) {
|
||||||
|
@ -116,6 +74,11 @@ export default class Actor5e extends Actor {
|
||||||
abl.save = Math.max(abl.save, originalSaves[id].save);
|
abl.save = Math.max(abl.save, originalSaves[id].save);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inventory encumbrance
|
||||||
|
data.attributes.encumbrance = this._computeEncumbrance(actorData);
|
||||||
|
|
||||||
|
// Prepare skills
|
||||||
this._prepareSkills(actorData, bonuses, checkBonus, originalSkills);
|
this._prepareSkills(actorData, bonuses, checkBonus, originalSkills);
|
||||||
|
|
||||||
// Determine Initiative Modifier
|
// Determine Initiative Modifier
|
||||||
|
@ -126,7 +89,8 @@ export default class Actor5e extends Actor {
|
||||||
if ( joat ) init.prof = Math.floor(0.5 * data.attributes.prof);
|
if ( joat ) init.prof = Math.floor(0.5 * data.attributes.prof);
|
||||||
else if ( athlete ) init.prof = Math.ceil(0.5 * data.attributes.prof);
|
else if ( athlete ) init.prof = Math.ceil(0.5 * data.attributes.prof);
|
||||||
else init.prof = 0;
|
else init.prof = 0;
|
||||||
init.bonus = Number(init.value + (flags.initiativeAlert ? 5 : 0));
|
init.value = init.value ?? 0;
|
||||||
|
init.bonus = init.value + (flags.initiativeAlert ? 5 : 0);
|
||||||
init.total = init.mod + init.prof + init.bonus;
|
init.total = init.mod + init.prof + init.bonus;
|
||||||
|
|
||||||
// Prepare power-casting data
|
// Prepare power-casting data
|
||||||
|
@ -169,7 +133,7 @@ export default class Actor5e extends Actor {
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
data.prof = this.data.data.attributes.prof;
|
data.prof = this.data.data.attributes.prof || 0;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,33 +141,36 @@ export default class Actor5e extends Actor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the features which a character is awarded for each class level
|
* Return the features which a character is awarded for each class level
|
||||||
* @param cls {Object} Data object for class, equivalent to Item5e.data or raw compendium entry
|
* @param {string} className The class name being added
|
||||||
|
* @param {string} subclassName The subclass of the class being added, if any
|
||||||
|
* @param {number} level The number of levels in the added class
|
||||||
|
* @param {number} priorLevel The previous level of the added class
|
||||||
* @return {Promise<Item5e[]>} Array of Item5e entities
|
* @return {Promise<Item5e[]>} Array of Item5e entities
|
||||||
*/
|
*/
|
||||||
static async getClassFeatures(cls) {
|
static async getClassFeatures({className="", subclassName="", level=1, priorLevel=0}={}) {
|
||||||
const level = cls.data.levels;
|
className = className.toLowerCase();
|
||||||
const className = cls.name.toLowerCase();
|
subclassName = subclassName.slugify();
|
||||||
|
|
||||||
// Get the configuration of features which may be added
|
// Get the configuration of features which may be added
|
||||||
const clsConfig = CONFIG.SW5E.classFeatures[className];
|
const clsConfig = CONFIG.SW5E.classFeatures[className];
|
||||||
if (!clsConfig) return [];
|
if (!clsConfig) return [];
|
||||||
let featureIDs = clsConfig["features"][level] || [];
|
|
||||||
const subclassName = cls.data.subclass.toLowerCase().slugify();
|
|
||||||
|
|
||||||
// Identify subclass features
|
// Acquire class features
|
||||||
if ( subclassName !== "" ) {
|
let ids = [];
|
||||||
const subclassConfig = clsConfig["subclasses"][subclassName];
|
for ( let [l, f] of Object.entries(clsConfig.features || {}) ) {
|
||||||
if ( subclassConfig !== undefined ) {
|
l = parseInt(l);
|
||||||
const subclassFeatureIDs = subclassConfig["features"][level];
|
if ( (l <= level) && (l > priorLevel) ) ids = ids.concat(f);
|
||||||
if ( subclassFeatureIDs ) {
|
}
|
||||||
featureIDs = featureIDs.concat(subclassFeatureIDs);
|
|
||||||
}
|
// Acquire subclass features
|
||||||
}
|
const subConfig = clsConfig.subclasses[subclassName] || {};
|
||||||
else console.warn("Invalid subclass: " + subclassName);
|
for ( let [l, f] of Object.entries(subConfig.features || {}) ) {
|
||||||
|
l = parseInt(l);
|
||||||
|
if ( (l <= level) && (l > priorLevel) ) ids = ids.concat(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load item data for all identified features
|
// Load item data for all identified features
|
||||||
const features = await Promise.all(featureIDs.map(id => fromUuid(id)));
|
const features = await Promise.all(ids.map(id => fromUuid(id)));
|
||||||
|
|
||||||
// Class powers should always be prepared
|
// Class powers should always be prepared
|
||||||
for ( const feature of features ) {
|
for ( const feature of features ) {
|
||||||
|
@ -237,35 +204,28 @@ export default class Actor5e extends Actor {
|
||||||
for (let u of updated instanceof Array ? updated : [updated]) {
|
for (let u of updated instanceof Array ? updated : [updated]) {
|
||||||
const item = this.items.get(u._id);
|
const item = this.items.get(u._id);
|
||||||
if (!item || (item.data.type !== "class")) continue;
|
if (!item || (item.data.type !== "class")) continue;
|
||||||
const classData = duplicate(item.data);
|
const updateData = expandObject(u);
|
||||||
let changed = false;
|
const config = {
|
||||||
|
className: updateData.name || item.data.name,
|
||||||
|
subclassName: updateData.data.subclass || item.data.data.subclass,
|
||||||
|
level: getProperty(updateData, "data.levels"),
|
||||||
|
priorLevel: item ? item.data.data.levels : 0
|
||||||
|
}
|
||||||
|
|
||||||
// Get and create features for an increased class level
|
// Get and create features for an increased class level
|
||||||
const newLevels = getProperty(u, "data.levels");
|
let changed = false;
|
||||||
if (newLevels && (newLevels > item.data.data.levels)) {
|
if ( config.level && (config.level > config.priorLevel)) changed = true;
|
||||||
classData.data.levels = newLevels;
|
if ( config.subclassName !== item.data.data.subclass ) changed = true;
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get features for a newly changed subclass
|
// Get features to create
|
||||||
const newSubclass = getProperty(u, "data.subclass");
|
|
||||||
if (newSubclass && (newSubclass !== item.data.data.subclass)) {
|
|
||||||
classData.data.subclass = newSubclass;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the new features
|
|
||||||
if ( changed ) {
|
if ( changed ) {
|
||||||
const features = await Actor5e.getClassFeatures(classData);
|
const existing = new Set(this.items.map(i => i.name));
|
||||||
if ( features.length ) toCreate.push(...features);
|
const features = await Actor5e.getClassFeatures(config);
|
||||||
|
for ( let f of features ) {
|
||||||
|
if ( !existing.has(f.name) ) toCreate.push(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-dupe created items with ones that already exist (by name)
|
|
||||||
if ( toCreate.length ) {
|
|
||||||
const existing = new Set(this.items.map(i => i.name));
|
|
||||||
toCreate = toCreate.filter(c => !existing.has(c.name));
|
|
||||||
}
|
|
||||||
return toCreate
|
return toCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,9 +261,6 @@ export default class Actor5e extends Actor {
|
||||||
const required = xp.max - prior;
|
const required = xp.max - prior;
|
||||||
const pct = Math.round((xp.value - prior) * 100 / required);
|
const pct = Math.round((xp.value - prior) * 100 / required);
|
||||||
xp.pct = Math.clamped(pct, 0, 100);
|
xp.pct = Math.clamped(pct, 0, 100);
|
||||||
|
|
||||||
// Inventory encumbrance
|
|
||||||
data.attributes.encumbrance = this._computeEncumbrance(actorData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -369,17 +326,17 @@ export default class Actor5e extends Actor {
|
||||||
}
|
}
|
||||||
if ( joat && (skl.value === 0 ) ) multi = 0.5;
|
if ( joat && (skl.value === 0 ) ) multi = 0.5;
|
||||||
|
|
||||||
|
// Retain the maximum skill proficiency when skill proficiencies are merged
|
||||||
|
if ( originalSkills ) {
|
||||||
|
skl.value = Math.max(skl.value, originalSkills[id].value);
|
||||||
|
}
|
||||||
|
|
||||||
// Compute modifier
|
// Compute modifier
|
||||||
skl.bonus = checkBonus + skillBonus;
|
skl.bonus = checkBonus + skillBonus;
|
||||||
skl.mod = data.abilities[skl.ability].mod;
|
skl.mod = data.abilities[skl.ability].mod;
|
||||||
skl.prof = round(multi * data.attributes.prof);
|
skl.prof = round(multi * data.attributes.prof);
|
||||||
skl.total = skl.mod + skl.prof + skl.bonus;
|
skl.total = skl.mod + skl.prof + skl.bonus;
|
||||||
|
|
||||||
// If we merged skills when transforming, take the highest bonus here.
|
|
||||||
if (originalSkills && skl.value > 0.5) {
|
|
||||||
skl.total = Math.max(skl.total, originalSkills[id].total);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute passive bonus
|
// Compute passive bonus
|
||||||
const passive = observant && (feats.observantFeat.skills.includes(id)) ? 5 : 0;
|
const passive = observant && (feats.observantFeat.skills.includes(id)) ? 5 : 0;
|
||||||
skl.passive = 10 + skl.total + passive;
|
skl.passive = 10 + skl.total + passive;
|
||||||
|
@ -489,8 +446,8 @@ export default class Actor5e extends Actor {
|
||||||
else powers.pact.max = Math.max(1, Math.min(pl, 2), Math.min(pl - 8, 3), Math.min(pl - 13, 4));
|
else powers.pact.max = Math.max(1, Math.min(pl, 2), Math.min(pl - 8, 3), Math.min(pl - 13, 4));
|
||||||
powers.pact.value = Math.min(powers.pact.value, powers.pact.max);
|
powers.pact.value = Math.min(powers.pact.value, powers.pact.max);
|
||||||
} else {
|
} else {
|
||||||
powers.pact.level = 0;
|
powers.pact.max = parseInt(powers.pact.override) || 0
|
||||||
powers.pact.max = 0;
|
powers.pact.level = powers.pact.max > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,14 +470,14 @@ export default class Actor5e extends Actor {
|
||||||
if ( !physicalItems.includes(i.type) ) return weight;
|
if ( !physicalItems.includes(i.type) ) return weight;
|
||||||
const q = i.data.quantity || 0;
|
const q = i.data.quantity || 0;
|
||||||
const w = i.data.weight || 0;
|
const w = i.data.weight || 0;
|
||||||
return weight + Math.round(q * w * 10) / 10;
|
return weight + (q * w);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// [Optional] add Currency Weight
|
// [Optional] add Currency Weight
|
||||||
if ( game.settings.get("sw5e", "currencyWeight") ) {
|
if ( game.settings.get("sw5e", "currencyWeight") ) {
|
||||||
const currency = actorData.data.currency;
|
const currency = actorData.data.currency;
|
||||||
const numCoins = Object.values(currency).reduce((val, denom) => val += Math.max(denom, 0), 0);
|
const numCoins = Object.values(currency).reduce((val, denom) => val += Math.max(denom, 0), 0);
|
||||||
weight += Math.round((numCoins * 10) / CONFIG.SW5E.encumbrance.currencyPerWeight) / 10;
|
weight += numCoins / CONFIG.SW5E.encumbrance.currencyPerWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the encumbrance size class
|
// Determine the encumbrance size class
|
||||||
|
@ -535,9 +492,10 @@ export default class Actor5e extends Actor {
|
||||||
if ( this.getFlag("sw5e", "powerfulBuild") ) mod = Math.min(mod * 2, 8);
|
if ( this.getFlag("sw5e", "powerfulBuild") ) mod = Math.min(mod * 2, 8);
|
||||||
|
|
||||||
// Compute Encumbrance percentage
|
// Compute Encumbrance percentage
|
||||||
|
weight = weight.toNearest(0.1);
|
||||||
const max = actorData.data.abilities.str.value * CONFIG.SW5E.encumbrance.strMultiplier * mod;
|
const max = actorData.data.abilities.str.value * CONFIG.SW5E.encumbrance.strMultiplier * mod;
|
||||||
const pct = Math.clamped((weight* 100) / max, 0, 100);
|
const pct = Math.clamped((weight * 100) / max, 0, 100);
|
||||||
return { value: weight, max, pct, encumbered: pct > (2/3) };
|
return { value: weight.toNearest(0.1), max, pct, encumbered: pct > (2/3) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -564,9 +522,6 @@ export default class Actor5e extends Actor {
|
||||||
/** @override */
|
/** @override */
|
||||||
async update(data, options={}) {
|
async update(data, options={}) {
|
||||||
|
|
||||||
// TODO: 0.7.1 compatibility - remove when stable
|
|
||||||
if ( !data.hasOwnProperty("data") ) data = expandObject(data);
|
|
||||||
|
|
||||||
// Apply changes in Actor size to Token width/height
|
// Apply changes in Actor size to Token width/height
|
||||||
const newSize = getProperty(data, "data.traits.size");
|
const newSize = getProperty(data, "data.traits.size");
|
||||||
if ( newSize && (newSize !== getProperty(this.data, "data.traits.size")) ) {
|
if ( newSize && (newSize !== getProperty(this.data, "data.traits.size")) ) {
|
||||||
|
@ -577,7 +532,7 @@ export default class Actor5e extends Actor {
|
||||||
data["token.width"] = size;
|
data["token.width"] = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset death save counters
|
// Reset death save counters
|
||||||
if ( (this.data.data.attributes.hp.value <= 0) && (getProperty(data, "data.attributes.hp.value") > 0) ) {
|
if ( (this.data.data.attributes.hp.value <= 0) && (getProperty(data, "data.attributes.hp.value") > 0) ) {
|
||||||
setProperty(data, "data.attributes.death.success", 0);
|
setProperty(data, "data.attributes.death.success", 0);
|
||||||
|
@ -858,7 +813,7 @@ export default class Actor5e extends Actor {
|
||||||
rollAbilitySave(abilityId, options={}) {
|
rollAbilitySave(abilityId, options={}) {
|
||||||
const label = CONFIG.SW5E.abilities[abilityId];
|
const label = CONFIG.SW5E.abilities[abilityId];
|
||||||
const abl = this.data.data.abilities[abilityId];
|
const abl = this.data.data.abilities[abilityId];
|
||||||
|
|
||||||
// Construct parts
|
// Construct parts
|
||||||
const parts = ["@mod"];
|
const parts = ["@mod"];
|
||||||
const data = {mod: abl.mod};
|
const data = {mod: abl.mod};
|
||||||
|
@ -937,7 +892,7 @@ export default class Actor5e extends Actor {
|
||||||
|
|
||||||
// Take action depending on the result
|
// Take action depending on the result
|
||||||
const success = roll.total >= 10;
|
const success = roll.total >= 10;
|
||||||
const d20 = roll.dice[0].total;
|
const d20 = roll.dice[0].total;
|
||||||
|
|
||||||
// Save success
|
// Save success
|
||||||
if ( success ) {
|
if ( success ) {
|
||||||
|
@ -1429,14 +1384,16 @@ export default class Actor5e extends Actor {
|
||||||
if ( !original ) return;
|
if ( !original ) return;
|
||||||
|
|
||||||
// Get the Tokens which represent this actor
|
// Get the Tokens which represent this actor
|
||||||
const tokens = this.getActiveTokens(true);
|
if ( canvas.ready ) {
|
||||||
const tokenUpdates = tokens.map(t => {
|
const tokens = this.getActiveTokens(true);
|
||||||
const tokenData = duplicate(original.data.token);
|
const tokenUpdates = tokens.map(t => {
|
||||||
tokenData._id = t.id;
|
const tokenData = duplicate(original.data.token);
|
||||||
tokenData.actorId = original.id;
|
tokenData._id = t.id;
|
||||||
return tokenData;
|
tokenData.actorId = original.id;
|
||||||
});
|
return tokenData;
|
||||||
canvas.scene.updateEmbeddedEntity("Token", tokenUpdates);
|
});
|
||||||
|
canvas.scene.updateEmbeddedEntity("Token", tokenUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the polymorphed Actor and maybe re-render the original sheet
|
// Delete the polymorphed Actor and maybe re-render the original sheet
|
||||||
const isRendered = this.sheet.rendered;
|
const isRendered = this.sheet.rendered;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import Item5e from "../../item/entity.js";
|
import Item5e from "../../item/entity.js";
|
||||||
import TraitSelector from "../../apps/trait-selector.js";
|
import TraitSelector from "../../apps/trait-selector.js";
|
||||||
import ActorSheetFlags from "../../apps/actor-flags.js";
|
import ActorSheetFlags from "../../apps/actor-flags.js";
|
||||||
|
import MovementConfig from "../../apps/movement-config.js";
|
||||||
import {SW5E} from '../../config.js';
|
import {SW5E} from '../../config.js';
|
||||||
|
import {onManageActiveEffect, prepareActiveEffectCategories} from "../../effects.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the basic ActorSheet class to do all the SW5e things!
|
* Extend the basic ActorSheet class to suppose SW5e-specific logic and functionality.
|
||||||
* This sheet is an Abstract layer which is not used.
|
* This sheet is an Abstract layer which is not used.
|
||||||
* @extends {ActorSheet}
|
* @extends {ActorSheet}
|
||||||
*/
|
*/
|
||||||
|
@ -94,6 +96,9 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Movement speeds
|
||||||
|
data.movement = this._getMovementSpeed(data.actor);
|
||||||
|
|
||||||
// Update traits
|
// Update traits
|
||||||
this._prepareTraits(data.actor.data.traits);
|
this._prepareTraits(data.actor.data.traits);
|
||||||
|
|
||||||
|
@ -101,7 +106,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
this._prepareItems(data);
|
this._prepareItems(data);
|
||||||
|
|
||||||
// Prepare active effects
|
// Prepare active effects
|
||||||
this._prepareEffects(data);
|
data.effects = prepareActiveEffectCategories(this.entity.effects);
|
||||||
|
|
||||||
// Return data to the sheet
|
// Return data to the sheet
|
||||||
return data
|
return data
|
||||||
|
@ -109,6 +114,28 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the display of movement speed data for the Actor
|
||||||
|
* @param {object} actorData
|
||||||
|
* @returns {{primary: string, special: string}}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_getMovementSpeed(actorData) {
|
||||||
|
const movement = actorData.data.attributes.movement;
|
||||||
|
const speeds = [
|
||||||
|
[movement.burrow, `${game.i18n.localize("SW5E.MovementBurrow")} ${movement.burrow}`],
|
||||||
|
[movement.climb, `${game.i18n.localize("SW5E.MovementClimb")} ${movement.climb}`],
|
||||||
|
[movement.fly, `${game.i18n.localize("SW5E.MovementFly")} ${movement.fly}` + (movement.hover ? ` (${game.i18n.localize("SW5E.MovementHover")})` : "")],
|
||||||
|
[movement.swim, `${game.i18n.localize("SW5E.MovementSwim")} ${movement.swim}`]
|
||||||
|
].filter(s => !!s[0]).sort((a, b) => b[0] - a[0]);
|
||||||
|
return {
|
||||||
|
primary: `${movement.walk || 0} ${movement.units}`,
|
||||||
|
special: speeds.length ? speeds.map(s => s[1]).join(", ") : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the data structure for traits data like languages, resistances & vulnerabilities, and proficiencies
|
* Prepare the data structure for traits data like languages, resistances & vulnerabilities, and proficiencies
|
||||||
* @param {object} traits The raw traits data object from the actor data
|
* @param {object} traits The raw traits data object from the actor data
|
||||||
|
@ -147,43 +174,6 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the data structure for Active Effects which are currently applied to the Actor.
|
|
||||||
* @param {object} data The object of rendering data which is being prepared
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_prepareEffects(data) {
|
|
||||||
|
|
||||||
// Define effect header categories
|
|
||||||
const categories = {
|
|
||||||
temporary: {
|
|
||||||
label: "Temporary Effects",
|
|
||||||
effects: []
|
|
||||||
},
|
|
||||||
passive: {
|
|
||||||
label: "Passive Effects",
|
|
||||||
effects: []
|
|
||||||
},
|
|
||||||
inactive: {
|
|
||||||
label: "Inactive Effects",
|
|
||||||
effects: []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Iterate over active effects, classifying them into categories
|
|
||||||
for ( let e of this.actor.effects ) {
|
|
||||||
e._getSourceName(); // Trigger a lookup for the source name
|
|
||||||
if ( e.data.disabled ) categories.inactive.effects.push(e);
|
|
||||||
else if ( e.isTemporary ) categories.temporary.effects.push(e);
|
|
||||||
else categories.passive.effects.push(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the prepared categories of effects to the rendering data
|
|
||||||
return data.effects = categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a power into the powerbook object when rendering the character sheet
|
* Insert a power into the powerbook object when rendering the character sheet
|
||||||
* @param {Object} data The Actor data being prepared
|
* @param {Object} data The Actor data being prepared
|
||||||
|
@ -242,7 +232,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
registerSection(sl, lvl, CONFIG.SW5E.powerLevels[lvl], levels[sl]);
|
registerSection(sl, lvl, CONFIG.SW5E.powerLevels[lvl], levels[sl]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pact magic users have cantrips and a pact magic section
|
// Pact magic users have cantrips and a pact magic section
|
||||||
if ( levels.pact && levels.pact.max ) {
|
if ( levels.pact && levels.pact.max ) {
|
||||||
if ( !powerbook["0"] ) registerSection("power0", 0, CONFIG.SW5E.powerLevels[0]);
|
if ( !powerbook["0"] ) registerSection("power0", 0, CONFIG.SW5E.powerLevels[0]);
|
||||||
|
@ -363,7 +353,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
filterLists.on("click", ".filter-item", this._onToggleFilter.bind(this));
|
filterLists.on("click", ".filter-item", this._onToggleFilter.bind(this));
|
||||||
|
|
||||||
// Item summaries
|
// Item summaries
|
||||||
html.find('.item .item-name h4').click(event => this._onItemSummary(event));
|
html.find('.item .item-name.rollable h4').click(event => this._onItemSummary(event));
|
||||||
|
|
||||||
// Editable Only Listeners
|
// Editable Only Listeners
|
||||||
if ( this.isEditable ) {
|
if ( this.isEditable ) {
|
||||||
|
@ -383,6 +373,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
html.find('.trait-selector').click(this._onTraitSelector.bind(this));
|
html.find('.trait-selector').click(this._onTraitSelector.bind(this));
|
||||||
|
|
||||||
// Configure Special Flags
|
// Configure Special Flags
|
||||||
|
html.find('.configure-movement').click(this._onMovementConfig.bind(this));
|
||||||
html.find('.configure-flags').click(this._onConfigureFlags.bind(this));
|
html.find('.configure-flags').click(this._onConfigureFlags.bind(this));
|
||||||
|
|
||||||
// Owned Item management
|
// Owned Item management
|
||||||
|
@ -393,8 +384,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
html.find('.slot-max-override').click(this._onPowerSlotOverride.bind(this));
|
html.find('.slot-max-override').click(this._onPowerSlotOverride.bind(this));
|
||||||
|
|
||||||
// Active Effect management
|
// Active Effect management
|
||||||
html.find(".effect-control").click(this._onManageActiveEffect.bind(this));
|
html.find(".effect-control").click(ev => onManageActiveEffect(ev, this.entity));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Owner Only Listeners
|
// Owner Only Listeners
|
||||||
|
@ -565,7 +555,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async _onDropItemCreate(itemData) {
|
async _onDropItemCreate(itemData) {
|
||||||
|
|
||||||
|
@ -576,9 +566,7 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the owned item as normal
|
// Create the owned item as normal
|
||||||
// TODO remove conditional logic in 0.7.x
|
return super._onDropItemCreate(itemData);
|
||||||
if (isNewerVersion(game.data.version, "0.6.9")) return super._onDropItemCreate(itemData);
|
|
||||||
else return this.actor.createEmbeddedEntity("OwnedItem", itemData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -731,28 +719,6 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage Active Effect instances through the Actor Sheet via effect control buttons.
|
|
||||||
* @param {MouseEvent} event The left-click event on the effect control
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_onManageActiveEffect(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const a = event.currentTarget;
|
|
||||||
const li = a.closest(".effect");
|
|
||||||
const effect = this.actor.effects.get(li.dataset.effectId);
|
|
||||||
switch ( a.dataset.action ) {
|
|
||||||
case "edit":
|
|
||||||
return effect.sheet.render(true);
|
|
||||||
case "delete":
|
|
||||||
return effect.delete();
|
|
||||||
case "toggle":
|
|
||||||
return effect.update({disabled: !effect.data.disabled});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle rolling an Ability check, either a test or a saving throw
|
* Handle rolling an Ability check, either a test or a saving throw
|
||||||
* @param {Event} event The originating click event
|
* @param {Event} event The originating click event
|
||||||
|
@ -825,6 +791,18 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle spawning the TraitSelector application which allows a checkbox of multiple trait options
|
||||||
|
* @param {Event} event The click event which originated the selection
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onMovementConfig(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
new MovementConfig(this.object).render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
_getHeaderButtons() {
|
_getHeaderButtons() {
|
||||||
let buttons = super._getHeaderButtons();
|
let buttons = super._getHeaderButtons();
|
||||||
|
@ -839,90 +817,4 @@ export default class ActorSheet5e extends ActorSheet {
|
||||||
});
|
});
|
||||||
return buttons;
|
return buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/* DEPRECATED */
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Remove once 0.7.x is release
|
|
||||||
* @deprecated since 0.7.0
|
|
||||||
*/
|
|
||||||
async _onDrop (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
// Get dropped data
|
|
||||||
let data;
|
|
||||||
try {
|
|
||||||
data = JSON.parse(event.dataTransfer.getData('text/plain'));
|
|
||||||
} catch (err) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ( !data ) return false;
|
|
||||||
|
|
||||||
// Handle the drop with a Hooked function
|
|
||||||
const allowed = Hooks.call("dropActorSheetData", this.actor, this, data);
|
|
||||||
if ( allowed === false ) return;
|
|
||||||
|
|
||||||
// Case 1 - Dropped Item
|
|
||||||
if ( data.type === "Item" ) {
|
|
||||||
return this._onDropItem(event, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 2 - Dropped Actor
|
|
||||||
if ( data.type === "Actor" ) {
|
|
||||||
return this._onDropActor(event, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Remove once 0.7.x is release
|
|
||||||
* @deprecated since 0.7.0
|
|
||||||
*/
|
|
||||||
async _onDropItem(event, data) {
|
|
||||||
if ( !this.actor.owner ) return false;
|
|
||||||
let itemData = await this._getItemDropData(event, data);
|
|
||||||
|
|
||||||
// Handle item sorting within the same Actor
|
|
||||||
const actor = this.actor;
|
|
||||||
let sameActor = (data.actorId === actor._id) || (actor.isToken && (data.tokenId === actor.token.id));
|
|
||||||
if (sameActor) return this._onSortItem(event, itemData);
|
|
||||||
|
|
||||||
// Create a new item
|
|
||||||
this._onDropItemCreate(itemData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Remove once 0.7.x is release
|
|
||||||
* @deprecated since 0.7.0
|
|
||||||
*/
|
|
||||||
async _getItemDropData(event, data) {
|
|
||||||
let itemData = null;
|
|
||||||
|
|
||||||
// Case 1 - Import from a Compendium pack
|
|
||||||
if (data.pack) {
|
|
||||||
const pack = game.packs.get(data.pack);
|
|
||||||
if (pack.metadata.entity !== "Item") return;
|
|
||||||
itemData = await pack.getEntry(data.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 2 - Data explicitly provided
|
|
||||||
else if (data.data) {
|
|
||||||
itemData = data.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 3 - Import from World entity
|
|
||||||
else {
|
|
||||||
let item = game.items.get(data.id);
|
|
||||||
if (!item) return;
|
|
||||||
itemData = item.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a copy of the extracted data
|
|
||||||
return duplicate(itemData);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -68,7 +68,7 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
backpack: { label: "SW5E.ItemTypeContainerPl", items: [], dataset: {type: "backpack"} },
|
backpack: { label: "SW5E.ItemTypeContainerPl", items: [], dataset: {type: "backpack"} },
|
||||||
loot: { label: "SW5E.ItemTypeLootPl", items: [], dataset: {type: "loot"} }
|
loot: { label: "SW5E.ItemTypeLootPl", items: [], dataset: {type: "loot"} }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Partition items by category
|
// Partition items by category
|
||||||
let [items, powers, feats, classes, species, archetypes, classfeatures, backgrounds, fightingstyles, fightingmasteries, lightsaberforms] = data.items.reduce((arr, item) => {
|
let [items, powers, feats, classes, species, archetypes, classfeatures, backgrounds, fightingstyles, fightingmasteries, lightsaberforms] = data.items.reduce((arr, item) => {
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
for ( let i of items ) {
|
for ( let i of items ) {
|
||||||
i.data.quantity = i.data.quantity || 0;
|
i.data.quantity = i.data.quantity || 0;
|
||||||
i.data.weight = i.data.weight || 0;
|
i.data.weight = i.data.weight || 0;
|
||||||
i.totalWeight = Math.round(i.data.quantity * i.data.weight * 10) / 10;
|
i.totalWeight = (i.data.quantity * i.data.weight).toNearest(0.1);
|
||||||
inventory[i.type].items.push(i);
|
inventory[i.type].items.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,12 +123,12 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
const features = {
|
const features = {
|
||||||
classes: { label: "SW5E.ItemTypeClassPl", items: [], hasActions: false, dataset: {type: "class"}, isClass: true },
|
classes: { label: "SW5E.ItemTypeClassPl", items: [], hasActions: false, dataset: {type: "class"}, isClass: true },
|
||||||
classfeatures: { label: "SW5E.ItemTypeClassFeats", items: [], hasActions: false, dataset: {type: "classfeature"}, isClassfeature: true },
|
classfeatures: { label: "SW5E.ItemTypeClassFeats", items: [], hasActions: false, dataset: {type: "classfeature"}, isClassfeature: true },
|
||||||
archetype: { label: "SW5E.ItemTypeArchetype", items: [], hasActions: false, dataset: {type: "archetype"}, isArchetype: true },
|
archetype: { label: "SW5E.ItemTypeArchetype", items: [], hasActions: false, dataset: {type: "archetype"}, isArchetype: true },
|
||||||
species: { label: "SW5E.ItemTypeSpecies", items: [], hasActions: false, dataset: {type: "species"}, isSpecies: true },
|
species: { label: "SW5E.ItemTypeSpecies", items: [], hasActions: false, dataset: {type: "species"}, isSpecies: true },
|
||||||
background: { label: "SW5E.ItemTypeBackground", items: [], hasActions: false, dataset: {type: "background"}, isBackground: true },
|
background: { label: "SW5E.ItemTypeBackground", items: [], hasActions: false, dataset: {type: "background"}, isBackground: true },
|
||||||
fightingstyles: { label: "SW5E.ItemTypeFightingStylePl", items: [], hasActions: false, dataset: {type: "fightingstyle"}, isFightingstyle: true },
|
fightingstyles: { label: "SW5E.ItemTypeFightingStylePl", items: [], hasActions: false, dataset: {type: "fightingstyle"}, isFightingstyle: true },
|
||||||
fightingmasteries: { label: "SW5E.ItemTypeFightingMasteryPl", items: [], hasActions: false, dataset: {type: "fightingmastery"}, isFightingmastery: true },
|
fightingmasteries: { label: "SW5E.ItemTypeFightingMasteryPl", items: [], hasActions: false, dataset: {type: "fightingmastery"}, isFightingmastery: true },
|
||||||
lightsaberforms: { label: "SW5E.ItemTypeLightsaberFormPl", items: [], hasActions: false, dataset: {type: "lightsaberform"}, isLightsaberform: true },
|
lightsaberforms: { label: "SW5E.ItemTypeLightsaberFormPl", items: [], hasActions: false, dataset: {type: "lightsaberform"}, isLightsaberform: true },
|
||||||
active: { label: "SW5E.FeatureActive", items: [], hasActions: true, dataset: {type: "feat", "activation.type": "action"} },
|
active: { label: "SW5E.FeatureActive", items: [], hasActions: true, dataset: {type: "feat", "activation.type": "action"} },
|
||||||
passive: { label: "SW5E.FeaturePassive", items: [], hasActions: false, dataset: {type: "feat"} }
|
passive: { label: "SW5E.FeaturePassive", items: [], hasActions: false, dataset: {type: "feat"} }
|
||||||
};
|
};
|
||||||
|
@ -138,13 +138,13 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
}
|
}
|
||||||
classes.sort((a, b) => b.levels - a.levels);
|
classes.sort((a, b) => b.levels - a.levels);
|
||||||
features.classes.items = classes;
|
features.classes.items = classes;
|
||||||
features.classfeatures.items = classfeatures;
|
features.classfeatures.items = classfeatures;
|
||||||
features.archetype.items = archetypes;
|
features.archetype.items = archetypes;
|
||||||
features.species.items = species;
|
features.species.items = species;
|
||||||
features.background.items = backgrounds;
|
features.background.items = backgrounds;
|
||||||
features.fightingstyles.items = fightingstyles;
|
features.fightingstyles.items = fightingstyles;
|
||||||
features.fightingmasteries.items = fightingmasteries;
|
features.fightingmasteries.items = fightingmasteries;
|
||||||
features.lightsaberforms.items = lightsaberforms;
|
features.lightsaberforms.items = lightsaberforms;
|
||||||
|
|
||||||
// Assign and return
|
// Assign and return
|
||||||
data.inventory = Object.values(inventory);
|
data.inventory = Object.values(inventory);
|
||||||
|
@ -189,9 +189,6 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
if ( !this.options.editable ) return;
|
if ( !this.options.editable ) return;
|
||||||
|
|
||||||
// Inventory Functions
|
|
||||||
html.find(".currency-convert").click(this._onConvertCurrency.bind(this));
|
|
||||||
|
|
||||||
// Item State Toggling
|
// Item State Toggling
|
||||||
html.find('.item-toggle').click(this._onToggleItem.bind(this));
|
html.find('.item-toggle').click(this._onToggleItem.bind(this));
|
||||||
|
|
||||||
|
@ -199,8 +196,8 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
html.find('.short-rest').click(this._onShortRest.bind(this));
|
html.find('.short-rest').click(this._onShortRest.bind(this));
|
||||||
html.find('.long-rest').click(this._onLongRest.bind(this));
|
html.find('.long-rest').click(this._onLongRest.bind(this));
|
||||||
|
|
||||||
// Death saving throws
|
// Rollable sheet actions
|
||||||
html.find('.death-save').click(this._onDeathSave.bind(this));
|
html.find(".rollable[data-action]").click(this._onSheetAction.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -210,14 +207,19 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
* @param {MouseEvent} event The originating click event
|
* @param {MouseEvent} event The originating click event
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onDeathSave(event) {
|
_onSheetAction(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return this.actor.rollDeathSave({event: event});
|
const button = event.currentTarget;
|
||||||
|
switch( button.dataset.action ) {
|
||||||
|
case "rollDeathSave":
|
||||||
|
return this.actor.rollDeathSave({event: event});
|
||||||
|
case "rollInitiative":
|
||||||
|
return this.actor.rollInitiative({createCombatants: true});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle toggling the state of an Owned Item within the Actor
|
* Handle toggling the state of an Owned Item within the Actor
|
||||||
* @param {Event} event The triggering click event
|
* @param {Event} event The triggering click event
|
||||||
|
@ -259,53 +261,39 @@ export default class ActorSheet5eCharacter extends ActorSheet5e {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle mouse click events to convert currency to the highest possible denomination
|
|
||||||
* @param {MouseEvent} event The originating click event
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
async _onConvertCurrency(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
return Dialog.confirm({
|
|
||||||
title: `${game.i18n.localize("SW5E.CurrencyConvert")}`,
|
|
||||||
content: `<p>${game.i18n.localize("SW5E.CurrencyConvertHint")}</p>`,
|
|
||||||
yes: () => this.actor.convertCurrency()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async _onDropItemCreate(itemData) {
|
async _onDropItemCreate(itemData) {
|
||||||
|
let addLevel = false;
|
||||||
|
|
||||||
// Upgrade the number of class levels a character has and add features
|
// Upgrade the number of class levels a character has and add features
|
||||||
if ( itemData.type === "class" ) {
|
if ( itemData.type === "class" ) {
|
||||||
const cls = this.actor.itemTypes.class.find(c => c.name === itemData.name);
|
const cls = this.actor.itemTypes.class.find(c => c.name === itemData.name);
|
||||||
const classWasAlreadyPresent = !!cls;
|
let priorLevel = cls?.data.data.levels ?? 0;
|
||||||
|
const hasClass = !!cls;
|
||||||
|
|
||||||
// Add new features for class level
|
// Increment levels instead of creating a new item
|
||||||
if ( !classWasAlreadyPresent ) {
|
if ( hasClass ) {
|
||||||
Actor5e.getClassFeatures(itemData).then(features => {
|
const next = Math.min(priorLevel + 1, 20 + priorLevel - this.actor.data.data.details.level);
|
||||||
this.actor.createEmbeddedEntity("OwnedItem", features);
|
if ( next > priorLevel ) {
|
||||||
});
|
itemData.levels = next;
|
||||||
|
await cls.update({"data.levels": next});
|
||||||
|
addLevel = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the actor already has the class, increment the level instead of creating a new item
|
// Add class features
|
||||||
// then add new features as long as level increases
|
if ( !hasClass || addLevel ) {
|
||||||
if ( classWasAlreadyPresent ) {
|
const features = await Actor5e.getClassFeatures({
|
||||||
const lvl = cls.data.data.levels;
|
className: itemData.name,
|
||||||
const newLvl = Math.min(lvl + 1, 20 + lvl - this.actor.data.data.details.level);
|
subclassName: itemData.data.subclass,
|
||||||
if ( !(lvl === newLvl) ) {
|
level: itemData.levels,
|
||||||
cls.update({"data.levels": newLvl});
|
priorLevel: priorLevel
|
||||||
itemData.data.levels = newLvl;
|
});
|
||||||
Actor5e.getClassFeatures(itemData).then(features => {
|
await this.actor.createEmbeddedEntity("OwnedItem", features);
|
||||||
this.actor.createEmbeddedEntity("OwnedItem", features);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super._onDropItemCreate(itemData);
|
// Default drop handling if levels were not added
|
||||||
|
if ( !addLevel ) super._onDropItemCreate(itemData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ export default class ActorSheet5eNPC extends ActorSheet5e {
|
||||||
/** @override */
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
html.find(".health .rollable").click(this._onRollHealthFormula.bind(this));
|
html.find(".health .rollable").click(this._onRollHPFormula.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -116,7 +116,7 @@ export default class ActorSheet5eNPC extends ActorSheet5e {
|
||||||
* @param {Event} event The original click event
|
* @param {Event} event The original click event
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onRollHealthFormula(event) {
|
_onRollHPFormula(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const formula = this.actor.data.data.attributes.hp.formula;
|
const formula = this.actor.data.data.attributes.hp.formula;
|
||||||
if ( !formula ) return;
|
if ( !formula ) return;
|
||||||
|
|
|
@ -49,12 +49,9 @@ export default class ActorSheet5eVehicle extends ActorSheet5e {
|
||||||
totalWeight /= CONFIG.SW5E.encumbrance.vehicleWeightMultiplier;
|
totalWeight /= CONFIG.SW5E.encumbrance.vehicleWeightMultiplier;
|
||||||
|
|
||||||
// Compute overall encumbrance
|
// Compute overall encumbrance
|
||||||
const enc = {
|
const max = actorData.data.attributes.capacity.cargo;
|
||||||
max: actorData.data.attributes.capacity.cargo,
|
const pct = Math.clamped((totalWeight * 100) / max, 0, 100);
|
||||||
value: Math.round(totalWeight * 10) / 10
|
return {value: totalWeight.toNearest(0.1), max, pct};
|
||||||
};
|
|
||||||
enc.pct = Math.min(enc.value * 100 / enc.max, 99);
|
|
||||||
return enc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -89,6 +86,13 @@ export default class ActorSheet5eVehicle extends ActorSheet5e {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_getMovementSpeed(actorData) {
|
||||||
|
return {primary: "", special: ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Organize Owned Items for rendering the Vehicle sheet.
|
* Organize Owned Items for rendering the Vehicle sheet.
|
||||||
* @private
|
* @private
|
||||||
|
|
|
@ -70,7 +70,7 @@ export default class AbilityUseDialog extends Dialog {
|
||||||
dlg.render(true);
|
dlg.render(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* An application class which provides advanced configuration for special character flags which modify an Actor
|
* An application class which provides advanced configuration for special character flags which modify an Actor
|
||||||
* @extends {BaseEntitySheet}
|
* @implements {BaseEntitySheet}
|
||||||
*/
|
*/
|
||||||
export default class ActorSheetFlags extends BaseEntitySheet {
|
export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
const options = super.defaultOptions;
|
const options = super.defaultOptions;
|
||||||
return mergeObject(options, {
|
return mergeObject(options, {
|
||||||
id: "actor-flags",
|
id: "actor-flags",
|
||||||
|
@ -16,22 +16,16 @@ export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/** @override */
|
||||||
* Configure the title of the special traits selection window to include the Actor name
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
get title() {
|
get title() {
|
||||||
return `${game.i18n.localize('SW5E.FlagsTitle')}: ${this.object.name}`;
|
return `${game.i18n.localize('SW5E.FlagsTitle')}: ${this.object.name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/** @override */
|
||||||
* Prepare data used to render the special Actor traits selection UI
|
|
||||||
* @return {Object}
|
|
||||||
*/
|
|
||||||
getData() {
|
getData() {
|
||||||
const data = super.getData();
|
const data = {};
|
||||||
data.actor = this.object;
|
data.actor = this.object;
|
||||||
data.flags = this._getFlags();
|
data.flags = this._getFlags();
|
||||||
data.bonuses = this._getBonuses();
|
data.bonuses = this._getBonuses();
|
||||||
|
@ -43,17 +37,18 @@ export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
/**
|
/**
|
||||||
* Prepare an object of flags data which groups flags by section
|
* Prepare an object of flags data which groups flags by section
|
||||||
* Add some additional data for rendering
|
* Add some additional data for rendering
|
||||||
* @return {Object}
|
* @return {object}
|
||||||
*/
|
*/
|
||||||
_getFlags() {
|
_getFlags() {
|
||||||
const flags = {};
|
const flags = {};
|
||||||
|
const baseData = this.entity._data;
|
||||||
for ( let [k, v] of Object.entries(CONFIG.SW5E.characterFlags) ) {
|
for ( let [k, v] of Object.entries(CONFIG.SW5E.characterFlags) ) {
|
||||||
if ( !flags.hasOwnProperty(v.section) ) flags[v.section] = {};
|
if ( !flags.hasOwnProperty(v.section) ) flags[v.section] = {};
|
||||||
let flag = duplicate(v);
|
let flag = duplicate(v);
|
||||||
flag.type = v.type.name;
|
flag.type = v.type.name;
|
||||||
flag.isCheckbox = v.type === Boolean;
|
flag.isCheckbox = v.type === Boolean;
|
||||||
flag.isSelect = v.hasOwnProperty('choices');
|
flag.isSelect = v.hasOwnProperty('choices');
|
||||||
flag.value = this.entity.getFlag("sw5e", k);
|
flag.value = getProperty(baseData.flags, `sw5e.${k}`);
|
||||||
flags[v.section][`flags.sw5e.${k}`] = flag;
|
flags[v.section][`flags.sw5e.${k}`] = flag;
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
|
@ -63,7 +58,7 @@ export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the bonuses fields and their localization strings
|
* Get the bonuses fields and their localization strings
|
||||||
* @return {Array}
|
* @return {Array<object>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_getBonuses() {
|
_getBonuses() {
|
||||||
|
@ -82,17 +77,14 @@ export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
{name: "data.bonuses.power.dc", label: "SW5E.BonusPowerDC"}
|
{name: "data.bonuses.power.dc", label: "SW5E.BonusPowerDC"}
|
||||||
];
|
];
|
||||||
for ( let b of bonuses ) {
|
for ( let b of bonuses ) {
|
||||||
b.value = getProperty(this.object.data, b.name) || "";
|
b.value = getProperty(this.object._data, b.name) || "";
|
||||||
}
|
}
|
||||||
return bonuses;
|
return bonuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/** @override */
|
||||||
* Update the Actor using the configured flags
|
|
||||||
* Remove/unset any flags which are no longer configured
|
|
||||||
*/
|
|
||||||
async _updateObject(event, formData) {
|
async _updateObject(event, formData) {
|
||||||
const actor = this.object;
|
const actor = this.object;
|
||||||
let updateData = expandObject(formData);
|
let updateData = expandObject(formData);
|
||||||
|
@ -100,10 +92,12 @@ export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
// Unset any flags which are "false"
|
// Unset any flags which are "false"
|
||||||
let unset = false;
|
let unset = false;
|
||||||
const flags = updateData.flags.sw5e;
|
const flags = updateData.flags.sw5e;
|
||||||
|
//clone flags to dnd5e for module compatability
|
||||||
|
updateData.flags.dnd5e = updateData.flags.sw5e
|
||||||
for ( let [k, v] of Object.entries(flags) ) {
|
for ( let [k, v] of Object.entries(flags) ) {
|
||||||
if ( [undefined, null, "", false, 0].includes(v) ) {
|
if ( [undefined, null, "", false, 0].includes(v) ) {
|
||||||
delete flags[k];
|
delete flags[k];
|
||||||
if ( hasProperty(actor.data.flags, `sw5e.${k}`) ) {
|
if ( hasProperty(actor._data.flags, `sw5e.${k}`) ) {
|
||||||
unset = true;
|
unset = true;
|
||||||
flags[`-=${k}`] = null;
|
flags[`-=${k}`] = null;
|
||||||
}
|
}
|
||||||
|
@ -118,10 +112,6 @@ export default class ActorSheetFlags extends BaseEntitySheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diff the data against any applied overrides and apply
|
// Diff the data against any applied overrides and apply
|
||||||
// TODO: Remove this logical gate once 0.7.x is release channel
|
|
||||||
if ( !isNewerVersion("0.7.1", game.data.version) ){
|
|
||||||
updateData = diffObject(this.object.data, updateData);
|
|
||||||
}
|
|
||||||
await actor.update(updateData, {diff: false});
|
await actor.update(updateData, {diff: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
/**
|
|
||||||
* A specialized Dialog subclass for casting a cast item at a certain level
|
|
||||||
* @type {Dialog}
|
|
||||||
*/
|
|
||||||
export class CastDialog extends Dialog {
|
|
||||||
constructor(actor, item, dialogData={}, options={}) {
|
|
||||||
super(dialogData, options);
|
|
||||||
this.options.classes = ["sw5e", "dialog"];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a reference to the Actor entity which is casting the cast
|
|
||||||
* @type {Actor5e}
|
|
||||||
*/
|
|
||||||
this.actor = actor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a reference to the Item entity which is the cast being cast
|
|
||||||
* @type {Item5e}
|
|
||||||
*/
|
|
||||||
this.item = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/* Rendering */
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A constructor function which displays the Cast Cast Dialog app for a given Actor and Item.
|
|
||||||
* Returns a Promise which resolves to the dialog FormData once the workflow has been completed.
|
|
||||||
* @param {Actor5e} actor
|
|
||||||
* @param {Item5e} item
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
static async create(actor, item) {
|
|
||||||
const ad = actor.data.data;
|
|
||||||
const id = item.data.data;
|
|
||||||
|
|
||||||
// Determine whether the cast may be upcast
|
|
||||||
const lvl = id.level;
|
|
||||||
const canUpcast = (lvl > 0) && CONFIG.SW5E.castUpcastModes.includes(id.preparation.mode);
|
|
||||||
|
|
||||||
// Determine the levels which are feasible
|
|
||||||
let lmax = 0;
|
|
||||||
const castLevels = Array.fromRange(10).reduce((arr, i) => {
|
|
||||||
if ( i < lvl ) return arr;
|
|
||||||
const l = ad.casts["cast"+i] || {max: 0, override: null};
|
|
||||||
let max = parseInt(l.override || l.max || 0);
|
|
||||||
let slots = Math.clamped(parseInt(l.value || 0), 0, max);
|
|
||||||
if ( max > 0 ) lmax = i;
|
|
||||||
arr.push({
|
|
||||||
level: i,
|
|
||||||
label: i > 0 ? `${CONFIG.SW5E.castLevels[i]} (${slots} Slots)` : CONFIG.SW5E.castLevels[i],
|
|
||||||
canCast: canUpcast && (max > 0),
|
|
||||||
hasSlots: slots > 0
|
|
||||||
});
|
|
||||||
return arr;
|
|
||||||
}, []).filter(sl => sl.level <= lmax);
|
|
||||||
|
|
||||||
const pact = ad.casts.pact;
|
|
||||||
if (pact.level >= lvl) {
|
|
||||||
// If this character has pact slots, present them as an option for
|
|
||||||
// casting the cast.
|
|
||||||
castLevels.push({
|
|
||||||
level: 'pact',
|
|
||||||
label: game.i18n.localize('SW5E.CastLevelPact')
|
|
||||||
+ ` (${game.i18n.localize('SW5E.Level')} ${pact.level}) `
|
|
||||||
+ `(${pact.value} ${game.i18n.localize('SW5E.Slots')})`,
|
|
||||||
canCast: canUpcast,
|
|
||||||
hasSlots: pact.value > 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const canCast = castLevels.some(l => l.hasSlots);
|
|
||||||
|
|
||||||
// Render the Cast casting template
|
|
||||||
const html = await renderTemplate("systems/sw5e/templates/apps/cast-cast.html", {
|
|
||||||
item: item.data,
|
|
||||||
canCast: canCast,
|
|
||||||
canUpcast: canUpcast,
|
|
||||||
castLevels,
|
|
||||||
hasPlaceableTemplate: game.user.can("TEMPLATE_CREATE") && item.hasAreaTarget
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create the Dialog and return as a Promise
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const dlg = new this(actor, item, {
|
|
||||||
title: `${item.name}: Cast Configuration`,
|
|
||||||
content: html,
|
|
||||||
buttons: {
|
|
||||||
cast: {
|
|
||||||
icon: '<i class="fas fa-magic"></i>',
|
|
||||||
label: "Cast",
|
|
||||||
callback: html => resolve(new FormData(html[0].querySelector("#cast-config-form")))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
default: "cast",
|
|
||||||
close: reject
|
|
||||||
});
|
|
||||||
dlg.render(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
32
module/apps/movement-config.js
Normal file
32
module/apps/movement-config.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* A simple form to set actor movement speeds
|
||||||
|
* @implements {BaseEntitySheet}
|
||||||
|
*/
|
||||||
|
export default class MovementConfig extends BaseEntitySheet {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static get defaultOptions() {
|
||||||
|
return mergeObject(super.defaultOptions, {
|
||||||
|
title: "SW5E.MovementConfig",
|
||||||
|
classes: ["sw5e"],
|
||||||
|
template: "systems/sw5e/templates/apps/movement-config.html",
|
||||||
|
width: 240,
|
||||||
|
height: "auto"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
getData(options) {
|
||||||
|
const data = {
|
||||||
|
movement: duplicate(this.entity._data.data.attributes.movement),
|
||||||
|
units: CONFIG.SW5E.movementUnits
|
||||||
|
}
|
||||||
|
for ( let [k, v] of Object.entries(data.movement) ) {
|
||||||
|
if ( ["units", "hover"].includes(k) ) continue;
|
||||||
|
data.movement[k] = Number.isNumeric(v) ? v.toNearest(0.1) : 0;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ export default class ShortRestDialog extends Dialog {
|
||||||
/** @override */
|
/** @override */
|
||||||
getData() {
|
getData() {
|
||||||
const data = super.getData();
|
const data = super.getData();
|
||||||
|
|
||||||
// Determine Hit Dice
|
// Determine Hit Dice
|
||||||
data.availableHD = this.actor.data.items.reduce((hd, item) => {
|
data.availableHD = this.actor.data.items.reduce((hd, item) => {
|
||||||
if ( item.type === "class" ) {
|
if ( item.type === "class" ) {
|
||||||
|
@ -49,7 +49,7 @@ export default class ShortRestDialog extends Dialog {
|
||||||
}, {});
|
}, {});
|
||||||
data.canRoll = this.actor.data.data.attributes.hd > 0;
|
data.canRoll = this.actor.data.data.attributes.hd > 0;
|
||||||
data.denomination = this._denom;
|
data.denomination = this._denom;
|
||||||
|
|
||||||
// Determine rest type
|
// Determine rest type
|
||||||
const variant = game.settings.get("sw5e", "restVariant");
|
const variant = game.settings.get("sw5e", "restVariant");
|
||||||
data.promptNewDay = variant !== "epic"; // It's never a new day when only resting 1 minute
|
data.promptNewDay = variant !== "epic"; // It's never a new day when only resting 1 minute
|
||||||
|
|
|
@ -11,14 +11,16 @@ export const highlightCriticalSuccessFailure = function(message, html, data) {
|
||||||
const d = roll.dice[0];
|
const d = roll.dice[0];
|
||||||
|
|
||||||
// Ensure it is an un-modified d20 roll
|
// Ensure it is an un-modified d20 roll
|
||||||
const isD20 = (d.faces === 20) && ( d.results.length === 1 );
|
const isD20 = (d.faces === 20) && ( d.values.length === 1 );
|
||||||
if ( !isD20 ) return;
|
if ( !isD20 ) return;
|
||||||
const isModifiedRoll = ("success" in d.results[0]) || d.options.marginSuccess || d.options.marginFailure;
|
const isModifiedRoll = ("success" in d.results[0]) || d.options.marginSuccess || d.options.marginFailure;
|
||||||
if ( isModifiedRoll ) return;
|
if ( isModifiedRoll ) return;
|
||||||
|
|
||||||
// Highlight successes and failures
|
// Highlight successes and failures
|
||||||
if ( d.options.critical && (d.total >= d.options.critical) ) html.find(".dice-total").addClass("critical");
|
const critical = d.options.critical || 20;
|
||||||
else if ( d.options.fumble && (d.total <= d.options.fumble) ) html.find(".dice-total").addClass("fumble");
|
const fumble = d.options.fumble || 1;
|
||||||
|
if ( d.total >= critical ) html.find(".dice-total").addClass("critical");
|
||||||
|
else if ( d.total <= fumble ) html.find(".dice-total").addClass("fumble");
|
||||||
else if ( d.options.target ) {
|
else if ( d.options.target ) {
|
||||||
if ( roll.total >= d.options.target ) html.find(".dice-total").addClass("success");
|
if ( roll.total >= d.options.target ) html.find(".dice-total").addClass("success");
|
||||||
else html.find(".dice-total").addClass("failure");
|
else html.find(".dice-total").addClass("failure");
|
||||||
|
@ -33,7 +35,8 @@ export const highlightCriticalSuccessFailure = function(message, html, data) {
|
||||||
export const displayChatActionButtons = function(message, html, data) {
|
export const displayChatActionButtons = function(message, html, data) {
|
||||||
const chatCard = html.find(".sw5e.chat-card");
|
const chatCard = html.find(".sw5e.chat-card");
|
||||||
if ( chatCard.length > 0 ) {
|
if ( chatCard.length > 0 ) {
|
||||||
html.find(".flavor-text").remove();
|
const flavor = html.find(".flavor-text");
|
||||||
|
if ( flavor.text() === html.find(".item-name").text() ) flavor.remove();
|
||||||
|
|
||||||
// If the user is the message author or the actor owner, proceed
|
// If the user is the message author or the actor owner, proceed
|
||||||
let actor = game.actors.get(data.message.speaker.actor);
|
let actor = game.actors.get(data.message.speaker.actor);
|
||||||
|
|
|
@ -27,41 +27,14 @@ export const _getInitiativeFormula = function(combatant) {
|
||||||
return parts.filter(p => p !== null).join(" + ");
|
return parts.filter(p => p !== null).join(" + ");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: A temporary shim until 0.7.x becomes stable
|
* When the Combat encounter updates - re-render open Actor sheets for combatants in the encounter.
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
TokenConfig.getTrackedAttributes = function(data, _path=[]) {
|
Hooks.on("updateCombat", (combat, data, options, userId) => {
|
||||||
|
const updateTurn = ("turn" in data) || ("round" in data);
|
||||||
// Track the path and record found attributes
|
if ( !updateTurn ) return;
|
||||||
const attributes = {
|
for ( let t of combat.turns ) {
|
||||||
"bar": [],
|
const a = t.actor;
|
||||||
"value": []
|
if ( t.actor ) t.actor.sheet.render(false);
|
||||||
};
|
|
||||||
|
|
||||||
// Recursively explore the object
|
|
||||||
for ( let [k, v] of Object.entries(data) ) {
|
|
||||||
let p = _path.concat([k]);
|
|
||||||
|
|
||||||
// Check objects for both a "value" and a "max"
|
|
||||||
if ( v instanceof Object ) {
|
|
||||||
const isBar = ("value" in v) && ("max" in v);
|
|
||||||
if ( isBar ) attributes.bar.push(p);
|
|
||||||
else {
|
|
||||||
const inner = this.getTrackedAttributes(data[k], p);
|
|
||||||
attributes.bar.push(...inner.bar);
|
|
||||||
attributes.value.push(...inner.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise identify values which are numeric or null
|
|
||||||
else if ( Number.isNumeric(v) || (v === null) ) {
|
|
||||||
attributes.value.push(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return attributes;
|
});
|
||||||
};
|
|
||||||
|
|
|
@ -325,17 +325,31 @@ SW5E.armorPropertiesTypes = {
|
||||||
"Versatile": "SW5E.ArmorProperVersatile"
|
"Versatile": "SW5E.ArmorProperVersatile"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/**
|
||||||
|
* The valid units of measure for movement distances in the game system.
|
||||||
|
* By default this uses the imperial units of feet and miles.
|
||||||
|
* @type {Object<string,string>}
|
||||||
|
*/
|
||||||
|
SW5E.movementUnits = {
|
||||||
|
"ft": "SW5E.DistFt",
|
||||||
|
"mi": "SW5E.DistMi"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The valid units of measure for the range of an action or effect.
|
||||||
|
* This object automatically includes the movement units from SW5E.movementUnits
|
||||||
|
* @type {Object<string,string>}
|
||||||
|
*/
|
||||||
SW5E.distanceUnits = {
|
SW5E.distanceUnits = {
|
||||||
"none": "SW5E.None",
|
"none": "SW5E.None",
|
||||||
"self": "SW5E.DistSelf",
|
"self": "SW5E.DistSelf",
|
||||||
"touch": "SW5E.DistTouch",
|
"touch": "SW5E.DistTouch",
|
||||||
"ft": "SW5E.DistFt",
|
|
||||||
"mi": "SW5E.DistMi",
|
|
||||||
"spec": "SW5E.Special",
|
"spec": "SW5E.Special",
|
||||||
"any": "SW5E.DistAny"
|
"any": "SW5E.DistAny"
|
||||||
};
|
};
|
||||||
|
for ( let [k, v] of Object.entries(SW5E.movementUnits) ) {
|
||||||
|
SW5E.distanceUnits[k] = v;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
@ -413,7 +427,7 @@ SW5E.healingTypes = {
|
||||||
* Enumerate the denominations of hit dice which can apply to classes in the SW5E system
|
* Enumerate the denominations of hit dice which can apply to classes in the SW5E system
|
||||||
* @type {Array.<string>}
|
* @type {Array.<string>}
|
||||||
*/
|
*/
|
||||||
SW5E.hitDieTypes = ["d4", "d6", "d8", "d10", "d12"];
|
SW5E.hitDieTypes = ["d4", "d6", "d8", "d10", "d12", "d20"];
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -461,15 +475,14 @@ SW5E.skills = {
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
SW5E.powerPreparationModes = {
|
SW5E.powerPreparationModes = {
|
||||||
|
"prepared": "SW5E.PowerPrepPrepared",
|
||||||
"always": "SW5E.PowerPrepAlways",
|
"always": "SW5E.PowerPrepAlways",
|
||||||
"atwill": "SW5E.PowerPrepAtWill",
|
"atwill": "SW5E.PowerPrepAtWill",
|
||||||
"innate": "SW5E.PowerPrepInnate",
|
"innate": "SW5E.PowerPrepInnate"
|
||||||
"prepared": "SW5E.PowerPrepPrepared"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SW5E.powerUpcastModes = ["always", "pact", "prepared"];
|
SW5E.powerUpcastModes = ["always", "pact", "prepared"];
|
||||||
|
|
||||||
|
|
||||||
SW5E.powerProgression = {
|
SW5E.powerProgression = {
|
||||||
"none": "SW5E.PowerNone",
|
"none": "SW5E.PowerNone",
|
||||||
"full": "SW5E.PowerProgFull",
|
"full": "SW5E.PowerProgFull",
|
||||||
|
@ -901,15 +914,27 @@ SW5E.characterFlags = {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
},
|
},
|
||||||
"weaponCriticalThreshold": {
|
"weaponCriticalThreshold": {
|
||||||
name: "SW5E.FlagsCritThreshold",
|
name: "SW5E.FlagsWeaponCritThreshold",
|
||||||
hint: "SW5E.FlagsCritThresholdHint",
|
hint: "SW5E.FlagsWeaponCritThresholdHint",
|
||||||
section: "Feats",
|
section: "Feats",
|
||||||
type: Number,
|
type: Number,
|
||||||
placeholder: 20
|
placeholder: 20
|
||||||
|
},
|
||||||
|
"powerCriticalThreshold": {
|
||||||
|
name: "SW5E.FlagsPowerCritThreshold",
|
||||||
|
hint: "SW5E.FlagsPowerCritThresholdHint",
|
||||||
|
section: "Feats",
|
||||||
|
type: Number,
|
||||||
|
placeholder: 20
|
||||||
|
},
|
||||||
|
"meleeCriticalDamageDice": {
|
||||||
|
name: "SW5E.FlagsMeleeCriticalDice",
|
||||||
|
hint: "SW5E.FlagsMeleeCriticalDiceHint",
|
||||||
|
section: "Feats",
|
||||||
|
type: Number,
|
||||||
|
placeholder: 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Configure allowed status flags
|
// Configure allowed status flags
|
||||||
SW5E.allowedActorFlags = [
|
SW5E.allowedActorFlags = ["isPolymorphed", "originalActor"].concat(Object.keys(SW5E.characterFlags));
|
||||||
"isPolymorphed", "originalActor"
|
|
||||||
].concat(Object.keys(SW5E.characterFlags));
|
|
||||||
|
|
273
module/dice.js
273
module/dice.js
|
@ -1,9 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* A standardized helper function for managing core 5e "d20 rolls"
|
* A standardized helper function for managing core 5e "d20 rolls"
|
||||||
*
|
*
|
||||||
* Holding SHIFT, ALT, or CTRL when the attack is rolled will "fast-forward".
|
* Holding SHIFT, ALT, or CTRL when the attack is rolled will "fast-forward".
|
||||||
* This chooses the default options of a normal attack with no bonus, Advantage, or Disadvantage respectively
|
* This chooses the default options of a normal attack with no bonus, Advantage, or Disadvantage respectively
|
||||||
*
|
*
|
||||||
* @param {Array} parts The dice roll component parts, excluding the initial d20
|
* @param {Array} parts The dice roll component parts, excluding the initial d20
|
||||||
* @param {Object} data Actor or item data against which to parse the roll
|
* @param {Object} data Actor or item data against which to parse the roll
|
||||||
* @param {Event|object} event The triggering event which initiated the roll
|
* @param {Event|object} event The triggering event which initiated the roll
|
||||||
|
@ -27,72 +27,72 @@
|
||||||
* @param {object} messageData Additional data which is applied to the created Chat Message, if any
|
* @param {object} messageData Additional data which is applied to the created Chat Message, if any
|
||||||
*
|
*
|
||||||
* @return {Promise} A Promise which resolves once the roll workflow has completed
|
* @return {Promise} A Promise which resolves once the roll workflow has completed
|
||||||
*/
|
*/
|
||||||
export async function d20Roll({parts=[], data={}, event={}, rollMode=null, template=null, title=null, speaker=null,
|
export async function d20Roll({parts=[], data={}, event={}, rollMode=null, template=null, title=null, speaker=null,
|
||||||
flavor=null, fastForward=null, dialogOptions,
|
flavor=null, fastForward=null, dialogOptions,
|
||||||
advantage=null, disadvantage=null, critical=20, fumble=1, targetValue=null,
|
advantage=null, disadvantage=null, critical=20, fumble=1, targetValue=null,
|
||||||
elvenAccuracy=false, halflingLucky=false, reliableTalent=false,
|
elvenAccuracy=false, halflingLucky=false, reliableTalent=false,
|
||||||
chatMessage=true, messageData={}}={}) {
|
chatMessage=true, messageData={}}={}) {
|
||||||
|
|
||||||
// Prepare Message Data
|
// Prepare Message Data
|
||||||
messageData.flavor = flavor || title;
|
messageData.flavor = flavor || title;
|
||||||
messageData.speaker = speaker || ChatMessage.getSpeaker();
|
messageData.speaker = speaker || ChatMessage.getSpeaker();
|
||||||
const messageOptions = {rollMode: rollMode || game.settings.get("core", "rollMode")};
|
const messageOptions = {rollMode: rollMode || game.settings.get("core", "rollMode")};
|
||||||
parts = parts.concat(["@bonus"]);
|
parts = parts.concat(["@bonus"]);
|
||||||
|
|
||||||
// Handle fast-forward events
|
// Handle fast-forward events
|
||||||
let adv = 0;
|
let adv = 0;
|
||||||
fastForward = fastForward ?? (event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey));
|
fastForward = fastForward ?? (event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey));
|
||||||
if (fastForward) {
|
if (fastForward) {
|
||||||
if ( advantage || event.altKey ) adv = 1;
|
if ( advantage || event.altKey ) adv = 1;
|
||||||
else if ( disadvantage || event.ctrlKey || event.metaKey ) adv = -1;
|
else if ( disadvantage || event.ctrlKey || event.metaKey ) adv = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the inner roll function
|
||||||
|
const _roll = (parts, adv, form) => {
|
||||||
|
|
||||||
|
// Determine the d20 roll and modifiers
|
||||||
|
let nd = 1;
|
||||||
|
let mods = halflingLucky ? "r=1" : "";
|
||||||
|
|
||||||
|
// Handle advantage
|
||||||
|
if (adv === 1) {
|
||||||
|
nd = elvenAccuracy ? 3 : 2;
|
||||||
|
messageData.flavor += ` (${game.i18n.localize("SW5E.Advantage")})`;
|
||||||
|
if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].advantage = true;
|
||||||
|
mods += "kh";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the inner roll function
|
|
||||||
const _roll = (parts, adv, form) => {
|
|
||||||
|
|
||||||
// Determine the d20 roll and modifiers
|
|
||||||
let nd = 1;
|
|
||||||
let mods = halflingLucky ? "r=1" : "";
|
|
||||||
|
|
||||||
// Handle advantage
|
// Handle disadvantage
|
||||||
if (adv === 1) {
|
else if (adv === -1) {
|
||||||
nd = elvenAccuracy ? 3 : 2;
|
nd = 2;
|
||||||
messageData.flavor += ` (${game.i18n.localize("SW5E.Advantage")})`;
|
messageData.flavor += ` (${game.i18n.localize("SW5E.Disadvantage")})`;
|
||||||
if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].advantage = true;
|
if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].disadvantage = true;
|
||||||
mods += "kh";
|
mods += "kl";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle disadvantage
|
|
||||||
else if (adv === -1) {
|
|
||||||
nd = 2;
|
|
||||||
messageData.flavor += ` (${game.i18n.localize("SW5E.Disadvantage")})`;
|
|
||||||
if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].disadvantage = true;
|
|
||||||
mods += "kl";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepend the d20 roll
|
// Prepend the d20 roll
|
||||||
let formula = `${nd}d20${mods}`;
|
let formula = `${nd}d20${mods}`;
|
||||||
if (reliableTalent) formula = `{${nd}d20${mods},10}kh`;
|
if (reliableTalent) formula = `{${nd}d20${mods},10}kh`;
|
||||||
parts.unshift(formula);
|
parts.unshift(formula);
|
||||||
|
|
||||||
// Optionally include a situational bonus
|
// Optionally include a situational bonus
|
||||||
if ( form ) {
|
if ( form ) {
|
||||||
data['bonus'] = form.bonus.value;
|
data['bonus'] = form.bonus.value;
|
||||||
messageOptions.rollMode = form.rollMode.value;
|
messageOptions.rollMode = form.rollMode.value;
|
||||||
}
|
}
|
||||||
if (!data["bonus"]) parts.pop();
|
if (!data["bonus"]) parts.pop();
|
||||||
|
|
||||||
// Optionally include an ability score selection (used for tool checks)
|
// Optionally include an ability score selection (used for tool checks)
|
||||||
const ability = form ? form.ability : null;
|
const ability = form ? form.ability : null;
|
||||||
if (ability && ability.value) {
|
if (ability && ability.value) {
|
||||||
data.ability = ability.value;
|
data.ability = ability.value;
|
||||||
const abl = data.abilities[data.ability];
|
const abl = data.abilities[data.ability];
|
||||||
if (abl) {
|
if (abl) {
|
||||||
data.mod = abl.mod;
|
data.mod = abl.mod;
|
||||||
messageData.flavor += ` (${CONFIG.SW5E.abilities[data.ability]})`;
|
messageData.flavor += ` (${CONFIG.SW5E.abilities[data.ability]})`;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute the roll
|
// Execute the roll
|
||||||
let roll = new Roll(parts.join(" + "), data);
|
let roll = new Roll(parts.join(" + "), data);
|
||||||
|
@ -139,73 +139,76 @@
|
||||||
*/
|
*/
|
||||||
async function _d20RollDialog({template, title, parts, data, rollMode, dialogOptions, roll}={}) {
|
async function _d20RollDialog({template, title, parts, data, rollMode, dialogOptions, roll}={}) {
|
||||||
|
|
||||||
// Render modal dialog
|
// Render modal dialog
|
||||||
template = template || "systems/sw5e/templates/chat/roll-dialog.html";
|
template = template || "systems/sw5e/templates/chat/roll-dialog.html";
|
||||||
let dialogData = {
|
let dialogData = {
|
||||||
formula: parts.join(" + "),
|
formula: parts.join(" + "),
|
||||||
data: data,
|
data: data,
|
||||||
rollMode: rollMode,
|
rollMode: rollMode,
|
||||||
rollModes: CONFIG.Dice.rollModes,
|
rollModes: CONFIG.Dice.rollModes,
|
||||||
config: CONFIG.SW5E
|
config: CONFIG.SW5E
|
||||||
};
|
};
|
||||||
const html = await renderTemplate(template, dialogData);
|
const html = await renderTemplate(template, dialogData);
|
||||||
|
|
||||||
// Create the Dialog window
|
// Create the Dialog window
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
new Dialog({
|
new Dialog({
|
||||||
title: title,
|
title: title,
|
||||||
content: html,
|
content: html,
|
||||||
buttons: {
|
buttons: {
|
||||||
advantage: {
|
advantage: {
|
||||||
label: game.i18n.localize("SW5E.Advantage"),
|
label: game.i18n.localize("SW5E.Advantage"),
|
||||||
callback: html => resolve(roll(parts, 1, html[0].querySelector("form")))
|
callback: html => resolve(roll(parts, 1, html[0].querySelector("form")))
|
||||||
},
|
|
||||||
normal: {
|
|
||||||
label: game.i18n.localize("SW5E.Normal"),
|
|
||||||
callback: html => resolve(roll(parts, 0, html[0].querySelector("form")))
|
|
||||||
},
|
|
||||||
disadvantage: {
|
|
||||||
label: game.i18n.localize("SW5E.Disadvantage"),
|
|
||||||
callback: html => resolve(roll(parts, -1, html[0].querySelector("form")))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
default: "normal",
|
normal: {
|
||||||
close: () => resolve(null)
|
label: game.i18n.localize("SW5E.Normal"),
|
||||||
}, dialogOptions).render(true);
|
callback: html => resolve(roll(parts, 0, html[0].querySelector("form")))
|
||||||
});
|
},
|
||||||
}
|
disadvantage: {
|
||||||
|
label: game.i18n.localize("SW5E.Disadvantage"),
|
||||||
|
callback: html => resolve(roll(parts, -1, html[0].querySelector("form")))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
default: "normal",
|
||||||
|
close: () => resolve(null)
|
||||||
|
}, dialogOptions).render(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A standardized helper function for managing core 5e "d20 rolls"
|
||||||
|
*
|
||||||
|
* Holding SHIFT, ALT, or CTRL when the attack is rolled will "fast-forward".
|
||||||
|
* This chooses the default options of a normal attack with no bonus, Critical, or no bonus respectively
|
||||||
|
*
|
||||||
|
* @param {Array} parts The dice roll component parts, excluding the initial d20
|
||||||
|
* @param {Actor} actor The Actor making the damage roll
|
||||||
|
* @param {Object} data Actor or item data against which to parse the roll
|
||||||
|
* @param {Event|object}[event The triggering event which initiated the roll
|
||||||
|
* @param {string} rollMode A specific roll mode to apply as the default for the resulting roll
|
||||||
|
* @param {String} template The HTML template used to render the roll dialog
|
||||||
|
* @param {String} title The dice roll UI window title
|
||||||
|
* @param {Object} speaker The ChatMessage speaker to pass when creating the chat
|
||||||
|
* @param {string} flavor Flavor text to use in the posted chat message
|
||||||
|
* @param {boolean} allowCritical Allow the opportunity for a critical hit to be rolled
|
||||||
|
* @param {Boolean} critical Flag this roll as a critical hit for the purposes of fast-forward rolls
|
||||||
|
* @param {number} criticalBonusDice A number of bonus damage dice that are added for critical hits
|
||||||
|
* @param {number} criticalMultiplier A critical hit multiplier which is applied to critical hits
|
||||||
|
* @param {Boolean} fastForward Allow fast-forward advantage selection
|
||||||
|
* @param {Function} onClose Callback for actions to take when the dialog form is closed
|
||||||
|
* @param {Object} dialogOptions Modal dialog options
|
||||||
|
* @param {boolean} chatMessage Automatically create a Chat Message for the result of this roll
|
||||||
|
* @param {object} messageData Additional data which is applied to the created Chat Message, if any
|
||||||
|
*
|
||||||
|
* @return {Promise} A Promise which resolves once the roll workflow has completed
|
||||||
|
*/
|
||||||
|
export async function damageRoll({parts, actor, data, event={}, rollMode=null, template, title, speaker, flavor,
|
||||||
|
allowCritical=true, critical=false, criticalBonusDice=0, criticalMultiplier=2, fastForward=null,
|
||||||
|
dialogOptions={}, chatMessage=true, messageData={}}={}) {
|
||||||
|
|
||||||
/**
|
|
||||||
* A standardized helper function for managing core 5e "d20 rolls"
|
|
||||||
*
|
|
||||||
* Holding SHIFT, ALT, or CTRL when the attack is rolled will "fast-forward".
|
|
||||||
* This chooses the default options of a normal attack with no bonus, Critical, or no bonus respectively
|
|
||||||
*
|
|
||||||
* @param {Array} parts The dice roll component parts, excluding the initial d20
|
|
||||||
* @param {Actor} actor The Actor making the damage roll
|
|
||||||
* @param {Object} data Actor or item data against which to parse the roll
|
|
||||||
* @param {Event|object}[event The triggering event which initiated the roll
|
|
||||||
* @param {string} rollMode A specific roll mode to apply as the default for the resulting roll
|
|
||||||
* @param {String} template The HTML template used to render the roll dialog
|
|
||||||
* @param {String} title The dice roll UI window title
|
|
||||||
* @param {Object} speaker The ChatMessage speaker to pass when creating the chat
|
|
||||||
* @param {string} flavor Flavor text to use in the posted chat message
|
|
||||||
* @param {boolean} allowCritical Allow the opportunity for a critical hit to be rolled
|
|
||||||
* @param {Boolean} critical Flag this roll as a critical hit for the purposes of fast-forward rolls
|
|
||||||
* @param {Boolean} fastForward Allow fast-forward advantage selection
|
|
||||||
* @param {Function} onClose Callback for actions to take when the dialog form is closed
|
|
||||||
* @param {Object} dialogOptions Modal dialog options
|
|
||||||
* @param {boolean} chatMessage Automatically create a Chat Message for the result of this roll
|
|
||||||
* @param {object} messageData Additional data which is applied to the created Chat Message, if any
|
|
||||||
*
|
|
||||||
* @return {Promise} A Promise which resolves once the roll workflow has completed
|
|
||||||
*/
|
|
||||||
export async function damageRoll({parts, actor, data, event={}, rollMode=null, template, title, speaker, flavor,
|
|
||||||
allowCritical=true, critical=false, fastForward=null, dialogOptions, chatMessage=true, messageData={}}={}) {
|
|
||||||
|
|
||||||
// Prepare Message Data
|
// Prepare Message Data
|
||||||
messageData.flavor = flavor || title;
|
messageData.flavor = flavor || title;
|
||||||
messageData.speaker = speaker || ChatMessage.getSpeaker();
|
messageData.speaker = speaker || ChatMessage.getSpeaker();
|
||||||
|
@ -213,8 +216,8 @@ async function _d20RollDialog({template, title, parts, data, rollMode, dialogOpt
|
||||||
parts = parts.concat(["@bonus"]);
|
parts = parts.concat(["@bonus"]);
|
||||||
fastForward = fastForward ?? (event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey));
|
fastForward = fastForward ?? (event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey));
|
||||||
|
|
||||||
// Define inner roll function
|
// Define inner roll function
|
||||||
const _roll = function(parts, crit, form) {
|
const _roll = function(parts, crit, form) {
|
||||||
|
|
||||||
// Optionally include a situational bonus
|
// Optionally include a situational bonus
|
||||||
if ( form ) {
|
if ( form ) {
|
||||||
|
@ -224,17 +227,17 @@ async function _d20RollDialog({template, title, parts, data, rollMode, dialogOpt
|
||||||
if (!data["bonus"]) parts.pop();
|
if (!data["bonus"]) parts.pop();
|
||||||
|
|
||||||
// Create the damage roll
|
// Create the damage roll
|
||||||
let roll = new Roll(parts.join("+"), data);
|
let roll = new Roll(parts.join("+"), data);
|
||||||
|
|
||||||
// Modify the damage formula for critical hits
|
// Modify the damage formula for critical hits
|
||||||
if ( crit === true ) {
|
if ( crit === true ) {
|
||||||
let add = (actor && actor.getFlag("sw5e", "savageAttacks")) ? 1 : 0;
|
roll.alter(criticalMultiplier, 0); // Multiply all dice
|
||||||
let mult = 2;
|
if ( roll.terms[0] instanceof Die ) { // Add bonus dice for only the main dice term
|
||||||
// TODO Backwards compatibility - REMOVE LATER
|
roll.terms[0].alter(1, criticalBonusDice);
|
||||||
if (isNewerVersion(game.data.version, "0.6.9")) roll.alter(mult, add);
|
roll._formula = roll.formula;
|
||||||
else roll.alter(add, mult);
|
}
|
||||||
messageData.flavor += ` (${game.i18n.localize("SW5E.Critical")})`;
|
messageData.flavor += ` (${game.i18n.localize("SW5E.Critical")})`;
|
||||||
if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].critical = true;
|
if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].critical = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the roll
|
// Execute the roll
|
||||||
|
|
63
module/effects.js
vendored
Normal file
63
module/effects.js
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* Manage Active Effect instances through the Actor Sheet via effect control buttons.
|
||||||
|
* @param {MouseEvent} event The left-click event on the effect control
|
||||||
|
* @param {Actor|Item} owner The owning entity which manages this effect
|
||||||
|
*/
|
||||||
|
export function onManageActiveEffect(event, owner) {
|
||||||
|
event.preventDefault();
|
||||||
|
const a = event.currentTarget;
|
||||||
|
const li = a.closest("li");
|
||||||
|
const effect = li.dataset.effectId ? owner.effects.get(li.dataset.effectId) : null;
|
||||||
|
switch ( a.dataset.action ) {
|
||||||
|
case "create":
|
||||||
|
return ActiveEffect.create({
|
||||||
|
label: "New Effect",
|
||||||
|
icon: "icons/svg/aura.svg",
|
||||||
|
origin: owner.uuid,
|
||||||
|
"duration.rounds": li.dataset.effectType === "temporary" ? 1 : undefined,
|
||||||
|
disabled: li.dataset.effectType === "inactive"
|
||||||
|
}, owner).create();
|
||||||
|
case "edit":
|
||||||
|
return effect.sheet.render(true);
|
||||||
|
case "delete":
|
||||||
|
return effect.delete();
|
||||||
|
case "toggle":
|
||||||
|
return effect.update({disabled: !effect.data.disabled});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the data structure for Active Effects which are currently applied to an Actor or Item.
|
||||||
|
* @param {ActiveEffect[]} effects The array of Active Effect instances to prepare sheet data for
|
||||||
|
* @return {object} Data for rendering
|
||||||
|
*/
|
||||||
|
export function prepareActiveEffectCategories(effects) {
|
||||||
|
|
||||||
|
// Define effect header categories
|
||||||
|
const categories = {
|
||||||
|
temporary: {
|
||||||
|
type: "temporary",
|
||||||
|
label: "Temporary Effects",
|
||||||
|
effects: []
|
||||||
|
},
|
||||||
|
passive: {
|
||||||
|
type: "passive",
|
||||||
|
label: "Passive Effects",
|
||||||
|
effects: []
|
||||||
|
},
|
||||||
|
inactive: {
|
||||||
|
type: "inactive",
|
||||||
|
label: "Inactive Effects",
|
||||||
|
effects: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iterate over active effects, classifying them into categories
|
||||||
|
for ( let e of effects ) {
|
||||||
|
e._getSourceName(); // Trigger a lookup for the source name
|
||||||
|
if ( e.data.disabled ) categories.inactive.effects.push(e);
|
||||||
|
else if ( e.isTemporary ) categories.temporary.effects.push(e);
|
||||||
|
else categories.passive.effects.push(e);
|
||||||
|
}
|
||||||
|
return categories;
|
||||||
|
}
|
|
@ -161,6 +161,7 @@ export default class Item5e extends Item {
|
||||||
|
|
||||||
// Power Level, School, and Components
|
// Power Level, School, and Components
|
||||||
if ( itemData.type === "power" ) {
|
if ( itemData.type === "power" ) {
|
||||||
|
data.preparation.mode = data.preparation.mode || "prepared";
|
||||||
labels.level = C.powerLevels[data.level];
|
labels.level = C.powerLevels[data.level];
|
||||||
labels.school = C.powerSchools[data.school];
|
labels.school = C.powerSchools[data.school];
|
||||||
labels.components = Object.entries(data.components).reduce((arr, c) => {
|
labels.components = Object.entries(data.components).reduce((arr, c) => {
|
||||||
|
@ -180,33 +181,33 @@ export default class Item5e extends Item {
|
||||||
else labels.featType = game.i18n.localize("SW5E.Passive");
|
else labels.featType = game.i18n.localize("SW5E.Passive");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Species Items
|
// Species Items
|
||||||
else if ( itemData.type === "species" ) {
|
else if ( itemData.type === "species" ) {
|
||||||
// labels.species = C.species[data.species];
|
// labels.species = C.species[data.species];
|
||||||
}
|
}
|
||||||
// Archetype Items
|
// Archetype Items
|
||||||
else if ( itemData.type === "archetype" ) {
|
else if ( itemData.type === "archetype" ) {
|
||||||
// labels.archetype = C.archetype[data.archetype];
|
// labels.archetype = C.archetype[data.archetype];
|
||||||
}
|
}
|
||||||
// Background Items
|
// Background Items
|
||||||
else if ( itemData.type === "background" ) {
|
else if ( itemData.type === "background" ) {
|
||||||
|
// labels.background = C.background[data.background];
|
||||||
}
|
}
|
||||||
// Class Feature Items
|
// Class Feature Items
|
||||||
else if ( itemData.type === "classfeature" ) {
|
else if ( itemData.type === "classfeature" ) {
|
||||||
|
// labels.classFeature = C.classFeature[data.classFeature];
|
||||||
}
|
}
|
||||||
// Fighting Style Items
|
// Fighting Style Items
|
||||||
else if ( itemData.type === "fightingstyle" ) {
|
else if ( itemData.type === "fightingstyle" ) {
|
||||||
|
// labels.fightingstyle = C.fightingstyle[data.fightingstyle];
|
||||||
}
|
}
|
||||||
// Fighting Mastery Items
|
// Fighting Mastery Items
|
||||||
else if ( itemData.type === "fightingmastery" ) {
|
else if ( itemData.type === "fightingmastery" ) {
|
||||||
|
// labels.fightingmastery = C.fightingmastery[data.fightingmastery];
|
||||||
}
|
}
|
||||||
// Lightsaber Form Items
|
// Lightsaber Form Items
|
||||||
else if ( itemData.type === "lightsaberform" ) {
|
else if ( itemData.type === "lightsaberform" ) {
|
||||||
|
// labels.lightsaberform = C.lightsaberform[data.lightsaberform];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equipment Items
|
// Equipment Items
|
||||||
|
@ -322,7 +323,7 @@ export default class Item5e extends Item {
|
||||||
user: game.user._id,
|
user: game.user._id,
|
||||||
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
|
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
|
||||||
content: html,
|
content: html,
|
||||||
flavor: this.name,
|
flavor: this.data.data.chatFlavor || this.name,
|
||||||
speaker: {
|
speaker: {
|
||||||
actor: this.actor._id,
|
actor: this.actor._id,
|
||||||
token: this.actor.token,
|
token: this.actor.token,
|
||||||
|
@ -348,7 +349,7 @@ export default class Item5e extends Item {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For items which consume a resource, handle the consumption of that resource when the item is used.
|
* For items which consume a resource, handle the consumption of that resource when the item is used.
|
||||||
* There are four types of ability consumptions which are handled:
|
* There are four types of ability consumptions which are handled:
|
||||||
* 1. Ammunition (on attack rolls)
|
* 1. Ammunition (on attack rolls)
|
||||||
|
@ -367,7 +368,6 @@ export default class Item5e extends Item {
|
||||||
if ( !consume.type ) return true;
|
if ( !consume.type ) return true;
|
||||||
const actor = this.actor;
|
const actor = this.actor;
|
||||||
const typeLabel = CONFIG.SW5E.abilityConsumptionTypes[consume.type];
|
const typeLabel = CONFIG.SW5E.abilityConsumptionTypes[consume.type];
|
||||||
const amount = parseInt(consume.amount || 1);
|
|
||||||
|
|
||||||
// Only handle certain types for certain actions
|
// Only handle certain types for certain actions
|
||||||
if ( ((consume.type === "ammo") && !isAttack ) || ((consume.type !== "ammo") && !isCard) ) return true;
|
if ( ((consume.type === "ammo") && !isAttack ) || ((consume.type !== "ammo") && !isCard) ) return true;
|
||||||
|
@ -380,6 +380,7 @@ export default class Item5e extends Item {
|
||||||
|
|
||||||
// Identify the consumed resource and it's quantity
|
// Identify the consumed resource and it's quantity
|
||||||
let consumed = null;
|
let consumed = null;
|
||||||
|
let amount = parseInt(consume.amount || 1);
|
||||||
let quantity = 0;
|
let quantity = 0;
|
||||||
switch ( consume.type ) {
|
switch ( consume.type ) {
|
||||||
case "attribute":
|
case "attribute":
|
||||||
|
@ -393,7 +394,13 @@ export default class Item5e extends Item {
|
||||||
break;
|
break;
|
||||||
case "charges":
|
case "charges":
|
||||||
consumed = actor.items.get(consume.target);
|
consumed = actor.items.get(consume.target);
|
||||||
quantity = consumed ? consumed.data.data.uses.value : 0;
|
if ( !consumed ) break;
|
||||||
|
const uses = consumed.data.data.uses;
|
||||||
|
if ( uses.per && uses.max ) quantity = uses.value;
|
||||||
|
else if ( consumed.data.data.recharge?.value ) {
|
||||||
|
quantity = consumed.data.data.recharge.charged ? 1 : 0;
|
||||||
|
amount = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +425,11 @@ export default class Item5e extends Item {
|
||||||
await consumed.update({"data.quantity": remaining});
|
await consumed.update({"data.quantity": remaining});
|
||||||
break;
|
break;
|
||||||
case "charges":
|
case "charges":
|
||||||
await consumed.update({"data.uses.value": remaining});
|
const uses = consumed.data.data.uses || {};
|
||||||
|
const recharge = consumed.data.data.recharge || {};
|
||||||
|
if ( uses.per && uses.max ) await consumed.update({"data.uses.value": remaining});
|
||||||
|
else if ( recharge.value ) await consumed.update({"data.recharge.charged": false});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -436,7 +447,7 @@ export default class Item5e extends Item {
|
||||||
// Configure whether to consume a limited use or to place a template
|
// Configure whether to consume a limited use or to place a template
|
||||||
const charge = this.data.data.recharge;
|
const charge = this.data.data.recharge;
|
||||||
const uses = this.data.data.uses;
|
const uses = this.data.data.uses;
|
||||||
let usesCharges = !!uses.per && (uses.max > 0);
|
let usesCharges = !!uses.per && !!uses.max;
|
||||||
let placeTemplate = false;
|
let placeTemplate = false;
|
||||||
let consume = charge.value || usesCharges;
|
let consume = charge.value || usesCharges;
|
||||||
|
|
||||||
|
@ -637,40 +648,37 @@ export default class Item5e extends Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attack Bonus
|
// Attack Bonus
|
||||||
|
if ( itemData.attackBonus ) parts.push(itemData.attackBonus);
|
||||||
const actorBonus = actorData?.bonuses?.[itemData.actionType] || {};
|
const actorBonus = actorData?.bonuses?.[itemData.actionType] || {};
|
||||||
if ( itemData.attackBonus || actorBonus.attack ) {
|
if ( actorBonus.attack ) parts.push(actorBonus.attack);
|
||||||
parts.push("@atk");
|
|
||||||
rollData["atk"] = [itemData.attackBonus, actorBonus.attack].filterJoin(" + ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ammunition Bonus
|
// Ammunition Bonus
|
||||||
delete this._ammo;
|
delete this._ammo;
|
||||||
const consume = itemData.consume;
|
const consume = itemData.consume;
|
||||||
if ( consume?.type === "ammo" ) {
|
if ( consume?.type === "ammo" ) {
|
||||||
const ammo = this.actor.items.get(consume.target);
|
const ammo = this.actor.items.get(consume.target);
|
||||||
if(ammo?.data){
|
if(ammo?.data){
|
||||||
const q = ammo.data.data.quantity;
|
const q = ammo.data.data.quantity;
|
||||||
const consumeAmount = consume.amount ?? 0;
|
const consumeAmount = consume.amount ?? 0;
|
||||||
if ( q && (q - consumeAmount >= 0) ) {
|
if ( q && (q - consumeAmount >= 0) ) {
|
||||||
let ammoBonus = ammo.data.data.attackBonus;
|
this._ammo = ammo;
|
||||||
if ( ammoBonus ) {
|
let ammoBonus = ammo.data.data.attackBonus;
|
||||||
parts.push("@ammo");
|
if ( ammoBonus ) {
|
||||||
rollData["ammo"] = ammoBonus;
|
parts.push("@ammo");
|
||||||
title += ` [${ammo.name}]`;
|
rollData["ammo"] = ammoBonus;
|
||||||
this._ammo = ammo;
|
title += ` [${ammo.name}]`;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//}else{
|
|
||||||
// ui.notifications.error(game.i18n.format("SW5E.ConsumeWarningNoResource", {name: this.name, type: typeLabel}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compose roll options
|
// Compose roll options
|
||||||
const rollConfig = mergeObject({
|
const rollConfig = mergeObject({
|
||||||
parts: parts,
|
parts: parts,
|
||||||
actor: this.actor,
|
actor: this.actor,
|
||||||
data: rollData,
|
data: rollData,
|
||||||
title: title,
|
title: title,
|
||||||
|
flavor: title,
|
||||||
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
||||||
dialogOptions: {
|
dialogOptions: {
|
||||||
width: 400,
|
width: 400,
|
||||||
|
@ -681,9 +689,11 @@ export default class Item5e extends Item {
|
||||||
}, options);
|
}, options);
|
||||||
rollConfig.event = options.event;
|
rollConfig.event = options.event;
|
||||||
|
|
||||||
// Expanded weapon critical threshold
|
// Expanded critical hit thresholds
|
||||||
if (( this.data.type === "weapon" ) && flags.weaponCriticalThreshold) {
|
if (( this.data.type === "weapon" ) && flags.weaponCriticalThreshold) {
|
||||||
rollConfig.critical = parseInt(flags.weaponCriticalThreshold);
|
rollConfig.critical = parseInt(flags.weaponCriticalThreshold);
|
||||||
|
} else if (( this.data.type === "power" ) && flags.powerCriticalThreshold) {
|
||||||
|
rollConfig.critical = parseInt(flags.powerCriticalThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elven Accuracy
|
// Elven Accuracy
|
||||||
|
@ -710,28 +720,41 @@ export default class Item5e extends Item {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Place a damage roll using an item (weapon, feat, power, or equipment)
|
* Place a damage roll using an item (weapon, feat, power, or equipment)
|
||||||
* Rely upon the damageRoll logic for the core implementation
|
* Rely upon the damageRoll logic for the core implementation.
|
||||||
*
|
* @param {MouseEvent} [event] An event which triggered this roll, if any
|
||||||
* @return {Promise<Roll>} A Promise which resolves to the created Roll instance
|
* @param {number} [powerLevel] If the item is a power, override the level for damage scaling
|
||||||
|
* @param {boolean} [versatile] If the item is a weapon, roll damage using the versatile formula
|
||||||
|
* @param {object} [options] Additional options passed to the damageRoll function
|
||||||
|
* @return {Promise<Roll>} A Promise which resolves to the created Roll instance
|
||||||
*/
|
*/
|
||||||
rollDamage({event, powerLevel=null, versatile=false}={}) {
|
rollDamage({event, powerLevel=null, versatile=false, options={}}={}) {
|
||||||
|
if ( !this.hasDamage ) throw new Error("You may not make a Damage Roll with this Item.");
|
||||||
const itemData = this.data.data;
|
const itemData = this.data.data;
|
||||||
const actorData = this.actor.data.data;
|
const actorData = this.actor.data.data;
|
||||||
if ( !this.hasDamage ) {
|
|
||||||
throw new Error("You may not make a Damage Roll with this Item.");
|
|
||||||
}
|
|
||||||
const messageData = {"flags.sw5e.roll": {type: "damage", itemId: this.id }};
|
const messageData = {"flags.sw5e.roll": {type: "damage", itemId: this.id }};
|
||||||
|
|
||||||
// Get roll data
|
// Get roll data
|
||||||
|
const parts = itemData.damage.parts.map(d => d[0]);
|
||||||
const rollData = this.getRollData();
|
const rollData = this.getRollData();
|
||||||
if ( powerLevel ) rollData.item.level = powerLevel;
|
if ( powerLevel ) rollData.item.level = powerLevel;
|
||||||
|
|
||||||
// Get message labels
|
// Configure the damage roll
|
||||||
const title = `${this.name} - ${game.i18n.localize("SW5E.DamageRoll")}`;
|
const title = `${this.name} - ${game.i18n.localize("SW5E.DamageRoll")}`;
|
||||||
let flavor = this.labels.damageTypes.length ? `${title} (${this.labels.damageTypes})` : title;
|
const rollConfig = {
|
||||||
|
event: event,
|
||||||
// Define Roll parts
|
parts: parts,
|
||||||
const parts = itemData.damage.parts.map(d => d[0]);
|
actor: this.actor,
|
||||||
|
data: rollData,
|
||||||
|
title: title,
|
||||||
|
flavor: this.labels.damageTypes.length ? `${title} (${this.labels.damageTypes})` : title,
|
||||||
|
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
||||||
|
dialogOptions: {
|
||||||
|
width: 400,
|
||||||
|
top: event ? event.clientY - 80 : null,
|
||||||
|
left: window.innerWidth - 710
|
||||||
|
},
|
||||||
|
messageData: messageData
|
||||||
|
};
|
||||||
|
|
||||||
// Adjust damage from versatile usage
|
// Adjust damage from versatile usage
|
||||||
if ( versatile && itemData.damage.versatile ) {
|
if ( versatile && itemData.damage.versatile ) {
|
||||||
|
@ -751,37 +774,27 @@ export default class Item5e extends Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define Roll Data
|
// Add damage bonus formula
|
||||||
const actorBonus = getProperty(actorData, `bonuses.${itemData.actionType}`) || {};
|
const actorBonus = getProperty(actorData, `bonuses.${itemData.actionType}`) || {};
|
||||||
if ( actorBonus.damage && parseInt(actorBonus.damage) !== 0 ) {
|
if ( actorBonus.damage && (parseInt(actorBonus.damage) !== 0) ) {
|
||||||
parts.push("@dmg");
|
parts.push(actorBonus.damage);
|
||||||
rollData["dmg"] = actorBonus.damage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ammunition Damage
|
// Add ammunition damage
|
||||||
if ( this._ammo ) {
|
if ( this._ammo ) {
|
||||||
parts.push("@ammo");
|
parts.push("@ammo");
|
||||||
rollData["ammo"] = this._ammo.data.data.damage.parts.map(p => p[0]).join("+");
|
rollData["ammo"] = this._ammo.data.data.damage.parts.map(p => p[0]).join("+");
|
||||||
flavor += ` [${this._ammo.name}]`;
|
rollConfig.flavor += ` [${this._ammo.name}]`;
|
||||||
delete this._ammo;
|
delete this._ammo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scale melee critical hit damage
|
||||||
|
if ( itemData.actionType === "mwak" ) {
|
||||||
|
rollConfig.criticalBonusDice = this.actor.getFlag("sw5e", "meleeCriticalDamageDice") ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Call the roll helper utility
|
// Call the roll helper utility
|
||||||
return damageRoll({
|
return damageRoll(mergeObject(rollConfig, options));
|
||||||
event: event,
|
|
||||||
parts: parts,
|
|
||||||
actor: this.actor,
|
|
||||||
data: rollData,
|
|
||||||
title: title,
|
|
||||||
flavor: flavor,
|
|
||||||
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
|
||||||
dialogOptions: {
|
|
||||||
width: 400,
|
|
||||||
top: event ? event.clientY - 80 : null,
|
|
||||||
left: window.innerWidth - 710
|
|
||||||
},
|
|
||||||
messageData
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -793,22 +806,7 @@ export default class Item5e extends Item {
|
||||||
_scaleAtWillDamage(parts, scale, level, rollData) {
|
_scaleAtWillDamage(parts, scale, level, rollData) {
|
||||||
const add = Math.floor((level + 1) / 6);
|
const add = Math.floor((level + 1) / 6);
|
||||||
if ( add === 0 ) return;
|
if ( add === 0 ) return;
|
||||||
|
this._scaleDamage(parts, scale || parts.join(" + "), add, rollData);
|
||||||
// FUTURE SOLUTION - 0.7.0 AND LATER
|
|
||||||
if (isNewerVersion(game.data.version, "0.6.9")) {
|
|
||||||
this._scaleDamage(parts, scale || parts.join(" + "), add, rollData)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// LEGACY SOLUTION - 0.6.x AND OLDER
|
|
||||||
// TODO: Deprecate the legacy solution one FVTT 0.7.x is RELEASE
|
|
||||||
else {
|
|
||||||
if ( scale && (scale !== parts[0]) ) {
|
|
||||||
parts[0] = parts[0] + " + " + scale.replace(new RegExp(Roll.diceRgx, "g"), (match, nd, d) => `${add}d${d}`);
|
|
||||||
} else {
|
|
||||||
parts[0] = parts[0].replace(new RegExp(Roll.diceRgx, "g"), (match, nd, d) => `${parseInt(nd)+add}d${d}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -826,20 +824,7 @@ export default class Item5e extends Item {
|
||||||
_scalePowerDamage(parts, baseLevel, powerLevel, formula, rollData) {
|
_scalePowerDamage(parts, baseLevel, powerLevel, formula, rollData) {
|
||||||
const upcastLevels = Math.max(powerLevel - baseLevel, 0);
|
const upcastLevels = Math.max(powerLevel - baseLevel, 0);
|
||||||
if ( upcastLevels === 0 ) return parts;
|
if ( upcastLevels === 0 ) return parts;
|
||||||
|
this._scaleDamage(parts, formula, upcastLevels, rollData);
|
||||||
// FUTURE SOLUTION - 0.7.0 AND LATER
|
|
||||||
if (isNewerVersion(game.data.version, "0.6.9")) {
|
|
||||||
this._scaleDamage(parts, formula, upcastLevels, rollData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// LEGACY SOLUTION - 0.6.x AND OLDER
|
|
||||||
// TODO: Deprecate the legacy solution one FVTT 0.7.x is RELEASE
|
|
||||||
else {
|
|
||||||
const bonus = new Roll(formula);
|
|
||||||
bonus.alter(0, upcastLevels);
|
|
||||||
parts.push(bonus.formula);
|
|
||||||
}
|
|
||||||
return parts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -882,7 +867,7 @@ export default class Item5e extends Item {
|
||||||
/**
|
/**
|
||||||
* Place an attack roll using an item (weapon, feat, power, or equipment)
|
* Place an attack roll using an item (weapon, feat, power, or equipment)
|
||||||
* Rely upon the d20Roll logic for the core implementation
|
* Rely upon the d20Roll logic for the core implementation
|
||||||
*
|
*
|
||||||
* @return {Promise<Roll>} A Promise which resolves to the created Roll instance
|
* @return {Promise<Roll>} A Promise which resolves to the created Roll instance
|
||||||
*/
|
*/
|
||||||
async rollFormula(options={}) {
|
async rollFormula(options={}) {
|
||||||
|
@ -899,7 +884,7 @@ export default class Item5e extends Item {
|
||||||
const roll = new Roll(rollData.item.formula, rollData).roll();
|
const roll = new Roll(rollData.item.formula, rollData).roll();
|
||||||
roll.toMessage({
|
roll.toMessage({
|
||||||
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
||||||
flavor: this.data.data.chatFlavor || title,
|
flavor: title,
|
||||||
rollMode: game.settings.get("core", "rollMode"),
|
rollMode: game.settings.get("core", "rollMode"),
|
||||||
messageData: {"flags.sw5e.roll": {type: "other", itemId: this.id }}
|
messageData: {"flags.sw5e.roll": {type: "other", itemId: this.id }}
|
||||||
});
|
});
|
||||||
|
@ -910,7 +895,7 @@ export default class Item5e extends Item {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use a consumable item, deducting from the quantity or charges of the item.
|
* Use a consumable item, deducting from the quantity or charges of the item.
|
||||||
* @param {boolean} configureDialog Whether to show a configuration dialog
|
* @param {boolean} configureDialog Whether to show a configuration dialog
|
||||||
* @return {boolean} Whether further execution should be prevented
|
* @return {boolean} Whether further execution should be prevented
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -972,7 +957,7 @@ export default class Item5e extends Item {
|
||||||
if ( this.owner && this.owner.sheet ) this.owner.sheet.minimize();
|
if ( this.owner && this.owner.sheet ) this.owner.sheet.minimize();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
@ -1021,7 +1006,7 @@ export default class Item5e extends Item {
|
||||||
template: "systems/sw5e/templates/chat/tool-roll-dialog.html",
|
template: "systems/sw5e/templates/chat/tool-roll-dialog.html",
|
||||||
title: title,
|
title: title,
|
||||||
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
||||||
flavor: `${this.name} - ${game.i18n.localize("SW5E.ToolCheck")}`,
|
flavor: title,
|
||||||
dialogOptions: {
|
dialogOptions: {
|
||||||
width: 400,
|
width: 400,
|
||||||
top: options.event ? options.event.clientY - 80 : null,
|
top: options.event ? options.event.clientY - 80 : null,
|
||||||
|
@ -1055,8 +1040,8 @@ export default class Item5e extends Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include a proficiency score
|
// Include a proficiency score
|
||||||
const prof = "proficient" in rollData.item ? (rollData.item.proficient || 0) : 1;
|
const prof = ("proficient" in rollData.item) ? (rollData.item.proficient || 0) : 1;
|
||||||
rollData["prof"] = Math.floor(prof * rollData.attributes.prof);
|
rollData["prof"] = Math.floor(prof * (rollData.attributes.prof || 0));
|
||||||
return rollData;
|
return rollData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,7 +1174,7 @@ export default class Item5e extends Item {
|
||||||
if ( !targets.length ) ui.notifications.warn(game.i18n.localize("SW5E.ActionWarningNoToken"));
|
if ( !targets.length ) ui.notifications.warn(game.i18n.localize("SW5E.ActionWarningNoToken"));
|
||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Factory Methods */
|
/* Factory Methods */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import TraitSelector from "../apps/trait-selector.js";
|
import TraitSelector from "../apps/trait-selector.js";
|
||||||
|
import {onManageActiveEffect, prepareActiveEffectCategories} from "../effects.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override and extend the core ItemSheet implementation to handle specific item types
|
* Override and extend the core ItemSheet implementation to handle specific item types
|
||||||
|
@ -7,8 +8,11 @@ import TraitSelector from "../apps/trait-selector.js";
|
||||||
export default class ItemSheet5e extends ItemSheet {
|
export default class ItemSheet5e extends ItemSheet {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
|
// Expand the default size of the class sheet
|
||||||
if ( this.object.data.type === "class" ) {
|
if ( this.object.data.type === "class" ) {
|
||||||
this.options.width = 600;
|
this.options.width = this.position.width = 600;
|
||||||
|
this.options.height = this.position.height = 680;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +22,7 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
return mergeObject(super.defaultOptions, {
|
return mergeObject(super.defaultOptions, {
|
||||||
width: 560,
|
width: 560,
|
||||||
height: "auto",
|
height: 400,
|
||||||
classes: ["sw5e", "sheet", "item"],
|
classes: ["sw5e", "sheet", "item"],
|
||||||
resizable: true,
|
resizable: true,
|
||||||
scrollY: [".tab.details"],
|
scrollY: [".tab.details"],
|
||||||
|
@ -37,17 +41,17 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
getData() {
|
async getData(options) {
|
||||||
const data = super.getData();
|
const data = super.getData(options);
|
||||||
data.labels = this.item.labels;
|
data.labels = this.item.labels;
|
||||||
data.config = CONFIG.SW5E;
|
data.config = CONFIG.SW5E;
|
||||||
|
|
||||||
// Item Type, Status, and Details
|
// Item Type, Status, and Details
|
||||||
data.itemType = data.item.type.titleCase();
|
data.itemType = game.i18n.localize(`ITEM.Type${data.item.type.titleCase()}`);
|
||||||
data.itemStatus = this._getItemStatus(data.item);
|
data.itemStatus = this._getItemStatus(data.item);
|
||||||
data.itemProperties = this._getItemProperties(data.item);
|
data.itemProperties = this._getItemProperties(data.item);
|
||||||
data.isPhysical = data.item.data.hasOwnProperty("quantity");
|
data.isPhysical = data.item.data.hasOwnProperty("quantity");
|
||||||
|
|
||||||
// Potential consumption targets
|
// Potential consumption targets
|
||||||
data.abilityConsumptionTargets = this._getItemConsumptionTargets(data.item);
|
data.abilityConsumptionTargets = this._getItemConsumptionTargets(data.item);
|
||||||
|
|
||||||
|
@ -55,17 +59,20 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
data.hasAttackRoll = this.item.hasAttack;
|
data.hasAttackRoll = this.item.hasAttack;
|
||||||
data.isHealing = data.item.data.actionType === "heal";
|
data.isHealing = data.item.data.actionType === "heal";
|
||||||
data.isFlatDC = getProperty(data.item.data, "save.scaling") === "flat";
|
data.isFlatDC = getProperty(data.item.data, "save.scaling") === "flat";
|
||||||
data.isLine = ["line", "wall"].includes(data.item.data.target?.type);
|
data.isLine = ["line", "wall"].includes(data.item.data.target?.type);
|
||||||
|
|
||||||
// Vehicles
|
// Vehicles
|
||||||
data.isCrewed = data.item.data.activation?.type === 'crew';
|
data.isCrewed = data.item.data.activation?.type === 'crew';
|
||||||
data.isMountable = this._isItemMountable(data.item);
|
data.isMountable = this._isItemMountable(data.item);
|
||||||
|
|
||||||
|
// Prepare Active Effects
|
||||||
|
data.effects = prepareActiveEffectCategories(this.entity.effects);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the valid item consumption targets which exist on the actor
|
* Get the valid item consumption targets which exist on the actor
|
||||||
* @param {Object} item Item data for the item being displayed
|
* @param {Object} item Item data for the item being displayed
|
||||||
* @return {{string: string}} An object of potential consumption targets
|
* @return {{string: string}} An object of potential consumption targets
|
||||||
|
@ -109,6 +116,8 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
// Charges
|
// Charges
|
||||||
else if ( consume.type === "charges" ) {
|
else if ( consume.type === "charges" ) {
|
||||||
return actor.items.reduce((obj, i) => {
|
return actor.items.reduce((obj, i) => {
|
||||||
|
|
||||||
|
// Limited-use items
|
||||||
const uses = i.data.data.uses || {};
|
const uses = i.data.data.uses || {};
|
||||||
if ( uses.per && uses.max ) {
|
if ( uses.per && uses.max ) {
|
||||||
const label = uses.per === "charges" ?
|
const label = uses.per === "charges" ?
|
||||||
|
@ -116,6 +125,10 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
` (${game.i18n.format("SW5E.AbilityUseConsumableLabel", {max: uses.max, per: uses.per})})`;
|
` (${game.i18n.format("SW5E.AbilityUseConsumableLabel", {max: uses.max, per: uses.per})})`;
|
||||||
obj[i.id] = i.name + label;
|
obj[i.id] = i.name + label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recharging items
|
||||||
|
const recharge = i.data.data.recharge || {};
|
||||||
|
if ( recharge.value ) obj[i.id] = `${i.name} (${game.i18n.format("SW5E.Recharge")})`;
|
||||||
return obj;
|
return obj;
|
||||||
}, {})
|
}, {})
|
||||||
}
|
}
|
||||||
|
@ -177,31 +190,26 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( item.type === "species" ) {
|
else if ( item.type === "species" ) {
|
||||||
|
//props.push(labels.species);
|
||||||
}
|
}
|
||||||
else if ( item.type === "archetype" ) {
|
else if ( item.type === "archetype" ) {
|
||||||
|
//props.push(labels.archetype);
|
||||||
|
}
|
||||||
|
else if ( item.type === "background" ) {
|
||||||
|
//props.push(labels.background);
|
||||||
|
}
|
||||||
|
else if ( item.type === "classfeature" ) {
|
||||||
|
//props.push(labels.classfeature);
|
||||||
|
}
|
||||||
|
else if ( item.type === "fightingmastery" ) {
|
||||||
|
//props.push(labels.fightingmastery);
|
||||||
|
}
|
||||||
|
else if ( item.type === "fightingstyle" ) {
|
||||||
|
//props.push(labels.fightingstyle);
|
||||||
|
}
|
||||||
|
else if ( item.type === "lightsaberform" ) {
|
||||||
|
//props.push(labels.lightsaberform);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( item.type === "background" ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( item.type === "classfeature" ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( item.type === "fightingmastery" ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( item.type === "fightingstyle" ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( item.type === "lightsaberform" ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Action type
|
// Action type
|
||||||
if ( item.data.actionType ) {
|
if ( item.data.actionType ) {
|
||||||
|
@ -240,8 +248,8 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
setPosition(position={}) {
|
setPosition(position={}) {
|
||||||
if ( !this._minimized ) {
|
if ( !(this._minimized || position.height) ) {
|
||||||
position.height = this._tabs[0].active === "details" ? "auto" : this.options.height;
|
position.height = (this._tabs[0].active === "details") ? "auto" : this.options.height;
|
||||||
}
|
}
|
||||||
return super.setPosition(position);
|
return super.setPosition(position);
|
||||||
}
|
}
|
||||||
|
@ -251,17 +259,20 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
_updateObject(event, formData) {
|
_getSubmitData(updateData={}) {
|
||||||
|
|
||||||
// TODO: This can be removed once 0.7.x is release channel
|
// Create the expanded update data object
|
||||||
if ( !formData.data ) formData = expandObject(formData);
|
const fd = new FormDataExtended(this.form, {editors: this.editors});
|
||||||
|
let data = fd.toObject();
|
||||||
|
if ( updateData ) data = mergeObject(data, updateData);
|
||||||
|
else data = expandObject(data);
|
||||||
|
|
||||||
// Handle Damage Array
|
// Handle Damage array
|
||||||
const damage = formData.data?.damage;
|
const damage = data.data?.damage;
|
||||||
if ( damage ) damage.parts = Object.values(damage?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
|
if ( damage ) damage.parts = Object.values(damage?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
|
||||||
|
|
||||||
// Update the Item
|
// Return the flattened submission data
|
||||||
super._updateObject(event, formData);
|
return flattenObject(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -269,8 +280,14 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
/** @override */
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
html.find(".damage-control").click(this._onDamageControl.bind(this));
|
if ( this.isEditable ) {
|
||||||
html.find('.trait-selector.class-skills').click(this._onConfigureClassSkills.bind(this));
|
html.find(".damage-control").click(this._onDamageControl.bind(this));
|
||||||
|
html.find('.trait-selector.class-skills').click(this._onConfigureClassSkills.bind(this));
|
||||||
|
html.find(".effect-control").click(ev => {
|
||||||
|
if ( this.item.isOwned ) return ui.notifications.warn("Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update.")
|
||||||
|
onManageActiveEffect(ev, this.item)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -328,4 +345,12 @@ export default class ItemSheet5e extends ItemSheet {
|
||||||
maximum: skills.number
|
maximum: skills.number
|
||||||
}).render(true)
|
}).render(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _onSubmit(...args) {
|
||||||
|
if ( this._tabs[0].active === "details" ) this.position.height = "auto";
|
||||||
|
await super._onSubmit(...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ export const migrateWorld = async function() {
|
||||||
await a.update(updateData, {enforceTypes: false});
|
await a.update(updateData, {enforceTypes: false});
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
err.message = `Failed sw5e system migration for Actor ${a.name}: ${err.message}`;
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +28,7 @@ export const migrateWorld = async function() {
|
||||||
await i.update(updateData, {enforceTypes: false});
|
await i.update(updateData, {enforceTypes: false});
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
err.message = `Failed sw5e system migration for Item ${i.name}: ${err.message}`;
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,15 +42,15 @@ export const migrateWorld = async function() {
|
||||||
await s.update(updateData, {enforceTypes: false});
|
await s.update(updateData, {enforceTypes: false});
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
err.message = `Failed sw5e system migration for Scene ${s.name}: ${err.message}`;
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate World Compendium Packs
|
// Migrate World Compendium Packs
|
||||||
const packs = game.packs.filter(p => {
|
for ( let p of game.packs ) {
|
||||||
return (p.metadata.package === "world") && ["Actor", "Item", "Scene"].includes(p.metadata.entity)
|
if ( p.metadata.package !== "world" ) continue;
|
||||||
});
|
if ( !["Actor", "Item", "Scene"].includes(p.metadata.entity) ) continue;
|
||||||
for ( let p of packs ) {
|
|
||||||
await migrateCompendium(p);
|
await migrateCompendium(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,27 +70,46 @@ export const migrateCompendium = async function(pack) {
|
||||||
const entity = pack.metadata.entity;
|
const entity = pack.metadata.entity;
|
||||||
if ( !["Actor", "Item", "Scene"].includes(entity) ) return;
|
if ( !["Actor", "Item", "Scene"].includes(entity) ) return;
|
||||||
|
|
||||||
|
// Unlock the pack for editing
|
||||||
|
const wasLocked = pack.locked;
|
||||||
|
await pack.configure({locked: false});
|
||||||
|
|
||||||
// Begin by requesting server-side data model migration and get the migrated content
|
// Begin by requesting server-side data model migration and get the migrated content
|
||||||
await pack.migrate();
|
await pack.migrate();
|
||||||
const content = await pack.getContent();
|
const content = await pack.getContent();
|
||||||
|
|
||||||
// Iterate over compendium entries - applying fine-tuned migration functions
|
// Iterate over compendium entries - applying fine-tuned migration functions
|
||||||
for ( let ent of content ) {
|
for ( let ent of content ) {
|
||||||
|
let updateData = {};
|
||||||
try {
|
try {
|
||||||
let updateData = null;
|
switch (entity) {
|
||||||
if (entity === "Item") updateData = migrateItemData(ent.data);
|
case "Actor":
|
||||||
else if (entity === "Actor") updateData = migrateActorData(ent.data);
|
updateData = migrateActorData(ent.data);
|
||||||
else if ( entity === "Scene" ) updateData = migrateSceneData(ent.data);
|
break;
|
||||||
if (!isObjectEmpty(updateData)) {
|
case "Item":
|
||||||
expandObject(updateData);
|
updateData = migrateItemData(ent.data);
|
||||||
updateData["_id"] = ent._id;
|
break;
|
||||||
await pack.updateEntity(updateData);
|
case "Scene":
|
||||||
console.log(`Migrated ${entity} entity ${ent.name} in Compendium ${pack.collection}`);
|
updateData = migrateSceneData(ent.data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch(err) {
|
if ( isObjectEmpty(updateData) ) continue;
|
||||||
|
|
||||||
|
// Save the entry, if data was changed
|
||||||
|
updateData["_id"] = ent._id;
|
||||||
|
await pack.updateEntity(updateData);
|
||||||
|
console.log(`Migrated ${entity} entity ${ent.name} in Compendium ${pack.collection}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle migration failures
|
||||||
|
catch(err) {
|
||||||
|
err.message = `Failed sw5e system migration for entity ${ent.name} in pack ${pack.collection}: ${err.message}`;
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the original locked status for the pack
|
||||||
|
pack.configure({locked: wasLocked});
|
||||||
console.log(`Migrated all ${entity} entities from Compendium ${pack.collection}`);
|
console.log(`Migrated all ${entity} entities from Compendium ${pack.collection}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,9 +128,7 @@ export const migrateActorData = function(actor) {
|
||||||
|
|
||||||
// Actor Data Updates
|
// Actor Data Updates
|
||||||
_migrateActorBonuses(actor, updateData);
|
_migrateActorBonuses(actor, updateData);
|
||||||
|
_migrateActorMovement(actor, updateData);
|
||||||
// Remove deprecated fields
|
|
||||||
_migrateRemoveDeprecated(actor, updateData);
|
|
||||||
|
|
||||||
// Migrate Owned Items
|
// Migrate Owned Items
|
||||||
if ( !actor.items ) return updateData;
|
if ( !actor.items ) return updateData;
|
||||||
|
@ -172,11 +191,6 @@ function cleanActorData(actorData) {
|
||||||
*/
|
*/
|
||||||
export const migrateItemData = function(item) {
|
export const migrateItemData = function(item) {
|
||||||
const updateData = {};
|
const updateData = {};
|
||||||
|
|
||||||
// Remove deprecated fields
|
|
||||||
_migrateRemoveDeprecated(item, updateData);
|
|
||||||
|
|
||||||
// Return the migrated update data
|
|
||||||
return updateData;
|
return updateData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -225,31 +239,17 @@ function _migrateActorBonuses(actor, updateData) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A general migration to remove all fields from the data model which are flagged with a _deprecated tag
|
* Migrate the actor bonuses object
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
const _migrateRemoveDeprecated = function(ent, updateData) {
|
function _migrateActorMovement(actor, updateData) {
|
||||||
const flat = flattenObject(ent.data);
|
if ( actor.data.attributes?.movement?.walk !== undefined ) return;
|
||||||
|
const s = (actor.data.attributes?.speed?.value || "").split(" ");
|
||||||
// Identify objects to deprecate
|
if ( s.length > 0 ) updateData["data.attributes.movement.walk"] = Number.isNumeric(s[0]) ? parseInt(s[0]) : null;
|
||||||
const toDeprecate = Object.entries(flat).filter(e => e[0].endsWith("_deprecated") && (e[1] === true)).map(e => {
|
}
|
||||||
let parent = e[0].split(".");
|
|
||||||
parent.pop();
|
|
||||||
return parent.join(".");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove them
|
|
||||||
for ( let k of toDeprecate ) {
|
|
||||||
let parts = k.split(".");
|
|
||||||
parts[parts.length-1] = "-=" + parts[parts.length-1];
|
|
||||||
updateData[`data.${parts.join(".")}`] = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
@ -280,3 +280,24 @@ export async function purgeFlags(pack) {
|
||||||
}
|
}
|
||||||
await pack.configure({locked: true});
|
await pack.configure({locked: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge the data model of any inner objects which have been flagged as _deprecated.
|
||||||
|
* @param {object} data The data to clean
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function removeDeprecatedObjects(data) {
|
||||||
|
for ( let [k, v] of Object.entries(data) ) {
|
||||||
|
if ( getType(v) === "Object" ) {
|
||||||
|
if (v._deprecated === true) {
|
||||||
|
console.log(`Deleting deprecated object key ${k}`);
|
||||||
|
delete data[k];
|
||||||
|
}
|
||||||
|
else removeDeprecatedObjects(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default class AbilityTemplate extends MeasuredTemplate {
|
||||||
templateData.width = target.value;
|
templateData.width = target.value;
|
||||||
templateData.direction = 45;
|
templateData.direction = 45;
|
||||||
break;
|
break;
|
||||||
case "ray": // 5e rays are most commonly 1 square (5 ft) in width
|
case "ray": // 5e rays are most commonly 1 square (5 ft) in width
|
||||||
templateData.width = target.width ?? canvas.dimensions.distance;
|
templateData.width = target.width ?? canvas.dimensions.distance;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -7,11 +7,11 @@ export const registerSystemSettings = function() {
|
||||||
name: "System Migration Version",
|
name: "System Migration Version",
|
||||||
scope: "world",
|
scope: "world",
|
||||||
config: false,
|
config: false,
|
||||||
type: Number,
|
type: String,
|
||||||
default: 0
|
default: ""
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register resting variants
|
* Register resting variants
|
||||||
*/
|
*/
|
||||||
game.settings.register("sw5e", "restVariant", {
|
game.settings.register("sw5e", "restVariant", {
|
||||||
|
@ -82,18 +82,6 @@ export const registerSystemSettings = function() {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Option to automatically create Power Measured Template on roll
|
|
||||||
*/
|
|
||||||
game.settings.register("sw5e", "alwaysPlacePowerTemplate", {
|
|
||||||
name: "SETTINGS.5eAutoPowerTemplateN",
|
|
||||||
hint: "SETTINGS.5eAutoPowerTemplateL",
|
|
||||||
scope: "client",
|
|
||||||
config: true,
|
|
||||||
default: false,
|
|
||||||
type: Boolean
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option to automatically collapse Item Card descriptions
|
* Option to automatically collapse Item Card descriptions
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,17 +4,16 @@
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
export const preloadHandlebarsTemplates = async function() {
|
export const preloadHandlebarsTemplates = async function() {
|
||||||
|
return loadTemplates([
|
||||||
|
|
||||||
// Define template paths to load
|
// Shared Partials
|
||||||
const templatePaths = [
|
"systems/sw5e/templates/actors/parts/active-effects.html",
|
||||||
|
|
||||||
// Actor Sheet Partials
|
// Actor Sheet Partials
|
||||||
"systems/sw5e/templates/actors/oldActor/parts/actor-traits.html",
|
"systems/sw5e/templates/actors/oldActor/parts/actor-traits.html",
|
||||||
"systems/sw5e/templates/actors/oldActor/parts/actor-inventory.html",
|
"systems/sw5e/templates/actors/oldActor/parts/actor-inventory.html",
|
||||||
"systems/sw5e/templates/actors/oldActor/parts/actor-features.html",
|
"systems/sw5e/templates/actors/oldActor/parts/actor-features.html",
|
||||||
"systems/sw5e/templates/actors/oldActor/parts/actor-powerbook.html",
|
"systems/sw5e/templates/actors/oldActor/parts/actor-powerbook.html",
|
||||||
"systems/sw5e/templates/actors/oldActor/parts/actor-effects.html",
|
|
||||||
|
|
||||||
|
|
||||||
"systems/sw5e/templates/actors/newActor/parts/swalt-biography.html",
|
"systems/sw5e/templates/actors/newActor/parts/swalt-biography.html",
|
||||||
"systems/sw5e/templates/actors/newActor/parts/swalt-core.html",
|
"systems/sw5e/templates/actors/newActor/parts/swalt-core.html",
|
||||||
|
@ -30,8 +29,5 @@ export const preloadHandlebarsTemplates = async function() {
|
||||||
"systems/sw5e/templates/items/parts/item-activation.html",
|
"systems/sw5e/templates/items/parts/item-activation.html",
|
||||||
"systems/sw5e/templates/items/parts/item-description.html",
|
"systems/sw5e/templates/items/parts/item-description.html",
|
||||||
"systems/sw5e/templates/items/parts/item-mountable.html"
|
"systems/sw5e/templates/items/parts/item-mountable.html"
|
||||||
];
|
]);
|
||||||
|
|
||||||
// Load the template parts
|
|
||||||
return loadTemplates(templatePaths);
|
|
||||||
};
|
};
|
||||||
|
|
257
sw5e.css
257
sw5e.css
|
@ -231,6 +231,12 @@
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* Trait Lists */
|
/* Trait Lists */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Items Lists */
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Active Effects */
|
||||||
|
/* ----------------------------------------- */
|
||||||
}
|
}
|
||||||
.sw5e.sheet .window-content {
|
.sw5e.sheet .window-content {
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
@ -404,6 +410,88 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
.sw5e.sheet .items-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
color: #7a7971;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item {
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 2px;
|
||||||
|
border-bottom: 1px solid #c9c7b8;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item .item-name {
|
||||||
|
color: #191813;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item .item-name .item-image {
|
||||||
|
flex: 0 0 30px;
|
||||||
|
height: 30px;
|
||||||
|
background-size: 30px;
|
||||||
|
border: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item .item-name h4 {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .items-header {
|
||||||
|
height: 28px;
|
||||||
|
margin: 2px 0;
|
||||||
|
padding: 0;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
border: 2px groove #eeede0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .items-header > * {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .items-header .item-name {
|
||||||
|
padding-left: 5px;
|
||||||
|
font-family: 'Russo One';
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item-name {
|
||||||
|
flex: 2;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: left;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item-controls {
|
||||||
|
flex: 0 0 60px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .items-list .item-controls a {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .effects .item .effect-source,
|
||||||
|
.sw5e.sheet .effects .item .effect-duration,
|
||||||
|
.sw5e.sheet .effects .item .effect-controls {
|
||||||
|
text-align: center;
|
||||||
|
border-left: 1px solid #c9c7b8;
|
||||||
|
border-right: 1px solid #c9c7b8;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.sw5e.sheet .effects .item .effect-controls {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* Trait Selector
|
/* Trait Selector
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
@ -447,9 +535,6 @@
|
||||||
/* Powerbook */
|
/* Powerbook */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* Active Effects */
|
|
||||||
/* ----------------------------------------- */
|
|
||||||
/* ----------------------------------------- */
|
|
||||||
/* TinyMCE */
|
/* TinyMCE */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
}
|
}
|
||||||
|
@ -515,6 +600,7 @@
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #4b4a44;
|
color: #4b4a44;
|
||||||
border-bottom: 1px solid #c9c7b8;
|
border-bottom: 1px solid #c9c7b8;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .tab.attributes {
|
.sw5e.sheet.actor .tab.attributes {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -559,6 +645,7 @@
|
||||||
font-family: "Signika", sans-serif;
|
font-family: "Signika", sans-serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .ability-scores {
|
.sw5e.sheet.actor .ability-scores {
|
||||||
flex: 0 0 100px;
|
flex: 0 0 100px;
|
||||||
|
@ -771,35 +858,10 @@
|
||||||
border-bottom: 2px groove #eeede0;
|
border-bottom: 2px groove #eeede0;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list {
|
.sw5e.sheet.actor .inventory-list {
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
overflow-y: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
color: #7a7971;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item {
|
|
||||||
line-height: 30px;
|
|
||||||
padding: 0 2px;
|
|
||||||
border-bottom: 1px solid #c9c7b8;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list .item .item-name {
|
.sw5e.sheet.actor .inventory-list .item .item-name {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
max-height: 30px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item .item-name .item-image {
|
|
||||||
flex: 0 0 30px;
|
|
||||||
background-size: 30px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item .item-name h4 {
|
|
||||||
margin: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list .item .item-name.rollable:hover .item-image {
|
.sw5e.sheet.actor .inventory-list .item .item-name.rollable:hover .item-image {
|
||||||
background-image: url("../../icons/svg/d20-grey.svg") !important;
|
background-image: url("../../icons/svg/d20-grey.svg") !important;
|
||||||
|
@ -821,36 +883,14 @@
|
||||||
flex: 0 0 80px;
|
flex: 0 0 80px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: #7a7971;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list .inventory-header {
|
|
||||||
margin: 2px 0;
|
|
||||||
padding: 0;
|
|
||||||
align-items: center;
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
border: 2px groove #eeede0;
|
|
||||||
font-weight: bold;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .inventory-header h3 {
|
|
||||||
margin: 0 -5px 0 0;
|
|
||||||
padding-left: 5px;
|
|
||||||
font-family: 'Russo One';
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .inventory-header .item-controls a.item-create {
|
.sw5e.sheet.actor .inventory-list .inventory-header .item-controls a.item-create {
|
||||||
flex: 0 0 100%;
|
flex: 0 0 100%;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list .item-name {
|
|
||||||
color: #191813;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-detail {
|
.sw5e.sheet.actor .inventory-list .item-detail {
|
||||||
flex: 0 0 70px;
|
flex: 0 0 70px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #7a7971;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-right: 1px solid #c9c7b8;
|
border-right: 1px solid #c9c7b8;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
@ -868,45 +908,15 @@
|
||||||
border-left: 1px solid #c9c7b8;
|
border-left: 1px solid #c9c7b8;
|
||||||
border-right: 1px solid #c9c7b8;
|
border-right: 1px solid #c9c7b8;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list .item-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls {
|
.sw5e.sheet.actor .inventory-list .item-controls {
|
||||||
flex: 0 0 44px;
|
flex: 0 0 44px;
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-start;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls > * {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls .flex1 {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls .flex2 {
|
|
||||||
flex: 2;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls .flex3 {
|
|
||||||
flex: 3;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls .flex4 {
|
|
||||||
flex: 4;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .inventory-list .item-controls a {
|
|
||||||
flex: 0 0 22px;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
color: #7a7971;
|
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .inventory-list .item-summary {
|
.sw5e.sheet.actor .inventory-list .item-summary {
|
||||||
flex: 0 0 100%;
|
flex: 0 0 100%;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
|
color: #191813;
|
||||||
border-top: 1px solid #c9c7b8;
|
border-top: 1px solid #c9c7b8;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .encumbrance {
|
.sw5e.sheet.actor .encumbrance {
|
||||||
|
@ -1034,42 +1044,25 @@
|
||||||
.sw5e.sheet.actor .powerbook-empty .item-controls {
|
.sw5e.sheet.actor .powerbook-empty .item-controls {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.actor .effects .effect-name {
|
|
||||||
flex: 2;
|
|
||||||
align-items: center;
|
|
||||||
color: #191813;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .effects .effect-name h4 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .effects .effect-icon {
|
|
||||||
flex: 0 0 30px;
|
|
||||||
height: 30px;
|
|
||||||
margin-right: 5px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .effects .effect-source,
|
|
||||||
.sw5e.sheet.actor .effects .effect-duration {
|
|
||||||
text-align: center;
|
|
||||||
border-left: 1px solid #c9c7b8;
|
|
||||||
border-right: 1px solid #c9c7b8;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .effects .effect-controls {
|
|
||||||
flex: 0 0 60px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .effects .effect {
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid #c9c7b8;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .effects .effect:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.sw5e.sheet.actor .editor {
|
.sw5e.sheet.actor .editor {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
|
#actor-flags .window-content {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
#actor-flags form {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
#actor-flags .form-body {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
.sw5e.sheet.item {
|
.sw5e.sheet.item {
|
||||||
min-height: 420px;
|
min-height: 400px;
|
||||||
|
max-height: 95%;
|
||||||
|
min-width: 480px;
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
/* Sheet Header */
|
/* Sheet Header */
|
||||||
/* ----------------------------------------- */
|
/* ----------------------------------------- */
|
||||||
|
@ -1090,7 +1083,7 @@
|
||||||
border: 2px solid #000;
|
border: 2px solid #000;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.item .sheet-header .item-subtitle {
|
.sw5e.sheet.item .sheet-header .item-subtitle {
|
||||||
flex: 0 0 80px;
|
flex: 0 0 100px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -1165,14 +1158,15 @@
|
||||||
.sw5e.sheet.item .details .form-group.input-select-select select {
|
.sw5e.sheet.item .details .form-group.input-select-select select {
|
||||||
flex: 1.5;
|
flex: 1.5;
|
||||||
}
|
}
|
||||||
|
.sw5e.sheet.item .details .form-group.uses-per .form-fields {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
.sw5e.sheet.item .details .form-group.uses-per input {
|
.sw5e.sheet.item .details .form-group.uses-per input {
|
||||||
flex: 1;
|
flex: 0 0 32px;
|
||||||
}
|
}
|
||||||
.sw5e.sheet.item .details .form-group.uses-per span {
|
.sw5e.sheet.item .details .form-group.uses-per span {
|
||||||
flex: 0 0 16px;
|
flex: 0 0 16px;
|
||||||
}
|
margin: 0 4px 0 0;
|
||||||
.sw5e.sheet.item .details .form-group.uses-per select {
|
|
||||||
flex: 3;
|
|
||||||
}
|
}
|
||||||
.sw5e.sheet.item .details span.sep {
|
.sw5e.sheet.item .details span.sep {
|
||||||
flex: 0 0 8px;
|
flex: 0 0 8px;
|
||||||
|
@ -1544,30 +1538,3 @@
|
||||||
max-width: 40px;
|
max-width: 40px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
input[type="number"] {
|
|
||||||
width: calc(100% - 2px);
|
|
||||||
min-width: 20px;
|
|
||||||
height: 26px;
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
padding: 1px 3px;
|
|
||||||
margin: 0;
|
|
||||||
color: #191813;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
text-align: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
border: 1px solid #7a7971;
|
|
||||||
border-radius: 3px;
|
|
||||||
-webkit-user-select: text;
|
|
||||||
-moz-user-select: text;
|
|
||||||
-ms-user-select: text;
|
|
||||||
user-select: text;
|
|
||||||
-moz-appearance: textfield;
|
|
||||||
}
|
|
||||||
input[type="number"]:focus {
|
|
||||||
box-shadow: 0 0 5px red;
|
|
||||||
}
|
|
||||||
input[type="number"]::-webkit-inner-spin-button,
|
|
||||||
input[type="number"]::-webkit-outer-spin-button {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
51
sw5e.js
51
sw5e.js
|
@ -29,6 +29,7 @@ import ActorSheet5eCharacterNew from "./module/actor/sheets/newSheet/character.j
|
||||||
import ItemSheet5e from "./module/item/sheet.js";
|
import ItemSheet5e from "./module/item/sheet.js";
|
||||||
import ShortRestDialog from "./module/apps/short-rest.js";
|
import ShortRestDialog from "./module/apps/short-rest.js";
|
||||||
import TraitSelector from "./module/apps/trait-selector.js";
|
import TraitSelector from "./module/apps/trait-selector.js";
|
||||||
|
import MovementConfig from "./module/apps/movement-config.js";
|
||||||
|
|
||||||
// Import Helpers
|
// Import Helpers
|
||||||
import * as chat from "./module/chat.js";
|
import * as chat from "./module/chat.js";
|
||||||
|
@ -54,7 +55,8 @@ Hooks.once("init", function() {
|
||||||
ActorSheet5eVehicle,
|
ActorSheet5eVehicle,
|
||||||
ItemSheet5e,
|
ItemSheet5e,
|
||||||
ShortRestDialog,
|
ShortRestDialog,
|
||||||
TraitSelector
|
TraitSelector,
|
||||||
|
MovementConfig
|
||||||
},
|
},
|
||||||
canvas: {
|
canvas: {
|
||||||
AbilityTemplate
|
AbilityTemplate
|
||||||
|
@ -74,7 +76,7 @@ Hooks.once("init", function() {
|
||||||
CONFIG.SW5E = SW5E;
|
CONFIG.SW5E = SW5E;
|
||||||
CONFIG.Actor.entityClass = Actor5e;
|
CONFIG.Actor.entityClass = Actor5e;
|
||||||
CONFIG.Item.entityClass = Item5e;
|
CONFIG.Item.entityClass = Item5e;
|
||||||
if ( CONFIG.time ) CONFIG.time.roundTime = 6; // TODO remove conditional after 0.7.x
|
CONFIG.time.roundTime = 6;
|
||||||
|
|
||||||
// Add DND5e namespace for module compatability
|
// Add DND5e namespace for module compatability
|
||||||
game.dnd5e = game.sw5e;
|
game.dnd5e = game.sw5e;
|
||||||
|
@ -132,18 +134,18 @@ Hooks.once("setup", function() {
|
||||||
|
|
||||||
// Localize CONFIG objects once up-front
|
// Localize CONFIG objects once up-front
|
||||||
const toLocalize = [
|
const toLocalize = [
|
||||||
"abilities", "abilityAbbreviations", "alignments", "conditionTypes", "consumableTypes", "currencies",
|
"abilities", "abilityAbbreviations", "abilityActivationTypes", "abilityConsumptionTypes", "actorSizes", "alignments",
|
||||||
"damageTypes", "damageResistanceTypes", "distanceUnits", "equipmentTypes", "healingTypes", "itemActionTypes",
|
"armorProficiencies", "armorPropertiesTypes", "conditionTypes", "consumableTypes", "cover", "currencies", "damageResistanceTypes",
|
||||||
"limitedUsePeriods", "senses", "skills", "powerComponents", "powerLevels", "powerPreparationModes", "powerSchools",
|
"damageTypes", "distanceUnits", "equipmentTypes", "healingTypes", "itemActionTypes", "languages",
|
||||||
"powerScalingModes", "targetTypes", "timePeriods", "weaponProperties", "weaponTypes", "languages",
|
"limitedUsePeriods", "movementUnits", "polymorphSettings", "proficiencyLevels", "senses", "skills",
|
||||||
"polymorphSettings", "armorProficiencies", "weaponProficiencies", "toolProficiencies", "abilityActivationTypes",
|
"powerComponents", "powerLevels", "powerPreparationModes", "powerScalingModes", "powerSchools", "targetTypes",
|
||||||
"abilityConsumptionTypes", "actorSizes", "proficiencyLevels", "armorPropertiesTypes", "cover"
|
"timePeriods", "toolProficiencies", "weaponProficiencies", "weaponProperties", "weaponTypes"
|
||||||
];
|
];
|
||||||
|
|
||||||
// Exclude some from sorting where the default order matters
|
// Exclude some from sorting where the default order matters
|
||||||
const noSort = [
|
const noSort = [
|
||||||
"abilities", "alignments", "currencies", "distanceUnits", "itemActionTypes", "proficiencyLevels",
|
"abilities", "alignments", "currencies", "distanceUnits", "movementUnits", "itemActionTypes", "proficiencyLevels",
|
||||||
"limitedUsePeriods", "powerComponents", "powerLevels", "weaponTypes"
|
"limitedUsePeriods", "powerComponents", "powerLevels", "powerPreparationModes", "weaponTypes"
|
||||||
];
|
];
|
||||||
|
|
||||||
// Localize and sort CONFIG objects
|
// Localize and sort CONFIG objects
|
||||||
|
@ -171,22 +173,23 @@ Hooks.once("setup", function() {
|
||||||
*/
|
*/
|
||||||
Hooks.once("ready", function() {
|
Hooks.once("ready", function() {
|
||||||
|
|
||||||
// Determine whether a system migration is required and feasible
|
|
||||||
const currentVersion = game.settings.get("sw5e", "systemMigrationVersion");
|
|
||||||
const NEEDS_MIGRATION_VERSION = 0.84;
|
|
||||||
const COMPATIBLE_MIGRATION_VERSION = 0.80;
|
|
||||||
let needMigration = (currentVersion < NEEDS_MIGRATION_VERSION) || (currentVersion === null);
|
|
||||||
|
|
||||||
// Perform the migration
|
|
||||||
if ( needMigration && game.user.isGM ) {
|
|
||||||
if ( currentVersion && (currentVersion < COMPATIBLE_MIGRATION_VERSION) ) {
|
|
||||||
ui.notifications.error(`Your SW5E system data is from too old a Foundry version and cannot be reliably migrated to the latest version. The process will be attempted, but errors may occur.`, {permanent: true});
|
|
||||||
}
|
|
||||||
migrations.migrateWorld();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
|
// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
|
||||||
Hooks.on("hotbarDrop", (bar, data, slot) => macros.create5eMacro(data, slot));
|
Hooks.on("hotbarDrop", (bar, data, slot) => macros.create5eMacro(data, slot));
|
||||||
|
|
||||||
|
// Determine whether a system migration is required and feasible
|
||||||
|
if ( !game.user.isGM ) return;
|
||||||
|
const currentVersion = game.settings.get("sw5e", "systemMigrationVersion");
|
||||||
|
const NEEDS_MIGRATION_VERSION = "1.1.0";
|
||||||
|
const COMPATIBLE_MIGRATION_VERSION = 0.80;
|
||||||
|
const needsMigration = currentVersion && isNewerVersion(NEEDS_MIGRATION_VERSION, currentVersion);
|
||||||
|
if ( !needsMigration ) return;
|
||||||
|
|
||||||
|
// Perform the migration
|
||||||
|
if ( currentVersion && isNewerVersion(COMPATIBLE_MIGRATION_VERSION, currentVersion) ) {
|
||||||
|
const warning = `Your SW5e system data is from too old a Foundry version and cannot be reliably migrated to the latest version. The process will be attempted, but errors may occur.`;
|
||||||
|
ui.notifications.error(warning, {permanent: true});
|
||||||
|
}
|
||||||
|
migrations.migrateWorld();
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
34
system.json
34
system.json
|
@ -2,7 +2,7 @@
|
||||||
"name": "sw5e",
|
"name": "sw5e",
|
||||||
"title": "SW 5th Edition",
|
"title": "SW 5th Edition",
|
||||||
"description": "A comprehensive game system for running games of SW 5th Edition in the Foundry VTT environment.",
|
"description": "A comprehensive game system for running games of SW 5th Edition in the Foundry VTT environment.",
|
||||||
"version": 0.98,
|
"version": "1.1.1",
|
||||||
"author": "Dev Team",
|
"author": "Dev Team",
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
"esmodules": ["sw5e.js"],
|
"esmodules": ["sw5e.js"],
|
||||||
|
@ -56,17 +56,17 @@
|
||||||
"path": "./packs/packs/feats.db",
|
"path": "./packs/packs/feats.db",
|
||||||
"entity": "Item"
|
"entity": "Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fightingstyles",
|
"name": "fightingstyles",
|
||||||
"label": "Fighting Styles",
|
"label": "Fighting Styles",
|
||||||
"path": "./packs/packs/fightingstyles.db",
|
"path": "./packs/packs/fightingstyles.db",
|
||||||
"entity": "Item"
|
"entity": "Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fightingmasteries",
|
"name": "fightingmasteries",
|
||||||
"label": "Fighting Masteries",
|
"label": "Fighting Masteries",
|
||||||
"path": "./packs/packs/fightingmasteries.db",
|
"path": "./packs/packs/fightingmasteries.db",
|
||||||
"entity": "Item"
|
"entity": "Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "forcepowers",
|
"name": "forcepowers",
|
||||||
|
@ -103,20 +103,20 @@
|
||||||
"label": "Species Traits",
|
"label": "Species Traits",
|
||||||
"path": "./packs/packs/speciestraits.db",
|
"path": "./packs/packs/speciestraits.db",
|
||||||
"entity": "Item"
|
"entity": "Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tables",
|
"name": "tables",
|
||||||
"label": "Tables",
|
"label": "Tables",
|
||||||
"path": "./packs/packs/tables.db",
|
"path": "./packs/packs/tables.db",
|
||||||
"entity": "RollTable"
|
"entity": "RollTable"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "techpowers",
|
"name": "techpowers",
|
||||||
"label": "Tech Powers",
|
"label": "Tech Powers",
|
||||||
"path": "./packs/packs/techpowers.db",
|
"path": "./packs/packs/techpowers.db",
|
||||||
"entity": "Item"
|
"entity": "Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "weapons",
|
"name": "weapons",
|
||||||
"label": "Weapons",
|
"label": "Weapons",
|
||||||
"path": "./packs/packs/weapons.db",
|
"path": "./packs/packs/weapons.db",
|
||||||
|
@ -135,8 +135,8 @@
|
||||||
"gridUnits": "ft",
|
"gridUnits": "ft",
|
||||||
"primaryTokenAttribute": "attributes.hp",
|
"primaryTokenAttribute": "attributes.hp",
|
||||||
"secondaryTokenAttribute": null,
|
"secondaryTokenAttribute": null,
|
||||||
"minimumCoreVersion": "0.5.6",
|
"minimumCoreVersion": "0.7.6",
|
||||||
"compatibleCoreVersion": "0.7.5",
|
"compatibleCoreVersion": "0.7.6",
|
||||||
"url": "https://github.com/unrealkakeman89/sw5e",
|
"url": "https://github.com/unrealkakeman89/sw5e",
|
||||||
"manifest": "https://raw.githubusercontent.com/unrealkakeman89/sw5e/master/system.json",
|
"manifest": "https://raw.githubusercontent.com/unrealkakeman89/sw5e/master/system.json",
|
||||||
"download": "https://github.com/unrealkakeman89/sw5e/archive/master.zip"
|
"download": "https://github.com/unrealkakeman89/sw5e/archive/master.zip"
|
||||||
|
|
|
@ -76,10 +76,18 @@
|
||||||
},
|
},
|
||||||
"creature": {
|
"creature": {
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"movement": {
|
||||||
|
"burrow": 0,
|
||||||
|
"climb": 0,
|
||||||
|
"fly": 0,
|
||||||
|
"swim": 0,
|
||||||
|
"walk": 30,
|
||||||
|
"units": "ft",
|
||||||
|
"hover": false
|
||||||
|
},
|
||||||
"powercasting": "int",
|
"powercasting": "int",
|
||||||
"speed": {
|
"speed": {
|
||||||
"value": "30 ft",
|
"_deprecated": true
|
||||||
"special": ""
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"details": {
|
"details": {
|
||||||
|
@ -481,14 +489,14 @@
|
||||||
"value": ""
|
"value": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"speciesDescription": {
|
"speciesDescription": {
|
||||||
"data": "$characteristics-table",
|
"data": "$characteristics-table",
|
||||||
"description": {
|
"description": {
|
||||||
"value": "",
|
"value": "",
|
||||||
"chat": "",
|
"chat": "",
|
||||||
"unidentified": ""
|
"unidentified": ""
|
||||||
},
|
},
|
||||||
"traits": ""
|
"traits": ""
|
||||||
},
|
},
|
||||||
"physicalItem": {
|
"physicalItem": {
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
|
@ -560,14 +568,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"archetype": {
|
"archetype": {
|
||||||
"templates": ["archetypeDescription"],
|
"templates": ["archetypeDescription"],
|
||||||
"className": "",
|
"className": "",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"templates": ["backgroundDescription"]
|
"templates": ["backgroundDescription"]
|
||||||
},
|
},
|
||||||
"backpack": {
|
"backpack": {
|
||||||
"templates": ["itemDescription", "physicalItem"],
|
"templates": ["itemDescription", "physicalItem"],
|
||||||
"capacity": {
|
"capacity": {
|
||||||
|
@ -593,19 +601,19 @@
|
||||||
},
|
},
|
||||||
"powercasting": "none"
|
"powercasting": "none"
|
||||||
},
|
},
|
||||||
"classfeature": {
|
"classfeature": {
|
||||||
"templates": ["itemDescription", "activatedEffect", "action"],
|
"templates": ["itemDescription", "activatedEffect", "action"],
|
||||||
"className": ""
|
"className": ""
|
||||||
},
|
},
|
||||||
"fightingmastery": {
|
"fightingmastery": {
|
||||||
"templates": ["fightingmasteryDescription"]
|
"templates": ["fightingmasteryDescription"]
|
||||||
},
|
},
|
||||||
"fightingstyle": {
|
"fightingstyle": {
|
||||||
"templates": ["fightingstyleDescription"]
|
"templates": ["fightingstyleDescription"]
|
||||||
},
|
},
|
||||||
"lightsaberform": {
|
"lightsaberform": {
|
||||||
"templates": ["lightsaberformDescription"]
|
"templates": ["lightsaberformDescription"]
|
||||||
},
|
},
|
||||||
"consumable": {
|
"consumable": {
|
||||||
"templates": ["itemDescription", "physicalItem", "activatedEffect", "action"],
|
"templates": ["itemDescription", "physicalItem", "activatedEffect", "action"],
|
||||||
"consumableType": "potion",
|
"consumableType": "potion",
|
||||||
|
@ -641,7 +649,7 @@
|
||||||
},
|
},
|
||||||
"species": {
|
"species": {
|
||||||
"templates": ["speciesDescription"]
|
"templates": ["speciesDescription"]
|
||||||
},
|
},
|
||||||
"tool": {
|
"tool": {
|
||||||
"templates": ["itemDescription", "physicalItem"],
|
"templates": ["itemDescription", "physicalItem"],
|
||||||
"ability": "int",
|
"ability": "int",
|
||||||
|
|
|
@ -82,25 +82,25 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="attribute">
|
<li class="attribute">
|
||||||
<h4 class="attribute-name box-title">{{ localize "SW5E.Speed" }}</h4>
|
<h4 class="attribute-name box-title">
|
||||||
|
{{ localize "SW5E.Speed" }}
|
||||||
|
</h4>
|
||||||
<div class="attribute-value">
|
<div class="attribute-value">
|
||||||
<input name="data.attributes.speed.value" type="text"
|
<span>{{movement.primary}}</span>
|
||||||
value="{{data.attributes.speed.value}}" placeholder="0"/>
|
|
||||||
</div>
|
</div>
|
||||||
<footer class="attribute-footer">
|
<footer class="attribute-footer">
|
||||||
<input type="text" class="speed" name="data.attributes.speed.special"
|
<span>{{movement.special}}</span>
|
||||||
value="{{data.attributes.speed.special}}" placeholder="{{ localize 'SW5E.SpeedSpecial' }}"/>
|
|
||||||
</footer>
|
</footer>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="attribute initiative">
|
<li class="attribute initiative">
|
||||||
<h4 class="attribute-name box-title">{{ localize "SW5E.Initiative" }}</h4>
|
<h4 class="attribute-name box-title rollable" data-action="rollInitiative">{{ localize "SW5E.Initiative" }}</h4>
|
||||||
<div class="attribute-value">
|
<div class="attribute-value">
|
||||||
<span>{{numberFormat data.attributes.init.total decimals=0 sign=true}}</span>
|
<span>{{numberFormat data.attributes.init.total decimals=0 sign=true}}</span>
|
||||||
</div>
|
</div>
|
||||||
<footer class="attribute-footer">
|
<footer class="attribute-footer">
|
||||||
<span>{{ localize "SW5E.Modifier" }}</span>
|
<span>{{ localize "SW5E.Modifier" }}</span>
|
||||||
<input name="data.attributes.init.value" type="number" placeholder="0"
|
<input name="data.attributes.init.value" type="text" data-dtype="Number" placeholder="0"
|
||||||
value="{{numberFormat data.attributes.init.value decimals=0 sign=true}}"/>
|
value="{{numberFormat data.attributes.init.value decimals=0 sign=true}}"/>
|
||||||
</footer>
|
</footer>
|
||||||
</li>
|
</li>
|
||||||
|
@ -108,17 +108,17 @@
|
||||||
</section>
|
</section>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{{!-- NPC Sheet Navigation --}}
|
{{!-- Character Sheet Navigation --}}
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="attributes">{{ localize "SW5E.Attributes" }}</a>
|
<a class="item active" data-tab="attributes">{{ localize "SW5E.Attributes" }}</a>
|
||||||
<a class="item" data-tab="inventory">{{ localize "SW5E.Inventory" }}</a>
|
<a class="item" data-tab="inventory">{{ localize "SW5E.Inventory" }}</a>
|
||||||
<a class="item" data-tab="features">{{ localize "SW5E.Features" }}</a>
|
<a class="item" data-tab="features">{{ localize "SW5E.Features" }}</a>
|
||||||
<a class="item" data-tab="powerbook">{{ localize "SW5E.Powerbook" }}</a>
|
<a class="item" data-tab="powerbook">{{ localize "SW5E.Powerbook" }}</a>
|
||||||
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<a class="item" data-tab="biography">{{ localize "SW5E.Biography" }}</a>
|
<a class="item" data-tab="biography">{{ localize "SW5E.Biography" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- NPC Sheet Body --}}
|
{{!-- Character Sheet Body --}}
|
||||||
<section class="sheet-body">
|
<section class="sheet-body">
|
||||||
|
|
||||||
<div class="tab attributes flexrow" data-group="primary" data-tab="attributes">
|
<div class="tab attributes flexrow" data-group="primary" data-tab="attributes">
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
{{!-- Counters --}}
|
{{!-- Counters --}}
|
||||||
<div class="counters">
|
<div class="counters">
|
||||||
<div class="counter flexrow death-saves">
|
<div class="counter flexrow death-saves">
|
||||||
<h4 class="death-save rollable">{{ localize "SW5E.DeathSave" }}</h4>
|
<h4 class="rollable" data-action="rollDeathSave">{{ localize "SW5E.DeathSave" }}</h4>
|
||||||
<div class="counter-value">
|
<div class="counter-value">
|
||||||
<i class="fas fa-check"></i>
|
<i class="fas fa-check"></i>
|
||||||
<input name="data.attributes.death.success" type="number" placeholder="0"
|
<input name="data.attributes.death.success" type="number" placeholder="0"
|
||||||
|
@ -228,12 +228,12 @@
|
||||||
<div class="tab powerbook flexcol" data-group="primary" data-tab="powerbook">
|
<div class="tab powerbook flexcol" data-group="primary" data-tab="powerbook">
|
||||||
{{> "systems/sw5e/templates/actors/oldActor/parts/actor-powerbook.html"}}
|
{{> "systems/sw5e/templates/actors/oldActor/parts/actor-powerbook.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Effects Tab --}}
|
{{!-- Effects Tab --}}
|
||||||
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
{{> "systems/sw5e/templates/actors/oldActor/parts/actor-effects.html"}}
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Biography Tab --}}
|
{{!-- Biography Tab --}}
|
||||||
<div class="tab flexrow" data-group="primary" data-tab="biography">
|
<div class="tab flexrow" data-group="primary" data-tab="biography">
|
||||||
<div class="characteristics flexcol">
|
<div class="characteristics flexcol">
|
||||||
|
|
|
@ -62,14 +62,14 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="attribute">
|
<li class="attribute">
|
||||||
<h4 class="attribute-name box-title">{{ localize "SW5E.Speed" }}</h4>
|
<h4 class="attribute-name box-title">
|
||||||
|
{{ localize "SW5E.Speed" }}
|
||||||
|
</h4>
|
||||||
<div class="attribute-value">
|
<div class="attribute-value">
|
||||||
<input name="data.attributes.speed.value" type="text"
|
<span>{{movement.primary}}</span>
|
||||||
value="{{data.attributes.speed.value}}" placeholder="0"/>
|
|
||||||
</div>
|
</div>
|
||||||
<footer class="attribute-footer">
|
<footer class="attribute-footer">
|
||||||
<input type="text" class="speed" name="data.attributes.speed.special"
|
<span>{{movement.special}}</span>
|
||||||
value="{{data.attributes.speed.special}}" placeholder="{{ localize 'SW5E.SpeedSpecial' }}"/>
|
|
||||||
</footer>
|
</footer>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -81,6 +81,7 @@
|
||||||
<a class="item active" data-tab="attributes">{{ localize "SW5E.Attributes" }}</a>
|
<a class="item active" data-tab="attributes">{{ localize "SW5E.Attributes" }}</a>
|
||||||
<a class="item" data-tab="features">{{ localize "SW5E.Features" }}</a>
|
<a class="item" data-tab="features">{{ localize "SW5E.Features" }}</a>
|
||||||
<a class="item" data-tab="powerbook">{{ localize "SW5E.Powerbook" }}</a>
|
<a class="item" data-tab="powerbook">{{ localize "SW5E.Powerbook" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<a class="item" data-tab="biography">{{ localize "SW5E.Biography" }}</a>
|
<a class="item" data-tab="biography">{{ localize "SW5E.Biography" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -143,24 +144,29 @@
|
||||||
<div class="counter-value">
|
<div class="counter-value">
|
||||||
<input name="data.resources.lair.value" type="checkbox" value="{{data.resources.lair.value}}"
|
<input name="data.resources.lair.value" type="checkbox" value="{{data.resources.lair.value}}"
|
||||||
data-dtype="Boolean" {{checked data.resources.lair.value}}/>
|
data-dtype="Boolean" {{checked data.resources.lair.value}}/>
|
||||||
<input name="data.resources.lair.initiative" type="number" value="{{data.resources.lair.initiative}}" placeholder="20"/>
|
<input name="data.resources.lair.initiative" type="number" value="{{data.resources.lair.initiative}}" placeholder="20"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Traits --}}
|
{{!-- Traits --}}
|
||||||
{{> "systems/sw5e/templates/actors/parts/actor-traits.html"}}
|
{{> "systems/sw5e/templates/actors/oldActor/parts/actor-traits.html"}}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Features Tab --}}
|
{{!-- Features Tab --}}
|
||||||
<div class="tab features flexcol" data-group="primary" data-tab="features">
|
<div class="tab features flexcol" data-group="primary" data-tab="features">
|
||||||
{{> "systems/sw5e/templates/actors/parts/actor-features.html" sections=features}}
|
{{> "systems/sw5e/templates/actors/oldActor/parts/actor-features.html" sections=features}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Powerbook Tab --}}
|
{{!-- Powerbook Tab --}}
|
||||||
<div class="tab powerbook flexcol" data-group="primary" data-tab="powerbook">
|
<div class="tab powerbook flexcol" data-group="primary" data-tab="powerbook">
|
||||||
{{> "systems/sw5e/templates/actors/parts/actor-powerbook.html"}}
|
{{> "systems/sw5e/templates/actors/oldActor/parts/actor-powerbook.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Biography Tab --}}
|
{{!-- Biography Tab --}}
|
||||||
|
@ -168,4 +174,4 @@
|
||||||
{{editor content=data.details.biography.value target="data.details.biography.value" button=true owner=owner editable=editable}}
|
{{editor content=data.details.biography.value target="data.details.biography.value" button=true owner=owner editable=editable}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<ol class="inventory-list">
|
|
||||||
{{#each effects as |section sid|}}
|
|
||||||
<li class="inventory-header flexrow">
|
|
||||||
<h3 class="effect-name flexrow">{{localize section.label}}</h3>
|
|
||||||
<div class="effect-source">Source</div>
|
|
||||||
<div class="effect-source">Duration</div>
|
|
||||||
<div class="effect-controls"></div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<ol class="effects-list item-list">
|
|
||||||
{{#each section.effects as |effect|}}
|
|
||||||
<li class="effect flexrow" data-effect-id="{{effect.id}}">
|
|
||||||
<div class="effect-name flexrow">
|
|
||||||
<img class="effect-icon" src="{{effect.data.icon}}"/>
|
|
||||||
<h4>{{effect.data.label}}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="effect-source">{{effect.sourceName}}</div>
|
|
||||||
<div class="effect-duration">{{effect.duration.label}}</div>
|
|
||||||
<div class="effect-controls">
|
|
||||||
<a class="effect-control" data-action="toggle"><i class="fas fa-circle-notch"></i></a>
|
|
||||||
<a class="effect-control" data-action="edit"><i class="fas fa-edit"></i></a>
|
|
||||||
<a class="effect-control" data-action="delete"><i class="fas fa-trash"></i></a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ol>
|
|
||||||
{{/each}}
|
|
||||||
</ol>
|
|
|
@ -8,9 +8,9 @@
|
||||||
</div>
|
</div>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
<ol class="inventory-list">
|
<ol class="items-list inventory-list">
|
||||||
{{#each sections as |section sid|}}
|
{{#each sections as |section sid|}}
|
||||||
<li class="inventory-header flexrow">
|
<li class="items-header flexrow">
|
||||||
<h3 class="item-name flexrow">{{localize section.label}}</h3>
|
<h3 class="item-name flexrow">{{localize section.label}}</h3>
|
||||||
|
|
||||||
{{#if section.hasActions}}
|
{{#if section.hasActions}}
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if ../owner}}
|
{{#if ../owner}}
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
<a class="item-control item-create" title="{{localize 'SW5E.FeatureAdd'}}" {{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}>
|
<a class="item-control item-create" title="{{localize 'SW5E.FeatureAdd'}}" {{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}>
|
||||||
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
||||||
</a>
|
</a>
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
<div class="item-detail player-classfeatures">
|
<div class="item-detail player-classfeatures">
|
||||||
{{item.data.name}}
|
{{item.data.name}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{else if section.isFightingstyles}}
|
{{else if section.isFightingstyles}}
|
||||||
<div class="item-detail player-fightingstyles">
|
<div class="item-detail player-fightingstyles">
|
||||||
{{item.data.name}}
|
{{item.data.name}}
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if ../../owner}}
|
{{#if ../../owner}}
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
{{#if section.crewable}}
|
{{#if section.crewable}}
|
||||||
<a class="item-control item-toggle {{item.toggleClass}}"
|
<a class="item-control item-toggle {{item.toggleClass}}"
|
||||||
title="{{item.toggleTitle}}">
|
title="{{item.toggleTitle}}">
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<ol class="currency flexrow">
|
<ol class="currency flexrow">
|
||||||
<h3>
|
<h3>
|
||||||
{{localize "SW5E.Currency"}}
|
{{localize "SW5E.Currency"}}
|
||||||
<a class="currency-convert" title="Convert Currency"><i class="fas fa-coins"></i></a>
|
|
||||||
</h3>
|
</h3>
|
||||||
{{#each data.currency as |v k|}}
|
{{#each data.currency as |v k|}}
|
||||||
<label class="denomination {{k}}">{{ lookup ../config.currencies k }}</label>
|
<label class="denomination {{k}}">{{ lookup ../config.currencies k }}</label>
|
||||||
|
@ -23,9 +22,9 @@
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ol class="inventory-list">
|
<ol class="items-list inventory-list">
|
||||||
{{#each sections as |section sid|}}
|
{{#each sections as |section sid|}}
|
||||||
<li class="inventory-header flexrow">
|
<li class="items-header flexrow">
|
||||||
<h3 class="item-name flexrow">{{localize section.label}}</h3>
|
<h3 class="item-name flexrow">{{localize section.label}}</h3>
|
||||||
|
|
||||||
{{#if section.columns}}
|
{{#if section.columns}}
|
||||||
|
@ -33,18 +32,18 @@
|
||||||
<div class="item-detail {{css}}">{{label}}</div>
|
<div class="item-detail {{css}}">{{label}}</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if ../isCharacter}}
|
{{#if ../isCharacter}}
|
||||||
<div class="item-detail item-weight">{{localize "SW5E.Weight"}}</div>
|
<div class="item-detail item-weight">{{localize "SW5E.Weight"}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<div class="item-detail item-uses">{{localize "SW5E.Charges"}}</div>
|
<div class="item-detail item-uses">{{localize "SW5E.Charges"}}</div>
|
||||||
<div class="item-detail item-action">{{localize "SW5E.Usage"}}</div>
|
<div class="item-detail item-action">{{localize "SW5E.Usage"}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if ../owner}}
|
{{#if ../owner}}
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
<a class="item-control item-create" title='{{localize "SW5E.ItemCreate"}}'
|
<a class="item-control item-create" title='{{localize "SW5E.ItemCreate"}}'
|
||||||
{{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}>
|
{{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}>
|
||||||
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,13 +52,13 @@
|
||||||
|
|
||||||
<ol class="item-list">
|
<ol class="item-list">
|
||||||
{{#each section.items as |item iid|}}
|
{{#each section.items as |item iid|}}
|
||||||
<li class="item flexrow {{section.css}}"
|
<li class="item flexrow {{section.css}}"
|
||||||
data-item-id="{{#if section.editableName}}{{iid}}{{else}}{{item._id}}{{/if}}">
|
data-item-id="{{#if section.editableName}}{{iid}}{{else}}{{item._id}}{{/if}}">
|
||||||
<div class="item-name flexrow rollable">
|
<div class="item-name flexrow rollable">
|
||||||
{{#if section.editableName}}
|
{{#if section.editableName}}
|
||||||
<input type="text" value="{{item.name}}">
|
<input type="text" value="{{item.name}}">
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="item-image" style="background-image: url('{{item.img}}')"></div>
|
<div class="item-image" style="background-image: url('{{item.img}}')"></div>
|
||||||
<h4>
|
<h4>
|
||||||
{{item.name~}}
|
{{item.name~}}
|
||||||
{{~#if item.isStack}} ({{item.data.quantity}}){{/if}}
|
{{~#if item.isStack}} ({{item.data.quantity}}){{/if}}
|
||||||
|
@ -82,32 +81,32 @@
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if ../../isCharacter}}
|
{{#if ../../isCharacter}}
|
||||||
<div class="item-detail item-weight">
|
<div class="item-detail item-weight">
|
||||||
{{#if item.totalWeight}}
|
{{#if item.totalWeight}}
|
||||||
<div class="item-detail">
|
<div class="item-detail">
|
||||||
{{ item.totalWeight }} {{localize "SW5E.AbbreviationLbs"}}
|
{{ item.totalWeight }} {{localize "SW5E.AbbreviationLbs"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="item-detail item-uses">
|
||||||
|
{{#if item.hasUses }}
|
||||||
|
<input type="text" value="{{item.data.uses.value}}" placeholder="0"/>
|
||||||
|
/ {{item.data.uses.max}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="item-detail item-uses">
|
<div class="item-detail item-action">
|
||||||
{{#if item.hasUses }}
|
{{#if item.data.activation.type }}
|
||||||
<input type="text" value="{{item.data.uses.value}}" placeholder="0"/>
|
{{item.labels.activation}}
|
||||||
/ {{item.data.uses.max}}
|
{{/if}}
|
||||||
{{/if}}
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-detail item-action">
|
|
||||||
{{#if item.data.activation.type }}
|
|
||||||
{{item.labels.activation}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if ../../owner}}
|
{{#if ../../owner}}
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
{{#unless @root.isVehicle}}
|
{{#unless @root.isVehicle}}
|
||||||
<a class="item-control item-toggle {{item.toggleClass}}" title='{{item.toggleTitle}}'><i class="fas fa-shield-alt"></i></a>
|
<a class="item-control item-toggle {{item.toggleClass}}" title='{{item.toggleTitle}}'><i class="fas fa-shield-alt"></i></a>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
|
@ -27,12 +27,10 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ol class="inventory-list">
|
<ol class="items-list inventory-list">
|
||||||
{{#each powerbook as |section|}}
|
{{#each powerbook as |section|}}
|
||||||
<li class="item flexrow inventory-header powerbook-header">
|
<li class="items-header powerbook-header flexrow">
|
||||||
<div class="item-name flexrow">
|
<h3 class="item-name flexrow">{{section.label}}</h3>
|
||||||
<h3>{{section.label}}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="power-slots">
|
<div class="power-slots">
|
||||||
{{#if section.usesSlots}}
|
{{#if section.usesSlots}}
|
||||||
|
@ -46,6 +44,7 @@
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</span>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<span>{{{section.uses}}}</span>
|
<span>{{{section.uses}}}</span>
|
||||||
<span class="sep"> / </span>
|
<span class="sep"> / </span>
|
||||||
|
@ -57,7 +56,7 @@
|
||||||
<div class="power-action">{{localize "SW5E.PowerUsage"}}</div>
|
<div class="power-action">{{localize "SW5E.PowerUsage"}}</div>
|
||||||
<div class="power-target">{{localize "SW5E.PowerTarget"}}</div>
|
<div class="power-target">{{localize "SW5E.PowerTarget"}}</div>
|
||||||
|
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
{{#if section.canCreate}}
|
{{#if section.canCreate}}
|
||||||
<a class="item-control item-create" title="{{localize 'SW5E.PowerCreate'}}" {{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}>
|
<a class="item-control item-create" title="{{localize 'SW5E.PowerCreate'}}" {{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}>
|
||||||
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
||||||
|
@ -91,9 +90,8 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{{#if ../../owner}}
|
{{#if ../../owner}}
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
{{#if section.canPrepare}}
|
{{#if section.canPrepare}}
|
||||||
<a class="item-control item-toggle {{item.toggleClass}}" title="{{item.toggleTitle}}"><i class="fas fa-sun"></i></a>
|
<a class="item-control item-toggle {{item.toggleClass}}" title="{{item.toggleTitle}}"><i class="fas fa-sun"></i></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -110,7 +108,7 @@
|
||||||
<li class="item flexrow"><p class="notes">{{localize "SW5E.FilterNoPowers"}}</p></li>
|
<li class="item flexrow"><p class="notes">{{localize "SW5E.FilterNoPowers"}}</p></li>
|
||||||
{{else}}
|
{{else}}
|
||||||
<li class="item flexrow inventory-header powerbook-header powerbook-empty">
|
<li class="item flexrow inventory-header powerbook-header powerbook-empty">
|
||||||
<div class="item-controls">
|
<div class="item-controls flexrow">
|
||||||
<a class="item-control item-create" title="{{localize 'SW5E.PowerCreate'}}" data-type="power"
|
<a class="item-control item-create" title="{{localize 'SW5E.PowerCreate'}}" data-type="power"
|
||||||
data-level="{{lvl}}"><i class="fas fa-plus"></i> {{localize "SW5E.PowerAdd"}}</a>
|
data-level="{{lvl}}"><i class="fas fa-plus"></i> {{localize "SW5E.PowerAdd"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#unless isVehicle}}
|
{{#unless isVehicle}}
|
||||||
|
<div class="form-group ">
|
||||||
|
<label>{{localize "SW5E.MovementConfig"}}</label>
|
||||||
|
<a class="configure-movement" title="{{localize 'SW5E.MovementConfig'}}"><i class="fas fa-cog"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group {{#unless data.traits.senses}}inactive{{/unless}}">
|
<div class="form-group {{#unless data.traits.senses}}inactive{{/unless}}">
|
||||||
<label>{{localize "SW5E.Senses"}}</label>
|
<label>{{localize "SW5E.Senses"}}</label>
|
||||||
<input type="text" name="data.traits.senses" value="{{data.traits.senses}}" placeholder="{{ localize 'SW5E.None' }}"/>
|
<input type="text" name="data.traits.senses" value="{{data.traits.senses}}" placeholder="{{ localize 'SW5E.None' }}"/>
|
||||||
|
|
|
@ -58,8 +58,7 @@
|
||||||
<li class="attribute">
|
<li class="attribute">
|
||||||
<h4 class="attribute-name box-title">{{localize 'SW5E.Speed'}}</h4>
|
<h4 class="attribute-name box-title">{{localize 'SW5E.Speed'}}</h4>
|
||||||
<div class="attribute-value">
|
<div class="attribute-value">
|
||||||
<input name="data.attributes.speed.value" type="text" placeholder="—"
|
<input name="data.attributes.speed" type="text" placeholder="—" value="{{data.attributes.speed}}"/>
|
||||||
value="{{data.attributes.speed.value}}">
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -139,16 +138,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{> 'systems/sw5e/templates/actors/parts/actor-traits.html'}}
|
{{> 'systems/sw5e/templates/actors/oldActor/parts/actor-traits.html'}}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab features flexcol" data-group="primary" data-tab="features">
|
<div class="tab features flexcol" data-group="primary" data-tab="features">
|
||||||
{{> 'systems/sw5e/templates/actors/parts/actor-features.html' sections=features}}
|
{{> 'systems/sw5e/templates/actors/oldActor/parts/actor-features.html' sections=features}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab cargo flexcol" data-group="primary" data-tab="cargo">
|
<div class="tab cargo flexcol" data-group="primary" data-tab="cargo">
|
||||||
{{> 'systems/sw5e/templates/actors/parts/actor-inventory.html' sections=cargo}}
|
{{> 'systems/sw5e/templates/actors/oldActor/parts/actor-inventory.html' sections=cargo}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab biography flexcol" data-group="primary" data-tab="biography">
|
<div class="tab biography flexcol" data-group="primary" data-tab="biography">
|
||||||
|
|
38
templates/actors/parts/active-effects.html
Normal file
38
templates/actors/parts/active-effects.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<ol class="items-list effects-list">
|
||||||
|
{{#each effects as |section sid|}}
|
||||||
|
<li class="items-header flexrow" data-effect-type="{{section.type}}">
|
||||||
|
<h3 class="item-name effect-name flexrow">{{localize section.label}}</h3>
|
||||||
|
<div class="effect-source">Source</div>
|
||||||
|
<div class="effect-source">Duration</div>
|
||||||
|
<div class="item-controls effect-controls flexrow">
|
||||||
|
<a class="effect-control" data-action="create" title="{{localize 'SW5E.EffectCreate'}}">
|
||||||
|
<i class="fas fa-plus"></i> {{localize "SW5E.Add"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<ol class="item-list">
|
||||||
|
{{#each section.effects as |effect|}}
|
||||||
|
<li class="item effect flexrow" data-effect-id="{{effect.id}}">
|
||||||
|
<div class="item-name effect-name flexrow">
|
||||||
|
<img class="item-image" src="{{effect.data.icon}}"/>
|
||||||
|
<h4>{{effect.data.label}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="effect-source">{{effect.sourceName}}</div>
|
||||||
|
<div class="effect-duration">{{effect.duration.label}}</div>
|
||||||
|
<div class="item-controls effect-controls flexrow">
|
||||||
|
<a class="effect-control" data-action="toggle" title="{{localize 'SW5E.EffectToggle'}}">
|
||||||
|
<i class="fas fa-circle-notch"></i>
|
||||||
|
</a>
|
||||||
|
<a class="effect-control" data-action="edit" title="{{localize 'SW5E.EffectEdit'}}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a class="effect-control" data-action="delete" title="{{localize 'SW5E.EffectDelete'}}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
|
@ -1,44 +1,48 @@
|
||||||
<form class="{{cssClass}}" autocomplete="off">
|
<form class="{{cssClass}}" autocomplete="off">
|
||||||
<p class="notes">{{localize 'SW5E.FlagsInstructions'}}</p>
|
<section class="form-body">
|
||||||
|
<p class="notes">{{localize 'SW5E.FlagsInstructions'}}</p>
|
||||||
|
|
||||||
{{#each flags as |fs section|}}
|
{{#each flags as |fs section|}}
|
||||||
<h3 class="form-header">{{localize section}}</h3>
|
<h3 class="form-header">{{localize section}}</h3>
|
||||||
{{#each fs as |flag key|}}
|
{{#each fs as |flag key|}}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{localize flag.name}}</label>
|
<label>{{localize flag.name}}</label>
|
||||||
|
|
||||||
{{#if flag.isCheckbox}}
|
{{#if flag.isCheckbox}}
|
||||||
<input type="checkbox" name="{{key}}" data-dtype="Boolean" {{checked flag.value}}/>
|
<input type="checkbox" name="{{key}}" data-dtype="Boolean" {{checked flag.value}}/>
|
||||||
|
|
||||||
{{else if flag.isSelect}}
|
{{else if flag.isSelect}}
|
||||||
<select name="{{key}}" data-dtype="{{flag.type}}">
|
<select name="{{key}}" data-dtype="{{flag.type}}">
|
||||||
{{#select flag.value}}
|
{{#select flag.value}}
|
||||||
{{#each flag.choices as |v k|}}
|
{{#each flag.choices as |v k|}}
|
||||||
<option value="{{k}}">{{localize v}}</option>
|
<option value="{{k}}">{{localize v}}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/select}}
|
{{/select}}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<input type="text" name="{{key}}" value="{{flag.value}}" placeholder="{{flag.placeholder}}" data-dtype="{{flag.type}}"/>
|
<input type="text" name="{{key}}" value="{{flag.value}}" placeholder="{{flag.placeholder}}" data-dtype="{{flag.type}}"/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<p class="notes">{{localize flag.hint}}</p>
|
<p class="notes">{{localize flag.hint}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
<h3 class="form-header">{{localize "SW5E.Bonuses"}}</h3>
|
<h3 class="form-header">{{localize "SW5E.Bonuses"}}</h3>
|
||||||
<p class="notes">{{localize "SW5E.BonusesHint"}}</p>
|
<p class="notes">{{localize "SW5E.BonusesHint"}}</p>
|
||||||
{{#each bonuses as |b|}}
|
{{#each bonuses as |b|}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{localize b.label}}</label>
|
<label>{{localize b.label}}</label>
|
||||||
<input type="text" name="{{b.name}}" value="{{b.value}}"/>
|
<input type="text" name="{{b.name}}" value="{{b.value}}"/>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
</section>
|
||||||
|
|
||||||
<button type="submit" name="submit">
|
<footer class="form-footer">
|
||||||
<i class="far fa-save"></i> {{localize 'SW5E.FlagsSave'}}
|
<button type="submit" name="submit">
|
||||||
</button>
|
<i class="far fa-save"></i> {{localize 'SW5E.FlagsSave'}}
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
<form id="cast-config-form">
|
|
||||||
<p>{{ localize "SW5E.SpellCastHint" }} <strong>{{item.name}}</strong> {{ localize "SW5E.cast" }}.</p>
|
|
||||||
|
|
||||||
{{#unless canCast}}
|
|
||||||
<p class="notification error">{{ localize "SW5E.SpellCastNoSlots" }}</p>
|
|
||||||
{{/unless}}
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label>{{ localize "SW5E.SpellCastUpcast" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<select name="level">
|
|
||||||
{{#select item.data.level}}
|
|
||||||
{{#each castLevels as |l|}}
|
|
||||||
<option value="{{l.level}}" {{#unless l.canCast}}disabled{{/unless}}>{{l.label}}</option>
|
|
||||||
{{/each}}
|
|
||||||
{{/select}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
{{#if canUpcast}}
|
|
||||||
<label class="checkbox">{{ localize "SW5E.SpellCastConsume" }} <input type="checkbox" name="consume" {{checked canCast}}/></label>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if hasPlaceableTemplate}}
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="checkbox">{{ localize "SW5E.PlaceTemplate" }}
|
|
||||||
<input type="checkbox" name="placeTemplate" checked/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
34
templates/apps/movement-config.html
Normal file
34
templates/apps/movement-config.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<form autocomplete="off">
|
||||||
|
<p class="notes">{{localize "SW5E.MovementConfigHint"}}</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementWalk"}}</label>
|
||||||
|
<input name="data.attributes.movement.walk" type="number" step="0.1" value="{{movement.walk}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementBurrow"}}</label>
|
||||||
|
<input name="data.attributes.movement.burrow" type="number" step="0.1" value="{{movement.burrow}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementClimb"}}</label>
|
||||||
|
<input name="data.attributes.movement.climb" type="number" step="0.1" value="{{movement.climb}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementFly"}}</label>
|
||||||
|
<input name="data.attributes.movement.fly" type="number" step="0.1" value="{{movement.fly}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementSwim"}}</label>
|
||||||
|
<input name="data.attributes.movement.swim" type="number" step="0.1" value="{{movement.swim}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementUnits"}}</label>
|
||||||
|
<select name="data.attributes.movement.units">
|
||||||
|
{{selectOptions units selected=movement.units}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SW5E.MovementHover"}}</label>
|
||||||
|
<input name="data.attributes.movement.hover" type="checkbox" {{checked movement.hover}}/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="submit" value="1"><i class="far fa-save"></i> {{ localize "Submit"}}</button>
|
||||||
|
</form>
|
|
@ -15,5 +15,5 @@
|
||||||
<input type="text" name="custom" value="{{custom}}" data-dtype="String"/>
|
<input type="text" name="custom" value="{{custom}}" data-dtype="String"/>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<button type="submit" name="submit" value="1"><i class="far fa-save"></i> {{ localize "SW5E.Save"}}</button>
|
<button type="submit" name="submit" value="1"><i class="far fa-save"></i> {{ localize "SW5E.TraitSave"}}</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="sw5e chat-card item-card" data-actor-id="{{actor._id}}" data-item-id="{{item._id}}" {{#if tokenId}}data-token-id="{{tokenId}}"{{/if}}>
|
<div class="sw5e chat-card item-card" data-actor-id="{{actor._id}}" data-item-id="{{item._id}}" {{#if tokenId}}data-token-id="{{tokenId}}"{{/if}}>
|
||||||
<header class="card-header flexrow">
|
<header class="card-header flexrow">
|
||||||
<img src="{{item.img}}" title="{{item.name}}" width="36" height="36"/>
|
<img src="{{item.img}}" title="{{item.name}}" width="36" height="36"/>
|
||||||
<h3>{{item.name}}</h3>
|
<h3 class="item-name">{{item.name}}</h3>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="card-content">{{{data.description.value}}}</div>
|
<div class="card-content">{{{data.description.value}}}</div>
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
{{!-- Item Sheet Navigation --}}
|
{{!-- Item Sheet Navigation --}}
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -39,7 +40,13 @@
|
||||||
|
|
||||||
{{!-- Description Tab --}}
|
{{!-- Description Tab --}}
|
||||||
<div class="tab description" data-group="primary" data-tab="description">
|
<div class="tab description" data-group="primary" data-tab="description">
|
||||||
{{editor content=data.description.value target="data.description.value" button=true owner=owner editable=editable}}
|
{{editor content=data.description.value target="data.description.value" button=true owner=owner editable=editable}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{{!-- Item Sheet Navigation --}}
|
{{!-- Item Sheet Navigation --}}
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -32,68 +33,42 @@
|
||||||
|
|
||||||
{{!-- Description Tab --}}
|
{{!-- Description Tab --}}
|
||||||
<div class="tab description" data-group="primary" data-tab="description">
|
<div class="tab description" data-group="primary" data-tab="description">
|
||||||
<div class="background">{{editor content=data.flavorText.value target="data.flavorText.value" button=true editable=editable}}</div>
|
<div class="background">{{editor content=data.flavorText.value target="data.flavorText.value" button=true editable=editable}}</div>
|
||||||
<div class="background"><p><strong>Skill Proficiencies:</strong> {{{data.skillProficiencies.value}}}</p></div>
|
<div class="background"><p><strong>Skill Proficiencies:</strong> {{{data.skillProficiencies.value}}}</p></div>
|
||||||
<div class="background"><p><strong>Tool Proficiencies:</strong> {{{data.toolProficiencies.value}}}</p></div>
|
<div class="background"><p><strong>Tool Proficiencies:</strong> {{{data.toolProficiencies.value}}}</p></div>
|
||||||
<div class="background"><p><strong>Languages:</strong> {{{data.languages.value}}}</p></div>
|
<div class="background"><p><strong>Languages:</strong> {{{data.languages.value}}}</p></div>
|
||||||
<div class="background"><p><strong>Equipment:</strong> {{{data.equipment.value}}}</p></div>
|
<div class="background"><p><strong>Equipment:</strong> {{{data.equipment.value}}}</p></div>
|
||||||
<div class="background"><h3>{{{data.flavorName.value}}}</h3></div>
|
<div class="background"><h3>{{{data.flavorName.value}}}</h3></div>
|
||||||
<div class="background"><p>{{{data.flavorDescription.value}}}</p></div>
|
<div class="background"><p>{{{data.flavorDescription.value}}}</p></div>
|
||||||
<div class="smalltable"><p>{{{data.flavorOptions.value}}}</p></div>
|
<div class="smalltable"><p>{{{data.flavorOptions.value}}}</p></div>
|
||||||
<div class="background"><h2>Feature: {{{data.featureName.value}}}</h2></div>
|
<div class="background"><h2>Feature: {{{data.featureName.value}}}</h2></div>
|
||||||
<div class="background"><p>{{{data.featureText.value}}}</p></div>
|
<div class="background"><p>{{{data.featureText.value}}}</p></div>
|
||||||
<h2>Background Feat</h2>
|
<h2>Background Feat</h2>
|
||||||
<p>As a further embodiment of the experience and training of your background, you can choose from the following feats:</p>
|
<p>As a further embodiment of the experience and training of your background, you can choose from the following feats:</p>
|
||||||
<div class="smalltable"><p>{{{data.featOptions.value}}}</p></div>
|
<div class="smalltable"><p>{{{data.featOptions.value}}}</p></div>
|
||||||
<h3>Suggested Characteristics</h3>
|
<h3>Suggested Characteristics</h3>
|
||||||
<div class="background"><p>{{{data.suggestedCharacteristics.value}}}</p></div>
|
<div class="background"><p>{{{data.suggestedCharacteristics.value}}}</p></div>
|
||||||
<div class="medtable"><p>{{{data.personalityTraitOptions.value}}}</p></div><p> </p>
|
<div class="medtable"><p>{{{data.personalityTraitOptions.value}}}</p></div><p> </p>
|
||||||
<div class="medtable"><p>{{{data.idealOptions.value}}}</p></div><p> </p>
|
<div class="medtable"><p>{{{data.idealOptions.value}}}</p></div><p> </p>
|
||||||
<div class="medtable"><p>{{{data.flawOptions.value}}}</p></div><p> </p>
|
<div class="medtable"><p>{{{data.flawOptions.value}}}</p></div><p> </p>
|
||||||
<div class="medtable"><p>{{{data.bondOptions.value}}}</p></div>
|
<div class="medtable"><p>{{{data.bondOptions.value}}}</p></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let nullField = document.querySelectorAll('.background > div');
|
let nullField = document.querySelectorAll('.background > div');
|
||||||
|
|
||||||
nullField.forEach(function(element) {
|
nullField.forEach(function(element) {
|
||||||
|
if (element.value === null) {
|
||||||
if (element.value === null) {
|
element.previousElementSibling.style.display = 'none';
|
||||||
element.previousElementSibling.style.display = 'none';
|
element.style.display = 'none';
|
||||||
element.style.display = 'none';
|
}
|
||||||
}
|
});
|
||||||
});
|
</script>
|
||||||
</script>
|
</div>
|
||||||
</div>
|
|
||||||
<!-- {{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
{{!-- Details Tab --}}
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
<div class="tab details" data-group="primary" data-tab="details">
|
</div>
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureUsage" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Activation Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-activation.html"}}
|
|
||||||
|
|
||||||
{{!-- Recharge Requirement --}}
|
|
||||||
{{#if data.activation.type}}
|
|
||||||
<div class="form-group recharge">
|
|
||||||
<label>{{ localize "SW5E.FeatureActionRecharge" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<span>{{ localize "SW5E.FeatureRechargeOn" }}</span>
|
|
||||||
<input type="text" name="data.recharge.value" value="{{data.recharge.value}}"
|
|
||||||
data-dtype="Number" placeholder="{{ localize 'SW5E.FeatureRechargeResult' }}"/>
|
|
||||||
<label class="checkbox">
|
|
||||||
{{ localize "SW5E.Charged" }}
|
|
||||||
<input type="checkbox" name="data.recharge.charged" {{checked data.recharge.charged}}/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureAttack" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Action Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
|
||||||
</div> -->
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
<form class="{{cssClass}} flexcol" autocomplete="off">
|
|
||||||
|
|
||||||
{{!-- Item Sheet Header --}}
|
|
||||||
<header class="sheet-header flexrow">
|
|
||||||
<img class="profile" src="{{item.img}}" title="{{item.name}}" data-edit="img"/>
|
|
||||||
|
|
||||||
<div class="header-details flexrow">
|
|
||||||
<h1 class="charname">
|
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'SW5E.CastName' }}"/>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div class="item-subtitle">
|
|
||||||
<h4 class="item-type">{{itemType}}</h4>
|
|
||||||
<span class="item-status">{{itemStatus}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="summary">
|
|
||||||
<li>
|
|
||||||
{{labels.level}}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
{{labels.school}}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input type="text" name="data.source" value="{{data.source}}" placeholder="{{ localize 'SW5E.Source' }}"/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{{!-- Item Sheet Navigation --}}
|
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
|
||||||
<section class="sheet-body">
|
|
||||||
|
|
||||||
{{!-- Description Tab --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
|
||||||
|
|
||||||
{{!-- Details Tab --}}
|
|
||||||
<div class="tab details" data-group="primary" data-tab="details">
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.CastDetails" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Cast Level --}}
|
|
||||||
<div class="form-group">
|
|
||||||
<label>{{ localize "SW5E.CastLevel" }}</label>
|
|
||||||
<select name="data.level" data-dtype="Number">
|
|
||||||
{{#select data.level}}
|
|
||||||
{{#each config.castLevels as |name lvl|}}
|
|
||||||
<option value="{{lvl}}">{{name}}</option>
|
|
||||||
{{/each}}
|
|
||||||
{{/select}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{!-- Cast School --}}
|
|
||||||
<div class="form-group">
|
|
||||||
<label>{{ localize "SW5E.CastSchool" }}</label>
|
|
||||||
<select name="data.school">
|
|
||||||
{{#select data.school}}
|
|
||||||
{{#each config.castSchools as |name sch|}}
|
|
||||||
<option value="{{sch}}">{{name}}</option>
|
|
||||||
{{/each}}
|
|
||||||
{{/select}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{!-- Cast Components --}}
|
|
||||||
<div class="cast-components form-group stacked">
|
|
||||||
<label>{{ localize "SW5E.CastComponents" }}</label>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" name="data.components.vocal" {{checked data.components.vocal}}/> {{ localize "SW5E.ComponentVerbal" }}
|
|
||||||
</label>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" name="data.components.somatic" {{checked data.components.somatic}}/> {{ localize "SW5E.ComponentSomatic" }}
|
|
||||||
</label>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" name="data.components.material" {{checked data.components.material}}/> {{ localize "SW5E.ComponentMaterial" }}
|
|
||||||
</label>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" name="data.components.concentration" {{checked data.components.concentration}}/> {{ localize "SW5E.Concentration" }}
|
|
||||||
</label>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" name="data.components.ritual" {{checked data.components.ritual}}/> {{ localize "SW5E.Ritual" }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{!-- Material Components --}}
|
|
||||||
<div class="form-group stacked">
|
|
||||||
<label>{{ localize "SW5E.CastMaterials" }}</label>
|
|
||||||
<input class="materials" type="text" name="data.materials.value" value="{{data.materials.value}}"/>
|
|
||||||
{{#if data.materials.value}}
|
|
||||||
<div class="cast-materials flexrow">
|
|
||||||
<label>{{ localize "SW5E.Supply" }}</label>
|
|
||||||
<input type="text" name="data.materials.supply" value="{{data.materials.supply}}" data-dtype="Number" Placeholder="0"/>
|
|
||||||
<label>{{ localize "SW5E.CostGP" }}</label>
|
|
||||||
<input type="text" name="data.materials.cost" value="{{data.materials.cost}}" data-dtype="Number" Placeholder="-"/>
|
|
||||||
<label>{{ localize "SW5E.Consumed" }}</label>
|
|
||||||
<input type="checkbox" name="data.materials.consumed" {{checked data.materials.consumed}}/>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{!-- Preparation Mode --}}
|
|
||||||
<div class="form-group input-select">
|
|
||||||
<label>{{ localize "SW5E.CastPreparationMode" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<label class="checkbox prepared">
|
|
||||||
{{ localize "SW5E.CastPrepared" }} <input type="checkbox" name="data.preparation.prepared" {{checked data.preparation.prepared}}/>
|
|
||||||
</label>
|
|
||||||
<select name="data.preparation.mode">
|
|
||||||
{{#select data.preparation.mode}}
|
|
||||||
<option value=""></option>
|
|
||||||
{{#each config.castPreparationModes as |name key|}}
|
|
||||||
<option value="{{key}}">{{name}}</option>
|
|
||||||
{{/each}}
|
|
||||||
{{/select}}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.CastingHeader" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Activation Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-activation.html"}}
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.CastEffects" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Action Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
|
||||||
|
|
||||||
{{!-- Cast Level Scaling --}}
|
|
||||||
<div class="form-group">
|
|
||||||
<label>{{ localize "SW5E.LevelScaling" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<select name="data.scaling.mode">
|
|
||||||
{{#select data.scaling.mode}}
|
|
||||||
{{#each config.castScalingModes as |name key|}}
|
|
||||||
<option value="{{key}}">{{name}}</option>
|
|
||||||
{{/each}}
|
|
||||||
{{/select}}
|
|
||||||
</select>
|
|
||||||
<input type="text" name="data.scaling.formula" value="{{data.scaling.formula}}" placeholder="{{ localize 'SW5E.ScalingFormula' }}"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
|
@ -32,6 +32,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -69,5 +70,11 @@
|
||||||
{{!-- Item Action Template --}}
|
{{!-- Item Action Template --}}
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -86,5 +87,10 @@
|
||||||
{{!-- Item Action Template --}}
|
{{!-- Item Action Template --}}
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -142,5 +143,10 @@
|
||||||
{{!-- Item Action Template --}}
|
{{!-- Item Action Template --}}
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -69,5 +70,11 @@
|
||||||
{{!-- Item Action Template --}}
|
{{!-- Item Action Template --}}
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{{!-- Item Sheet Navigation --}}
|
{{!-- Item Sheet Navigation --}}
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -36,36 +37,11 @@
|
||||||
{{editor content=data.description.value target="data.description.value" button=true editable=editable}}
|
{{editor content=data.description.value target="data.description.value" button=true editable=editable}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- {{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{!-- Details Tab --}}
|
|
||||||
<div class="tab details" data-group="primary" data-tab="details">
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureUsage" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Activation Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-activation.html"}}
|
|
||||||
|
|
||||||
{{!-- Recharge Requirement --}}
|
|
||||||
{{#if data.activation.type}}
|
|
||||||
<div class="form-group recharge">
|
|
||||||
<label>{{ localize "SW5E.FeatureActionRecharge" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<span>{{ localize "SW5E.FeatureRechargeOn" }}</span>
|
|
||||||
<input type="text" name="data.recharge.value" value="{{data.recharge.value}}"
|
|
||||||
data-dtype="Number" placeholder="{{ localize 'SW5E.FeatureRechargeResult' }}"/>
|
|
||||||
<label class="checkbox">
|
|
||||||
{{ localize "SW5E.Charged" }}
|
|
||||||
<input type="checkbox" name="data.recharge.charged" {{checked data.recharge.charged}}/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureAttack" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Action Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
|
||||||
</div> -->
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{{!-- Item Sheet Navigation --}}
|
{{!-- Item Sheet Navigation --}}
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -36,36 +37,11 @@
|
||||||
{{editor content=data.description.value target="data.description.value" button=true editable=editable}}
|
{{editor content=data.description.value target="data.description.value" button=true editable=editable}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- {{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{!-- Details Tab --}}
|
|
||||||
<div class="tab details" data-group="primary" data-tab="details">
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureUsage" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Activation Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-activation.html"}}
|
|
||||||
|
|
||||||
{{!-- Recharge Requirement --}}
|
|
||||||
{{#if data.activation.type}}
|
|
||||||
<div class="form-group recharge">
|
|
||||||
<label>{{ localize "SW5E.FeatureActionRecharge" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<span>{{ localize "SW5E.FeatureRechargeOn" }}</span>
|
|
||||||
<input type="text" name="data.recharge.value" value="{{data.recharge.value}}"
|
|
||||||
data-dtype="Number" placeholder="{{ localize 'SW5E.FeatureRechargeResult' }}"/>
|
|
||||||
<label class="checkbox">
|
|
||||||
{{ localize "SW5E.Charged" }}
|
|
||||||
<input type="checkbox" name="data.recharge.charged" {{checked data.recharge.charged}}/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureAttack" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Action Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
|
||||||
</div> -->
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{{!-- Item Sheet Navigation --}}
|
{{!-- Item Sheet Navigation --}}
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -36,36 +37,11 @@
|
||||||
{{editor content=data.description.value target="data.description.value" button=true editable=editable}}
|
{{editor content=data.description.value target="data.description.value" button=true editable=editable}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- {{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{!-- Details Tab --}}
|
|
||||||
<div class="tab details" data-group="primary" data-tab="details">
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureUsage" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Activation Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-activation.html"}}
|
|
||||||
|
|
||||||
{{!-- Recharge Requirement --}}
|
|
||||||
{{#if data.activation.type}}
|
|
||||||
<div class="form-group recharge">
|
|
||||||
<label>{{ localize "SW5E.FeatureActionRecharge" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<span>{{ localize "SW5E.FeatureRechargeOn" }}</span>
|
|
||||||
<input type="text" name="data.recharge.value" value="{{data.recharge.value}}"
|
|
||||||
data-dtype="Number" placeholder="{{ localize 'SW5E.FeatureRechargeResult' }}"/>
|
|
||||||
<label class="checkbox">
|
|
||||||
{{ localize "SW5E.Charged" }}
|
|
||||||
<input type="checkbox" name="data.recharge.charged" {{checked data.recharge.charged}}/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.FeatureAttack" }}</h3>
|
|
||||||
|
|
||||||
{{!-- Item Action Template --}}
|
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
|
||||||
</div> -->
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -25,8 +25,26 @@
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
{{!-- Item Sheet Navigation --}}
|
||||||
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
|
<!-- <a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a> -->
|
||||||
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
<section class="sheet-body">
|
<section class="sheet-body">
|
||||||
{{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
|
||||||
|
{{!-- Description Tab --}}
|
||||||
|
<div class="tab description" data-group="primary" data-tab="description">
|
||||||
|
{{> "systems/sw5e/templates/items/parts/item-description.html"}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -112,8 +112,9 @@
|
||||||
<label>{{ localize "SW5E.LimitedUses" }}</label>
|
<label>{{ localize "SW5E.LimitedUses" }}</label>
|
||||||
<div class="form-fields">
|
<div class="form-fields">
|
||||||
<input type="text" name="data.uses.value" value="{{data.uses.value}}" data-dtype="Number"/>
|
<input type="text" name="data.uses.value" value="{{data.uses.value}}" data-dtype="Number"/>
|
||||||
<span class="sep"> {{ localize "SW5E.of" }} </span>
|
<span class="sep">{{ localize "SW5E.of" }}</span>
|
||||||
<input type="text" name="data.uses.max" value="{{data.uses.max}}" data-dtype="Number"/>
|
<input type="text" name="data.uses.max" value="{{data.uses.max}}" data-dtype="Number"/>
|
||||||
|
<span class="sep">{{ localize "SW5E.per" }}</span>
|
||||||
<select name="data.uses.per">
|
<select name="data.uses.per">
|
||||||
{{#select data.uses.per}}
|
{{#select data.uses.per}}
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -68,6 +69,30 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Power Components --}}
|
||||||
|
<div class="power-components form-group stacked">
|
||||||
|
<label>{{ localize "SW5E.PowerComponents" }}</label>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" name="data.components.concentration" {{checked data.components.concentration}}/> {{ localize "SW5E.Concentration" }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Material Components --}}
|
||||||
|
<div class="form-group stacked">
|
||||||
|
<label>{{ localize "SW5E.PowerMaterials" }}</label>
|
||||||
|
<input class="materials" type="text" name="data.materials.value" value="{{data.materials.value}}"/>
|
||||||
|
{{#if data.materials.value}}
|
||||||
|
<div class="power-materials flexrow">
|
||||||
|
<label>{{ localize "SW5E.Supply" }}</label>
|
||||||
|
<input type="text" name="data.materials.supply" value="{{data.materials.supply}}" data-dtype="Number" Placeholder="0"/>
|
||||||
|
<label>{{ localize "SW5E.CostGP" }}</label>
|
||||||
|
<input type="text" name="data.materials.cost" value="{{data.materials.cost}}" data-dtype="Number" Placeholder="-"/>
|
||||||
|
<label>{{ localize "SW5E.Consumed" }}</label>
|
||||||
|
<input type="checkbox" name="data.materials.consumed" {{checked data.materials.consumed}}/>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{!-- Preparation Mode --}}
|
{{!-- Preparation Mode --}}
|
||||||
<div class="form-group input-select">
|
<div class="form-group input-select">
|
||||||
<label>{{ localize "SW5E.PowerPreparationMode" }}</label>
|
<label>{{ localize "SW5E.PowerPreparationMode" }}</label>
|
||||||
|
@ -76,24 +101,10 @@
|
||||||
{{ localize "SW5E.PowerPrepared" }} <input type="checkbox" name="data.preparation.prepared" {{checked data.preparation.prepared}}/>
|
{{ localize "SW5E.PowerPrepared" }} <input type="checkbox" name="data.preparation.prepared" {{checked data.preparation.prepared}}/>
|
||||||
</label>
|
</label>
|
||||||
<select name="data.preparation.mode">
|
<select name="data.preparation.mode">
|
||||||
{{#select data.preparation.mode}}
|
{{ selectOptions config.powerPreparationModes selected=data.preparation.mode }}
|
||||||
<option value=""></option>
|
|
||||||
{{#each config.powerPreparationModes as |name key|}}
|
|
||||||
<option value="{{key}}">{{name}}</option>
|
|
||||||
{{/each}}
|
|
||||||
{{/select}}
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{!-- Concentration Mode --}}
|
|
||||||
<div class="form-group input-select">
|
|
||||||
<label>{{ localize "SW5E.PowerConcentrationMode" }}</label>
|
|
||||||
<div class="form-fields">
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" name="data.components.concentration" {{checked data.components.concentration}}/> {{ localize "SW5E.Concentrated" }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 class="form-header">{{ localize "SW5E.PowerCastingHeader" }}</h3>
|
<h3 class="form-header">{{ localize "SW5E.PowerCastingHeader" }}</h3>
|
||||||
|
|
||||||
|
@ -120,5 +131,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">Description</a>
|
<a class="item active" data-tab="description">Description</a>
|
||||||
<a class="item" data-tab="species-traits">Species Traits</a>
|
<a class="item" data-tab="species-traits">Species Traits</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -110,8 +111,11 @@
|
||||||
{{editor content=data.traits.value target="data.traits.value" button=true editable=editable}}
|
{{editor content=data.traits.value target="data.traits.value" button=true editable=editable}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<nav class="sheet-navigation tabs" data-group="primary">
|
<nav class="sheet-navigation tabs" data-group="primary">
|
||||||
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
<a class="item active" data-tab="description">{{ localize "SW5E.Description" }}</a>
|
||||||
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
<a class="item" data-tab="details">{{ localize "SW5E.Details" }}</a>
|
||||||
|
<a class="item" data-tab="effects">{{ localize "SW5E.Effects" }}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Item Sheet Body --}}
|
{{!-- Item Sheet Body --}}
|
||||||
|
@ -110,5 +111,10 @@
|
||||||
{{!-- Item Action Template --}}
|
{{!-- Item Action Template --}}
|
||||||
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
{{> "systems/sw5e/templates/items/parts/item-action.html"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{!-- Effects Tab --}}
|
||||||
|
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
|
||||||
|
{{> "systems/sw5e/templates/actors/parts/active-effects.html"}}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue