Spot the link / entityClass error!

This commit is contained in:
Professor Bunbury 2020-10-23 17:45:27 -04:00
parent 5f5a145626
commit d392b568db
56 changed files with 6353 additions and 3288 deletions

1
.gitignore vendored
View file

@ -25,3 +25,4 @@ hs_err_pid*
# IDE Folders # IDE Folders
.idea/ .idea/
.vs/ .vs/
node_modules

View file

@ -1,9 +1,27 @@
# sw5e # Foundry Virtual Tabletop - SW5e Game System
SW5E Foundry VTT System
For easy install This game system for [Foundry Virtual Tabletop](http://foundryvtt.com) provides character sheet and game system
support for the SW5E roleplaying game.
In the Foundry Configuration and Setup window go to the Game Systems tab, click on the "Install System" button, and This system provides character sheet support for Actors and Items, mechanical support for dice and rules necessary to
place the following link into the Manifest URL at the bottom play games of SW5E, and compendium content for Monsters, Heroes, Items, Powers, Class Features, Monster
Features, and more!
The software component of this system is distributed under the GNUv3 license.
## Installation Instructions
To install and use the SW5e system for Foundry Virtual Tabletop, simply paste the following URL into the
**Install System** dialog on the Setup menu of the application.
https://raw.githubusercontent.com/unrealkakeman89/sw5e/master/system.json https://raw.githubusercontent.com/unrealkakeman89/sw5e/master/system.json
If you wish to manually install the system, you must clone or extract it into the ``Data/systems/sw5e`` folder. You
may do this by cloning the repository or downloading a zip archive from the
[Releases Page](https://github.com/unrealkakeman89/sw5e).
## Community Contribution
Code and content contributions are accepted. Please feel free to submit issues to the issue tracker or submit merge
requests for code changes. Approval for such requests involves code and (if necessary) design review by The Dev Team.
Please reach out on the SW5E Foundry Dev Discord with any questions.

32
gulpfile.js Normal file
View file

@ -0,0 +1,32 @@
const gulp = require('gulp');
const less = require('gulp-less');
/* ----------------------------------------- */
/* Compile LESS
/* ----------------------------------------- */
const SW5E_LESS = ["less/*.less"];
function compileLESS() {
return gulp.src("less/sw5e.less")
.pipe(less())
.pipe(gulp.dest("./"))
}
const css = gulp.series(compileLESS);
/* ----------------------------------------- */
/* Watch Updates
/* ----------------------------------------- */
function watchUpdates() {
gulp.watch(SW5E_LESS, css);
}
/* ----------------------------------------- */
/* Export Tasks
/* ----------------------------------------- */
exports.default = gulp.series(
gulp.parallel(css),
watchUpdates
);
exports.css = css;

View file

@ -1,29 +1,58 @@
{ {
"ACTOR.TypeCharacter": "Player Character",
"ACTOR.TypeNpc": "Non-Player Character",
"ACTOR.TypeVehicle": "Vehicle",
"ITEM.TypeBackpack": "Backpack",
"ITEM.TypeClass": "Class",
"ITEM.TypeConsumable": "Consumable",
"ITEM.TypeEquipment": "Equipment",
"ITEM.TypeFeat": "Feature",
"ITEM.TypeLoot": "Loot",
"ITEM.TypePower": "Power",
"ITEM.TypeTool": "Tool",
"ITEM.TypeWeapon": "Weapon",
"Star Wars 5th Edition": "Star Wars 5th Edition", "Star Wars 5th Edition": "Star Wars 5th Edition",
"SW5E.title": "Star Wars 5th Edition", "SW5E.title": "Star Wars 5th Edition",
"SW5E.AbbreviationCR": "CR", "SW5E.AbbreviationCR": "CR",
"SW5E.AbbreviationConc": "Conc.", "SW5E.AbbreviationConc": "Conc.",
"SW5E.AbbreviationDC": "DC", "SW5E.AbbreviationDC": "DC",
"SW5E.AbbreviationLR": "LR", "SW5E.AbbreviationLR": "LR",
"SW5E.AbbreviationLevel": "Lvl.",
"SW5E.AbbreviationLbs": "lbs.", "SW5E.AbbreviationLbs": "lbs.",
"SW5E.AbbreviationSR": "SR", "SW5E.AbbreviationSR": "SR",
"SW5E.Ability": "Ability", "SW5E.Ability": "Ability",
"SW5E.AbilityCha": "Charisma",
"SW5E.AbilityCon": "Constitution",
"SW5E.AbilityDex": "Dexterity",
"SW5E.AbilityInt": "Intelligence",
"SW5E.AbilityModifier": "Ability Modifier",
"SW5E.AbilityStr": "Strength", "SW5E.AbilityStr": "Strength",
"SW5E.AbilityUseCantUse": "You are not currently able to use this ability!", "SW5E.AbilityStrAbbr": "str",
"SW5E.AbilityUseCharged": "charged", "SW5E.AbilityCon": "Constitution",
"SW5E.AbilityUseConsume": "Consume Available Usage?", "SW5E.AbilityConAbbr": "con",
"SW5E.AbilityUseDepleted": "depleted", "SW5E.AbilityDex": "Dexterity",
"SW5E.AbilityUseHint": "Configure how you would like to use the", "SW5E.AbilityDexAbbr": "dex",
"SW5E.AbilityUseRechargeHint": "This ability uses a recharge mechanic and is currently", "SW5E.AbilityInt": "Intelligence",
"SW5E.AbilityUseWarnEnd": "available uses per", "SW5E.AbilityIntAbbr": "int",
"SW5E.AbilityUseWarnStart": "This ability has",
"SW5E.AbilityWis": "Wisdom", "SW5E.AbilityWis": "Wisdom",
"SW5E.AbilityWisAbbr": "wis",
"SW5E.AbilityCha": "Charisma",
"SW5E.AbilityChaAbbr": "cha",
"SW5E.AbilityModifier": "Ability Modifier",
"SW5E.AbilityPromptText": "What type of {ability} check?",
"SW5E.AbilityPromptTitle": "{ability} Ability Check",
"SW5E.AbilityUseHint": "Configure how you would like to use the {name} {type}.",
"SW5E.AbilityUseUnavailableHint": "There are no uses of this item remaining!",
"SW5E.AbilityUseChargedHint": "This {type} is charged and ready to use!",
"SW5E.AbilityUseRechargedHint": "This {type} is depleted and must be recharged!",
"SW5E.AbilityUseNormalHint": "This {type} has {value} of {max} uses per {per} remaining.",
"SW5E.AbilityUseConsumableChargeHint": "Using this {type} will consume 1 charge of {value} remaining.",
"SW5E.AbilityUseConsumableQuantityHint": "Using this {type} will consume 1 quantity of {quantity} remaining",
"SW5E.AbilityUseConsumableDestroyHint": "Using this {type} will consume its final charge and it will be destroyed.",
"SW5E.AbilityUseConsume": "Consume Available Usage?",
"SW5E.AbilityUseChargesLabel": "{value} Charges",
"SW5E.AbilityUseConsumableLabel": "{max} per {per}",
"SW5E.AbilityUseCast": "Cast Power",
"SW5E.AbilityUseUse": "Use Ability",
"SW5E.Action": "Action", "SW5E.Action": "Action",
"SW5E.ActionPl": "Actions",
"SW5E.ActionAbil": "Ability Check", "SW5E.ActionAbil": "Ability Check",
"SW5E.ActionHeal": "Healing", "SW5E.ActionHeal": "Healing",
"SW5E.ActionMPAK": "Melee Power Attack", "SW5E.ActionMPAK": "Melee Power Attack",
@ -33,6 +62,8 @@
"SW5E.ActionRWAK": "Ranged Weapon Attack", "SW5E.ActionRWAK": "Ranged Weapon Attack",
"SW5E.ActionSave": "Saving Throw", "SW5E.ActionSave": "Saving Throw",
"SW5E.ActionUtil": "Utility", "SW5E.ActionUtil": "Utility",
"SW5E.ActionWarningNoItem": "The requested item {item} no longer exists on Actor {name}",
"SW5E.ActionWarningNoToken": "You must have one or more controlled Tokens in order to use this option.",
"SW5E.Add": "Add", "SW5E.Add": "Add",
"SW5E.Advantage": "Advantage", "SW5E.Advantage": "Advantage",
"SW5E.Alignment": "Alignment", "SW5E.Alignment": "Alignment",
@ -44,15 +75,18 @@
"SW5E.AlignmentLN": "Lawful Neutral", "SW5E.AlignmentLN": "Lawful Neutral",
"SW5E.AlignmentND": "Neutral Dark", "SW5E.AlignmentND": "Neutral Dark",
"SW5E.AlignmentNL": "Neutral Light", "SW5E.AlignmentNL": "Neutral Light",
"SW5E.AlignmentBN": "Balenced Neutral", "SW5E.AlignmentBN": "Balanced Neutral",
"SW5E.Archetypes": "Archetypes", "SW5E.Archetypes": "Archetypes",
"SW5E.Appearance": "Appearance",
"SW5E.ArmorClass": "Armor Class", "SW5E.ArmorClass": "Armor Class",
"SW5E.AC": "AC",
"SW5E.ArmorProperties": "Armor Properties", "SW5E.ArmorProperties": "Armor Properties",
"SW5E.ArmorProperAbsorptive": "Absorptive", "SW5E.ArmorProperAbsorptive": "Absorptive",
"SW5E.ArmorProperAgile": "Agile", "SW5E.ArmorProperAgile": "Agile",
"SW5E.ArmorProperAnchor": "Anchor", "SW5E.ArmorProperAnchor": "Anchor",
"SW5E.ArmorProperAvoidant": "Avoidant", "SW5E.ArmorProperAvoidant": "Avoidant",
"SW5E.ArmorProperBarbed": "Barbed", "SW5E.ArmorProperBarbed": "Barbed",
"SW5E.ArmorProperBulky": "Bulky",
"SW5E.ArmorProperCharging": "Charging", "SW5E.ArmorProperCharging": "Charging",
"SW5E.ArmorProperConcealing": "Concealing", "SW5E.ArmorProperConcealing": "Concealing",
"SW5E.ArmorProperCumbersome": "Cumbersome", "SW5E.ArmorProperCumbersome": "Cumbersome",
@ -65,6 +99,7 @@
"SW5E.ArmorProperLightweight": "Lightweight", "SW5E.ArmorProperLightweight": "Lightweight",
"SW5E.ArmorProperMagnetic": "Magnetic", "SW5E.ArmorProperMagnetic": "Magnetic",
"SW5E.ArmorProperObscured": "Obscured", "SW5E.ArmorProperObscured": "Obscured",
"SW5E.ArmorProperObtrusive": "Obtrusive",
"SW5E.ArmorProperPowered": "Powered", "SW5E.ArmorProperPowered": "Powered",
"SW5E.ArmorProperReactive": "Reactive", "SW5E.ArmorProperReactive": "Reactive",
"SW5E.ArmorProperRegulated": "Regulated", "SW5E.ArmorProperRegulated": "Regulated",
@ -74,22 +109,26 @@
"SW5E.ArmorProperSilent": "Silent", "SW5E.ArmorProperSilent": "Silent",
"SW5E.ArmorProperSpiked": "Spiked", "SW5E.ArmorProperSpiked": "Spiked",
"SW5E.ArmorProperSteadfast": "Steadfast", "SW5E.ArmorProperSteadfast": "Steadfast",
"SW5E.ArmorProperStrength": "Strength Rqmt.",
"SW5E.ArmorProperVersatile": "Versatile", "SW5E.ArmorProperVersatile": "Versatile",
"SW5E.Attack": "Attack", "SW5E.Attack": "Attack",
"SW5E.AttackPl": "Attacks",
"SW5E.AttackRoll": "Attack Roll",
"SW5E.Attributes": "Attributes", "SW5E.Attributes": "Attributes",
"SW5E.Attuned": "Attuned", "SW5E.Attuned": "Attuned",
"SW5E.Background": "Background", "SW5E.Background": "Background",
"SW5E.Biography": "Biography", "SW5E.Biography": "Biography",
"SW5E.Bonds": "Bonds",
"SW5E.BonusAbilityCheck": "Global Ability Check Bonus", "SW5E.BonusAbilityCheck": "Global Ability Check Bonus",
"SW5E.BonusAbilitySave": "Global Saving Throw Bonus", "SW5E.BonusAbilitySave": "Global Saving Throw Bonus",
"SW5E.BonusAbilitySkill": "Global Skill Check Bonus", "SW5E.BonusAbilitySkill": "Global Skill Check Bonus",
"SW5E.BonusAction": "Bonus Action", "SW5E.BonusAction": "Bonus Action",
"SW5E.BonusMSAttack": "Melee Power Attack Bonus", "SW5E.BonusMPAttack": "Melee Power Attack Bonus",
"SW5E.BonusMSDamage": "Melee Power Damage Bonus", "SW5E.BonusMPDamage": "Melee Power Damage Bonus",
"SW5E.BonusMWAttack": "Melee Weapon Attack Bonus", "SW5E.BonusMWAttack": "Melee Weapon Attack Bonus",
"SW5E.BonusMWDamage": "Melee Weapon Damage Bonus", "SW5E.BonusMWDamage": "Melee Weapon Damage Bonus",
"SW5E.BonusRSAttack": "Ranged Power Attack Bonus", "SW5E.BonusRPAttack": "Ranged Power Attack Bonus",
"SW5E.BonusRSDamage": "Ranged Power Damage Bonus", "SW5E.BonusRPDamage": "Ranged Power Damage Bonus",
"SW5E.BonusRWAttack": "Ranged Weapon Attack Bonus", "SW5E.BonusRWAttack": "Ranged Weapon Attack Bonus",
"SW5E.BonusRWDamage": "Ranged Weapon Damage Bonus", "SW5E.BonusRWDamage": "Ranged Weapon Damage Bonus",
"SW5E.BonusSaveForm": "Update Bonuses", "SW5E.BonusSaveForm": "Update Bonuses",
@ -116,6 +155,7 @@
"SW5E.ConBlinded": "Blinded", "SW5E.ConBlinded": "Blinded",
"SW5E.ConCharmed": "Charmed", "SW5E.ConCharmed": "Charmed",
"SW5E.ConDeafened": "Deafened", "SW5E.ConDeafened": "Deafened",
"SW5E.ConDiseased": "Diseased",
"SW5E.ConExhaustion": "Exhaustion", "SW5E.ConExhaustion": "Exhaustion",
"SW5E.ConFrightened": "Frightened", "SW5E.ConFrightened": "Frightened",
"SW5E.ConGrappled": "Grappled", "SW5E.ConGrappled": "Grappled",
@ -128,9 +168,22 @@
"SW5E.ConProne": "Prone", "SW5E.ConProne": "Prone",
"SW5E.ConRestrained": "Restrained", "SW5E.ConRestrained": "Restrained",
"SW5E.ConShocked": "Shocked", "SW5E.ConShocked": "Shocked",
"SW5E.ConSlowed": "Slowed",
"SW5E.ConStunned": "Stunned", "SW5E.ConStunned": "Stunned",
"SW5E.ConUnconscious": "Unconscious", "SW5E.ConUnconscious": "Unconscious",
"SW5E.Concentration": "Concentration", "SW5E.Concentration": "Concentration",
"SW5E.ConsumeTitle": "Resource Consumption",
"SW5E.ConsumeAmmunition": "Ammunition",
"SW5E.ConsumeAttribute": "Attribute",
"SW5E.ConsumeMaterial": "Material",
"SW5E.ConsumeCharges": "Item Uses",
"SW5E.ConsumeWarningNoResource": "{name} is designated to consume {type} but no resource is specified!",
"SW5E.ConsumeWarningNoSource": "The designated {type} source that {name} consumes no longer exists!",
"SW5E.ConsumeWarningNoQuantity": "{name} has run out of its designated {type}!",
"SW5E.ConsumeWarningZeroAttribute": "{name} has run out of its designated attribute resource pool!",
"SW5E.ConsumableAmmunition": "Ammunition",
"SW5E.ConsumableFood": "Food", "SW5E.ConsumableFood": "Food",
"SW5E.ConsumablePoison": "Poison", "SW5E.ConsumablePoison": "Poison",
"SW5E.ConsumableAdrenal": "Adrenal", "SW5E.ConsumableAdrenal": "Adrenal",
@ -138,9 +191,19 @@
"SW5E.ConsumableMedpac": "Medpac", "SW5E.ConsumableMedpac": "Medpac",
"SW5E.ConsumableTrinket": "Trinket", "SW5E.ConsumableTrinket": "Trinket",
"SW5E.ConsumableTechnology": "Technology", "SW5E.ConsumableTechnology": "Technology",
"SW5E.ConsumableAmmunition": "Ammunition", "SW5E.ConsumableForce": "Force Points",
"SW5E.ConsumableTech": "Tech Points",
"SW5E.ConsumableUseWarnStart": "This consumable has",
"SW5E.ConsumableUseWarnEnd": "of the current unit",
"SW5E.ConsumableUnitWarn": "units remaining",
"SW5E.ConsumableLastChargeWarn": "This is the last charge of this unit and consuming it will also reduce the item's quantity by 1",
"SW5E.ConsumableWithoutCharges": "available units to use",
"SW5E.Consumed": "Consumed", "SW5E.Consumed": "Consumed",
"SW5E.CostGP": "Cost (GP)", "SW5E.Cover": "Cover",
"SW5E.CoverHalf": "Half",
"SW5E.CoverThreeQuarters": "Three Quarters",
"SW5E.CoverTotal": "Total",
"SW5E.CostGP": "Cost (CR)",
"SW5E.Critical": "Critical", "SW5E.Critical": "Critical",
"SW5E.CriticalHit": "Critical Hit", "SW5E.CriticalHit": "Critical Hit",
"SW5E.Currency": "Currency", "SW5E.Currency": "Currency",
@ -151,24 +214,31 @@
"SW5E.DamRes": "Damage Resistances", "SW5E.DamRes": "Damage Resistances",
"SW5E.DamVuln": "Damage Vulnerabilities", "SW5E.DamVuln": "Damage Vulnerabilities",
"SW5E.Damage": "Damage", "SW5E.Damage": "Damage",
"SW5E.DamageAcid": "Acid", "SW5E.DamageAcid": "Acid",
"SW5E.DamageCold": "Cold", "SW5E.DamageCold": "Cold",
"SW5E.DamageEnergy": "Energy", "SW5E.DamageEnergy": "Energy",
"SW5E.DamageFire": "Fire", "SW5E.DamageFire": "Fire",
"SW5E.DamageForce": "Force", "SW5E.DamageForce": "Force",
"SW5E.DamageIon": "ION", "SW5E.DamageIon": "Ion",
"SW5E.DamageKinetic": "Kinetic", "SW5E.DamageKinetic": "Kinetic",
"SW5E.DamageLightning": "Lightning", "SW5E.DamageLightning": "Lightning",
"SW5E.DamageNecrotic": "Necrotic", "SW5E.DamageNecrotic": "Necrotic",
"SW5E.DamagePoison": "Poison", "SW5E.DamagePoison": "Poison",
"SW5E.DamagePsychic": "Psychic", "SW5E.DamagePsychic": "Psychic",
"SW5E.DamageSonic": "Sonic", "SW5E.DamageSonic": "Sonic",
"SW5E.DamageRoll": "Damage Roll",
"SW5E.Day": "Day", "SW5E.Day": "Day",
"SW5E.DeathSave": "Death Saves", "SW5E.DeathSave": "Death Saves",
"SW5E.DeathSaveCriticalSuccess": "{name} critically succeeded on a death saving throw and has regained 1 Hit Point!",
"SW5E.DeathSaveSuccess": "{name} has survived with 3 death save successes and is now stable!",
"SW5E.DeathSaveFailure": "{name} has died with 3 death save failures!",
"SW5E.DeathSavingThrow": "Death Saving Throw",
"SW5E.DeathSaveUnnecessary": "You do not need to roll death saves because you have a positive number of hit points or have already reached 3 successes or failures.",
"SW5E.Default": "Default", "SW5E.Default": "Default",
"SW5E.DefaultAbilityCheck": "Default Ability Check", "SW5E.DefaultAbilityCheck": "Default Ability Check",
"SW5E.Description": "Description", "SW5E.Description": "Description",
"SW5E.Details": "Details", "SW5E.Details": "Details",
"SW5E.Dimensions": "Dimensions",
"SW5E.Disadvantage": "Disadvantage", "SW5E.Disadvantage": "Disadvantage",
"SW5E.DistAny": "Any", "SW5E.DistAny": "Any",
"SW5E.DistFt": "Feet", "SW5E.DistFt": "Feet",
@ -176,6 +246,7 @@
"SW5E.DistSelf": "Self", "SW5E.DistSelf": "Self",
"SW5E.DistTouch": "Touch", "SW5E.DistTouch": "Touch",
"SW5E.Duration": "Duration", "SW5E.Duration": "Duration",
"SW5E.Effects": "Effects",
"SW5E.EquipmentBonus": "Magical Bonus", "SW5E.EquipmentBonus": "Magical Bonus",
"SW5E.EquipmentClothing": "Clothing", "SW5E.EquipmentClothing": "Clothing",
"SW5E.EquipmentHeavy": "Heavy Armor", "SW5E.EquipmentHeavy": "Heavy Armor",
@ -185,19 +256,20 @@
"SW5E.EquipmentShield": "Shield", "SW5E.EquipmentShield": "Shield",
"SW5E.EquipmentShieldProficiency": "Shields", "SW5E.EquipmentShieldProficiency": "Shields",
"SW5E.EquipmentTrinket": "Trinket", "SW5E.EquipmentTrinket": "Trinket",
"SW5E.EquipmentVehicle": "Vehicle Equipment",
"SW5E.Equipped": "Equipped", "SW5E.Equipped": "Equipped",
"SW5E.Exhaustion": "Exhaustion", "SW5E.Exhaustion": "Exhaustion",
"SW5E.Expertise": "Expertise", "SW5E.Expertise": "Expertise",
"SW5E.FeatureActionRecharge": "Action Recharge", "SW5E.FeatureActionRecharge": "Action Recharge",
"SW5E.Flaws": "Flaws",
<<<<<<< Updated upstream
=======
"SW5E.ItemTypeArchetype": "Archetype", "SW5E.ItemTypeArchetype": "Archetype",
"SW5E.ItemTypeBackground": "Background", "SW5E.ItemTypeBackground": "Background",
"Sw5E.ItemTypeBackgroundPl": "Backgrounds", "Sw5E.ItemTypeBackgroundPl": "Backgrounds",
>>>>>>> Stashed changes
"SW5E.ItemTypeClass": "Class", "SW5E.ItemTypeClass": "Class",
"SW5E.ItemTypeClassPl": "Class Levels", "SW5E.ItemTypeClassPl": "Class Levels",
"SW5E.ItemTypeClassFeat": "Class Feature",
"SW5E.ItemTypeClassFeats": "Class Features",
"SW5E.ItemTypeConsumable": "Consumable", "SW5E.ItemTypeConsumable": "Consumable",
"SW5E.ItemTypeConsumablePl": "Consumables", "SW5E.ItemTypeConsumablePl": "Consumables",
"SW5E.ItemTypeContainer": "Container", "SW5E.ItemTypeContainer": "Container",
@ -214,6 +286,7 @@
"SW5E.ItemTypePowerPl": "Powers", "SW5E.ItemTypePowerPl": "Powers",
"SW5E.ItemTypeWeapon": "Weapon", "SW5E.ItemTypeWeapon": "Weapon",
"SW5E.ItemTypeWeaponPl": "Weapons", "SW5E.ItemTypeWeaponPl": "Weapons",
"SW5E.ItemNoUses": "{name} has no available uses remaining.",
"SW5E.FeatureActive": "Active Abilities", "SW5E.FeatureActive": "Active Abilities",
"SW5E.FeatureAdd": "Create Feature", "SW5E.FeatureAdd": "Create Feature",
@ -223,12 +296,37 @@
"SW5E.FeatureRechargeResult": "1d6 Result", "SW5E.FeatureRechargeResult": "1d6 Result",
"SW5E.FeatureUsage": "Feature Usage", "SW5E.FeatureUsage": "Feature Usage",
"SW5E.Features": "Features", "SW5E.Features": "Features",
"SW5E.FeetAbbr": "ft.",
"SW5E.Filter": "Filter", "SW5E.Filter": "Filter",
"SW5E.FilterNoPowers": "No powers found for this set of filters.", "SW5E.FilterNoPowers": "No powers found for this set of filters.",
"SW5E.NoPowerLevels": "This character has no powercaster levels, but you may add powers manually.", "SW5E.NoPowerLevels": "This character has no powercaster levels, but you may add powers manually.",
"SW5E.FlagsInstructions": "Configure character features and traits which fine-tune behaviors of the SW5e system.", "SW5E.FlagsInstructions": "Configure character features and traits which fine-tune behaviors of the SW5e system.",
"SW5E.FlagsSave": "Update Special Traits", "SW5E.FlagsSave": "Update Special Traits",
"SW5E.FlagsTitle": "Configure Special Traits", "SW5E.FlagsTitle": "Configure Special Traits",
"SW5E.FlagsPowerfulBuild": "Powerful Build",
"SW5E.FlagsPowerfulBuildHint": "Provides increased carrying capacity.",
"SW5E.FlagsSavageAttacks": "Savage Attacks",
"SW5E.FlagsSavageAttacksHint": "Adds extra critical hit weapon dice.",
"SW5E.FlagsElvenAccuracy": "Elven Accuracy",
"SW5E.FlagsElvenAccuracyHint": "Roll an extra d20 with advantage to Dex, Int, Wis, or Cha.",
"SW5E.FlagsHalflingLucky": "Halfling Lucky",
"SW5E.FlagsHalflingLuckyHint": "Reroll ones when rolling d20 checks.",
"SW5E.FlagsInitiativeAdv": "Advantage on Initiative",
"SW5E.FlagsInitiativeAdvHint": "Provided by feats or magical items.",
"SW5E.FlagsAlert": "Alert Feat",
"SW5E.FlagsAlertHint": "Provides +5 to Initiative.",
"SW5E.FlagsJOAT": "Jack of All Trades",
"SW5E.FlagsJOATHint": "Half-Proficiency to Ability Checks in which you are not already Proficient.",
"SW5E.FlagsObservant": "Observant Feat",
"SW5E.FlagsObservantHint": "Provides a +5 to passive Perception and Investigation.",
"SW5E.FlagsReliableTalent": "Reliable Talent",
"SW5E.FlagsReliableTalentHint": "Rogues Reliable Talent Feature.",
"SW5E.FlagsRemarkableAthlete": "Remarkable Athlete.",
"SW5E.FlagsRemarkableAthleteHint": "Half-Proficiency (rounded-up) to physical Ability Checks and Initiative.",
"SW5E.FlagsCritThreshold": "Critical Hit Threshold",
"SW5E.FlagsCritThresholdHint": "Allow for expanded critical range; for example Improved or Superior Critical",
"SW5E.Flat": "Flat", "SW5E.Flat": "Flat",
"SW5E.Formula": "Formula", "SW5E.Formula": "Formula",
"SW5E.GrantedAbilities": "Granted Abilities", "SW5E.GrantedAbilities": "Granted Abilities",
@ -236,9 +334,15 @@
"SW5E.Healing": "Healing", "SW5E.Healing": "Healing",
"SW5E.HealingTemp": "Healing (Temporary)", "SW5E.HealingTemp": "Healing (Temporary)",
"SW5E.Health": "Health", "SW5E.Health": "Health",
"SW5E.HP": "Health",
"SW5E.HealthConditions": "Health Conditions",
"SW5E.HealthFormula": "Health Formula", "SW5E.HealthFormula": "Health Formula",
"SW5E.HPFormula": "Health Formula",
"SW5E.HitDice": "Hit Dice", "SW5E.HitDice": "Hit Dice",
"SW5E.HitDiceRoll": "Roll Hit Dice",
"SW5E.HitDiceUsed": "Hit Dice Used", "SW5E.HitDiceUsed": "Hit Dice Used",
"SW5E.HitDiceWarn": "{name} has no available {formula} Hit Dice remaining!",
"SW5E.Ideals": "Ideals",
"SW5E.Identified": "Identified", "SW5E.Identified": "Identified",
"SW5E.Initiative": "Initiative", "SW5E.Initiative": "Initiative",
"SW5E.Inspiration": "Inspiration", "SW5E.Inspiration": "Inspiration",
@ -248,12 +352,10 @@
"SW5E.ItemActivationCost": "Activation Cost", "SW5E.ItemActivationCost": "Activation Cost",
"SW5E.ItemAttackBonus": "Attack Roll Bonus", "SW5E.ItemAttackBonus": "Attack Roll Bonus",
"SW5E.ItemConsumableActivation": "Consumable Activation", "SW5E.ItemConsumableActivation": "Consumable Activation",
"SW5E.ItemConsumableUsage": "Consumable Usage",
"SW5E.ItemConsumableDetails": "Consumable Details", "SW5E.ItemConsumableDetails": "Consumable Details",
"SW5E.ItemConsumableStatus": "Consumable Status", "SW5E.ItemConsumableStatus": "Consumable Status",
"SW5E.ItemConsumableType": "Consumable Type", "SW5E.ItemConsumableType": "Consumable Type",
"SW5E.ItemConsumableUsage": "Consumable Usage",
"SW5E.ItemConsumeOnUse": "Consume on Use",
"SW5E.ItemContainerCapacity": "Capacity", "SW5E.ItemContainerCapacity": "Capacity",
"SW5E.ItemContainerCapacityItems": "Items", "SW5E.ItemContainerCapacityItems": "Items",
"SW5E.ItemContainerCapacityType": "Capacity Type", "SW5E.ItemContainerCapacityType": "Capacity Type",
@ -276,6 +378,10 @@
"SW5E.ItemEquipmentUsage": "Equipment Usage", "SW5E.ItemEquipmentUsage": "Equipment Usage",
"SW5E.ItemName": "Item Name", "SW5E.ItemName": "Item Name",
"SW5E.ItemNew": "New {type}",
"SW5E.ItemRechargeCheck": "{name} recharge check",
"SW5E.ItemRechargeFailure": "failure!",
"SW5E.ItemRechargeSuccess": "success!",
"SW5E.ItemRequiredStr": "Required Strength", "SW5E.ItemRequiredStr": "Required Strength",
"SW5E.ItemToolProficiency": "Tool Proficiency", "SW5E.ItemToolProficiency": "Tool Proficiency",
@ -287,112 +393,9 @@
"SW5E.ItemWeaponType": "Weapon Type", "SW5E.ItemWeaponType": "Weapon Type",
"SW5E.ItemWeaponUsage": "Weapon Usage", "SW5E.ItemWeaponUsage": "Weapon Usage",
"SW5E.JackOfAllTrades": "Jack of all Trades", "SW5E.JackOfAllTrades": "Jack of all Trades",
"SW5E.LairAct": "Lair Action", "SW5E.LairAct": "Uses Lair Action",
"SW5E.LairActionLabel": "Lair Action",
"SW5E.Languages": "Languages", "SW5E.Languages": "Languages",
<<<<<<< Updated upstream
"SW5E.LanguagesAleena": "Aleena",
"SW5E.LanguagesAntarian": "Antarian",
"SW5E.LanguagesAnzellan": "Anzellan",
"SW5E.LanguagesAqualish": "Aqualish",
"SW5E.LanguagesArdennian": "Ardennian",
"SW5E.LanguagesBalosur": "Balosur",
"SW5E.LanguagesBarabel": "Barabel",
"SW5E.LanguagesBasic": "Basic",
"SW5E.LanguagesBesalisk": "Besalisk",
"SW5E.LanguagesBinary": "Binary",
"SW5E.LanguagesBith": "Bith",
"SW5E.LanguagesBocce": "Bocce",
"SW5E.LanguagesBothese": "Bothese",
"SW5E.LanguagesCatharese": "Catharese",
"SW5E.LanguagesCerean": "Cerean",
"SW5E.LanguagesChadra-Fan": "Chadra-Fan",
"SW5E.LanguagesChagri": "Chagri",
"SW5E.LanguagesCheunh": "Cheunh",
"SW5E.LanguagesChevin": "Chevin",
"SW5E.LanguagesChironan": "Chironan",
"SW5E.LanguagesClawdite": "Clawdite",
"SW5E.LanguagesCodruese": "Codruese",
"SW5E.LanguagesColicoid": "Colicoid",
"SW5E.LanguagesDashadi": "Dashadi",
"SW5E.LanguagesDefel": "Defel",
"SW5E.LanguagesDevaronese": "Devaronese",
"SW5E.LanguagesDosh": "Dosh",
"SW5E.LanguagesDraethos": "Draethos",
"SW5E.LanguagesDug": "Dug",
"SW5E.LanguagesDurese": "Durese",
"SW5E.LanguagesEwokese": "Ewokese",
"SW5E.LanguagesFalleen": "Falleen",
"SW5E.LanguagesFelucianese": "Felucianese",
"SW5E.LanguagesGamorrese": "Gamorrese",
"SW5E.LanguagesGand": "Gand",
"SW5E.LanguagesGeonosian": "Geonosian",
"SW5E.LanguagesGivin": "Givin",
"SW5E.LanguagesGran": "Gran",
"SW5E.LanguagesGungan": "Gungan",
"SW5E.LanguagesHapan": "Hapan",
"SW5E.LanguagesHarchese": "Harchese",
"SW5E.LanguagesHerglese": "Herglese",
"SW5E.LanguagesHonoghran": "Honoghran",
"SW5E.LanguagesHuttese": "Huttese",
"SW5E.LanguagesIktotchese": "Iktotchese",
"SW5E.LanguagesIthorese": "Ithorese",
"SW5E.LanguagesJawaese": "Jawaese",
"SW5E.LanguagesKaleesh": "Kaleesh",
"SW5E.LanguagesKaminoan": "Kaminoan",
"SW5E.LanguagesKarkaran": "Karkaran",
"SW5E.LanguagesKelDor": "Kel Dor",
"SW5E.LanguagesKharan": "Kharan",
"SW5E.LanguagesKillik": "Killik",
"SW5E.LanguagesKlatooinian": "Klatooinian",
"SW5E.LanguagesKubazian": "Kubazian",
"SW5E.LanguagesKushiban": "Kushiban",
"SW5E.LanguagesKyuzo": "Kyuzo",
"SW5E.LanguagesLannik": "Lannik",
"SW5E.LanguagesLasat": "Lasat",
"SW5E.LanguagesLowickese": "Lowickese",
"SW5E.LanguagesMandoa": "Mando'a",
"SW5E.LanguagesMiralukese": "Miralukese",
"SW5E.LanguagesMirialan": "Mirialan",
"SW5E.LanguagesMonCal": "Mon Cal",
"SW5E.LanguagesMustafarian": "Mustafarian",
"SW5E.LanguagesMuun": "Muun",
"SW5E.LanguagesNautila": "Nautila",
"SW5E.LanguagesOrtolan": "Ortolan",
"SW5E.LanguagesPakPak": "Pak Pak",
"SW5E.LanguagesPyke": "Pyke",
"SW5E.LanguagesQuarrenese": "Quarrenese",
"SW5E.LanguagesRakata": "Rakata",
"SW5E.LanguagesRattataki": "Rattataki",
"SW5E.LanguagesRishii": "Rishii",
"SW5E.LanguagesRodese": "Rodese",
"SW5E.LanguagesSelkatha": "Selkatha",
"SW5E.LanguagesSemblan": "Semblan",
"SW5E.LanguagesShyriiwook": "Shyriiwook",
"SW5E.LanguagesShistavanen": "Shistavanen",
"SW5E.LanguagesSith": "Sith",
"SW5E.LanguagesSquibbian": "Squibbian",
"SW5E.LanguagesSriluurian": "Sriluurian",
"SW5E.LanguagesSsi-ruuvi": "Ssi-ruuvi",
"SW5E.LanguagesSullustese": "Sullustese",
"SW5E.LanguagesTalzzi": "Talzzi",
"SW5E.LanguagesThisspiasian": "Thisspiasian",
"SW5E.LanguagesTogorese": "Togorese",
"SW5E.LanguagesTogruti": "Togruti",
"SW5E.LanguagesToydarian": "Toydarian",
"SW5E.LanguagesTusken": "Tusken",
"SW5E.LanguagesTwileki": "Twi'leki",
"SW5E.LanguagesUgnaught": "Ugnaught",
"SW5E.LanguagesUmbaran": "Umbaran",
"SW5E.LanguagesUtapese": "Utapese",
"SW5E.LanguagesVerpine": "Verpine",
"SW5E.LanguagesVong": "Vong",
"SW5E.LanguagesVoss": "Voss",
"SW5E.LanguagesYevethan": "Yevethan",
"SW5E.LanguagesZabraki": "Zabraki",
"SW5E.LanguagesZygerrian": "Zygerrian",
"SW5E.LegAct": "Legd. Actions",
"SW5E.LegRes": "Legd. Resistance",
=======
"SW5E.LanguagesAleena": "Aleena", "SW5E.LanguagesAleena": "Aleena",
"SW5E.LanguagesAntarian": "Antarian", "SW5E.LanguagesAntarian": "Antarian",
"SW5E.LanguagesAnzellan": "Anzellan", "SW5E.LanguagesAnzellan": "Anzellan",
@ -501,11 +504,18 @@
"SW5E.LegAct": "Legendary Actions", "SW5E.LegAct": "Legendary Actions",
"SW5E.LegendaryActionLabel": "Legendary Action", "SW5E.LegendaryActionLabel": "Legendary Action",
"SW5E.LegRes": "Legendary Resistance", "SW5E.LegRes": "Legendary Resistance",
>>>>>>> Stashed changes
"SW5E.Level": "Level", "SW5E.Level": "Level",
"SW5E.LevelScaling": "Level Scaling", "SW5E.LevelScaling": "Level Scaling",
"SW5E.LimitedUses": "Limited Uses", "SW5E.LimitedUses": "Limited Uses",
"SW5E.LongRest": "Long Rest", "SW5E.LongRest": "Long Rest",
"SW5E.LongRestNormal": "Long Rest (8 hours)",
"SW5E.LongRestGritty": "Long Rest (7 days)",
"SW5E.LongRestEpic": "Long Rest (1 hour)",
"SW5E.LongRestOvernight": "Long Rest (New Day)",
"SW5E.LongRestResult": "{name} takes a long rest and recovers {health} Hit Points and {dice} Hit Dice.",
"SW5E.LongRestResultHitDice": "{name} takes a long rest and recovers {dice} Hit Dice.",
"SW5E.LongRestResultHitPoints": "{name} takes a long rest and recovers {health} Hit Points.",
"SW5E.LongRestResultShort": "{name} takes a long rest.",
"SW5E.Max": "Max", "SW5E.Max": "Max",
"SW5E.Modifier": "Modifier", "SW5E.Modifier": "Modifier",
"SW5E.Name": "Character Name", "SW5E.Name": "Character Name",
@ -514,6 +524,9 @@
"SW5E.Normal": "Normal", "SW5E.Normal": "Normal",
"SW5E.NotProficient": "Not Proficient", "SW5E.NotProficient": "Not Proficient",
"SW5E.OtherFormula": "Other Formula", "SW5E.OtherFormula": "Other Formula",
"SW5E.PactMagic": "Pact Magic",
"SW5E.Passive": "Passive",
"SW5E.PersonalityTraits": "Personality Traits",
"SW5E.PlaceTemplate": "Place Measured Template", "SW5E.PlaceTemplate": "Place Measured Template",
"SW5E.Polymorph": "Polymorph", "SW5E.Polymorph": "Polymorph",
"SW5E.PolymorphAcceptSettings": "Custom Settings", "SW5E.PolymorphAcceptSettings": "Custom Settings",
@ -531,9 +544,13 @@
"SW5E.PolymorphMergeSkills": "Merge skill proficiencies (take the highest)", "SW5E.PolymorphMergeSkills": "Merge skill proficiencies (take the highest)",
"SW5E.PolymorphPromptTitle": "Transforming Actor", "SW5E.PolymorphPromptTitle": "Transforming Actor",
"SW5E.PolymorphRestoreTransformation": "Restore Transformation", "SW5E.PolymorphRestoreTransformation": "Restore Transformation",
"SW5E.PolymorphRevertWarn": "You do not have permission to revert this Actor's polymorphed state.",
"SW5E.PolymorphTmpClass": "Temporary Class", "SW5E.PolymorphTmpClass": "Temporary Class",
"SW5E.PolymorphTokens": "Transform all linked tokens?", "SW5E.PolymorphTokens": "Transform all linked tokens?",
"SW5E.PolymorphWarn": "You are not allowed to polymorph this actor!",
"SW5E.PolymorphWildShape": "Wild Shape", "SW5E.PolymorphWildShape": "Wild Shape",
"SW5E.Prepared": "Prepared",
"SW5E.Concentrate": "Concentrate",
"SW5E.Concentrated": "Concentrate", "SW5E.Concentrated": "Concentrate",
"SW5E.Price": "Price", "SW5E.Price": "Price",
"SW5E.Proficiency": "Proficiency", "SW5E.Proficiency": "Proficiency",
@ -543,6 +560,8 @@
"SW5E.Range": "Range", "SW5E.Range": "Range",
"SW5E.Rarity": "Rarity", "SW5E.Rarity": "Rarity",
"SW5E.Reaction": "Reaction", "SW5E.Reaction": "Reaction",
"SW5E.ReactionPl": "Reactions",
"SW5E.Recharge": "Recharge",
"SW5E.RequiredMaterials": "Required Materials", "SW5E.RequiredMaterials": "Required Materials",
"SW5E.Requirements": "Requirements", "SW5E.Requirements": "Requirements",
"SW5E.ResourcePrimary": "Resource 1", "SW5E.ResourcePrimary": "Resource 1",
@ -556,6 +575,14 @@
"SW5E.RollMode": "Roll Mode", "SW5E.RollMode": "Roll Mode",
"SW5E.RollSituationalBonus": "Situational Bonus?", "SW5E.RollSituationalBonus": "Situational Bonus?",
"SW5E.Save": "Save", "SW5E.Save": "Save",
"SW5E.SheetClassCharacter": "Default Character Sheet",
"SW5E.SheetClassNPC": "Default NPC Sheet",
"SW5E.SheetClassVehicle": "Default Vehicle Sheet",
"SW5E.SheetClassItem": "Default Item Sheet",
"SW5E.SavingThrow": "Saving Throw",
"SW5E.SaveDC": "DC {dc} {ability}",
"SW5E.SavePromptTitle": "{ability} Saving Throw",
"SW5E.ScalingFormula": "Scaling Formula", "SW5E.ScalingFormula": "Scaling Formula",
"SW5E.SchoolLgt": "Light", "SW5E.SchoolLgt": "Light",
"SW5E.SchoolUni": "Universal", "SW5E.SchoolUni": "Universal",
@ -568,8 +595,14 @@
"SW5E.SenseTS": "Tremorsense", "SW5E.SenseTS": "Tremorsense",
"SW5E.Senses": "Senses", "SW5E.Senses": "Senses",
"SW5E.ShortRest": "Short Rest", "SW5E.ShortRest": "Short Rest",
"SW5E.ShortRestNormal": "Short Rest (1 hour)",
"SW5E.ShortRestGritty": "Short Rest (8 hours)",
"SW5E.ShortRestEpic": "Short Rest (5 minutes)",
"SW5E.ShortRestOvernight": "Short Rest (New Day)",
"SW5E.ShortRestHint": "Take a short rest? On a short rest you may spend remaining Hit Dice and recover primary or secondary resources.", "SW5E.ShortRestHint": "Take a short rest? On a short rest you may spend remaining Hit Dice and recover primary or secondary resources.",
"SW5E.ShortRestNoHD": "No Hit Dice remaining", "SW5E.ShortRestNoHD": "No Hit Dice remaining",
"SW5E.ShortRestResult": "{name} takes a short rest spending {dice} Hit Dice to recover {health} Hit Points.",
"SW5E.ShortRestResultShort": "{name} takes a short rest.",
"SW5E.ShortRestSelect": "Select Dice to Roll", "SW5E.ShortRestSelect": "Select Dice to Roll",
"SW5E.Size": "Size", "SW5E.Size": "Size",
"SW5E.SizeGargantuan": "Gargantuan", "SW5E.SizeGargantuan": "Gargantuan",
@ -596,6 +629,7 @@
"SW5E.SkillSte": "Stealth", "SW5E.SkillSte": "Stealth",
"SW5E.SkillSur": "Survival", "SW5E.SkillSur": "Survival",
"SW5E.SkillTec": "Technology", "SW5E.SkillTec": "Technology",
"SW5E.SkillPromptTitle": "{skill} Skill Check",
"SW5E.Slots": "Slots", "SW5E.Slots": "Slots",
"SW5E.Source": "Source", "SW5E.Source": "Source",
"SW5E.Special": "Special", "SW5E.Special": "Special",
@ -628,7 +662,8 @@
"SW5E.PowerLevel7": "7th Level", "SW5E.PowerLevel7": "7th Level",
"SW5E.PowerLevel8": "8th Level", "SW5E.PowerLevel8": "8th Level",
"SW5E.PowerLevel9": "9th Level", "SW5E.PowerLevel9": "9th Level",
"SW5E.PowerLevelPact": "Pact Slot", "SW5E.PowerLevelSlot": "{level} ({n} Slots)",
"SW5E.PowerLevelPact": "Pact Slot [Level {level}] ({n} Slots)",
"SW5E.PowerMaterials": "Powercasting Materials", "SW5E.PowerMaterials": "Powercasting Materials",
"SW5E.PowerName": "Power Name", "SW5E.PowerName": "Power Name",
"SW5E.PowerNone": "None", "SW5E.PowerNone": "None",
@ -636,6 +671,8 @@
"SW5E.PowerPrepInnate": "Innate Powercasting", "SW5E.PowerPrepInnate": "Innate Powercasting",
"SW5E.PowerPrepPrepared": "Prepared", "SW5E.PowerPrepPrepared": "Prepared",
"SW5E.PowerPrepAlways": "Always Prepared", "SW5E.PowerPrepAlways": "Always Prepared",
"SW5E.PowerPreparationMode": "Power Preparation Mode",
"SW5E.PowerPrepared": "Prepared",
"SW5E.PowerConcentrationMode": "Power Concentration Mode", "SW5E.PowerConcentrationMode": "Power Concentration Mode",
"SW5E.PowerConcentrating": "Concentrating", "SW5E.PowerConcentrating": "Concentrating",
"SW5E.PowerProgArt": "Artificer", "SW5E.PowerProgArt": "Artificer",
@ -649,6 +686,7 @@
"SW5E.Powerbook": "Powerbook", "SW5E.Powerbook": "Powerbook",
"SW5E.SpeciesDescription": "Description", "SW5E.SpeciesDescription": "Description",
"SW5E.SpeciesTraits": "Species Traits", "SW5E.SpeciesTraits": "Species Traits",
"SW5E.StealthDisadvantage": "Stealth Disadvantage",
"SW5E.SubclassName": "Subclass Name", "SW5E.SubclassName": "Subclass Name",
"SW5E.Supply": "Supply", "SW5E.Supply": "Supply",
"SW5E.Target": "Target", "SW5E.Target": "Target",
@ -657,6 +695,7 @@
"SW5E.TargetCreature": "Creature", "SW5E.TargetCreature": "Creature",
"SW5E.TargetCube": "Cube", "SW5E.TargetCube": "Cube",
"SW5E.TargetCylinder": "Cylinder", "SW5E.TargetCylinder": "Cylinder",
"SW5E.TargetDroid": "Droid",
"SW5E.TargetEnemy": "Enemy", "SW5E.TargetEnemy": "Enemy",
"SW5E.TargetLine": "Line", "SW5E.TargetLine": "Line",
"SW5E.TargetObject": "Object", "SW5E.TargetObject": "Object",
@ -666,8 +705,10 @@
"SW5E.TargetSphere": "Sphere", "SW5E.TargetSphere": "Sphere",
"SW5E.TargetSquare": "Square", "SW5E.TargetSquare": "Square",
"SW5E.TargetWall": "Wall", "SW5E.TargetWall": "Wall",
"SW5E.TargetDroid": "Droid", "SW5E.TargetWeapon": "Weapon",
"SW5E.TargetWidth": "Line Width",
"SW5E.Temp": "Temp", "SW5E.Temp": "Temp",
"SW5E.Threshold": "Threshold",
"SW5E.TimeDay": "Days", "SW5E.TimeDay": "Days",
"SW5E.TimeHour": "Hours", "SW5E.TimeHour": "Hours",
"SW5E.TimeInst": "Instantaneous", "SW5E.TimeInst": "Instantaneous",
@ -677,38 +718,40 @@
"SW5E.TimeRound": "Rounds", "SW5E.TimeRound": "Rounds",
"SW5E.TimeTurn": "Turns", "SW5E.TimeTurn": "Turns",
"SW5E.TimeYear": "Years", "SW5E.TimeYear": "Years",
"SW5E.ToolArmormech": "Armormech's Tools", "SW5E.ToolArmormech": "Armormech's Tools",
"SW5E.ToolArmstech": "Armstech's Tools", "SW5E.ToolArmstech": "Armstech's Tools",
"SW5E.ToolArtificer": "Artificer's Tools", "SW5E.ToolArtificer": "Artificer's Tools",
"SW5E.ToolArtist": "Artist's Tools", "SW5E.ToolArtist": "Artist's Tools",
"SW5E.ToolAstrotech": "Astrotech's Tools", "SW5E.ToolAstrotech": "Astrotech's Tools",
"SW5E.ToolBiotech": "Biotech's Tools", "SW5E.ToolBiotech": "Biotech's Tools",
"SW5E.ToolConstructor": "Constructor's Tools", "SW5E.ToolCheck": "Tool Check",
"SW5E.ToolCybertech": "Cybertech's Tools", "SW5E.ToolConstructor": "Constructor's Tools",
"SW5E.ToolJeweler": "Jeweler's Tools", "SW5E.ToolCybertech": "Cybertech's Tools",
"SW5E.ToolSurveyor": "Surveyor's Tools", "SW5E.ToolJeweler": "Jeweler's Tools",
"SW5E.ToolSynthweaver": "Synthweavers's Tools", "SW5E.ToolSurveyor": "Surveyor's Tools",
"SW5E.ToolTinker": "Tinker's Tools", "SW5E.ToolSynthweaver": "Synthweavers's Tools",
"SW5E.ToolAntitoxkit": "Antitoxkit", "SW5E.ToolTinker": "Tinker's Tools",
"SW5E.ToolArchaeologistKit": "Archaeologist Kit", "SW5E.ToolAntitoxkit": "Antitoxkit",
"SW5E.ToolAudiotechKit": "Audiotech's Kit", "SW5E.ToolArchaeologistKit": "Archaeologist Kit",
"SW5E.ToolBioanalysisKit": "Bioanalysis Kit", "SW5E.ToolAudiotechKit": "Audiotech's Kit",
"SW5E.ToolBrewerKit": "Brewer's Kit", "SW5E.ToolBioanalysisKit": "Bioanalysis Kit",
"SW5E.ToolChefKit": "Chef's Kit", "SW5E.ToolBrewerKit": "Brewer's Kit",
"SW5E.ToolDemolitionKit": "Demolition Kit", "SW5E.ToolChefKit": "Chef's Kit",
"SW5E.ToolDisguiseKit": "Disguise Kit", "SW5E.ToolDemolitionKit": "Demolition Kit",
"SW5E.ToolForgeryKit": "Forgery Kit", "SW5E.ToolDisguiseKit": "Disguise Kit",
"SW5E.ToolMechanicKit": "Mechanic's Kit", "SW5E.ToolForgeryKit": "Forgery Kit",
"SW5E.ToolMunitionsKit": "Munitions Kit", "SW5E.ToolMechanicKit": "Mechanic's Kit",
"SW5E.ToolPoisonKit": "Poisoner's Kit", "SW5E.ToolMunitionsKit": "Munitions Kit",
"SW5E.ToolScavengingKit": "Scavenging Kit", "SW5E.ToolPoisonKit": "Poisoner's Kit",
"SW5E.ToolSecurityKit": "Security Kit", "SW5E.ToolScavengingKit": "Scavenging Kit",
"SW5E.ToolSlicerKit": "Slicer's Kit", "SW5E.ToolSecurityKit": "Security Kit",
"SW5E.ToolSpiceKit": "Spicer's Kit", "SW5E.ToolSlicerKit": "Slicer's Kit",
"SW5E.ToolSpiceKit": "Spicer's Kit",
"SW5E.ToolGamingSet": "Gaming Set", "SW5E.ToolGamingSet": "Gaming Set",
"SW5E.ToolMusicalInstrument": "Musical Instrument", "SW5E.ToolMusicalInstrument": "Musical Instrument",
"SW5E.ToolVehicle": "Vehicle (Land or Water)", "SW5E.ToolVehicle": "Vehicle (Land or Water)",
"SW5E.TraitArmorProf": "Armor Proficiencies", "SW5E.TraitArmorProf": "Armor Proficiencies",
"SW5E.TraitSave": "Update",
"SW5E.TraitSelectorSpecial": "Special (Split with Semi-Colon)", "SW5E.TraitSelectorSpecial": "Special (Split with Semi-Colon)",
"SW5E.TraitToolProf": "Tool Proficiencies", "SW5E.TraitToolProf": "Tool Proficiencies",
"SW5E.TraitWeaponProf": "Weapon Proficiencies", "SW5E.TraitWeaponProf": "Weapon Proficiencies",
@ -718,6 +761,20 @@
"SW5E.Usage": "Usage", "SW5E.Usage": "Usage",
"SW5E.Use": "Use", "SW5E.Use": "Use",
"SW5E.Uses": "Uses", "SW5E.Uses": "Uses",
"SW5E.Vehicle": "Vehicle",
"SW5E.VehicleActionStations": "Action Stations",
"SW5E.VehicleActionThresholds": "Action Thresholds",
"SW5E.VehicleCargo": "Cargo",
"SW5E.VehicleCargoCapacity": "Cargo Capacity",
"SW5E.VehicleCargoCrew": "Cargo & Crew",
"SW5E.VehicleCreatureCapacity": "Creature Capacity",
"SW5E.VehicleCrew": "Crew",
"SW5E.VehicleCrewed": "Crewed",
"SW5E.VehicleCrewAction": "Crew Action",
"SW5E.VehicleEquipment": "Vehicle Equipment",
"SW5E.VehicleMishap": "Mishap",
"SW5E.VehiclePassengers": "Passengers",
"SW5E.VehicleUncrewed": "Uncrewed",
"SW5E.Versatile": "Versatile", "SW5E.Versatile": "Versatile",
"SW5E.VersatileDamage": "Versatile Damage", "SW5E.VersatileDamage": "Versatile Damage",
"SW5E.VsDC": "vs DC.", "SW5E.VsDC": "vs DC.",
@ -728,43 +785,48 @@
"SW5E.WeaponMartialB": "Martial Blaster", "SW5E.WeaponMartialB": "Martial Blaster",
"SW5E.WeaponMartialLW": "Martial Lightweapon", "SW5E.WeaponMartialLW": "Martial Lightweapon",
"SW5E.WeaponNatural": "Natural", "SW5E.WeaponNatural": "Natural",
"SW5E.WeaponPropertiesAmm": "Ammunition", "SW5E.WeaponSiege": "Siege",
"SW5E.WeaponPropertiesBur": "Burst", "SW5E.WeaponPropertiesAmm": "Ammunition",
"SW5E.WeaponPropertiesDef": "Defensive", "SW5E.WeaponPropertiesAut": "Auto",
"SW5E.WeaponPropertiesDex": "Dexterity Rqmt.", "SW5E.WeaponPropertiesBur": "Burst",
"SW5E.WeaponPropertiesDrm": "Disarming", "SW5E.WeaponPropertiesDef": "Defensive",
"SW5E.WeaponPropertiesDgd": "Disguised", "SW5E.WeaponPropertiesDex": "Dexterity Rqmt.",
"SW5E.WeaponPropertiesDis": "Disintegrate", "SW5E.WeaponPropertiesDir": "Dire",
"SW5E.WeaponPropertiesDpt": "Disruptive", "SW5E.WeaponPropertiesDrm": "Disarming",
"SW5E.WeaponPropertiesDou": "Double", "SW5E.WeaponPropertiesDgd": "Disguised",
"SW5E.WeaponPropertiesFin": "Finesse", "SW5E.WeaponPropertiesDis": "Disintegrate",
"SW5E.WeaponPropertiesFix": "Fixed", "SW5E.WeaponPropertiesDpt": "Disruptive",
"SW5E.WeaponPropertiesFoc": "Focus", "SW5E.WeaponPropertiesDou": "Double",
"SW5E.WeaponPropertiesHvy": "Heavy", "SW5E.WeaponPropertiesFin": "Finesse",
"SW5E.WeaponPropertiesHid": "Hidden", "SW5E.WeaponPropertiesFix": "Fixed",
"SW5E.WeaponPropertiesKen": "Keen", "SW5E.WeaponPropertiesFoc": "Focus",
"SW5E.WeaponPropertiesLgt": "Light", "SW5E.WeaponPropertiesHvy": "Heavy",
"SW5E.WeaponPropertiesLum": "Luminous", "SW5E.WeaponPropertiesHid": "Hidden",
"SW5E.WeaponPropertiesPic": "Piercing", "SW5E.WeaponPropertiesKen": "Keen",
"SW5E.WeaponPropertiesRan": "Range", "SW5E.WeaponPropertiesLgt": "Light",
"SW5E.WeaponPropertiesRap": "Rapid", "SW5E.WeaponPropertiesLum": "Luminous",
"SW5E.WeaponPropertiesRch": "Reach", "SW5E.WeaponPropertiesMig": "Mighty",
"SW5E.WeaponPropertiesRel": "Reload", "SW5E.WeaponPropertiesPic": "Piercing",
"SW5E.WeaponPropertiesRet": "Returning", "SW5E.WeaponPropertiesRan": "Range",
"SW5E.WeaponPropertiesShk": "Shocking", "SW5E.WeaponPropertiesRap": "Rapid",
"SW5E.WeaponPropertiesSpc": "Special", "SW5E.WeaponPropertiesRch": "Reach",
"SW5E.WeaponPropertiesStr": "Strength Rqmt.", "SW5E.WeaponPropertiesRel": "Reload",
"SW5E.WeaponPropertiesThr": "Thrown", "SW5E.WeaponPropertiesRet": "Returning",
"SW5E.WeaponPropertiesTwo": "Two-Handed", "SW5E.WeaponPropertiesShk": "Shocking",
"SW5E.WeaponPropertiesVer": "Versatile", "SW5E.WeaponPropertiesSil": "Silent",
"SW5E.WeaponPropertiesVic": "Vicious", "SW5E.WeaponPropertiesSpc": "Special",
"SW5E.WeaponPropertiesStr": "Strength Rqmt.",
"SW5E.WeaponPropertiesThr": "Thrown",
"SW5E.WeaponPropertiesTwo": "Two-Handed",
"SW5E.WeaponPropertiesVer": "Versatile",
"SW5E.WeaponPropertiesVic": "Vicious",
"SW5E.WeaponSimpleVW": "Simple Vibroweapon", "SW5E.WeaponSimpleVW": "Simple Vibroweapon",
"SW5E.WeaponSimpleProficiency": "Simple Weapons", "SW5E.WeaponSimpleProficiency": "Simple Weapons",
"SW5E.WeaponSimpleB": "Simple Blaster", "SW5E.WeaponSimpleB": "Simple Blaster",
"SW5E.WeaponSimpleLW": "Simple Lightweapon", "SW5E.WeaponSimpleLW": "Simple Lightweapon",
"SW5E.Weight": "Weight", "SW5E.Weight": "Weight",
"SW5E.available": "available", "SW5E.available": "available",
"SW5E.description": "A comprehensive game system for running games of Dungeons & Dragons 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.power": "power", "SW5E.power": "power",
"SETTINGS.5eAllowPolymorphingL": "Allow players to polymorph their own actors.", "SETTINGS.5eAllowPolymorphingL": "Allow players to polymorph their own actors.",
@ -775,12 +837,19 @@
"SETTINGS.5eAutoPowerTemplateN": "Always place Power Template", "SETTINGS.5eAutoPowerTemplateN": "Always place Power Template",
"SETTINGS.5eCurWtL": "Carried currency affects character encumbrance following the rules on PHB pg. 143.", "SETTINGS.5eCurWtL": "Carried currency affects character encumbrance following the rules on PHB pg. 143.",
"SETTINGS.5eCurWtN": "Apply Currency Weight", "SETTINGS.5eCurWtN": "Apply Currency Weight",
"SETTINGS.5eDiagDMG": "Dungeon Master's Guide (5/10/5)",
"SETTINGS.5eDiagEuclidean": "Euclidean (7.07 ft. Diagonal)",
"SETTINGS.5eDiagL": "Configure which diagonal movement rule should be used for games within this system.", "SETTINGS.5eDiagL": "Configure which diagonal movement rule should be used for games within this system.",
"SETTINGS.5eDiagN": "Diagonal Movement Rule", "SETTINGS.5eDiagN": "Diagonal Movement Rule",
"SETTINGS.5eDiagPHB": "Player's Handbook (5/5/5)", "SETTINGS.5eDiagPHB": "PHB: Equidistant (5/5/5)",
"SETTINGS.5eDiagDMG": "DMG: Alternating (5/10/5)",
"SETTINGS.5eInitTBL": "Append the raw Dexterity ability score to break ties in Initiative.", "SETTINGS.5eInitTBL": "Append the raw Dexterity ability score to break ties in Initiative.",
"SETTINGS.5eInitTBN": "Initiative Dexterity Tiebreaker", "SETTINGS.5eInitTBN": "Initiative Dexterity Tiebreaker",
"SETTINGS.5eNoExpL": "Remove experience bars from character sheets.", "SETTINGS.5eNoExpL": "Remove experience bars from character sheets.",
"SETTINGS.5eNoExpN": "Disable Experience Tracking" "SETTINGS.5eNoExpN": "Disable Experience Tracking",
"SETTINGS.5eRestL": "Configure which rest variant should be used for games within this system.",
"SETTINGS.5eRestN": "Rest Variant",
"SETTINGS.5eRestPHB": "Player's Handbook (LR: 8 hours, SR: 1 hour)",
"SETTINGS.5eRestGritty": "Gritty Realism (LR: 7 days, SR: 8 hours)",
"SETTINGS.5eRestEpic": "Epic Heroism (LR: 1 hour, SR: 1 min)"
} }

View file

@ -1,597 +0,0 @@
{
"Star Wars 5th Edition": "Star Wars 5th Edition",
"SW5E.title": "Star Wars 5th Edition",
"SW5E.AbbreviationCR": "CR",
"SW5E.AbbreviationConc": "Conc.",
"SW5E.AbbreviationDC": "DC",
"SW5E.AbbreviationLR": "LR",
"SW5E.AbbreviationLbs": "lbs.",
"SW5E.AbbreviationSR": "SR",
"SW5E.Ability": "Ability",
"SW5E.AbilityCha": "Charisma",
"SW5E.AbilityCon": "Constitution",
"SW5E.AbilityDex": "Dexterity",
"SW5E.AbilityInt": "Intelligence",
"SW5E.AbilityModifier": "Ability Modifier",
"SW5E.AbilityStr": "Strength",
"SW5E.AbilityUseCantUse": "You are not currently able to use this ability!",
"SW5E.AbilityUseCharged": "charged",
"SW5E.AbilityUseConsume": "Consume Available Usage?",
"SW5E.AbilityUseDepleted": "depleted",
"SW5E.AbilityUseHint": "Configure how you would like to use the",
"SW5E.AbilityUseRechargeHint": "This ability uses a recharge mechanic and is currently",
"SW5E.AbilityUseWarnEnd": "available uses per",
"SW5E.AbilityUseWarnStart": "This ability has",
"SW5E.AbilityWis": "Wisdom",
"SW5E.Action": "Action",
"SW5E.ActionAbil": "Ability Check",
"SW5E.ActionHeal": "Healing",
"SW5E.ActionMPAK": "Melee Power Attack",
"SW5E.ActionMWAK": "Melee Weapon Attack",
"SW5E.ActionOther": "Other",
"SW5E.ActionRPAK": "Ranged Power Attack",
"SW5E.ActionRWAK": "Ranged Weapon Attack",
"SW5E.ActionSave": "Saving Throw",
"SW5E.ActionUtil": "Utility",
"SW5E.Add": "Add",
"SW5E.Advantage": "Advantage",
"SW5E.Alignment": "Alignment",
"SW5E.AlignmentCD": "Chaotic Dark",
"SW5E.AlignmentCL": "Chaotic Light",
"SW5E.AlignmentCN": "Chaotic Neutral",
"SW5E.AlignmentLD": "Lawful Dark",
"SW5E.AlignmentLL": "Lawful Light",
"SW5E.AlignmentLN": "Lawful Neutral",
"SW5E.AlignmentND": "Neutral Dark",
"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",
"SW5E.Background": "Background",
"SW5E.Biography": "Biography",
"SW5E.BonusAbilityCheck": "Global Ability Check Bonus",
"SW5E.BonusAbilitySave": "Global Saving Throw Bonus",
"SW5E.BonusAbilitySkill": "Global Skill Check Bonus",
"SW5E.BonusAction": "Bonus Action",
"SW5E.BonusMSAttack": "Melee Power Attack Bonus",
"SW5E.BonusMSDamage": "Melee Power Damage Bonus",
"SW5E.BonusMWAttack": "Melee Weapon Attack Bonus",
"SW5E.BonusMWDamage": "Melee Weapon Damage Bonus",
"SW5E.BonusRSAttack": "Ranged Power Attack Bonus",
"SW5E.BonusRSDamage": "Ranged Power Damage Bonus",
"SW5E.BonusRWAttack": "Ranged Weapon Attack Bonus",
"SW5E.BonusRWDamage": "Ranged Weapon Damage Bonus",
"SW5E.BonusSaveForm": "Update Bonuses",
"SW5E.BonusPowerDC": "Global Power DC Bonus",
"SW5E.BonusTitle": "Configure Actor Bonuses",
"SW5E.Bonuses": "Global Bonuses",
"SW5E.BonusesHint": "Define global bonuses as formulas which are added to certain rolls. For example: 1d4 + 2",
"SW5E.BonusesInstructions": "Configure character bonuses which are added to the appropriate dice roll",
"SW5E.ChallengeRating": "Challenge Rating",
"SW5E.Charged": "Charged",
"SW5E.Charges": "Charges",
"SW5E.ChatContextDamage": "Apply Damage",
"SW5E.ChatContextHealing": "Apply Healing",
"SW5E.ChatContextDoubleDamage": "Apply Double Damage",
"SW5E.ChatContextHalfDamage": "Apply Half Damage",
"SW5E.ChatFlavor": "Chat Message Flavor",
"SW5E.ClassLevels": "Class Levels",
"SW5E.ClassName": "Class Name",
"SW5E.ClassSkillsNumber": "Number of Starting Skills",
"SW5E.ClassSkillsChosen": "Chosen Class Skills",
"SW5E.ComponentMaterial": "Material",
"SW5E.ComponentSomatic": "Somatic",
"SW5E.ComponentVerbal": "Verbal",
"SW5E.ConBlinded": "Blinded",
"SW5E.ConCharmed": "Charmed",
"SW5E.ConDeafened": "Deafened",
"SW5E.ConExhaustion": "Exhaustion",
"SW5E.ConFrightened": "Frightened",
"SW5E.ConGrappled": "Grappled",
"SW5E.ConImm": "Condition Immunities",
"SW5E.ConIncapacitated": "Incapacitated",
"SW5E.ConInvisible": "Invisible",
"SW5E.ConParalyzed": "Paralyzed",
"SW5E.ConPetrified": "Petrified",
"SW5E.ConPoisoned": "Poisoned",
"SW5E.ConProne": "Prone",
"SW5E.ConRestrained": "Restrained",
"SW5E.ConShocked": "Shocked",
"SW5E.ConStunned": "Stunned",
"SW5E.ConUnconscious": "Unconscious",
"SW5E.Concentration": "Concentration",
"SW5E.ConsumableFood": "Food",
"SW5E.ConsumablePoison": "Poison",
"SW5E.ConsumableAdrenal": "Adrenal",
"SW5E.ConsumableExplosive": "Explosive",
"SW5E.ConsumableMedpac": "Medpac",
"SW5E.ConsumableTrinket": "Trinket",
"SW5E.ConsumableTechnology": "Technology",
"SW5E.ConsumableAmmunition": "Ammunition",
"SW5E.Consumed": "Consumed",
"SW5E.CostGP": "Cost (GP)",
"SW5E.Critical": "Critical",
"SW5E.CriticalHit": "Critical Hit",
"SW5E.Currency": "Currency",
"SW5E.CurrencyConvert": "Convert All Currency",
"SW5E.CurrencyConvertHint": "Convert all carried currency to the highest possible denomination to reduce the amount of coinage carried by the character. Be wary, this action cannot be undone.",
"SW5E.CurrencyGC": "Credits",
"SW5E.DamImm": "Damage Immunities",
"SW5E.DamRes": "Damage Resistances",
"SW5E.DamVuln": "Damage Vulnerabilities",
"SW5E.Damage": "Damage",
"SW5E.DamageAcid": "Acid",
"SW5E.DamageCold": "Cold",
"SW5E.DamageEnergy": "Energy",
"SW5E.DamageFire": "Fire",
"SW5E.DamageForce": "Force",
"SW5E.DamageIon": "ION",
"SW5E.DamageKinetic": "Kinetic",
"SW5E.DamageLightning": "Lightning",
"SW5E.DamageNecrotic": "Necrotic",
"SW5E.DamagePoison": "Poison",
"SW5E.DamagePsychic": "Psychic",
"SW5E.DamageSonic": "Sonic",
"SW5E.Day": "Day",
"SW5E.DeathSave": "Death Saves",
"SW5E.Default": "Default",
"SW5E.DefaultAbilityCheck": "Default Ability Check",
"SW5E.Description": "Description",
"SW5E.Details": "Details",
"SW5E.Disadvantage": "Disadvantage",
"SW5E.DistAny": "Any",
"SW5E.DistFt": "Feet",
"SW5E.DistMi": "Miles",
"SW5E.DistSelf": "Self",
"SW5E.DistTouch": "Touch",
"SW5E.Duration": "Duration",
"SW5E.EquipmentBonus": "Magical Bonus",
"SW5E.EquipmentClothing": "Clothing",
"SW5E.EquipmentHeavy": "Heavy Armor",
"SW5E.EquipmentLight": "Light Armor",
"SW5E.EquipmentMedium": "Medium Armor",
"SW5E.EquipmentNatural": "Natural Armor",
"SW5E.EquipmentShield": "Shield",
"SW5E.EquipmentShieldProficiency": "Shields",
"SW5E.EquipmentTrinket": "Trinket",
"SW5E.Equipped": "Equipped",
"SW5E.Exhaustion": "Exhaustion",
"SW5E.Expertise": "Expertise",
"SW5E.FeatureActionRecharge": "Action Recharge",
"SW5E.ItemTypeClass": "Class",
"SW5E.ItemTypeClassPl": "Class Levels",
"SW5E.ItemTypeConsumable": "Consumable",
"SW5E.ItemTypeConsumablePl": "Consumables",
"SW5E.ItemTypeContainer": "Container",
"SW5E.ItemTypeContainerPl": "Containers",
"SW5E.ItemTypeEquipment": "Equipment",
"SW5E.ItemTypeEquipmentPl": "Equipment",
"SW5E.ItemTypeLoot": "Loot",
"SW5E.ItemTypeLootPl": "Loot",
"SW5E.ItemTypeSpecies": "Species",
"SW5E.ItemTypeSpeciesPl": "Species",
"SW5E.ItemTypeTool": "Tool",
"SW5E.ItemTypeToolPl": "Tools",
"SW5E.ItemTypePower": "Power",
"SW5E.ItemTypePowerPl": "Powers",
"SW5E.ItemTypeWeapon": "Weapon",
"SW5E.ItemTypeWeaponPl": "Weapons",
"SW5E.FeatureActive": "Active Abilities",
"SW5E.FeatureAdd": "Create Feature",
"SW5E.FeatureAttack": "Feature Attack",
"SW5E.FeaturePassive": "Passive Abilities",
"SW5E.FeatureRechargeOn": "Recharge On",
"SW5E.FeatureRechargeResult": "1d6 Result",
"SW5E.FeatureUsage": "Feature Usage",
"SW5E.Features": "Features",
"SW5E.Filter": "Filter",
"SW5E.FilterNoPowers": "No powers found for this set of filters.",
"SW5E.NoPowerLevels": "This character has no powercaster levels, but you may add powers manually.",
"SW5E.FlagsInstructions": "Configure character features and traits which fine-tune behaviors of the SW5e system.",
"SW5E.FlagsSave": "Update Special Traits",
"SW5E.FlagsTitle": "Configure Special Traits",
"SW5E.Flat": "Flat",
"SW5E.Formula": "Formula",
"SW5E.GrantedAbilities": "Granted Abilities",
"SW5E.HalfProficient": "Half Proficient",
"SW5E.Healing": "Healing",
"SW5E.HealingTemp": "Healing (Temporary)",
"SW5E.Health": "Health",
"SW5E.HealthFormula": "Health Formula",
"SW5E.HitDice": "Hit Dice",
"SW5E.HitDiceUsed": "Hit Dice Used",
"SW5E.Identified": "Identified",
"SW5E.Initiative": "Initiative",
"SW5E.Inspiration": "Inspiration",
"SW5E.Inventory": "Inventory",
"SW5E.ItemActionType": "Action Type",
"SW5E.ItemActivationCondition": "Activation Condition",
"SW5E.ItemActivationCost": "Activation Cost",
"SW5E.ItemAttackBonus": "Attack Roll Bonus",
"SW5E.ItemConsumableActivation": "Consumable Activation",
"SW5E.ItemConsumableDetails": "Consumable Details",
"SW5E.ItemConsumableStatus": "Consumable Status",
"SW5E.ItemConsumableType": "Consumable Type",
"SW5E.ItemConsumableUsage": "Consumable Usage",
"SW5E.ItemConsumeOnUse": "Consume on Use",
"SW5E.ItemContainerCapacity": "Capacity",
"SW5E.ItemContainerCapacityItems": "Items",
"SW5E.ItemContainerCapacityType": "Capacity Type",
"SW5E.ItemContainerCapacityWeight": "Weight",
"SW5E.ItemContainerDetails": "Container Details",
"SW5E.ItemContainerProperties": "Container Properties",
"SW5E.ItemContainerWeightless": "Weightless Contents",
"SW5E.ItemCreate": "Create Item",
"SW5E.ItemDelete": "Delete Item",
"SW5E.ItemDestroyEmpty": "Destroy on Empty",
"SW5E.ItemEdit": "Edit Item",
"SW5E.ItemEquipmentAction": "Equipment Action",
"SW5E.ItemEquipmentDetails": "Equipment Details",
"SW5E.ItemEquipmentDexMod": "Max. Dexterity Modifier",
"SW5E.ItemEquipmentStatus": "Equipment Status",
"SW5E.ItemEquipmentStealthDisav": "Imposes Stealth Disadvantage",
"SW5E.ItemEquipmentType": "Equipment Type",
"SW5E.ItemEquipmentUsage": "Equipment Usage",
"SW5E.ItemName": "Item Name",
"SW5E.ItemRequiredStr": "Required Strength",
"SW5E.ItemToolProficiency": "Tool Proficiency",
"SW5E.ItemWeaponAttack": "Weapon Attack",
"SW5E.ItemWeaponDetails": "Weapon Details",
"SW5E.ItemWeaponProperties": "Weapon Properties",
"SW5E.ItemWeaponStatus": "Weapon Status",
"SW5E.ItemWeaponType": "Weapon Type",
"SW5E.ItemWeaponUsage": "Weapon Usage",
"SW5E.JackOfAllTrades": "Jack of all Trades",
"SW5E.LairAct": "Lair Action",
"SW5E.Languages": "Languages",
"SW5E.LanguagesBasic": "Basic",
"SW5E.LanguagesBinary": "Binary",
"SW5E.LanguagesBith": "Bith",
"SW5E.LanguagesBocce": "Bocce",
"SW5E.LanguagesBothese": "Bothese",
"SW5E.LanguagesCartharese": "Catharese",
"SW5E.LanguagesCheunh": "Cheunh",
"SW5E.LanguagesDurese": "Durese",
"SW5E.LanguagesDug": "Dug",
"SW5E.LanguagesEwokese": "Ewokese",
"SW5E.LanguagesGamorrese": "Gamorrese",
"SW5E.LanguagesGeonosian": "Geonosian",
"SW5E.LanguagesHapan": "Hapan",
"SW5E.LanguagesHuttese": "Huttese",
"SW5E.LanguagesJawaese": "Jawaese",
"SW5E.LanguagesKaleesh": "Kaleesh",
"SW5E.LanguagesKaminoan": "Kaminoan",
"SW5E.LanguagesKelDor": "Kel Dor",
"SW5E.LanguagesMandoa": "Mando'a",
"SW5E.LanguagesMonCal": "Mon Cal",
"SW5E.LanguagesPakPak": "Pak Pak",
"SW5E.LanguagesRodese": "Rodese",
"SW5E.LanguagesSith": "Sith",
"SW5E.LanguagesTogruti": "Togruti",
"SW5E.LanguagesDosh": "Dosh",
"SW5E.LanguagesTwileki": "Twi'leki",
"SW5E.LanguagesTusken": "Tusken",
"SW5E.LanguagesShyriiwook": "Shyriiwook",
"SW5E.LanguagesZabraki": "Zabraki",
"SW5E.LanguagesVong": "Vong",
"SW5E.LegAct": "Legd. Actions",
"SW5E.LegRes": "Legd. Resistance",
"SW5E.Level": "Level",
"SW5E.LevelScaling": "Level Scaling",
"SW5E.LimitedUses": "Limited Uses",
"SW5E.LongRest": "Long Rest",
"SW5E.Max": "Max",
"SW5E.Modifier": "Modifier",
"SW5E.Name": "Character Name",
"SW5E.NoCharges": "No Charges",
"SW5E.None": "None",
"SW5E.Normal": "Normal",
"SW5E.NotProficient": "Not Proficient",
"SW5E.OtherFormula": "Other Formula",
"SW5E.PlaceTemplate": "Place Measured Template",
"SW5E.Polymorph": "Polymorph",
"SW5E.PolymorphAcceptSettings": "Custom Settings",
"SW5E.PolymorphKeepBio": "Keep biography",
"SW5E.PolymorphKeepClass": "Keep proficiency bonus (leaves class items in sheet)",
"SW5E.PolymorphKeepFeats": "Keep features",
"SW5E.PolymorphKeepItems": "Keep equipment",
"SW5E.PolymorphKeepMental": "Keep mental ability scores (Int, Wis, Cha)",
"SW5E.PolymorphKeepPhysical": "Keep physical ability scores (Str, Dex, Con)",
"SW5E.PolymorphKeepSaves": "Keep saving throw proficiencies",
"SW5E.PolymorphKeepSkills": "Keep skill proficiencies",
"SW5E.PolymorphKeepPowers": "Keep powers",
"SW5E.PolymorphKeepVision": "Keep vision (character and token)",
"SW5E.PolymorphMergeSaves": "Merge saving throw proficiencies (take the highest)",
"SW5E.PolymorphMergeSkills": "Merge skill proficiencies (take the highest)",
"SW5E.PolymorphPromptTitle": "Transforming Actor",
"SW5E.PolymorphRestoreTransformation": "Restore Transformation",
"SW5E.PolymorphTmpClass": "Temporary Class",
"SW5E.PolymorphTokens": "Transform all linked tokens?",
"SW5E.PolymorphWildShape": "Wild Shape",
"SW5E.Concentrated": "Concentrate",
"SW5E.Price": "Price",
"SW5E.Proficiency": "Proficiency",
"SW5E.Proficient": "Proficient",
"SW5E.Quantity": "Quantity",
"SW5E.Species": "Species",
"SW5E.Range": "Range",
"SW5E.Rarity": "Rarity",
"SW5E.Reaction": "Reaction",
"SW5E.RequiredMaterials": "Required Materials",
"SW5E.Requirements": "Requirements",
"SW5E.ResourcePrimary": "Resource 1",
"SW5E.ResourceSecondary": "Resource 2",
"SW5E.ResourceTertiary": "Resource 3",
"SW5E.RestL": "L. Rest",
"SW5E.RestS": "S. Rest",
"SW5E.Ritual": "Ritual",
"SW5E.Roll": "Roll",
"SW5E.RollExample": "e.g. +1d4",
"SW5E.RollMode": "Roll Mode",
"SW5E.RollSituationalBonus": "Situational Bonus?",
"SW5E.Save": "Save",
"SW5E.ScalingFormula": "Scaling Formula",
"SW5E.SchoolLgt": "Light",
"SW5E.SchoolUni": "Universal",
"SW5E.SchoolDrk": "Dark",
"SW5E.SchoolTec": "Tech",
"SW5E.SchoolEnh": "Enhancement",
"SW5E.SenseBS": "Blindsight",
"SW5E.SenseDV": "Darkvision",
"SW5E.SenseTR": "Truesight",
"SW5E.SenseTS": "Tremorsense",
"SW5E.Senses": "Senses",
"SW5E.ShortRest": "Short Rest",
"SW5E.ShortRestHint": "Take a short rest? On a short rest you may spend remaining Hit Dice and recover primary or secondary resources.",
"SW5E.ShortRestNoHD": "No Hit Dice remaining",
"SW5E.ShortRestSelect": "Select Dice to Roll",
"SW5E.Size": "Size",
"SW5E.SizeGargantuan": "Gargantuan",
"SW5E.SizeHuge": "Huge",
"SW5E.SizeLarge": "Large",
"SW5E.SizeMedium": "Medium",
"SW5E.SizeSmall": "Small",
"SW5E.SizeTiny": "Tiny",
"SW5E.SkillAcr": "Acrobatics",
"SW5E.SkillAni": "Animal Handling",
"SW5E.SkillAth": "Athletics",
"SW5E.SkillDec": "Deception",
"SW5E.SkillIns": "Insight",
"SW5E.SkillInv": "Investigation",
"SW5E.SkillItm": "Intimidation",
"SW5E.SkillLor": "Lore",
"SW5E.SkillMed": "Medicine",
"SW5E.SkillNat": "Nature",
"SW5E.SkillPer": "Persuasion",
"SW5E.SkillPrc": "Perception",
"SW5E.SkillPrf": "Performance",
"SW5E.SkillPil": "Piloting",
"SW5E.SkillSlt": "Sleight of Hand",
"SW5E.SkillSte": "Stealth",
"SW5E.SkillSur": "Survival",
"SW5E.SkillTec": "Technology",
"SW5E.Slots": "Slots",
"SW5E.Source": "Source",
"SW5E.Special": "Special",
"SW5E.SpecialTraits": "Special Traits",
"SW5E.Speed": "Speed",
"SW5E.SpeedSpecial": "Special Movement",
"SW5E.PowerAbility": "Powercasting Ability",
"SW5E.PowerAdd": "Add Power",
"SW5E.PowerAtWill": "At-Will",
"SW5E.PowerCastConsume": "Consume Power Slot?",
"SW5E.PowerCastHint": "Configure how you would like to cast the",
"SW5E.PowerCastNoSlots": "You have no available power slots to cast this power",
"SW5E.PowerCastUpcast": "Cast at Level",
"SW5E.PowercasterLevel": "Powercaster Level",
"SW5E.PowerCastingHeader": "Power Casting",
"SW5E.Powercasting": "Powercasting",
"SW5E.PowerComponents": "Power Components",
"SW5E.PowerCreate": "Create Power",
"SW5E.PowerDC": "Power DC",
"SW5E.PowerDetails": "Power Details",
"SW5E.PowerEffects": "Power Effects",
"SW5E.PowerLevel": "Power Level",
"SW5E.PowerLevel0": "At-Will",
"SW5E.PowerLevel1": "1st Level",
"SW5E.PowerLevel2": "2nd Level",
"SW5E.PowerLevel3": "3rd Level",
"SW5E.PowerLevel4": "4th Level",
"SW5E.PowerLevel5": "5th Level",
"SW5E.PowerLevel6": "6th Level",
"SW5E.PowerLevel7": "7th Level",
"SW5E.PowerLevel8": "8th Level",
"SW5E.PowerLevel9": "9th Level",
"SW5E.PowerLevelPact": "Pact Slot",
"SW5E.PowerMaterials": "Powercasting Materials",
"SW5E.PowerName": "Power Name",
"SW5E.PowerNone": "None",
"SW5E.PowerPrepAtWill": "At-Will",
"SW5E.PowerPrepInnate": "Innate Powercasting",
"SW5E.PowerPrepPrepared": "Prepared",
"SW5E.PowerPrepAlways": "Always Prepared",
"SW5E.PowerConcentrationMode": "Power Concentration Mode",
"SW5E.PowerConcentrating": "Concentrating",
"SW5E.PowerProgArt": "Artificer",
"SW5E.PowerProgFull": "Full Caster",
"SW5E.PowerProgOverride": "Override slots",
"SW5E.PowerProgression": "Power Progression",
"SW5E.PowerSchool": "Power School",
"SW5E.PowerTarget": "Power Target",
"SW5E.PowerUnprepared": "Unprepared",
"SW5E.PowerUsage": "Power Usage",
"SW5E.Powerbook": "Powerbook",
"SW5E.SpeciesTraits": "Species Traits",
"SW5E.SubclassName": "Subclass Name",
"SW5E.Supply": "Supply",
"SW5E.Target": "Target",
"SW5E.TargetAlly": "Ally",
"SW5E.TargetCone": "Cone",
"SW5E.TargetCreature": "Creature",
"SW5E.TargetCube": "Cube",
"SW5E.TargetCylinder": "Cylinder",
"SW5E.TargetEnemy": "Enemy",
"SW5E.TargetLine": "Line",
"SW5E.TargetObject": "Object",
"SW5E.TargetRadius": "Radius",
"SW5E.TargetSelf": "Self",
"SW5E.TargetSpace": "Space",
"SW5E.TargetSphere": "Sphere",
"SW5E.TargetSquare": "Square",
"SW5E.TargetWall": "Wall",
"SW5E.TargetDroid": "Droid",
"SW5E.Temp": "Temp",
"SW5E.TimeDay": "Days",
"SW5E.TimeHour": "Hours",
"SW5E.TimeInst": "Instantaneous",
"SW5E.TimeMinute": "Minutes",
"SW5E.TimeMonth": "Months",
"SW5E.TimePerm": "Permanent",
"SW5E.TimeRound": "Rounds",
"SW5E.TimeTurn": "Turns",
"SW5E.TimeYear": "Years",
"SW5E.ToolArmormech": "Armormech's Tools",
"SW5E.ToolArmstech": "Armstech's Tools",
"SW5E.ToolArtificer": "Artificer's Tools",
"SW5E.ToolArtist": "Artist's Tools",
"SW5E.ToolAstrotech": "Astrotech's Tools",
"SW5E.ToolBiotech": "Biotech's Tools",
"SW5E.ToolConstructor": "Constructor's Tools",
"SW5E.ToolCybertech": "Cybertech's Tools",
"SW5E.ToolJeweler": "Jeweler's Tools",
"SW5E.ToolSurveyor": "Surveyor's Tools",
"SW5E.ToolSynthweaver": "Synthweavers's Tools",
"SW5E.ToolTinker": "Tinker's Tools",
"SW5E.ToolAntitoxkit": "Antitoxkit",
"SW5E.ToolArchaeologistKit": "Archaeologist Kit",
"SW5E.ToolAudiotechKit": "Audiotech's Kit",
"SW5E.ToolBioanalysisKit": "Bioanalysis Kit",
"SW5E.ToolBrewerKit": "Brewer's Kit",
"SW5E.ToolChefKit": "Chef's Kit",
"SW5E.ToolDemolitionKit": "Demolition Kit",
"SW5E.ToolDisguiseKit": "Disguise Kit",
"SW5E.ToolForgeryKit": "Forgery Kit",
"SW5E.ToolMechanicKit": "Mechanic's Kit",
"SW5E.ToolMunitionsKit": "Munitions Kit",
"SW5E.ToolPoisonKit": "Poisoner's Kit",
"SW5E.ToolScavengingKit": "Scavenging Kit",
"SW5E.ToolSecurityKit": "Security Kit",
"SW5E.ToolSlicerKit": "Slicer's Kit",
"SW5E.ToolSpiceKit": "Spicer's Kit",
"SW5E.ToolGamingSet": "Gaming Set",
"SW5E.ToolMusicalInstrument": "Musical Instrument",
"SW5E.ToolVehicle": "Vehicle (Land or Water)",
"SW5E.TraitArmorProf": "Armor Proficiencies",
"SW5E.TraitSelectorSpecial": "Special (Split with Semi-Colon)",
"SW5E.TraitToolProf": "Tool Proficiencies",
"SW5E.TraitWeaponProf": "Weapon Proficiencies",
"SW5E.Type": "Type",
"SW5E.Unequipped": "Not Equipped",
"SW5E.Unlimited": "Unlimited",
"SW5E.Usage": "Usage",
"SW5E.Use": "Use",
"SW5E.Uses": "Uses",
"SW5E.Versatile": "Versatile",
"SW5E.VersatileDamage": "Versatile Damage",
"SW5E.VsDC": "vs DC.",
"SW5E.WeaponAmmo": "Ammunition",
"SW5E.WeaponImprov": "Improvised",
"SW5E.WeaponMartialVW": "Martial Vibroweapon",
"SW5E.WeaponMartialProficiency": "Martial Weapons",
"SW5E.WeaponMartialB": "Martial Blaster",
"SW5E.WeaponMartialLW": "Martial Lightweapon",
"SW5E.WeaponNatural": "Natural",
"SW5E.WeaponPropertiesAmm": "Ammunition",
"SW5E.WeaponPropertiesBur": "Burst",
"SW5E.WeaponPropertiesDef": "Defensive",
"SW5E.WeaponPropertiesDex": "Dexterity Rqmt.",
"SW5E.WeaponPropertiesDrm": "Disarming",
"SW5E.WeaponPropertiesDgd": "Disguised",
"SW5E.WeaponPropertiesDis": "Disintegrate",
"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",
"SW5E.WeaponPropertiesRan": "Range",
"SW5E.WeaponPropertiesRap": "Rapid",
"SW5E.WeaponPropertiesRch": "Reach",
"SW5E.WeaponPropertiesRel": "Reload",
"SW5E.WeaponPropertiesRet": "Returning",
"SW5E.WeaponPropertiesShk": "Shocking",
"SW5E.WeaponPropertiesSpc": "Special",
"SW5E.WeaponPropertiesStr": "Strength Rqmt.",
"SW5E.WeaponPropertiesThr": "Thrown",
"SW5E.WeaponPropertiesTwo": "Two-Handed",
"SW5E.WeaponPropertiesVer": "Versatile",
"SW5E.WeaponPropertiesVic": "Vicious",
"SW5E.WeaponSimpleVW": "Simple Vibroweapon",
"SW5E.WeaponSimpleProficiency": "Simple Weapons",
"SW5E.WeaponSimpleB": "Simple Blaster",
"SW5E.WeaponSimpleLW": "Simple Lightweapon",
"SW5E.Weight": "Weight",
"SW5E.available": "available",
"SW5E.description": "A comprehensive game system for running games of Dungeons & Dragons 5th Edition in the Foundry VTT environment.",
"SW5E.of": "of",
"SW5E.power": "power",
"SETTINGS.5eAllowPolymorphingL": "Allow players to polymorph their own actors.",
"SETTINGS.5eAllowPolymorphingN": "Allow Polymorphing",
"SETTINGS.5eAutoCollapseCardL": "Automatically collapse Item Card descriptions in the Chat Log",
"SETTINGS.5eAutoCollapseCardN": "Collapse Item Cards in Chat",
"SETTINGS.5eAutoPowerTemplateL": "When a power is cast, defaults to begin the process to create the corresponding Measured Template if any (requires TRUSTED or higher player role)",
"SETTINGS.5eAutoPowerTemplateN": "Always place Power Template",
"SETTINGS.5eCurWtL": "Carried currency affects character encumbrance following the rules on PHB pg. 143.",
"SETTINGS.5eCurWtN": "Apply Currency Weight",
"SETTINGS.5eDiagDMG": "Dungeon Master's Guide (5/10/5)",
"SETTINGS.5eDiagL": "Configure which diagonal movement rule should be used for games within this system.",
"SETTINGS.5eDiagN": "Diagonal Movement Rule",
"SETTINGS.5eDiagPHB": "Player's Handbook (5/5/5)",
"SETTINGS.5eInitTBL": "Append the raw Dexterity ability score to break ties in Initiative.",
"SETTINGS.5eInitTBN": "Initiative Dexterity Tiebreaker",
"SETTINGS.5eNoExpL": "Remove experience bars from character sheets.",
"SETTINGS.5eNoExpN": "Disable Experience Tracking"
}

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,14 @@
import {TraitSelector} from "../../apps/trait-selector.js"; import Item5e from "../../item/entity.js";
import {ActorSheetFlags} from "../../apps/actor-flags.js"; import TraitSelector from "../../apps/trait-selector.js";
import ActorSheetFlags from "../../apps/actor-flags.js";
import {SW5E} from '../../config.js'; import {SW5E} from '../../config.js';
/** /**
* Extend the basic ActorSheet class to do all the D&D5e things! * Extend the basic ActorSheet class to do all the SW5e things!
* This sheet is an Abstract layer which is not used. * This sheet is an Abstract layer which is not used.
* * @extends {ActorSheet}
* @type {ActorSheet}
*/ */
export class ActorSheet5e extends ActorSheet { export default class ActorSheet5e extends ActorSheet {
constructor(...args) { constructor(...args) {
super(...args); super(...args);
@ -19,7 +19,8 @@ export class ActorSheet5e extends ActorSheet {
this._filters = { this._filters = {
inventory: new Set(), inventory: new Set(),
powerbook: new Set(), powerbook: new Set(),
features: new Set() features: new Set(),
effects: new Set()
}; };
} }
@ -31,12 +32,20 @@ export class ActorSheet5e extends ActorSheet {
scrollY: [ scrollY: [
".inventory .inventory-list", ".inventory .inventory-list",
".features .inventory-list", ".features .inventory-list",
".powerbook .inventory-list" ".powerbook .inventory-list",
".effects .inventory-list"
], ],
tabs: [{navSelector: ".tabs", contentSelector: ".sheet-body", initial: "description"}] tabs: [{navSelector: ".tabs", contentSelector: ".sheet-body", initial: "description"}]
}); });
} }
/* -------------------------------------------- */
/** @override */
get template() {
if ( !game.user.isGM && this.actor.limited ) return "systems/sw5e/templates/actors/limited-sheet.html";
return `systems/sw5e/templates/actors/${this.actor.data.type}-sheet.html`;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -53,6 +62,7 @@ export class ActorSheet5e extends ActorSheet {
cssClass: isOwner ? "editable" : "locked", cssClass: isOwner ? "editable" : "locked",
isCharacter: this.entity.data.type === "character", isCharacter: this.entity.data.type === "character",
isNPC: this.entity.data.type === "npc", isNPC: this.entity.data.type === "npc",
isVehicle: this.entity.data.type === 'vehicle',
config: CONFIG.SW5E, config: CONFIG.SW5E,
}; };
@ -74,12 +84,14 @@ export class ActorSheet5e extends ActorSheet {
abl.label = CONFIG.SW5E.abilities[a]; abl.label = CONFIG.SW5E.abilities[a];
} }
// Update skill labels // Skills
for ( let [s, skl] of Object.entries(data.actor.data.skills)) { if (data.actor.data.skills) {
skl.ability = data.actor.data.abilities[skl.ability].label.substring(0, 3); for ( let [s, skl] of Object.entries(data.actor.data.skills)) {
skl.icon = this._getProficiencyIcon(skl.value); skl.ability = CONFIG.SW5E.abilityAbbreviations[skl.ability];
skl.hover = CONFIG.SW5E.proficiencyLevels[skl.value]; skl.icon = this._getProficiencyIcon(skl.value);
skl.label = CONFIG.SW5E.skills[s]; skl.hover = CONFIG.SW5E.proficiencyLevels[skl.value];
skl.label = CONFIG.SW5E.skills[s];
}
} }
// Update traits // Update traits
@ -88,17 +100,25 @@ export class ActorSheet5e extends ActorSheet {
// Prepare owned items // Prepare owned items
this._prepareItems(data); this._prepareItems(data);
// Prepare active effects
this._prepareEffects(data);
// Return data to the sheet // Return data to the sheet
return data return data
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/**
* 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
* @private
*/
_prepareTraits(traits) { _prepareTraits(traits) {
const map = { const map = {
"dr": CONFIG.SW5E.damageTypes, "dr": CONFIG.SW5E.damageResistanceTypes,
"di": CONFIG.SW5E.damageTypes, "di": CONFIG.SW5E.damageResistanceTypes,
"dv": CONFIG.SW5E.damageTypes, "dv": CONFIG.SW5E.damageResistanceTypes,
"ci": CONFIG.SW5E.conditionTypes, "ci": CONFIG.SW5E.conditionTypes,
"languages": CONFIG.SW5E.languages, "languages": CONFIG.SW5E.languages,
"armorProf": CONFIG.SW5E.armorProficiencies, "armorProf": CONFIG.SW5E.armorProficiencies,
@ -127,6 +147,43 @@ export 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
@ -153,18 +210,18 @@ export class ActorSheet5e extends ActorSheet {
}; };
// Format a powerbook entry for a certain indexed level // Format a powerbook entry for a certain indexed level
const registerSection = (sl, i, label, level={}) => { const registerSection = (sl, i, label, {prepMode="prepared", value, max, override}={}) => {
powerbook[i] = { powerbook[i] = {
order: i, order: i,
label: label, label: label,
usesSlots: i > 0, usesSlots: i > 0,
canCreate: owner && (i >= 1), canCreate: owner,
canPrepare: (data.actor.type === "character") && (i >= 1), canPrepare: (data.actor.type === "character") && (i >= 1),
powers: [], powers: [],
uses: useLabels[i] || level.value || 0, uses: useLabels[i] || value || 0,
slots: useLabels[i] || level.max || 0, slots: useLabels[i] || max || 0,
override: level.override || 0, override: override || 0,
dataset: {"type": "power", "level": i}, dataset: {"type": "power", "level": prepMode in sections ? 1 : i, "preparation.mode": prepMode},
prop: sl prop: sl
}; };
}; };
@ -177,7 +234,7 @@ export class ActorSheet5e extends ActorSheet {
return max; return max;
}, 0); }, 0);
// Structure the powerbook for every level up to the maximum which has a slot // Level-based powercasters have cantrips and leveled slots
if ( maxLevel > 0 ) { if ( maxLevel > 0 ) {
registerSection("power0", 0, CONFIG.SW5E.powerLevels[0]); registerSection("power0", 0, CONFIG.SW5E.powerLevels[0]);
for (let lvl = 1; lvl <= maxLevel; lvl++) { for (let lvl = 1; lvl <= maxLevel; lvl++) {
@ -185,9 +242,18 @@ export 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
if ( levels.pact && levels.pact.max ) { if ( levels.pact && levels.pact.max ) {
registerSection("power0", 0, CONFIG.SW5E.powerLevels[0]); if ( !powerbook["0"] ) registerSection("power0", 0, CONFIG.SW5E.powerLevels[0]);
registerSection("pact", sections.pact, CONFIG.SW5E.powerPreparationModes.pact, levels.pact); const l = levels.pact;
const config = CONFIG.SW5E.powerPreparationModes.pact;
registerSection("pact", sections.pact, config, {
prepMode: "pact",
value: l.value,
max: l.max,
override: l.override
});
} }
// Iterate over every power item, adding powers to the powerbook by section // Iterate over every power item, adding powers to the powerbook by section
@ -196,17 +262,24 @@ export class ActorSheet5e extends ActorSheet {
let s = power.data.level || 0; let s = power.data.level || 0;
const sl = `power${s}`; const sl = `power${s}`;
// Powercasting mode specific headings // Specialized powercasting modes (if they exist)
if ( mode in sections ) { if ( mode in sections ) {
s = sections[mode]; s = sections[mode];
if ( !powerbook[s] ){ if ( !powerbook[s] ){
registerSection(sl, s, CONFIG.SW5E.powerPreparationModes[mode], levels[mode]); const l = levels[mode] || {};
const config = CONFIG.SW5E.powerPreparationModes[mode];
registerSection(mode, s, config, {
prepMode: mode,
value: l.value,
max: l.max,
override: l.override
});
} }
} }
// Higher-level power headings // Sections for higher-level powers which the caster "should not" have, but power items exist for
else if ( !powerbook[s] ) { else if ( !powerbook[s] ) {
registerSection(sl, s, CONFIG.SW5E.powerLevels[s], levels[sl]); registerSection(sl, s, CONFIG.SW5E.powerLevels[s], {levels: levels[sl]});
} }
// Add the power to the relevant heading // Add the power to the relevant heading
@ -252,7 +325,7 @@ export class ActorSheet5e extends ActorSheet {
// Equipment-specific filters // Equipment-specific filters
if ( filters.has("equipped") ) { if ( filters.has("equipped") ) {
if (data.equipped && data.equipped !== true) return false; if ( data.equipped !== true ) return false;
} }
return true; return true;
}); });
@ -295,8 +368,10 @@ export class ActorSheet5e extends ActorSheet {
// Editable Only Listeners // Editable Only Listeners
if ( this.isEditable ) { if ( this.isEditable ) {
// Relative updates for numeric fields // Input focus and update
html.find('input[data-dtype="Number"]').change(this._onChangeInputDelta.bind(this)); const inputs = html.find("input");
inputs.focus(ev => ev.currentTarget.select());
inputs.addBack().find('[data-dtype="Number"]').change(this._onChangeInputDelta.bind(this));
// Ability Proficiency // Ability Proficiency
html.find('.ability-proficiency').click(this._onToggleAbilityProficiency.bind(this)); html.find('.ability-proficiency').click(this._onToggleAbilityProficiency.bind(this));
@ -316,6 +391,10 @@ export class ActorSheet5e extends ActorSheet {
html.find('.item-delete').click(this._onItemDelete.bind(this)); html.find('.item-delete').click(this._onItemDelete.bind(this));
html.find('.item-uses input').click(ev => ev.target.select()).change(this._onUsesChange.bind(this)); html.find('.item-uses input').click(ev => ev.target.select()).change(this._onUsesChange.bind(this));
html.find('.slot-max-override').click(this._onPowerSlotOverride.bind(this)); html.find('.slot-max-override').click(this._onPowerSlotOverride.bind(this));
// Active Effect management
html.find(".effect-control").click(this._onManageActiveEffect.bind(this));
} }
// Owner Only Listeners // Owner Only Listeners
@ -328,14 +407,6 @@ export class ActorSheet5e extends ActorSheet {
// Roll Skill Checks // Roll Skill Checks
html.find('.skill-name').click(this._onRollSkillCheck.bind(this)); html.find('.skill-name').click(this._onRollSkillCheck.bind(this));
// Item Dragging
let handler = ev => this._onDragItemStart(ev);
html.find('li.item').each((i, li) => {
if ( li.classList.contains("inventory-header") ) return;
li.setAttribute("draggable", true);
li.addEventListener("dragstart", handler, false);
});
// Item Rolling // Item Rolling
html.find('.item .item-image').click(event => this._onItemRoll(event)); html.find('.item .item-image').click(event => this._onItemRoll(event));
html.find('.item .item-recharge').click(event => this._onItemRecharge(event)); html.find('.item .item-recharge').click(event => this._onItemRecharge(event));
@ -424,37 +495,9 @@ export class ActorSheet5e extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
async _onDrop (event) { async _onDropActor(event, data) {
event.preventDefault(); const canPolymorph = game.user.isGM || (this.actor.owner && game.settings.get('sw5e', 'allowPolymorphing'));
if ( !canPolymorph ) return false;
// Get dropped data
let data;
try {
data = JSON.parse(event.dataTransfer.getData('text/plain'));
} catch (err) {
return false;
}
// Handle a polymorph
if (data && (data.type === "Actor")) {
if (game.user.isGM || (game.settings.get('sw5e', 'allowPolymorphing') && this.actor.owner)) {
return this._onDropPolymorph(event, data);
}
}
// Call parent on drop logic
return super._onDrop(event);
}
/* -------------------------------------------- */
/**
* Handle dropping an Actor on the sheet to trigger a Polymorph workflow
* @param {DragEvent} event The drop event
* @param {Object} data The data transfer
* @private
*/
async _onDropPolymorph(event, data) {
// Get the target actor // Get the target actor
let sourceActor = null; let sourceActor = null;
@ -521,6 +564,23 @@ export class ActorSheet5e extends ActorSheet {
}).render(true); }).render(true);
} }
/* -------------------------------------------- */
/** @override */
async _onDropItemCreate(itemData) {
// Create a Consumable power scroll on the Inventory tab
if ( (itemData.type === "power") && (this._tabs[0].active === "inventory") ) {
const scroll = await Item5e.createScrollFromPower(itemData);
itemData = scroll.data;
}
// Create the owned item as normal
// TODO remove conditional logic in 0.7.x
if (isNewerVersion(game.data.version, "0.6.9")) return super._onDropItemCreate(itemData);
else return this.actor.createEmbeddedEntity("OwnedItem", itemData);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
@ -634,7 +694,7 @@ export class ActorSheet5e extends ActorSheet {
const header = event.currentTarget; const header = event.currentTarget;
const type = header.dataset.type; const type = header.dataset.type;
const itemData = { const itemData = {
name: `New ${type.capitalize()}`, name: game.i18n.format("SW5E.ItemNew", {type: type.capitalize()}),
type: type, type: type,
data: duplicate(header.dataset) data: duplicate(header.dataset)
}; };
@ -671,6 +731,28 @@ export 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
@ -736,11 +818,8 @@ export class ActorSheet5e extends ActorSheet {
event.preventDefault(); event.preventDefault();
const a = event.currentTarget; const a = event.currentTarget;
const label = a.parentElement.querySelector("label"); const label = a.parentElement.querySelector("label");
const options = { const choices = CONFIG.SW5E[a.dataset.options];
name: label.getAttribute("for"), const options = { name: a.dataset.target, title: label.innerText, choices };
title: label.innerText,
choices: CONFIG.SW5E[a.dataset.options]
};
new TraitSelector(this.actor, options).render(true) new TraitSelector(this.actor, options).render(true)
} }
@ -760,4 +839,90 @@ export 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);
}
}

View file

@ -1,37 +1,21 @@
import { ActorSheet5e } from "../sheets/base.js"; import ActorSheet5e from "../sheets/base.js";
/** /**
* An Actor sheet for NPC type characters in the D&D5E system. * An Actor sheet for NPC type characters in the SW5E system.
* Extends the base ActorSheet5e class. * Extends the base ActorSheet5e class.
* @type {ActorSheet5e} * @extends {ActorSheet5e}
*/ */
export class ActorSheet5eNPC extends ActorSheet5e { export default class ActorSheet5eNPC extends ActorSheet5e {
/** /** @override */
* Define default rendering options for the NPC sheet
* @return {Object}
*/
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: ["sw5e", "sheet", "actor", "npc"], classes: ["sw5e", "sheet", "actor", "npc"],
width: 600, width: 600,
height: 658 height: 680
}); });
} }
/* -------------------------------------------- */
/* Rendering */
/* -------------------------------------------- */
/**
* Get the correct HTML template path to use for rendering this particular sheet
* @type {String}
*/
get template() {
if ( !game.user.isGM && this.actor.limited ) return "systems/sw5e/templates/actors/limited-sheet.html";
return "systems/sw5e/templates/actors/npc-sheet.html";
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
@ -42,16 +26,16 @@ export class ActorSheet5eNPC extends ActorSheet5e {
// Categorize Items as Features and Powers // Categorize Items as Features and Powers
const features = { const features = {
weapons: { label: "Attacks", items: [] , hasActions: true, dataset: {type: "weapon", "weapon-type": "natural"} }, weapons: { label: game.i18n.localize("SW5E.AttackPl"), items: [] , hasActions: true, dataset: {type: "weapon", "weapon-type": "natural"} },
actions: { label: "Actions", items: [] , hasActions: true, dataset: {type: "feat", "activation.type": "action"} }, actions: { label: game.i18n.localize("SW5E.ActionPl"), items: [] , hasActions: true, dataset: {type: "feat", "activation.type": "action"} },
passive: { label: "Features", items: [], dataset: {type: "feat"} }, passive: { label: game.i18n.localize("SW5E.Features"), items: [], dataset: {type: "feat"} },
equipment: { label: "Inventory", items: [], dataset: {type: "loot"}} equipment: { label: game.i18n.localize("SW5E.Inventory"), items: [], dataset: {type: "loot"}}
}; };
// Start by classifying items into groups for rendering // Start by classifying items into groups for rendering
let [powers, other] = data.items.reduce((arr, item) => { let [powers, other] = data.items.reduce((arr, item) => {
item.img = item.img || DEFAULT_TOKEN; item.img = item.img || DEFAULT_TOKEN;
item.isStack = item.data.quantity ? item.data.quantity > 1 : false; item.isStack = Number.isNumeric(item.data.quantity) && (item.data.quantity !== 1);
item.hasUses = item.data.uses && (item.data.uses.max > 0); item.hasUses = item.data.uses && (item.data.uses.max > 0);
item.isOnCooldown = item.data.recharge && !!item.data.recharge.value && (item.data.recharge.charged === false); item.isOnCooldown = item.data.recharge && !!item.data.recharge.value && (item.data.recharge.charged === false);
item.isDepleted = item.isOnCooldown && (item.data.uses.per && (item.data.uses.value > 0)); item.isDepleted = item.isOnCooldown && (item.data.uses.per && (item.data.uses.value > 0));
@ -86,9 +70,7 @@ export class ActorSheet5eNPC extends ActorSheet5e {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /** @override */
* Add some extra data when rendering the sheet to reduce the amount of logic required within the template.
*/
getData() { getData() {
const data = super.getData(); const data = super.getData();
@ -103,12 +85,7 @@ export class ActorSheet5eNPC extends ActorSheet5e {
/* Object Updates */ /* Object Updates */
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /** @override */
* This method is called upon form submission after form data is validated
* @param event {Event} The initial triggering submission event
* @param formData {Object} The object of validated form data with which to update the object
* @private
*/
_updateObject(event, formData) { _updateObject(event, formData) {
// Format NPC Challenge Rating // Format NPC Challenge Rating
@ -126,14 +103,9 @@ export class ActorSheet5eNPC extends ActorSheet5e {
/* Event Listeners and Handlers */ /* Event Listeners and Handlers */
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /** @override */
* Activate event listeners using the prepared sheet HTML
* @param html {HTML} The prepared HTML object ready to be rendered into the DOM
*/
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
// Rollable Health Formula
html.find(".health .rollable").click(this._onRollHealthFormula.bind(this)); html.find(".health .rollable").click(this._onRollHealthFormula.bind(this));
} }
@ -152,4 +124,4 @@ export class ActorSheet5eNPC extends ActorSheet5e {
AudioHelper.play({src: CONFIG.sounds.dice}); AudioHelper.play({src: CONFIG.sounds.dice});
this.actor.update({"data.attributes.hp.value": hp, "data.attributes.hp.max": hp}); this.actor.update({"data.attributes.hp.value": hp, "data.attributes.hp.max": hp});
} }
} }

View file

@ -0,0 +1,381 @@
import ActorSheet5e from "./base.js";
/**
* An Actor sheet for Vehicle type actors.
* Extends the base ActorSheet5e class.
* @type {ActorSheet5e}
*/
export default class ActorSheet5eVehicle extends ActorSheet5e {
/**
* Define default rendering options for the Vehicle sheet.
* @returns {Object}
*/
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["sw5e", "sheet", "actor", "vehicle"],
width: 605,
height: 680
});
}
/* -------------------------------------------- */
/**
* Creates a new cargo entry for a vehicle Actor.
*/
static get newCargo() {
return {
name: '',
quantity: 1
};
}
/* -------------------------------------------- */
/**
* Compute the total weight of the vehicle's cargo.
* @param {Number} totalWeight The cumulative item weight from inventory items
* @param {Object} actorData The data object for the Actor being rendered
* @returns {{max: number, value: number, pct: number}}
* @private
*/
_computeEncumbrance(totalWeight, actorData) {
// Compute currency weight
const totalCoins = Object.values(actorData.data.currency).reduce((acc, denom) => acc + denom, 0);
totalWeight += totalCoins / CONFIG.SW5E.encumbrance.currencyPerWeight;
// Vehicle weights are an order of magnitude greater.
totalWeight /= CONFIG.SW5E.encumbrance.vehicleWeightMultiplier;
// Compute overall encumbrance
const enc = {
max: actorData.data.attributes.capacity.cargo,
value: Math.round(totalWeight * 10) / 10
};
enc.pct = Math.min(enc.value * 100 / enc.max, 99);
return enc;
}
/* -------------------------------------------- */
/**
* Prepare items that are mounted to a vehicle and require one or more crew
* to operate.
* @private
*/
_prepareCrewedItem(item) {
// Determine crewed status
const isCrewed = item.data.crewed;
item.toggleClass = isCrewed ? 'active' : '';
item.toggleTitle = game.i18n.localize(`SW5E.${isCrewed ? 'Crewed' : 'Uncrewed'}`);
// Handle crew actions
if (item.type === 'feat' && item.data.activation.type === 'crew') {
item.crew = item.data.activation.cost;
item.cover = game.i18n.localize(`SW5E.${item.data.cover ? 'CoverTotal' : 'None'}`);
if (item.data.cover === .5) item.cover = '½';
else if (item.data.cover === .75) item.cover = '¾';
else if (item.data.cover === null) item.cover = '—';
if (item.crew < 1 || item.crew === null) item.crew = '—';
}
// Prepare vehicle weapons
if (item.type === 'equipment' || item.type === 'weapon') {
item.threshold = item.data.hp.dt ? item.data.hp.dt : '—';
}
}
/* -------------------------------------------- */
/**
* Organize Owned Items for rendering the Vehicle sheet.
* @private
*/
_prepareItems(data) {
const cargoColumns = [{
label: game.i18n.localize('SW5E.Quantity'),
css: 'item-qty',
property: 'quantity',
editable: 'Number'
}];
const equipmentColumns = [{
label: game.i18n.localize('SW5E.Quantity'),
css: 'item-qty',
property: 'data.quantity'
}, {
label: game.i18n.localize('SW5E.AC'),
css: 'item-ac',
property: 'data.armor.value'
}, {
label: game.i18n.localize('SW5E.HP'),
css: 'item-hp',
property: 'data.hp.value',
editable: 'Number'
}, {
label: game.i18n.localize('SW5E.Threshold'),
css: 'item-threshold',
property: 'threshold'
}];
const features = {
actions: {
label: game.i18n.localize('SW5E.ActionPl'),
items: [],
crewable: true,
dataset: {type: 'feat', 'activation.type': 'crew'},
columns: [{
label: game.i18n.localize('SW5E.VehicleCrew'),
css: 'item-crew',
property: 'crew'
}, {
label: game.i18n.localize('SW5E.Cover'),
css: 'item-cover',
property: 'cover'
}]
},
equipment: {
label: game.i18n.localize('SW5E.ItemTypeEquipment'),
items: [],
crewable: true,
dataset: {type: 'equipment', 'armor.type': 'vehicle'},
columns: equipmentColumns
},
passive: {
label: game.i18n.localize('SW5E.Features'),
items: [],
dataset: {type: 'feat'}
},
reactions: {
label: game.i18n.localize('SW5E.ReactionPl'),
items: [],
dataset: {type: 'feat', 'activation.type': 'reaction'}
},
weapons: {
label: game.i18n.localize('SW5E.ItemTypeWeaponPl'),
items: [],
crewable: true,
dataset: {type: 'weapon', 'weapon-type': 'siege'},
columns: equipmentColumns
}
};
const cargo = {
crew: {
label: game.i18n.localize('SW5E.VehicleCrew'),
items: data.data.cargo.crew,
css: 'cargo-row crew',
editableName: true,
dataset: {type: 'crew'},
columns: cargoColumns
},
passengers: {
label: game.i18n.localize('SW5E.VehiclePassengers'),
items: data.data.cargo.passengers,
css: 'cargo-row passengers',
editableName: true,
dataset: {type: 'passengers'},
columns: cargoColumns
},
cargo: {
label: game.i18n.localize('SW5E.VehicleCargo'),
items: [],
dataset: {type: 'loot'},
columns: [{
label: game.i18n.localize('SW5E.Quantity'),
css: 'item-qty',
property: 'data.quantity',
editable: 'Number'
}, {
label: game.i18n.localize('SW5E.Price'),
css: 'item-price',
property: 'data.price',
editable: 'Number'
}, {
label: game.i18n.localize('SW5E.Weight'),
css: 'item-weight',
property: 'data.weight',
editable: 'Number'
}]
}
};
let totalWeight = 0;
for (const item of data.items) {
this._prepareCrewedItem(item);
if (item.type === 'weapon') features.weapons.items.push(item);
else if (item.type === 'equipment') features.equipment.items.push(item);
else if (item.type === 'loot') {
totalWeight += (item.data.weight || 0) * item.data.quantity;
cargo.cargo.items.push(item);
}
else if (item.type === 'feat') {
if (!item.data.activation.type || item.data.activation.type === 'none') {
features.passive.items.push(item);
}
else if (item.data.activation.type === 'reaction') features.reactions.items.push(item);
else features.actions.items.push(item);
}
}
data.features = Object.values(features);
data.cargo = Object.values(cargo);
data.data.attributes.encumbrance = this._computeEncumbrance(totalWeight, data);
}
/* -------------------------------------------- */
/* Event Listeners and Handlers */
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
html.find('.item-toggle').click(this._onToggleItem.bind(this));
html.find('.item-hp input')
.click(evt => evt.target.select())
.change(this._onHPChange.bind(this));
html.find('.item:not(.cargo-row) input[data-property]')
.click(evt => evt.target.select())
.change(this._onEditInSheet.bind(this));
html.find('.cargo-row input')
.click(evt => evt.target.select())
.change(this._onCargoRowChange.bind(this));
if (this.actor.data.data.attributes.actions.stations) {
html.find('.counter.actions, .counter.action-thresholds').hide();
}
}
/* -------------------------------------------- */
/**
* Handle saving a cargo row (i.e. crew or passenger) in-sheet.
* @param event {Event}
* @returns {Promise<Actor>|null}
* @private
*/
_onCargoRowChange(event) {
event.preventDefault();
const target = event.currentTarget;
const row = target.closest('.item');
const idx = Number(row.dataset.itemId);
const property = row.classList.contains('crew') ? 'crew' : 'passengers';
// Get the cargo entry
const cargo = duplicate(this.actor.data.data.cargo[property]);
const entry = cargo[idx];
if (!entry) return null;
// Update the cargo value
const key = target.dataset.property || 'name';
const type = target.dataset.dtype;
let value = target.value;
if (type === 'Number') value = Number(value);
entry[key] = value;
// Perform the Actor update
return this.actor.update({[`data.cargo.${property}`]: cargo});
}
/* -------------------------------------------- */
/**
* Handle editing certain values like quantity, price, and weight in-sheet.
* @param event {Event}
* @returns {Promise<Item>}
* @private
*/
_onEditInSheet(event) {
event.preventDefault();
const itemID = event.currentTarget.closest('.item').dataset.itemId;
const item = this.actor.items.get(itemID);
const property = event.currentTarget.dataset.property;
const type = event.currentTarget.dataset.dtype;
let value = event.currentTarget.value;
switch (type) {
case 'Number': value = parseInt(value); break;
case 'Boolean': value = value === 'true'; break;
}
return item.update({[`${property}`]: value});
}
/* -------------------------------------------- */
/**
* Handle creating a new crew or passenger row.
* @param event {Event}
* @returns {Promise<Actor|Item>}
* @private
*/
_onItemCreate(event) {
event.preventDefault();
const target = event.currentTarget;
const type = target.dataset.type;
if (type === 'crew' || type === 'passengers') {
const cargo = duplicate(this.actor.data.data.cargo[type]);
cargo.push(this.constructor.newCargo);
return this.actor.update({[`data.cargo.${type}`]: cargo});
}
return super._onItemCreate(event);
}
/* -------------------------------------------- */
/**
* Handle deleting a crew or passenger row.
* @param event {Event}
* @returns {Promise<Actor|Item>}
* @private
*/
_onItemDelete(event) {
event.preventDefault();
const row = event.currentTarget.closest('.item');
if (row.classList.contains('cargo-row')) {
const idx = Number(row.dataset.itemId);
const type = row.classList.contains('crew') ? 'crew' : 'passengers';
const cargo = duplicate(this.actor.data.data.cargo[type]).filter((_, i) => i !== idx);
return this.actor.update({[`data.cargo.${type}`]: cargo});
}
return super._onItemDelete(event);
}
/* -------------------------------------------- */
/**
* Special handling for editing HP to clamp it within appropriate range.
* @param event {Event}
* @returns {Promise<Item>}
* @private
*/
_onHPChange(event) {
event.preventDefault();
const itemID = event.currentTarget.closest('.item').dataset.itemId;
const item = this.actor.items.get(itemID);
const hp = Math.clamped(0, parseInt(event.currentTarget.value), item.data.data.hp.max);
event.currentTarget.value = hp;
return item.update({'data.hp.value': hp});
}
/* -------------------------------------------- */
/**
* Handle toggling an item's crewed status.
* @param event {Event}
* @returns {Promise<Item>}
* @private
*/
_onToggleItem(event) {
event.preventDefault();
const itemID = event.currentTarget.closest('.item').dataset.itemId;
const item = this.actor.items.get(itemID);
const crewed = !!item.data.data.crewed;
return item.update({'data.crewed': !crewed});
}
};

View file

@ -2,7 +2,7 @@
* A specialized Dialog subclass for ability usage * A specialized Dialog subclass for ability usage
* @type {Dialog} * @type {Dialog}
*/ */
export class AbilityUseDialog extends Dialog { export default class AbilityUseDialog extends Dialog {
constructor(item, dialogData={}, options={}) { constructor(item, dialogData={}, options={}) {
super(dialogData, options); super(dialogData, options);
this.options.classes = ["sw5e", "dialog"]; this.options.classes = ["sw5e", "dialog"];
@ -25,40 +25,156 @@ export class AbilityUseDialog extends Dialog {
* @return {Promise} * @return {Promise}
*/ */
static async create(item) { static async create(item) {
if ( !item.isOwned ) throw new Error("You cannot display an ability usage dialog for an unowned item");
const uses = item.data.data.uses; // Prepare data
const recharge = item.data.data.recharge; const actorData = item.actor.data.data;
const itemData = item.data.data;
const uses = itemData.uses || {};
const quantity = itemData.quantity || 0;
const recharge = itemData.recharge || {};
const recharges = !!recharge.value; const recharges = !!recharge.value;
// Render the ability usage template // Prepare dialog form data
const html = await renderTemplate("systems/sw5e/templates/apps/ability-use.html", { const data = {
item: item.data, item: item.data,
canUse: recharges ? recharge.charged : uses.value > 0, title: game.i18n.format("SW5E.AbilityUseHint", item.data),
consume: true, note: this._getAbilityUseNote(item.data, uses, recharge),
uses: uses, hasLimitedUses: uses.max || recharges,
recharges: !!recharge.value, canUse: recharges ? recharge.charged : (quantity > 0 && !uses.value) || uses.value > 0,
isCharged: recharge.charged,
hasPlaceableTemplate: game.user.can("TEMPLATE_CREATE") && item.hasAreaTarget, hasPlaceableTemplate: game.user.can("TEMPLATE_CREATE") && item.hasAreaTarget,
perLabel: CONFIG.SW5E.limitedUsePeriods[uses.per] errors: []
}); };
if ( item.data.type === "power" ) this._getPowerData(actorData, itemData, data);
// Render the ability usage template
const html = await renderTemplate("systems/sw5e/templates/apps/ability-use.html", data);
// Create the Dialog and return as a Promise // Create the Dialog and return as a Promise
const icon = data.isPower ? "fa-magic" : "fa-fist-raised";
const label = game.i18n.localize("SW5E.AbilityUse" + (data.isPower ? "Cast" : "Use"));
return new Promise((resolve) => { return new Promise((resolve) => {
let formData = null;
const dlg = new this(item, { const dlg = new this(item, {
title: `${item.name}: Ability Configuration`, title: `${item.name}: Usage Configuration`,
content: html, content: html,
buttons: { buttons: {
use: { use: {
icon: '<i class="fas fa-fist-raised"></i>', icon: `<i class="fas ${icon}"></i>`,
label: "Use Ability", label: label,
callback: html => formData = new FormData(html[0].querySelector("#ability-use-form")) callback: html => resolve(new FormData(html[0].querySelector("form")))
} }
}, },
default: "use", default: "use",
close: () => resolve(formData) close: () => resolve(null)
}); });
dlg.render(true); dlg.render(true);
}); });
} }
/* -------------------------------------------- */
/* Helpers */
/* -------------------------------------------- */
/**
* Get dialog data related to limited power slots
* @private
*/
static _getPowerData(actorData, itemData, data) {
// Determine whether the power may be up-cast
const lvl = itemData.level;
const canUpcast = (lvl > 0) && CONFIG.SW5E.powerUpcastModes.includes(itemData.preparation.mode);
// If can't upcast, return early and don't bother calculating available power slots
if (!canUpcast) {
data = mergeObject(data, { isPower: true, canUpcast });
return;
}
// Determine the levels which are feasible
let lmax = 0;
const powerLevels = Array.fromRange(10).reduce((arr, i) => {
if ( i < lvl ) return arr;
const label = CONFIG.SW5E.powerLevels[i];
const l = actorData.powers["power"+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 ? game.i18n.format('SW5E.PowerLevelSlot', {level: label, n: slots}) : label,
canCast: max > 0,
hasSlots: slots > 0
});
return arr;
}, []).filter(sl => sl.level <= lmax);
// If this character has pact slots, present them as an option for casting the power.
const pact = actorData.powers.pact;
if (pact.level >= lvl) {
powerLevels.push({
level: 'pact',
label: `${game.i18n.format('SW5E.PowerLevelPact', {level: pact.level, n: pact.value})}`,
canCast: true,
hasSlots: pact.value > 0
});
}
const canCast = powerLevels.some(l => l.hasSlots);
// Return merged data
data = mergeObject(data, { isPower: true, canUpcast, powerLevels });
if ( !canCast ) data.errors.push("SW5E.PowerCastNoSlots");
}
/* -------------------------------------------- */
/**
* Get the ability usage note that is displayed
* @private
*/
static _getAbilityUseNote(item, uses, recharge) {
// Zero quantity
const quantity = item.data.quantity;
if ( quantity <= 0 ) return game.i18n.localize("SW5E.AbilityUseUnavailableHint");
// Abilities which use Recharge
if ( !!recharge.value ) {
return game.i18n.format(recharge.charged ? "SW5E.AbilityUseChargedHint" : "SW5E.AbilityUseRechargeHint", {
type: item.type,
})
}
// Does not use any resource
if ( !uses.per || !uses.max ) return "";
// Consumables
if ( item.type === "consumable" ) {
let str = "SW5E.AbilityUseNormalHint";
if ( uses.value > 1 ) str = "SW5E.AbilityUseConsumableChargeHint";
else if ( item.data.quantity === 1 && uses.autoDestroy ) str = "SW5E.AbilityUseConsumableDestroyHint";
else if ( item.data.quantity > 1 ) str = "SW5E.AbilityUseConsumableQuantityHint";
return game.i18n.format(str, {
type: item.data.consumableType,
value: uses.value,
quantity: item.data.quantity,
});
}
// Other Items
else {
return game.i18n.format("SW5E.AbilityUseNormalHint", {
type: item.type,
value: uses.value,
max: uses.max,
per: CONFIG.SW5E.limitedUsePeriods[uses.per]
});
}
}
/* -------------------------------------------- */
static _handleSubmit(formData, item) {
}
} }

View file

@ -1,5 +1,9 @@
export class ActorSheetFlags extends BaseEntitySheet { /**
static get defaultOptions() { * An application class which provides advanced configuration for special character flags which modify an Actor
* @extends {BaseEntitySheet}
*/
export default class ActorSheetFlags extends BaseEntitySheet {
static get defaultOptions() {
const options = super.defaultOptions; const options = super.defaultOptions;
return mergeObject(options, { return mergeObject(options, {
id: "actor-flags", id: "actor-flags",
@ -68,10 +72,10 @@ export class ActorSheetFlags extends BaseEntitySheet {
{name: "data.bonuses.mwak.damage", label: "SW5E.BonusMWDamage"}, {name: "data.bonuses.mwak.damage", label: "SW5E.BonusMWDamage"},
{name: "data.bonuses.rwak.attack", label: "SW5E.BonusRWAttack"}, {name: "data.bonuses.rwak.attack", label: "SW5E.BonusRWAttack"},
{name: "data.bonuses.rwak.damage", label: "SW5E.BonusRWDamage"}, {name: "data.bonuses.rwak.damage", label: "SW5E.BonusRWDamage"},
{name: "data.bonuses.msak.attack", label: "SW5E.BonusMSAttack"}, {name: "data.bonuses.mpak.attack", label: "SW5E.BonusMPAttack"},
{name: "data.bonuses.msak.damage", label: "SW5E.BonusMSDamage"}, {name: "data.bonuses.mpak.damage", label: "SW5E.BonusMPDamage"},
{name: "data.bonuses.rsak.attack", label: "SW5E.BonusRSAttack"}, {name: "data.bonuses.rpak.attack", label: "SW5E.BonusRPAttack"},
{name: "data.bonuses.rsak.damage", label: "SW5E.BonusRSDamage"}, {name: "data.bonuses.rpak.damage", label: "SW5E.BonusRPDamage"},
{name: "data.bonuses.abilities.check", label: "SW5E.BonusAbilityCheck"}, {name: "data.bonuses.abilities.check", label: "SW5E.BonusAbilityCheck"},
{name: "data.bonuses.abilities.save", label: "SW5E.BonusAbilitySave"}, {name: "data.bonuses.abilities.save", label: "SW5E.BonusAbilitySave"},
{name: "data.bonuses.abilities.skill", label: "SW5E.BonusAbilitySkill"}, {name: "data.bonuses.abilities.skill", label: "SW5E.BonusAbilitySkill"},
@ -91,7 +95,7 @@ export class ActorSheetFlags extends BaseEntitySheet {
*/ */
async _updateObject(event, formData) { async _updateObject(event, formData) {
const actor = this.object; const actor = this.object;
const updateData = expandObject(formData); let updateData = expandObject(formData);
// Unset any flags which are "false" // Unset any flags which are "false"
let unset = false; let unset = false;
@ -106,7 +110,18 @@ export class ActorSheetFlags extends BaseEntitySheet {
} }
} }
// Apply the changes // Clear any bonuses which are whitespace only
for ( let b of Object.values(updateData.data.bonuses ) ) {
for ( let [k, v] of Object.entries(b) ) {
b[k] = v.trim();
}
}
// 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});
} }
} }

69
module/apps/long-rest.js Normal file
View file

@ -0,0 +1,69 @@
/**
* A helper Dialog subclass for completing a long rest
* @extends {Dialog}
*/
export default class LongRestDialog extends Dialog {
constructor(actor, dialogData = {}, options = {}) {
super(dialogData, options);
this.actor = actor;
}
/* -------------------------------------------- */
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
template: "systems/sw5e/templates/apps/long-rest.html",
classes: ["sw5e", "dialog"]
});
}
/* -------------------------------------------- */
/** @override */
getData() {
const data = super.getData();
const variant = game.settings.get("sw5e", "restVariant");
data.promptNewDay = variant !== "gritty"; // It's always a new day when resting 1 week
data.newDay = variant === "normal"; // It's probably a new day when resting normally (8 hours)
return data;
}
/* -------------------------------------------- */
/**
* A helper constructor function which displays the Long Rest confirmation dialog and returns a Promise once it's
* workflow has been resolved.
* @param {Actor5e} actor
* @return {Promise}
*/
static async longRestDialog({ actor } = {}) {
return new Promise((resolve, reject) => {
const dlg = new this(actor, {
title: "Long Rest",
buttons: {
rest: {
icon: '<i class="fas fa-bed"></i>',
label: "Rest",
callback: html => {
let newDay = false;
if (game.settings.get("sw5e", "restVariant") === "normal")
newDay = html.find('input[name="newDay"]')[0].checked;
else if(game.settings.get("sw5e", "restVariant") === "gritty")
newDay = true;
resolve(newDay);
}
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel",
callback: reject
}
},
default: 'rest',
close: reject
});
dlg.render(true);
});
}
}

View file

@ -1,8 +1,10 @@
import LongRestDialog from "./long-rest.js";
/** /**
* A helper Dialog subclass for rolling Hit Dice on short rest * A helper Dialog subclass for rolling Hit Dice on short rest
* @type {Dialog} * @extends {Dialog}
*/ */
export class ShortRestDialog extends Dialog { export default class ShortRestDialog extends Dialog {
constructor(actor, dialogData={}, options={}) { constructor(actor, dialogData={}, options={}) {
super(dialogData, options); super(dialogData, options);
@ -34,6 +36,8 @@ export class ShortRestDialog extends Dialog {
/** @override */ /** @override */
getData() { getData() {
const data = super.getData(); const data = super.getData();
// 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" ) {
const d = item.data; const d = item.data;
@ -45,6 +49,11 @@ export 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
const variant = game.settings.get("sw5e", "restVariant");
data.promptNewDay = variant !== "epic"; // It's never a new day when only resting 1 minute
data.newDay = false; // It may be a new day, but not by default
return data; return data;
} }
@ -56,7 +65,6 @@ export class ShortRestDialog extends Dialog {
super.activateListeners(html); super.activateListeners(html);
let btn = html.find("#roll-hd"); let btn = html.find("#roll-hd");
btn.click(this._onRollHitDie.bind(this)); btn.click(this._onRollHitDie.bind(this));
super.activateListeners(html);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -83,21 +91,27 @@ export class ShortRestDialog extends Dialog {
* @return {Promise} * @return {Promise}
*/ */
static async shortRestDialog({actor}={}) { static async shortRestDialog({actor}={}) {
return new Promise(resolve => { return new Promise((resolve, reject) => {
const dlg = new this(actor, { const dlg = new this(actor, {
title: "Short Rest", title: "Short Rest",
buttons: { buttons: {
rest: { rest: {
icon: '<i class="fas fa-bed"></i>', icon: '<i class="fas fa-bed"></i>',
label: "Rest", label: "Rest",
callback: () => resolve(true) callback: html => {
let newDay = false;
if (game.settings.get("sw5e", "restVariant") === "gritty")
newDay = html.find('input[name="newDay"]')[0].checked;
resolve(newDay);
}
}, },
cancel: { cancel: {
icon: '<i class="fas fa-times"></i>', icon: '<i class="fas fa-times"></i>',
label: "Cancel", label: "Cancel",
callback: () => resolve(false) callback: reject
} }
} },
close: reject
}); });
dlg.render(true); dlg.render(true);
}); });
@ -108,31 +122,12 @@ export class ShortRestDialog extends Dialog {
/** /**
* A helper constructor function which displays the Long Rest confirmation dialog and returns a Promise once it's * A helper constructor function which displays the Long Rest confirmation dialog and returns a Promise once it's
* workflow has been resolved. * workflow has been resolved.
* @deprecated
* @param {Actor5e} actor * @param {Actor5e} actor
* @return {Promise} * @return {Promise}
*/ */
static async longRestDialog({actor}={}) { static async longRestDialog({actor}={}) {
const content = `<p>Take a long rest?</p><p>On a long rest you will recover hit points, half your maximum hit dice, console.warn("WARNING! ShortRestDialog.longRestDialog has been deprecated, use LongRestDialog.longRestDialog instead.");
class resources, limited use item charges, and power slots.</p>`; return LongRestDialog.longRestDialog(...arguments);
return new Promise((resolve, reject) => {
new Dialog({
title: "Long Rest",
content: content,
buttons: {
rest: {
icon: '<i class="fas fa-bed"></i>',
label: "Rest",
callback: resolve
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel",
callback: reject
},
},
default: 'rest',
close: reject
}, {classes: ["sw5e", "dialog"]}).render(true);
});
} }
} }

View file

@ -1,102 +0,0 @@
/**
* A specialized Dialog subclass for casting a spell item at a certain level
* @type {Dialog}
*/
export class SpellCastDialog extends Dialog {
constructor(actor, item, dialogData={}, options={}) {
super(dialogData, options);
this.options.classes = ["dnd5e", "dialog"];
/**
* Store a reference to the Actor entity which is casting the spell
* @type {Actor5e}
*/
this.actor = actor;
/**
* Store a reference to the Item entity which is the spell being cast
* @type {Item5e}
*/
this.item = item;
}
/* -------------------------------------------- */
/* Rendering */
/* -------------------------------------------- */
/**
* A constructor function which displays the Spell 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 spell may be upcast
const lvl = id.level;
const canUpcast = (lvl > 0) && CONFIG.DND5E.spellUpcastModes.includes(id.preparation.mode);
// Determine the levels which are feasible
let lmax = 0;
const spellLevels = Array.fromRange(10).reduce((arr, i) => {
if ( i < lvl ) return arr;
const l = ad.spells["spell"+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.DND5E.spellLevels[i]} (${slots} Slots)` : CONFIG.DND5E.spellLevels[i],
canCast: canUpcast && (max > 0),
hasSlots: slots > 0
});
return arr;
}, []).filter(sl => sl.level <= lmax);
const pact = ad.spells.pact;
if (pact.level >= lvl) {
// If this character has pact slots, present them as an option for
// casting the spell.
spellLevels.push({
level: 'pact',
label: game.i18n.localize('DND5E.SpellLevelPact')
+ ` (${game.i18n.localize('DND5E.Level')} ${pact.level}) `
+ `(${pact.value} ${game.i18n.localize('DND5E.Slots')})`,
canCast: canUpcast,
hasSlots: pact.value > 0
});
}
const canCast = spellLevels.some(l => l.hasSlots);
// Render the Spell casting template
const html = await renderTemplate("systems/dnd5e/templates/apps/spell-cast.html", {
item: item.data,
canCast: canCast,
canUpcast: canUpcast,
spellLevels,
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}: Spell Configuration`,
content: html,
buttons: {
cast: {
icon: '<i class="fas fa-magic"></i>',
label: "Cast",
callback: html => resolve(new FormData(html[0].querySelector("#spell-config-form")))
}
},
default: "cast",
close: reject
});
dlg.render(true);
});
}
}

View file

@ -2,7 +2,7 @@
* A specialized form used to select from a checklist of attributes, traits, or properties * A specialized form used to select from a checklist of attributes, traits, or properties
* @extends {FormApplication} * @extends {FormApplication}
*/ */
export class TraitSelector extends FormApplication { export default class TraitSelector extends FormApplication {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {

View file

@ -1,32 +1,40 @@
/** /** @override */
* Measure the distance between two pixel coordinates export const measureDistances = function(segments, options={}) {
* See BaseGrid.measureDistance for more details if ( !options.gridSpaces ) return BaseGrid.prototype.measureDistances.call(this, segments, options);
*
* @param {Object} p0 The origin coordinate {x, y}
* @param {Object} p1 The destination coordinate {x, y}
* @param {boolean} gridSpaces Enforce grid distance (if true) vs. direct point-to-point (if false)
* @return {number} The distance between p1 and p0
*/
export const measureDistance = function(p0, p1, {gridSpaces=true}={}) {
if ( !gridSpaces ) return BaseGrid.prototype.measureDistance.bind(this)(p0, p1, {gridSpaces});
let gs = canvas.dimensions.size,
ray = new Ray(p0, p1),
nx = Math.abs(Math.ceil(ray.dx / gs)),
ny = Math.abs(Math.ceil(ray.dy / gs));
// Get the number of straight and diagonal moves // Track the total number of diagonals
let nDiagonal = Math.min(nx, ny), let nDiagonal = 0;
nStraight = Math.abs(ny - nx); const rule = this.parent.diagonalRule;
const d = canvas.dimensions;
// Alternative DMG Movement // Iterate over measured segments
if ( this.parent.diagonalRule === "5105" ) { return segments.map(s => {
let nd10 = Math.floor(nDiagonal / 2); let r = s.ray;
let spaces = (nd10 * 2) + (nDiagonal - nd10) + nStraight;
return spaces * canvas.dimensions.distance;
}
// Standard PHB Movement // Determine the total distance traveled
else return (nStraight + nDiagonal) * canvas.scene.data.gridDistance; let nx = Math.abs(Math.ceil(r.dx / d.size));
let ny = Math.abs(Math.ceil(r.dy / d.size));
// Determine the number of straight and diagonal moves
let nd = Math.min(nx, ny);
let ns = Math.abs(ny - nx);
nDiagonal += nd;
// Alternative DMG Movement
if (rule === "5105") {
let nd10 = Math.floor(nDiagonal / 2) - Math.floor((nDiagonal - nd) / 2);
let spaces = (nd10 * 2) + (nd - nd10) + ns;
return spaces * canvas.dimensions.distance;
}
// Euclidean Measurement
else if (rule === "EUCL") {
return Math.round(Math.hypot(nx, ny) * canvas.scene.data.gridDistance);
}
// Standard PHB Movement
else return (ns + nd) * canvas.scene.data.gridDistance;
});
}; };
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -39,8 +47,8 @@ const _TokenGetBarAttribute = Token.prototype.getBarAttribute;
export const getBarAttribute = function(...args) { export const getBarAttribute = function(...args) {
const data = _TokenGetBarAttribute.bind(this)(...args); const data = _TokenGetBarAttribute.bind(this)(...args);
if ( data && (data.attribute === "attributes.hp") ) { if ( data && (data.attribute === "attributes.hp") ) {
data.value += parseInt(data['temp'] || 0); data.value += parseInt(getProperty(this.actor.data, "data.attributes.hp.temp") || 0);
data.max += parseInt(data['tempmax'] || 0); data.max += parseInt(getProperty(this.actor.data, "data.attributes.hp.tempmax") || 0);
} }
return data; return data;
}; };

View file

@ -1,19 +1,19 @@
import {Actor5e} from "./actor/entity.js";
/** /**
* Highlight critical success or failure on d20 rolls * Highlight critical success or failure on d20 rolls
*/ */
export const highlightCriticalSuccessFailure = function(message, html, data) { export const highlightCriticalSuccessFailure = function(message, html, data) {
if ( !message.isRoll || !message.isRollVisible || !message.roll.parts.length ) return; if ( !message.isRoll || !message.isContentVisible ) return;
// Highlight rolls where the first part is a d20 roll // Highlight rolls where the first part is a d20 roll
const roll = message.roll; const roll = message.roll;
let d = roll.parts[0]; if ( !roll.dice.length ) return;
const isD20Roll = d instanceof Die && (d.faces === 20) && (d.results.length === 1); const d = roll.dice[0];
if ( !isD20Roll ) return;
// Ensure it is not a modified roll // Ensure it is an un-modified d20 roll
const isModifiedRoll = ("success" in d.rolls[0]) || d.options.marginSuccess || d.options.marginFailure; const isD20 = (d.faces === 20) && ( d.results.length === 1 );
if ( !isD20 ) return;
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
@ -33,6 +33,7 @@ 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();
// 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);
@ -60,32 +61,55 @@ export const displayChatActionButtons = function(message, html, data) {
* @return {Array} The extended options Array including new context choices * @return {Array} The extended options Array including new context choices
*/ */
export const addChatMessageContextOptions = function(html, options) { export const addChatMessageContextOptions = function(html, options) {
let canApply = li => canvas.tokens.controlledTokens.length && li.find(".dice-roll").length; let canApply = li => {
const message = game.messages.get(li.data("messageId"));
return message.isRoll && message.isContentVisible && canvas.tokens.controlled.length;
};
options.push( options.push(
{ {
name: game.i18n.localize("SW5E.ChatContextDamage"), name: game.i18n.localize("SW5E.ChatContextDamage"),
icon: '<i class="fas fa-user-minus"></i>', icon: '<i class="fas fa-user-minus"></i>',
condition: canApply, condition: canApply,
callback: li => Actor5e.applyDamage(li, 1) callback: li => applyChatCardDamage(li, 1)
}, },
{ {
name: game.i18n.localize("SW5E.ChatContextHealing"), name: game.i18n.localize("SW5E.ChatContextHealing"),
icon: '<i class="fas fa-user-plus"></i>', icon: '<i class="fas fa-user-plus"></i>',
condition: canApply, condition: canApply,
callback: li => Actor5e.applyDamage(li, -1) callback: li => applyChatCardDamage(li, -1)
}, },
{ {
name: game.i18n.localize("SW5E.ChatContextDoubleDamage"), name: game.i18n.localize("SW5E.ChatContextDoubleDamage"),
icon: '<i class="fas fa-user-injured"></i>', icon: '<i class="fas fa-user-injured"></i>',
condition: canApply, condition: canApply,
callback: li => Actor5e.applyDamage(li, 2) callback: li => applyChatCardDamage(li, 2)
}, },
{ {
name: game.i18n.localize("SW5E.ChatContextHalfDamage"), name: game.i18n.localize("SW5E.ChatContextHalfDamage"),
icon: '<i class="fas fa-user-shield"></i>', icon: '<i class="fas fa-user-shield"></i>',
condition: canApply, condition: canApply,
callback: li => Actor5e.applyDamage(li, 0.5) callback: li => applyChatCardDamage(li, 0.5)
} }
); );
return options; return options;
}; };
/* -------------------------------------------- */
/**
* Apply rolled dice damage to the token or tokens which are currently controlled.
* This allows for damage to be scaled by a multiplier to account for healing, critical hits, or resistance
*
* @param {HTMLElement} roll The chat entry which contains the roll data
* @param {Number} multiplier A damage multiplier to apply to the rolled damage.
* @return {Promise}
*/
function applyChatCardDamage(roll, multiplier) {
const amount = roll.find('.dice-total').text();
return Promise.all(canvas.tokens.controlled.map(t => {
const a = t.actor;
return a.applyDamage(amount, multiplier);
}));
}
/* -------------------------------------------- */

35
module/classFeatures.js Normal file
View file

@ -0,0 +1,35 @@
export const ClassFeatures = {
"berserker": {
"archetypes": {
"addicted-approach": {
"label": "Addicted Approach",
"source": "PHB",
"features": {
"3": ["Compendium.sw5e.archetypes.PCwepUZqHYlxr4T3", "Compendium.sw5e.classfeatures.efOA0nrvUqKJOOeP", "Compendium.sw5e.classfeatures.nT6AfpQXSZ4IeChO"],
"6": ["Compendium.sw5e.classfeatures.GbJDWzoTKWL7sEpR"],
"10": ["Compendium.sw5e.classfeatures.3jqPPd5qJBBnonPw"],
"14": ["Compendium.sw5e.classfeatures.xzRNHB2M2HdOZzr7"]
}
}
},
"features": {
"1": ["Compendium.sw5e.classfeatures.IDt6duVrBzL8euRc", "Compendium.sw5e.classfeatures.rPOLy96fW96N2UPg"],
"2": ["Compendium.sw5e.classfeatures.DlYiCiG39R0goG9u", "Compendium.sw5e.classfeatures.FbSpxpXm1xONn0na", "Compendium.sw5e.classfeatures.KDiQ8O2evV2Z1YTo", "Compendium.sw5e.classfeatures.Q1JyHnVs9iIEBs91", "Compendium.sw5e.classfeatures.ROdICoWR82v6A2Rf", "Compendium.sw5e.classfeatures.cdCx5Hvq2rYRMzRj", "Compendium.sw5e.classfeatures.dTdbL8dypa6BAdnP", "Compendium.sw5e.classfeatures.h1uDhP1tEOuvjRw6", "Compendium.sw5e.classfeatures.hMiA075EKBBOL2cv", "Compendium.sw5e.classfeatures.sgJdISZMtwv08WPJ", "Compendium.sw5e.classfeatures.v4CZJ8LBMl5PYZCO"],
"3": ["Compendium.sw5e.classfeatures.kzwSN9SabKgWZZvU"],
"4": ["Compendium.sw5e.classfeatures.9oyy0MMqEws2qoil"],
"5": ["Compendium.sw5e.classfeatures.dPWmHiWmpnhHTsgd"],
"7": ["Compendium.sw5e.classfeatures.Cid5ujSdnooH0vMm", "Compendium.sw5e.classfeatures.WTBhKJgkArQI3Tgv", "Compendium.sw5e.classfeatures.oiT3TJxzRWPKAX9E", "Compendium.sw5e.classfeatures.pMEmIt3NWThbee8k", "Compendium.sw5e.classfeatures.qWV5YogZcpZ3Y3xj"],
"9": ["Compendium.sw5e.classfeatures.bi8G8H5Ur9B3BAyM"],
"11": ["Compendium.sw5e.classfeatures.eWbTifdXJvvXT4CV"],
"13": ["Compendium.sw5e.classfeatures.Hg8zYh1iXL0DGUVq", "Compendium.sw5e.classfeatures.QRnYiJmRk18ekE9v", "Compendium.sw5e.classfeatures.sfEr8ZBFVddlfLeF", "Compendium.sw5e.classfeatures.yGC9VzT840qQWxca"],
"15": ["Compendium.sw5e.classfeatures.YHPUv9lN3nCapAgP"],
"18": ["Compendium.sw5e.classfeatures.fFKNqUAWh0ZOhvRc"],
"20": ["Compendium.sw5e.classfeatures.IWTDawTUf79eWbEV"]
}
},
"consular": {
"features": {
"20": ["Compendium.sw5e.classfeatures.gSGeitc98ItAwhfF"]
}
}
};

View file

@ -1,6 +1,6 @@
/** /**
* Override the default Initiative formula to customize special behaviors of the D&D5e system. * Override the default Initiative formula to customize special behaviors of the SW5e system.
* Apply advantage, proficiency, or bonuses where appropriate * Apply advantage, proficiency, or bonuses where appropriate
* Apply the dexterity score as a decimal tiebreaker if requested * Apply the dexterity score as a decimal tiebreaker if requested
* See Combat._getInitiativeFormula for more detail. * See Combat._getInitiativeFormula for more detail.
@ -9,8 +9,59 @@ export const _getInitiativeFormula = function(combatant) {
const actor = combatant.actor; const actor = combatant.actor;
if ( !actor ) return "1d20"; if ( !actor ) return "1d20";
const init = actor.data.data.attributes.init; const init = actor.data.data.attributes.init;
const parts = ["1d20", init.mod, (init.prof !== 0) ? init.prof : null, (init.bonus !== 0) ? init.bonus : null];
if ( actor.getFlag("sw5e", "initiativeAdv") ) parts[0] = "2d20kh"; let nd = 1;
if ( CONFIG.Combat.initiative.tiebreaker ) parts.push(actor.data.data.abilities.dex.value / 100); let mods = "";
if (actor.getFlag("sw5e", "halflingLucky")) mods += "r=1";
if (actor.getFlag("sw5e", "initiativeAdv")) {
nd = 2;
mods += "kh";
}
const parts = [`${nd}d20${mods}`, init.mod, (init.prof !== 0) ? init.prof : null, (init.bonus !== 0) ? init.bonus : null];
// Optionally apply Dexterity tiebreaker
const tiebreaker = game.settings.get("sw5e", "initiativeDexTiebreaker");
if ( tiebreaker ) parts.push(actor.data.data.abilities.dex.value / 100);
return parts.filter(p => p !== null).join(" + "); return parts.filter(p => p !== null).join(" + ");
}; };
/* -------------------------------------------- */
/**
* TODO: A temporary shim until 0.7.x becomes stable
* @override
*/
TokenConfig.getTrackedAttributes = function(data, _path=[]) {
// Track the path and record found attributes
const attributes = {
"bar": [],
"value": []
};
// 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;
};

View file

@ -1,839 +0,0 @@
// Namespace D&D5e Configuration Values
export const SW5E = {};
// ASCII Artwork
SW5E.ASCII = `_______________________________
_
| |
___| |_ __ _ _ ____ ____ _ _ __ ___
/ __| __/ _\ | |__\ \ /\ / / _\ | |__/ __|
\__ \ || (_) | | \ V V / (_) | | \__ \
|___/\__\__/_|_| \_/\_/ \__/_|_| |___/
_______________________________`;
/**
* The set of Ability Scores used within the system
* @type {Object}
*/
SW5E.abilities = {
"str": "SW5E.AbilityStr",
"dex": "SW5E.AbilityDex",
"con": "SW5E.AbilityCon",
"int": "SW5E.AbilityInt",
"wis": "SW5E.AbilityWis",
"cha": "SW5E.AbilityCha"
};
/* -------------------------------------------- */
/**
* Character alignment options
* @type {Object}
*/
SW5E.alignments = {
'll': "SW5E.AlignmentLL",
'nl': "SW5E.AlignmentNL",
'cl': "SW5E.AlignmentCL",
'lb': "SW5E.AlignmentLB",
'bn': "SW5E.AlignmentBN",
'cb': "SW5E.AlignmentCB",
'ld': "SW5E.AlignmentLD",
'nd': "SW5E.AlignmentND",
'cd': "SW5E.AlignmentCD"
};
SW5E.weaponProficiencies = {
"sim": "SW5E.WeaponSimpleProficiency",
"bla": "SW5E.WeaponBlasterProficiency"
};
SW5E.toolProficiencies = {
"armor": "SW5E.ToolArmormech",
"arms": "SW5E.ToolArmstech",
"arti": "SW5E.ToolArtificer",
"art": "SW5E.ToolArtist",
"astro": "SW5E.ToolAstrotech",
"bio": "SW5E.ToolBiotech",
"con": "SW5E.ToolConstructor",
"cyb": "SW5E.ToolCybertech",
"jew": "SW5E.ToolJeweler",
"sur": "SW5E.ToolSurveyor",
"syn": "SW5E.ToolSynthweaver",
"tin": "SW5E.ToolTinker",
"ant": "SW5E.ToolAntitoxkit",
"arc": "SW5E.ToolArchaeologistKit",
"aud": "SW5E.ToolAudiotechKit",
"bioa": "SW5E.ToolBioanalysisKit",
"brew": "SW5E.ToolBrewerKit",
"chef": "SW5E.ToolChefKit",
"demo": "SW5E.ToolDemolitionKit",
"disg": "SW5E.ToolDisguiseKit",
"forg": "SW5E.ToolForgeryKit",
"mech": "SW5E.ToolMechanicKit",
"game": "SW5E.ToolGamingSet",
"poi": "SW5E.ToolPoisonKit",
"scav": "SW5E.ToolScavengingKit",
"secur": "SW5E.ToolSecurityKit",
"slic": "SW5E.ToolSlicerKit",
"spice": "SW5E.ToolSpiceKit",
"music": "SW5E.ToolMusicalInstrument",
"vehicle": "SW5E.ToolVehicle"
};
/* -------------------------------------------- */
/**
* This Object defines the various lengths of time which can occur in D&D5e
* @type {Object}
*/
SW5E.timePeriods = {
"inst": "SW5E.TimeInst",
"turn": "SW5E.TimeTurn",
"round": "SW5E.TimeRound",
"minute": "SW5E.TimeMinute",
"hour": "SW5E.TimeHour",
"day": "SW5E.TimeDay",
"month": "SW5E.TimeMonth",
"year": "SW5E.TimeYear",
"perm": "SW5E.TimePerm",
"spec": "SW5E.Special"
};
/* -------------------------------------------- */
/**
* This describes the ways that an ability can be activated
* @type {Object}
*/
SW5E.abilityActivationTypes = {
"none": "SW5E.None",
"action": "SW5E.Action",
"bonus": "SW5E.BonusAction",
"reaction": "SW5E.Reaction",
"minute": SW5E.timePeriods.minute,
"hour": SW5E.timePeriods.hour,
"day": SW5E.timePeriods.day,
"special": SW5E.timePeriods.spec,
"legendary": "SW5E.LegAct",
"lair": "SW5E.LairAct"
};
/* -------------------------------------------- */
// Creature Sizes
SW5E.actorSizes = {
"tiny": "SW5E.SizeTiny",
"sm": "SW5E.SizeSmall",
"med": "SW5E.SizeMedium",
"lg": "SW5E.SizeLarge",
"huge": "SW5E.SizeHuge",
"grg": "SW5E.SizeGargantuan"
};
SW5E.tokenSizes = {
"tiny": 1,
"sm": 1,
"med": 1,
"lg": 2,
"huge": 3,
"grg": 4
};
/* -------------------------------------------- */
/**
* Classification types for item action types
* @type {Object}
*/
SW5E.itemActionTypes = {
"mwak": "SW5E.ActionMWAK",
"rwak": "SW5E.ActionRWAK",
"mpak": "SW5E.ActionMPAK",
"rpak": "SW5E.ActionRPAK",
"save": "SW5E.ActionSave",
"heal": "SW5E.ActionHeal",
"abil": "SW5E.ActionAbil",
"util": "SW5E.ActionUtil",
"other": "SW5E.ActionOther"
};
/* -------------------------------------------- */
SW5E.itemCapacityTypes = {
"items": "SW5E.ItemContainerCapacityItems",
"weight": "SW5E.ItemContainerCapacityWeight"
};
/* -------------------------------------------- */
/**
* Enumerate the lengths of time over which an item can have limited use ability
* @type {Object}
*/
SW5E.limitedUsePeriods = {
"sr": "SW5E.ShortRest",
"lr": "SW5E.LongRest",
"day": "SW5E.Day",
"charges": "SW5E.Charges"
};
/* -------------------------------------------- */
/**
* The set of equipment types for armor, clothing, and other objects which can ber worn by the character
* @type {Object}
*/
SW5E.equipmentTypes = {
"light": "SW5E.EquipmentLight",
"medium": "SW5E.EquipmentMedium",
"heavy": "SW5E.EquipmentHeavy",
"bonus": "SW5E.EquipmentBonus",
"natural": "SW5E.EquipmentNatural",
"shield": "SW5E.EquipmentShield",
"clothing": "SW5E.EquipmentClothing",
"trinket": "SW5E.EquipmentTrinket"
};
/* -------------------------------------------- */
/**
* The set of Armor Proficiencies which a character may have
* @type {Object}
*/
SW5E.armorProficiencies = {
"lgt": SW5E.equipmentTypes.light,
"med": SW5E.equipmentTypes.medium,
"hvy": SW5E.equipmentTypes.heavy,
"shl": "SW5E.EquipmentShieldProficiency"
};
/* -------------------------------------------- */
/**
* Enumerate the valid consumable types which are recognized by the system
* @type {Object}
*/
SW5E.consumableTypes = {
"adrenal": "SW5E.ConsumableAdrenal",
"poison": "SW5E.ConsumablePoison",
"explosive": "SW5E.ConsumableExplosive",
"food": "SW5E.ConsumableFood",
"medpac": "SW5E.ConsumableMedpac",
"technology": "SW5E.ConsumableTechnology",
"ammunition": "SW5E.ConsumableAmmunition",
"trinket": "SW5E.ConsumableTrinket"
};
/* -------------------------------------------- */
/**
* The valid currency denominations supported by the 5e system
* @type {Object}
*/
SW5E.currencies = {
"CR": "SW5E.CurrencyCR",
};
/* -------------------------------------------- */
// Damage Types
SW5E.damageTypes = {
"acid": "SW5E.DamageAcid",
"cold": "SW5E.DamageCold",
"energy": "SW5E.DamageEnergy",
"fire": "SW5E.DamageFire",
"force": "SW5E.DamageForce",
"ion": "SW5E.DamageIon",
"kinetic": "SW5E.DamageKinetic",
"lightning": "SW5E.DamageLightning",
"necrotic": "SW5E.DamageNecrotic",
"poison": "SW5E.DamagePoison",
"psychic": "SW5E.DamagePsychic",
"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"
};
/* -------------------------------------------- */
SW5E.distanceUnits = {
"none": "SW5E.None",
"self": "SW5E.DistSelf",
"touch": "SW5E.DistTouch",
"ft": "SW5E.DistFt",
"mi": "SW5E.DistMi",
"spec": "SW5E.Special",
"any": "SW5E.DistAny"
};
/* -------------------------------------------- */
/**
* Configure aspects of encumbrance calculation so that it could be configured by modules
* @type {Object}
*/
SW5E.encumbrance = {
currencyPerWeight: 50,
strMultiplier: 15
};
/* -------------------------------------------- */
/**
* This Object defines the types of single or area targets which can be applied in D&D5e
* @type {Object}
*/
SW5E.targetTypes = {
"none": "SW5E.None",
"self": "SW5E.TargetSelf",
"creature": "SW5E.TargetCreature",
"droid": "SW5E.TargetDroid",
"ally": "SW5E.TargetAlly",
"enemy": "SW5E.TargetEnemy",
"object": "SW5E.TargetObject",
"space": "SW5E.TargetSpace",
"radius": "SW5E.TargetRadius",
"sphere": "SW5E.TargetSphere",
"cylinder": "SW5E.TargetCylinder",
"cone": "SW5E.TargetCone",
"square": "SW5E.TargetSquare",
"cube": "SW5E.TargetCube",
"line": "SW5E.TargetLine",
"wall": "SW5E.TargetWall",
};
/* -------------------------------------------- */
/**
* Map the subset of target types which produce a template area of effect
* The keys are SW5E target types and the values are MeasuredTemplate shape types
* @type {Object}
*/
SW5E.areaTargetTypes = {
cone: "cone",
cube: "rect",
cylinder: "circle",
line: "ray",
radius: "circle",
sphere: "circle",
square: "rect",
wall: "ray"
};
/* -------------------------------------------- */
// Healing Types
SW5E.healingTypes = {
"healing": "SW5E.Healing",
"temphp": "SW5E.HealingTemp"
};
/* -------------------------------------------- */
/**
* Enumerate the denominations of hit dice which can apply to classes in the D&D5E system
* @type {Array.<string>}
*/
SW5E.hitDieTypes = ["d6", "d8", "d10", "d12"];
/* -------------------------------------------- */
/**
* Character senses options
* @type {Object}
*/
SW5E.senses = {
"bs": "SW5E.SenseBS",
"dv": "SW5E.SenseDV",
"ts": "SW5E.SenseTS",
"tr": "SW5E.SenseTR"
};
/* -------------------------------------------- */
/**
* The set of skill which can be trained in D&D5e
* @type {Object}
*/
SW5E.skills = {
"acr": "SW5E.SkillAcr",
"ani": "SW5E.SkillAni",
"ath": "SW5E.SkillAth",
"dec": "SW5E.SkillDec",
"ins": "SW5E.SkillIns",
"itm": "SW5E.SkillItm",
"inv": "SW5E.SkillInv",
"lor": "SW5E.SkillLor",
"med": "SW5E.SkillMed",
"nat": "SW5E.SkillNat",
"prc": "SW5E.SkillPrc",
"prf": "SW5E.SkillPrf",
"per": "SW5E.SkillPer",
"pil": "SW5E.SkillPil",
"slt": "SW5E.SkillSlt",
"ste": "SW5E.SkillSte",
"sur": "SW5E.SkillSur",
"tec": "SW5E.SkillTec",
};
/* -------------------------------------------- */
SW5E.powerPreparationModes = {
"always": "SW5E.PowerPrepAlways",
"atwill": "SW5E.PowerPrepAtWill",
"innate": "SW5E.PowerPrepInnate",
"prepared": "SW5E.PowerPrepPrepared"
};
SW5E.powerUpcastModes = ["always"];
SW5E.powerProgression = {
"none": "SW5E.PowerNone",
"full": "SW5E.PowerProgFull",
"artificer": "SW5E.PowerProgArt"
};
/* -------------------------------------------- */
/**
* The available choices for how power damage scaling may be computed
* @type {Object}
*/
SW5E.powerScalingModes = {
"none": "SW5E.PowerNone",
"atwill": "SW5E.PowerAtWill",
"level": "SW5E.PowerLevel"
};
/* -------------------------------------------- */
// Weapon Types
SW5E.weaponTypes = {
"simpleVW": "SW5E.WeaponSimpleVW",
"simpleB": "SW5E.WeaponSimpleB",
"simpleLW": "SW5E.WeaponSimpleLW",
"martialVW": "SW5E.WeaponMartialVW",
"martialB": "SW5E.WeaponMartialB",
"martialLW": "SW5E.WeaponMartialLW",
"natural": "SW5E.WeaponNatural",
"improv": "SW5E.WeaponImprov",
"ammo": "SW5E.WeaponAmmo"
};
/* -------------------------------------------- */
/**
* Define the set of weapon property flags which can exist on a weapon
* @type {Object}
*/
SW5E.weaponProperties = {
"amm": "SW5E.WeaponPropertiesAmm",
"bur": "SW5E.WeaponPropertiesBur",
"def": "SW5E.WeaponPropertiesDef",
"dex": "SW5E.WeaponPropertiesDex",
"drm": "SW5E.WeaponPropertiesDrm",
"dgd": "SW5E.WeaponPropertiesDgd",
"dis": "SW5E.WeaponPropertiesDis",
"dpt": "SW5E.WeaponPropertiesDpt",
"dou": "SW5E.WeaponPropertiesDou",
"hvy": "SW5E.WeaponPropertiesHvy",
"hid": "SW5E.WeaponPropertiesHid",
"fin": "SW5E.WeaponPropertiesFin",
"fix": "SW5E.WeaponPropertiesFix",
"foc": "SW5E.WeaponPropertiesFoc",
"ken": "SW5E.WeaponPropertiesKen",
"lgt": "SW5E.WeaponPropertiesLgt",
"lum": "SW5E.WeaponPropertiesLum",
"pic": "SW5E.WeaponPropertiesPic",
"rap": "SW5E.WeaponPropertiesRap",
"rch": "SW5E.WeaponPropertiesRch",
"rel": "SW5E.WeaponPropertiesRel",
"ret": "SW5E.WeaponPropertiesRet",
"shk": "SW5E.WeaponPropertiesShk",
"spc": "SW5E.WeaponPropertiesSpc",
"str": "SW5E.WeaponPropertiesStr",
"thr": "SW5E.WeaponPropertiesThr",
"two": "SW5E.WeaponPropertiesTwo",
"ver": "SW5E.WeaponPropertiesVer",
"vic": "SW5E.WeaponPropertiesVic"
};
// Power Components
SW5E.powerComponents = {
"V": "SW5E.ComponentVerbal",
"S": "SW5E.ComponentSomatic",
"M": "SW5E.ComponentMaterial"
};
// Power Schools
SW5E.powerSchools = {
"lgt": "SW5E.SchoolLgt",
"uni": "SW5E.SchoolUni",
"drk": "SW5E.SchoolDrk",
"tec": "SW5E.SchoolTec",
"enh": "SW5E.SchoolEnh"
};
// Power Levels
SW5E.powerLevels = {
0: "SW5E.PowerLevel0",
1: "SW5E.PowerLevel1",
2: "SW5E.PowerLevel2",
3: "SW5E.PowerLevel3",
4: "SW5E.PowerLevel4",
5: "SW5E.PowerLevel5",
6: "SW5E.PowerLevel6",
7: "SW5E.PowerLevel7",
8: "SW5E.PowerLevel8",
9: "SW5E.PowerLevel9"
};
/**
* Define the standard slot progression by character level.
* The entries of this array represent the power slot progression for a full power-caster.
* @type {Array[]}
*/
SW5E.SPELL_SLOT_TABLE = [
[2],
[3],
[4, 2],
[4, 3],
[4, 3, 2],
[4, 3, 3],
[4, 3, 3, 1],
[4, 3, 3, 2],
[4, 3, 3, 3, 1],
[4, 3, 3, 3, 2],
[4, 3, 3, 3, 2, 1],
[4, 3, 3, 3, 2, 1],
[4, 3, 3, 3, 2, 1, 1],
[4, 3, 3, 3, 2, 1, 1],
[4, 3, 3, 3, 2, 1, 1, 1],
[4, 3, 3, 3, 2, 1, 1, 1],
[4, 3, 3, 3, 2, 1, 1, 1, 1],
[4, 3, 3, 3, 3, 1, 1, 1, 1],
[4, 3, 3, 3, 3, 2, 1, 1, 1],
[4, 3, 3, 3, 3, 2, 2, 1, 1]
];
/* -------------------------------------------- */
// Polymorph options.
SW5E.polymorphSettings = {
keepPhysical: 'SW5E.PolymorphKeepPhysical',
keepMental: 'SW5E.PolymorphKeepMental',
keepSaves: 'SW5E.PolymorphKeepSaves',
keepSkills: 'SW5E.PolymorphKeepSkills',
mergeSaves: 'SW5E.PolymorphMergeSaves',
mergeSkills: 'SW5E.PolymorphMergeSkills',
keepClass: 'SW5E.PolymorphKeepClass',
keepFeats: 'SW5E.PolymorphKeepFeats',
keepPowers: 'SW5E.PolymorphKeepPowers',
keepItems: 'SW5E.PolymorphKeepItems',
keepBio: 'SW5E.PolymorphKeepBio',
keepVision: 'SW5E.PolymorphKeepVision'
};
/* -------------------------------------------- */
/**
* Skill, ability, and tool proficiency levels
* Each level provides a proficiency multiplier
* @type {Object}
*/
SW5E.proficiencyLevels = {
0: "SW5E.NotProficient",
1: "SW5E.Proficient",
0.5: "SW5E.HalfProficient",
2: "SW5E.Expertise"
};
/* -------------------------------------------- */
// Condition Types
SW5E.conditionTypes = {
"blinded": "SW5E.ConBlinded",
"charmed": "SW5E.ConCharmed",
"deafened": "SW5E.ConDeafened",
"exhaustion": "SW5E.ConExhaustion",
"frightened": "SW5E.ConFrightened",
"grappled": "SW5E.ConGrappled",
"incapacitated": "SW5E.ConIncapacitated",
"invisible": "SW5E.ConInvisible",
"paralyzed": "SW5E.ConParalyzed",
"petrified": "SW5E.ConPetrified",
"poisoned": "SW5E.ConPoisoned",
"prone": "SW5E.ConProne",
"restrained": "SW5E.ConRestrained",
"shocked": "SW5E.ConShocked",
"stunned": "SW5E.ConStunned",
"unconscious": "SW5E.ConUnconscious"
};
// Languages
SW5E.languages = {
"aleena": "SW5E.LanguagesAleena",
"antarian": "SW5E.LanguagesAntarian",
"anzellan": "SW5E.LanguagesAnzellan",
"aqualish": "SW5E.LanguagesAqualish",
"ardennian": "SW5E.LanguagesArdennian",
"balosur": "SW5E.LanguagesBalosur",
"barabel": "SW5E.LanguagesBarabel",
"basic": "SW5E.LanguagesBasic",
"besalisk": "SW5E.LanguagesBesalisk",
"binary": "SW5E.LanguagesBinary",
"bith": "SW5E.LanguagesBith",
"bocce": "SW5E.LanguagesBocce",
"bothese": "SW5E.LanguagesBothese",
"catharese": "SW5E.LanguagesCartharese",
"cerean": "SW5E.LanguagesCerean",
"chadra-fan": "SW5E.LanguagesChadra-Fan",
"chagri": "SW5E.LanguagesChagri",
"cheunh": "SW5E.LanguagesCheunh",
"chevin": "SW5E.LanguagesChevin",
"chironan": "SW5E.LanguagesChironan",
"clawdite": "SW5E.LanguagesClawdite",
"codruese": "SW5E.LanguagesCodruese",
"colicoid": "SW5E.LanguagesColicoid",
"dashadi": "SW5E.LanguagesDashadi",
"defel": "SW5E.LanguagesDefel",
"devaronese": "SW5E.LanguagesDevaronese",
"dosh": "SW5E.LanguagesDosh",
"draethos": "SW5E.LanguagesDraethos",
"durese": "SW5E.LanguagesDurese",
"dug": "SW5E.LanguagesDug",
"ewokese": "SW5E.LanguagesEwokese",
"falleen": "SW5E.LanguagesFalleen",
"felucianese": "SW5E.LanguagesFelucianese",
"gamorrese": "SW5E.LanguagesGamorrese",
"gand": "SW5E.LanguagesGand",
"geonosian": "SW5E.LanguagesGeonosian",
"givin": "SW5E.LanguagesGivin",
"gran": "SW5E.LanguagesGran",
"gungan": "SW5E.LanguagesGungan",
"hapan": "SW5E.LanguagesHapan",
"harchese": "SW5E.LanguagesHarchese",
"herglese": "SW5E.LanguagesHerglese",
"honoghran": "SW5E.LanguagesHonoghran",
"huttese": "SW5E.LanguagesHuttese",
"iktotchese": "SW5E.LanguagesIktotchese",
"ithorese": "SW5E.LanguagesIthorese",
"jawaese": "SW5E.LanguagesJawaese",
"kaleesh": "SW5E.LanguagesKaleesh",
"kaminoan": "SW5E.LanguagesKaminoan",
"karkaran": "SW5E.LanguagesKarkaran",
"keldor": "SW5E.LanguagesKelDor",
"kharan": "SW5E.LanguagesKharan",
"killik": "SW5E.LanguagesKillik",
"klatooinian": "SW5E.LanguagesKlatooinian",
"kubazian": "SW5E.LanguagesKubazian",
"kushiban": "SW5E.LanguagesKushiban",
"kyuzo": "SW5E.LanguagesKyuzo",
"lannik": "SW5E.LanguagesLannik",
"lasat": "SW5E.LanguagesLasat",
"lowickese": "SW5E.LanguagesLowickese",
"mandoa": "SW5E.LanguagesMandoa",
"miralukese": "SW5E.LanguagesMiralukese",
"mirialan": "SW5E.LanguagesMirialan",
"moncal": "SW5E.LanguagesMonCal",
"mustafarian": "SW5E.LanguagesMustafarian",
"muun": "SW5E.LanguagesMuun",
"nautila": "SW5E.LanguagesNautila",
"ortolan": "SW5E.LanguagesOrtolan",
"pakpak": "SW5E.LanguagesPakPak",
"pyke": "SW5E.LanguagesPyke",
"quarrenese": "SW5E.LanguagesQuarrenese",
"rakata": "SW5E.LanguagesRakata",
"rattataki": "SW5E.LanguagesRattataki",
"rishii": "SW5E.LanguagesRishii",
"rodese": "SW5E.LanguagesRodese",
"selkatha": "SW5E.LanguagesSelkatha",
"semblan": "SW5E.LanguagesSemblan",
"shistavanen": "SW5E.LanguagesShistavanen",
"shyriiwook": "SW5E.LanguagesShyriiwook",
"sith": "SW5E.LanguagesSith",
"squibbian": "SW5E.LanguagesSquibbian",
"sriluurian": "SW5E.LanguagesSriluurian",
"ssi-ruuvi": "SW5E.LanguagesSsi-ruuvi",
"sullustese": "SW5E.LanguagesSullustese",
"talzzi": "SW5E.LanguagesTalzzi",
"thisspiasian": "SW5E.LanguagesThisspiasian",
"togorese": "SW5E.LanguagesTogorese",
"togruti": "SW5E.LanguagesTogruti",
"toydarian": "SW5E.LanguagesToydarian",
"tusken": "SW5E.LanguagesTusken",
"twi'leki": "SW5E.LanguagesTwileki",
"ugnaught": "SW5E.LanguagesUgnaught",
"umbaran": "SW5E.LanguagesUmbaran",
"utapese": "SW5E.LanguagesUtapese",
"verpine": "SW5E.LanguagesVerpine",
"vong": "SW5E.LanguagesVong",
"voss": "SW5E.LanguagesVoss",
"yevethan": "SW5E.LanguagesYevethan",
"zabraki": "SW5E.LanguagesZabraki",
"zygerrian": "SW5E.LanguagesZygerrian"
};
// Character Level XP Requirements
SW5E.CHARACTER_EXP_LEVELS = [
0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000,
120000, 140000, 165000, 195000, 225000, 265000, 305000, 355000]
;
// Challenge Rating XP Levels
SW5E.CR_EXP_LEVELS = [
10, 200, 450, 700, 1100, 1800, 2300, 2900, 3900, 5000, 5900, 7200, 8400, 10000, 11500, 13000, 15000, 18000,
20000, 22000, 25000, 33000, 41000, 50000, 62000, 75000, 90000, 105000, 120000, 135000, 155000
];
// Configure Optional Character Flags
SW5E.characterFlags = {
"detailOriented": {
name: "Detail Oriented",
hint: "You have advantage on Intelligence (Investigation) checks within 5 feet.",
section: "Racial Traits",
type: Boolean
},
"keenSenses": {
name: "Keen Hearing and Smell",
hint: "You have advantage on Wisdom (Perception) checks that involve hearing or smell.",
section: "Racial Traits",
type: Boolean
},
"naturallyStealthy": {
name: "Naturally Stealthy",
hint: "You can attempt to hide even when you are obscured only by a creature that is your size or larger than you.",
section: "Racial Traits",
type: Boolean
},
"nimbleEscape": {
name: "Nimble Escape",
hint: "You can take the Disengage or Hide action as a bonus action.",
section: "Racial Traits",
type: Boolean
},
"powerfulBuild": {
name: "Powerful Build",
hint: "You count as one size larger when determining your carrying capacity and the weight you can push, drag, or lift.",
section: "Racial Traits",
type: Boolean
},
"programmer": {
name: "Programmer",
hint: "Whenever you make an Intelligence (Technology) check related to computers, you are considered to have expertise in the Technology skill.",
section: "Racial Traits",
type: Boolean
},
"techResistance": {
name: "Tech Resistance",
hint: "You have advantage on Dexterity and Intelligence saving throws against tech powers.",
section: "Racial Traits",
type: Boolean
},
"unarmedCombatant": {
name: "Unarmed Combatant",
hint: "Your unarmed strikes deal 1d4 kinetic damage. You can use your choice of your Strength or Dexterity modifier for the attack and damage rolls. You must use the same modifier for both rolls.",
section: "Racial Traits",
type: Boolean
},
"undersized": {
name: "Undersized",
hint: "You cant use heavy shields, martial weapons with the two-handed property unless it also has the light property, and if a martial weapon has the versatile property, you can only wield it in two hands.",
section: "Racial Traits",
type: Boolean
},
"initiativeAdv": {
name: "Advantage on Initiative",
hint: "Provided by feats or magical items.",
section: "Feats",
type: Boolean
},
"initiativeAlert": {
name: "Alert Feat",
hint: "Provides +5 to Initiative.",
section: "Feats",
type: Boolean
},
"jackOfAllTrades": {
name: "Jack of All Trades",
hint: "Half-Proficiency to Ability Checks in which you are not already Proficient.",
section: "Feats",
type: Boolean
},
"observantFeat": {
name: "Observant Feat",
hint: "Provides a +5 to passive Perception and Investigation.",
skills: ['prc','inv'],
section: "Feats",
type: Boolean
},
"remarkableAthlete": {
name: "Remarkable Athlete.",
hint: "Half-Proficiency (rounded-up) to physical Ability Checks and Initiative.",
abilities: ['str','dex','con'],
section: "Feats",
type: Boolean
},
"weaponCriticalThreshold": {
name: "Critical Hit Threshold",
hint: "Allow for expanded critical range; for example Improved or Superior Critical",
section: "Feats",
type: Number,
placeholder: 20
}
};

View file

@ -1,125 +1,156 @@
export class Dice5e {
/** /**
* 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
* @param {string} rollMode A specific roll mode to apply as the default for the resulting roll * @param {string} rollMode A specific roll mode to apply as the default for the resulting roll
* @param {string|null} template The HTML template used to render the roll dialog * @param {string|null} template The HTML template used to render the roll dialog
* @param {string|null} title The dice roll UI window title * @param {string|null} title The dice roll UI window title
* @param {Object} speaker The ChatMessage speaker to pass when creating the chat * @param {Object} speaker The ChatMessage speaker to pass when creating the chat
* @param {string|null} flavor Flavor text to use in the posted chat message * @param {string|null} flavor Flavor text to use in the posted chat message
* @param {Boolean} fastForward Allow fast-forward advantage selection * @param {Boolean} fastForward Allow fast-forward advantage selection
* @param {Function} onClose Callback for actions to take when the dialog form is closed * @param {Function} onClose Callback for actions to take when the dialog form is closed
* @param {Object} dialogOptions Modal dialog options * @param {Object} dialogOptions Modal dialog options
* @param {boolean} advantage Apply advantage to the roll (unless otherwise specified) * @param {boolean} advantage Apply advantage to the roll (unless otherwise specified)
* @param {boolean} disadvantage Apply disadvantage to the roll (unless otherwise specified) * @param {boolean} disadvantage Apply disadvantage to the roll (unless otherwise specified)
* @param {number} critical The value of d20 result which represents a critical success * @param {number} critical The value of d20 result which represents a critical success
* @param {number} fumble The value of d20 result which represents a critical failure * @param {number} fumble The value of d20 result which represents a critical failure
* @param {number} targetValue Assign a target value against which the result of this roll should be compared * @param {number} targetValue Assign a target value against which the result of this roll should be compared
* @param {boolean} elvenAccuracy Allow Elven Accuracy to modify this roll? * @param {boolean} elvenAccuracy Allow Elven Accuracy to modify this roll?
* @param {boolean} halflingLucky Allow Halfling Luck to modify this roll? * @param {boolean} halflingLucky Allow Halfling Luck to modify this roll?
* * @param {boolean} reliableTalent Allow Reliable Talent to modify this roll?
* @return {Promise} A Promise which resolves once the roll workflow has completed * @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
*/ */
static async 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, onClose, 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}={}) { elvenAccuracy=false, halflingLucky=false, reliableTalent=false,
chatMessage=true, messageData={}}={}) {
// Handle input arguments
flavor = flavor || title; // Prepare Message Data
speaker = speaker || ChatMessage.getSpeaker(); messageData.flavor = flavor || title;
messageData.speaker = speaker || ChatMessage.getSpeaker();
const messageOptions = {rollMode: rollMode || game.settings.get("core", "rollMode")};
parts = parts.concat(["@bonus"]); parts = parts.concat(["@bonus"]);
rollMode = rollMode || game.settings.get("core", "rollMode");
let rolled = false; // Handle fast-forward events
let adv = 0;
// Define inner roll function fastForward = fastForward ?? (event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey));
const _roll = function(parts, adv, form=null) { if (fastForward) {
if ( advantage || event.altKey ) adv = 1;
// Determine the d20 roll and modifiers 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 nd = 1;
let mods = halflingLucky ? "r=1" : ""; let mods = halflingLucky ? "r=1" : "";
// Handle advantage // Handle advantage
if ( adv === 1 ) { if (adv === 1) {
nd = elvenAccuracy ? 3 : 2; nd = elvenAccuracy ? 3 : 2;
flavor += ` (${game.i18n.localize("SW5E.Advantage")})`; messageData.flavor += ` (${game.i18n.localize("SW5E.Advantage")})`;
mods += "kh"; if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].advantage = true;
mods += "kh";
} }
// Handle disadvantage // Handle disadvantage
else if ( adv === -1 ) { else if (adv === -1) {
nd = 2; nd = 2;
flavor += ` (${game.i18n.localize("SW5E.Disadvantage")})`; messageData.flavor += ` (${game.i18n.localize("SW5E.Disadvantage")})`;
mods += "kl"; if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].disadvantage = true;
mods += "kl";
} }
// Include the d20 roll // Prepend the d20 roll
parts.unshift(`${nd}d20${mods}`); let formula = `${nd}d20${mods}`;
if (reliableTalent) formula = `{${nd}d20${mods},10}kh`;
parts.unshift(formula);
// Optionally include a situational bonus // Optionally include a situational bonus
if ( form !== null ) data['bonus'] = form.bonus.value; if ( form ) {
if ( !data["bonus"] ) parts.pop(); data['bonus'] = form.bonus.value;
messageOptions.rollMode = form.rollMode.value;
}
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;
flavor += ` (${CONFIG.SW5E.abilities[data.ability]})`; messageData.flavor += ` (${CONFIG.SW5E.abilities[data.ability]})`;
} }
} }
// Execute the roll and flag critical thresholds on the d20 // Execute the roll
let roll = new Roll(parts.join(" + "), data).roll(); let roll = new Roll(parts.join(" + "), data);
const d20 = roll.parts[0]; try {
d20.options.critical = critical; roll.roll();
d20.options.fumble = fumble; } catch (err) {
if ( targetValue ) d20.options.target = targetValue; console.error(err);
ui.notifications.error(`Dice roll evaluation failed: ${err.message}`);
// Convert the roll to a chat message and return the roll return null;
rollMode = form ? form.rollMode.value : rollMode;
roll.toMessage({
speaker: speaker,
flavor: flavor
}, { rollMode });
rolled = true;
return roll;
};
// Determine whether the roll can be fast-forward
if ( fastForward === null ) {
fastForward = event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey);
} }
// Optionally allow fast-forwarding to specify advantage or disadvantage // Flag d20 options for any 20-sided dice in the roll
if ( fastForward ) { for (let d of roll.dice) {
if ( advantage || event.altKey ) return _roll(parts, 1); if (d.faces === 20) {
else if ( disadvantage || event.ctrlKey || event.metaKey ) return _roll(parts, -1); d.options.critical = critical;
else return _roll(parts, 0); d.options.fumble = fumble;
if (targetValue) d.options.target = targetValue;
}
} }
// If reliable talent was applied, add it to the flavor text
if (reliableTalent && roll.dice[0].total < 10) {
messageData.flavor += ` (${game.i18n.localize("SW5E.FlagsReliableTalent")})`;
}
return roll;
};
// Create the Roll instance
const roll = fastForward ? _roll(parts, adv) :
await _d20RollDialog({template, title, parts, data, rollMode: messageOptions.rollMode, dialogOptions, roll: _roll});
// Create a Chat Message
if ( roll && chatMessage ) roll.toMessage(messageData, messageOptions);
return roll;
}
/* -------------------------------------------- */
/**
* Present a Dialog form which creates a d20 roll once submitted
* @return {Promise<Roll>}
* @private
*/
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.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
let roll;
return new Promise(resolve => { return new Promise(resolve => {
new Dialog({ new Dialog({
title: title, title: title,
@ -127,26 +158,24 @@ export class Dice5e {
buttons: { buttons: {
advantage: { advantage: {
label: game.i18n.localize("SW5E.Advantage"), label: game.i18n.localize("SW5E.Advantage"),
callback: html => roll = _roll(parts, 1, html[0].children[0]) callback: html => resolve(roll(parts, 1, html[0].querySelector("form")))
}, },
normal: { normal: {
label: game.i18n.localize("SW5E.Normal"), label: game.i18n.localize("SW5E.Normal"),
callback: html => roll = _roll(parts, 0, html[0].children[0]) callback: html => resolve(roll(parts, 0, html[0].querySelector("form")))
}, },
disadvantage: { disadvantage: {
label: game.i18n.localize("SW5E.Disadvantage"), label: game.i18n.localize("SW5E.Disadvantage"),
callback: html => roll = _roll(parts, -1, html[0].children[0]) callback: html => resolve(roll(parts, -1, html[0].querySelector("form")))
} }
}, },
default: "normal", default: "normal",
close: html => { close: () => resolve(null)
if (onClose) onClose(html, parts, data);
resolve(rolled ? roll : false)
}
}, dialogOptions).render(true); }, dialogOptions).render(true);
}) });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
@ -169,83 +198,103 @@ export class Dice5e {
* @param {Boolean} fastForward Allow fast-forward advantage selection * @param {Boolean} fastForward Allow fast-forward advantage selection
* @param {Function} onClose Callback for actions to take when the dialog form is closed * @param {Function} onClose Callback for actions to take when the dialog form is closed
* @param {Object} dialogOptions Modal dialog options * @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 * @return {Promise} A Promise which resolves once the roll workflow has completed
*/ */
static async damageRoll({parts, actor, data, event={}, rollMode=null, template, title, speaker, flavor, export async function damageRoll({parts, actor, data, event={}, rollMode=null, template, title, speaker, flavor,
allowCritical=true, critical=false, fastForward=null, onClose, dialogOptions}) { allowCritical=true, critical=false, fastForward=null, dialogOptions, chatMessage=true, messageData={}}={}) {
// Handle input arguments // Prepare Message Data
flavor = flavor || title; messageData.flavor = flavor || title;
speaker = speaker || ChatMessage.getSpeaker(); messageData.speaker = speaker || ChatMessage.getSpeaker();
rollMode = game.settings.get("core", "rollMode"); const messageOptions = {rollMode: rollMode || game.settings.get("core", "rollMode")};
let rolled = false; parts = parts.concat(["@bonus"]);
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) {
data['bonus'] = form ? form.bonus.value : 0;
// Optionally include a situational bonus
if ( form ) {
data['bonus'] = form.bonus.value;
messageOptions.rollMode = form.rollMode.value;
}
if (!data["bonus"]) parts.pop();
// 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; let add = (actor && actor.getFlag("sw5e", "savageAttacks")) ? 1 : 0;
let mult = 2; let mult = 2;
roll.alter(add, mult); // TODO Backwards compatibility - REMOVE LATER
flavor = `${flavor} (${game.i18n.localize("SW5E.Critical")})`; if (isNewerVersion(game.data.version, "0.6.9")) roll.alter(mult, add);
} else roll.alter(add, mult);
messageData.flavor += ` (${game.i18n.localize("SW5E.Critical")})`;
// Convert the roll to a chat message if ( "flags.sw5e.roll" in messageData ) messageData["flags.sw5e.roll"].critical = true;
rollMode = form ? form.rollMode.value : rollMode;
roll.toMessage({
speaker: speaker,
flavor: flavor
}, { rollMode });
rolled = true;
return roll;
};
// Determine whether the roll can be fast-forward
if ( fastForward === null ) {
fastForward = event && (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey);
} }
// Modify the roll and handle fast-forwarding // Execute the roll
if ( fastForward ) return _roll(parts, critical || event.altKey); try {
else parts = parts.concat(["@bonus"]); return roll.roll();
} catch(err) {
console.error(err);
ui.notifications.error(`Dice roll evaluation failed: ${err.message}`);
return null;
}
};
// Render modal dialog // Create the Roll instance
template = template || "systems/sw5e/templates/chat/roll-dialog.html"; const roll = fastForward ? _roll(parts, critical || event.altKey) : await _damageRollDialog({
let dialogData = { template, title, parts, data, allowCritical, rollMode: messageOptions.rollMode, dialogOptions, roll: _roll
formula: parts.join(" + "), });
data: data,
rollMode: rollMode, // Create a Chat Message
rollModes: CONFIG.rollModes if ( roll && chatMessage ) roll.toMessage(messageData, messageOptions);
}; return roll;
const html = await renderTemplate(template, dialogData);
// Create the Dialog window }
let roll;
return new Promise(resolve => { /* -------------------------------------------- */
new Dialog({
title: title, /**
content: html, * Present a Dialog form which creates a damage roll once submitted
buttons: { * @return {Promise<Roll>}
critical: { * @private
condition: allowCritical, */
label: game.i18n.localize("SW5E.CriticalHit"), async function _damageRollDialog({template, title, parts, data, allowCritical, rollMode, dialogOptions, roll}={}) {
callback: html => roll = _roll(parts, true, html[0].children[0])
}, // Render modal dialog
normal: { template = template || "systems/sw5e/templates/chat/roll-dialog.html";
label: game.i18n.localize(allowCritical ? "SW5E.Normal" : "SW5E.Roll"), let dialogData = {
callback: html => roll = _roll(parts, false, html[0].children[0]) formula: parts.join(" + "),
}, data: data,
}, rollMode: rollMode,
default: "normal", rollModes: CONFIG.Dice.rollModes
close: html => { };
if (onClose) onClose(html, parts, data); const html = await renderTemplate(template, dialogData);
resolve(rolled ? roll : false);
} // Create the Dialog window
}, dialogOptions).render(true); return new Promise(resolve => {
}); new Dialog({
} title: title,
content: html,
buttons: {
critical: {
condition: allowCritical,
label: game.i18n.localize("SW5E.CriticalHit"),
callback: html => resolve(roll(parts, true, html[0].querySelector("form")))
},
normal: {
label: game.i18n.localize(allowCritical ? "SW5E.Normal" : "SW5E.Roll"),
callback: html => resolve(roll(parts, false, html[0].querySelector("form")))
},
},
default: "normal",
close: () => resolve(null)
}, dialogOptions).render(true);
});
} }

60
module/macros.js Normal file
View file

@ -0,0 +1,60 @@
/* -------------------------------------------- */
/* Hotbar Macros */
/* -------------------------------------------- */
/**
* Create a Macro from an Item drop.
* Get an existing item macro if one exists, otherwise create a new one.
* @param {Object} data The dropped data
* @param {number} slot The hotbar slot to use
* @returns {Promise}
*/
export async function create5eMacro(data, slot) {
if ( data.type !== "Item" ) return;
if (!( "data" in data ) ) return ui.notifications.warn("You can only create macro buttons for owned Items");
const item = data.data;
// Create the macro command
const command = `game.sw5e.rollItemMacro("${item.name}");`;
let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command));
if ( !macro ) {
macro = await Macro.create({
name: item.name,
type: "script",
img: item.img,
command: command,
flags: {"sw5e.itemMacro": true}
});
}
game.user.assignHotbarMacro(macro, slot);
return false;
}
/* -------------------------------------------- */
/**
* Create a Macro from an Item drop.
* Get an existing item macro if one exists, otherwise create a new one.
* @param {string} itemName
* @return {Promise}
*/
export function rollItemMacro(itemName) {
const speaker = ChatMessage.getSpeaker();
let actor;
if ( speaker.token ) actor = game.actors.tokens[speaker.token];
if ( !actor ) actor = game.actors.get(speaker.actor);
// Get matching items
const items = actor ? actor.items.filter(i => i.name === itemName) : [];
if ( items.length > 1 ) {
ui.notifications.warn(`Your controlled Actor ${actor.name} has more than one Item with name ${itemName}. The first matched item will be chosen.`);
} else if ( items.length === 0 ) {
return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemName}`);
}
const item = items[0];
// Trigger the item roll
if ( item.data.type === "power" ) return actor.usePower(item);
return item.roll();
}

View file

@ -136,6 +136,34 @@ export const migrateActorData = function(actor) {
return updateData; return updateData;
}; };
/* -------------------------------------------- */
/**
* Scrub an Actor's system data, removing all keys which are not explicitly defined in the system template
* @param {Object} actorData The data object for an Actor
* @return {Object} The scrubbed Actor data
*/
function cleanActorData(actorData) {
// Scrub system data
const model = game.system.model.Actor[actorData.type];
actorData.data = filterObject(actorData.data, model);
// Scrub system flags
const allowedFlags = CONFIG.SW5E.allowedActorFlags.reduce((obj, f) => {
obj[f] = null;
return obj;
}, {});
if ( actorData.flags.sw5e ) {
actorData.flags.sw5e = filterObject(actorData.flags.sw5e, allowedFlags);
}
// Return the scrubbed data
return actorData;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
@ -222,3 +250,33 @@ const _migrateRemoveDeprecated = function(ent, updateData) {
updateData[`data.${parts.join(".")}`] = null; updateData[`data.${parts.join(".")}`] = null;
} }
}; };
/* -------------------------------------------- */
/**
* A general tool to purge flags from all entities in a Compendium pack.
* @param {Compendium} pack The compendium pack to clean
* @private
*/
export async function purgeFlags(pack) {
const cleanFlags = (flags) => {
const flags5e = flags.sw5e || null;
return flags5e ? {sw5e: flags5e} : {};
};
await pack.configure({locked: false});
const content = await pack.getContent();
for ( let entity of content ) {
const update = {_id: entity.id, flags: cleanFlags(entity.data.flags)};
if ( pack.entity === "Actor" ) {
update.items = entity.data.items.map(i => {
i.flags = cleanFlags(i.flags);
return i;
})
}
await pack.updateEntity(update, {recursive: false});
console.log(`Purged flags from ${entity.name}`);
}
await pack.configure({locked: true});
}

View file

@ -4,7 +4,7 @@ import { SW5E } from "../config.js";
* A helper class for building MeasuredTemplates for 5e powers and abilities * A helper class for building MeasuredTemplates for 5e powers and abilities
* @extends {MeasuredTemplate} * @extends {MeasuredTemplate}
*/ */
export class AbilityTemplate extends MeasuredTemplate { export default class AbilityTemplate extends MeasuredTemplate {
/** /**
* A factory method to create an AbilityTemplate instance using provided data from an Item5e instance * A factory method to create an AbilityTemplate instance using provided data from an Item5e instance
@ -37,8 +37,8 @@ export 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 5ft wide case "ray": // 5e rays are most commonly 1 square (5 ft) in width
templateData.width = 5; templateData.width = target.width ?? canvas.dimensions.distance;
break; break;
default: default:
break; break;
@ -52,9 +52,8 @@ export class AbilityTemplate extends MeasuredTemplate {
/** /**
* Creates a preview of the power template * Creates a preview of the power template
* @param {Event} event The initiating click event
*/ */
drawPreview(event) { drawPreview() {
const initialLayer = canvas.activeLayer; const initialLayer = canvas.activeLayer;
this.draw(); this.draw();
this.layer.activate(); this.layer.activate();

View file

@ -11,6 +11,23 @@ export const registerSystemSettings = function() {
default: 0 default: 0
}); });
/**
* Register resting variants
*/
game.settings.register("sw5e", "restVariant", {
name: "SETTINGS.5eRestN",
hint: "SETTINGS.5eRestL",
scope: "world",
config: true,
default: "normal",
type: String,
choices: {
"normal": "SETTINGS.5eRestPHB",
"gritty": "SETTINGS.5eRestGritty",
"epic": "SETTINGS.5eRestEpic",
}
});
/** /**
* Register diagonal movement rule setting * Register diagonal movement rule setting
*/ */
@ -23,7 +40,8 @@ export const registerSystemSettings = function() {
type: String, type: String,
choices: { choices: {
"555": "SETTINGS.5eDiagPHB", "555": "SETTINGS.5eDiagPHB",
"5105": "SETTINGS.5eDiagDMG" "5105": "SETTINGS.5eDiagDMG",
"EUCL": "SETTINGS.5eDiagEuclidean",
}, },
onChange: rule => canvas.grid.diagonalRule = rule onChange: rule => canvas.grid.diagonalRule = rule
}); });
@ -31,21 +49,14 @@ export const registerSystemSettings = function() {
/** /**
* Register Initiative formula setting * Register Initiative formula setting
*/ */
function _set5eInitiative(tiebreaker) {
CONFIG.Combat.initiative.tiebreaker = tiebreaker;
CONFIG.Combat.initiative.decimals = tiebreaker ? 2 : 0;
if ( ui.combat && ui.combat._rendered ) ui.combat.render();
}
game.settings.register("sw5e", "initiativeDexTiebreaker", { game.settings.register("sw5e", "initiativeDexTiebreaker", {
name: "SETTINGS.5eInitTBN", name: "SETTINGS.5eInitTBN",
hint: "SETTINGS.5eInitTBL", hint: "SETTINGS.5eInitTBL",
scope: "world", scope: "world",
config: true, config: true,
default: false, default: false,
type: Boolean, type: Boolean
onChange: enable => _set5eInitiative(enable)
}); });
_set5eInitiative(game.settings.get("sw5e", "initiativeDexTiebreaker"));
/** /**
* Require Currency Carrying Weight * Require Currency Carrying Weight

View file

@ -13,11 +13,13 @@ export const preloadHandlebarsTemplates = async function() {
"systems/sw5e/templates/actors/parts/actor-inventory.html", "systems/sw5e/templates/actors/parts/actor-inventory.html",
"systems/sw5e/templates/actors/parts/actor-features.html", "systems/sw5e/templates/actors/parts/actor-features.html",
"systems/sw5e/templates/actors/parts/actor-powerbook.html", "systems/sw5e/templates/actors/parts/actor-powerbook.html",
"systems/sw5e/templates/actors/parts/actor-effects.html",
// Item Sheet Partials // Item Sheet Partials
"systems/sw5e/templates/items/parts/item-action.html", "systems/sw5e/templates/items/parts/item-action.html",
"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"
]; ];
// Load the template parts // Load the template parts

3101
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View file

@ -1,6 +1,6 @@
{ {
"Actor": { "Actor": {
"types": ["character", "npc"], "types": ["character", "npc", "vehicle"],
"templates": { "templates": {
"common": { "common": {
"abilities": { "abilities": {
@ -31,7 +31,7 @@
}, },
"attributes": { "attributes": {
"ac": { "ac": {
"min": 0 "value": 10
}, },
"hp": { "hp": {
"value": 10, "value": 10,
@ -43,19 +43,47 @@
"init": { "init": {
"value": 0, "value": 0,
"bonus": 0 "bonus": 0
}, }
"speed": {
"value": "30 ft",
"special": ""
},
"powercasting": "int"
}, },
"details": { "details": {
"alignment": "",
"biography": { "biography": {
"value": "", "value": "",
"public": "" "public": ""
}
},
"traits": {
"size": "med",
"di": {
"value": [],
"custom": ""
}, },
"dr": {
"value": [],
"custom": ""
},
"dv": {
"value": [],
"custom": ""
},
"ci": {
"value": [],
"custom": ""
}
},
"currency": {
"gc": 0
}
},
"creature": {
"attributes": {
"powercasting": "int",
"speed": {
"value": "30 ft",
"special": ""
}
},
"details": {
"alignment": "",
"species": "" "species": ""
}, },
"skills": { "skills": {
@ -133,81 +161,51 @@
} }
}, },
"traits": { "traits": {
"size": "med",
"senses": "", "senses": "",
"languages": { "languages": {
"value": [], "value": [],
"custom": "" "custom": ""
},
"di": {
"value": [],
"custom": ""
},
"dr": {
"value": [],
"custom": ""
},
"dv": {
"value": [],
"custom": ""
},
"ci": {
"value": [],
"custom": ""
} }
}, },
"currency": {
"gc": 0
},
"powers": { "powers": {
"power1": { "power1": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power2": { "power2": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power3": { "power3": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power4": { "power4": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power5": { "power5": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power6": { "power6": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power7": { "power7": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power8": { "power8": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"power9": { "power9": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
}, },
"pact": { "pact": {
"value": 0, "value": 0,
"max": 0,
"override": null "override": null
} }
}, },
@ -240,12 +238,16 @@
} }
}, },
"character": { "character": {
"templates": ["common"], "templates": ["common", "creature"],
"attributes": { "attributes": {
"death": { "death": {
"success": 0, "success": 0,
"failure": 0 "failure": 0
}, },
"encumbrance": {
"value": null,
"max": null
},
"exhaustion": 0, "exhaustion": 0,
"inspiration": 0 "inspiration": 0
}, },
@ -256,6 +258,7 @@
"min": 0, "min": 0,
"max": 300 "max": 300
}, },
"appearance": "",
"trait": "", "trait": "",
"ideal": "", "ideal": "",
"bond": "", "bond": "",
@ -297,7 +300,7 @@
} }
}, },
"npc": { "npc": {
"templates": ["common"], "templates": ["common", "creature"],
"details": { "details": {
"type": "", "type": "",
"environment": "", "environment": "",
@ -322,13 +325,64 @@
"initiative": 0 "initiative": 0
} }
} }
},
"vehicle": {
"templates": ["common"],
"abilities": {
"int": {
"value": 0
},
"wis": {
"value": 0
},
"cha": {
"value": 0
}
},
"attributes": {
"ac": {
"value": null,
"motionless": ""
},
"actions": {
"stations": false,
"value": 0,
"thresholds": {
"2": null,
"1": null,
"0": null
}
},
"hp": {
"value": null,
"max": null,
"dt": null,
"mt": null
},
"capacity": {
"creature": "",
"cargo": 0
},
"speed": ""
},
"traits": {
"size": "lg",
"dimensions": "",
"di": {
"value": ["poison", "psychic"]
},
"ci": {
"value": ["blinded", "charmed", "deafened", "frightened", "paralyzed", "petrified", "poisoned", "stunned",
"unconscious"]
}
},
"cargo": {
"crew": [],
"passengers": []
}
} }
}, },
"Item": { "Item": {
<<<<<<< Updated upstream
"types": ["weapon", "equipment", "consumable", "tool", "loot", "class", "power", "feat", "species", "backpack"],
"templates": {
=======
"types": ["weapon", "equipment", "consumable", "tool", "loot", "class", "power", "feat", "species", "backpack", "archetype", "classfeature", "background"], "types": ["weapon", "equipment", "consumable", "tool", "loot", "class", "power", "feat", "species", "backpack", "archetype", "classfeature", "background"],
"templates": { "templates": {
"archetypeDescription": { "archetypeDescription": {
@ -389,7 +443,6 @@
"value": "" "value": ""
} }
}, },
>>>>>>> Stashed changes
"itemDescription": { "itemDescription": {
"description": { "description": {
"value": "", "value": "",
@ -398,8 +451,6 @@
}, },
"source": "" "source": ""
}, },
<<<<<<< Updated upstream
=======
"classDescription": { "classDescription": {
"className": "", "className": "",
"description": { "description": {
@ -409,7 +460,6 @@
"value": "" "value": ""
} }
}, },
>>>>>>> Stashed changes
"speciesDescription": { "speciesDescription": {
"data": "$characteristics-table", "data": "$characteristics-table",
"description": { "description": {
@ -440,6 +490,7 @@
}, },
"target": { "target": {
"value": null, "value": null,
"width": null,
"units": "", "units": "",
"type": "" "type": ""
}, },
@ -452,6 +503,11 @@
"value": 0, "value": 0,
"max": 0, "max": 0,
"per": null "per": null
},
"consume": {
"type": "",
"target": null,
"amount": null
} }
}, },
"action": { "action": {
@ -470,6 +526,17 @@
"dc": null, "dc": null,
"scaling": "power" "scaling": "power"
} }
},
"mountable": {
"armor": {
"value": 10
},
"hp": {
"value": 0,
"max": 0,
"dt": null,
"conditions": ""
}
} }
}, },
"archetype": { "archetype": {
@ -505,31 +572,28 @@
}, },
"powercasting": "none" "powercasting": "none"
}, },
<<<<<<< Updated upstream
=======
"classfeature": { "classfeature": {
"templates": ["itemDescription", "activatedEffect", "action"], "templates": ["itemDescription", "activatedEffect", "action"],
"className": "" "className": ""
}, },
>>>>>>> Stashed changes
"consumable": { "consumable": {
"templates": ["itemDescription", "physicalItem", "activatedEffect", "action"], "templates": ["itemDescription", "physicalItem", "activatedEffect", "action"],
"consumableType": "potion", "consumableType": "potion",
"uses": { "uses": {
"value": 0, "autoDestroy": false
"max": 0,
"per": null,
"autoUse": true,
"autoDestroy": true
} }
}, },
"equipment": { "equipment": {
"templates": ["itemDescription", "physicalItem", "activatedEffect", "action"], "templates": ["itemDescription", "physicalItem", "activatedEffect", "action", "mountable"],
"armor": { "armor": {
"type": "light", "type": "light",
"value": 10, "value": 10,
"dex": null "dex": null
}, },
"speed": {
"value": null,
"conditions": ""
},
"strength": 0, "strength": 0,
"stealth": false, "stealth": false,
"proficient": true "proficient": true
@ -547,10 +611,6 @@
}, },
"species": { "species": {
"templates": ["speciesDescription"] "templates": ["speciesDescription"]
<<<<<<< Updated upstream
=======
>>>>>>> Stashed changes
}, },
"tool": { "tool": {
"templates": ["itemDescription", "physicalItem"], "templates": ["itemDescription", "physicalItem"],
@ -581,13 +641,13 @@
"prepared": false "prepared": false
}, },
"scaling": { "scaling": {
"mode": null, "mode": "none",
"formula": null "formula": null
} }
}, },
"weapon": { "weapon": {
"templates": ["itemDescription", "physicalItem" ,"activatedEffect", "action"], "templates": ["itemDescription", "physicalItem" ,"activatedEffect", "action", "mountable"],
"weaponType": "simpleM", "weaponType": "simpleVW",
"properties": {}, "properties": {},
"proficient": true "proficient": true
} }

View file

@ -1,488 +0,0 @@
{
"Actor": {
"types": ["character", "npc"],
"templates": {
"common": {
"abilities": {
"str": {
"value": 10,
"proficient": 0
},
"dex": {
"value": 10,
"proficient": 0
},
"con": {
"value": 10,
"proficient": 0
},
"int": {
"value": 10,
"proficient": 0
},
"wis": {
"value": 10,
"proficient": 0
},
"cha": {
"value": 10,
"proficient": 0
}
},
"attributes": {
"ac": {
"min": 0
},
"hp": {
"value": 10,
"min": 0,
"max": 10,
"temp": 0,
"tempmax": 0
},
"init": {
"value": 0,
"bonus": 0
},
"speed": {
"value": "30 ft",
"special": ""
},
"powercasting": "int"
},
"details": {
"alignment": "",
"biography": {
"value": "",
"public": ""
},
"race": ""
},
"skills": {
"acr": {
"value": 0,
"ability": "dex"
},
"ani": {
"value": 0,
"ability": "wis"
},
"ath": {
"value": 0,
"ability": "str"
},
"dec": {
"value": 0,
"ability": "cha"
},
"ins": {
"value": 0,
"ability": "wis"
},
"itm": {
"value": 0,
"ability": "cha"
},
"inv": {
"value": 0,
"ability": "int"
},
"lor": {
"value": 0,
"ability": "int"
},
"med": {
"value": 0,
"ability": "wis"
},
"nat": {
"value": 0,
"ability": "int"
},
"pil": {
"value": 0,
"ability": "int"
},
"prc": {
"value": 0,
"ability": "wis"
},
"prf": {
"value": 0,
"ability": "cha"
},
"per": {
"value": 0,
"ability": "cha"
},
"slt": {
"value": 0,
"ability": "dex"
},
"ste": {
"value": 0,
"ability": "dex"
},
"sur": {
"value": 0,
"ability": "wis"
},
"tec": {
"value": 0,
"ability": "int"
}
},
"traits": {
"size": "med",
"senses": "",
"languages": {
"value": [],
"custom": ""
},
"di": {
"value": [],
"custom": ""
},
"dr": {
"value": [],
"custom": ""
},
"dv": {
"value": [],
"custom": ""
},
"ci": {
"value": [],
"custom": ""
}
},
"currency": {
"gc": 0
},
"powers": {
"power1": {
"value": 0,
"max": 0,
"override": null
},
"power2": {
"value": 0,
"max": 0,
"override": null
},
"power3": {
"value": 0,
"max": 0,
"override": null
},
"power4": {
"value": 0,
"max": 0,
"override": null
},
"power5": {
"value": 0,
"max": 0,
"override": null
},
"power6": {
"value": 0,
"max": 0,
"override": null
},
"power7": {
"value": 0,
"max": 0,
"override": null
},
"power8": {
"value": 0,
"max": 0,
"override": null
},
"power9": {
"value": 0,
"max": 0,
"override": null
},
"pact": {
"value": 0,
"max": 0,
"override": null
}
},
"bonuses": {
"mwak": {
"attack": "",
"damage": ""
},
"rwak": {
"attack": "",
"damage": ""
},
"mpak": {
"attack": "",
"damage": ""
},
"rpak": {
"attack": "",
"damage": ""
},
"abilities": {
"check": "",
"save": "",
"skill": ""
},
"power": {
"dc": ""
}
}
}
},
"character": {
"templates": ["common"],
"attributes": {
"death": {
"success": 0,
"failure": 0
},
"exhaustion": 0,
"inspiration": 0
},
"details": {
"background": "",
"xp": {
"value": 0,
"min": 0,
"max": 300
},
"trait": "",
"ideal": "",
"bond": "",
"flaw": ""
},
"resources": {
"primary": {
"value": 0,
"max": 0,
"sr": 0,
"lr": 0
},
"secondary": {
"value": 0,
"max": 0,
"sr": 0,
"lr": 0
},
"tertiary": {
"value": 0,
"max": 0,
"sr": 0,
"lr": 0
}
},
"traits": {
"weaponProf": {
"value": [],
"custom": ""
},
"armorProf": {
"value": [],
"custom": ""
},
"toolProf": {
"value": [],
"custom": ""
}
}
},
"npc": {
"templates": ["common"],
"details": {
"type": "",
"environment": "",
"cr": 1,
"powerLevel": 0,
"xp": {
"value": 10
},
"source": ""
},
"resources": {
"legact": {
"value": 0,
"max": 0
},
"legres": {
"value": 0,
"max": 0
},
"lair": {
"value": 0,
"initiative": 0
}
}
}
},
"Item": {
"types": ["weapon", "equipment", "consumable", "tool", "loot", "class", "power", "feat", "backpack"],
"templates": {
"itemDescription": {
"description": {
"value": "",
"chat": "",
"unidentified": ""
},
"source": ""
},
"physicalItem": {
"quantity": 1,
"weight": 0,
"price": 0,
"attuned": false,
"equipped": false,
"rarity": "",
"identified": true
},
"activatedEffect": {
"activation": {
"type": "",
"cost": 0,
"condition": ""
},
"duration": {
"value": null,
"units": ""
},
"target": {
"value": null,
"units": "",
"type": ""
},
"range": {
"value": null,
"long": null,
"units": ""
},
"uses": {
"value": 0,
"max": 0,
"per": null
}
},
"action": {
"ability": null,
"actionType": null,
"attackBonus": 0,
"chatFlavor": "",
"critical": null,
"damage": {
"parts": [],
"versatile": ""
},
"formula": "",
"save": {
"ability": "",
"dc": null,
"scaling": "power"
}
}
},
"backpack": {
"templates": ["itemDescription", "physicalItem"],
"capacity": {
"type": "weight",
"value": 0,
"weightless": false
},
"currency": {
"gc": 0
}
},
"class": {
"templates": ["itemDescription"],
"levels": 1,
"subclass": "",
"hitDice": "d6",
"hitDiceUsed": 0,
"skills": {
"number": 2,
"choices": [],
"value": []
},
"powercasting": "none"
},
"consumable": {
"templates": ["itemDescription", "physicalItem", "activatedEffect", "action"],
"consumableType": "potion",
"uses": {
"value": 0,
"max": 0,
"per": null,
"autoUse": true,
"autoDestroy": true
}
},
"equipment": {
"templates": ["itemDescription", "physicalItem", "activatedEffect", "action"],
"armor": {
"type": "light",
"value": 10,
"dex": null
},
"strength": 0,
"stealth": false,
"proficient": true
},
"feat": {
"templates": ["itemDescription", "activatedEffect", "action"],
"requirements": "",
"recharge": {
"value": null,
"charged": false
}
},
"loot": {
"templates": ["itemDescription", "physicalItem"]
},
"tool": {
"templates": ["itemDescription", "physicalItem"],
"ability": "int",
"chatFlavor": "",
"proficient": 0
},
"power": {
"templates": ["itemDescription", "activatedEffect", "action"],
"level": 1,
"school": "",
"components": {
"value": "",
"vocal": false,
"somatic": false,
"material": false,
"ritual": false,
"concentration": false
},
"materials": {
"value": "",
"consumed": false,
"cost": 0,
"supply": 0
},
"preparation": {
"mode": null,
"prepared": false
},
"scaling": {
"mode": null,
"formula": null
}
},
"weapon": {
"templates": ["itemDescription", "physicalItem" ,"activatedEffect", "action"],
"weaponType": "simpleM",
"properties": {},
"proficient": true
}
}
}

View file

@ -4,31 +4,33 @@
<header class="sheet-header flexrow"> <header class="sheet-header flexrow">
<img class="profile" src="{{actor.img}}" title="{{actor.name}}" data-edit="img"/> <img class="profile" src="{{actor.img}}" title="{{actor.name}}" data-edit="img"/>
<div class="header-details flexrow"> <section class="header-details flexrow">
<h1 class="charname"> <h1 class="charname">
<input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'SW5E.Name' }}"/> <input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'SW5E.Name' }}"/>
</h1> </h1>
<div class="charlevel"> <aside class="header-exp flexcol">
<div class="level {{#if disableExperience}}noxp{{/if}}"> <div class="charlevel">
<label>{{ localize "SW5E.Level" }} {{data.details.level}}</label> <label>{{ localize "SW5E.Level" }} {{data.details.level}}</label>
<span class="levels">{{classLabels}}</span>
</div> </div>
{{#unless disableExperience}} {{#unless disableExperience}}
<div class="experience"> <div class="experience flexrow">
<input name="data.details.xp.value" type="text" value="{{data.details.xp.value}}" <input name="data.details.xp.value" type="text" value="{{data.details.xp.value}}" placeholder="0" data-dtype="Number"/>
data-dtype="Number" placeholder="0"/> <span class="sep">/</span>
<span class="max"> / {{data.details.xp.max}}</span> <span class="max">{{data.details.xp.max}}</span>
</div> </div>
<div class="xpbar"> <div class="xpbar">
<span class="bar" style="width: {{data.details.xp.pct}}%"></span> <span class="bar" style="width: {{data.details.xp.pct}}%"></span>
</div> </div>
{{/unless}} {{/unless}}
</div> </aside>
{{!-- Character Summary --}} {{!-- Character Summary --}}
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
<input type="text" name="data.details.race" value="{{data.details.race}}" placeholder="{{ localize 'SW5E.Species' }}"/> <input type="text" name="data.details.species" value="{{data.details.species}}" placeholder="{{ localize 'SW5E.Species' }}"/>
</li> </li>
<li> <li>
<input type="text" name="data.details.background" value="{{data.details.background}}" placeholder="{{ localize 'SW5E.Background' }}"/> <input type="text" name="data.details.background" value="{{data.details.background}}" placeholder="{{ localize 'SW5E.Background' }}"/>
@ -36,6 +38,9 @@
<li> <li>
<input type="text" name="data.details.alignment" value="{{data.details.alignment}}" placeholder="{{ localize 'SW5E.Alignment' }}"/> <input type="text" name="data.details.alignment" value="{{data.details.alignment}}" placeholder="{{ localize 'SW5E.Alignment' }}"/>
</li> </li>
<li class="proficiency">
<span>{{ localize "SW5E.Proficiency" }} {{numberFormat data.attributes.prof decimals=0 sign=true}}</span>
</li>
</ul> </ul>
{{!-- Header Attributes --}} {{!-- Header Attributes --}}
@ -43,29 +48,36 @@
<li class="attribute health"> <li class="attribute health">
<h4 class="attribute-name box-title">{{ localize "SW5E.Health" }}</h4> <h4 class="attribute-name box-title">{{ localize "SW5E.Health" }}</h4>
<div class="attribute-value multiple"> <div class="attribute-value multiple">
<input name="data.attributes.hp.value" type="text" value="{{data.attributes.hp.value}}" <input name="data.attributes.hp.value" type="text" value="{{data.attributes.hp.value}}" placeholder="10" data-dtype="Number"/>
data-dtype="Number" placeholder="10"/>
<span class="sep"> / </span> <span class="sep"> / </span>
<input name="data.attributes.hp.max" type="text" value="{{data.attributes.hp.max}}" <input name="data.attributes.hp.max" type="text" value="{{data.attributes.hp.max}}" placeholder="10" data-dtype="Number"/>
data-dtype="Number" placeholder="10"/>
</div> </div>
<footer class="attribute-footer"> <footer class="attribute-footer">
<input name="data.attributes.hp.temp" type="text" class="temphp" placeholder="+{{ localize 'SW5E.Temp' }}" <input name="data.attributes.hp.temp" type="text" class="temphp" placeholder="+{{ localize 'SW5E.Temp' }}"
value="{{data.attributes.hp.temp}}" data-dtype="{{data.attributes.hp.type}}"/> value="{{data.attributes.hp.temp}}" data-dtype="Number"/>
<input name="data.attributes.hp.tempmax" type="text" class="temphp" placeholder="+{{ localize 'SW5E.Max' }}" <input name="data.attributes.hp.tempmax" type="text" class="temphp" placeholder="+{{ localize 'SW5E.Max' }}"
value="{{data.attributes.hp.tempmax}}" data-dtype="{{data.attributes.hp.type}}"/> value="{{data.attributes.hp.tempmax}}" data-dtype="Number"/>
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{ localize "SW5E.HitDice" }}</h4>
<div class="attribute-value multiple">
<label class="hit-dice">{{data.attributes.hd}} <span class="sep"> / </span> {{data.details.level}}</label>
</div>
<footer class="attribute-footer">
<a class="rest short-rest">{{ localize "SW5E.RestS" }}</a>
<a class="rest long-rest">{{ localize "SW5E.RestL" }}</a>
</footer> </footer>
</li> </li>
<li class="attribute"> <li class="attribute">
<h4 class="attribute-name box-title">{{ localize "SW5E.ArmorClass" }}</h4> <h4 class="attribute-name box-title">{{ localize "SW5E.ArmorClass" }}</h4>
<div class="attribute-value"> <div class="attribute-value">
<input name="data.attributes.ac.value" type="text" value="{{data.attributes.ac.value}}" <input name="data.attributes.ac.value" type="number" value="{{data.attributes.ac.value}}" placeholder="10"/>
data-dtype="Number" placeholder="10"/>
</div> </div>
<footer class="attribute-footer"> <footer class="attribute-footer">
<span>{{ localize "SW5E.Proficiency" }}</span> <span class="power-dc">{{localize "SW5E.PowerDC"}} {{data.attributes.powerdc}}</span>
<span>{{numberFormat data.attributes.prof decimals=0 sign=true}}</span>
</footer> </footer>
</li> </li>
@ -81,18 +93,19 @@
</footer> </footer>
</li> </li>
<li class="attribute"> <li class="attribute initiative">
<h4 class="attribute-name box-title">{{ localize "SW5E.HitDice" }}</h4> <h4 class="attribute-name box-title">{{ localize "SW5E.Initiative" }}</h4>
<div class="attribute-value multiple"> <div class="attribute-value">
<label class="hit-dice">{{data.attributes.hd}} / {{data.details.level}}</label> <span>{{numberFormat data.attributes.init.total decimals=0 sign=true}}</span>
</div> </div>
<footer class="attribute-footer"> <footer class="attribute-footer">
<a class="rest short-rest">{{ localize "SW5E.RestS" }}</a> <span>{{ localize "SW5E.Modifier" }}</span>
<a class="rest long-rest">{{ localize "SW5E.RestL" }}</a> <input name="data.attributes.init.value" type="number" placeholder="0"
value="{{numberFormat data.attributes.init.value decimals=0 sign=true}}"/>
</footer> </footer>
</li> </li>
</ul> </ul>
</div> </section>
</header> </header>
{{!-- NPC Sheet Navigation --}} {{!-- NPC Sheet Navigation --}}
@ -101,6 +114,7 @@
<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="biography">{{ localize "SW5E.Biography" }}</a> <a class="item" data-tab="biography">{{ localize "SW5E.Biography" }}</a>
</nav> </nav>
@ -114,11 +128,11 @@
{{#each data.abilities as |ability id|}} {{#each data.abilities as |ability id|}}
<li class="ability {{#if ability.proficient}}proficient{{/if}}" data-ability="{{id}}"> <li class="ability {{#if ability.proficient}}proficient{{/if}}" data-ability="{{id}}">
<h4 class="ability-name box-title rollable">{{ability.label}}</h4> <h4 class="ability-name box-title rollable">{{ability.label}}</h4>
<input class="ability-score" name="data.abilities.{{id}}.value" type="text" value="{{ability.value}}" data-dtype="Number" placeholder="10"/> <input class="ability-score" name="data.abilities.{{id}}.value" type="number" value="{{ability.value}}" placeholder="10"/>
<div class="ability-modifiers flexrow"> <div class="ability-modifiers flexrow">
<span class="ability-mod" title="Modifier">{{numberFormat ability.mod decimals=0 sign=true}}</span> <span class="ability-mod" title="Modifier">{{numberFormat ability.mod decimals=0 sign=true}}</span>
<input type="hidden" name="data.abilities.{{id}}.proficient" value="{{ability.proficient}}" data-dtype="Number"/> <input type="hidden" name="data.abilities.{{id}}.proficient" value="{{ability.proficient}}" data-dtype="Number"/>
<a class="proficiency-toggle ability-proficiency" title="Proficiency">{{{ability.icon}}}</a> <a class="proficiency-toggle ability-proficiency" title="{{ localize 'SW5E.Proficiency' }}">{{{ability.icon}}}</a>
<span class="ability-save" title="Saving Throw">{{numberFormat ability.save decimals=0 sign=true}}</span> <span class="ability-save" title="Saving Throw">{{numberFormat ability.save decimals=0 sign=true}}</span>
</div> </div>
</li> </li>
@ -133,13 +147,13 @@
<a class="proficiency-toggle skill-proficiency" title="{{skill.hover}}">{{{skill.icon}}}</a> <a class="proficiency-toggle skill-proficiency" title="{{skill.hover}}">{{{skill.icon}}}</a>
<h4 class="skill-name rollable">{{skill.label}}</h4> <h4 class="skill-name rollable">{{skill.label}}</h4>
<span class="skill-ability">{{skill.ability}}</span> <span class="skill-ability">{{skill.ability}}</span>
<span class="skill-mod">{{numberFormat skill.mod decimals=0 sign=true}}</span> <span class="skill-mod">{{numberFormat skill.total decimals=0 sign=true}}</span>
<span class="skill-passive">({{skill.passive}})</span> <span class="skill-passive">({{skill.passive}})</span>
</li> </li>
{{/each}} {{/each}}
</ul> </ul>
<section class="center-pane"> <section class="center-pane flexcol">
{{!-- Body Attributes --}} {{!-- Body Attributes --}}
<ul class="attributes flexrow"> <ul class="attributes flexrow">
@ -149,58 +163,44 @@
<input name="data.resources.{{res.name}}.label" type="text" value="{{res.label}}" <input name="data.resources.{{res.name}}.label" type="text" value="{{res.label}}"
placeholder="{{res.placeholder}}" /> placeholder="{{res.placeholder}}" />
</h4> </h4>
<div class="attribute-value multiple"> <div class="attribute-value">
<input name="data.resources.{{res.name}}.value" type="text" value="{{res.value}}" <label class="recharge checkbox">
data-dtype="Number" placeholder="0"/>
<span class="sep"> / </span>
<input name="data.resources.{{res.name}}.max" type="text" value="{{res.max}}"
data-dtype="Number" placeholder="0"/>
</div>
<footer class="attribute-footer">
<label class="checkbox">
{{ localize "SW5E.AbbreviationSR" }} <input name="data.resources.{{res.name}}.sr" type="checkbox" {{checked res.sr}}/> {{ localize "SW5E.AbbreviationSR" }} <input name="data.resources.{{res.name}}.sr" type="checkbox" {{checked res.sr}}/>
</label> </label>
<label class="checkbox">
<input name="data.resources.{{res.name}}.value" type="number" value="{{res.value}}" placeholder="0"/>
<span class="sep"> / </span>
<input name="data.resources.{{res.name}}.max" type="number" value="{{res.max}}" placeholder="0"/>
<label class="recharge checkbox">
{{ localize "SW5E.AbbreviationLR" }} <input name="data.resources.{{res.name}}.lr" type="checkbox" {{checked res.lr}}/> {{ localize "SW5E.AbbreviationLR" }} <input name="data.resources.{{res.name}}.lr" type="checkbox" {{checked res.lr}}/>
</label> </label>
</footer> </div>
</li> </li>
{{/each}} {{/each}}
<li class="attribute initiative">
<h4 class="attribute-name box-title">{{ localize "SW5E.Initiative" }}</h4>
<div class="attribute-value">
<span>{{numberFormat data.attributes.init.total decimals=0 sign=true}}</span>
</div>
<footer class="attribute-footer">
<span>{{ localize "SW5E.Modifier" }}</span>
<input name="data.attributes.init.value" type="text" placeholder="0" data-dtype="Number"
value="{{numberFormat data.attributes.init.value decimals=0 sign=true}}"/>
</footer>
</li>
</ul> </ul>
{{!-- Counters --}} {{!-- Counters --}}
<div class="counters flexrow"> <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="death-save rollable">{{ 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 type="text" name="data.attributes.death.success" data-dtype="Number" placeholder="0" <input name="data.attributes.death.success" type="number" placeholder="0"
value="{{data.attributes.death.success}}"/> value="{{data.attributes.death.success}}"/>
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
<input type="text" name="data.attributes.death.failure" data-dtype="Number" placeholder="0" <input name="data.attributes.death.failure" type="number" placeholder="0"
value="{{data.attributes.death.failure}}"/> value="{{data.attributes.death.failure}}"/>
</div> </div>
</div> </div>
<div class="counter flexrow"> <div class="counter flexrow exhaustion">
<h4>{{ localize "SW5E.Exhaustion" }}</h4> <h4>{{ localize "SW5E.Exhaustion" }}</h4>
<div class="counter-value"> <div class="counter-value">
<input type="text" name="data.attributes.exhaustion" data-dtype="Number" placeholder="0" <input name="data.attributes.exhaustion" type="number" placeholder="0"
value="{{data.attributes.exhaustion}}" /> value="{{data.attributes.exhaustion}}" />
</div> </div>
</div> </div>
<div class="counter flexrow"> <div class="counter flexrow inspiration">
<h4>{{ localize "SW5E.Inspiration" }}</h4> <h4>{{ localize "SW5E.Inspiration" }}</h4>
<div class="counter-value"> <div class="counter-value">
<input type="checkbox" name="data.attributes.inspiration" data-dtype="Boolean" <input type="checkbox" name="data.attributes.inspiration" data-dtype="Boolean"
@ -228,10 +228,29 @@
<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/parts/actor-powerbook.html"}}
</div> </div>
{{!-- Effects Tab --}}
<div class="tab effects flexcol" data-group="primary" data-tab="effects">
{{> "systems/sw5e/templates/actors/parts/actor-effects.html"}}
</div>
{{!-- Biography Tab --}} {{!-- Biography Tab --}}
<div class="tab biography flexcol" data-group="primary" data-tab="biography"> <div class="tab flexrow" data-group="primary" data-tab="biography">
{{editor content=data.details.biography.value target="data.details.biography.value" button=true owner=owner editable=editable}} <div class="characteristics flexcol">
<label>{{ localize "SW5E.Appearance" }}</label>
<textarea name="data.details.appearance">{{data.details.appearance}}</textarea>
<label>{{ localize "SW5E.PersonalityTraits" }}</label>
<textarea name="data.details.trait">{{data.details.trait}}</textarea>
<label>{{ localize "SW5E.Ideals" }}</label>
<textarea name="data.details.ideal">{{data.details.ideal}}</textarea>
<label>{{ localize "SW5E.Bonds" }}</label>
<textarea name="data.details.bond">{{data.details.bond}}</textarea>
<label>{{ localize "SW5E.Flaws" }}</label>
<textarea name="data.details.flaw">{{data.details.flaw}}</textarea>
</div>
<div class="biography">
{{editor content=data.details.biography.value target="data.details.biography.value" button=true owner=owner editable=editable}}
</div>
</div> </div>
</section> </section>
</form> </form>

View file

@ -1,21 +1,20 @@
<form class="{{cssClass}}" autocomplete="off"> <form class="{{cssClass}} flexcol limited" autocomplete="off">
<!-- HEADER --> {{!-- Sheet Header --}}
<header class="sheet-header"> <header class="sheet-header flexrow">
<h1 class="charname"> <img class="profile" src="{{actor.img}}" title="{{actor.name}}" data-edit="img"/>
<input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'SW5E.Name' }}"/>
</h1> <section class="header-details flexrow">
<h1 class="charname">
<input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'SW5E.Name' }}"/>
</h1>
</section>
</header> </header>
<!-- BODY --> {{!-- Sheet Body --}}
<section class="sheet-body"> <section class="sheet-body">
<div class="tab biography"> <div class="tab biography">
{{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>
<!-- SIDEBAR -->
<section class="sheet-sidebar">
<img class="sheet-profile" src="{{actor.img}}" title="{{actor.name}}" height="220" width="220" data-edit="img"/>
</section>
</form> </form>

View file

@ -4,33 +4,76 @@
<header class="sheet-header flexrow"> <header class="sheet-header flexrow">
<img class="profile" src="{{actor.img}}" title="{{actor.name}}" data-edit="img"/> <img class="profile" src="{{actor.img}}" title="{{actor.name}}" data-edit="img"/>
<div class="header-details flexrow"> <section class="header-details flexrow">
<h1 class="charname"> <h1 class="charname">
<input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'SW5E.Name' }}"/> <input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'SW5E.Name' }}"/>
</h1> </h1>
<div class="charlevel"> <aside class="header-exp flexcol">
<div class="level"> <div class="cr">
<label>{{ localize "SW5E.AbbreviationCR" }}</label> <label>{{ localize "SW5E.AbbreviationCR" }}</label>
<input name="data.details.cr" type="text" value="{{labels.cr}}" placeholder="1"/> <input name="data.details.cr" type="text" value="{{labels.cr}}" placeholder="1"/>
</div> </div>
<div class="experience"> <div class="experience">
<span>{{data.details.xp.value}} XP</span> <span>{{data.details.xp.value}} XP</span>
</div> </div>
</div> </aside>
<ul class="summary"> {{!-- Character Summary --}}
<ul class="summary flexrow">
<li> <li>
<input type="text" name="data.details.type" value="{{data.details.type}}" placeholder="{{ localize 'SW5E.Type' }}"/> <span>{{lookup config.actorSizes data.traits.size}}</span>
</li> </li>
<li> <li>
<input type="text" name="data.details.alignment" value="{{data.details.alignment}}" placeholder="{{ localize 'SW5E.Alignment' }}"/> <input type="text" name="data.details.alignment" value="{{data.details.alignment}}" placeholder="{{ localize 'SW5E.Alignment' }}"/>
</li> </li>
<li>
<input type="text" name="data.details.type" value="{{data.details.type}}" placeholder="{{ localize 'SW5E.Type' }}"/>
</li>
<li> <li>
<input type="text" name="data.details.source" value="{{data.details.source}}" placeholder="{{ localize 'SW5E.Source' }}"/> <input type="text" name="data.details.source" value="{{data.details.source}}" placeholder="{{ localize 'SW5E.Source' }}"/>
</li> </li>
</ul> </ul>
</div>
{{!-- Header Attributes --}}
<ul class="attributes flexrow">
<li class="attribute health">
<h4 class="attribute-name box-title rollable">{{ localize "SW5E.Health" }}</h4>
<div class="attribute-value multiple">
<input name="data.attributes.hp.value" type="text" value="{{data.attributes.hp.value}}" placeholder="10" data-dtype="Number"/>
<span class="sep"> / </span>
<input name="data.attributes.hp.max" type="text" value="{{data.attributes.hp.max}}" placeholder="10" data-dtype="Number"/>
</div>
<footer class="attribute-footer">
<input name="data.attributes.hp.formula" class="hpformula" type="text" placeholder="{{ localize 'SW5E.HealthFormula' }}"
value="{{data.attributes.hp.formula}}"/>
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{ localize "SW5E.ArmorClass" }}</h4>
<div class="attribute-value">
<input name="data.attributes.ac.value" type="number" value="{{data.attributes.ac.value}}" placeholder="10"/>
</div>
<footer class="attribute-footer">
<span>{{ localize "SW5E.Proficiency" }}</span>
<span>{{numberFormat data.attributes.prof decimals=0 sign=true}}</span>
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{ localize "SW5E.Speed" }}</h4>
<div class="attribute-value">
<input name="data.attributes.speed.value" type="text"
value="{{data.attributes.speed.value}}" placeholder="0"/>
</div>
<footer class="attribute-footer">
<input type="text" class="speed" name="data.attributes.speed.special"
value="{{data.attributes.speed.special}}" placeholder="{{ localize 'SW5E.SpeedSpecial' }}"/>
</footer>
</li>
</ul>
</section>
</header> </header>
{{!-- NPC Sheet Navigation --}} {{!-- NPC Sheet Navigation --}}
@ -50,11 +93,11 @@
{{#each data.abilities as |ability id|}} {{#each data.abilities as |ability id|}}
<li class="ability {{#if ability.proficient}}proficient{{/if}}" data-ability="{{id}}"> <li class="ability {{#if ability.proficient}}proficient{{/if}}" data-ability="{{id}}">
<h4 class="ability-name box-title rollable">{{ability.label}}</h4> <h4 class="ability-name box-title rollable">{{ability.label}}</h4>
<input class="ability-score" name="data.abilities.{{id}}.value" type="text" value="{{ability.value}}" data-dtype="Number" placeholder="10"/> <input class="ability-score" name="data.abilities.{{id}}.value" type="number" value="{{ability.value}}" placeholder="10"/>
<div class="ability-modifiers flexrow"> <div class="ability-modifiers flexrow">
<span class="ability-mod" title="Modifier">{{numberFormat ability.mod decimals=0 sign=true}}</span> <span class="ability-mod" title="Modifier">{{numberFormat ability.mod decimals=0 sign=true}}</span>
<input type="hidden" name="data.abilities.{{id}}.proficient" value="{{ability.proficient}}" data-dtype="Number"/> <input type="hidden" name="data.abilities.{{id}}.proficient" value="{{ability.proficient}}" data-dtype="Number"/>
<a class="proficiency-toggle ability-proficiency" title="Proficiency">{{{ability.icon}}}</a> <a class="proficiency-toggle ability-proficiency" title="{{ localize 'SW5E.Proficiency' }}">{{{ability.icon}}}</a>
<span class="ability-save" title="Saving Throw">{{numberFormat ability.save decimals=0 sign=true}}</span> <span class="ability-save" title="Saving Throw">{{numberFormat ability.save decimals=0 sign=true}}</span>
</div> </div>
</li> </li>
@ -69,76 +112,30 @@
<a class="proficiency-toggle skill-proficiency" title="{{skill.hover}}">{{{skill.icon}}}</a> <a class="proficiency-toggle skill-proficiency" title="{{skill.hover}}">{{{skill.icon}}}</a>
<h4 class="skill-name rollable">{{skill.label}}</h4> <h4 class="skill-name rollable">{{skill.label}}</h4>
<span class="skill-ability">{{skill.ability}}</span> <span class="skill-ability">{{skill.ability}}</span>
<span class="skill-mod">{{numberFormat skill.mod decimals=0 sign=true}}</span> <span class="skill-mod">{{numberFormat skill.total decimals=0 sign=true}}</span>
<span class="skill-passive">({{skill.passive}})</span> <span class="skill-passive">({{skill.passive}})</span>
</li> </li>
{{/each}} {{/each}}
</ul> </ul>
<section class="center-pane"> <section class="center-pane flexcol">
{{!-- Attributes --}}
<ul class="attributes flexrow">
<li class="attribute health">
<h4 class="attribute-name box-title rollable">{{ localize "SW5E.Health" }}</h4>
<div class="attribute-value multiple">
<input name="data.attributes.hp.value" type="text" value="{{data.attributes.hp.value}}"
data-dtype="Number" placeholder="10"/>
<span class="sep"> / </span>
<input name="data.attributes.hp.max" type="text" value="{{data.attributes.hp.max}}"
data-dtype="Number" placeholder="10"/>
</div>
<footer class="attribute-footer">
<input name="data.attributes.hp.formula" class="hpformula" type="text" placeholder="{{ localize 'SW5E.HealthFormula' }}"
value="{{data.attributes.hp.formula}}"/>
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{ localize "SW5E.ArmorClass" }}</h4>
<div class="attribute-value">
<input name="data.attributes.ac.value" type="text" value="{{data.attributes.ac.value}}"
data-dtype="Number" placeholder="10"/>
</div>
<footer class="attribute-footer">
<span>{{ localize "SW5E.Proficiency" }}</span>
<span>{{numberFormat data.attributes.prof decimals=0 sign=true}}</span>
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{ localize "SW5E.Speed" }}</h4>
<div class="attribute-value">
<input name="data.attributes.speed.value" type="text"
value="{{data.attributes.speed.value}}" placeholder="0"/>
</div>
<footer class="attribute-footer">
<input type="text" class="speed" name="data.attributes.speed.special"
value="{{data.attributes.speed.special}}" placeholder="{{ localize 'SW5E.SpeedSpecial' }}"/>
</footer>
</li>
</ul>
{{!-- Legendary Actions --}} {{!-- Legendary Actions --}}
<div class="counters flexrow"> <div class="counters">
<div class="counter flexrow legendary"> <div class="counter flexrow legendary">
<h4>{{ localize "SW5E.LegAct" }}</h4> <h4>{{ localize "SW5E.LegAct" }}</h4>
<div class="counter-value"> <div class="counter-value">
<input type="text" name="data.resources.legact.value" data-dtype="Number" placeholder="0" <input name="data.resources.legact.value" type="number" value="{{data.resources.legact.value}}" placeholder="0"/>
value="{{data.resources.legact.value}}"/>
<span class="sep">/</span> <span class="sep">/</span>
<input type="text" name="data.resources.legact.max" data-dtype="Number" placeholder="0" <input name="data.resources.legact.max" type="number" value="{{data.resources.legact.max}}" placeholder="0"/>
value="{{data.resources.legact.max}}"/>
</div> </div>
</div> </div>
<div class="counter flexrow legendary"> <div class="counter flexrow legendary">
<h4>{{ localize "SW5E.LegRes" }}</h4> <h4>{{ localize "SW5E.LegRes" }}</h4>
<div class="counter-value"> <div class="counter-value">
<input type="text" name="data.resources.legres.value" data-dtype="Number" placeholder="0" <input name="data.resources.legres.value" type="number" value="{{data.resources.legres.value}}" placeholder="0"/>
value="{{data.resources.legres.value}}"/>
<span class="sep">/</span> <span class="sep">/</span>
<input type="text" name="data.resources.legres.max" data-dtype="Number" placeholder="0" <input name="data.resources.legres.max" type="number" value="{{data.resources.legres.max}}" placeholder="0"/>
value="{{data.resources.legres.max}}"/>
</div> </div>
</div> </div>
<div class="counter flexrow lair"> <div class="counter flexrow lair">
@ -146,9 +143,8 @@
<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="text" value="{{data.resources.lair.initiative}}" <input name="data.resources.lair.initiative" type="number" value="{{data.resources.lair.initiative}}" placeholder="20"/>
data-dtype="Number" placeholder="Init."/> </div>
</div>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
<div class="inventory-filters"> <div class="inventory-filters flexrow">
{{#if isCharacter}} {{#unless isNPC}}
<ol class="currency flexrow"> <ol class="currency flexrow">
<h3> <h3>
{{localize "SW5E.Currency"}} {{localize "SW5E.Currency"}}
@ -11,15 +11,16 @@
<input type="text" name="data.currency.{{k}}" value="{{v}}" data-dtype="Number"/> <input type="text" name="data.currency.{{k}}" value="{{v}}" data-dtype="Number"/>
{{/each}} {{/each}}
</ol> </ol>
{{/if}} {{/unless}}
{{#unless isVehicle}}
<ul class="filter-list flexrow" data-filter="inventory"> <ul class="filter-list flexrow" data-filter="inventory">
<li class="filter-title">{{localize "SW5E.Filter"}}</li>
<li class="filter-item" data-filter="action">{{localize "SW5E.Action"}}</li> <li class="filter-item" data-filter="action">{{localize "SW5E.Action"}}</li>
<li class="filter-item" data-filter="bonus">{{localize "SW5E.BonusAction"}}</li> <li class="filter-item" data-filter="bonus">{{localize "SW5E.BonusAction"}}</li>
<li class="filter-item" data-filter="reaction">{{localize "SW5E.Reaction"}}</li> <li class="filter-item" data-filter="reaction">{{localize "SW5E.Reaction"}}</li>
<li class="filter-item" data-filter="equipped">{{localize "SW5E.Equipped"}}</li> <li class="filter-item" data-filter="equipped">{{localize "SW5E.Equipped"}}</li>
</ul> </ul>
{{/unless}}
</div> </div>
<ol class="inventory-list"> <ol class="inventory-list">
@ -27,16 +28,23 @@
<li class="inventory-header flexrow"> <li class="inventory-header flexrow">
<h3 class="item-name flexrow">{{localize section.label}}</h3> <h3 class="item-name flexrow">{{localize section.label}}</h3>
{{#if section.columns}}
{{#each section.columns}}
<div class="item-detail {{css}}">{{label}}</div>
{{/each}}
{{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 ../owner}} {{#if ../owner}}
<div class="item-controls"> <div class="item-controls">
<a class="item-control item-create" title='{{localize "SW5E.ItemCreate"}}' {{#each section.dataset as |v k|}}data-{{k}}="{{v}}"{{/each}}> <a class="item-control item-create" title='{{localize "SW5E.ItemCreate"}}'
{{#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>
@ -45,16 +53,35 @@
<ol class="item-list"> <ol class="item-list">
{{#each section.items as |item iid|}} {{#each section.items as |item iid|}}
<li class="item flexrow" data-item-id="{{item._id}}"> <li class="item flexrow {{section.css}}"
<div class="item-name flexrow rollable"> data-item-id="{{#if section.editableName}}{{iid}}{{else}}{{item._id}}{{/if}}">
<div class="item-image" style="background-image: url({{item.img}})"></div> <div class="item-name flexrow rollable">
{{#if section.editableName}}
<input type="text" value="{{item.name}}">
{{else}}
<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}}
{{~#if item.data.attuned}} <i class="fas fa-sun attuned" title={{localize "SW5E.Attuned"}}></i>{{/if}} {{~#if item.data.attuned}} <i class="fas fa-sun attuned" title={{localize "SW5E.Attuned"}}></i>{{/if}}
</h4> </h4>
{{/if}}
</div> </div>
{{#if section.columns}}
{{#each section.columns}}
<div class="item-detail {{css}}">
{{#with (getProperty item property)}}
{{#if ../editable}}
<input type="text" value="{{this}}" placeholder="&mdash;"
data-dtype="{{../editable}}" data-property="{{../property}}">
{{else}}
{{this}}
{{/if}}
{{/with}}
</div>
{{/each}}
{{else}}
{{#if ../../isCharacter}} {{#if ../../isCharacter}}
<div class="item-detail item-weight"> <div class="item-detail item-weight">
{{#if item.totalWeight}} {{#if item.totalWeight}}
@ -77,11 +104,16 @@
{{item.labels.activation}} {{item.labels.activation}}
{{/if}} {{/if}}
</div> </div>
{{/if}}
{{#if ../../owner}} {{#if ../../owner}}
<div class="item-controls"> <div class="item-controls">
{{#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 section.editableName}}
<a class="item-control item-edit" title='{{localize "SW5E.ItemEdit"}}'><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title='{{localize "SW5E.ItemEdit"}}'><i class="fas fa-edit"></i></a>
{{/unless}}
<a class="item-control item-delete" title='{{localize "SW5E.ItemDelete"}}'><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title='{{localize "SW5E.ItemDelete"}}'><i class="fas fa-trash"></i></a>
</div> </div>
{{/if}} {{/if}}
@ -92,7 +124,7 @@
</ol> </ol>
{{#if isCharacter }} {{#unless isNPC}}
{{#with data.attributes.encumbrance}} {{#with data.attributes.encumbrance}}
<div class="encumbrance {{#if encumbered}}encumbered{{/if}}"> <div class="encumbrance {{#if encumbered}}encumbered{{/if}}">
<span class="encumbrance-bar" style="width:{{pct}}%"></span> <span class="encumbrance-bar" style="width:{{pct}}%"></span>
@ -103,4 +135,4 @@
<i class="encumbrance-breakpoint encumbrance-66 arrow-down"></i> <i class="encumbrance-breakpoint encumbrance-66 arrow-down"></i>
</div> </div>
{{/with}} {{/with}}
{{/if}} {{/unless}}

View file

@ -1,6 +1,12 @@
<div class="inventory-filters powerbook-filters"> <div class="inventory-filters powerbook-filters flexrow">
<div class="form-group powercasting-ability"> <div class="form-group powercasting-ability">
<h3>{{localize "SW5E.PowerAbility"}}</h3> {{#unless isNPC}}
<label>{{localize "SW5E.PowerAbility"}}</label>
{{else}}
<label>{{localize "SW5E.Level"}}</label>
<input class="powercasting-level" type="text" name="data.details.powerLevel"
value="{{data.details.powerLevel}}" data-dtype="Number" placeholder="0"/>
{{/unless}}
<select name="data.attributes.powercasting" data-type="String"> <select name="data.attributes.powercasting" data-type="String">
{{#select data.attributes.powercasting}} {{#select data.attributes.powercasting}}
<option value="">{{localize "SW5E.None"}}</option> <option value="">{{localize "SW5E.None"}}</option>
@ -9,16 +15,9 @@
{{/each}} {{/each}}
{{/select}} {{/select}}
</select> </select>
{{#if isNPC}}
<h3>{{localize "SW5E.PowercasterLevel"}}</h3>
<input class="powercasting-level" type="text" name="data.details.powerLevel"
value="{{data.details.powerLevel}}" data-dtype="Number" placeholder="0"/>
{{/if}}
<h3 class="power-dc">{{localize "SW5E.PowerDC"}} {{data.attributes.powerdc}}</h3>
</div> </div>
<ul class="filter-list flexrow" data-filter="powerbook"> <ul class="filter-list flexrow" data-filter="powerbook">
<li class="filter-title">{{localize "SW5E.Filter"}}</li>
<li class="filter-item" data-filter="action">{{localize "SW5E.Action"}}</li> <li class="filter-item" data-filter="action">{{localize "SW5E.Action"}}</li>
<li class="filter-item" data-filter="bonus">{{localize "SW5E.BonusAction"}}</li> <li class="filter-item" data-filter="bonus">{{localize "SW5E.BonusAction"}}</li>
<li class="filter-item" data-filter="reaction">{{localize "SW5E.Reaction"}}</li> <li class="filter-item" data-filter="reaction">{{localize "SW5E.Reaction"}}</li>
@ -48,7 +47,7 @@
</a> </a>
{{/if}} {{/if}}
{{ else }} {{ else }}
<span class="power-slots">{{{section.uses}}}</span> <span>{{{section.uses}}}</span>
<span class="sep"> / </span> <span class="sep"> / </span>
<span class="power-max">{{{section.slots}}}</span> <span class="power-max">{{{section.slots}}}</span>
{{/if}} {{/if}}
@ -71,9 +70,9 @@
{{#each section.powers as |item i|}} {{#each section.powers as |item i|}}
<li class="item flexrow" data-item-id="{{item._id}}"> <li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name flexrow rollable"> <div class="item-name flexrow rollable">
<div class="item-image" style="background-image: url({{item.img}})"></div> <div class="item-image" style="background-image: url('{{item.img}}')"></div>
<h4>{{item.name}}</h4> <h4>{{item.name}}</h4>
{{#if item.data.uses.value }} {{#if item.data.uses.per }}
<div class="item-detail power-uses">Uses {{item.data.uses.value}} / {{item.data.uses.max}}</div> <div class="item-detail power-uses">Uses {{item.data.uses.value}} / {{item.data.uses.max}}</div>
{{/if}} {{/if}}
</div> </div>

View file

@ -10,95 +10,115 @@
</select> </select>
</div> </div>
{{#unless isVehicle}}
<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' }}"/>
</div> </div>
<div class="form-group {{data.traits.languages.cssClass}}"> <div class="form-group {{data.traits.languages.cssClass}}">
<label for="data.traits.languages">{{localize "SW5E.Languages"}}</label> <label>{{localize "SW5E.Languages"}}</label>
<a class="trait-selector" data-options="languages" data-target="data.traits.languages">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.languages.selected as |v k|}} {{#each data.traits.languages.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="languages"><i class="fas fa-edit"></i></a>
</div> </div>
{{/unless}}
<div class="form-group {{data.traits.di.cssClass}}"> <div class="form-group {{data.traits.di.cssClass}}">
<label for="data.traits.di">{{localize "SW5E.DamImm"}}</label> <label>{{localize "SW5E.DamImm"}}</label>
<a class="trait-selector" data-options="damageResistanceTypes" data-target="data.traits.di">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.di.selected as |v k|}} {{#each data.traits.di.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="damageTypes"><i class="fas fa-edit"></i></a>
</div> </div>
<div class="form-group {{data.traits.dr.cssClass}}"> <div class="form-group {{data.traits.dr.cssClass}}">
<label for="data.traits.dr">{{localize "SW5E.DamRes"}}</label> <label>{{localize "SW5E.DamRes"}}</label>
<a class="trait-selector" data-options="damageResistanceTypes" data-target="data.traits.dr">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.dr.selected as |v k|}} {{#each data.traits.dr.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="damageTypes"><i class="fas fa-edit"></i></a>
</div> </div>
<div class="form-group {{data.traits.dv.cssClass}}"> <div class="form-group {{data.traits.dv.cssClass}}">
<label for="data.traits.dv">{{localize "SW5E.DamVuln"}}</label> <label>{{localize "SW5E.DamVuln"}}</label>
<a class="trait-selector" data-options="damageResistanceTypes" data-target="data.traits.dv">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.dv.selected as |v k|}} {{#each data.traits.dv.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="damageTypes"><i class="fas fa-edit"></i></a>
</div> </div>
<div class="form-group {{data.traits.ci.cssClass}}"> <div class="form-group {{data.traits.ci.cssClass}}">
<label for="data.traits.ci">{{localize "SW5E.ConImm"}}</label> <label>{{localize "SW5E.ConImm"}}</label>
<a class="trait-selector" data-options="conditionTypes" data-target="data.traits.ci">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.ci.selected as |v k|}} {{#each data.traits.ci.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="conditionTypes"><i class="fas fa-edit"></i></a>
</div> </div>
{{#if isCharacter}} {{#if isCharacter}}
<div class="form-group {{data.traits.weaponProf.cssClass}}"> <div class="form-group {{data.traits.weaponProf.cssClass}}">
<label for="data.traits.weaponProf">{{localize "SW5E.TraitWeaponProf"}}</label> <label>{{localize "SW5E.TraitWeaponProf"}}</label>
<a class="trait-selector" data-options="weaponProficiencies" data-target="data.traits.weaponProf">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.weaponProf.selected as |v k|}} {{#each data.traits.weaponProf.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="weaponProficiencies"><i class="fas fa-edit"></i></a>
</div> </div>
<div class="form-group {{data.traits.armorProf.cssClass}}"> <div class="form-group {{data.traits.armorProf.cssClass}}">
<label for="data.traits.armorProf">{{localize "SW5E.TraitArmorProf"}}</label> <label>{{localize "SW5E.TraitArmorProf"}}</label>
<a class="trait-selector" data-options="armorProficiencies" data-target="data.traits.armorProf">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.armorProf.selected as |v k|}} {{#each data.traits.armorProf.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="armorProficiencies"><i class="fas fa-edit"></i></a>
</div> </div>
<div class="form-group {{data.traits.toolProf.cssClass}}"> <div class="form-group {{data.traits.toolProf.cssClass}}">
<label for="data.traits.toolProf">{{localize "SW5E.TraitToolProf"}}</label> <label>{{localize "SW5E.TraitToolProf"}}</label>
<a class="trait-selector" data-options="toolProficiencies" data-target="data.traits.toolProf">
<i class="fas fa-edit"></i>
</a>
<ul class="traits-list"> <ul class="traits-list">
{{#each data.traits.toolProf.selected as |v k|}} {{#each data.traits.toolProf.selected as |v k|}}
<li class="tag {{k}}">{{v}}</li> <li class="tag {{k}}">{{v}}</li>
{{/each}} {{/each}}
</ul> </ul>
<a class="trait-selector" data-options="toolProficiencies"><i class="fas fa-edit"></i></a>
</div> </div>
{{/if}} {{/if}}
{{#unless isVehicle}}
<div class="form-group "> <div class="form-group ">
<label>{{localize "SW5E.SpecialTraits"}}</label> <label>{{localize "SW5E.SpecialTraits"}}</label>
<a class="configure-flags"><i class="fas fa-cog"></i></a> <a class="configure-flags"><i class="fas fa-cog"></i></a>
</div> </div>
</div> {{/unless}}
</div>

View file

@ -0,0 +1,159 @@
<form class="{{cssClass}} flexcol" autocomplete="off">
<header class="sheet-header flexrow">
<img class="profile" src="{{actor.img}}" title="{{actor.name}}" alt="{{actor.name}}"
data-edit="img">
<section class="header-details flexrow">
<h1 class="charnam">
<input name="name" type="text" value="{{actor.name}}"
placeholder="{{localize 'SW5E.Name'}}">
</h1>
<ul class="summary flexrow">
<li>
<span>{{lookup config.actorSizes data.traits.size}}</span>
</li>
<li>
<span>{{localize 'SW5E.Vehicle'}}</span>
</li>
<li>
<input type="text" name="data.traits.dimensions"
value="{{data.traits.dimensions}}"
placeholder="{{localize 'SW5E.Dimensions'}}">
</li>
<li>
<input type="text" name="data.details.source"
value="{{data.details.source}}"
placeholder="{{localize 'SW5E.Source'}}">
</li>
</ul>
<ul class="attributes flexrow">
<li class="attribute health">
<h4 class="attribute-name box-title">{{localize 'SW5E.Health'}}</h4>
<div class="attribute-value multiple">
<input name="data.attributes.hp.value" type="text" placeholder="&mdash;"
value="{{data.attributes.hp.value}}" data-dtype="Number">
<span class="sep"> &sol; </span>
<input name="data.attributes.hp.max" type="text" placeholder="&mdash;"
value="{{data.attributes.hp.max}}" data-dtype="Number">
</div>
<footer class="attribute-footer">
<input name="data.attributes.hp.dt" type="text" class="temphp"
placeholder="{{localize 'SW5E.Threshold'}}"
value="{{data.attributes.hp.dt}}" data-dtype="Number">
<input name="data.attributes.hp.mt" type="text" class="temphp"
placeholder="{{localize 'SW5E.VehicleMishap'}}"
value="{{data.attributes.hp.mt}}" data-dtype="Number">
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{localize 'SW5E.ArmorClass'}}</h4>
<div class="attribute-value">
<input name="data.attributes.ac.value" type="text" placeholder="&mdash;"
value="{{data.attributes.ac.value}}" data-dtype="Number">
</div>
<footer class="attribute-footer">
<input type="text" name="data.attributes.ac.motionless"
placeholder="&mdash;" value="{{data.attributes.ac.motionless}}">
</footer>
</li>
<li class="attribute">
<h4 class="attribute-name box-title">{{localize 'SW5E.Speed'}}</h4>
<div class="attribute-value">
<input name="data.attributes.speed.value" type="text" placeholder="&mdash;"
value="{{data.attributes.speed.value}}">
</div>
</li>
</ul>
</section>
</header>
<nav class="sheet-navigation tabs" data-group="primary">
<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="cargo">{{localize 'SW5E.VehicleCargoCrew'}}</a>
<a class="item" data-tab="biography">{{localize 'SW5E.Description'}}</a>
</nav>
<section class="sheet-body">
<div class="tab attributes flexrow" data-group="primary" data-tab="attributes">
<ul class="ability-scores flexrow">
{{#each data.abilities as |ability id|}}
<li class="ability" data-ability="{{id}}">
<h4 class="ability-name box-title rollable">{{ability.label}}</h4>
<input class="ability-score" name="data.abilities.{{id}}.value" type="text"
value="{{ability.value}}" data-dtype="Number" placeholder="0">
<div class="ability-modifiers flexrow">
<span class="ability-mod" title="{{localize 'SW5E.Modifier'}}">
{{numberFormat ability.mod decimals=0 sign=true}}
</span>
</div>
</li>
{{/each}}
</ul>
<section class="center-pane flexcol">
<div class="counters">
<div class="counter flexrow creature-cap">
<h4>{{localize 'SW5E.VehicleCreatureCapacity'}}</h4>
<div class="counter-value">
<input type="text" placeholder="&mdash;"
name="data.attributes.capacity.creature"
value="{{data.attributes.capacity.creature}}">
</div>
</div>
<div class="counter flexrow cargo-cap">
<h4>{{localize 'SW5E.VehicleCargoCapacity'}}</h4>
<div class="counter-value">
<input type="text" name="data.attributes.capacity.cargo" placeholder="0"
data-dtype="Number" value="{{data.attributes.capacity.cargo}}">
</div>
</div>
<div class="counter flexrow stations">
<h4>{{localize 'SW5E.VehicleActionStations'}}</h4>
<div class="counter-value">
<input name="data.attributes.actions.stations" type="checkbox"
data-dtype="Boolean" value="{{data.attributes.actions.stations}}"
{{checked data.attributes.actions.stations}}>
</div>
</div>
<div class="counter flexrow actions">
<h4>{{localize 'SW5E.ActionPl'}}</h4>
<div class="counter-value">
<input type="text" name="data.attributes.actions.value" placeholder="0"
data-dtype="Number" value="{{data.attributes.actions.value}}">
</div>
</div>
<div class="counter flexrow action-thresholds">
<h4>{{localize 'SW5E.VehicleActionThresholds'}}</h4>
<div class="counter-value">
<span class="sep">&lt;</span>
<input type="text" placeholder="&mdash;" data-dtype="Number"
value="{{data.attributes.actions.thresholds.[2]}}"
name="data.attributes.actions.thresholds.2">
<span class="sep">&lt;</span>
<input type="text" placeholder="&mdash;" data-dtype="Number"
value="{{data.attributes.actions.thresholds.[1]}}"
name="data.attributes.actions.thresholds.1">
<span class="sep">&lt;</span>
<input type="text" placeholder="&mdash;" data-dtype="Number"
value="{{data.attributes.actions.thresholds.[0]}}"
name="data.attributes.actions.thresholds.0">
</div>
</div>
</div>
{{> 'systems/sw5e/templates/actors/parts/actor-traits.html'}}
</section>
</div>
<div class="tab features flexcol" data-group="primary" data-tab="features">
{{> 'systems/sw5e/templates/actors/parts/actor-features.html' sections=features}}
</div>
<div class="tab cargo flexcol" data-group="primary" data-tab="cargo">
{{> 'systems/sw5e/templates/actors/parts/actor-inventory.html' sections=cargo}}
</div>
<div class="tab biography flexcol" data-group="primary" data-tab="biography">
{{editor content=data.details.biography.value target='data.details.biography.value'
button=true owner=owner editable=editable}}
</div>
</section>
</form>

View file

@ -1,26 +1,41 @@
<form id="ability-use-form"> <form id="ability-use-form">
<p>{{ localize "SW5E.AbilityUseHint" }} <strong>{{item.name}}</strong> {{ localize "SW5E.Ability" }}.</p> <p>{{ title }}</p>
<p class="notes">{{note}}</p>
{{#each errors}}
<p class="notification error">{{localize this}}</p>
{{/each}}
<p type="note"> {{#if canUpcast}}
{{#if recharges}} <div class="form-group">
{{ localize "SW5E.AbilityUseRechargeHint" }} <strong>{{#if isCharged}}{{ localize "SW5E.AbilityUseCharged" }}{{else}}{{ localize "SW5E.AbilityUseDepleted" }}{{/if}}</strong>.</p> <label>{{ localize "SW5E.PowerCastUpcast" }}</label>
{{else}} <div class="form-fields">
{{ localize "SW5E.AbilityUseWarnStart" }} <strong>{{uses.value}} {{ localize "SW5E.of" }} {{uses.max}}</strong> {{ localize "SW5E.AbilityUseWarnEnd" }} {{perLabel}}. <select name="level" {{#unless canUpcast}}disabled{{/unless}}>
{{/if}} {{#select item.data.level}}
{{#unless canUse}} {{#each powerLevels as |l|}}
{{ localize "SW5E.AbilityUseCantUse" }} <option value="{{l.level}}" {{#unless l.canCast}}disabled{{/unless}}>{{l.label}}</option>
{{/unless}} {{/each}}
</p> {{/select}}
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="checkbox">{{ localize "SW5E.AbilityUseConsume" }} <input type="checkbox" name="consume" {{checked consume}}/></label> <label class="checkbox"><input type="checkbox" name="consumeSlot" checked/>{{ localize "SW5E.PowerCastConsume" }}</label>
{{#if hasPlaceableTemplate}}
<div class="form-group">
<label class="checkbox">{{ localize "SW5E.PlaceTemplate" }}
<input type="checkbox" name="placeTemplate" checked/>
</label>
</div>
{{/if}}
</div> </div>
{{/if}}
{{#if hasLimitedUses}}
<div class="form-group">
<label class="checkbox"><input type="checkbox" name="consumeUse" checked/>{{ localize "SW5E.AbilityUseConsume" }}</label>
</div>
{{/if}}
{{#if hasPlaceableTemplate}}
<div class="form-group">
<label class="checkbox">
<input type="checkbox" name="placeTemplate" checked/>
{{ localize "SW5E.PlaceTemplate" }}
</label>
</div>
{{/if}}
</form> </form>

View file

@ -24,7 +24,7 @@
<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">{{flag.hint}}</p> <p class="notes">{{localize flag.hint}}</p>
</div> </div>
{{/each}} {{/each}}
{{/each}} {{/each}}

View file

@ -0,0 +1,20 @@
<form id="long-rest" class="dialog-content" onsubmit="event.preventDefault();">
<p>Take a long rest? On a long rest you will recover hit points, half your maximum hit dice, class resources, limited use item charges, and power points.</p>
{{#if promptNewDay}}
<div class="form-group">
<label>Is New Day?</label>
<input type="checkbox" name="newDay" {{checked newDay}}/>
<p class="hint">Recover limited use abilities which recharge "per day"?</p>
</div>
{{/if}}
<div class="dialog-buttons">
{{#each buttons as |button id|}}
<button class="dialog-button" data-button="{{id}}">
{{{button.icon}}}
{{{button.label}}}
</button>
{{/each}}
</div>
</form>

View file

@ -18,6 +18,15 @@
<p class="notes">{{ localize "SW5E.ShortRestNoHD" }}</p> <p class="notes">{{ localize "SW5E.ShortRestNoHD" }}</p>
{{/unless}} {{/unless}}
</div> </div>
{{#if promptNewDay}}
<div class="form-group">
<label>Is New Day?</label>
<input type="checkbox" name="newDay" {{checked newDay}}/>
<p class="hint">Recover limited use abilities which recharge "per day"?</p>
</div>
{{/if}}
<div class="dialog-buttons"> <div class="dialog-buttons">
{{#each buttons as |button id|}} {{#each buttons as |button id|}}
<button class="dialog-button" data-button="{{id}}"> <button class="dialog-button" data-button="{{id}}">

View file

@ -1,34 +0,0 @@
<form id="spell-config-form">
<p>{{ localize "DND5E.SpellCastHint" }} <strong>{{item.name}}</strong> {{ localize "DND5E.spell" }}.</p>
{{#unless canCast}}
<p class="notification error">{{ localize "DND5E.SpellCastNoSlots" }}</p>
{{/unless}}
<div class="form-group">
<label>{{ localize "DND5E.SpellCastUpcast" }}</label>
<div class="form-fields">
<select name="level">
{{#select item.data.level}}
{{#each spellLevels 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 "DND5E.SpellCastConsume" }} <input type="checkbox" name="consume" {{checked canCast}}/></label>
{{/if}}
{{#if hasPlaceableTemplate}}
<div class="form-group">
<label class="checkbox">{{ localize "DND5E.PlaceTemplate" }}
<input type="checkbox" name="placeTemplate" checked/>
</label>
</div>
{{/if}}
</div>
</form>

View file

@ -9,9 +9,11 @@
</li> </li>
{{/each}} {{/each}}
</ol> </ol>
{{#if allowCustom}}
<div class="form-group stacked"> <div class="form-group stacked">
<label>{{ localize "SW5E.TraitSelectorSpecial" }}</label> <label>{{ localize "SW5E.TraitSelectorSpecial" }}</label>
<input type="text" name="custom" value="{{custom}}" data-dtype="String"/> <input type="text" name="custom" value="{{custom}}" data-dtype="String"/>
</div> </div>
{{/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.Save"}}</button>
</form> </form>

View file

@ -28,7 +28,7 @@
{{#if hasSave}} {{#if hasSave}}
<button data-action="save" data-ability="{{data.save.ability}}" disabled> <button data-action="save" data-ability="{{data.save.ability}}" disabled>
{{ localize "SW5E.Save" }} {{labels.save}} {{ localize "SW5E.SavingThrow" }} {{labels.save}}
</button> </button>
{{/if}} {{/if}}

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li></li> <li></li>
<li> <li>
<input type="text" name="data.rarity" value="{{data.rarity}}" placeholder="{{ localize 'SW5E.Rarity' }}"/> <input type="text" name="data.rarity" value="{{data.rarity}}" placeholder="{{ localize 'SW5E.Rarity' }}"/>

View file

@ -0,0 +1,73 @@
<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.ItemName' }}"/>
</h1>
<div class="item-subtitle">
<h4 class="item-type">{{itemType}}</h4>
<span class="item-status">{{itemStatus}}</span>
</div>
<ul class="summary">
<li>
{{labels.featType}}
</li>
<li>
<input type="text" name="data.requirements" value="{{data.requirements}}" placeholder="{{ localize 'SW5E.Requirements' }}"/>
</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.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>
</form>

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
{{lookup config.equipmentTypes data.armor.type }} {{lookup config.equipmentTypes data.armor.type }}
</li> </li>
@ -57,6 +57,7 @@
</select> </select>
</div> </div>
{{#unless isMountable}}
{{!-- Equipment Status --}} {{!-- Equipment Status --}}
<div class="form-group stacked"> <div class="form-group stacked">
<label>{{ localize "SW5E.ItemEquipmentStatus" }}</label> <label>{{ localize "SW5E.ItemEquipmentStatus" }}</label>
@ -73,33 +74,17 @@
<input type="checkbox" name="data.attuned" {{checked data.attuned}}/> {{ localize "SW5E.Attuned" }} <input type="checkbox" name="data.attuned" {{checked data.attuned}}/> {{ localize "SW5E.Attuned" }}
</label> </label>
</div> </div>
{{/unless}}
{{#unless isWeapon }}
{{!-- ArmorProperties Formula --}} {{!-- Armor Properties --}}
<div class="form-group stacked weapon-properties"> <div class="form-group stacked armor-properties">
<h4 class="armorproperties-header"> <label>{{ localize "SW5E.ArmorProperties" }}</label>
{{#unless isWeapon }}{{ localize "SW5E.ArmorProperties" }}{{ else }}{{ localize "SW5E.ItemWeaponProperties" }}{{/unless}} {{#each config.armorPropertiesTypes as |name prop|}}
<a class="armorproperties-control add-armorproperties"><i class="fas fa-plus"></i></a> <label class="checkbox">
</h4> <input type="checkbox" name="data.properties.{{prop}}" {{checked (lookup ../data.properties prop)}}/> {{ name }}
<ol class="armorproperties-parts form-group"> </label>
{{#each data.armorproperties.parts as |part i| }} {{/each}}
<li class="armorproperties-part flexrow" data-armorproperties-part="{{i}}"> </div>
<select name="data.armorproperties.parts.{{i}}.1">
{{#select (lookup this "1") }}
<option value="">{{ localize "SW5E.None" }}</option>
{{#each ../config.armorpropertiesTypes as |name type|}}
<option value="{{type}}">{{name}}</option>
{{/each}}
{{/select}}
</select>
<input type="text" name="data.armorproperties.parts.{{i}}.0" value="{{lookup this "0"}}"/>
<a class="armorproperties-control delete-armorproperties"><i class="fas fa-minus"></i></a>
</li>
{{/each}}
</ol>
</div>
{{/unless}}
{{!-- Armor Class --}} {{!-- Armor Class --}}
<div class="form-group"> <div class="form-group">
@ -109,6 +94,7 @@
</div> </div>
</div> </div>
{{#unless isMountable}}
{{!-- Dexterity Modifier --}} {{!-- Dexterity Modifier --}}
<div class="form-group"> <div class="form-group">
<label>{{ localize "SW5E.ItemEquipmentDexMod" }}</label> <label>{{ localize "SW5E.ItemEquipmentDexMod" }}</label>
@ -130,6 +116,21 @@
<label>{{ localize "SW5E.ItemEquipmentStealthDisav" }}</label> <label>{{ localize "SW5E.ItemEquipmentStealthDisav" }}</label>
<input type="checkbox" name="data.stealth" value="1" {{checked data.stealth}}/> <input type="checkbox" name="data.stealth" value="1" {{checked data.stealth}}/>
</div> </div>
{{/unless}}
{{#if isMountable}}
{{> 'systems/sw5e/templates/items/parts/item-mountable.html'}}
<div class="form-group">
<label>{{localize 'SW5E.Speed'}}</label>
<div class="form-fields">
<input type="text" name="data.speed.value" value="{{data.speed.value}}"
placeholder="0" data-dtype="Number">
<span class="sep">{{localize 'SW5E.FeetAbbr'}}</span>
<input type="text" name="data.speed.conditions"
value="{{data.speed.conditions}}">
</div>
</div>
{{/if}}
<h3 class="form-header">{{ localize "SW5E.ItemEquipmentUsage" }}</h3> <h3 class="form-header">{{ localize "SW5E.ItemEquipmentUsage" }}</h3>

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
{{labels.featType}} {{labels.featType}}
</li> </li>

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
<input type="text" name="data.rarity" value="{{data.rarity}}" placeholder="{{ localize 'SW5E.Rarity' }}"/> <input type="text" name="data.rarity" value="{{data.rarity}}" placeholder="{{ localize 'SW5E.Rarity' }}"/>
</li> </li>

View file

@ -23,6 +23,21 @@
</div> </div>
</div> </div>
{{#if isCrewed}}
<div class="form-group">
<label>{{localize 'SW5E.Cover'}}</label>
<div class="form-fields">
<select name="data.cover" data-dtype="Number">
{{#select data.cover}}
<option value="">&mdash;</option>
{{#each config.cover as |v k|}}
<option value="{{k}}">{{v}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
{{/if}}
{{!-- Ability Target --}} {{!-- Ability Target --}}
<div class="form-group input-select-select"> <div class="form-group input-select-select">
@ -48,6 +63,16 @@
</div> </div>
</div> </div>
{{!-- Ability Target Width --}}
{{#if isLine}}
<div class="form-group input-select-select">
<label>{{ localize "SW5E.TargetWidth" }}</label>
<div class="form-fields">
<input type="text" name="data.target.width" value="{{data.target.width}}" data-dtype="Number" placeholder="-"/>
</div>
</div>
{{/if}}
{{!-- Ability Range --}} {{!-- Ability Range --}}
<div class="form-group input-select"> <div class="form-group input-select">
<label>{{ localize "SW5E.Range" }}</label> <label>{{ localize "SW5E.Range" }}</label>
@ -99,4 +124,28 @@
</select> </select>
</div> </div>
</div> </div>
{{/if}}
{{!-- Consumption --}}
<div class="form-group uses-per">
<label>{{ localize "SW5E.ConsumeTitle" }}</label>
<div class="form-fields">
<select name="data.consume.type">
{{#select data.consume.type}}
<option value=""></option>
{{#each config.abilityConsumptionTypes as |name key|}}
<option value="{{key}}">{{name}}</option>
{{/each}}
{{/select}}
</select>
<select name="data.consume.target">
{{#select data.consume.target}}
<option value=""></option>
{{#each abilityConsumptionTargets as |name key|}}
<option value="{{key}}">{{name}}</option>
{{/each}}
{{/select}}
</select>
<input type="text" name="data.consume.amount" value="{{data.consume.amount}}" data-dtype="Number"/>
</div>
</div>
{{/if}}

View file

@ -0,0 +1,19 @@
<div class="form-group">
<label>{{localize 'SW5E.Health'}}</label>
<div class="form-fields">
<input type="text" name="data.hp.value" value="{{data.hp.value}}"
placeholder="0" data-dtype="Number">
<span class="sep">&sol;</span>
<input type="text" name="data.hp.max" value="{{data.hp.max}}" placeholder="0"
data-dtype="Number">
<input type="text" name="data.hp.dt" value="{{data.hp.dt}}" data-dtype="Number"
placeholder="{{localize 'SW5E.Threshold'}}">
</div>
</div>
<div class="form-group">
<label>{{localize 'SW5E.HealthConditions'}}</label>
<div class="form-fields">
<input type="text" name="data.hp.conditions" value="{{data.hp.conditions}}">
</div>
</div>

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
{{labels.level}} {{labels.level}}
</li> </li>
@ -68,12 +68,29 @@
</select> </select>
</div> </div>
{{!-- Preparation Mode --}}
<div class="form-group input-select">
<label>{{ localize "SW5E.PowerPreparationMode" }}</label>
<div class="form-fields">
<label class="checkbox prepared">
{{ localize "SW5E.PowerPrepared" }} <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.powerPreparationModes as |name key|}}
<option value="{{key}}">{{name}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
{{!-- Concentration Mode --}} {{!-- Concentration Mode --}}
<div class="form-group input-select"> <div class="form-group input-select">
<label>{{ localize "SW5E.PowerConcentrationMode" }}</label> <label>{{ localize "SW5E.PowerConcentrationMode" }}</label>
<div class="form-fields"> <div class="form-fields">
<label class="checkbox prepared"> <label class="checkbox">
{{ localize "SW5E.Concentrated" }} <input type="checkbox" name="data.preparation.prepared" {{checked data.preparation.prepared}}/> <input type="checkbox" name="data.components.concentration" {{checked data.components.concentration}}/> {{ localize "SW5E.Concentrated" }}
</label> </label>
</div> </div>
</div> </div>

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
<input type="text" name="data.rarity" value="{{data.rarity}}" placeholder="{{ localize 'SW5E.Rarity' }}"/> <input type="text" name="data.rarity" value="{{data.rarity}}" placeholder="{{ localize 'SW5E.Rarity' }}"/>
</li> </li>

View file

@ -14,7 +14,7 @@
<span class="item-status">{{itemStatus}}</span> <span class="item-status">{{itemStatus}}</span>
</div> </div>
<ul class="summary"> <ul class="summary flexrow">
<li> <li>
{{lookup config.weaponTypes data.weaponType }} {{lookup config.weaponTypes data.weaponType }}
</li> </li>
@ -56,24 +56,27 @@
</select> </select>
</div> </div>
{{#unless isMountable}}
{{!-- Weapon Status --}} {{!-- Weapon Status --}}
<div class="form-group stacked"> <div class="form-group stacked">
<label>{{ localize "SW5E.ItemWeaponStatus" }}</label> <label>{{ localize "SW5E.ItemWeaponStatus" }}</label>
<label class="checkbox"> <div class="form-fields">
<input type="checkbox" name="data.proficient" {{checked data.proficient}}/> {{ localize "SW5E.Proficient" }} <label class="checkbox">
</label> <input type="checkbox" name="data.proficient" {{checked data.proficient}}/> {{ localize "SW5E.Proficient" }}
<label class="checkbox"> </label>
<input type="checkbox" name="data.equipped" {{checked data.equipped}}/> {{ localize "SW5E.Equipped" }} <label class="checkbox">
</label> <input type="checkbox" name="data.equipped" {{checked data.equipped}}/> {{ localize "SW5E.Equipped" }}
<label class="checkbox"> </label>
<input type="checkbox" name="data.identified" {{checked data.identified}}/> {{ localize "SW5E.Identified" }} <label class="checkbox">
</label> <input type="checkbox" name="data.identified" {{checked data.identified}}/> {{ localize "SW5E.Identified" }}
<label class="checkbox"> </label>
<input type="checkbox" name="data.attuned" {{checked data.attuned}}/> {{ localize "SW5E.Attuned" }} <label class="checkbox">
</label> <input type="checkbox" name="data.attuned" {{checked data.attuned}}/> {{ localize "SW5E.Attuned" }}
</label>
</div>
</div> </div>
{{/unless}}
{{#if sss}}
{{!-- Weapon Properties --}} {{!-- Weapon Properties --}}
<div class="form-group stacked weapon-properties"> <div class="form-group stacked weapon-properties">
<label>{{ localize "SW5E.ItemWeaponProperties" }}</label> <label>{{ localize "SW5E.ItemWeaponProperties" }}</label>
@ -81,37 +84,21 @@
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" name="data.properties.{{prop}}" {{checked (lookup ../data.properties prop)}}/> {{ name }} <input type="checkbox" name="data.properties.{{prop}}" {{checked (lookup ../data.properties prop)}}/> {{ name }}
</label> </label>
<label class="text"> <input type="text" maxlength="2" name="wpNum"/></label>
{{/each}} {{/each}}
</div> </div>
{{/if}}
{{#if isWeapon }} {{#if isMountable}}
<div class="form-group stacked weapon-properties"> <div class="form-group">
{{!-- weaponproperties Formula --}} <label>{{localize 'SW5E.ArmorClass'}}</label>
<h4 class="weaponproperties-header"> <div class="form-fields">
{{#unless isWeapon }}{{ localize "SW5E.ArmorProperties" }}{{ else }}{{ localize "SW5E.ItemWeaponProperties" }}{{/unless}} <input type="text" name="data.armor.value" value="{{data.armor.value}}"
<a class="weaponproperties-control add-weaponproperties"><i class="fas fa-plus"></i></a> data-dtype="Number">
</h4> </div>
<ol class="weaponproperties-parts form-group"> </div>
{{#each data.weaponproperties.parts as |part i| }}
<li class="weaponproperties-part flexrow" data-weaponproperties-part="{{i}}">
<select name="data.weaponproperties.parts.{{i}}.1">
{{#select (lookup this "1") }}
<option value="">{{ localize "SW5E.None" }}</option>
{{#each ../config.weaponProperties as |name type|}}
<option value="{{type}}">{{name}}</option>
{{/each}}
{{/select}}
</select>
<input type="text" name="data.weaponproperties.parts.{{i}}.0" value="{{lookup this "0"}}"/>
<a class="weaponproperties-control delete-weaponproperties"><i class="fas fa-minus"></i></a>
</li>
{{/each}}
</ol>
{{/if}}
</div> {{> 'systems/sw5e/templates/items/parts/item-mountable.html'}}
{{/if}}
<h3 class="form-header">{{ localize "SW5E.ItemWeaponUsage" }}</h3> <h3 class="form-header">{{ localize "SW5E.ItemWeaponUsage" }}</h3>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB