mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
2029 lines
No EOL
91 KiB
JavaScript
2029 lines
No EOL
91 KiB
JavaScript
import { capitalize } from '../../helpers/utils.mjs';
|
|
import DhpDeathMove from '../deathMove.mjs';
|
|
import DhpDowntime from '../downtime.mjs';
|
|
import DhpLevelup from '../levelup.mjs';
|
|
import AncestrySelectionDialog from '../ancestrySelectionDialog.mjs';
|
|
import DaggerheartSheet from './daggerheart-sheet.mjs';
|
|
|
|
const { ActorSheetV2 } = foundry.applications.sheets;
|
|
export default class PCSheet extends DaggerheartSheet(ActorSheetV2) {
|
|
constructor(options={}){
|
|
super(options);
|
|
|
|
this.editAttributes = false;
|
|
this.onVaultTab = false;
|
|
this.currentInventoryPage = 0;
|
|
this.selectedScar = null;
|
|
this.storyEditor = null;
|
|
this.dropItemBlock = false;
|
|
this.multiclassFeatureSetSelected = false;
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
tag: 'form',
|
|
id: "daggerheart-pc",
|
|
classes: ["daggerheart", "sheet", "pc"],
|
|
position: { width: 810, height: 1080 },
|
|
actions: {
|
|
toggleEditAttributes: this.toggleEditAttributes,
|
|
attributeRoll: this.rollAttribute,
|
|
toggleMarks: this.toggleMarks,
|
|
toggleAttributeMark: this.toggleAttributeMark,
|
|
toggleHP: this.toggleHP,
|
|
toggleStress: this.toggleStress,
|
|
toggleHope: this.toggleHope,
|
|
toggleGold: this.toggleGold,
|
|
attackRoll: this.attackRoll,
|
|
tabToLoadout: () => this.domainCardsTab(false),
|
|
tabToVault: () => this.domainCardsTab(true),
|
|
sendToVault: (_, button) => this.moveDomainCard(button, true),
|
|
sentToLoadout: (_, button) => this.moveDomainCard(button, false),
|
|
useDomainCard: this.useDomainCard,
|
|
selectClass: this.selectClass,
|
|
selectSubclass: this.selectSubclass,
|
|
selectAncestry: this.selectAncestry,
|
|
selectCommunity: this.selectCommunity,
|
|
viewObject: this.viewObject,
|
|
useFeature: this.useFeature,
|
|
takeShortRest: this.takeShortRest,
|
|
takeLongRest: this.takeLongRest,
|
|
removeActiveItem: this.removeActiveItem,
|
|
removeInventoryWeapon: this.removeInventoryWeapon,
|
|
addMiscItem: this.addMiscItem,
|
|
deleteItem: this.deleteItem,
|
|
addScar: this.addScar,
|
|
selectScar: this.selectScar,
|
|
deleteScar: this.deleteScar,
|
|
makeDeathMove: this.makeDeathMove,
|
|
toggleFeatureDice: this.toggleFeatureDice,
|
|
setStoryEditor: this.setStoryEditor,
|
|
itemQuantityDecrease: (_, button) => this.setItemQuantity(button, -1),
|
|
itemQuantityIncrease: (_, button) => this.setItemQuantity(button, 1),
|
|
useAbility: this.useAbility,
|
|
useAdvancementCard: this.useAdvancementCard,
|
|
useAdvancementAbility: this.useAdvancementAbility,
|
|
selectFeatureSet: this.selectFeatureSet,
|
|
},
|
|
form: {
|
|
handler: this.updateForm,
|
|
submitOnChange: true,
|
|
closeOnSubmit: false,
|
|
},
|
|
dragDrop: [
|
|
{dragSelector: null, dropSelector: ".weapon-section" },
|
|
{dragSelector: null, dropSelector: ".armor-section"},
|
|
{dragSelector: null, dropSelector: ".inventory-weapon-section-first"},
|
|
{dragSelector: null, dropSelector: ".inventory-weapon-section-second"},
|
|
{dragSelector: ".item-list .item", dropSelector: null},
|
|
],
|
|
};
|
|
|
|
static PARTS = {
|
|
form: {
|
|
id: "pc",
|
|
template: "systems/daggerheart/templates/sheets/pc/pc.hbs"
|
|
}
|
|
}
|
|
|
|
_getTabs() {
|
|
const setActive = (tabs) => {
|
|
for ( const v of Object.values(tabs) ) {
|
|
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
|
|
v.cssClass = v.active ? "active" : "";
|
|
}
|
|
}
|
|
|
|
const primaryTabs = {
|
|
features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Features') },
|
|
loadout: { active: false, cssClass: '', group: 'primary', id: 'loadout', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Loadout') },
|
|
inventory: { active: false, cssClass: '', group: 'primary', id: 'inventory', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Inventory') },
|
|
story: { active: false, cssClass: '', group: 'primary', id: 'story', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Story') },
|
|
}
|
|
const secondaryTabs = {
|
|
foundation: { active: true, cssClass: '', group: 'secondary', id: 'foundation', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Foundation') },
|
|
loadout: { active: false, cssClass: '', group: 'secondary', id: 'loadout', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Loadout') },
|
|
vault: { active: false, cssClass: '', group: 'secondary', id: 'vault', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Vault') },
|
|
}
|
|
|
|
setActive(primaryTabs);
|
|
setActive(secondaryTabs);
|
|
|
|
return { primary: primaryTabs, secondary: secondaryTabs };
|
|
}
|
|
|
|
_attachPartListeners(partId, htmlElement, options) {
|
|
super._attachPartListeners(partId, htmlElement, options);
|
|
$(htmlElement).find(".attribute-value").on("change", this.attributeChange.bind(this));
|
|
$(htmlElement).find(".tab-selector").on("click", this.tabSwitch.bind(this));
|
|
$(htmlElement).find(".level-title.levelup").on("click", this.openLevelUp.bind(this));
|
|
$(htmlElement).find(".feature-input").on("change", this.onFeatureInputBlur.bind(this));
|
|
$(htmlElement).find(".experience-description").on("change", this.experienceDescriptionChange.bind(this));
|
|
$(htmlElement).find(".experience-value").on("change", this.experienceValueChange.bind(this));
|
|
$(htmlElement).find("[data-item]").on("change", this.itemUpdate.bind(this));
|
|
}
|
|
|
|
async _prepareContext(_options) {
|
|
const context = await super._prepareContext(_options);
|
|
context.document = this.document;
|
|
context.tabs = this._getTabs();
|
|
|
|
context.config = SYSTEM;
|
|
context.editAttributes = this.editAttributes;
|
|
context.onVaultTab = this.onVaultTab;
|
|
context.selectedScar = this.selectedScar;
|
|
context.storyEditor = this.storyEditor;
|
|
context.multiclassFeatureSetSelected = this.multiclassFeatureSetSelected;
|
|
|
|
const selectedAttributes = Object.values(this.document.system.attributes).map(x => x.data.base);
|
|
context.abilityScoreArray = JSON.parse(await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray)).reduce((acc, x) => {
|
|
const selectedIndex = selectedAttributes.indexOf(x);
|
|
if(selectedIndex !== -1){
|
|
selectedAttributes.splice(selectedIndex, 1);
|
|
} else {
|
|
acc.push({ name: x, value: x });
|
|
}
|
|
|
|
return acc;
|
|
}, []);
|
|
if(!context.abilityScoreArray.includes(0)) context.abilityScoreArray.push({ name: 0, value: 0 });
|
|
context.abilityScoresFinished = context.abilityScoreArray.every(x => x.value === 0);
|
|
|
|
context.domains = this.document.system.class ? {
|
|
first: this.document.system.class.system.domains[0] ? SYSTEM.DOMAIN.domains[this.document.system.class.system.domains[0]].src : null,
|
|
second: this.document.system.class.system.domains[1] ? SYSTEM.DOMAIN.domains[this.document.system.class.system.domains[1]].src : null,
|
|
} : { };
|
|
|
|
context.attributes = Object.keys(this.document.system.attributes).reduce((acc, key) => {
|
|
acc[key] = {
|
|
...this.document.system.attributes[key],
|
|
name: game.i18n.localize(SYSTEM.ACTOR.abilities[key].name),
|
|
verbs: SYSTEM.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)),
|
|
};
|
|
|
|
return acc;
|
|
}, {});
|
|
|
|
const ancestry = await this.mapFeatureType(this.document.system.ancestry ? [this.document.system.ancestry] : [], SYSTEM.GENERAL.objectTypes);
|
|
const community = await this.mapFeatureType(this.document.system.community ? [this.document.system.community] : [], SYSTEM.GENERAL.objectTypes);
|
|
const foundation = {
|
|
ancestry: ancestry[0],
|
|
community: community[0],
|
|
advancement: {
|
|
...this.mapAdvancementFeatures(this.document, SYSTEM)
|
|
}
|
|
};
|
|
|
|
const nrLoadoutCards = this.document.system.domainCards.loadout.length;
|
|
const loadout = await this.mapFeatureType(this.document.system.domainCards.loadout, SYSTEM.DOMAIN.cardTypes);
|
|
const vault = await this.mapFeatureType(this.document.system.domainCards.vault, SYSTEM.DOMAIN.cardTypes);
|
|
context.abilities = {
|
|
foundation: foundation,
|
|
loadout: {
|
|
top: loadout.slice(0, Math.min(2, nrLoadoutCards)),
|
|
bottom: nrLoadoutCards > 2 ? loadout.slice(2, Math.min(5, nrLoadoutCards)) : [],
|
|
nrTotal: nrLoadoutCards,
|
|
},
|
|
vault: vault.map(x => ({ ...x, uuid: x.uuid, sendToLoadoutDisabled: this.document.system.domainCards.loadout.length >= this.document.system.domainData.maxLoadout }))
|
|
};
|
|
|
|
context.inventory = {
|
|
consumable: {
|
|
titles: {
|
|
name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.ConsumableTitle"),
|
|
quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"),
|
|
},
|
|
items: this.document.items.filter(x => x.type === 'consumable'),
|
|
},
|
|
miscellaneous: {
|
|
titles: {
|
|
name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.MiscellaneousTitle"),
|
|
quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"),
|
|
},
|
|
items: this.document.items.filter(x => x.type === 'miscellaneous'),
|
|
},
|
|
}
|
|
|
|
if(context.inventory.length === 0){
|
|
context.inventory = Array(1).fill(Array(5).fill([]));
|
|
}
|
|
|
|
context.classFeatures = (this.multiclassFeatureSetSelected ? this.document.system.multiclassFeatures : this.document.system.classFeatures).map(x => {
|
|
if(x.system.featureType.type !== 'dice'){
|
|
return x;
|
|
}
|
|
|
|
return { ...x, uuid: x.uuid, system: { ...x.system, featureType: { ...x.system.featureType, data: { ...x.system.featureType.data, property: this.document.system.subclass ? SYSTEM.ACTOR.featureProperties[x.system.featureType.data.property].path(this.document) : 0 }}}};
|
|
});
|
|
|
|
return context;
|
|
}
|
|
|
|
static async updateForm(event, _, formData) {
|
|
await this.document.update(formData.object)
|
|
this.render();
|
|
}
|
|
|
|
async mapFeatureType(data, configType){
|
|
return await Promise.all(data.map(async x => {
|
|
const abilities = x.system.abilities ? await Promise.all(x.system.abilities.map(async x => await fromUuid(x.uuid))) : [];
|
|
|
|
return {
|
|
...x,
|
|
uuid: x.uuid,
|
|
system: {
|
|
...x.system,
|
|
abilities: abilities,
|
|
type: game.i18n.localize(configType[x.system.type??x.type].label)
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
mapAdvancementFeatures(actor, config) {
|
|
if(!actor.system.subclass) return { foundation: null, advancements: [] };
|
|
|
|
const { subclass, multiclassSubclass } = actor.system.subclassFeatures;
|
|
|
|
const foundation = {
|
|
type: 'foundation',
|
|
multiclass: false,
|
|
img: actor.system.subclass.img,
|
|
subtitle: game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"),
|
|
domains: actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src),
|
|
className: actor.system.class.name,
|
|
subclassUuid: actor.system.subclass.uuid,
|
|
subclassName: actor.system.subclass.name,
|
|
spellcast: config.ACTOR.abilities[actor.system.subclass.system.spellcastingTrait]?.name ?? null,
|
|
description: actor.system.subclass.system.foundationFeature.description,
|
|
abilities: subclass.foundation,
|
|
abilityKey: 'foundationFeature',
|
|
};
|
|
|
|
const firstKey = actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 2 ? 'sub' :
|
|
actor.system.multiclass?.system?.multiclassTier === 2 ? 'multi' : null;
|
|
const firstType = firstKey === 'sub' ? 'specialization' : 'foundation';
|
|
const firstBase = firstKey === 'sub' ? actor.system.subclass : firstKey === 'multi' ? actor.system.multiclassSubclass : null;
|
|
const first = !firstBase ? null : {
|
|
type: firstType,
|
|
multiclass: firstKey === 'multi',
|
|
img: firstBase.img,
|
|
subtitle: firstKey === 'sub' ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"),
|
|
domains: firstKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src),
|
|
className: firstKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name,
|
|
subclassUuid: firstBase.uuid,
|
|
subclassName: firstBase.name,
|
|
spellcast: firstKey === 'sub' ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null,
|
|
description: firstKey === 'sub' ? firstBase.system.specializationFeature.description : firstBase.system.foundationFeature.description,
|
|
abilities: firstKey === 'sub' ? subclass.specialization : multiclassSubclass.foundation,
|
|
abilityKey: firstKey === 'sub' ? 'specializationFeature' : 'foundationFeature',
|
|
};
|
|
|
|
const secondKey = (actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 3) || (actor.system.subclass.system.masteryFeature.unlocked && actor.system.subclass.system.masteryFeature.tier === 3) ? 'sub' :
|
|
(actor.system.multiclass?.system?.multiclassTier === 3) || (actor.system.multiclassSubclass?.system?.specializationFeature?.unlocked) ? 'multi' : null;
|
|
const secondBase = secondKey === 'sub' ? actor.system.subclass : secondKey === 'multi' ? actor.system.multiclassSubclass : null;
|
|
const secondAbilities = secondKey === 'sub' ? subclass : multiclassSubclass;
|
|
const secondType = secondBase ? secondBase.system.masteryFeature.unlocked ? 'mastery' : secondBase.system.specializationFeature.unlocked ? 'specialization' : 'foundation' : null;
|
|
const second = !secondBase ? null : {
|
|
type: secondType,
|
|
multiclass: secondKey === 'multi',
|
|
img: secondBase.img,
|
|
subtitle: secondBase.system.masteryFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.MasteryTitle") :
|
|
secondBase.system.specializationFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"),
|
|
domains: secondKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src),
|
|
className: secondKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name,
|
|
subclassUuid: secondBase.uuid,
|
|
subclassName: secondBase.name,
|
|
spellcast: secondKey === 'sub' || secondBase.system.specializationFeature.unlocked ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null,
|
|
description:
|
|
secondBase.system.masteryFeature.unlocked ? secondBase.system.masteryFeature.description :
|
|
secondBase.system.specializationFeature.unlocked ? secondBase.system.specializationFeature.description : firstBase.system.foundationFeature.description,
|
|
abilities:
|
|
secondBase.system.masteryFeature.unlocked ? secondAbilities.mastery :
|
|
secondBase.system.specializationFeature.unlocked ? secondAbilities.specialization : secondAbilities.foundation,
|
|
abilityKey: secondBase.system.masteryFeature.unlocked ? 'masteryFeature' : secondBase.system.specializationFeature.unlocked ? 'specializationFeature' : 'foundationFeature',
|
|
};
|
|
|
|
return {
|
|
foundation: foundation,
|
|
first: first,
|
|
second: second,
|
|
}
|
|
}
|
|
|
|
async attributeChange(event){
|
|
const path = `system.attributes.${event.currentTarget.dataset.attribute}.data.base`;
|
|
await this.document.update({ [path]: event.currentTarget.value });
|
|
}
|
|
|
|
static toggleEditAttributes(){
|
|
this.editAttributes = !this.editAttributes;
|
|
this.render();
|
|
}
|
|
|
|
static async rollAttribute(_, event){
|
|
const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.document.dualityRoll({ title: 'Attribute Bonus', value: event.currentTarget.dataset.value }, event.shiftKey);
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
type: 'dualityRoll',
|
|
system: {
|
|
roll: roll._formula,
|
|
modifiers: modifiers,
|
|
hope: hope,
|
|
fear: fear,
|
|
advantage: advantage,
|
|
disadvantage: disadvantage,
|
|
},
|
|
user: game.user.id,
|
|
content: "systems/daggerheart/templates/chat/duality-roll.hbs",
|
|
rolls: [roll]
|
|
});
|
|
|
|
await cls.create(msg.toObject());
|
|
}
|
|
|
|
static async toggleMarks(_, button){
|
|
const markValue = Number.parseInt(button.dataset.value);
|
|
const newValue = this.document.system.armor.system.marks.value >= markValue ? markValue-1 : markValue;
|
|
await this.document.system.armor.update({ 'system.marks.value': newValue });
|
|
}
|
|
|
|
static async toggleAttributeMark(_, button){
|
|
const attribute = this.document.system.attributes[button.dataset.attribute];
|
|
const newMark = this.document.system.availableAttributeMarks.filter(x => x > Math.max.apply(null, this.document.system.attributes[button.dataset.attribute].levelMarks)).sort((a, b) => a > b ? 1 : -1)[0];
|
|
|
|
if(attribute.levelMark || !newMark) return;
|
|
|
|
|
|
const path = `system.attributes.${button.dataset.attribute}.levelMarks`;
|
|
await this.document.update({ [path]: [...attribute.levelMarks, newMark] });
|
|
}
|
|
|
|
static async toggleHP(_, button){
|
|
const healthValue = Number.parseInt(button.dataset.value);
|
|
const newValue = this.document.system.resources.health.value >= healthValue ? healthValue-1 : healthValue;
|
|
await this.document.update({ 'system.resources.health.value': newValue });
|
|
}
|
|
|
|
static async toggleStress(_, button){
|
|
const healthValue = Number.parseInt(button.dataset.value);
|
|
const newValue = this.document.system.resources.stress.value >= healthValue ? healthValue-1 : healthValue;
|
|
await this.document.update({ 'system.resources.stress.value': newValue });
|
|
}
|
|
|
|
static async toggleHope(_, button){
|
|
const hopeValue = Number.parseInt(button.dataset.value);
|
|
const newValue = this.document.system.resources.hope.value >= hopeValue ? hopeValue-1 : hopeValue;
|
|
await this.document.update({ 'system.resources.hope.value': newValue });
|
|
}
|
|
|
|
static async toggleGold(_, button){
|
|
const goldValue = Number.parseInt(button.dataset.value);
|
|
const goldType = button.dataset.type;
|
|
const newValue = this.document.system.gold[goldType] >= goldValue ? goldValue-1 : goldValue;
|
|
|
|
const update = `system.gold.${goldType}`;
|
|
await this.document.update({ [update]: newValue });
|
|
}
|
|
|
|
static async attackRoll(_, event){
|
|
const weapon = await fromUuid(event.currentTarget.dataset.weapon);
|
|
const damage = {
|
|
value: `${this.document.system.proficiency.value}${weapon.system.damage.value}`,
|
|
type: weapon.system.damage.type,
|
|
bonusDamage: this.document.system.bonuses.damage
|
|
};
|
|
const modifier = this.document.system.attributes[weapon.system.trait].data.value;
|
|
|
|
const { roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString } = await this.document.dualityRoll({ title: 'Attribute Modifier', value: modifier }, event.shiftKey, damage.bonusDamage);
|
|
|
|
damage.value = damage.value.concat(bonusDamageString);
|
|
|
|
const targets = Array.from(game.user.targets).map(x => ({
|
|
id: x.id,
|
|
name: x.actor.name,
|
|
img: x.actor.img,
|
|
difficulty: x.actor.system.difficulty,
|
|
evasion: x.actor.system.evasion,
|
|
}));
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
type: 'dualityRoll',
|
|
system: {
|
|
roll: roll._formula,
|
|
modifiers: modifiers,
|
|
hope: hope,
|
|
fear: fear,
|
|
advantage: advantage,
|
|
disadvantage: disadvantage,
|
|
damage: damage,
|
|
targets: targets,
|
|
},
|
|
content: "systems/daggerheart/templates/chat/attack-roll.hbs",
|
|
rolls: [roll]
|
|
});
|
|
|
|
await cls.create(msg.toObject());
|
|
}
|
|
|
|
tabSwitch(event){
|
|
const tab = event.currentTarget.dataset.tab;
|
|
if(tab !== 'loadout'){
|
|
this.onVaultTab = false;
|
|
}
|
|
|
|
this.render();
|
|
}
|
|
|
|
openLevelUp(){
|
|
new DhpLevelup(this.document).render(true);
|
|
}
|
|
|
|
static domainCardsTab(toVault){
|
|
this.onVaultTab = toVault;
|
|
this.render();
|
|
}
|
|
|
|
static async moveDomainCard(button, toVault){
|
|
if(!toVault && this.document.system.domainCards.loadout.length >= this.document.system.domainData.maxLoadout){
|
|
return;
|
|
}
|
|
|
|
const card = this.document.items.find(x => x.uuid === button.dataset.domain);
|
|
await card.update({ "system.inVault": toVault });
|
|
}
|
|
|
|
static async useDomainCard(_, button){
|
|
const card = this.document.items.find(x => x.uuid === button.dataset.key);
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
type: 'abilityUse',
|
|
user: game.user.id,
|
|
content: "systems/daggerheart/templates/chat/ability-use.hbs",
|
|
system: {
|
|
title: `${game.i18n.localize("DAGGERHEART.Chat.DomainCard.Title")} - ${capitalize(button.dataset.domain)}`,
|
|
img: card.img,
|
|
name: card.name,
|
|
description: card.system.effect,
|
|
actions: card.system.actions,
|
|
},
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
}
|
|
|
|
static async selectClass(){
|
|
(await game.packs.get('daggerheart.playtest-classes'))?.render(true);
|
|
}
|
|
|
|
static async selectSubclass(){
|
|
(await game.packs.get('daggerheart.playtest-subclasses'))?.render(true);
|
|
}
|
|
|
|
static async selectAncestry(){
|
|
const dialogClosed = new Promise((resolve, _) => {
|
|
new AncestrySelectionDialog(resolve).render(true);
|
|
});
|
|
const result = await dialogClosed;
|
|
|
|
// await this.emulateItemDrop({ type: 'item', data: result });
|
|
for(var ancestry of this.document.items.filter(x => x => x.type === 'ancestry')){
|
|
await ancestry.delete();
|
|
}
|
|
|
|
const createdItems = [];
|
|
for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){
|
|
await feature.delete();
|
|
}
|
|
|
|
// createdItems.push(...result.data.system.abilities);
|
|
createdItems.push(result.data);
|
|
|
|
|
|
await this.document.createEmbeddedDocuments('Item', createdItems);
|
|
|
|
// await this.document.createEmbeddedDocuments("Item", [result.toObject()]);
|
|
// (await game.packs.get('daggerheart.playtest-ancestries'))?.render(true);
|
|
}
|
|
|
|
static async selectCommunity(){
|
|
(await game.packs.get('daggerheart.playtest-communities'))?.render(true);;
|
|
}
|
|
|
|
static async viewObject(button){
|
|
const object = await fromUuid(button.dataset.value);
|
|
if(!object) return;
|
|
|
|
const tab = button.dataset.tab;
|
|
if(tab) object.sheet._tabs[0].active = tab;
|
|
|
|
if(object.sheet.editMode) object.sheet.editMode = false;
|
|
|
|
object.sheet.render(true);
|
|
}
|
|
|
|
static async takeShortRest(){
|
|
await new DhpDowntime(this.document, true).render(true);
|
|
await this.minimize();
|
|
}
|
|
|
|
static async takeLongRest(){
|
|
await new DhpDowntime(this.document, false).render(true);
|
|
await this.minimize();
|
|
}
|
|
|
|
static async removeActiveItem(_, event){
|
|
event.stopPropagation();
|
|
const item = await fromUuid(event.currentTarget.dataset.item);
|
|
await item.delete();
|
|
}
|
|
|
|
static async removeInventoryWeapon(_, event){
|
|
event.stopPropagation();
|
|
const item = await fromUuid(event.currentTarget.dataset.item);
|
|
await item.delete();
|
|
}
|
|
|
|
static async addMiscItem(){
|
|
const result = await this.document.createEmbeddedDocuments("Item", [{
|
|
name: game.i18n.localize('DAGGERHEART.Sheets.PC.NewItem'),
|
|
type: 'miscellaneous'
|
|
}]);
|
|
|
|
await result[0].sheet.render(true);
|
|
}
|
|
|
|
static async addScar(){
|
|
if(this.document.system.story.scars.length === 5) return;
|
|
|
|
await this.document.update({ "system.story.scars": [...this.document.system.story.scars, { name: game.i18n.localize("DAGGERHEART.Sheets.PC.NewScar"), description: '' }] });
|
|
}
|
|
|
|
static async selectScar(_, button){
|
|
this.selectedScar = Number.parseInt(button.dataset.value);
|
|
this.render();
|
|
}
|
|
|
|
static async deleteScar(event, button) {
|
|
event.stopPropagation();
|
|
await this.document.update({ "system.story.scars": this.document.system.story.scars.filter((_, index) => index !== Number.parseInt(button.currentTarget.dataset.scar) ) })
|
|
}
|
|
|
|
static async makeDeathMove() {
|
|
if(this.document.system.resources.health.value === this.document.system.resources.health.max){
|
|
await new DhpDeathMove(this.document).render(true);
|
|
await this.minimize();
|
|
}
|
|
}
|
|
|
|
static async toggleFeatureDice(_, button){
|
|
const index = Number.parseInt(button.dataset.index);
|
|
const feature = this.document.system.classFeatures.find(x => x.uuid === button.dataset.feature);
|
|
const path = `system.featureType.data.numbers.${index}`;
|
|
if(feature.system.featureType.data.numbers[index]?.used) return;
|
|
|
|
if(Object.keys(feature.system.featureType.data.numbers).length <= index) {
|
|
const roll = new Roll(feature.system.featureType.data.value);
|
|
const rollData = await roll.evaluate();
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
user: game.user.id,
|
|
rolls: [roll]
|
|
});
|
|
|
|
await cls.create(msg.toObject());
|
|
|
|
await feature.update({ [path]: { value: Number.parseInt(rollData.total), used: false } });
|
|
} else {
|
|
await Dialog.confirm({
|
|
title: game.i18n.localize("Confirm feature use"),
|
|
content: `Are you sure you want to use ${feature.name}?`,
|
|
yes: async () => {
|
|
await feature.update({ [path]: { used: true } });
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
user: game.user.id,
|
|
content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", {
|
|
title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"),
|
|
card: { name: `${feature.name} - Roll Of ${feature.system.featureType.data.numbers[index].value}`, img: feature.img },
|
|
}),
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
},
|
|
no: () => { return; },
|
|
defaultYes: false
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
async onFeatureInputBlur(event){
|
|
const feature = this.document.system.classFeatures.find(x => x.uuid === event.currentTarget.dataset.feature);
|
|
const value = Number.parseInt(event.currentTarget.value);
|
|
if(!Number.isNaN(value)) await feature?.update({ "system.featureType.data.value": value });
|
|
}
|
|
|
|
async experienceDescriptionChange(event){
|
|
const newExperiences = [...this.document.system.experiences];
|
|
newExperiences[event.currentTarget.dataset.index].description = event.currentTarget.value;
|
|
await this.document.update({ "system.experiences": newExperiences });
|
|
}
|
|
|
|
async experienceValueChange(event){
|
|
const newExperiences = [...this.document.system.experiences];
|
|
newExperiences[event.currentTarget.dataset.index].value = event.currentTarget.value;
|
|
await this.document.update({ "system.experiences": newExperiences });
|
|
}
|
|
|
|
static setStoryEditor(_, button) {
|
|
this.storyEditor = this.storyEditor === button.dataset.value ? null : button.dataset.value;
|
|
this.render();
|
|
}
|
|
|
|
async itemUpdate(event){
|
|
const name = event.currentTarget.dataset.item;
|
|
const item = await fromUuid($(event.currentTarget).closest('[data-item-id]')[0].dataset.itemId);
|
|
await item.update({ [name]: event.currentTarget.value });
|
|
}
|
|
|
|
static async deleteItem(_, button){
|
|
const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId);
|
|
await item.delete();
|
|
}
|
|
|
|
static async setItemQuantity(button, value){
|
|
const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId);
|
|
await item.update({ "system.quantity": Math.max(item.system.quantity + value, 1) });
|
|
}
|
|
|
|
static async useFeature(_, button) {
|
|
const item = await fromUuid(button.dataset.id);
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
type: 'abilityUse',
|
|
user: game.user.id,
|
|
content: "systems/daggerheart/templates/chat/ability-use.hbs",
|
|
system: {
|
|
title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"),
|
|
img: item.img,
|
|
name: item.name,
|
|
description: item.system.description,
|
|
actions: item.system.actions,
|
|
},
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
}
|
|
|
|
static async useAbility(_, button) {
|
|
const item = await fromUuid(button.dataset.feature);
|
|
const type = button.dataset.type
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
type: 'abilityUse',
|
|
user: game.user.id,
|
|
system: {
|
|
title: type === 'ancestry' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.AncestryTitle") :
|
|
type === 'community' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.CommunityTitle") :
|
|
game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"),
|
|
img: item.img,
|
|
name: item.name,
|
|
description: item.system.description,
|
|
actions: [],
|
|
},
|
|
content: "systems/daggerheart/templates/chat/ability-use.hbs",
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
}
|
|
|
|
static async useAdvancementCard(_, button){
|
|
const item = button.dataset.multiclass === 'true' ? this.document.system.multiclassSubclass : this.document.system.subclass;
|
|
const ability = item.system[`${button.dataset.key}Feature`];
|
|
const title = `${item.name} - ${game.i18n.localize(`DAGGERHEART.Sheets.PC.DomainCard.${capitalize(button.dataset.key)}Title`)}`;
|
|
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
user: game.user.id,
|
|
content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", {
|
|
title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"),
|
|
card: { name: title, img: item.img, description: ability.description },
|
|
}),
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
}
|
|
|
|
static async useAdvancementAbility(_, button){
|
|
// const item = await fromUuid(button.dataset.id);
|
|
const item = this.document.items.find(x => x.uuid === button.dataset.id);
|
|
|
|
const cls = getDocumentClass("ChatMessage");
|
|
const msg = new cls({
|
|
user: game.user.id,
|
|
content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", {
|
|
title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"),
|
|
card: { name: item.name, img: item.img, description: item.system.description },
|
|
}),
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
}
|
|
|
|
static async selectFeatureSet(_, button){
|
|
const multiclass = button.dataset.multiclass === 'true';
|
|
this.multiclassFeatureSetSelected = multiclass;
|
|
this.render();
|
|
}
|
|
|
|
static async close(options){
|
|
this.onVaultTab = false;
|
|
super.close(options);
|
|
}
|
|
|
|
async _onDragStart(_, event){
|
|
if(event.currentTarget.classList.contains('inventory-item')){
|
|
if(!['weapon', 'armor'].includes(event.currentTarget.dataset.type)){
|
|
return;
|
|
}
|
|
|
|
const targets = {
|
|
'weapon': ['weapon-section', 'inventory-weapon-section'],
|
|
'armor': ['armor-section', 'inventory-armor-section'],
|
|
};
|
|
|
|
event.dataTransfer.setData("text/plain", JSON.stringify({ uuid: event.currentTarget.dataset.item, internal: true, targets: targets[event.currentTarget.dataset.type] }));
|
|
}
|
|
|
|
super._onDragStart(event);
|
|
}
|
|
|
|
async _onDrop(event){
|
|
const itemData = event.dataTransfer?.getData('text/plain');
|
|
const item = itemData ? JSON.parse(itemData) : null;
|
|
if (item?.internal){
|
|
let target = null;
|
|
event.currentTarget.classList.forEach(x => {
|
|
if(item.targets.some(target => target === x)){
|
|
target = x;
|
|
}
|
|
});
|
|
if(target){
|
|
const itemObject = await fromUuid(item.uuid);
|
|
switch(target){
|
|
case 'weapon-section':
|
|
if(itemObject.system.secondary && this.document.system.activeWeapons.burden === 'twoHanded'){
|
|
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded"));
|
|
return;
|
|
}
|
|
else if(itemObject.system.burden === 'twoHanded' && this.document.system.activeWeapons.secondary){
|
|
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary"));
|
|
return;
|
|
}
|
|
|
|
const existingWeapon = this.document.items.find(x => x.system.active && x.system.secondary === itemObject.system.secondary);
|
|
await existingWeapon?.update({ "system.active": false });
|
|
await itemObject.update({ "system.active": true });
|
|
break;
|
|
case 'armor-section':
|
|
const existingArmor = this.document.items.find(x => x.type === 'armor' && x.system.active);
|
|
await existingArmor?.update({ "system.active": false });
|
|
await itemObject.update({ "system.active": true });
|
|
break;
|
|
case 'inventory-weapon-section':
|
|
const existingInventoryWeapon = this.document.items.find(x => x.system.inventoryWeapon);
|
|
await existingInventoryWeapon?.update({ "system.inventoryWeapon": false });
|
|
await itemObject.update({ "system.inventoryWeapon": true });
|
|
break;
|
|
case 'inventory-armor-section':
|
|
const existingInventoryArmor = this.document.items.find(x => x.system.inventoryArmor);
|
|
await existingInventoryArmor?.update({ "system.inventoryArmor": false });
|
|
await itemObject.update({ "system.inventoryArmor": true });
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
super._onDrop(event);
|
|
this._onDropItem(event, TextEditor.getDragEventData(event));
|
|
}
|
|
}
|
|
|
|
async _onDropItem(event, data){
|
|
if(this.dropItemBlock){
|
|
return;
|
|
}
|
|
else {
|
|
this.dropItemBlock = true;
|
|
setTimeout(() => this.dropItemBlock = false, 500);
|
|
}
|
|
|
|
const element = event.currentTarget;
|
|
const item = await Item.implementation.fromDropData(data);
|
|
const itemData = item.toObject();
|
|
|
|
const createdItems = [];
|
|
|
|
if(item.type === 'domainCard'){
|
|
if(!this.document.system.class)
|
|
{
|
|
ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.NoClassSelected"));
|
|
return;
|
|
}
|
|
|
|
if(!this.document.system.domains.find(x => x === item.system.domain)){
|
|
ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.LacksDomain"));
|
|
return;
|
|
}
|
|
|
|
if(this.document.system.domainCards.total.length === this.document.system.domainData.maxCards){
|
|
ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.MaxLoadoutReached"));
|
|
return;
|
|
}
|
|
|
|
if(this.document.system.domainCards.total.find(x => x.name === item.name)){
|
|
ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.DuplicateDomainCard"));
|
|
return;
|
|
}
|
|
|
|
if(this.document.system.domainCards.loadout.length >= this.document.system.domainData.maxLoadout){
|
|
itemData.system.inVault = true;
|
|
}
|
|
|
|
if ( this.document.uuid === item.parent?.uuid ) return this._onSortItem(event, itemData);
|
|
const createdItem = await this._onDropItemCreate(itemData);
|
|
|
|
return createdItem;
|
|
}
|
|
else {
|
|
if(!item.system.multiclass && ['class', 'subclass', 'ancestry', 'community'].includes(item.type)){
|
|
const existing = this.document.items.find(x => x.type === item.type);
|
|
await existing?.delete();
|
|
}
|
|
|
|
if(item.type === 'subclass'){
|
|
if(!item.system.multiclass){
|
|
if(!this.document.system.class){
|
|
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SelectClassBeforeSubclass"));
|
|
return;
|
|
}
|
|
else if(!this.document.system.class.system.subclasses.some(x => x.uuid === item.uuid)){
|
|
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SubclassNotOfClass"));
|
|
return;
|
|
}
|
|
|
|
for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.subclass.id)){
|
|
await feature.delete();
|
|
}
|
|
}
|
|
|
|
const features = [itemData.system.foundationFeature, itemData.system.specializationFeature, itemData.system.masteryFeature];
|
|
for(var i = 0; i < features.length; i++){
|
|
const feature = features[i];
|
|
for(var ability of feature.abilities){
|
|
const data = (await fromUuid(ability.uuid)).toObject();
|
|
if(i > 0 ) data.system.disabled = true;
|
|
data.uuid = itemData.uuid;
|
|
|
|
const abilityData = await this._onDropItemCreate(data);
|
|
ability.uuid = abilityData[0].uuid;
|
|
|
|
createdItems.push(abilityData);
|
|
}
|
|
}
|
|
}
|
|
else if(item.type === 'class'){
|
|
if(!item.system.multiclass){
|
|
for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id)){
|
|
await feature.delete();
|
|
}
|
|
}
|
|
|
|
for(var feature of item.system.features){
|
|
const data = (await fromUuid(feature.uuid)).toObject();
|
|
const itemData = await this._onDropItemCreate(data);
|
|
createdItems.push(itemData);
|
|
}
|
|
}
|
|
else if(item.type === 'ancestry'){
|
|
for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){
|
|
await feature.delete();
|
|
}
|
|
|
|
for(var feature of item.system.abilities){
|
|
const data = (await fromUuid(feature.uuid)).toObject();
|
|
const itemData = await this._onDropItemCreate(data);
|
|
createdItems.push(itemData);
|
|
}
|
|
}
|
|
else if(item.type === 'community'){
|
|
for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.community.id)){
|
|
await feature.delete();
|
|
}
|
|
|
|
for(var feature of item.system.abilities){
|
|
const data = (await fromUuid(feature.uuid)).toObject();
|
|
const itemData = await this._onDropItemCreate(data);
|
|
createdItems.push(itemData);
|
|
}
|
|
}
|
|
|
|
if ( this.document.uuid === item.parent?.uuid ) return this._onSortItem(event, item);
|
|
|
|
if(item.type === 'weapon'){
|
|
if(!element) return;
|
|
|
|
if(element.classList.contains('weapon-section')){
|
|
if(item.system.secondary && this.document.system.activeWeapons.burden === 'twoHanded'){
|
|
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded"));
|
|
return;
|
|
}
|
|
else if(item.system.burden === 'twoHanded' && this.document.system.activeWeapons.secondary){
|
|
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary"));
|
|
return;
|
|
}
|
|
|
|
const existing = this.document.system.activeWeapons.primary && !item.system.secondary ? await fromUuid(this.document.system.activeWeapons.primary.uuid) :
|
|
this.document.system.activeWeapons.secondary && item.system.secondary ? await fromUuid(this.document.system.activeWeapons.secondary.uuid) : null;
|
|
await existing?.delete();
|
|
itemData.system.active = true;
|
|
}
|
|
else if(element.classList.contains('inventory-weapon-section-first')){
|
|
const existing = this.document.system.inventoryWeapons.first ? await fromUuid(this.document.system.inventoryWeapons.first.uuid) : null;
|
|
await existing?.delete();
|
|
|
|
itemData.system.inventoryWeapon = 1;
|
|
}
|
|
else if(element.classList.contains('inventory-weapon-section-second')){
|
|
const existing = this.document.system.inventoryWeapons.second ? await fromUuid(this.document.system.inventoryWeapons.second.uuid) : null;
|
|
await existing?.delete();
|
|
|
|
itemData.system.inventoryWeapon = 2;
|
|
}
|
|
else return [];
|
|
}
|
|
|
|
if(item.type === 'armor'){
|
|
if(!element) return;
|
|
|
|
if(element.classList.contains('armor-section')){
|
|
const existing = this.document.system.armor ? await fromUuid(this.document.system.armor.uuid) : null;
|
|
await existing?.delete();
|
|
}
|
|
|
|
else return;
|
|
}
|
|
|
|
const createdItem = await this._onDropItemCreate(itemData);
|
|
createdItems.push(createdItem);
|
|
|
|
return createdItems;
|
|
}
|
|
}
|
|
|
|
async _onDropItemCreate(itemData, event) {
|
|
itemData = itemData instanceof Array ? itemData : [itemData];
|
|
return this.document.createEmbeddedDocuments("Item", itemData);
|
|
}
|
|
|
|
async emulateItemDrop(data) {
|
|
const event = new DragEvent("drop", { altKey: game.keyboard.isModifierActive("Alt") });
|
|
return this._onDropItem(event, data);
|
|
}
|
|
}
|
|
|
|
// export default class PCSheet extends DhpApplicationMixin(ActorSheet) {
|
|
// static applicationType = "sheets/pc";
|
|
// static documentType = "pc";
|
|
|
|
// constructor(actor, options){
|
|
// super(actor, options);
|
|
|
|
// this.editAttributes = false;
|
|
// this.onVaultTab = false;
|
|
// this.currentInventoryPage = 0;
|
|
// this.selectedScar = null;
|
|
// this.storyEditor = null;
|
|
// this.dropItemBlock = false;
|
|
// this.multiclassFeatureSetSelected = false;
|
|
// }
|
|
|
|
// /** @override */
|
|
// static get defaultOptions() {
|
|
// return foundry.utils.mergeObject(super.defaultOptions, {
|
|
// classes: ["daggerheart", "sheet", "pc"],
|
|
// width: 810,
|
|
// height: 1080,
|
|
// resizable: false,
|
|
// tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "features" }, { navSelector: ".loadout-tabs", contentSelector: ".loadout-body", initial: "loadout"}],
|
|
// dragDrop: [
|
|
// {dragSelector: null, dropSelector: ".weapon-section" },
|
|
// {dragSelector: null, dropSelector: ".armor-section"},
|
|
// {dragSelector: null, dropSelector: ".inventory-weapon-section-first"},
|
|
// {dragSelector: null, dropSelector: ".inventory-weapon-section-second"},
|
|
// {dragSelector: ".item-list .item", dropSelector: null},
|
|
// ]
|
|
// }, { overwrite: true, inplace: true });
|
|
// }
|
|
|
|
// async mapFeatureType(data, configType){
|
|
// return await Promise.all(data.map(async x => {
|
|
// const abilities = x.system.abilities ? await Promise.all(x.system.abilities.map(async x => await fromUuid(x.uuid))) : [];
|
|
|
|
// return {
|
|
// ...x,
|
|
// uuid: x.uuid,
|
|
// system: {
|
|
// ...x.system,
|
|
// abilities: abilities,
|
|
// type: game.i18n.localize(configType[x.system.type??x.type].label)
|
|
// }
|
|
// }
|
|
// }));
|
|
// }
|
|
|
|
// mapAdvancementFeatures(actor, config) {
|
|
// if(!actor.system.subclass) return { foundation: null, advancements: [] };
|
|
|
|
// const { subclass, multiclassSubclass } = actor.system.subclassFeatures;
|
|
|
|
// const foundation = {
|
|
// type: 'foundation',
|
|
// multiclass: false,
|
|
// img: actor.system.subclass.img,
|
|
// subtitle: game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"),
|
|
// domains: actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src),
|
|
// className: actor.system.class.name,
|
|
// subclassUuid: actor.system.subclass.uuid,
|
|
// subclassName: actor.system.subclass.name,
|
|
// spellcast: config.ACTOR.abilities[actor.system.subclass.system.spellcastingTrait]?.name ?? null,
|
|
// description: actor.system.subclass.system.foundationFeature.description,
|
|
// abilities: subclass.foundation,
|
|
// abilityKey: 'foundationFeature',
|
|
// };
|
|
|
|
// const firstKey = actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 2 ? 'sub' :
|
|
// actor.system.multiclass?.system?.multiclassTier === 2 ? 'multi' : null;
|
|
// const firstType = firstKey === 'sub' ? 'specialization' : 'foundation';
|
|
// const firstBase = firstKey === 'sub' ? actor.system.subclass : firstKey === 'multi' ? actor.system.multiclassSubclass : null;
|
|
// const first = !firstBase ? null : {
|
|
// type: firstType,
|
|
// multiclass: firstKey === 'multi',
|
|
// img: firstBase.img,
|
|
// subtitle: firstKey === 'sub' ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"),
|
|
// domains: firstKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src),
|
|
// className: firstKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name,
|
|
// subclassUuid: firstBase.uuid,
|
|
// subclassName: firstBase.name,
|
|
// spellcast: firstKey === 'sub' ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null,
|
|
// description: firstKey === 'sub' ? firstBase.system.specializationFeature.description : firstBase.system.foundationFeature.description,
|
|
// abilities: firstKey === 'sub' ? subclass.specialization : multiclassSubclass.foundation,
|
|
// abilityKey: firstKey === 'sub' ? 'specializationFeature' : 'foundationFeature',
|
|
// };
|
|
|
|
// const secondKey = (actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 3) || (actor.system.subclass.system.masteryFeature.unlocked && actor.system.subclass.system.masteryFeature.tier === 3) ? 'sub' :
|
|
// (actor.system.multiclass?.system?.multiclassTier === 3) || (actor.system.multiclassSubclass?.system?.specializationFeature?.unlocked) ? 'multi' : null;
|
|
// const secondBase = secondKey === 'sub' ? actor.system.subclass : secondKey === 'multi' ? actor.system.multiclassSubclass : null;
|
|
// const secondAbilities = secondKey === 'sub' ? subclass : multiclassSubclass;
|
|
// const secondType = secondBase ? secondBase.system.masteryFeature.unlocked ? 'mastery' : secondBase.system.specializationFeature.unlocked ? 'specialization' : 'foundation' : null;
|
|
// const second = !secondBase ? null : {
|
|
// type: secondType,
|
|
// multiclass: secondKey === 'multi',
|
|
// img: secondBase.img,
|
|
// subtitle: secondBase.system.masteryFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.MasteryTitle") :
|
|
// secondBase.system.specializationFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"),
|
|
// domains: secondKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src),
|
|
// className: secondKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name,
|
|
// subclassUuid: secondBase.uuid,
|
|
// subclassName: secondBase.name,
|
|
// spellcast: secondKey === 'sub' || secondBase.system.specializationFeature.unlocked ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null,
|
|
// description:
|
|
// secondBase.system.masteryFeature.unlocked ? secondBase.system.masteryFeature.description :
|
|
// secondBase.system.specializationFeature.unlocked ? secondBase.system.specializationFeature.description : firstBase.system.foundationFeature.description,
|
|
// abilities:
|
|
// secondBase.system.masteryFeature.unlocked ? secondAbilities.mastery :
|
|
// secondBase.system.specializationFeature.unlocked ? secondAbilities.specialization : secondAbilities.foundation,
|
|
// abilityKey: secondBase.system.masteryFeature.unlocked ? 'masteryFeature' : secondBase.system.specializationFeature.unlocked ? 'specializationFeature' : 'foundationFeature',
|
|
// };
|
|
|
|
// return {
|
|
// foundation: foundation,
|
|
// first: first,
|
|
// second: second,
|
|
// }
|
|
// }
|
|
|
|
// /** @override */
|
|
// async getData() {
|
|
// const context = super.getData();
|
|
// context.config = SYSTEM;
|
|
// context.editAttributes = this.editAttributes;
|
|
// context.onVaultTab = this.onVaultTab;
|
|
// context.selectedScar = this.selectedScar;
|
|
// context.storyEditor = this.storyEditor;
|
|
// context.multiclassFeatureSetSelected = this.multiclassFeatureSetSelected;
|
|
|
|
// const selectedAttributes = Object.values(this.actor.system.attributes).map(x => x.data.base);
|
|
// context.abilityScoreArray = JSON.parse(await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray)).reduce((acc, x) => {
|
|
// const selectedIndex = selectedAttributes.indexOf(x);
|
|
// if(selectedIndex !== -1){
|
|
// selectedAttributes.splice(selectedIndex, 1);
|
|
// } else {
|
|
// acc.push({ name: x, value: x });
|
|
// }
|
|
|
|
// return acc;
|
|
// }, []);
|
|
// if(!context.abilityScoreArray.includes(0)) context.abilityScoreArray.push({ name: 0, value: 0 });
|
|
// context.abilityScoresFinished = context.abilityScoreArray.every(x => x.value === 0);
|
|
|
|
// context.domains = this.actor.system.class ? {
|
|
// first: this.actor.system.class.system.domains[0] ? SYSTEM.DOMAIN.domains[this.actor.system.class.system.domains[0]].src : null,
|
|
// second: this.actor.system.class.system.domains[1] ? SYSTEM.DOMAIN.domains[this.actor.system.class.system.domains[1]].src : null,
|
|
// } : { };
|
|
|
|
// context.attributes = Object.keys(this.actor.system.attributes).reduce((acc, key) => {
|
|
// acc[key] = {
|
|
// ...this.actor.system.attributes[key],
|
|
// name: game.i18n.localize(SYSTEM.ACTOR.abilities[key].name),
|
|
// verbs: SYSTEM.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)),
|
|
// };
|
|
|
|
// return acc;
|
|
// }, {});
|
|
|
|
// const ancestry = await this.mapFeatureType(this.actor.system.ancestry ? [this.actor.system.ancestry] : [], SYSTEM.GENERAL.objectTypes);
|
|
// const community = await this.mapFeatureType(this.actor.system.community ? [this.actor.system.community] : [], SYSTEM.GENERAL.objectTypes);
|
|
// const foundation = {
|
|
// ancestry: ancestry[0],
|
|
// community: community[0],
|
|
// advancement: {
|
|
// ...this.mapAdvancementFeatures(this.actor, SYSTEM)
|
|
// }
|
|
// };
|
|
|
|
// const nrLoadoutCards = this.actor.system.domainCards.loadout.length;
|
|
// const loadout = await this.mapFeatureType(this.actor.system.domainCards.loadout, SYSTEM.DOMAIN.cardTypes);
|
|
// const vault = await this.mapFeatureType(this.actor.system.domainCards.vault, SYSTEM.DOMAIN.cardTypes);
|
|
// context.abilities = {
|
|
// foundation: foundation,
|
|
// loadout: {
|
|
// top: loadout.slice(0, Math.min(2, nrLoadoutCards)),
|
|
// bottom: nrLoadoutCards > 2 ? loadout.slice(2, Math.min(5, nrLoadoutCards)) : [],
|
|
// nrTotal: nrLoadoutCards,
|
|
// },
|
|
// vault: vault.map(x => ({ ...x, uuid: x.uuid, sendToLoadoutDisabled: this.actor.system.domainCards.loadout.length >= this.actor.system.domainData.maxLoadout }))
|
|
// };
|
|
|
|
// context.inventory = {
|
|
// consumable: {
|
|
// titles: {
|
|
// name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.ConsumableTitle"),
|
|
// quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"),
|
|
// },
|
|
// items: this.actor.items.filter(x => x.type === 'consumable'),
|
|
// },
|
|
// miscellaneous: {
|
|
// titles: {
|
|
// name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.MiscellaneousTitle"),
|
|
// quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"),
|
|
// },
|
|
// items: this.actor.items.filter(x => x.type === 'miscellaneous'),
|
|
// },
|
|
// }
|
|
|
|
// if(context.inventory.length === 0){
|
|
// context.inventory = Array(1).fill(Array(5).fill([]));
|
|
// }
|
|
|
|
// context.classFeatures = (this.multiclassFeatureSetSelected ? this.actor.system.multiclassFeatures : this.actor.system.classFeatures).map(x => {
|
|
// if(x.system.featureType.type !== 'dice'){
|
|
// return x;
|
|
// }
|
|
|
|
// return { ...x, uuid: x.uuid, system: { ...x.system, featureType: { ...x.system.featureType, data: { ...x.system.featureType.data, property: this.actor.system.subclass ? SYSTEM.ACTOR.featureProperties[x.system.featureType.data.property].path(this.actor) : 0 }}}};
|
|
// });
|
|
|
|
// return context;
|
|
// }
|
|
|
|
// activateListeners(html) {
|
|
// super.activateListeners(html);
|
|
|
|
// html.find(".attribute-value").on("change", this.attributeChange.bind(this));
|
|
// html.on('click', '.tab-selector', this.tabSwitch.bind(this));
|
|
// html.on('click', '.level-title.levelup', this.openLevelUp.bind(this));
|
|
// html.find(".feature-input").on("change", this.onFeatureInputBlur.bind(this));
|
|
// html.find(".experience-description").on("change", this.experienceDescriptionChange.bind(this));
|
|
// html.find(".experience-value").on("change", this.experienceValueChange.bind(this));
|
|
// html.on("change", "[data-item]", this.itemUpdate.bind(this));
|
|
// }
|
|
|
|
// async _handleAction(action, event, button) {
|
|
// switch(action){
|
|
// case 'toggleEditAttributes':
|
|
// this.toggleEditAttributes();
|
|
// break;
|
|
// case 'attributeRoll':
|
|
// await this.rollAttribute(event);
|
|
// break;
|
|
// case 'toggleMarks':
|
|
// await this.toggleMarks(button);
|
|
// break;
|
|
// case 'toggleAttributeMark':
|
|
// await this.toggleAttributeMark(button);
|
|
// break;
|
|
// case 'toggleHP':
|
|
// await this.toggleHP(button);
|
|
// break;
|
|
// case 'toggleStress':
|
|
// await this.toggleStress(button);
|
|
// break;
|
|
// case 'toggleHope':
|
|
// await this.toggleHope(button);
|
|
// break;
|
|
// case 'toggleGold':
|
|
// await this.toggleGold(button);
|
|
// break;
|
|
// case 'attackRoll':
|
|
// await this.attackRoll(event);
|
|
// break;
|
|
// case 'tabToLoadout':
|
|
// this.domainCardsTab(false);
|
|
// break;
|
|
// case 'tabToVault':
|
|
// this.domainCardsTab(true);
|
|
// break;
|
|
// case 'sendToVault':
|
|
// await this.moveDomainCard(button, true);
|
|
// break;
|
|
// case 'sendToLoadout':
|
|
// await this.moveDomainCard(button, false);
|
|
// break;
|
|
// case 'useDomainCard':
|
|
// await this.useDomainCard(button);
|
|
// break;
|
|
// case 'selectClass':
|
|
// await this.selectClass();
|
|
// break;
|
|
// case 'selectSubclass':
|
|
// await this.selectSubclass();
|
|
// break;
|
|
// case 'selectAncestry':
|
|
// await this.selectAncestry();
|
|
// break;
|
|
// case 'selectCommunity':
|
|
// await this.selectCommunity();
|
|
// break;
|
|
// case 'viewObject':
|
|
// await this.viewObject(button);
|
|
// break;
|
|
// case 'useFeature':
|
|
// await this.useFeature(button);
|
|
// break;
|
|
// case 'takeShortRest':
|
|
// await this.takeShortRest();
|
|
// break;
|
|
// case 'takeLongRest':
|
|
// await this.takeLongRest();
|
|
// break;
|
|
// case 'removeActiveItem':
|
|
// await this.removeActiveItem(event);
|
|
// break;
|
|
// case 'removeInventoryWeapon':
|
|
// await this.removeInventoryWeapon(event);
|
|
// break;
|
|
// case 'addMiscItem':
|
|
// await this.addMiscItem();
|
|
// break;
|
|
// case 'deleteItem':
|
|
// await this.deleteItem(button);
|
|
// break;
|
|
// case 'addScar':
|
|
// await this.addScar();
|
|
// break;
|
|
// case 'selectScar':
|
|
// await this.selectScar(button);
|
|
// break;
|
|
// case 'deleteScar':
|
|
// await this.deleteScar(event);
|
|
// break;
|
|
// case 'makeDeathMove':
|
|
// await this.makeDeathMove();
|
|
// break;
|
|
// case 'toggleFeatureDice':
|
|
// await this.toggleFeatureDice(button);
|
|
// break;
|
|
// case 'setStoryEditor':
|
|
// this.setStoryEditor(button);
|
|
// break;
|
|
// case 'itemQuantityDecrease':
|
|
// await this.setItemQuantity(button, -1);
|
|
// break;
|
|
// case 'itemQuantityIncrease':
|
|
// await this.setItemQuantity(button, 1);
|
|
// break;
|
|
// case 'useAbility':
|
|
// await this.useAbility(button);
|
|
// break;
|
|
// case 'useAdvancementCard':
|
|
// await this.useAdvancementCard(button);
|
|
// break;
|
|
// case 'useAdvancementAbility':
|
|
// await this.useAdvancementAbility(button);
|
|
// break;
|
|
// case 'selectFeatureSet':
|
|
// await this.selectFeatureSet(button);
|
|
// break;
|
|
// }
|
|
// }
|
|
|
|
// async attributeChange(event){
|
|
// const path = `system.attributes.${event.currentTarget.dataset.attribute}.data.base`;
|
|
// await this.actor.update({ [path]: event.currentTarget.value });
|
|
// }
|
|
|
|
// toggleEditAttributes(){
|
|
// this.editAttributes = !this.editAttributes;
|
|
// this.render();
|
|
// }
|
|
|
|
// async rollAttribute(event){
|
|
// const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.actor.dualityRoll({ title: 'Attribute Bonus', value: event.currentTarget.dataset.value }, event.shiftKey);
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// type: 'dualityRoll',
|
|
// system: {
|
|
// roll: roll._formula,
|
|
// modifiers: modifiers,
|
|
// hope: hope,
|
|
// fear: fear,
|
|
// advantage: advantage,
|
|
// disadvantage: disadvantage,
|
|
// },
|
|
// user: game.user.id,
|
|
// content: "systems/daggerheart/templates/chat/duality-roll.hbs",
|
|
// rolls: [roll]
|
|
// });
|
|
|
|
// await cls.create(msg.toObject());
|
|
// }
|
|
|
|
// async toggleMarks(button){
|
|
// const markValue = Number.parseInt(button.dataset.value);
|
|
// const newValue = this.actor.system.armor.system.marks.value >= markValue ? markValue-1 : markValue;
|
|
// await this.actor.system.armor.update({ 'system.marks.value': newValue });
|
|
// }
|
|
|
|
// async toggleAttributeMark(button){
|
|
// const attribute = this.actor.system.attributes[button.dataset.attribute];
|
|
// const newMark = this.actor.system.availableAttributeMarks.filter(x => x > Math.max.apply(null, this.actor.system.attributes[button.dataset.attribute].levelMarks)).sort((a, b) => a > b ? 1 : -1)[0];
|
|
|
|
// if(attribute.levelMark || !newMark) return;
|
|
|
|
|
|
// const path = `system.attributes.${button.dataset.attribute}.levelMarks`;
|
|
// await this.actor.update({ [path]: [...attribute.levelMarks, newMark] });
|
|
// }
|
|
|
|
// async toggleHP(button){
|
|
// const healthValue = Number.parseInt(button.dataset.value);
|
|
// const newValue = this.actor.system.resources.health.value >= healthValue ? healthValue-1 : healthValue;
|
|
// await this.actor.update({ 'system.resources.health.value': newValue });
|
|
// }
|
|
|
|
// async toggleStress(button){
|
|
// const healthValue = Number.parseInt(button.dataset.value);
|
|
// const newValue = this.actor.system.resources.stress.value >= healthValue ? healthValue-1 : healthValue;
|
|
// await this.actor.update({ 'system.resources.stress.value': newValue });
|
|
// }
|
|
|
|
// async toggleHope(button){
|
|
// const hopeValue = Number.parseInt(button.dataset.value);
|
|
// const newValue = this.actor.system.resources.hope.value >= hopeValue ? hopeValue-1 : hopeValue;
|
|
// await this.actor.update({ 'system.resources.hope.value': newValue });
|
|
// }
|
|
|
|
// async toggleGold(button){
|
|
// const goldValue = Number.parseInt(button.dataset.value);
|
|
// const goldType = button.dataset.type;
|
|
// const newValue = this.actor.system.gold[goldType] >= goldValue ? goldValue-1 : goldValue;
|
|
|
|
// const update = `system.gold.${goldType}`;
|
|
// await this.actor.update({ [update]: newValue });
|
|
// }
|
|
|
|
// async attackRoll(event){
|
|
// const weapon = await fromUuid(event.currentTarget.dataset.weapon);
|
|
// const damage = {
|
|
// value: `${this.actor.system.proficiency.value}${weapon.system.damage.value}`,
|
|
// type: weapon.system.damage.type,
|
|
// bonusDamage: this.actor.system.bonuses.damage
|
|
// };
|
|
// const modifier = this.actor.system.attributes[weapon.system.trait].data.value;
|
|
|
|
// const { roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString } = await this.actor.dualityRoll({ title: 'Attribute Modifier', value: modifier }, event.shiftKey, damage.bonusDamage);
|
|
|
|
// damage.value = damage.value.concat(bonusDamageString);
|
|
|
|
// const targets = Array.from(game.user.targets).map(x => ({
|
|
// id: x.id,
|
|
// name: x.actor.name,
|
|
// img: x.actor.img,
|
|
// difficulty: x.actor.system.difficulty,
|
|
// evasion: x.actor.system.evasion,
|
|
// }));
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// type: 'dualityRoll',
|
|
// system: {
|
|
// roll: roll._formula,
|
|
// modifiers: modifiers,
|
|
// hope: hope,
|
|
// fear: fear,
|
|
// advantage: advantage,
|
|
// disadvantage: disadvantage,
|
|
// damage: damage,
|
|
// targets: targets,
|
|
// },
|
|
// content: "systems/daggerheart/templates/chat/attack-roll.hbs",
|
|
// rolls: [roll]
|
|
// });
|
|
|
|
// await cls.create(msg.toObject());
|
|
// }
|
|
|
|
// tabSwitch(event){
|
|
// const tab = event.currentTarget.dataset.tab;
|
|
// if(tab !== 'loadout'){
|
|
// this.onVaultTab = false;
|
|
// }
|
|
|
|
// this.render();
|
|
// }
|
|
|
|
// openLevelUp(event){
|
|
// new DhpLevelup(this.actor).render(true);
|
|
// }
|
|
|
|
// domainCardsTab(toVault){
|
|
// this.onVaultTab = toVault;
|
|
// this.render();
|
|
// }
|
|
|
|
// async moveDomainCard(button, toVault){
|
|
// if(!toVault && this.actor.system.domainCards.loadout.length >= this.actor.system.domainData.maxLoadout){
|
|
// return;
|
|
// }
|
|
|
|
// const card = this.actor.items.find(x => x.uuid === button.dataset.domain);
|
|
// await card.update({ "system.inVault": toVault });
|
|
// }
|
|
|
|
// async useDomainCard(button){
|
|
// const card = this.actor.items.find(x => x.uuid === button.dataset.key);
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// type: 'abilityUse',
|
|
// user: game.user.id,
|
|
// content: "systems/daggerheart/templates/chat/ability-use.hbs",
|
|
// system: {
|
|
// title: `${game.i18n.localize("DAGGERHEART.Chat.DomainCard.Title")} - ${capitalize(button.dataset.domain)}`,
|
|
// img: card.img,
|
|
// name: card.name,
|
|
// description: card.system.effect,
|
|
// actions: card.system.actions,
|
|
// },
|
|
// });
|
|
|
|
// cls.create(msg.toObject());
|
|
// }
|
|
|
|
// async selectClass(){
|
|
// (await game.packs.get('daggerheart.playtest-classes'))?.render(true);
|
|
// }
|
|
|
|
// async selectSubclass(){
|
|
// (await game.packs.get('daggerheart.playtest-subclasses'))?.render(true);
|
|
// }
|
|
|
|
// async selectAncestry(){
|
|
// const dialogClosed = new Promise((resolve, _) => {
|
|
// new AncestrySelectionDialog(resolve).render(true);
|
|
// });
|
|
// const result = await dialogClosed;
|
|
|
|
// // await this.emulateItemDrop({ type: 'item', data: result });
|
|
// for(var ancestry of this.actor.items.filter(x => x => x.type === 'ancestry')){
|
|
// await ancestry.delete();
|
|
// }
|
|
|
|
// const createdItems = [];
|
|
// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){
|
|
// await feature.delete();
|
|
// }
|
|
|
|
// // createdItems.push(...result.data.system.abilities);
|
|
// createdItems.push(result.data);
|
|
|
|
|
|
// await this.actor.createEmbeddedDocuments('Item', createdItems);
|
|
|
|
// // await this.actor.createEmbeddedDocuments("Item", [result.toObject()]);
|
|
// // (await game.packs.get('daggerheart.playtest-ancestries'))?.render(true);
|
|
// }
|
|
|
|
// async selectCommunity(){
|
|
// (await game.packs.get('daggerheart.playtest-communities'))?.render(true);;
|
|
// }
|
|
|
|
// async viewObject(button){
|
|
// const object = await fromUuid(button.dataset.value);
|
|
// if(!object) return;
|
|
|
|
// const tab = button.dataset.tab;
|
|
// if(tab) object.sheet._tabs[0].active = tab;
|
|
|
|
// if(object.sheet.editMode) object.sheet.editMode = false;
|
|
|
|
// object.sheet.render(true);
|
|
// }
|
|
|
|
// async takeShortRest(){
|
|
// await new DhpDowntime(this.actor, true).render(true);
|
|
// await this.minimize();
|
|
// }
|
|
|
|
// async takeLongRest(){
|
|
// await new DhpDowntime(this.actor, false).render(true);
|
|
// await this.minimize();
|
|
// }
|
|
|
|
// async removeActiveItem(event){
|
|
// event.stopPropagation();
|
|
// const item = await fromUuid(event.currentTarget.dataset.item);
|
|
// await item.delete();
|
|
// }
|
|
|
|
// async removeInventoryWeapon(event){
|
|
// event.stopPropagation();
|
|
// const item = await fromUuid(event.currentTarget.dataset.item);
|
|
// await item.delete();
|
|
// }
|
|
|
|
// async addMiscItem(){
|
|
// const result = await this.actor.createEmbeddedDocuments("Item", [{
|
|
// name: game.i18n.localize('DAGGERHEART.Sheets.PC.NewItem'),
|
|
// type: 'miscellaneous'
|
|
// }]);
|
|
|
|
// await result[0].sheet.render(true);
|
|
// }
|
|
|
|
// async addScar(){
|
|
// if(this.actor.system.story.scars.length === 5) return;
|
|
|
|
// await this.actor.update({ "system.story.scars": [...this.actor.system.story.scars, { name: game.i18n.localize("DAGGERHEART.Sheets.PC.NewScar"), description: '' }] });
|
|
// }
|
|
|
|
// async selectScar(button){
|
|
// this.selectedScar = Number.parseInt(button.dataset.value);
|
|
// this.render();
|
|
// }
|
|
|
|
// async deleteScar(event) {
|
|
// event.stopPropagation();
|
|
// await this.actor.update({ "system.story.scars": this.actor.system.story.scars.filter((_, index) => index !== Number.parseInt(event.currentTarget.dataset.scar) ) })
|
|
// }
|
|
|
|
// async makeDeathMove() {
|
|
// if(this.actor.system.resources.health.value === this.actor.system.resources.health.max){
|
|
// await new DhpDeathMove(this.actor).render(true);
|
|
// await this.minimize();
|
|
// }
|
|
// }
|
|
|
|
// async toggleFeatureDice(button){
|
|
// const index = Number.parseInt(button.dataset.index);
|
|
// const feature = this.actor.system.classFeatures.find(x => x.uuid === button.dataset.feature);
|
|
// const path = `system.featureType.data.numbers.${index}`;
|
|
// if(feature.system.featureType.data.numbers[index]?.used) return;
|
|
|
|
// if(Object.keys(feature.system.featureType.data.numbers).length <= index) {
|
|
// const roll = new Roll(feature.system.featureType.data.value);
|
|
// const rollData = await roll.evaluate();
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// user: game.user.id,
|
|
// rolls: [roll]
|
|
// });
|
|
|
|
// await cls.create(msg.toObject());
|
|
|
|
// await feature.update({ [path]: { value: Number.parseInt(rollData.total), used: false } });
|
|
// } else {
|
|
// await Dialog.confirm({
|
|
// title: game.i18n.localize("Confirm feature use"),
|
|
// content: `Are you sure you want to use ${feature.name}?`,
|
|
// yes: async () => {
|
|
// await feature.update({ [path]: { used: true } });
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// user: game.user.id,
|
|
// content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", {
|
|
// title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"),
|
|
// card: { name: `${feature.name} - Roll Of ${feature.system.featureType.data.numbers[index].value}`, img: feature.img },
|
|
// }),
|
|
// });
|
|
|
|
// cls.create(msg.toObject());
|
|
// },
|
|
// no: () => { return; },
|
|
// defaultYes: false
|
|
// });
|
|
|
|
// }
|
|
// }
|
|
|
|
// async onFeatureInputBlur(event){
|
|
// const feature = this.actor.system.classFeatures.find(x => x.uuid === event.currentTarget.dataset.feature);
|
|
// const value = Number.parseInt(event.currentTarget.value);
|
|
// if(!Number.isNaN(value)) await feature?.update({ "system.featureType.data.value": value });
|
|
// }
|
|
|
|
// async experienceDescriptionChange(event){
|
|
// const newExperiences = [...this.actor.system.experiences];
|
|
// newExperiences[event.currentTarget.dataset.index].description = event.currentTarget.value;
|
|
// await this.actor.update({ "system.experiences": newExperiences });
|
|
// }
|
|
|
|
// async experienceValueChange(event){
|
|
// const newExperiences = [...this.actor.system.experiences];
|
|
// newExperiences[event.currentTarget.dataset.index].value = event.currentTarget.value;
|
|
// await this.actor.update({ "system.experiences": newExperiences });
|
|
// }
|
|
|
|
// setStoryEditor(button) {
|
|
// this.storyEditor = this.storyEditor === button.dataset.value ? null : button.dataset.value;
|
|
// this.render();
|
|
// }
|
|
|
|
// async itemUpdate(event){
|
|
// const name = event.currentTarget.dataset.item;
|
|
// const item = await fromUuid($(event.currentTarget).closest('[data-item-id]')[0].dataset.itemId);
|
|
// await item.update({ [name]: event.currentTarget.value });
|
|
// }
|
|
|
|
// async deleteItem(button){
|
|
// const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId);
|
|
// await item.delete();
|
|
// }
|
|
|
|
// async setItemQuantity(button, value){
|
|
// const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId);
|
|
// await item.update({ "system.quantity": Math.max(item.system.quantity + value, 1) });
|
|
// }
|
|
|
|
// async useFeature(button) {
|
|
// const item = await fromUuid(button.dataset.id);
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// type: 'abilityUse',
|
|
// user: game.user.id,
|
|
// content: "systems/daggerheart/templates/chat/ability-use.hbs",
|
|
// system: {
|
|
// title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"),
|
|
// img: item.img,
|
|
// name: item.name,
|
|
// description: item.system.description,
|
|
// actions: item.system.actions,
|
|
// },
|
|
// });
|
|
|
|
// cls.create(msg.toObject());
|
|
// }
|
|
|
|
// async useAbility(button) {
|
|
// const item = await fromUuid(button.dataset.feature);
|
|
// const type = button.dataset.type
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// type: 'abilityUse',
|
|
// user: game.user.id,
|
|
// system: {
|
|
// title: type === 'ancestry' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.AncestryTitle") :
|
|
// type === 'community' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.CommunityTitle") :
|
|
// game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"),
|
|
// img: item.img,
|
|
// name: item.name,
|
|
// description: item.system.description,
|
|
// actions: [],
|
|
// },
|
|
// content: "systems/daggerheart/templates/chat/ability-use.hbs",
|
|
// });
|
|
|
|
// cls.create(msg.toObject());
|
|
// }
|
|
|
|
// async useAdvancementCard(button){
|
|
// const item = button.dataset.multiclass === 'true' ? this.actor.system.multiclassSubclass : this.actor.system.subclass;
|
|
// const ability = item.system[`${button.dataset.key}Feature`];
|
|
// const title = `${item.name} - ${game.i18n.localize(`DAGGERHEART.Sheets.PC.DomainCard.${capitalize(button.dataset.key)}Title`)}`;
|
|
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// user: game.user.id,
|
|
// content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", {
|
|
// title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"),
|
|
// card: { name: title, img: item.img, description: ability.description },
|
|
// }),
|
|
// });
|
|
|
|
// cls.create(msg.toObject());
|
|
// }
|
|
|
|
// async useAdvancementAbility(button){
|
|
// // const item = await fromUuid(button.dataset.id);
|
|
// const item = this.actor.items.find(x => x.uuid === button.dataset.id);
|
|
|
|
// const cls = getDocumentClass("ChatMessage");
|
|
// const msg = new cls({
|
|
// user: game.user.id,
|
|
// content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", {
|
|
// title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"),
|
|
// card: { name: item.name, img: item.img, description: item.system.description },
|
|
// }),
|
|
// });
|
|
|
|
// cls.create(msg.toObject());
|
|
// }
|
|
|
|
// async selectFeatureSet(button){
|
|
// const multiclass = button.dataset.multiclass === 'true';
|
|
// this.multiclassFeatureSetSelected = multiclass;
|
|
// this.render();
|
|
// }
|
|
|
|
// async close(options){
|
|
// this.onVaultTab = false;
|
|
// super.close(options);
|
|
// }
|
|
|
|
// async _onDragStart(event){
|
|
// if(event.currentTarget.classList.contains('inventory-item')){
|
|
// if(!['weapon', 'armor'].includes(event.currentTarget.dataset.type)){
|
|
// return;
|
|
// }
|
|
|
|
// const targets = {
|
|
// 'weapon': ['weapon-section', 'inventory-weapon-section'],
|
|
// 'armor': ['armor-section', 'inventory-armor-section'],
|
|
// };
|
|
|
|
// event.dataTransfer.setData("text/plain", JSON.stringify({ uuid: event.currentTarget.dataset.item, internal: true, targets: targets[event.currentTarget.dataset.type] }));
|
|
// }
|
|
|
|
// super._onDragStart(event);
|
|
// }
|
|
|
|
// async _onDrop(event){
|
|
// const itemData = event.dataTransfer?.getData('text/plain');
|
|
// const item = itemData ? JSON.parse(itemData) : null;
|
|
// if (item?.internal){
|
|
// let target = null;
|
|
// event.currentTarget.classList.forEach(x => {
|
|
// if(item.targets.some(target => target === x)){
|
|
// target = x;
|
|
// }
|
|
// });
|
|
// if(target){
|
|
// const itemObject = await fromUuid(item.uuid);
|
|
// switch(target){
|
|
// case 'weapon-section':
|
|
// if(itemObject.system.secondary && this.actor.system.activeWeapons.burden === 'twoHanded'){
|
|
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded"));
|
|
// return;
|
|
// }
|
|
// else if(itemObject.system.burden === 'twoHanded' && this.actor.system.activeWeapons.secondary){
|
|
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary"));
|
|
// return;
|
|
// }
|
|
|
|
// const existingWeapon = this.actor.items.find(x => x.system.active && x.system.secondary === itemObject.system.secondary);
|
|
// await existingWeapon?.update({ "system.active": false });
|
|
// await itemObject.update({ "system.active": true });
|
|
// break;
|
|
// case 'armor-section':
|
|
// const existingArmor = this.actor.items.find(x => x.type === 'armor' && x.system.active);
|
|
// await existingArmor?.update({ "system.active": false });
|
|
// await itemObject.update({ "system.active": true });
|
|
// break;
|
|
// case 'inventory-weapon-section':
|
|
// const existingInventoryWeapon = this.actor.items.find(x => x.system.inventoryWeapon);
|
|
// await existingInventoryWeapon?.update({ "system.inventoryWeapon": false });
|
|
// await itemObject.update({ "system.inventoryWeapon": true });
|
|
// break;
|
|
// case 'inventory-armor-section':
|
|
// const existingInventoryArmor = this.actor.items.find(x => x.system.inventoryArmor);
|
|
// await existingInventoryArmor?.update({ "system.inventoryArmor": false });
|
|
// await itemObject.update({ "system.inventoryArmor": true });
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
// else {
|
|
// super._onDrop(event);
|
|
// }
|
|
// }
|
|
|
|
// async _onDropItem(event, data){
|
|
// if(this.dropItemBlock){
|
|
// return;
|
|
// }
|
|
// else {
|
|
// this.dropItemBlock = true;
|
|
// setTimeout(() => this.dropItemBlock = false, 500);
|
|
// }
|
|
|
|
// const element = event.currentTarget;
|
|
// const item = await Item.implementation.fromDropData(data);
|
|
// const itemData = item.toObject();
|
|
|
|
// const createdItems = [];
|
|
|
|
// if(item.type === 'domainCard'){
|
|
// if(!this.actor.system.class)
|
|
// {
|
|
// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.NoClassSelected"));
|
|
// return;
|
|
// }
|
|
|
|
// if(!this.actor.system.domains.find(x => x === item.system.domain)){
|
|
// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.LacksDomain"));
|
|
// return;
|
|
// }
|
|
|
|
// if(this.actor.system.domainCards.total.length === this.actor.system.domainData.maxCards){
|
|
// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.MaxLoadoutReached"));
|
|
// return;
|
|
// }
|
|
|
|
// if(this.actor.system.domainCards.total.find(x => x.name === item.name)){
|
|
// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.DuplicateDomainCard"));
|
|
// return;
|
|
// }
|
|
|
|
// if(this.actor.system.domainCards.loadout.length >= this.actor.system.domainData.maxLoadout){
|
|
// itemData.system.inVault = true;
|
|
// }
|
|
|
|
// if ( this.actor.uuid === item.parent?.uuid ) return this._onSortItem(event, itemData);
|
|
// const createdItem = await this._onDropItemCreate(itemData);
|
|
|
|
// return createdItem;
|
|
// }
|
|
// else {
|
|
// if(!item.system.multiclass && ['class', 'subclass', 'ancestry', 'community'].includes(item.type)){
|
|
// const existing = this.actor.items.find(x => x.type === item.type);
|
|
// await existing?.delete();
|
|
// }
|
|
|
|
// if(item.type === 'subclass'){
|
|
// if(!item.system.multiclass){
|
|
// if(!this.actor.system.class){
|
|
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SelectClassBeforeSubclass"));
|
|
// return;
|
|
// }
|
|
// else if(!this.actor.system.class.system.subclasses.some(x => x.uuid === item.uuid)){
|
|
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SubclassNotOfClass"));
|
|
// return;
|
|
// }
|
|
|
|
// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.subclass.id)){
|
|
// await feature.delete();
|
|
// }
|
|
// }
|
|
|
|
// const features = [itemData.system.foundationFeature, itemData.system.specializationFeature, itemData.system.masteryFeature];
|
|
// for(var i = 0; i < features.length; i++){
|
|
// const feature = features[i];
|
|
// for(var ability of feature.abilities){
|
|
// const data = (await fromUuid(ability.uuid)).toObject();
|
|
// if(i > 0 ) data.system.disabled = true;
|
|
// data.uuid = itemData.uuid;
|
|
|
|
// const abilityData = await this._onDropItemCreate(data);
|
|
// ability.uuid = abilityData[0].uuid;
|
|
|
|
// createdItems.push(abilityData);
|
|
// }
|
|
// }
|
|
// }
|
|
// else if(item.type === 'class'){
|
|
// if(!item.system.multiclass){
|
|
// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id)){
|
|
// await feature.delete();
|
|
// }
|
|
// }
|
|
|
|
// for(var feature of item.system.features){
|
|
// const data = (await fromUuid(feature.uuid)).toObject();
|
|
// const itemData = await this._onDropItemCreate(data);
|
|
// createdItems.push(itemData);
|
|
// }
|
|
// }
|
|
// else if(item.type === 'ancestry'){
|
|
// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){
|
|
// await feature.delete();
|
|
// }
|
|
|
|
// for(var feature of item.system.abilities){
|
|
// const data = (await fromUuid(feature.uuid)).toObject();
|
|
// const itemData = await this._onDropItemCreate(data);
|
|
// createdItems.push(itemData);
|
|
// }
|
|
// }
|
|
// else if(item.type === 'community'){
|
|
// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.community.id)){
|
|
// await feature.delete();
|
|
// }
|
|
|
|
// for(var feature of item.system.abilities){
|
|
// const data = (await fromUuid(feature.uuid)).toObject();
|
|
// const itemData = await this._onDropItemCreate(data);
|
|
// createdItems.push(itemData);
|
|
// }
|
|
// }
|
|
|
|
// if ( this.actor.uuid === item.parent?.uuid ) return this._onSortItem(event, item);
|
|
|
|
// if(item.type === 'weapon'){
|
|
// if(!element) return;
|
|
|
|
// if(element.classList.contains('weapon-section')){
|
|
// if(item.system.secondary && this.actor.system.activeWeapons.burden === 'twoHanded'){
|
|
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded"));
|
|
// return;
|
|
// }
|
|
// else if(item.system.burden === 'twoHanded' && this.actor.system.activeWeapons.secondary){
|
|
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary"));
|
|
// return;
|
|
// }
|
|
|
|
// const existing = this.actor.system.activeWeapons.primary && !item.system.secondary ? await fromUuid(this.actor.system.activeWeapons.primary.uuid) :
|
|
// this.actor.system.activeWeapons.secondary && item.system.secondary ? await fromUuid(this.actor.system.activeWeapons.secondary.uuid) : null;
|
|
// await existing?.delete();
|
|
// itemData.system.active = true;
|
|
// }
|
|
// else if(element.classList.contains('inventory-weapon-section-first')){
|
|
// const existing = this.actor.system.inventoryWeapons.first ? await fromUuid(this.actor.system.inventoryWeapons.first.uuid) : null;
|
|
// await existing?.delete();
|
|
|
|
// itemData.system.inventoryWeapon = 1;
|
|
// }
|
|
// else if(element.classList.contains('inventory-weapon-section-second')){
|
|
// const existing = this.actor.system.inventoryWeapons.second ? await fromUuid(this.actor.system.inventoryWeapons.second.uuid) : null;
|
|
// await existing?.delete();
|
|
|
|
// itemData.system.inventoryWeapon = 2;
|
|
// }
|
|
// else return [];
|
|
// }
|
|
|
|
// if(item.type === 'armor'){
|
|
// if(!element) return;
|
|
|
|
// if(element.classList.contains('armor-section')){
|
|
// const existing = this.actor.system.armor ? await fromUuid(this.actor.system.armor.uuid) : null;
|
|
// await existing?.delete();
|
|
// }
|
|
|
|
// else return;
|
|
// }
|
|
|
|
// const createdItem = await this._onDropItemCreate(itemData);
|
|
// createdItems.push(createdItem);
|
|
|
|
// return createdItems;
|
|
// }
|
|
// }
|
|
|
|
// async emulateItemDrop(data) {
|
|
// const event = new DragEvent("drop", { altKey: game.keyboard.isModifierActive("Alt") });
|
|
// return this._onDropItem(event, data);
|
|
// }
|
|
// }
|