diff --git a/lang/en.json b/lang/en.json index 177a6300..d9a0d2c2 100644 --- a/lang/en.json +++ b/lang/en.json @@ -46,6 +46,34 @@ "SW5E.AlignmentNL": "Neutral Light", "SW5E.AlignmentBN": "Balenced Neutral", "SW5E.ArmorClass": "Armor Class", +"SW5E.ArmorProperties": "Armor Properties", +"SW5E.ArmorProperAbsorptive": "Absorptive", +"SW5E.ArmorProperAgile": "Agile", +"SW5E.ArmorProperAnchor": "Anchor", +"SW5E.ArmorProperAvoidant": "Avoidant", +"SW5E.ArmorProperBarbed": "Barbed", +"SW5E.ArmorProperCharging": "Charging", +"SW5E.ArmorProperConcealing": "Concealing", +"SW5E.ArmorProperCumbersome": "Cumbersome", +"SW5E.ArmorProperGauntleted": "Gauntleted", +"SW5E.ArmorProperImbalanced": "Imbalanced", +"SW5E.ArmorProperImpermeable": "Impermeable", +"SW5E.ArmorProperInsulated": "Insulated", +"SW5E.ArmorProperInterlocking": "Interlocking", +"SW5E.ArmorProperLambent": "Lambent", +"SW5E.ArmorProperLightweight": "Lightweight", +"SW5E.ArmorProperMagnetic": "Magnetic", +"SW5E.ArmorProperObscured": "Obscured", +"SW5E.ArmorProperPowered": "Powered", +"SW5E.ArmorProperReactive": "Reactive", +"SW5E.ArmorProperRegulated": "Regulated", +"SW5E.ArmorProperReinforced": "Reinforced", +"SW5E.ArmorProperResponsive": "Responsive", +"SW5E.ArmorProperRigid": "Rigid", +"SW5E.ArmorProperSilent": "Silent", +"SW5E.ArmorProperSpiked": "Spiked", +"SW5E.ArmorProperSteadfast": "Steadfast", +"SW5E.ArmorProperVersatile": "Versatile", "SW5E.Attack": "Attack", "SW5E.Attributes": "Attributes", "SW5E.Attuned": "Attuned", @@ -512,14 +540,16 @@ "SW5E.WeaponPropertiesDef": "Defensive", "SW5E.WeaponPropertiesDex": "Dexterity Rqmt.", "SW5E.WeaponPropertiesDrm": "Disarming", - "SW5E.WeaponPropertiesDis": "Disguised", + "SW5E.WeaponPropertiesDgd": "Disguised", "SW5E.WeaponPropertiesDis": "Disintegrate", - "SW5E.WeaponPropertiesDis": "Disruptive", - "SW5E.WeaponPropertiesDbl": "Double", + "SW5E.WeaponPropertiesDpt": "Disruptive", + "SW5E.WeaponPropertiesDou": "Double", "SW5E.WeaponPropertiesFin": "Finesse", "SW5E.WeaponPropertiesFix": "Fixed", + "SW5E.WeaponPropertiesFoc": "Focus", "SW5E.WeaponPropertiesHvy": "Heavy", "SW5E.WeaponPropertiesHid": "Hidden", + "SW5E.WeaponPropertiesKen": "Keen", "SW5E.WeaponPropertiesLgt": "Light", "SW5E.WeaponPropertiesLum": "Luminous", "SW5E.WeaponPropertiesPic": "Piercing", @@ -535,7 +565,7 @@ "SW5E.WeaponPropertiesTwo": "Two-Handed", "SW5E.WeaponPropertiesVer": "Versatile", "SW5E.WeaponPropertiesVic": "Vicious", -"SW5E.WeaponSimpleVM": "Simple Vibroweapon", +"SW5E.WeaponSimpleVW": "Simple Vibroweapon", "SW5E.WeaponSimpleProficiency": "Simple Weapons", "SW5E.WeaponSimpleB": "Simple Blaster", "SW5E.WeaponSimpleLW": "Simple Lightweapon", diff --git a/less/items.less b/less/items.less index e040ddaa..bc2a3542 100644 --- a/less/items.less +++ b/less/items.less @@ -192,6 +192,76 @@ text-align: right; color: @colorTan; } + + h4.armorproperties-header { + margin: 0; + padding: 0; + font-weight: bold; + line-height: 24px; + color: @colorOlive; + } + + .armorproperties-parts { + list-style: none; + margin: 0; + padding: 0; + + .armorproperties-part { + flex: 0 0 100%; + padding: 0; + input { + flex: 3; + } + select { + margin-left: 5px; + flex: 1; + } + } + } + + .armorproperties-control { + width: 18px; + flex: 0 0 18px; + line-height: 24px; + float: right; + text-align: right; + color: @colorTan; + } + + h4.weaponproperties-header { + margin: 0; + padding: 0; + font-weight: bold; + line-height: 24px; + color: @colorOlive; + } + + .weaponproperties-parts { + list-style: none; + margin: 0; + padding: 0; + + .weaponproperties-part { + flex: 0 0 100%; + padding: 0; + input { + flex: 3; + } + select { + margin-left: 5px; + flex: 1; + } + } + } + + .weaponproperties-control { + width: 18px; + flex: 0 0 18px; + line-height: 24px; + float: right; + text-align: right; + color: @colorTan; + } .recharge { span { diff --git a/module/config.js b/module/config.js index 6f13086c..2490a6e9 100644 --- a/module/config.js +++ b/module/config.js @@ -238,7 +238,40 @@ SW5E.damageTypes = { "necrotic": "SW5E.DamageNecrotic", "poison": "SW5E.DamagePoison", "psychic": "SW5E.DamagePsychic", - "Sonic": "SW5E.DamageSonic", + "Sonic": "SW5E.DamageSonic" +}; + +/* -------------------------------------------- */ + +// armor Types +SW5E.armorpropertiesTypes = { +"Absorptive": "SW5E.ArmorProperAbsorptive", +"Agile": "SW5E.ArmorProperAgile", +"Anchor": "SW5E.ArmorProperAnchor", +"Avoidant": "SW5E.ArmorProperAvoidant", +"Barbed": "SW5E.ArmorProperBarbed", +"Charging": "SW5E.ArmorProperCharging", +"Concealing": "SW5E.ArmorProperConcealing", +"Cumbersome": "SW5E.ArmorProperCumbersome", +"Gauntleted": "SW5E.ArmorProperGauntleted", +"Imbalanced": "SW5E.ArmorProperImbalanced", +"Impermeable": "SW5E.ArmorProperImpermeable", +"Insulated": "SW5E.ArmorProperInsulated", +"Interlocking": "SW5E.ArmorProperInterlocking", +"Lambent": "SW5E.ArmorProperLambent", +"Lightweight": "SW5E.ArmorProperLightweight", +"Magnetic": "SW5E.ArmorProperMagnetic", +"Obscured": "SW5E.ArmorProperObscured", +"Powered": "SW5E.ArmorProperPowered", +"Reactive": "SW5E.ArmorProperReactive", +"Regulated": "SW5E.ArmorProperRegulated", +"Reinforced": "SW5E.ArmorProperReinforced", +"Responsive": "SW5E.ArmorProperResponsive", +"Rigid": "SW5E.ArmorProperRigid", +"Silent": "SW5E.ArmorProperSilent", +"Spiked": "SW5E.ArmorProperSpiked", +"Steadfast": "SW5E.ArmorProperSteadfast", +"Versatile": "SW5E.ArmorProperVersatile" }; /* -------------------------------------------- */ @@ -597,7 +630,7 @@ SW5E.languages = { "sith": "SW5E.LanguagesSith", "togruti": "SW5E.LanguagesTogruti", "dosh": "SW5E.LanguagesDosh", - "twi'leki": "SW5E.LanguagesTwi'leki", + "twi'leki": "SW5E.LanguagesTwileki", "tusken": "SW5E.LanguagesTusken", "shyriiwook": "SW5E.LanguagesShyriiwook", "zabraki": "SW5E.LanguagesZabraki", diff --git a/module/item/sheet.js b/module/item/sheet.js index 9457b588..30bc94be 100644 --- a/module/item/sheet.js +++ b/module/item/sheet.js @@ -47,6 +47,7 @@ export class ItemSheet5e extends ItemSheet { data.hasAttackRoll = this.item.hasAttack; data.isHealing = data.item.data.actionType === "heal"; data.isFlatDC = getProperty(data.item.data, "save.scaling") === "flat"; + data.isWeapon = data.item.type === "weapon"; return data; } @@ -145,6 +146,25 @@ export class ItemSheet5e extends ItemSheet { return arr; }, []); +// Handle armorproperties Array + let armorproperties = Object.entries(formData).filter(e => e[0].startsWith("data.armorproperties.parts")); + formData["data.armorproperties.parts"] = armorproperties.reduce((arr, entry) => { + let [i, j] = entry[0].split(".").slice(3); + if ( !arr[i] ) arr[i] = []; + arr[i][j] = entry[1]; + return arr; + }, []); + + // Handle weaponproperties Array + let weaponproperties = Object.entries(formData).filter(e => e[0].startsWith("data.weaponproperties.parts")); + formData["data.weaponproperties.parts"] = weaponproperties.reduce((arr, entry) => { + let [i, j] = entry[0].split(".").slice(3); + if ( !arr[i] ) arr[i] = []; + arr[i][j] = entry[1]; + return arr; + }, []); + + // Update the Item super._updateObject(event, formData); } @@ -158,6 +178,13 @@ export class ItemSheet5e extends ItemSheet { // Activate any Trait Selectors html.find('.trait-selector.class-skills').click(this._onConfigureClassSkills.bind(this)); + + // Armor properties + html.find(".armorproperties-control").click(this._onarmorpropertiesControl.bind(this)); + + // Weapon properties + html.find(".weaponproperties-control").click(this._onweaponpropertiesControl.bind(this)); + } /* -------------------------------------------- */ @@ -191,6 +218,64 @@ export class ItemSheet5e extends ItemSheet { /* -------------------------------------------- */ +/** + * Add or remove a armorproperties part from the armorproperties formula + * @param {Event} event The original click event + * @return {Promise} + * @private + */ + async _onarmorpropertiesControl(event) { + event.preventDefault(); + const a = event.currentTarget; + + // Add new armorproperties component + if ( a.classList.contains("add-armorproperties") ) { + await this._onSubmit(event); // Submit any unsaved changes + const armorproperties = this.item.data.data.armorproperties; + return this.item.update({"data.armorproperties.parts": armorproperties.parts.concat([["", ""]])}); + } + + // Remove a armorproperties component + if ( a.classList.contains("delete-armorproperties") ) { + await this._onSubmit(event); // Submit any unsaved changes + const li = a.closest(".armorproperties-part"); + const armorproperties = duplicate(this.item.data.data.armorproperties); + armorproperties.parts.splice(Number(li.dataset.armorpropertiesPart), 1); + return this.item.update({"data.armorproperties.parts": armorproperties.parts}); + } + } + + /* -------------------------------------------- */ + + /** + * Add or remove a weaponproperties part from the weaponproperties formula + * @param {Event} event The original click event + * @return {Promise} + * @private + */ + async _onweaponpropertiesControl(event) { + event.preventDefault(); + const a = event.currentTarget; + + // Add new weaponproperties component + if ( a.classList.contains("add-weaponproperties") ) { + await this._onSubmit(event); // Submit any unsaved changes + const weaponproperties = this.item.data.data.weaponproperties; + return this.item.update({"data.weaponproperties.parts": weaponproperties.parts.concat([["", ""]])}); + } + + // Remove a weaponproperties component + if ( a.classList.contains("delete-weaponproperties") ) { + await this._onSubmit(event); // Submit any unsaved changes + const li = a.closest(".weaponproperties-part"); + const weaponproperties = duplicate(this.item.data.data.weaponproperties); + weaponproperties.parts.splice(Number(li.dataset.weaponpropertiesPart), 1); + return this.item.update({"data.weaponproperties.parts": weaponproperties.parts}); + } + } + + /* -------------------------------------------- */ + /** * Handle spawning the TraitSelector application which allows a checkbox of multiple trait options * @param {Event} event The click event which originated the selection diff --git a/sw5e.css b/sw5e.css index 01ad236c..5cabe8e0 100644 --- a/sw5e.css +++ b/sw5e.css @@ -1053,6 +1053,72 @@ text-align: right; color: #7a7971; } + +.sw5e.sheet.item h4.armorproperties-header { + margin: 0; + padding: 0; + font-weight: bold; + line-height: 24px; + color: #4b4a44; +} +.sw5e.sheet.item .armorproperties-parts { + list-style: none; + margin: 0; + padding: 0; +} +.sw5e.sheet.item .armorproperties-parts .armorproperties-part { + flex: 0 0 100%; + padding: 0; +} +.sw5e.sheet.item .armorproperties-parts .armorproperties-part input { + flex: 3; +} +.sw5e.sheet.item .armorproperties-parts .armorproperties-part select { + margin-left: 5px; + flex: 1; +} +.sw5e.sheet.item .armorproperties-control { + width: 18px; + flex: 0 0 18px; + line-height: 24px; + float: right; + text-align: right; + color: #7a7971; + +} + +.sw5e.sheet.item h4.weaponproperties-header { + margin: 0; + padding: 0; + font-weight: bold; + line-height: 24px; + color: #4b4a44; +} +.sw5e.sheet.item .weaponproperties-parts { + list-style: none; + margin: 0; + padding: 0; +} +.sw5e.sheet.item .weaponproperties-parts .weaponproperties-part { + flex: 0 0 100%; + padding: 0; +} +.sw5e.sheet.item .weaponproperties-parts .weaponproperties-part input { + flex: 3; +} +.sw5e.sheet.item .weaponproperties-parts .weaponproperties-part select { + margin-left: 5px; + flex: 1; +} +.sw5e.sheet.item .weaponproperties-control { + width: 18px; + flex: 0 0 18px; + line-height: 24px; + float: right; + text-align: right; + color: #7a7971; +} + .sw5e.sheet.item .recharge span { flex: 0 0 80px; } diff --git a/sw5e.js b/sw5e.js index f37ec6c6..8256adf1 100644 --- a/sw5e.js +++ b/sw5e.js @@ -75,7 +75,7 @@ Hooks.once("setup", function() { "abilities", "alignments", "conditionTypes", "consumableTypes", "currencies", "damageTypes", "distanceUnits", "equipmentTypes", "healingTypes", "itemActionTypes", "limitedUsePeriods", "senses", "skills", "powerComponents", "powerLevels", "powerPreparationModes", "powerSchools", "powerScalingModes", "targetTypes", "timePeriods", "weaponProperties", "weaponTypes", "languages", "polymorphSettings", - "armorProficiencies", "weaponProficiencies", "toolProficiencies", "abilityActivationTypes", "actorSizes", "proficiencyLevels" + "armorProficiencies", "weaponProficiencies", "toolProficiencies", "abilityActivationTypes", "actorSizes", "proficiencyLevels", "armorpropertiesTypes" ]; for ( let o of toLocalize ) { CONFIG.SW5E[o] = Object.entries(CONFIG.SW5E[o]).reduce((obj, e) => { diff --git a/templates/items/equipment.html b/templates/items/equipment.html index 323b5321..e4d7d980 100644 --- a/templates/items/equipment.html +++ b/templates/items/equipment.html @@ -73,6 +73,33 @@ {{ localize "SW5E.Attuned" }} + +{{#unless isWeapon }} +{{!-- ArmorProperties Formula --}} +