diff --git a/lang/en-EN.json b/lang/en-EN.json index 333888d..1fff4bf 100644 --- a/lang/en-EN.json +++ b/lang/en-EN.json @@ -45,17 +45,14 @@ "ACTIONSELECTOR.SelectedAction": "Selected Action:", "ACTIONSELECTOR.Title": "Action Selector", - "APPLICATION.BUTTON.BasicSkillsAdding": "Add Basic Skills", "APPLICATION.BUTTON.DeleteItem": "Delete Item", "APPLICATION.BUTTON.EditItem": "Edit Item", "APPLICATION.BUTTON.Expand": "More", "APPLICATION.BUTTON.RollItem": "Roll Item", "APPLICATION.TITLE.ActionUsage": "Action Usage Confirmation", - "APPLICATION.TITLE.BasicSkillsAdding": "Basic Skills Adding", "APPLICATION.TITLE.DeleteItem": "Delete Item Confirmation", "APPLICATION.TITLE.MemberRemoval": "Member Removal Confirmation", "APPLICATION.DESCRIPTION.ActionUsage": "Do you really want to use {action}?", - "APPLICATION.DESCRIPTION.BasicSkillsAdding": "{actor} has no skill. Do you wish to give {actor} all the basic skills?", "APPLICATION.DESCRIPTION.DeleteItem": "Do you really want to delete {item}?", "APPLICATION.DESCRIPTION.MemberRemoval": "Do you really wish to remove {actor} from the party?", @@ -158,10 +155,12 @@ "CHARACTER.IMPAIRMENT.Stress": "Stress", "CHARACTER.IMPAIRMENT.FatigueTokens": "Fatigue Tokens", "CHARACTER.IMPAIRMENT.StressTokens": "Stress Tokens", + "CHARACTER.SHEET.AddBasicSkills": "Add Basic Skills", "CHARACTER.SHEET.AddRemoveConservativeSegment": "Add/Remove Conservative Segment", "CHARACTER.SHEET.AddRemoveRecklessSegment": "Add/Remove Reckless Segment", "CHARACTER.SHEET.MinimumSegmentWarning": "You cannot remove any more segment.", "CHARACTER.SHEET.NoExperienceLeft": "You have no Experience left.", + "CHARACTER.SHEET.NoSkill": "{actor} has no skill. Do you wish to give {actor} all the basic skills?", "CHARACTERGENERATOR.Actions": "Action Cards", "CHARACTERGENERATOR.Acquired": "Acquired", @@ -245,9 +244,11 @@ "CREATURE.DamageRating": "Damage Rating", "CREATURE.DefenceValue": "Defence Value", "CREATURE.Details": "Details", + "CREATURE.Nemesis": "Nemesis", "CREATURE.SoakValue": "Soak Value", "CREATURE.Stance": "Stance", "CREATURE.ThreatRating": "Threat Rating", + "CREATURE.Trappings": "Trappings", "CREATURE.WoundsThreshold": "Wounds Threshold", "CREATURE.WoundsValue": "Wounds Value", "CREATURE.ABBREVIATION.DamageRating": "DR", @@ -564,9 +565,12 @@ "WEAPON.CriticalRating": "Critical Rating", "WEAPON.DamageRating": "Damage Rating", "WEAPON.Group": "Group", + "WEAPON.Improvised": "Improvised", + "WEAPON.ImprovisedWeapon": "Improvised Weapon", "WEAPON.Qualities": "Qualities", "WEAPON.Range": "Range", "WEAPON.Rating": "Rating", + "WEAPON.Unarmed": "Unarmed", "WEAPON.ABBREVIATION.CriticalRating": "CR", "WEAPON.ABBREVIATION.DamageRating": "DR", "WEAPON.GROUP.Blackpowder": "Blackpowder", diff --git a/lang/fr-FR.json b/lang/fr-FR.json index f033878..095df94 100644 --- a/lang/fr-FR.json +++ b/lang/fr-FR.json @@ -42,22 +42,19 @@ "ACTIONSELECTOR.ChooseANewAction": "Choisissez une nouvelle action", "ACTIONSELECTOR.NoActionSelected": "Aucune", "ACTIONSELECTOR.NoActionSelectedWarning": "Vous devez sélectionner une carte d'action.", - "ACTIONSELECTOR.SelectedAction": "Action sélectionnée :", + "ACTIONSELECTOR.SelectedAction": "Action sélectionnée :", "ACTIONSELECTOR.Title": "Sélecteur d'action", - "APPLICATION.BUTTON.BasicSkillsAdding": "Add Basic Skills", - "APPLICATION.BUTTON.DeleteItem": "Delete Item", - "APPLICATION.BUTTON.EditItem": "Edit Item", - "APPLICATION.BUTTON.Expand": "More", - "APPLICATION.BUTTON.RollItem": "Roll Item", - "APPLICATION.TITLE.ActionUsage": "Action Usage Confirmation", - "APPLICATION.TITLE.BasicSkillsAdding": "Basic Skills Adding", - "APPLICATION.TITLE.DeleteItem": "Delete Item Confirmation", - "APPLICATION.TITLE.MemberRemoval": "Member Removal Confirmation", - "APPLICATION.DESCRIPTION.ActionUsage": "Do you really want to use {action}?", - "APPLICATION.DESCRIPTION.BasicSkillsAdding": "{actor} has no skill. Do you wish to give {actor} all the basic skills?", - "APPLICATION.DESCRIPTION.DeleteItem": "Do you really want to delete {item}?", - "APPLICATION.DESCRIPTION.MemberRemoval": "Do you really wish to remove {actor} from the party?", + "APPLICATION.BUTTON.DeleteItem": "Supprimer l'objet", + "APPLICATION.BUTTON.EditItem": "Modifier l'objet", + "APPLICATION.BUTTON.Expand": "Plus", + "APPLICATION.BUTTON.RollItem": "Faire un test", + "APPLICATION.TITLE.ActionUsage": "Confirmation de l'utilisation de l'action", + "APPLICATION.TITLE.DeleteItem": "Confirmation de la suppression de l'objet", + "APPLICATION.TITLE.MemberRemoval": "Confirmation du retrait du membre", + "APPLICATION.DESCRIPTION.ActionUsage": "Souhaitez-vous vraiment utiliser {action} ?", + "APPLICATION.DESCRIPTION.DeleteItem": "Souhaitez-vous vraiment supprimer {item} ?", + "APPLICATION.DESCRIPTION.MemberRemoval": "Souhaitez-vous vraiment retirer {actor} du groupe ?", "ARMOUR.Defence": "Défense", "ARMOUR.Soak": "Encaissement", @@ -120,7 +117,7 @@ "CAREERSELECTOR.NotEnoughExperiencePoint": "Vous n'avez pas assez d'expérience pour entamer cette carrière.", "CAREERSELECTOR.NoCareerSelected": "Aucune", "CAREERSELECTOR.NoCareerSelectedWarning": "Vous devez sélectionner une fiche de carrière.", - "CAREERSELECTOR.SelectedCareer": "Carrière sélectionnée :", + "CAREERSELECTOR.SelectedCareer": "Carrière sélectionnée :", "CAREERSELECTOR.Title": "Selecteur de carrière", "CHARACTER.Abilities": "Aptitudes", @@ -158,10 +155,12 @@ "CHARACTER.IMPAIRMENT.Stress": "Stress", "CHARACTER.IMPAIRMENT.FatigueTokens": "Jetons de Fatigue", "CHARACTER.IMPAIRMENT.StressTokens": "Jetons de Stress", + "CHARACTER.SHEET.AddBasicSkills": "Ajouter les compétences de base", "CHARACTER.SHEET.AddRemoveConservativeSegment": "Ajouter/retirer un segment de prudence", "CHARACTER.SHEET.AddRemoveRecklessSegment": "Ajouter/retirer un segment de témérité", "CHARACTER.SHEET.MinimumSegmentWarning": "Vous ne pouvez pas retirer davantage de segments.", "CHARACTER.SHEET.NoExperienceLeft": "Vous n'avez pas d'expérience à dépenser.", + "CHARACTER.SHEET.NoSkill": "{actor} ne possède aucune compétence. Souhaitez-vous donner les compétences de base à {actor} ?", "CHARACTERGENERATOR.Actions": "Cartes d'action", "CHARACTERGENERATOR.Acquired": "Acquis", @@ -177,23 +176,23 @@ "CHARACTERGENERATOR.TrainingLevel": "Niveau de formation", "CHARACTERGENERATOR.Title": "Générateur de personnage", "CHARACTERGENERATOR.Wealth": "Richesse", - "CHARACTERGENERATOR.CorruptionThreshold": "Plafond de Corruption : ", - "CHARACTERGENERATOR.WoundThreshold": "Plafond de Blessures : ", + "CHARACTERGENERATOR.CorruptionThreshold": "Plafond de Corruption : ", + "CHARACTERGENERATOR.WoundThreshold": "Plafond de Blessures : ", "CHARACTERGENERATOR.PlusToughnessRating": "{value} + Toughness rating", - "CHARACTERGENERATOR.CurrentlySelectedCareer": "Carrière sélectionnée : ", - "CHARACTERGENERATOR.CurrentlySelectedOrigin": "Origine sélectionnée : ", + "CHARACTERGENERATOR.CurrentlySelectedCareer": "Carrière sélectionnée : ", + "CHARACTERGENERATOR.CurrentlySelectedOrigin": "Origine sélectionnée : ", "CHARACTERGENERATOR.RemainingActions": "Actions restantes: ", - "CHARACTERGENERATOR.RemainingCreationPoints": "Points de création restants : ", - "CHARACTERGENERATOR.RemainingSkillTrainings": "Formation de compétences restantes : ", - "CHARACTERGENERATOR.RemainingSpecialisations": "Spécialisations restantes : ", - "CHARACTERGENERATOR.RemainingTalents": "Talents restants : ", - "CHARACTERGENERATOR.RemainingFaithTalents": "Talents de Foi restants : ", - "CHARACTERGENERATOR.RemainingFocusTalents": "Talents d'Affinité restants : ", - "CHARACTERGENERATOR.RemainingOrderTalents": "Talents d'Ordre restants : ", + "CHARACTERGENERATOR.RemainingCreationPoints": "Points de création restants : ", + "CHARACTERGENERATOR.RemainingSkillTrainings": "Formation de compétences restantes : ", + "CHARACTERGENERATOR.RemainingSpecialisations": "Spécialisations restantes : ", + "CHARACTERGENERATOR.RemainingTalents": "Talents restants : ", + "CHARACTERGENERATOR.RemainingFaithTalents": "Talents de Foi restants : ", + "CHARACTERGENERATOR.RemainingFocusTalents": "Talents d'Affinité restants : ", + "CHARACTERGENERATOR.RemainingOrderTalents": "Talents d'Ordre restants : ", "CHARACTERGENERATOR.RemainingInsanityTalents": "Folies restantes: ", "CHARACTERGENERATOR.STEP.ActionsSelection": "Choisissez vos cartes d'action", "CHARACTERGENERATOR.STEP.CareerSelection": "Choisissez votre carrière", - "CHARACTERGENERATOR.STEP.Confirm": "Votre personnage vous convient-il ?", + "CHARACTERGENERATOR.STEP.Confirm": "Votre personnage vous convient-il ?", "CHARACTERGENERATOR.STEP.CreationPointsInvestment": "Distribuez vos points de création", "CHARACTERGENERATOR.STEP.OriginSelection": "Choisissez votre origine", "CHARACTERGENERATOR.STEP.SkillTraining": "Entraînez vos compétences", @@ -230,7 +229,7 @@ "CHARACTERISTICUPGRADER.IncreaseFortune": "Dé de Fortune +1", "CHARACTERISTICUPGRADER.IncreaseRating": "Valeur +1", "CHARACTERISTICUPGRADER.NoUpgradeSelected": "Aucune augmentation sélectionnée", - "CHARACTERISTICUPGRADER.SelectedUpgrade": "Augmentation sélectionnée : ", + "CHARACTERISTICUPGRADER.SelectedUpgrade": "Augmentation sélectionnée : ", "CHARACTERISTICUPGRADER.Title": "Améliorateur de caractéristique", "CHARACTERISTICUPGRADER.UpgradeACharacteristic": "Améliorer une caractéristique", @@ -245,9 +244,11 @@ "CREATURE.DamageRating": "Niveaux de Dégâts", "CREATURE.DefenceValue": "Valeur de Défense", "CREATURE.Details": "Détails", + "CREATURE.Nemesis": "Nemesis", "CREATURE.SoakValue": "Valeur d'Encaissement", "CREATURE.Stance": "Attitude", "CREATURE.ThreatRating": "Niveau de Menace", + "CREATURE.Trappings": "Dotations", "CREATURE.WoundsThreshold": "Plafond de Blessure", "CREATURE.WoundsValue": "Points de Blessures", "CREATURE.ABBREVIATION.DamageRating": "ND", @@ -326,10 +327,10 @@ "ORIGIN.Ulthuan": "Haut Elfe d'Ulthuan", "ORIGIN.Reiklander": "Reiklander", "ORIGIN.AthelLoren": "Elfe Sylvain d'Athel Loren", - "ORIGIN.INTRODUCTION.KarakAzgaraz": "Les nains de Karak Azgaraz bénéficient des aptitudes raciales suivantes, reflétant leur témérité et leurs fières traditions :", - "ORIGIN.INTRODUCTION.Ulthuan": "Les personnages hauts elfes bénéficient des aptitudes raciales suivantes, qui représentent leur éducation ainsi que leur riche histoire :", - "ORIGIN.INTRODUCTION.Reiklander": "Les personnages du Reikland disposent des aptitudes raciales suivantes, reflétant leur éducation et leur caractère :", - "ORIGIN.INTRODUCTION.AthelLoren": "Les personnages elfes sylvains bénéficient des aptitudes raciales suivantes, reflétant leur lien avec la nature et les traditions qui régissent leur culture :", + "ORIGIN.INTRODUCTION.KarakAzgaraz": "Les nains de Karak Azgaraz bénéficient des aptitudes raciales suivantes, reflétant leur témérité et leurs fières traditions :", + "ORIGIN.INTRODUCTION.Ulthuan": "Les personnages hauts elfes bénéficient des aptitudes raciales suivantes, qui représentent leur éducation ainsi que leur riche histoire :", + "ORIGIN.INTRODUCTION.Reiklander": "Les personnages du Reikland disposent des aptitudes raciales suivantes, reflétant leur éducation et leur caractère :", + "ORIGIN.INTRODUCTION.AthelLoren": "Les personnages elfes sylvains bénéficient des aptitudes raciales suivantes, reflétant leur lien avec la nature et les traditions qui régissent leur culture  :", "PARTY.FortunePool": "Réserve de Fortune", "PARTY.FortuneToken": "Jeton de Fortune", @@ -412,7 +413,7 @@ "ROLL.DICEPOOLBUILDER.Options": "Options", "ROLL.DICEPOOLBUILDER.RollCheck": "Lancer le test", "ROLL.DICEPOOLBUILDER.Specialisations": "Spécialisations", - "ROLL.DICEPOOLBUILDER.Skill": "Skill", + "ROLL.DICEPOOLBUILDER.Skill": "Compétence", "ROLL.DICEPOOLBUILDER.StartingResults": "Pictogrammes de départ", "ROLL.DICEPOOLBUILDER.Weapon": "Arme", "ROLL.DIE.ChallengeDice": "dés de défi", @@ -490,7 +491,7 @@ "SKILL.AdvancedSkill": "Compétence Avancée", "SKILL.Characteristic": "Caractéristique", "SKILL.Name": "Nom", - "SKILL.SpecialisationList": "Spécialisations : {specialisations}", + "SKILL.SpecialisationList": "Spécialisations : {specialisations}", "SKILL.Specialisations": "Spécialisations", "SKILL.TrainingLevel": "Formation", "SKILL.ABBREVIATION.Characteristic": "Car.", @@ -511,7 +512,7 @@ "TALENTSELECTOR.ChooseANewTalent": "Choisissez un nouveau talent", "TALENTSELECTOR.NoTalentSelected": "Aucun", "TALENTSELECTOR.NoTalentSelectedWarning": "Vous devez sélectionner une carte de talent.", - "TALENTSELECTOR.SelectedTalent": "Talent sélectionné :", + "TALENTSELECTOR.SelectedTalent": "Talent sélectionné :", "TALENTSELECTOR.Title": "Sélecteur de talent", "TRAININGSELECTOR.Acquired": "Acquis", @@ -521,7 +522,7 @@ "TRAININGSELECTOR.NewSpecialisation": "Spécialisation {specialisation}", "TRAININGSELECTOR.NoTrainingSelected": "Aucune", "TRAININGSELECTOR.NoTrainingSelectedWarning": "Vous devez sélectionner une formation.", - "TRAININGSELECTOR.SelectedTraining": "Formation sélectionnée :", + "TRAININGSELECTOR.SelectedTraining": "Formation sélectionnée :", "TRAININGSELECTOR.Specialisations": "Spécialisations", "TRAININGSELECTOR.Title": "Sélecteur de formation", "TRAININGSELECTOR.TrainingLevel": "Niveau de formation", @@ -564,9 +565,12 @@ "WEAPON.CriticalRating": "Niveau Critique", "WEAPON.DamageRating": "Niveau de Dégâts", "WEAPON.Group": "Groupe", + "WEAPON.Improvised": "Improvised", + "WEAPON.ImprovisedWeapon": "Arme improvisée", "WEAPON.Qualities": "Attributs", "WEAPON.Range": "Portée", "WEAPON.Rating": "Niveau", + "WEAPON.Unarmed": "Mains nues", "WEAPON.ABBREVIATION.CriticalRating": "NC", "WEAPON.ABBREVIATION.DamageRating": "ND", "WEAPON.GROUP.Blackpowder": "Poudre Noire", diff --git a/modules/CheckHelper.js b/modules/CheckHelper.js index b87b287..aed43a0 100644 --- a/modules/CheckHelper.js +++ b/modules/CheckHelper.js @@ -405,8 +405,7 @@ export default class CheckHelper if(match) { const characteristicName = checkData.action.system.type === "ranged" ? "agility" : "strength"; outcome.targetDamages = actor.system.characteristics[characteristicName].rating + - (checkData.weapon?.system.damageRating ?? 0) + - (actor.system.damageRating ?? 0) + + (checkData.weapon ? checkData.weapon.system.damageRating : actor.system.damageRating ?? 0) + parseInt(match[1]); } @@ -422,17 +421,14 @@ export default class CheckHelper match = effectDescription.match(new RegExp(game.i18n.localize("ROLL.REGEX.ForMinusAmountDamage"), "u")); if(match) { const characteristicName = checkData.action.system.type === "ranged" ? "agility" : "strength"; - console. outcome.targetDamages = actor.system.characteristics[characteristicName].rating + - (checkData.weapon?.system.damageRating ?? 0) + - (actor.system.damageRating ?? 0) + + (checkData.weapon ? checkData.weapon.system.damageRating : actor.system.damageRating ?? 0) + parseInt(match[1]); } match = effectDescription.match(new RegExp(game.i18n.localize("ROLL.REGEX.ForNormalDamage"), "u")); if(match) { const characteristicName = checkData.action.system.type === "ranged" ? "agility" : "strength"; - console.log(actor.system.characteristics[characteristicName].rating, checkData.weapon?.system.damageRating, actor.system.damageRating) outcome.targetDamages = actor.system.characteristics[characteristicName].rating + (checkData.weapon?.system.damageRating ?? 0) + (actor.system.damageRating ?? 0); @@ -505,9 +501,7 @@ export default class CheckHelper if(targetActor) { // If the attack inflicts damages, reduce them by Toughness and Soak values. if(outcome.targetDamages > 0) { - outcome.targetDamages -= targetActor.system.characteristics.toughness.rating + - (targetActor.system.totalSoak ?? 0) + - (targetActor.system.soakValue ?? 0); + outcome.targetDamages -= targetActor.system.characteristics.toughness.rating + targetActor.system.totalSoak; // If the attack still inflicts more damages than the target's wound threshold, the target suffers from a critical wound // (in addition to those coming from effects). @@ -537,11 +531,23 @@ export default class CheckHelper } } - if(outcome.targetFatigue > 0 || outcome.targetFatigue < 0) - targetUpdates.system.impairments = {fatigue: targetActor.system.impairments.fatigue + outcome.targetFatigue}; + if(outcome.targetFatigue > 0 || outcome.targetFatigue < 0) { + if(targetActor.type === "creature" && !targetActor.system.nemesis) + targetUpdates.system.impairments = {fatigue: targetActor.system.impairments.fatigue + outcome.targetFatigue}; + else if(targetActor.system.wounds.value) + targetUpdates.system.wounds.value -= outcome.targetFatigue; + else + targetUpdates.system.wounds = {value: targetActor.system.wounds.value - outcome.targetFatigue}; + } - if(outcome.targetStress > 0 || outcome.targetStress < 0) - targetUpdates.system.impairments = {stress: targetActor.system.impairments.stress + outcome.targetStress}; + if(outcome.targetStress > 0 || outcome.targetStress < 0) { + if(targetActor.type === "creature" && !targetActor.system.nemesis) + targetUpdates.system.impairments = {stress: targetActor.system.impairments.stress + outcome.targetStress}; + else if(targetActor.system.wounds.value) + targetUpdates.system.wounds.value -= outcome.targetStress; + else + targetUpdates.system.wounds = {value: targetActor.system.wounds.value - outcome.targetStress}; + } targetActor.update(targetUpdates); } diff --git a/modules/applications/CharacterGenerator.js b/modules/applications/CharacterGenerator.js index 069ec96..ed203df 100644 --- a/modules/applications/CharacterGenerator.js +++ b/modules/applications/CharacterGenerator.js @@ -301,7 +301,7 @@ export default class CharacterGenerator extends FormApplication do { await startingCareerRollTable.draw({displayChat: false}).then(async tableResult => { - if(tableResult.results[0].type === 2 && !drawnCareers.has(tableResult.results[0].documentId)) + if(tableResult.results[0].type === "pack" && !drawnCareers.has(tableResult.results[0].documentId)) drawnCareers.set( tableResult.results[0].documentId, await game.packs.get("wfrp3e.items").getDocument(tableResult.results[0].documentId) diff --git a/modules/applications/DicePoolBuilder.js b/modules/applications/DicePoolBuilder.js index 8630349..ac6ba61 100644 --- a/modules/applications/DicePoolBuilder.js +++ b/modules/applications/DicePoolBuilder.js @@ -113,16 +113,26 @@ export default class DicePoolBuilder extends FormApplication data.action = action; if(["melee", "ranged"].includes(action.system.type)) { - data.availableWeapons = action.actor.itemTypes.weapon.filter(weapon => { - return Object.entries(CONFIG.WFRP3e.weapon.groups).reduce((array, weaponGroup) => { - if(weaponGroup[1].type === action.system.type) - array.push(weaponGroup[0]); - return array; - }, []).includes(weapon.system.group); - }); - - data.weapon = checkData.weapon ?? Object.values(data.availableWeapons)[0]; - checkData.weapon = Object.values(data.availableWeapons)[0]; + data.availableWeapons = [ + ...action.actor.itemTypes.weapon.filter(weapon => { + return Object.entries(CONFIG.WFRP3e.weapon.groups).reduce((array, weaponGroup) => { + if(weaponGroup[1].type === action.system.type) + array.push(weaponGroup[0]); + return array; + }, []).includes(weapon.system.group); + }) + ]; + + if(action.system.type === "melee") + data.availableWeapons.push( + CONFIG.WFRP3e.weapon.commonWeapons.improvisedWeapon, + CONFIG.WFRP3e.weapon.commonWeapons.unarmed + ); + else + data.availableWeapons.push(CONFIG.WFRP3e.weapon.commonWeapons.improvised); + + data.weapon = checkData.weapon ?? data.availableWeapons[0]; + checkData.weapon = data.availableWeapons[0]; } } } @@ -536,11 +546,24 @@ export default class DicePoolBuilder extends FormApplication { event.preventDefault(); - this.object.checkData.weapon = this.actor.itemTypes.weapon(weapon => weapon._id === event.currentTarget.value); + switch(event.currentTarget.value) { + case "unarmed": + this.object.checkData.weapon = CONFIG.WFRP3e.weapon.commonWeapons.unarmed; + break; + case "improvised": + this.object.checkData.weapon = CONFIG.WFRP3e.weapon.commonWeapons.improvised; + break; + case "improvisedWeapon": + this.object.checkData.weapon = CONFIG.WFRP3e.weapon.commonWeapons.improvisedWeapon; + break; + default: + this.object.checkData.weapon = this.actor.itemTypes.weapon.find(weapon => weapon.id === event.currentTarget.value); + break; + } } /** - * Performs follow-up operations after left-clicks on a extend button. + * Performs follow-up operations after left-clicks on an extend button. * @param {MouseEvent} event * @private */ diff --git a/modules/applications/actors/WFRP3eActorSheet.js b/modules/applications/actors/WFRP3eActorSheet.js new file mode 100644 index 0000000..29c7447 --- /dev/null +++ b/modules/applications/actors/WFRP3eActorSheet.js @@ -0,0 +1,372 @@ +/** @inheritDoc */ +export default class WFRP3eActorSheet extends ActorSheet +{ + /** @inheritDoc */ + static get defaultOptions() + { + return { + ...super.defaultOptions, + dragDrop: [{dragSelector: ".item", dropSelector: null}] + }; + } + + /** @inheritdoc */ + get template() + { + return `systems/wfrp3e/templates/applications/actors/${this.actor.type.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)}-sheet.hbs`; + } + + /** @inheritdoc */ + getData() + { + const data = { + ...super.getData(), + actionTypes: CONFIG.WFRP3e.actionTypes, + conditionDurations: CONFIG.WFRP3e.conditionDurations, + characteristics: CONFIG.WFRP3e.characteristics, + diseaseSymptoms: CONFIG.WFRP3e.disease.symptoms, + origins: Object.values(CONFIG.WFRP3e.availableRaces).reduce((origins, race) => { + Object.entries(race.origins).forEach(origin => origins[origin[0]] = origin[1]); + return origins; + }, {}), + stances: CONFIG.WFRP3e.stances, + symbols: CONFIG.WFRP3e.symbols, + talentTypes: CONFIG.WFRP3e.talentTypes, + weaponGroups: CONFIG.WFRP3e.weapon.groups, + weaponQualities: CONFIG.WFRP3e.weapon.qualities, + weaponRanges: CONFIG.WFRP3e.weapon.ranges + }; + data.items = this._buildItemLists(data.items); + data.hasAbility = data.items.abilities.length > 0 + || data.items.conditions.length > 0 + || data.items.criticalWounds.length > 0 + || data.items.diseases.length > 0 + || data.items.insanities.length > 0 + || data.items.miscasts.length > 0 + || data.items.mutations.length > 0; + data.hasTrapping = (data.items.armours.length > 0 || data.items.trappings.length > 0 || data.items.weapons.length > 0); + + return data; + } + + /** + * Returns items sorted by type. + * @param {Array} items The items owned by the Actor. + * @returns {Object} The sorted items owned by the Actor. + * @private + */ + _buildItemLists(items) + { + const basicTrait = game.i18n.localize("ACTION.TRAITS.Basic"); + const sortedItems = items.sort((a, b) => a.name.localeCompare(b.name)); + const actions = sortedItems.filter(item => item.type === "action").sort((a, b) => { + if(a.system.conservative.traits.includes(basicTrait) && !b.system.conservative.traits.includes(basicTrait)) + return -1; + else if(!a.system.conservative.traits.includes(basicTrait) && b.system.conservative.traits.includes(basicTrait)) + return 1 + else + return 0; + }); + const talents = sortedItems.filter(item => item.type === "talent"); + + return { + abilities: sortedItems.filter(item => item.type === "ability"), + actions: Object.keys(CONFIG.WFRP3e.actionTypes).reduce((sortedActions, actionType) => { + sortedActions[actionType] = actions.filter(action => action.system.type === actionType); + return sortedActions; + }, {}), + armours: sortedItems.filter(item => item.type === "armour"), + careers: sortedItems.filter(item => item.type === "career"), + conditions: sortedItems.filter(item => item.type === "condition"), + criticalWounds: sortedItems.filter(item => item.type === "criticalWound"), + diseases: sortedItems.filter(item => item.type === "disease"), + insanities: sortedItems.filter(item => item.type === "insanity"), + miscasts: sortedItems.filter(item => item.type === "miscast"), + money: sortedItems.filter(item => item.type === "money"), + mutations: sortedItems.filter(item => item.type === "mutation"), + skills: sortedItems.filter(item => item.type === "skill"), + talents: Object.keys(CONFIG.WFRP3e.talentTypes).reduce((sortedTalents, talentType) => { + sortedTalents[talentType] = talents.filter(talent => talent.system.type === talentType); + return sortedTalents; + }, {}), + trappings: sortedItems.filter(item => item.type === "trapping"), + weapons: sortedItems.filter(item => item.type === "weapon") + }; + } + + /** @inheritDoc */ + activateListeners(html) + { + super.activateListeners(html); + + html.find(".characteristic a").click(this._onCharacteristicClick.bind(this)); + + html.find(".impairment .token") + .click(this._onImpairmentTokenClick.bind(this, 1)) + .contextmenu(this._onImpairmentTokenClick.bind(this, -1)); + + html.find(".flip-link").click(this._onFlipClick.bind(this)); + + html.find(".item-roll-link").click(this._onItemRollClick.bind(this)); + html.find(".item-expand-link").click(this._onItemExpandClick.bind(this)); + html.find(".item-edit-link").click(this._onItemEditClick.bind(this)); + html.find(".item-delete-link").click(this._onItemDeleteClick.bind(this)); + + html.find(".item-name-link") + .click(this._onItemLeftClick.bind(this)) + .contextmenu(this._onItemRightClick.bind(this)); + + html.find(".item-input").change(this._onItemInput.bind(this)); + + html.find(".quantity-link") + .click(this._onQuantityClick.bind(this, 1)) + .contextmenu(this._onQuantityClick.bind(this, -1)); + + html.find(".recharge-token") + .click(this._onRechargeTokenClick.bind(this, 1)) + .contextmenu(this._onRechargeTokenClick.bind(this, -1)); + + html.find(".stance-meter .stance-meter-link") + .click(this._onStanceMeterLinkClick.bind(this, 1)) + .contextmenu(this._onStanceMeterLinkClick.bind(this, -1)); + } + + /** + * Get an Item's id from a clicked element hierarchy. + * @param {MouseEvent} event + * @private + */ + _getItemById(event) + { + return this.actor.items.get(event.currentTarget.dataset.itemId ?? $(event.currentTarget).parents(".item").data("itemId")); + } + + /** + * Performs follow-up operations after clicks on a Characteristic. + * @param {MouseEvent} event + * @private + */ + _onCharacteristicClick(event) + { + this.actor.performCharacteristicCheck(event.currentTarget.dataset.characteristic); + } + + /** + * Performs follow-up operations after clicks on a sheet's flip button. + * @param {MouseEvent} event + * @private + */ + async _onFlipClick(event) + { + event.preventDefault(); + + const parent = $(event.currentTarget).parents(".item"); + const activeFace = parent.find(".face.active"); + const inactiveFace = parent.find(".face:not(.active)"); + + activeFace.removeClass("active"); + inactiveFace.addClass("active"); + } + + /** + * Performs follow-up operations after clicks on an impairment token. + * @param {Number} amount + * @param {MouseEvent} event + * @private + */ + _onImpairmentTokenClick(amount, event) + { + this.actor.changeImpairment(event.currentTarget.dataset.impairment, amount); + } + + /** + * Performs follow-up operations after clicks on an Item delete button. + * @param {MouseEvent} event + * @private + */ + async _onItemDeleteClick(event) + { + const item = this._getItemById(event); + + await new Dialog({ + title: game.i18n.localize("APPLICATION.TITLE.DeleteItem"), + content: "

" + game.i18n.format("APPLICATION.DESCRIPTION.DeleteItem", {item: item.name}) + "

", + buttons: { + confirm: { + icon: '', + label: game.i18n.localize("Yes"), + callback: async dlg => { + await this.actor.deleteEmbeddedDocuments("Item", [item._id]); + li.slideUp(200, () => this.render(false)); + } + }, + cancel: { + icon: '', + label: game.i18n.localize("Cancel") + }, + }, + default: "confirm" + }).render(true); + } + + /** + * Performs follow-up operations after clicks on an Item edit button. + * @param {MouseEvent} event + * @private + */ + _onItemEditClick(event) + { + return this._getItemById(event).sheet.render(true); + } + + /** + * Performs follow-up operations after clicks on an item's expand button. + * @param {MouseEvent} event + * @private + */ + _onItemExpandClick(event) + { + event.preventDefault(); + event.stopPropagation(); + + const itemElement = $(event.currentTarget).hasClass("item") + ? $(event.currentTarget) + : $(event.currentTarget).parents(".item"); + const item = this._getItemById(event); + + if(itemElement.hasClass("expanded")) { + // Toggle expansion for an item + const details = itemElement.children(".details"); + + details.slideUp(200, () => details.remove()); + + itemElement.find(".item-expand-link .fas").removeClass("fa-chevron-up").addClass("fa-chevron-down"); + } + else { + // Add a div with the item's details below the row. + const detailsElement = $(`
${item.getDetails()}
`); + + itemElement.append(detailsElement.hide()); + detailsElement.slideDown(200); + + itemElement.find(".item-expand-link .fas").removeClass("fa-chevron-down").addClass("fa-chevron-up"); + } + + itemElement.toggleClass("expanded"); + } + + /** + * Performs follow-up operations after inputs on an Item. + * @param {Event} event + * @private + */ + _onItemInput(event) + { + event.preventDefault(); + event.stopPropagation(); + + const item = this._getItemById(event); + const propertyPath = event.currentTarget.dataset.path; + let value = event.target.value; + + if(event.currentTarget.type === "checkbox" && !event.currentTarget.checked) + value = false; + if(value === "on") + value = true; + + // Additional process needed for updates on Arrays. + let itemProperty = item; + for(let i = 0, path = propertyPath.split('.'), length = path.length; i < length; i++) + itemProperty = itemProperty[path[i]]; + + if(itemProperty instanceof Array) { + const index = event.currentTarget.dataset.index; + const subProperty = event.currentTarget.dataset.property; + + subProperty ? itemProperty[index][subProperty] = value : itemProperty[index] = value; + + item.update({[propertyPath]: itemProperty}); + } + else + item.update({[propertyPath]: value}); + } + + /** + * Performs follow-up operations after left-clicks on an Item button. + * @param {MouseEvent} event + * @private + */ + async _onItemLeftClick(event) + { + event.stopPropagation(); + + const options = {}; + const face = $(event.currentTarget).parents(".face").data("face"); + + if(face) + options.face = face; + + this._getItemById(event).useItem(options); + } + + /** + * Performs follow-up operations after right-clicks on an Item button. + * @param {MouseEvent} event + * @private + */ + async _onItemRightClick(event) + { + this._getItemById(event).sheet.render(true); + } + + /** + * Performs follow-up operations after clicks on an Item roll button. + * @param {MouseEvent} event + * @private + */ + _onItemRollClick(event) + { + const options = {}; + const face = $(event.currentTarget).parents(".face").data("face"); + + if(face) + options.face = face; + + this._getItemById(event).useItem(options); + } + + /** + * Performs follow-up operations after clicks on a Trapping's quantity button. + * @param {Number} amount + * @param {MouseEvent} event + * @private + */ + _onQuantityClick(amount, event) + { + this._getItemById(event).changeQuantity(event.ctrlKey ? amount * 10 : amount); + } + + /** + * Performs follow-up operations after left-clicks on a Card's recharge token button. + * @param {Number} amount + * @param {MouseEvent} event + * @private + */ + _onRechargeTokenClick(amount, event) + { + const item = this._getItemById(event); + + item.update({"system.rechargeTokens": item.system.rechargeTokens + amount}); + } + + /** + * Performs follow-up operations after clicks on a stance meter link. + * @param {Number} amount + * @param {MouseEvent} event + * @private + */ + _onStanceMeterLinkClick(amount, event) + { + this.actor.adjustStanceMeter(event.currentTarget.dataset.stance, amount); + } +} \ No newline at end of file diff --git a/modules/applications/actors/WFRP3eCharacterSheet.js b/modules/applications/actors/WFRP3eCharacterSheet.js index 42d998d..f0067e6 100644 --- a/modules/applications/actors/WFRP3eCharacterSheet.js +++ b/modules/applications/actors/WFRP3eCharacterSheet.js @@ -1,18 +1,17 @@ +import WFRP3eActorSheet from "./WFRP3eActorSheet.js"; import {capitalize} from "../../helpers.js"; /** @inheritDoc */ -export default class WFRP3eCharacterSheet extends ActorSheet +export default class WFRP3eCharacterSheet extends WFRP3eActorSheet { /** @inheritDoc */ static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/actors/character-sheet.hbs", - width: 932, - height: 815, + width: 920, + height: 840, classes: ["wfrp3e", "sheet", "actor", "character", "character-sheet"], - dragDrop: [{dragSelector: ".item", dropSelector: null}], tabs: [ {group: "primary", navSelector: ".primary-tabs", contentSelector: ".character-sheet-body", initial: "characteristics"}, {group: "careers", navSelector: ".character-sheet-career-tabs", contentSelector: ".character-sheet-careers"}, @@ -26,55 +25,12 @@ export default class WFRP3eCharacterSheet extends ActorSheet /** @inheritDoc */ getData() { - const data = { + this.options.tabs[1].initial = this.actor.system.currentCareer?._id; + + return { ...super.getData(), - actionTypes: CONFIG.WFRP3e.actionTypes, - conditionDurations: CONFIG.WFRP3e.conditionDurations, - characteristics: CONFIG.WFRP3e.characteristics, - diseaseSymptoms: CONFIG.WFRP3e.disease.symptoms, - origins: Object.values(CONFIG.WFRP3e.availableRaces).reduce((origins, race) => { - Object.entries(race.origins).forEach(origin => origins[origin[0]] = origin[1]); - return origins; - }, {}), - stances: CONFIG.WFRP3e.stances, - symbols: CONFIG.WFRP3e.symbols, - talentTypes: CONFIG.WFRP3e.talentTypes, - weaponGroups: CONFIG.WFRP3e.weapon.groups, - weaponQualities: CONFIG.WFRP3e.weapon.qualities, - weaponRanges: CONFIG.WFRP3e.weapon.ranges, talentSocketsByType: this._buildTalentSocketsList() }; - data.items = this._buildItemLists(data.items); - - this.options.tabs[1].initial = this.actor.system.currentCareer?._id; - - // Add basic skills to the Character. - if(this.actor.type === "character" && data.items.skills.length === 0) { - new Dialog({ - title: game.i18n.localize("APPLICATION.TITLE.BasicSkillsAdding"), - content: "

" + game.i18n.format("APPLICATION.DESCRIPTION.BasicSkillsAdding", {actor: this.actor.name}) + "

", - buttons: { - confirm: { - icon: '', - label: game.i18n.localize("APPLICATION.BUTTON.BasicSkillsAdding"), - callback: async dlg => { - const basicSkills = await game.packs.get("wfrp3e.items").getDocuments({type: "skill", system: {advanced: false}}); - - await Item.createDocuments(basicSkills, {parent: this.actor}); - } - }, - cancel: { - icon: '', - label: game.i18n.localize("Ignore") - }, - }, - default: 'confirm' - }).render(true); - } - - console.log(data) - - return data; } /** @inheritDoc */ @@ -83,88 +39,11 @@ export default class WFRP3eCharacterSheet extends ActorSheet super.activateListeners(html); html.find(".advance-checkbox").change(this._onAdvanceCheckboxChange.bind(this)); - - html.find(".characteristic a").click(this._onCharacteristicClick.bind(this)); - + html.find(".basic-skills-adding").click(this._onBasicSkillsAddingClick.bind(this)); html.find(".current-career-input").click(this._onCurrentCareerInput.bind(this)); - - html.find(".impairment .token") - .click(this._onImpairmentTokenLeftClick.bind(this)) - .contextmenu(this._onImpairmentTokenRightClick.bind(this)); - - html.find(".flip-link").click(this._onFlipClick.bind(this)); - - html.find(".item-roll-link").click(this._onItemRoll.bind(this)); - html.find(".item-expand-link").click(this._onItemExpandClick.bind(this)); - html.find(".item-edit-link").click(this._onItemEdit.bind(this)); - html.find(".item-delete-link").click(this._onItemDelete.bind(this)); - - html.find(".item-name-link") - .click(this._onItemLeftClick.bind(this)) - .contextmenu(this._onItemRightClick.bind(this)); - - html.find(".item-input").change(this._onItemInput.bind(this)); - - html.find(".quantity-link") - .click(this._onQuantityLeftClick.bind(this)) - .contextmenu(this._onQuantityRightClick.bind(this)); - - html.find(".recharge-token") - .click(this._onRechargeTokenLeftClick.bind(this)) - .contextmenu(this._onRechargeTokenRightClick.bind(this)); - - html.find(".stance-meter .stance-meter-link") - .click(this._onStanceMeterLinkClick.bind(this, 1)) - .contextmenu(this._onStanceMeterLinkClick.bind(this, -1)); - html.find(".skill-training-level-input").change(this._onSkillTrainingLevelChange.bind(this)); } - /** - * Returns items sorted by type. - * @param {Array} items The items owned by the Actor. - * @returns {Object} The sorted items owned by the Actor. - * @private - */ - _buildItemLists(items) - { - const basicTrait = game.i18n.localize("ACTION.TRAITS.Basic"); - const sortedItems = items.sort((a, b) => a.name.localeCompare(b.name)); - const actions = sortedItems.filter(item => item.type === "action").sort((a, b) => { - if(a.system.conservative.traits.includes(basicTrait) && !b.system.conservative.traits.includes(basicTrait)) - return -1; - else if(!a.system.conservative.traits.includes(basicTrait) && b.system.conservative.traits.includes(basicTrait)) - return 1 - else - return 0; - }); - const talents = sortedItems.filter(item => item.type === "talent"); - - return { - abilities: sortedItems.filter(item => item.type === "ability"), - actions: Object.keys(CONFIG.WFRP3e.actionTypes).reduce((sortedActions, actionType) => { - sortedActions[actionType] = actions.filter(action => action.system.type === actionType); - return sortedActions; - }, {}), - armours: sortedItems.filter(item => item.type === "armour"), - careers: sortedItems.filter(item => item.type === "career"), - conditions: sortedItems.filter(item => item.type === "condition"), - criticalWounds: sortedItems.filter(item => item.type === "criticalWound"), - diseases: sortedItems.filter(item => item.type === "disease"), - insanities: sortedItems.filter(item => item.type === "insanity"), - miscasts: sortedItems.filter(item => item.type === "miscast"), - money: sortedItems.filter(item => item.type === "money"), - mutations: sortedItems.filter(item => item.type === "mutation"), - skills: sortedItems.filter(item => item.type === "skill"), - talents: Object.keys(CONFIG.WFRP3e.talentTypes).reduce((sortedTalents, talentType) => { - sortedTalents[talentType] = talents.filter(talent => talent.system.type === talentType); - return sortedTalents; - }, {}), - trappings: sortedItems.filter(item => item.type === "trapping"), - weapons: sortedItems.filter(item => item.type === "weapon") - }; - } - /** * Builds up the list of Talent Sockets available for the Actor by Talent type. * @private @@ -226,16 +105,6 @@ export default class WFRP3eCharacterSheet extends ActorSheet return talentSocketsByType; } - /** - * Get an Item's id from a clicked element hierarchy. - * @param {MouseEvent} event - * @private - */ - _getItemById(event) - { - return this.actor.items.get(event.currentTarget.dataset.itemId ?? $(event.currentTarget).parents(".item").data("itemId")); - } - /** * Performs follow-up operations after changes on advance checkbox. * @param {Event} event @@ -255,13 +124,16 @@ export default class WFRP3eCharacterSheet extends ActorSheet } /** - * Performs follow-up operations after clicks on a Characteristic. - * @param {MouseEvent} event + * Performs follow-up operations after clicks on a basic skills adding button. + * @param {Event} event * @private */ - _onCharacteristicClick(event) + async _onBasicSkillsAddingClick(event) { - this.actor.performCharacteristicCheck(event.currentTarget.dataset.characteristic); + await Item.createDocuments( + await game.packs.get("wfrp3e.items").getDocuments({type: "skill", system: {advanced: false}}), + {parent: this.actor} + ); } /** @@ -274,264 +146,6 @@ export default class WFRP3eCharacterSheet extends ActorSheet this.actor.changeCurrentCareer(this._getItemById(event)); } - /** - * Performs follow-up operations after left-clicks on an impairment token. - * @param {MouseEvent} event - * @private - */ - _onImpairmentTokenLeftClick(event) - { - this.actor.changeImpairment(event.currentTarget.dataset.impairment, 1); - } - - /** - * Performs follow-up operations after right-clicks on an impairment token. - * @param {MouseEvent} event - * @private - */ - _onImpairmentTokenRightClick(event) - { - this.actor.changeImpairment(event.currentTarget.dataset.impairment, -1); - } - - /** - * Performs follow-up operations after clicks on a sheet's flip button. - * @param {MouseEvent} event - * @private - */ - async _onFlipClick(event) - { - event.preventDefault(); - - const parent = $(event.currentTarget).parents(".item"); - const activeFace = parent.find(".face.active"); - const inactiveFace = parent.find(".face:not(.active)"); - - activeFace.removeClass("active"); - inactiveFace.addClass("active"); - } - - /** - * Performs follow-up operations after left-clicks on a Trapping's quantity button. - * @param {MouseEvent} event - * @private - */ - _onQuantityLeftClick(event) - { - this._getItemById(event).changeQuantity(event.ctrlKey ? 10 : 1); - } - - /** - * Performs follow-up operations after right-clicks on a Trapping's quantity button. - * @param {MouseEvent} event - * @private - */ - _onQuantityRightClick(event) - { - const item = this._getItemById(event); - let quantity = item.system.quantity - (event.ctrlKey ? 10 : 1); - - // Floor quantity to 0 - if(quantity < 0) - quantity = 0; - - item.update({"system.quantity": quantity}); - } - - /** - * Performs follow-up operations after clicks on an Item roll button. - * @param {MouseEvent} event - * @private - */ - _onItemRoll(event) - { - const options = {}; - const face = $(event.currentTarget).parents(".face").data("face"); - - if(face) - options.face = face; - - this._getItemById(event).useItem(options); - } - - /** - * Performs follow-up operations after clicks on an Item edit button. - * @param {MouseEvent} event - * @private - */ - _onItemEdit(event) - { - return this._getItemById(event).sheet.render(true); - } - - /** - * Performs follow-up operations after clicks on an Item delete button. - * @param {MouseEvent} event - * @private - */ - async _onItemDelete(event) - { - const clickedItem = this._getItemById(event); - - await new Dialog({ - title: game.i18n.localize("APPLICATION.TITLE.DeleteItem"), - content: "

" + game.i18n.format("APPLICATION.DESCRIPTION.DeleteItem", {item: clickedItem.name}) + "

", - buttons: { - confirm: { - icon: '', - label: game.i18n.localize("Yes"), - callback: async dlg => { - await this.actor.deleteEmbeddedDocuments("Item", [clickedItem._id]); - li.slideUp(200, () => this.render(false)); - } - }, - cancel: { - icon: '', - label: game.i18n.localize("Cancel") - }, - }, - default: "confirm" - }).render(true); - } - - /** - * Performs follow-up operations after left-clicks on an Item button. - * @param {MouseEvent} event - * @private - */ - async _onItemLeftClick(event) - { - event.stopPropagation(); - - const options = {}; - const face = $(event.currentTarget).parents(".face").data("face"); - - if(face) - options.face = face; - - this._getItemById(event).useItem(options); - } - - /** - * Performs follow-up operations after right-clicks on an Item button. - * @param {MouseEvent} event - * @private - */ - async _onItemRightClick(event) - { - this._getItemById(event).sheet.render(true); - } - - /** - * Performs follow-up operations after inputs on an Item. - * @param {Event} event - * @private - */ - _onItemInput(event) - { - event.preventDefault(); - event.stopPropagation(); - - const item = this._getItemById(event); - const propertyPath = event.currentTarget.dataset.path; - let value = event.target.value; - - if(event.currentTarget.type === "checkbox" && !event.currentTarget.checked) - value = false; - if(value === "on") - value = true; - - // Additional process needed for updates on Arrays. - let itemProperty = item; - for(let i = 0, path = propertyPath.split('.'), length = path.length; i < length; i++) - itemProperty = itemProperty[path[i]]; - - if(itemProperty instanceof Array) { - const index = event.currentTarget.dataset.index; - const subProperty = event.currentTarget.dataset.property; - - subProperty ? itemProperty[index][subProperty] = value : itemProperty[index] = value; - - item.update({[propertyPath]: itemProperty}); - } - else - item.update({[propertyPath]: value}); - } - - /** - * Performs follow-up operations after left-clicks on a Card's recharge token button. - * @param {MouseEvent} event - * @private - */ - _onRechargeTokenLeftClick(event) - { - const item = this._getItemById(event); - - item.update({"system.rechargeTokens": item.system.rechargeTokens + 1}); - } - - /** - * Performs follow-up operations after right-clicks on a Card's recharge token button. - * @param {MouseEvent} event - * @private - */ - _onRechargeTokenRightClick(event) - { - const item = this._getItemById(event); - let rechargeTokens = item.system.rechargeTokens - 1; - - // Floor recharge tokens to 0 - if(rechargeTokens < 0) - rechargeTokens = 0; - - item.update({"system.rechargeTokens": rechargeTokens}); - } - - /** - * Performs follow-up operations after clicks on an item's expand button. - * @param {MouseEvent} event - * @private - */ - _onItemExpandClick(event) - { - event.preventDefault(); - event.stopPropagation(); - - const itemElement = $(event.currentTarget).hasClass("item") - ? $(event.currentTarget) - : $(event.currentTarget).parents(".item"); - const item = this._getItemById(event); - - if(itemElement.hasClass("expanded")) { - // Toggle expansion for an item - const details = itemElement.children(".details"); - - details.slideUp(200, () => details.remove()); - - itemElement.find(".item-expand-link .fas").removeClass("fa-chevron-up").addClass("fa-chevron-down"); - } - else { - // Add a div with the item's details below the row. - const detailsElement = $(`
${item.getDetails()}
`); - - itemElement.append(detailsElement.hide()); - detailsElement.slideDown(200); - - itemElement.find(".item-expand-link .fas").removeClass("fa-chevron-down").addClass("fa-chevron-up"); - } - - itemElement.toggleClass("expanded"); - } - - /** - * Performs follow-up operations after clicks on a stance meter link. - * @private - */ - _onStanceMeterLinkClick(amount, event) - { - this.actor.adjustStanceMeter(event.currentTarget.dataset.stance, amount); - } - /** * Performs follow-up operations after changes on a Skill's training level checkbox. * @param {Event} event diff --git a/modules/applications/actors/WFRP3eCreatureSheet.js b/modules/applications/actors/WFRP3eCreatureSheet.js index fb25637..ddeebfe 100644 --- a/modules/applications/actors/WFRP3eCreatureSheet.js +++ b/modules/applications/actors/WFRP3eCreatureSheet.js @@ -1,38 +1,37 @@ -export default class WFRP3eCreatureSheet extends ActorSheet +import WFRP3eActorSheet from "./WFRP3eActorSheet.js"; + +export default class WFRP3eCreatureSheet extends WFRP3eActorSheet { + constructor(object = {}, options = {}) + { + super(object, options); + + if(this.actor.system.nemesis) + this.position.height = 780; + } + static get defaultOptions() { return { ...super.defaultOptions, + width: 600, + height: 710, classes: ["wfrp3e", "sheet", "actor", "creature", "creature-sheet"], - dragDrop: [{dragSelector: ".item", dropSelector: null}], - height: 750, tabs: [ - {group: "primary", navSelector: ".creature-sheet-tabs", contentSelector: ".creature-sheet-body", initial: "main"}, + {group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"}, {group: "actions", navSelector: ".action-tabs", contentSelector: ".actions", initial: "melee"}, {group: "abilities", navSelector: ".ability-tabs", contentSelector: ".abilities", initial: "ability"} - ], - template: "systems/wfrp3e/templates/applications/actors/creature-sheet.hbs", - width: 600 + ] }; } /** @inheritDoc */ getData() { - const data = { + return { ...super.getData(), - actionTypes: CONFIG.WFRP3e.actionTypes, attributes: CONFIG.WFRP3e.attributes, - characteristics: CONFIG.WFRP3e.characteristics, - stances: CONFIG.WFRP3e.stances, - symbols: CONFIG.WFRP3e.symbols }; - data.items = this._buildItemLists(data.items); - - console.log(data) - - return data; } /** @inheritDoc */ @@ -40,223 +39,19 @@ export default class WFRP3eCreatureSheet extends ActorSheet { super.activateListeners(html); - html.find(".characteristic a").click(this._onCharacteristicLink.bind(this)); - - html.find(".creature-sheet-stance") - .click(this._onStanceLinkLeftClick.bind(this)) - .contextmenu(this._onStanceLinkRightClick.bind(this)); - - html.find(".flip-link").click(this._onFlipClick.bind(this)); - - html.find(".item-edit-link").click(this._onItemEdit.bind(this)); - html.find(".item-delete-link").click(this._onItemDelete.bind(this)); - - html.find(".item-name-link") - .click(this._onItemLeftClick.bind(this)) - .contextmenu(this._onItemRightClick.bind(this)); - - html.find(".recharge-token") - .click(this._onRechargeTokenLeftClick.bind(this)) - .contextmenu(this._onRechargeTokenRightClick.bind(this)); - } - - /** - * Returns items sorted by type. - * @param {Array} items The items owned by the Actor. - * @returns {Object} The sorted items owned by the Actor. - * @private - */ - _buildItemLists(items) - { - const basicTrait = game.i18n.localize("ACTION.TRAITS.Basic"); - const sortedItems = items.sort((a, b) => a.name.localeCompare(b.name)); - const actions = sortedItems.filter(item => item.type === "action").sort((a, b) => { - if(a.system.conservative.traits.includes(basicTrait) && !b.system.conservative.traits.includes(basicTrait)) - return -1; - else if(!a.system.conservative.traits.includes(basicTrait) && b.system.conservative.traits.includes(basicTrait)) - return 1 - else - return 0; - }); - const talents = sortedItems.filter(item => item.type === "talent"); - - return { - abilities: sortedItems.filter(item => item.type === "ability"), - actions: Object.keys(CONFIG.WFRP3e.actionTypes).reduce((sortedActions, actionType) => { - sortedActions[actionType] = actions.filter(action => action.system.type === actionType); - return sortedActions; - }, {}), - armours: sortedItems.filter(item => item.type === "armour"), - careers: sortedItems.filter(item => item.type === "career"), - conditions: sortedItems.filter(item => item.type === "condition"), - criticalWounds: sortedItems.filter(item => item.type === "criticalWound"), - diseases: sortedItems.filter(item => item.type === "disease"), - insanities: sortedItems.filter(item => item.type === "insanity"), - miscasts: sortedItems.filter(item => item.type === "miscast"), - money: sortedItems.filter(item => item.type === "money"), - mutations: sortedItems.filter(item => item.type === "mutation"), - skills: sortedItems.filter(item => item.type === "skill"), - talents: Object.keys(CONFIG.WFRP3e.talentTypes).reduce((sortedTalents, talentType) => { - sortedTalents[talentType] = talents.filter(talent => talent.system.type === talentType); - return sortedTalents; - }, {}), - trappings: sortedItems.filter(item => item.type === "trapping"), - weapons: sortedItems.filter(item => item.type === "weapon") - }; - } - - /** - * Get an Item's id from a clicked element hierarchy. - * @param {MouseEvent} event - * @private - */ - _getItemById(event) - { - return this.actor.items.get(event.currentTarget.dataset.itemId ?? $(event.currentTarget).parents(".item").data("itemId")); - } - - /** - * Performs follow-up operations after clicks on a Characteristic link. - * @param {MouseEvent} event - * @private - */ - _onCharacteristicLink(event) - { - this.actor.performCharacteristicCheck(event.currentTarget.dataset.characteristic); + html.find(".stance") + .click(this._onStanceLinkClick.bind(this, 1)) + .contextmenu(this._onStanceLinkClick.bind(this, -1)); } /** * Performs follow-up operations after left-clicks on the stance link. + * @param {Number} amount * @param {MouseEvent} event * @private */ - _onStanceLinkLeftClick(event) + _onStanceLinkClick(event) { this.actor.update({"system.stance": this.actor.system.stance + 1}); } - - /** - * Performs follow-up operations after right-clicks on the stance link. - * @param {MouseEvent} event - * @private - */ - _onStanceLinkRightClick(event) - { - this.actor.update({"system.stance": this.actor.system.stance - 1}); - } - - /** - * Performs follow-up operations after clicks on a sheet's flip button. - * @param {MouseEvent} event - * @private - */ - async _onFlipClick(event) - { - event.preventDefault(); - - const parent = $(event.currentTarget).parents(".item"); - const activeFace = parent.find(".face.active"); - const inactiveFace = parent.find(".face:not(.active)"); - - activeFace.removeClass("active"); - inactiveFace.addClass("active"); - } - - /** - * Performs follow-up operations after clicks on an Item edit button. - * @param {MouseEvent} event - * @private - */ - _onItemEdit(event) - { - return this._getItemById(event).sheet.render(true); - } - - /** - * Performs follow-up operations after clicks on an Item delete button. - * @param {MouseEvent} event - * @private - */ - async _onItemDelete(event) - { - const item = this._getItemById(event); - - await new Dialog({ - title: game.i18n.localize("APPLICATION.TITLE.DeleteItem"), - content: "

" + game.i18n.format("APPLICATION.DESCRIPTION.DeleteItem", {item: item.name}) + "

", - buttons: { - confirm: { - icon: '', - label: game.i18n.localize("Yes"), - callback: async dlg => { - await this.actor.deleteEmbeddedDocuments("Item", [item._id]); - li.slideUp(200, () => this.render(false)); - } - }, - cancel: { - icon: '', - label: game.i18n.localize("Cancel") - }, - }, - default: "confirm" - }).render(true); - } - - /** - * Performs follow-up operations after left-clicks on an Item button. - * @param {MouseEvent} event - * @private - */ - async _onItemLeftClick(event) - { - event.stopPropagation(); - - const item = this._getItemById(event); - const options = {}; - const face = $(event.currentTarget).parents(".face").data("face"); - - if(face) - options.face = face; - - item.useItem(options); - } - - /** - * Performs follow-up operations after right-clicks on an Item button. - * @param {MouseEvent} event - * @private - */ - async _onItemRightClick(event) - { - this._getItemById(event).sheet.render(true); - } - - /** - * Performs follow-up operations after left-clicks on a Card's recharge token button. - * @param {MouseEvent} event - * @private - */ - _onRechargeTokenLeftClick(event) - { - const item =this._getItemById(event); - - item.update({"system.rechargeTokens": item.system.rechargeTokens + 1}); - } - - /** - * Performs follow-up operations after right-clicks on a Card's recharge token button. - * @param {MouseEvent} event - * @private - */ - _onRechargeTokenRightClick(event) - { - const item = this._getItemById(event); - let rechargeTokens = item.system.rechargeTokens - 1; - - // Floor recharge tokens to 0. - if(rechargeTokens < 0) - rechargeTokens = 0; - - item.update({"system.rechargeTokens": rechargeTokens}); - } } \ No newline at end of file diff --git a/modules/applications/actors/WFRP3eGroupSheet.js b/modules/applications/actors/WFRP3eGroupSheet.js index 28d7562..df6dc9f 100644 --- a/modules/applications/actors/WFRP3eGroupSheet.js +++ b/modules/applications/actors/WFRP3eGroupSheet.js @@ -1,13 +1,14 @@ -export default class WFRP3eGroupSheet extends ActorSheet +import WFRP3eActorSheet from "./WFRP3eActorSheet.js"; + +export default class WFRP3eGroupSheet extends WFRP3eActorSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/actors/group-sheet.hbs", - classes: ["wfrp3e", "sheet", "actor", "group", "group-sheet"], width: 830, height: 540, + classes: ["wfrp3e", "sheet", "actor", "group", "group-sheet"], tabs: [ {group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"}, {group: "talents", navSelector: ".talent-tabs", contentSelector: ".talents", initial: "focus"} @@ -15,15 +16,6 @@ export default class WFRP3eGroupSheet extends ActorSheet }; } - /** @inheritDoc */ - getData() - { - const data = {...super.getData(), talentTypes: CONFIG.WFRP3e.talentTypes}; - data.items = this._buildItemLists(data.items); - - return data; - } - /** @inheritDoc */ activateListeners(html) { @@ -39,30 +31,6 @@ export default class WFRP3eGroupSheet extends ActorSheet html.find(".talent-socket-delete").click(this._onTalentSocketDelete.bind(this)); } - /** - * Returns items sorted by type. - * @param {Array} items The items owned by the Actor. - * @returns {Object} The sorted items owned by the Actor. - * @private - */ - _buildItemLists(items) - { - const talents = items - .filter(item => item.type === "talent") - .sort((a, b) => a.name.localeCompare(b.name)); - - return { - talents: { - focus: talents.filter(item => item.system.type === "focus"), - reputation: talents.filter(item => item.system.type === "reputation"), - tactic: talents.filter(item => item.system.type === "tactic"), - faith: talents.filter(item => item.system.type === "faith"), - order: talents.filter(item => item.system.type === "order"), - trick: talents.filter(item => item.system.type === "trick") - } - }; - } - /** * Performs follow-up operations clicks on an Ability Track edit button. * @param event {MouseEvent} diff --git a/modules/applications/actors/WFRP3ePartySheet.js b/modules/applications/actors/WFRP3ePartySheet.js index f923925..77b07fc 100644 --- a/modules/applications/actors/WFRP3ePartySheet.js +++ b/modules/applications/actors/WFRP3ePartySheet.js @@ -1,11 +1,12 @@ -export default class WFRP3ePartySheet extends ActorSheet +import WFRP3eActorSheet from "./WFRP3eActorSheet.js"; + +export default class WFRP3ePartySheet extends WFRP3eActorSheet { /** @inheritDoc */ static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/actors/party-sheet.hbs", width: 800, height: 540, classes: ["wfrp3e", "sheet", "actor", "party", "party-sheet"] @@ -31,7 +32,11 @@ export default class WFRP3ePartySheet extends ActorSheet html.find(".party-sheet-tension-meter .party-sheet-tension-meter-minus").click(this._onTensionMeterMinusClick.bind(this)); html.find(".party-sheet-members .party-sheet-member .party-sheet-member-portrait").click(this._onMemberPortraitClick.bind(this)); html.find(".party-sheet-members .party-sheet-member .party-sheet-member-remove").click(this._onMemberRemoveClick.bind(this)); - html.find(".fortune-token").mousedown(this._onFortunePoolClick.bind(this)); + + html.find(".fortune-token") + .click(this._onFortunePoolClick.bind(this, 1)) + .contextmenu(this._onFortunePoolClick.bind(this, -1)); + html.find(".party-sheet-footer .party-sheet-talent-socket-button-container .talent-socket-add").click(this._onTalentSocketAdd.bind(this)); html.find(".party-sheet-footer .party-sheet-talent-socket-button-container .talent-socket-delete").click(this._onTalentSocketDelete.bind(this)); } @@ -129,29 +134,13 @@ export default class WFRP3ePartySheet extends ActorSheet /** * Performs follow-up operations after clicks on the Fortune Pool's button. - * @param event {MouseEvent} + * @param {Number} amount + * @param {MouseEvent} event * @private */ - _onFortunePoolClick(event) + _onFortunePoolClick(amount, event) { - let fortunePool = this.actor.system.fortunePool; - - switch(event.button) { - // If left click… - case 0: - fortunePool++; - break; - // If right click… - case 2: - fortunePool--; - - if(fortunePool < 0) - fortunePool = 0; - - break; - } - - this.actor.update({"system.fortunePool": fortunePool}); + this.actor.update({"system.fortunePool": this.actor.system.fortunePool + amount}); } /** diff --git a/modules/applications/items/WFRP3eAbilitySheet.js b/modules/applications/items/WFRP3eAbilitySheet.js index 022620c..3552516 100644 --- a/modules/applications/items/WFRP3eAbilitySheet.js +++ b/modules/applications/items/WFRP3eAbilitySheet.js @@ -1,18 +1,12 @@ -export default class WFRP3eAbilitySheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eAbilitySheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/ability-sheet.hbs", - //width: 530, - height: 300, classes: ["wfrp3e", "sheet", "item", "ability"] }; } - - getData() - { - return super.getData(); - } } \ No newline at end of file diff --git a/modules/applications/items/WFRP3eActionSheet.js b/modules/applications/items/WFRP3eActionSheet.js index 142b3ee..30328a4 100644 --- a/modules/applications/items/WFRP3eActionSheet.js +++ b/modules/applications/items/WFRP3eActionSheet.js @@ -1,11 +1,12 @@ -export default class WFRP3eActionSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eActionSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/action-sheet.hbs", - width: 550, + width: 600, height: 680, classes: ["wfrp3e", "sheet", "item", "action"], tabs: [ diff --git a/modules/applications/items/WFRP3eArmourSheet.js b/modules/applications/items/WFRP3eArmourSheet.js index 67acf78..538dd5f 100644 --- a/modules/applications/items/WFRP3eArmourSheet.js +++ b/modules/applications/items/WFRP3eArmourSheet.js @@ -1,11 +1,11 @@ -export default class WFRP3eArmourSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eArmourSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/armour-sheet.hbs", - //width: 530, height: 400, classes: ["wfrp3e", "sheet", "item", "trapping", "armour"], tabs: [{group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"}] diff --git a/modules/applications/items/WFRP3eCareerSheet.js b/modules/applications/items/WFRP3eCareerSheet.js index aaa23d2..bb3b3be 100644 --- a/modules/applications/items/WFRP3eCareerSheet.js +++ b/modules/applications/items/WFRP3eCareerSheet.js @@ -1,11 +1,11 @@ -export default class WFRP3eCareerSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eCareerSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/career-sheet.hbs", - //width: 530, height: 820, classes: ["wfrp3e", "sheet", "item", "career"], tabs: [{group: "primary", navSelector: ".career-sheet-tabs", contentSelector: ".career-sheet-body", initial: "header"}] diff --git a/modules/applications/items/WFRP3eConditionSheet.js b/modules/applications/items/WFRP3eConditionSheet.js index 0361af3..a32ff06 100644 --- a/modules/applications/items/WFRP3eConditionSheet.js +++ b/modules/applications/items/WFRP3eConditionSheet.js @@ -1,12 +1,11 @@ -export default class WFRP3eConditionSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eConditionSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/condition-sheet.hbs", - //width: 530, - height: 400, classes: ["wfrp3e", "sheet", "item", "condition"] }; } diff --git a/modules/applications/items/WFRP3eCriticalWoundSheet.js b/modules/applications/items/WFRP3eCriticalWoundSheet.js index 81d2b4d..15db386 100644 --- a/modules/applications/items/WFRP3eCriticalWoundSheet.js +++ b/modules/applications/items/WFRP3eCriticalWoundSheet.js @@ -1,18 +1,12 @@ -export default class WFRP3eCriticalWoundSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eCriticalWoundSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/critical-wound-sheet.hbs", - //width: 530, - height: 300, classes: ["wfrp3e", "sheet", "item", "critical-wound"] }; } - - getData() - { - return super.getData(); - } } \ No newline at end of file diff --git a/modules/applications/items/WFRP3eDiseaseSheet.js b/modules/applications/items/WFRP3eDiseaseSheet.js index 3f1fabc..512dc03 100644 --- a/modules/applications/items/WFRP3eDiseaseSheet.js +++ b/modules/applications/items/WFRP3eDiseaseSheet.js @@ -1,12 +1,11 @@ -export default class WFRP3eDiseaseSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eDiseaseSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/disease-sheet.hbs", - //width: 530, - height: 400, classes: ["wfrp3e", "sheet", "item", "disease"] }; } diff --git a/modules/applications/items/WFRP3eInsanitySheet.js b/modules/applications/items/WFRP3eInsanitySheet.js index e553670..b66f40a 100644 --- a/modules/applications/items/WFRP3eInsanitySheet.js +++ b/modules/applications/items/WFRP3eInsanitySheet.js @@ -1,18 +1,12 @@ -export default class WFRP3eInsanitySheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eInsanitySheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/insanity-sheet.hbs", - //width: 530, - height: 400, classes: ["wfrp3e", "sheet", "item", "insanity"] }; } - - getData() - { - return super.getData(); - } } \ No newline at end of file diff --git a/modules/applications/items/WFRP3eItemSheet.js b/modules/applications/items/WFRP3eItemSheet.js new file mode 100644 index 0000000..3733093 --- /dev/null +++ b/modules/applications/items/WFRP3eItemSheet.js @@ -0,0 +1,15 @@ +export default class WFRP3eItemSheet extends ItemSheet +{ + static get defaultOptions() + { + return { + ...super.defaultOptions, + height: 400 + }; + } + + get template() + { + return `systems/wfrp3e/templates/applications/items/${this.item.type.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)}-sheet.hbs`; + } +} \ No newline at end of file diff --git a/modules/applications/items/WFRP3eMiscastSheet.js b/modules/applications/items/WFRP3eMiscastSheet.js index b554a1b..9170761 100644 --- a/modules/applications/items/WFRP3eMiscastSheet.js +++ b/modules/applications/items/WFRP3eMiscastSheet.js @@ -1,18 +1,12 @@ -export default class WFRP3eMiscastSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eMiscastSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/miscast-sheet.hbs", - //width: 530, - height: 300, classes: ["wfrp3e", "sheet", "item", "miscast"] }; } - - getData() - { - return super.getData(); - } } \ No newline at end of file diff --git a/modules/applications/items/WFRP3eMoneySheet.js b/modules/applications/items/WFRP3eMoneySheet.js index af497ed..b915cbb 100644 --- a/modules/applications/items/WFRP3eMoneySheet.js +++ b/modules/applications/items/WFRP3eMoneySheet.js @@ -1,18 +1,12 @@ -export default class WFRP3eMoneySheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eMoneySheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/money-sheet.hbs", - //width: 530, - //height: 340, classes: ["wfrp3e", "sheet", "item", "money"] }; } - - getData() - { - return super.getData(); - } } \ No newline at end of file diff --git a/modules/applications/items/WFRP3eMutationSheet.js b/modules/applications/items/WFRP3eMutationSheet.js index 8dceade..58a4337 100644 --- a/modules/applications/items/WFRP3eMutationSheet.js +++ b/modules/applications/items/WFRP3eMutationSheet.js @@ -1,18 +1,12 @@ -export default class WFRP3eMutationSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eMutationSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/mutation-sheet.hbs", - //width: 530, - height: 400, classes: ["wfrp3e", "sheet", "item", "mutation"] }; } - - getData() - { - return super.getData(); - } } \ No newline at end of file diff --git a/modules/applications/items/WFRP3eSkillSheet.js b/modules/applications/items/WFRP3eSkillSheet.js index 987d505..14947d8 100644 --- a/modules/applications/items/WFRP3eSkillSheet.js +++ b/modules/applications/items/WFRP3eSkillSheet.js @@ -1,12 +1,11 @@ -export default class WFRP3eSkillSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eSkillSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/skill-sheet.hbs", - //width: 530, - //height: 340, classes: ["wfrp3e", "sheet", "item", "skill"] }; } diff --git a/modules/applications/items/WFRP3eTalentSheet.js b/modules/applications/items/WFRP3eTalentSheet.js index 3d1e6e8..aa3f85a 100644 --- a/modules/applications/items/WFRP3eTalentSheet.js +++ b/modules/applications/items/WFRP3eTalentSheet.js @@ -1,12 +1,11 @@ -export default class WFRP3eTalentSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eTalentSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/talent-sheet.hbs", - //width: 530, - height: 250, classes: ["wfrp3e", "sheet", "item", "talent"] }; } diff --git a/modules/applications/items/WFRP3eTrappingSheet.js b/modules/applications/items/WFRP3eTrappingSheet.js index f0b36ff..1afa896 100644 --- a/modules/applications/items/WFRP3eTrappingSheet.js +++ b/modules/applications/items/WFRP3eTrappingSheet.js @@ -1,14 +1,13 @@ -export default class WFRP3eTrappingSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eTrappingSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/trapping-sheet.hbs", - //width: 530, - height: 400, classes: ["wfrp3e", "sheet", "item", "trapping"], - tabs: [{group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"},] + tabs: [{group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"}] }; } diff --git a/modules/applications/items/WFRP3eWeaponSheet.js b/modules/applications/items/WFRP3eWeaponSheet.js index 1969e1a..683c09d 100644 --- a/modules/applications/items/WFRP3eWeaponSheet.js +++ b/modules/applications/items/WFRP3eWeaponSheet.js @@ -1,14 +1,14 @@ -export default class WFRP3eWeaponSheet extends ItemSheet +import WFRP3eItemSheet from "./WFRP3eItemSheet.js"; + +export default class WFRP3eWeaponSheet extends WFRP3eItemSheet { static get defaultOptions() { return { ...super.defaultOptions, - template: "systems/wfrp3e/templates/applications/items/weapon-sheet.hbs", - //width: 530, - //height: 560, + height: 600, classes: ["wfrp3e", "sheet", "item", "trapping", "weapon"], - tabs: [{group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"},] + tabs: [{group: "primary", navSelector: ".primary-tabs", contentSelector: ".sheet-body", initial: "main"}] }; } diff --git a/modules/config.js b/modules/config.js index 0258a33..f10c019 100644 --- a/modules/config.js +++ b/modules/config.js @@ -1036,6 +1036,41 @@ export const WFRP3e = { tricks: "TALENT.TYPE.Tricks" }, weapon: { + commonWeapons: { + improvised: { + id: "improvised", + name: "WEAPON.Improvised", + system: { + criticalRating: 4, + damageRating: 3, + group: "thrown", + qualities: ["thrown"], + range: "close" + } + }, + improvisedWeapon: { + id: "improvisedWeapon", + name: "WEAPON.ImprovisedWeapon", + system: { + criticalRating: 3, + damageRating: 3, + group: "ordinary", + qualities: [], + range: "close" + } + }, + unarmed: { + id: "unarmed", + name: "WEAPON.Unarmed", + system: { + criticalRating: 4, + damageRating: 3, + group: "unarmed", + qualities: [], + range: "close" + } + } + }, groups: { blackpowder: { name: "WEAPON.GROUP.Blackpowder", diff --git a/modules/data/actors/WFRP3eCharacterDataModel.js b/modules/data/actors/WFRP3eCharacterDataModel.js index 5fdb32c..76e7da6 100644 --- a/modules/data/actors/WFRP3eCharacterDataModel.js +++ b/modules/data/actors/WFRP3eCharacterDataModel.js @@ -25,14 +25,14 @@ export default class WFRP3eCharacterDataModel extends foundry.abstract.TypeDataM characteristics: new fields.SchemaField(Object.keys(CONFIG.WFRP3e.characteristics).reduce((object, characteristic) => { if(characteristic !== "varies") object[characteristic] = new fields.SchemaField({ - rating: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), + rating: new fields.NumberField({initial: 2, integer: true, min: 0, nullable: false, required: true}), fortune: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}) }, {label: characteristic}); return object; }, {})), corruption: new fields.SchemaField({ - max: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), + max: new fields.NumberField({initial: 7, integer: true, min: 0, nullable: false, required: true}), value: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}) }), experience: new fields.SchemaField({ @@ -41,8 +41,8 @@ export default class WFRP3eCharacterDataModel extends foundry.abstract.TypeDataM }), favour: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), fortune: new fields.SchemaField({ - max: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), - value: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}) + max: new fields.NumberField({initial: 3, integer: true, min: 0, nullable: false, required: true}), + value: new fields.NumberField({initial: 3, integer: true, min: 0, nullable: false, required: true}) }), impairments: new fields.SchemaField({ fatigue: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), @@ -59,8 +59,8 @@ export default class WFRP3eCharacterDataModel extends foundry.abstract.TypeDataM current: new fields.NumberField({initial: 0, integer: true, nullable: false, required: true}) }), wounds: new fields.SchemaField({ - max: new fields.NumberField({initial: 7, integer: true, min: 0, nullable: false, required: true}), - value: new fields.NumberField({initial: 7, integer: true, min: 0, nullable: false, required: true}) + max: new fields.NumberField({initial: 10, integer: true, min: 0, nullable: false, required: true}), + value: new fields.NumberField({initial: 10, integer: true, min: 0, nullable: false, required: true}) }) }; } @@ -73,9 +73,8 @@ export default class WFRP3eCharacterDataModel extends foundry.abstract.TypeDataM this._calculateCurrentExperience(); this._prepareRace(); - this._prepareDefence(); + this._prepareDefenceAndSoak(); this._prepareEncumbrance(); - this._prepareSoak(); this._prepareRank(); this._prepareStanceMeter(); this._prepareDefaultStance(); @@ -129,12 +128,24 @@ export default class WFRP3eCharacterDataModel extends foundry.abstract.TypeDataM } /** - * Prepares the total defence of the WFRP3eCharacter. + * Prepares the total defence and soak of the WFRP3eCharacter. * @private */ - _prepareDefence() + _prepareDefenceAndSoak() { - this.totalDefence = this.parent.itemTypes.armour.reduce((totalDefence, armour) => totalDefence + armour.system.defenceValue, 0); + this.totalDefence = 0; + this.totalSoak = 0; + + this.parent.itemTypes.armour.forEach((armour) => { + this.totalDefence += armour.system.defenceValue; + this.totalSoak += armour.system.soakValue; + }); + + if(this.totalDefence === 0) + this.totalDefence = this.defenceValue; + + if(this.totalSoak === 0) + this.totalSoak = this.soakValue; } /** @@ -148,15 +159,6 @@ export default class WFRP3eCharacterDataModel extends foundry.abstract.TypeDataM .reduce((totalEncumbrance, item) => totalEncumbrance + item.system.encumbrance, 0); } - /** - * Prepares the total soak of the WFRP3eCharacter. - * @private - */ - _prepareSoak() - { - this.totalSoak = this.parent.itemTypes.armour.reduce((totalSoak, armour) => totalSoak + armour.system.soakValue, 0); - } - /** * Prepares the rank of the WFRP3eCharacter. * @private diff --git a/modules/data/actors/WFRP3eCreatureDataModel.js b/modules/data/actors/WFRP3eCreatureDataModel.js index 06f94dc..2cacd28 100644 --- a/modules/data/actors/WFRP3eCreatureDataModel.js +++ b/modules/data/actors/WFRP3eCreatureDataModel.js @@ -30,9 +30,19 @@ export default class WFRP3eCreatureDataModel extends foundry.abstract.TypeDataMo damageRating: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), defenceValue: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), description: new fields.HTMLField(), + impairments: new fields.SchemaField({ + fatigue: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), + stress: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}) + }), specialRuleSummary: new fields.HTMLField(), soakValue: new fields.NumberField({initial: 0, integer: true, min: 0, nullable: false, required: true}), - stance: new fields.NumberField({initial: 0, integer: true, nullable: false, required: true}), + stance: new fields.SchemaField({ + ...Object.keys(CONFIG.WFRP3e.stances).reduce((object, stance) => { + object[stance] = new fields.NumberField({initial: 1, integer: true, min: 0, nullable: false, required: true}); + return object; + }, {}), + current: new fields.NumberField({initial: 0, integer: true, nullable: false, required: true}) + }), threatRating: new fields.NumberField({initial: 1, integer: true, min: 1, nullable: false, required: true}), wounds: new fields.SchemaField({ max: new fields.NumberField({initial: 7, integer: true, min: 0, nullable: false, required: true}), @@ -41,13 +51,27 @@ export default class WFRP3eCreatureDataModel extends foundry.abstract.TypeDataMo }; } + static migrateData(source) + { + if(typeof source.stance === "number") + source.stance = { + conservative: source.stance < 0 ? Math.abs(source.stance) : 1, + reckless: source.stance > 0 ? source.stance : 1, + current: source.stance + }; + + return source; + } + /** @inheritDoc */ prepareBaseData() { super.prepareBaseData(); - this._prepareDefence(); + this._prepareDefenceAndSoak(); this._prepareDefaultStance(); + this._prepareNemesis(); + this._prepareStanceMeter(); if(this.specialRuleSummary) this._prepareSpecialRuleSummary(); @@ -66,25 +90,56 @@ export default class WFRP3eCreatureDataModel extends foundry.abstract.TypeDataMo } /** - * Prepares the total defence of the WFRP3eCharacter. + * Prepares the total defence and soak of the WFRP3eCreature. * @private */ - _prepareDefence() + _prepareDefenceAndSoak() { - const armourValue = this.parent.itemTypes.armour.reduce((totalDefence, armour) => totalDefence + armour.system.defenceValue, 0); - this.totalDefence = armourValue > 0 ? armourValue : this.defenceValue; + this.totalDefence = 0; + this.totalSoak = 0; + + this.parent.itemTypes.armour.forEach((armour) => { + this.totalDefence += armour.system.defenceValue; + this.totalSoak += armour.system.soakValue; + }); + + if(this.totalDefence === 0) + this.totalDefence = this.defenceValue; + + if(this.totalSoak === 0) + this.totalSoak = this.soakValue; } /** - * Prepares the default stance of the WFRP3eCharacter. + * Prepares the default stance of the WFRP3eCreature. * @private */ _prepareDefaultStance() { this.defaultStance = "conservative"; - if(this.stance > 0) { + if(this.stance.current > 0) this.defaultStance = "reckless"; - } + } + + /** + * Prepares the Nemesis status of the WFRP3eCreature. + * @private + */ + _prepareNemesis() + { + this.nemesis = this.category.includes(game.i18n.localize("CREATURE.Nemesis")); + } + + /** + * Prepares the stance meter of the WFRP3eCharacter. + * @private + */ + _prepareStanceMeter() + { + this.stanceMeter = { + conservative: -this.stance.conservative - (this.parent.system.currentCareer?.system.startingStance.conservativeSegments ?? 0), + reckless: this.stance.reckless + (this.parent.system.currentCareer?.system.startingStance.recklessSegments ?? 0) + }; } } \ No newline at end of file diff --git a/modules/data/items/WFRP3eCareerDataModel.js b/modules/data/items/WFRP3eCareerDataModel.js index 6a31bc9..2d5d23e 100644 --- a/modules/data/items/WFRP3eCareerDataModel.js +++ b/modules/data/items/WFRP3eCareerDataModel.js @@ -35,7 +35,7 @@ export default class WFRP3eCareerDataModel extends foundry.abstract.TypeDataMode cost: new fields.NumberField({initial: 0, integer: true, min: 0}), type: new fields.StringField({initial: "", nullable: false, required: true}) }), - {initial: new Array(2).fill({cost: 0, nature: ""})} + {initial: new Array(2).fill({cost: 0, type: ""})} ) }), careerSkills: new fields.StringField({initial: ", , , , ", required: true}), diff --git a/styles/less/components/action_sheet.less b/styles/less/components/action_sheet.less index 8bfefd8..0e59e73 100644 --- a/styles/less/components/action_sheet.less +++ b/styles/less/components/action_sheet.less @@ -43,6 +43,10 @@ &.effect-description { display: none; } + + & .editor { + min-height: 100px; + } } } } diff --git a/styles/less/components/character_sheet.less b/styles/less/components/character_sheet.less index 770a1b1..8b2968b 100644 --- a/styles/less/components/character_sheet.less +++ b/styles/less/components/character_sheet.less @@ -24,7 +24,7 @@ & .characteristics-tab { &.active { - flex-direction: row; + flex-direction: row !important; } & .attributes { @@ -127,61 +127,14 @@ display: flex; flex-direction: column; - .impairment { - display: flex; - margin: auto; - flex: 1 1 auto; - flex-direction: row; - - &:first-child { - margin-bottom: 10px; - } - - &:last-child { - margin-top: 10px; - } - - & > .token { - position: relative; - width: 4rem; - - & > * { - position: absolute; - } - - - & > img { - border: none; - opacity: 75%; - top: 50%; - transform: translate(0, -50%); - } - - & > .token-counter { - color: white; - font-size: 24pt; - left: 38%; - text-shadow: - -1pt -1pt 0 black, - -1pt 0 0 black, - 0 -1pt 0 black, - -1pt 1pt 0 black, - 1pt -1pt 0 black, - 0 1pt 0 black, - 1pt 0 0 black, - 1pt 1pt 0 black; - top: 47%; - } - } + & .token-counter { + left: 50%; + top: 50%; + transform: translate(-50%, -20%); + } - & .title { - display: block; - font: small-caps bold var(--font-size-18) var(--font-primary); - padding: 0 2px 0 4px; - writing-mode: vertical-lr; - text-align: center; - transform: rotate(180deg); - } + & .title { + transform: rotate(180deg); } } } @@ -197,52 +150,17 @@ } } - & .stance-meter { - margin-bottom: 0.5rem; - - & h3 { - align-items: center; - display: flex; - gap: 0.25rem; - justify-content: center; - margin-bottom: 0.25rem; - - & .stance-meter-segment > img { - opacity: 50%; - } - } - - & .stance-meter-segments { - display: flex; - justify-content: center; - } - - & .stance-meter-segment { - display: block; - height: 27px; - - &.active { - filter: drop-shadow(gold 0px 0px 4px); - } - - & > img { - border: none; - width: 32px; - - &.stance-neutral { - width: 38px; - } - } - - & > input { - display: none; - } - } + & .stance-meter h3 { + align-items: center; + display: flex; + gap: 0.25rem; + justify-content: center; + margin-bottom: 0.25rem; } } & .talents-tab .character-sheet-talents .talent-container { - & > div { + & > label { margin-bottom: 2rem; & > select { @@ -256,10 +174,6 @@ } } - & .trappings-tab { - gap: 1rem; - } - & .item-container .career-partial { display: flex; flex-flow: row wrap; @@ -311,172 +225,6 @@ } } } - - & .table { - display: flex; - flex-direction: column; - min-height: 0; - - & hr { - margin: 0; - } - - & > * hr { - border: none; - border-left: 1px solid var(--color-border-light-primary); - border-right: 1px solid var(--color-border-light-highlight); - height: 1rem; - width: 1px; - } - - & .buttons { - font-size: 10pt; - width: 5%; - } - - & .encumbrance { - width: 5%; - } - - & .quantity { - width: 10%; - } - - & .row { - background: #D8CFC0; - padding: 0.25rem; - - &:nth-of-type(even) { - background: #E9E2DB; - } - - &.skill { - background: #EDE1D1; - - &:nth-of-type(even) { - background: #E1CFB6; - } - } - - & .content:first-child { - align-items: center; - display: flex; - text-align: center; - } - } - - & .table-header { - background: #7E1518; - color: var(--color-text-light-highlight); - display: flex; - font-weight: bold; - padding: 0.25rem; - text-align: center; - text-shadow: 1px 1px var(--color-shadow-dark); - - &.skill { - background: initial; - color: initial; - font-variant-caps: small-caps; - text-shadow: initial; - } - - &.title { - background: #3F0B0CFF; - display: block; - } - - & hr { - border-right: 1px solid var(--color-border-light-primary); - } - } - - & .table-body { - overflow: auto; - } - - &.armour { - & .armour-defence-value { - width: 10%; - } - - & .armour-soak-value { - width: 10%; - } - - & .armour-name { - text-align: initial; - width: 70%; - } - } - - &.money { - & .money-value { - width: 10%; - } - - & .money-name { - text-align: initial; - width: 70%; - } - } - - &.skill { - & .buttons { - width: 10%; - } - - & .skill-characteristic { - font-variant-caps: small-caps; - width: 15%; - } - - & .skill-name { - font-variant-caps: small-caps; - text-align: initial; - width: 50%; - } - - & .skill-training-level { - width: 25%; - } - } - - &.trapping { - - & .trapping-name { - text-align: initial; - width: 90%; - } - } - - &.weapon { - & .weapon-critical-rating { - width: 5%; - } - - & .weapon-damage-rating { - width: 5%; - } - - & .weapon-group { - width: 15%; - } - - & .weapon-name { - text-align: initial; - width: 20%; - } - - & .weapon-qualities { - width: 40%; - } - - & .weapon-range { - width: 10%; - } - } - } } & .character-sheet-header { diff --git a/styles/less/components/creature_sheet.less b/styles/less/components/creature_sheet.less index 4cd8772..7303364 100644 --- a/styles/less/components/creature_sheet.less +++ b/styles/less/components/creature_sheet.less @@ -6,7 +6,19 @@ display: flex; flex-direction: column; - & .creature-sheet-body { + & .category { + background-color: #240000; + border: solid dimgray; + border-radius: 0; + border-width: 2px 0; + color: white; + font-style: italic; + padding-top: 0.25rem; + text-align: center; + width: 100%; + } + + & .sheet-body { flex: 1 1 0; min-height: 0; @@ -17,213 +29,186 @@ overflow: auto; } - & .creature-sheet-actions-tab { - overflow: unset; - - &.action-card { - margin: 0.5rem auto; - } - - & .creature-sheet-actions { - min-height: 0; - overflow: auto; - } - - & .creature-sheet-action-tabs { - border-bottom: 1px solid #b5b3a4; - display: flex; - flex-flow: row wrap; - justify-content: space-around; - - & > * { - margin: 0 5px; - } - } - - & .action-container { - &.active { - align-items: center; - display: flex; - flex-wrap: wrap; - justify-content: space-around; - } - } + & .action-tab .actions .action-container { + justify-content: center; } - & .creature-sheet-main-tab { - & > div { - display: flex; - - &.creature-sheet-attributes { - background-color: #884832; - border: solid dimgray; - border-radius: 0; - border-width: 4px 1rem 0; - color: white; - padding: 0.25rem 0 0.5rem; - text-align: center; - text-shadow: - -1pt -1pt 0 black, + & .main-tab > div { + display: flex; + + &.attributes { + background-color: #884832; + border: solid dimgray; + border-radius: 0; + border-width: 4px 1rem 0; + color: white; + padding: 0.25rem 0 0.5rem; + text-align: center; + text-shadow: + -1pt -1pt 0 black, -1pt 0 0 black, - 0 -1pt 0 black, + 0 -1pt 0 black, -1pt 1pt 0 black, - 1pt -1pt 0 black, + 1pt -1pt 0 black, 0 1pt 0 black, 1pt 0 0 black, 1pt 1pt 0 black; - & .attribute { - flex-grow: 1; - margin: 0 0.5rem; + & .attribute { + flex-grow: 1; + margin: 0 0.5rem; - & .attribute-title { - font-size: var(--font-size-18); - font-variant: small-caps; - } + & .attribute-title { + font-size: var(--font-size-18); + font-variant: small-caps; + } - & .attribute-input-container input { - color: white; - font-size: var(--font-size-22); - font-style: italic; - padding-top: 0.5rem; - text-shadow: + & .attribute-input-container input { + color: white; + font-size: var(--font-size-22); + font-style: italic; + padding-top: 0.5rem; + text-shadow: -1pt -1pt 0 black, - -1pt 0 0 black, + -1pt 0 0 black, 0 -1pt 0 black, - -1pt 1pt 0 black, + -1pt 1pt 0 black, 1pt -1pt 0 black, - 0 1pt 0 black, - 1pt 0 0 black, - 1pt 1pt 0 black; - width: 2rem; - } + 0 1pt 0 black, + 1pt 0 0 black, + 1pt 1pt 0 black; + width: 2rem; + } - &.expertise { - color: yellow; + &.expertise { + color: yellow; - & input { - color: yellow; - } + & input { + color: yellow; } } } + } - &.creature-sheet-main-infos { - & .creature-sheet-characteristics { - flex: 1 1 20%; - padding: 0 0.5rem; + &.main-infos { + & .characteristics { + flex: 0 0 100px; + padding: 0 0.5rem; - & > div { - align-items: center; - display: flex; - font-weight: bold; - margin-bottom: 0.25rem; + & > div { + align-items: center; + display: flex; + font-weight: bold; + margin-bottom: 0.25rem; - & > .characteristic-title { - margin-right: auto; - } + & > .characteristic-title { + margin-right: auto; + } - & .characteristic-rating-input { - background: lightcyan; - border-color: lightsteelblue; - border-width: 2px; - padding-top: 0.25rem; - font-weight: bold; - text-align: center; - width: 2rem; - } + & .characteristic-rating-input { + background: lightcyan; + border-color: lightsteelblue; + border-width: 2px; + padding-top: 0.25rem; + font-weight: bold; + text-align: center; + width: 2rem; + } - & .characteristic-fortune-input { - background: white; - border-color: dimgray; - font-size: var(--font-size-14); - font-weight: bold; - height: 1.25rem; - padding-top: 0.25rem; - text-align: center; - width: 1.25rem; - } + & .characteristic-fortune-input { + background: white; + border-color: dimgray; + font-size: var(--font-size-14); + font-weight: bold; + height: 1.25rem; + padding-top: 0.25rem; + text-align: center; + width: 1.25rem; } } + } - & .creature-sheet-image { - flex-basis: 60%; + & .image { + flex: 1 1 auto; + + & > img { + display: block; + margin: auto; } + } - & .creature-sheet-ratings { - flex: 1 1 20%; - padding-left: 0.5rem; - - & > div { - align-items: center; - background-color: #240000; - border: solid dimgrey; - border-radius: 2rem 0 0 2rem; - border-width: 2px 0; - display: flex; - margin-bottom: 0.25rem; - - & > img { - border: none; - } + & .ratings { + flex: 0 0 100px; + padding-left: 0.5rem; + + & > .rating-container { + align-items: center; + background-color: #240000; + border: solid dimgrey; + border-radius: 2rem 0 0 2rem; + border-width: 2px 0; + display: flex; + margin-bottom: 0.25rem; + + & > img { + border: none; + } - & > input { - border: none; - color: white; - font-weight: bold; - padding: 0.25rem 0 0 0.5rem; + & > input { + border: none; + color: white; + font-weight: bold; + padding: 0.25rem 0 0 0.5rem; - &:focus { - box-shadow: none; - text-shadow: 0 0 5px var(--color-shadow-primary); - } + &:focus { + box-shadow: none; + text-shadow: 0 0 5px var(--color-shadow-primary); } } } + + & > .impairment .token-counter { + left: 50%; + top: 50%; + transform: translate(-50%, -25%); + } } + } - &.creature-sheet-secondary-infos { - flex-grow: 1; - padding: 0 1rem 1rem; + &.secondary-infos { + flex-grow: 1; + padding: 0 1rem 1rem; - & .creature-sheet-special-rule-summary { - flex-grow: 1; + & .special-rule-summary { + flex-grow: 1; - & > .editor { - height: 100%; - } + & > .editor { + height: 100%; } + } - & .creature-sheet-stance { - font-size: var(--font-size-18); - margin: auto 1rem 1rem 0; + & .stance { + font-size: var(--font-size-18); + margin: auto 1rem 1rem 0; - &.conservative { - color: green; - } + &.conservative { + color: green; + } - &.reckless { - color: red; - } + &.reckless { + color: red; } } } - } - } - & .creature-sheet-category { - background-color: #240000; - border: solid dimgray; - border-radius: 0; - border-width: 2px 0; - color: white; - font-style: italic; - padding-top: 0.25rem; - text-align: center; - width: 100%; + &.stance-meter { + justify-content: center; + margin: 0.5rem 0; + } + } } - & .creature-sheet-header { + & .sheet-header { background: url(../assets/images/creature-sheet-header.webp) center/100% 100% no-repeat; flex-wrap: nowrap; padding: 0 0.5rem; @@ -247,7 +232,7 @@ text-shadow: 0 0 5px var(--color-shadow-primary); } - &.creature-sheet-threat-rating { + &.threat-rating { color: white; flex: 0 0 12.5%; font-size: var(--font-size-28); @@ -255,7 +240,7 @@ } } - & .creature-sheet-name > input { + & .name > input { color: bisque; text-shadow: -1pt -1pt 2pt black, @@ -268,7 +253,7 @@ 1pt 1pt 2pt black; } - & .creature-sheet-wounds { + & .wounds { flex: 0 0 3rem; & hr { @@ -283,7 +268,7 @@ } } - & .creature-sheet-tabs { + & .primary-tabs { border-top: none; } } diff --git a/styles/less/components/sheet.less b/styles/less/components/sheet.less index c8bb76a..17e9852 100644 --- a/styles/less/components/sheet.less +++ b/styles/less/components/sheet.less @@ -1,93 +1,376 @@ -.sheet { - & nav.primary-tabs { - font: small-caps bold var(--font-size-18) var(--font-primary); - } - - & section > nav { - border-top: none; - } - - & .editor-content { - margin: 0 0.5rem; - } - - & .form-div { +.wfrp3e.sheet { + & form { display: flex; - flex-wrap: wrap; - gap: 0.5rem; + flex-direction: column; - & > * { - flex: 1 1 auto; + & hr { + width: 100%; } - & input[type=number] { - width: 2rem; + & nav.primary-tabs { + font: small-caps bold var(--font-size-18) var(--font-primary); } - } - & .form-label { - align-items: center; - display: flex; - gap: 0.5rem; - - & > input { + & .editor-container { + display: flex; + flex-direction: column; flex-grow: 1; - width: unset; } - } - - & .sheet-body { - flex: 1 1 0; - min-height: 0; - & > .tab.active { + & .sheet-body { display: flex; - flex-flow: column nowrap; - height: 100%; - overflow: auto; - } + flex: 1 1 0; + flex-direction: column; + min-height: 0; + + & > .tab.active { + display: flex; + flex-flow: column nowrap; + height: 100%; + overflow: auto; + } + + & section > nav { + border-top: none; + } - & .tab { - overflow: unset; + & .editor { + background: rgba(250, 240, 230, 0.5); + border-radius: 0.5rem; + flex-grow: 1; + min-height: 200px; - & .tab-content { - min-height: 0; + & .editor-content { + margin: 0 0.5rem; + } } - & .sheet-tabs { - border-bottom: 1px solid #b5b3a4; + & .form-div { display: flex; - flex-flow: row wrap; - justify-content: space-around; + flex-wrap: wrap; + gap: 0.5rem; & > * { - margin: 0 5px; + flex: 1 1 auto; + } + + & input[type=number] { + width: 2rem; } } - } - & .item-container { - display: none; - flex-flow: row wrap; - height: 100%; - overflow: auto; + & .form-label { + align-items: center; + display: flex; + gap: 0.5rem; - &.active { + & > input { + flex-grow: 1; + width: unset; + } + } + + & .impairment { display: flex; + margin: auto; + flex: 1 1 auto; + flex-direction: row; + + &:first-child { + margin-bottom: 10px; + } + + &:last-child { + margin-top: 10px; + } + + & > .token { + position: relative; + width: 4rem; + + & > * { + position: absolute; + } + + + & > img { + border: none; + opacity: 75%; + top: 50%; + transform: translate(0, -50%); + } + + & > .token-counter { + color: white; + font-size: 24pt; + text-shadow: + -1pt -1pt 0 black, + -1pt 0 0 black, + 0 -1pt 0 black, + -1pt 1pt 0 black, + 1pt -1pt 0 black, + 0 1pt 0 black, + 1pt 0 0 black, + 1pt 1pt 0 black; + } + } + + & .title { + display: block; + font: small-caps bold var(--font-size-18) var(--font-primary); + padding: 0 2px 0 4px; + writing-mode: vertical-lr; + text-align: center; + } + } + + & .item-container { + display: none; + flex-flow: row wrap; + height: 100%; + overflow: auto; + + &.active { + display: flex; + } + } + + & .stance-meter { + margin-bottom: 0.5rem; + + & .stance-meter-link > img { + opacity: 50%; + } + + & .stance-meter-segment { + display: block; + height: 27px; + + &.active { + filter: drop-shadow(gold 0px 0px 4px); + } + + & > img { + border: none; + width: 32px; + + &.stance-neutral { + width: 38px; + } + } + + & > input { + display: none; + } + } + + & .stance-meter-segment-container { + display: flex; + justify-content: center; + } + } + + & .tab { + overflow: unset; + + & .tab-content { + min-height: 0; + } + + & .sheet-tabs { + border-bottom: 1px solid #b5b3a4; + display: flex; + flex-flow: row wrap; + justify-content: space-around; + + & > * { + margin: 0 5px; + } + } + } + + & .table { + display: flex; + flex-direction: column; + min-height: 0; + + & hr { + margin: 0; + } + + & > * hr { + border: none; + border-left: 1px solid var(--color-border-light-primary); + border-right: 1px solid var(--color-border-light-highlight); + height: 1rem; + width: 1px; + } + + & .buttons { + font-size: 10pt; + width: 5%; + } + + & .encumbrance { + width: 5%; + } + + & .quantity { + width: 10%; + } + + & .row { + background: #D8CFC0; + padding: 0.25rem; + + &:nth-of-type(even) { + background: #E9E2DB; + } + + &.skill { + background: #EDE1D1; + + &:nth-of-type(even) { + background: #E1CFB6; + } + } + + & .content:first-child { + align-items: center; + display: flex; + text-align: center; + } + } + + & .table-header { + background: #7E1518; + color: var(--color-text-light-highlight); + display: flex; + font-weight: bold; + padding: 0.25rem; + text-align: center; + text-shadow: 1px 1px var(--color-shadow-dark); + + &.skill { + background: initial; + color: initial; + font-variant-caps: small-caps; + text-shadow: initial; + } + + &.title { + background: #3F0B0CFF; + display: block; + } + + & hr { + border-right: 1px solid var(--color-border-light-primary); + } + } + + & .table-body { + overflow: auto; + } + + &.armour { + & .armour-defence-value { + width: 10%; + } + + & .armour-soak-value { + width: 10%; + } + + & .armour-name { + text-align: initial; + width: 70%; + } + } + + &.money { + & .money-value { + width: 10%; + } + + & .money-name { + text-align: initial; + width: 70%; + } + } + + &.skill { + & .buttons { + width: 10%; + } + + & .skill-characteristic { + font-variant-caps: small-caps; + width: 15%; + } + + & .skill-name { + font-variant-caps: small-caps; + text-align: initial; + width: 50%; + } + + & .skill-training-level { + width: 25%; + } + } + + &.trapping { + + & .trapping-name { + text-align: initial; + width: 90%; + } + } + + &.weapon { + & .weapon-critical-rating { + width: 5%; + } + + & .weapon-damage-rating { + width: 5%; + } + + & .weapon-group { + width: 15%; + } + + & .weapon-name { + text-align: initial; + width: 20%; + } + + & .weapon-qualities { + width: 40%; + } + + & .weapon-range { + width: 10%; + } + } + } + + & .trappings-tab { + gap: 1rem; } } - } - & .tab-link.active { - color: white; - text-shadow: - -1px -1px 0 black, - -1px 0 0 black, - 0 -1px 0 black, - -1px 1px 0 black, - 1px -1px 0 black, - 0 1px 0 black, - 1px 0 0 black, - 1px 1px 0 black !important; + & .tab-link.active { + color: white; + text-shadow: + -1px -1px 0 black, + -1px 0 0 black, + 0 -1px 0 black, + -1px 1px 0 black, + 1px -1px 0 black, + 0 1px 0 black, + 1px 0 0 black, + 1px 1px 0 black !important; + } } } \ No newline at end of file diff --git a/styles/less/wfrp3e.less b/styles/less/wfrp3e.less index 09ce048..fb73d73 100644 --- a/styles/less/wfrp3e.less +++ b/styles/less/wfrp3e.less @@ -135,13 +135,6 @@ th { background-color: green; } -.editor { - background: rgba(250, 240, 230, 0.5); - border-radius: 0.5rem; - flex-grow: 1; - min-height: 75px; -} - .face { display: none; height: 100%; diff --git a/system.json b/system.json index 118686f..b105aac 100644 --- a/system.json +++ b/system.json @@ -4,7 +4,7 @@ "version": "#{VERSION}#", "compatibility": { "minimum": "12", - "verified": "12.328", + "verified": "12.330", "maximum": "12" }, "authors": [{ diff --git a/templates/applications/actors/character-sheet.hbs b/templates/applications/actors/character-sheet.hbs index 28b2e24..b211983 100644 --- a/templates/applications/actors/character-sheet.hbs +++ b/templates/applications/actors/character-sheet.hbs @@ -30,11 +30,21 @@ @@ -65,23 +75,28 @@

{{localize "CHARACTER.Skills"}}

-
-
- {{localize "SKILL.Name"}} + {{#if items.skills}} +
+
+ {{localize "SKILL.Name"}} - {{localize "SKILL.ABBREVIATION.Characteristic"}} + {{localize "SKILL.ABBREVIATION.Characteristic"}} - {{localize "SKILL.TrainingLevel"}} + {{localize "SKILL.TrainingLevel"}} - -
+ +
-
- {{#each items.skills as |skill sk|}} - {{>systems/wfrp3e/templates/partials/item-skill-row.hbs skill=skill}} - {{/each}} +
+ {{#each items.skills as |skill sk|}} + {{>systems/wfrp3e/templates/partials/item-skill-row.hbs skill=skill}} + {{/each}} +
-
+ {{else}} +

{{{localize "CHARACTER.SHEET.NoSkill" actor=actor.name}}}

+ + {{/if}}
@@ -135,7 +150,7 @@ -
+
{{#for actor.system.stanceMeter.conservative (increment actor.system.stanceMeter.reckless 1) 1}}
\ No newline at end of file diff --git a/templates/applications/actors/creature-sheet.hbs b/templates/applications/actors/creature-sheet.hbs index c07892f..ae8219f 100644 --- a/templates/applications/actors/creature-sheet.hbs +++ b/templates/applications/actors/creature-sheet.hbs @@ -1,31 +1,48 @@
-
- +
+ -

+

-
- +
+
- +
- + -
- {{editor item.system.description target='system.description' button=true owner=owner editable=editable}} +
+ {{editor item.system.description target='system.description' button=true owner=owner editable=editable}} +
\ No newline at end of file diff --git a/templates/applications/items/action-sheet.hbs b/templates/applications/items/action-sheet.hbs index 39bb5c2..01e5973 100644 --- a/templates/applications/items/action-sheet.hbs +++ b/templates/applications/items/action-sheet.hbs @@ -10,7 +10,7 @@ @@ -105,9 +105,8 @@
-
diff --git a/templates/applications/items/weapon-sheet.hbs b/templates/applications/items/weapon-sheet.hbs index fa0f2a0..5ecb6b6 100644 --- a/templates/applications/items/weapon-sheet.hbs +++ b/templates/applications/items/weapon-sheet.hbs @@ -94,18 +94,18 @@
-