mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 07:59:03 +01:00
Merge branch 'Foundryborne:main' into main
This commit is contained in:
commit
e4db746e44
210 changed files with 1453 additions and 902 deletions
39
lang/en.json
39
lang/en.json
|
|
@ -189,7 +189,11 @@
|
|||
"title": "Multiclass Subclass",
|
||||
"text": "Do you want to add this subclass as your multiclass subclass?"
|
||||
},
|
||||
"cannotRemoveCoreExperience": "You are using Levelup Auto. You cannot remove an experience given to you by the rule progression."
|
||||
"cannotRemoveCoreExperience": "You are using Levelup Auto. You cannot remove an experience given to you by the rule progression.",
|
||||
"companionLevelup": {
|
||||
"confirmTitle": "Companion Levelup",
|
||||
"confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)"
|
||||
}
|
||||
},
|
||||
"Companion": {
|
||||
"FIELDS": {
|
||||
|
|
@ -233,13 +237,14 @@
|
|||
},
|
||||
"APPLICATIONS": {
|
||||
"CharacterCreation": {
|
||||
"setupTabs": {
|
||||
"tabs": {
|
||||
"ancestry": "Ancestry",
|
||||
"community": "Community",
|
||||
"class": "Class",
|
||||
"experience": "Experience",
|
||||
"traits": "Traits",
|
||||
"domainCards": "Domain Cards"
|
||||
"domainCards": "Domain Cards",
|
||||
"equipment": "Equipment"
|
||||
},
|
||||
"ancestryNamePlaceholder": "Your ancestry's name",
|
||||
"buttonTitle": "Character Setup",
|
||||
|
|
@ -816,6 +821,10 @@
|
|||
"name": "Dead",
|
||||
"description": "The character is dead"
|
||||
},
|
||||
"defeated": {
|
||||
"name": "Defeated",
|
||||
"description": "This adversary is defeated."
|
||||
},
|
||||
"hidden": {
|
||||
"name": "Hidden",
|
||||
"description": "While Hidden, attacks cannot be made directly targeting them nd any rolls against them are at disadvantage.\nWhen a Hidden creature moves or attacks, they are no longer Hidden. However, if a creature is Hidden when they begin making an attack, the roll has advantage; the Hidden condition isn’t cleared until after the attack is resolved."
|
||||
|
|
@ -1865,7 +1874,8 @@
|
|||
"tier3": "Tier 3",
|
||||
"tier4": "tier 4",
|
||||
"domains": "Domains",
|
||||
"downtime": "Downtime"
|
||||
"downtime": "Downtime",
|
||||
"rules": "Rules"
|
||||
},
|
||||
"Tiers": {
|
||||
"singular": "Tier",
|
||||
|
|
@ -1934,6 +1944,7 @@
|
|||
"itemResource": "Item Resource",
|
||||
"label": "Label",
|
||||
"level": "Level",
|
||||
"levelShort": "Lv",
|
||||
"levelUp": "Level Up",
|
||||
"loadout": "Loadout",
|
||||
"max": "Max",
|
||||
|
|
@ -2081,7 +2092,12 @@
|
|||
"FIELDS": {
|
||||
"displayFear": { "label": "Fear Display" },
|
||||
"dualityColorScheme": { "label": "Chat Style" },
|
||||
"showGenericStatusEffects": { "label": "Show Foundry Status Effects" }
|
||||
"showGenericStatusEffects": { "label": "Show Foundry Status Effects" },
|
||||
"expandedTitle": "Auto-expand Descriptions",
|
||||
"extendCharacterDescriptions": { "label": "Characters" },
|
||||
"extendAdversaryDescriptions": { "label": "Adversaries" },
|
||||
"extendEnvironmentDescriptions": { "label": "Environments" },
|
||||
"extendItemDescriptions": { "label": "Items" }
|
||||
},
|
||||
"fearDisplay": {
|
||||
"token": "Tokens",
|
||||
|
|
@ -2099,6 +2115,13 @@
|
|||
"label": "Damage Reduction Rules Default",
|
||||
"hint": "Wether using armor and reductions has rules on by default"
|
||||
},
|
||||
"defeated": {
|
||||
"enabled": { "label": "Enabled" },
|
||||
"overlay": { "label": "Overlay Effect" },
|
||||
"characterDefault": { "label": "Character Default Defeated Status" },
|
||||
"adversaryDefault": { "label": "Adversary Default Defeated Status" },
|
||||
"companionDefault": { "label": "Companion Default Defeated Status" }
|
||||
},
|
||||
"hopeFear": {
|
||||
"label": "Hope & Fear",
|
||||
"gm": { "label": "GM" },
|
||||
|
|
@ -2130,6 +2153,9 @@
|
|||
"label": "Players Can Manually Edit Character Settings",
|
||||
"hint": "Players are allowed to access the manual Character Settings and change their statistics beyond the rules."
|
||||
}
|
||||
},
|
||||
"defeated": {
|
||||
"title": "Defeated Handling"
|
||||
}
|
||||
},
|
||||
"Homebrew": {
|
||||
|
|
@ -2369,7 +2395,8 @@
|
|||
"rulesOn": "Rules On",
|
||||
"rulesOff": "Rules Off",
|
||||
"remainingUses": "Uses refresh on {type}",
|
||||
"rightClickExtand": "Right-Click to extand"
|
||||
"rightClickExtand": "Right-Click to extand",
|
||||
"companionPartnerLevelBlock": "The companion needs an assigned partner to level up."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
|
||||
this.setup = {
|
||||
traits: this.character.system.traits,
|
||||
ancestryName: '',
|
||||
ancestryName: {
|
||||
primary: '',
|
||||
secondary: ''
|
||||
},
|
||||
mixedAncestry: false,
|
||||
primaryAncestry: this.character.system.ancestry ?? {},
|
||||
secondaryAncestry: {},
|
||||
|
|
@ -83,131 +86,70 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
|
||||
static PARTS = {
|
||||
tabs: { template: 'systems/daggerheart/templates/characterCreation/tabs.hbs' },
|
||||
setup: { template: 'systems/daggerheart/templates/characterCreation/tabs/setup.hbs' },
|
||||
ancestry: { template: 'systems/daggerheart/templates/characterCreation/setupTabs/ancestry.hbs' },
|
||||
community: { template: 'systems/daggerheart/templates/characterCreation/setupTabs/community.hbs' },
|
||||
class: { template: 'systems/daggerheart/templates/characterCreation/setupTabs/class.hbs' },
|
||||
traits: { template: 'systems/daggerheart/templates/characterCreation/setupTabs/traits.hbs' },
|
||||
experience: { template: 'systems/daggerheart/templates/characterCreation/setupTabs/experience.hbs' },
|
||||
domainCards: { template: 'systems/daggerheart/templates/characterCreation/setupTabs/domainCards.hbs' },
|
||||
equipment: { template: 'systems/daggerheart/templates/characterCreation/tabs/equipment.hbs' },
|
||||
// story: { template: 'systems/daggerheart/templates/characterCreation/tabs/story.hbs' },
|
||||
ancestry: { template: 'systems/daggerheart/templates/characterCreation/tabs/ancestry.hbs' },
|
||||
community: { template: 'systems/daggerheart/templates/characterCreation/tabs/community.hbs' },
|
||||
class: { template: 'systems/daggerheart/templates/characterCreation/tabs/class.hbs' },
|
||||
traits: { template: 'systems/daggerheart/templates/characterCreation/tabs/traits.hbs' },
|
||||
experience: { template: 'systems/daggerheart/templates/characterCreation/tabs/experience.hbs' },
|
||||
domainCards: { template: 'systems/daggerheart/templates/characterCreation/tabs/domainCards.hbs' },
|
||||
equipment: { template: 'systems/daggerheart/templates/characterCreation/equipment.hbs' },
|
||||
// story: { template: 'systems/daggerheart/templates/characterCreation/story.hbs' },
|
||||
footer: { template: 'systems/daggerheart/templates/characterCreation/footer.hbs' }
|
||||
};
|
||||
|
||||
static TABS = {
|
||||
setup: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'setup',
|
||||
label: 'DAGGERHEART.GENERAL.Tabs.setup'
|
||||
},
|
||||
equipment: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'equipment',
|
||||
label: 'DAGGERHEART.GENERAL.Tabs.equipment',
|
||||
optional: true
|
||||
}
|
||||
// story: {
|
||||
// active: false,
|
||||
// cssClass: '',
|
||||
// group: 'primary',
|
||||
// id: 'story',
|
||||
// label: 'DAGGERHEART.GENERAL.Tabs.story',
|
||||
// optional: true
|
||||
// }
|
||||
};
|
||||
|
||||
static SETUPTABS = {
|
||||
ancestry: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'ancestry',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.setupTabs.ancestry'
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.ancestry'
|
||||
},
|
||||
community: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'community',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.setupTabs.community'
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.community'
|
||||
},
|
||||
class: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'class',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.setupTabs.class'
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.class'
|
||||
},
|
||||
traits: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'traits',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.setupTabs.traits'
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.traits'
|
||||
},
|
||||
experience: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'experience',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.setupTabs.experience'
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.experience'
|
||||
},
|
||||
domainCards: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'domainCards',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.setupTabs.domainCards'
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.domainCards'
|
||||
},
|
||||
equipment: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'setup',
|
||||
id: 'equipment',
|
||||
label: 'DAGGERHEART.APPLICATIONS.CharacterCreation.tabs.equipment'
|
||||
}
|
||||
};
|
||||
|
||||
_getTabs(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' : '';
|
||||
|
||||
switch (v.id) {
|
||||
case 'setup':
|
||||
const ancestryFinished = this.setup.primaryAncestry.uuid;
|
||||
const communityFinished = this.setup.community.uuid;
|
||||
const classFinished = this.setup.class.uuid && this.setup.subclass.uuid;
|
||||
const traitsFinished = Object.values(this.setup.traits).every(x => x.value !== null);
|
||||
const experiencesFinished = Object.values(this.setup.experiences).every(x => x.name);
|
||||
const domainCardsFinished = Object.values(this.setup.domainCards).every(x => x.uuid);
|
||||
v.finished =
|
||||
ancestryFinished &&
|
||||
communityFinished &&
|
||||
classFinished &&
|
||||
traitsFinished &&
|
||||
experiencesFinished &&
|
||||
domainCardsFinished;
|
||||
break;
|
||||
case 'equipment':
|
||||
const armorFinished = this.equipment.armor?.uuid;
|
||||
const primaryFinished = this.equipment.primaryWeapon?.uuid;
|
||||
const secondaryFinished =
|
||||
this.equipment.secondaryWeapon?.uuid ||
|
||||
(primaryFinished && this.equipment.primaryWeapon.system.burden == burden.twoHanded.value);
|
||||
const choiceAFinished = this.equipment.inventory.choiceA?.uuid;
|
||||
const choiceBFinished = this.equipment.inventory.choiceB?.uuid;
|
||||
|
||||
v.finished =
|
||||
armorFinished && primaryFinished && secondaryFinished && choiceAFinished && choiceBFinished;
|
||||
}
|
||||
}
|
||||
|
||||
tabs.equipment.cssClass = tabs.setup.finished ? tabs.equipment.cssClass : 'disabled';
|
||||
// tabs.story.cssClass = tabs.setup.finished ? tabs.story.cssClass : 'disabled';
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
_getSetupTabs(tabs) {
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group]
|
||||
? this.tabGroups[v.group] === v.id
|
||||
|
|
@ -232,37 +174,15 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
case 'domainCards':
|
||||
v.disabled = this.setup.visibility < 6;
|
||||
break;
|
||||
case 'equipment':
|
||||
v.disabled = this.setup.visibility < 7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
changeTab(tab, group, options) {
|
||||
super.changeTab(tab, group, options);
|
||||
|
||||
if (group === 'primary') {
|
||||
for (var listTab of Object.keys(this.constructor.TABS)) {
|
||||
const marker = options.navElement.querySelector(`a[data-action="tab"].${listTab} .finish-marker`);
|
||||
if (listTab === tab) {
|
||||
marker.classList.add('active');
|
||||
} else {
|
||||
marker.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
if (tab === 'equipment') {
|
||||
this.tabGroups.setup = null;
|
||||
this.element.querySelector('section[data-group="setup"].active')?.classList?.remove?.('active');
|
||||
} else {
|
||||
this.tabGroups.setup = 'domainCards';
|
||||
this.element
|
||||
.querySelector('section[data-group="setup"][data-tab="domainCards"]')
|
||||
?.classList?.add?.('active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_attachPartListeners(partId, htmlElement, options) {
|
||||
super._attachPartListeners(partId, htmlElement, options);
|
||||
|
||||
|
|
@ -274,14 +194,71 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
});
|
||||
}
|
||||
|
||||
async _preFirstRender(_context, _options) {
|
||||
this.tabGroups.primary = 'setup';
|
||||
this.tabGroups.setup = 'ancestry';
|
||||
}
|
||||
|
||||
async _prepareContext(_options) {
|
||||
this.tabGroups.setup = this.tabGroups.setup ?? 'ancestry';
|
||||
const context = await super._prepareContext(_options);
|
||||
|
||||
context.tabs = this._getTabs(this.constructor.TABS);
|
||||
const availableTraitModifiers = game.settings
|
||||
.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew)
|
||||
.traitArray.map(trait => ({ key: trait, name: trait }));
|
||||
for (let trait of Object.values(this.setup.traits).filter(x => x.value !== null)) {
|
||||
const index = availableTraitModifiers.findIndex(x => x.key === trait.value);
|
||||
if (index !== -1) {
|
||||
availableTraitModifiers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
context.suggestedTraits = this.setup.class.system
|
||||
? Object.keys(this.setup.class.system.characterGuide.suggestedTraits).map(traitKey => {
|
||||
const trait = this.setup.class.system.characterGuide.suggestedTraits[traitKey];
|
||||
return `${game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${traitKey}.short`)} ${trait > 0 ? `+${trait}` : trait}`;
|
||||
})
|
||||
: [];
|
||||
context.traits = {
|
||||
values: Object.keys(this.setup.traits).map(traitKey => {
|
||||
const trait = this.setup.traits[traitKey];
|
||||
const options = [...availableTraitModifiers];
|
||||
if (trait.value !== null && !options.some(x => x.key === trait.value))
|
||||
options.push({ key: trait.value, name: trait.value });
|
||||
|
||||
return {
|
||||
...trait,
|
||||
key: traitKey,
|
||||
name: game.i18n.localize(abilities[traitKey].label),
|
||||
options: options
|
||||
};
|
||||
})
|
||||
};
|
||||
context.traits.nrTotal = Object.keys(context.traits.values).length;
|
||||
context.traits.nrSelected = this.getNrSelectedTrait();
|
||||
|
||||
context.experience = {
|
||||
values: this.setup.experiences,
|
||||
nrTotal: Object.keys(this.setup.experiences).length,
|
||||
nrSelected: Object.values(this.setup.experiences).reduce((acc, exp) => acc + (exp.name ? 1 : 0), 0)
|
||||
};
|
||||
|
||||
context.mixedAncestry = Number(this.setup.mixedAncestry);
|
||||
|
||||
const { primary, secondary, overwrite } = this.setup.ancestryName;
|
||||
context.ancestryName = overwrite ?? (primary && secondary ? `${primary}/${secondary}` : primary);
|
||||
context.primaryAncestry = { ...this.setup.primaryAncestry, compendium: 'ancestries' };
|
||||
context.secondaryAncestry = { ...this.setup.secondaryAncestry, compendium: 'ancestries' };
|
||||
context.community = { ...this.setup.community, compendium: 'communities' };
|
||||
context.class = { ...this.setup.class, compendium: 'classes' };
|
||||
context.subclass = { ...this.setup.subclass, compendium: 'subclasses' };
|
||||
|
||||
const allDomainData = CONFIG.DH.DOMAIN.allDomains();
|
||||
context.classDomains = context.class.uuid
|
||||
? context.class.system.domains.map(key => game.i18n.localize(allDomainData[key].label))
|
||||
: [];
|
||||
context.domainCards = Object.keys(this.setup.domainCards).reduce((acc, x) => {
|
||||
acc[x] = { ...this.setup.domainCards[x], compendium: 'domains' };
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
context.visibility = this.setup.visibility;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
@ -289,7 +266,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
async _preparePartContext(partId, context) {
|
||||
switch (partId) {
|
||||
case 'footer':
|
||||
context.isLastTab = this.tabGroups.setup === 'domainCards' || this.tabGroups.primary !== 'setup';
|
||||
context.isLastTab = this.tabGroups.setup === 'equipment';
|
||||
switch (this.tabGroups.setup) {
|
||||
case null:
|
||||
case 'ancestry':
|
||||
|
|
@ -307,69 +284,11 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
case 'experience':
|
||||
context.nextDisabled = this.setup.visibility === 5;
|
||||
break;
|
||||
case 'domainCards':
|
||||
context.nextDisabled = this.setup.visibility === 6;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'setup':
|
||||
context.setupTabs = this._getSetupTabs(this.constructor.SETUPTABS);
|
||||
const availableTraitModifiers = game.settings
|
||||
.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew)
|
||||
.traitArray.map(trait => ({ key: trait, name: trait }));
|
||||
for (let trait of Object.values(this.setup.traits).filter(x => x.value !== null)) {
|
||||
const index = availableTraitModifiers.findIndex(x => x.key === trait.value);
|
||||
if (index !== -1) {
|
||||
availableTraitModifiers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
context.suggestedTraits = this.setup.class.system
|
||||
? Object.keys(this.setup.class.system.characterGuide.suggestedTraits).map(traitKey => {
|
||||
const trait = this.setup.class.system.characterGuide.suggestedTraits[traitKey];
|
||||
return `${game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${traitKey}.short`)} ${trait > 0 ? `+${trait}` : trait}`;
|
||||
})
|
||||
: [];
|
||||
context.traits = {
|
||||
values: Object.keys(this.setup.traits).map(traitKey => {
|
||||
const trait = this.setup.traits[traitKey];
|
||||
const options = [...availableTraitModifiers];
|
||||
if (trait.value !== null && !options.some(x => x.key === trait.value))
|
||||
options.push({ key: trait.value, name: trait.value });
|
||||
|
||||
return {
|
||||
...trait,
|
||||
key: traitKey,
|
||||
name: game.i18n.localize(abilities[traitKey].label),
|
||||
options: options
|
||||
};
|
||||
})
|
||||
};
|
||||
context.traits.nrTotal = Object.keys(context.traits.values).length;
|
||||
context.traits.nrSelected = this.getNrSelectedTrait();
|
||||
|
||||
context.experience = {
|
||||
values: this.setup.experiences,
|
||||
nrTotal: Object.keys(this.setup.experiences).length,
|
||||
nrSelected: Object.values(this.setup.experiences).reduce((acc, exp) => acc + (exp.name ? 1 : 0), 0)
|
||||
};
|
||||
|
||||
context.mixedAncestry = Number(this.setup.mixedAncestry);
|
||||
context.ancestryName = this.setup.ancestryName;
|
||||
context.primaryAncestry = { ...this.setup.primaryAncestry, compendium: 'ancestries' };
|
||||
context.secondaryAncestry = { ...this.setup.secondaryAncestry, compendium: 'ancestries' };
|
||||
context.community = { ...this.setup.community, compendium: 'communities' };
|
||||
context.class = { ...this.setup.class, compendium: 'classes' };
|
||||
context.subclass = { ...this.setup.subclass, compendium: 'subclasses' };
|
||||
|
||||
const allDomainData = CONFIG.DH.DOMAIN.allDomains();
|
||||
context.classDomains = context.class.uuid
|
||||
? context.class.system.domains.map(key => game.i18n.localize(allDomainData[key].label))
|
||||
: [];
|
||||
context.domainCards = Object.keys(this.setup.domainCards).reduce((acc, x) => {
|
||||
acc[x] = { ...this.setup.domainCards[x], compendium: 'domains' };
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
context.visibility = this.setup.visibility;
|
||||
break;
|
||||
case 'equipment':
|
||||
const suggestions = await this.getEquipmentSuggestions(
|
||||
|
|
@ -438,8 +357,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
|
||||
getUpdateVisibility() {
|
||||
switch (this.setup.visibility) {
|
||||
case 7:
|
||||
return 7;
|
||||
case 6:
|
||||
return 6;
|
||||
return Object.values(this.setup.domainCards).every(x => x.uuid) ? 7 : 6;
|
||||
case 5:
|
||||
return Object.values(this.setup.experiences).every(x => x.name) ? 6 : 5;
|
||||
case 4:
|
||||
|
|
@ -505,7 +426,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
|
||||
const presets = {
|
||||
compendium: 'daggerheart',
|
||||
folder: equipment.includes(type) ? "equipments" : type,
|
||||
folder: equipment.includes(type) ? 'equipments' : type,
|
||||
render: {
|
||||
noFolder: true
|
||||
}
|
||||
|
|
@ -565,6 +486,9 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
case 6:
|
||||
this.tabGroups.setup = 'domainCards';
|
||||
break;
|
||||
case 7:
|
||||
this.tabGroups.setup = 'equipment';
|
||||
break;
|
||||
}
|
||||
|
||||
this.render();
|
||||
|
|
@ -576,9 +500,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
? this.setup.secondaryAncestry.system.secondaryFeature
|
||||
: this.setup.primaryAncestry.system.secondaryFeature;
|
||||
|
||||
const { primary, secondary, overwrite } = this.setup.ancestryName;
|
||||
const ancestry = {
|
||||
...this.setup.primaryAncestry,
|
||||
name: this.setup.ancestryName ?? this.setup.primaryAncestry.name,
|
||||
name: overwrite ?? (primary && secondary ? `${primary}/${secondary}` : primary),
|
||||
system: {
|
||||
...this.setup.primaryAncestry.system,
|
||||
features: [
|
||||
|
|
@ -650,13 +575,14 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||
const item = await foundry.utils.fromUuid(data.uuid);
|
||||
if (item.type === 'ancestry' && event.target.closest('.primary-ancestry-card')) {
|
||||
this.setup.ancestryName = item.name;
|
||||
this.setup.ancestryName.primary = item.name;
|
||||
this.setup.primaryAncestry = {
|
||||
...item,
|
||||
effects: Array.from(item.effects).map(x => x.toObject()),
|
||||
uuid: item.uuid
|
||||
};
|
||||
} else if (item.type === 'ancestry' && event.target.closest('.secondary-ancestry-card')) {
|
||||
this.setup.ancestryName.secondary = item.name;
|
||||
this.setup.secondaryAncestry = {
|
||||
...item,
|
||||
effects: Array.from(item.effects).map(x => x.toObject()),
|
||||
|
|
|
|||
|
|
@ -95,8 +95,9 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
if (x.system.actions) {
|
||||
const recoverable = x.system.actions.reduce((acc, action) => {
|
||||
if (
|
||||
(action.uses.recovery && (action.uses.recovery === 'longRest') === !this.shortrest) ||
|
||||
action.uses.recovery === 'shortRest'
|
||||
action.uses.recovery &&
|
||||
((action.uses.recovery === 'longRest' && !this.shortrest) ||
|
||||
action.uses.recovery === 'shortRest')
|
||||
) {
|
||||
acc.push({
|
||||
title: x.name,
|
||||
|
|
|
|||
|
|
@ -49,12 +49,7 @@ export default class DhCharacterLevelUp extends LevelUpBase {
|
|||
const experienceIncreases = Object.values(advancementChoices.experience ?? {});
|
||||
const experienceIncreaseValues = experienceIncreases
|
||||
.filter(exp => exp.data.length > 0)
|
||||
.flatMap(exp =>
|
||||
exp.data.map(data => {
|
||||
const experience = Object.keys(this.actor.system.experiences)[data];
|
||||
return this.actor.system.experiences[experience].name;
|
||||
})
|
||||
);
|
||||
.flatMap(exp => exp.data);
|
||||
context.experienceIncreases = {
|
||||
values: experienceIncreaseValues,
|
||||
active: experienceIncreases.length > 0,
|
||||
|
|
|
|||
|
|
@ -37,12 +37,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
|
|||
const experienceIncreases = Object.values(advancementChoices.experience ?? {});
|
||||
const experienceIncreaseValues = experienceIncreases
|
||||
.filter(exp => exp.data.length > 0)
|
||||
.flatMap(exp =>
|
||||
exp.data.map(data => {
|
||||
const experience = Object.keys(this.actor.system.experiences)[data];
|
||||
return this.actor.system.experiences[experience].name;
|
||||
})
|
||||
);
|
||||
.flatMap(exp => exp.data);
|
||||
context.experienceIncreases = {
|
||||
values: experienceIncreaseValues,
|
||||
active: experienceIncreases.length > 0,
|
||||
|
|
@ -72,6 +67,28 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
|
|||
const levelKeys = Object.keys(this.levelup.levels);
|
||||
const actorDamageDice = this.actor.system.attack.damage.parts[0].value.dice;
|
||||
const actorRange = this.actor.system.attack.range;
|
||||
|
||||
let achievementExperiences = [];
|
||||
for (var levelKey of levelKeys) {
|
||||
const level = this.levelup.levels[levelKey];
|
||||
if (Number(levelKey) < this.levelup.startLevel) continue;
|
||||
|
||||
achievementExperiences = level.achievements.experiences
|
||||
? Object.values(level.achievements.experiences).reduce((acc, experience) => {
|
||||
if (experience.name) acc.push(experience);
|
||||
return acc;
|
||||
}, [])
|
||||
: [];
|
||||
}
|
||||
context.achievements = {
|
||||
experiences: {
|
||||
values: achievementExperiences,
|
||||
shown: achievementExperiences.length > 0
|
||||
}
|
||||
};
|
||||
|
||||
context.achievements = context.achievements.experiences.shown ? context.achievements : undefined;
|
||||
|
||||
const advancement = {};
|
||||
for (var levelKey of levelKeys) {
|
||||
const level = this.levelup.levels[levelKey];
|
||||
|
|
|
|||
|
|
@ -31,8 +31,19 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
|
|||
};
|
||||
|
||||
static PARTS = {
|
||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
header: { template: 'systems/daggerheart/templates/settings/automation-settings/header.hbs' },
|
||||
general: { template: 'systems/daggerheart/templates/settings/automation-settings/general.hbs' },
|
||||
rules: { template: 'systems/daggerheart/templates/settings/automation-settings/rules.hbs' },
|
||||
footer: { template: 'systems/daggerheart/templates/settings/automation-settings/footer.hbs' }
|
||||
};
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
main: {
|
||||
template: 'systems/daggerheart/templates/settings/automation-settings.hbs'
|
||||
tabs: [{ id: 'general' }, { id: 'rules' }],
|
||||
initial: 'general',
|
||||
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { GMUpdateEvent, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
import DhCompanionlevelUp from '../levelup/companionLevelup.mjs';
|
||||
import DHBaseActorSettings from '../sheets/api/actor-setting.mjs';
|
||||
|
||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||
|
|
@ -11,8 +10,7 @@ export default class DHCompanionSettings extends DHBaseActorSettings {
|
|||
position: { width: 455, height: 'auto' },
|
||||
actions: {
|
||||
addExperience: DHCompanionSettings.#addExperience,
|
||||
removeExperience: DHCompanionSettings.#removeExperience,
|
||||
levelUp: DHCompanionSettings.#levelUp
|
||||
removeExperience: DHCompanionSettings.#removeExperience
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -121,12 +119,4 @@ export default class DHCompanionSettings extends DHBaseActorSettings {
|
|||
|
||||
await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null });
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the companion level-up dialog for the associated actor.
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #levelUp() {
|
||||
new DhCompanionlevelUp(this.actor).render({ force: true });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -638,15 +638,21 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
ability: abilityLabel
|
||||
})
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.consumeResource(result?.costs);
|
||||
}, 50);
|
||||
|
||||
this.consumeResource(result?.costs);
|
||||
}
|
||||
|
||||
// Remove when Action Refactor part #2 done
|
||||
async consumeResource(costs) {
|
||||
if (!costs?.length) return;
|
||||
const usefulResources = foundry.utils.deepClone(this.actor.system.resources);
|
||||
const usefulResources = {
|
||||
...foundry.utils.deepClone(this.actor.system.resources),
|
||||
fear: {
|
||||
value: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
|
||||
max: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear,
|
||||
reversed: false
|
||||
}
|
||||
};
|
||||
const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(costs).map(c => {
|
||||
const resource = usefulResources[c.key];
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import DhCompanionLevelUp from '../../levelup/companionLevelup.mjs';
|
||||
import DHBaseActorSheet from '../api/base-actor.mjs';
|
||||
|
||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||
|
|
@ -5,8 +6,10 @@ import DHBaseActorSheet from '../api/base-actor.mjs';
|
|||
export default class DhCompanionSheet extends DHBaseActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['actor', 'companion'],
|
||||
position: { width: 300 },
|
||||
actions: {}
|
||||
position: { width: 340 },
|
||||
actions: {
|
||||
levelManagement: DhCompanionSheet.#levelManagement
|
||||
}
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
|
|
@ -25,4 +28,25 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
|
|||
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
||||
}
|
||||
};
|
||||
|
||||
/** @inheritDoc */
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
this.element
|
||||
.querySelector('.level-value')
|
||||
?.addEventListener('change', event => this.document.updateLevel(Number(event.currentTarget.value)));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Application Clicks Actions */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Opens the companions level management window.
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static #levelManagement() {
|
||||
new DhCompanionLevelUp(this.document).render({ force: true });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,23 @@ const { HandlebarsApplicationMixin } = foundry.applications.api;
|
|||
import { getDocFromElement, getDocFromElementSync, tagifyElement } from '../../../helpers/utils.mjs';
|
||||
import { ItemBrowser } from '../../ui/itemBrowser.mjs';
|
||||
|
||||
const typeSettingsMap = {
|
||||
character: 'extendCharacterDescriptions',
|
||||
adversary: 'extendAdversaryDescriptions',
|
||||
environment: 'extendEnvironmentDescriptions',
|
||||
ancestry: 'extendItemDescriptions',
|
||||
community: 'extendItemDescriptions',
|
||||
class: 'extendItemDescriptions',
|
||||
subclass: 'extendItemDescriptions',
|
||||
feature: 'extendItemDescriptions',
|
||||
domainCard: 'extendItemDescriptions',
|
||||
loot: 'extendItemDescriptions',
|
||||
consumable: 'extendItemDescriptions',
|
||||
weapon: 'extendItemDescriptions',
|
||||
armor: 'extendItemDescriptions',
|
||||
beastform: 'extendItemDescriptions'
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction
|
||||
*/
|
||||
|
|
@ -137,6 +154,8 @@ export default function DHApplicationMixin(Base) {
|
|||
docs.filter(doc => doc).forEach(doc => (doc.apps[this.id] = this));
|
||||
|
||||
if (!!this.options.contextMenus.length) this._createContextMenus();
|
||||
|
||||
this.#autoExtendDescriptions(context);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
|
|
@ -149,6 +168,7 @@ export default function DHApplicationMixin(Base) {
|
|||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
this._createTagifyElements(this.options.tagifyConfigs);
|
||||
await this.#prepareInventoryDescription(context);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
|
@ -162,13 +182,7 @@ export default function DHApplicationMixin(Base) {
|
|||
const { actionId, itemUuid } = el.parentElement.dataset;
|
||||
const selector = `${actionId ? `[data-action-id="${actionId}"]` : `[data-item-uuid="${itemUuid}"]`} .extensible`;
|
||||
const newExtensible = newElement.querySelector(selector);
|
||||
|
||||
if (!newExtensible) continue;
|
||||
newExtensible.classList.add('extended');
|
||||
const descriptionElement = newExtensible.querySelector('.invetory-description');
|
||||
if (descriptionElement) {
|
||||
this.#prepareInventoryDescription(newExtensible, descriptionElement);
|
||||
}
|
||||
newExtensible?.classList.add('extended');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -395,6 +409,7 @@ export default function DHApplicationMixin(Base) {
|
|||
context.source = this.document;
|
||||
context.fields = this.document.schema.fields;
|
||||
context.systemFields = this.document.system.schema.fields;
|
||||
context.settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -404,32 +419,69 @@ export default function DHApplicationMixin(Base) {
|
|||
|
||||
/**
|
||||
* Prepares and enriches an inventory item or action description for display.
|
||||
* @param {HTMLElement} extensibleElement - The parent element containing the description.
|
||||
* @param {HTMLElement} descriptionElement - The element where the enriched description will be rendered.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async #prepareInventoryDescription(extensibleElement, descriptionElement) {
|
||||
const parent = extensibleElement.closest('[data-item-uuid], [data-action-id]');
|
||||
const { actionId, itemUuid } = parent?.dataset || {};
|
||||
if (!actionId && !itemUuid) return;
|
||||
async #prepareInventoryDescription(context) {
|
||||
// Get all inventory item elements with a data-item-uuid attribute
|
||||
const inventoryItems = this.element.querySelectorAll('.inventory-item[data-item-uuid]');
|
||||
for (const el of inventoryItems) {
|
||||
// Get the doc uuid from the element
|
||||
const { itemUuid } = el?.dataset || {};
|
||||
if (!itemUuid) continue;
|
||||
|
||||
const doc = itemUuid
|
||||
? await getDocFromElement(extensibleElement)
|
||||
: this.document.system.attack?.id === actionId
|
||||
? this.document.system.attack
|
||||
: this.document.system.actions?.get(actionId);
|
||||
if (!doc) return;
|
||||
//get doc by uuid
|
||||
const doc = await fromUuid(itemUuid);
|
||||
|
||||
const description = game.i18n.localize(doc.system?.description ?? doc.description);
|
||||
const isAction = !!actionId;
|
||||
descriptionElement.innerHTML = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
description,
|
||||
{
|
||||
relativeTo: isAction ? doc.parent : doc,
|
||||
rollData: doc.getRollData?.(),
|
||||
secrets: isAction ? doc.parent.isOwner : doc.isOwner
|
||||
//get inventory-item description element
|
||||
const descriptionElement = el.querySelector('.invetory-description');
|
||||
if (!doc || !descriptionElement) continue;
|
||||
|
||||
// localize the description (idk if it's still necessary)
|
||||
const description = game.i18n.localize(doc.system?.description ?? doc.description);
|
||||
|
||||
// Enrich the description and attach it;
|
||||
const isAction = doc.documentName === 'Action';
|
||||
descriptionElement.innerHTML = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
description,
|
||||
{
|
||||
relativeTo: isAction ? doc.parent : doc,
|
||||
rollData: doc.getRollData?.(),
|
||||
secrets: isAction ? doc.parent.isOwner : doc.isOwner
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Extend Descriptions by Settings */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Extend inventory description when enabled in settings.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async #autoExtendDescriptions(context) {
|
||||
const inventoryItems = this.element.querySelectorAll('.inventory-item[data-item-uuid]');
|
||||
for (const el of inventoryItems) {
|
||||
// Get the doc uuid from the element
|
||||
const { itemUuid } = el?.dataset || {};
|
||||
if (!itemUuid) continue;
|
||||
|
||||
//get doc by uuid
|
||||
const doc = await fromUuid(itemUuid);
|
||||
|
||||
//check the type of the document
|
||||
const actorType =
|
||||
doc?.type === 'adversary' && context.document?.type === 'environment'
|
||||
? typeSettingsMap[doc?.type]
|
||||
: doc.actor?.type;
|
||||
|
||||
// If the actor type is defined and the setting is enabled, extend the description
|
||||
if (typeSettingsMap[actorType]) {
|
||||
const settingKey = typeSettingsMap[actorType];
|
||||
if (context.settings[settingKey]) this.#activeExtended(el);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
|
@ -437,8 +489,6 @@ export default function DHApplicationMixin(Base) {
|
|||
/* -------------------------------------------- */
|
||||
|
||||
static async #addNewItem(event, target) {
|
||||
const { type } = target.dataset;
|
||||
|
||||
const createChoice = await foundry.applications.api.DialogV2.wait({
|
||||
classes: ['dh-style', 'two-big-buttons'],
|
||||
buttons: [
|
||||
|
|
@ -606,10 +656,12 @@ export default function DHApplicationMixin(Base) {
|
|||
static async #toggleExtended(_, target) {
|
||||
const container = target.closest('.inventory-item');
|
||||
const extensible = container?.querySelector('.extensible');
|
||||
const t = extensible?.classList.toggle('extended');
|
||||
extensible?.classList.toggle('extended');
|
||||
}
|
||||
|
||||
const descriptionElement = extensible?.querySelector('.invetory-description');
|
||||
if (t && !!descriptionElement) await this.#prepareInventoryDescription(extensible, descriptionElement);
|
||||
async #activeExtended(element) {
|
||||
const extensible = element?.querySelector('.extensible');
|
||||
extensible?.classList.add('extended');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export default function ItemAttachmentSheet(Base) {
|
|||
...super.TABS,
|
||||
primary: {
|
||||
...super.TABS?.primary,
|
||||
tabs: [...(super.TABS?.primary?.tabs || []), { id: 'attachments' }],
|
||||
tabs: [...(super.TABS?.primary?.tabs || []) /*{ id: 'attachments' }*/], // Disabled until fixed
|
||||
initial: super.TABS?.primary?.initial || 'description',
|
||||
labelPrefix: super.TABS?.primary?.labelPrefix || 'DAGGERHEART.GENERAL.Tabs'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
});
|
||||
}
|
||||
|
||||
async _prepareTurnContext(combat, combatant, index) {
|
||||
const turn = await super._prepareTurnContext(combat, combatant, index);
|
||||
return { ...turn, isNPC: combatant.isNPC, system: combatant.system.toObject() };
|
||||
}
|
||||
|
||||
_getCombatContextOptions() {
|
||||
return [
|
||||
{
|
||||
|
|
@ -65,6 +60,57 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
];
|
||||
}
|
||||
|
||||
getDefeatedId(combatant) {
|
||||
if (!combatant.actor) return CONFIG.specialStatusEffects.DEFEATED;
|
||||
|
||||
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
||||
return settings[`${combatant.actor.type}Default`];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
async _onToggleDefeatedStatus(combatant) {
|
||||
const isDefeated = !combatant.isDefeated;
|
||||
await combatant.update({ defeated: isDefeated });
|
||||
await combatant.actor?.toggleStatusEffect(this.getDefeatedId(combatant), { overlay: true, active: isDefeated });
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
async _prepareTurnContext(combat, combatant, index) {
|
||||
const { id, name, isOwner, isDefeated, hidden, initiative, permission } = combatant;
|
||||
const resource = permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER ? combatant.resource : null;
|
||||
const hasDecimals = Number.isFinite(initiative) && !Number.isInteger(initiative);
|
||||
const turn = {
|
||||
hasDecimals,
|
||||
hidden,
|
||||
id,
|
||||
isDefeated,
|
||||
initiative,
|
||||
isOwner,
|
||||
name,
|
||||
resource,
|
||||
active: index === combat.turn,
|
||||
canPing: combatant.sceneId === canvas.scene?.id && game.user.hasPermission('PING_CANVAS'),
|
||||
img: await this._getCombatantThumbnail(combatant)
|
||||
};
|
||||
|
||||
turn.css = [turn.active ? 'active' : null, hidden ? 'hide' : null, isDefeated ? 'defeated' : null].filterJoin(
|
||||
' '
|
||||
);
|
||||
|
||||
const defeatedId = this.getDefeatedId(combatant);
|
||||
const effects = [];
|
||||
for (const effect of combatant.actor?.temporaryEffects ?? []) {
|
||||
if (effect.statuses.has(defeatedId)) turn.isDefeated = true;
|
||||
else if (effect.img) effects.push({ img: effect.img, name: effect.name });
|
||||
}
|
||||
turn.effects = {
|
||||
icons: effects,
|
||||
tooltip: this._formatEffectsTooltip(effects)
|
||||
};
|
||||
|
||||
return { ...turn, isNPC: combatant.isNPC, system: combatant.system.toObject() };
|
||||
}
|
||||
|
||||
async setCombatantSpotlight(combatantId) {
|
||||
const update = {
|
||||
system: {
|
||||
|
|
|
|||
|
|
@ -15,17 +15,19 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
|||
acc.push(effect);
|
||||
|
||||
const currentStatusActiveEffects = acc.filter(
|
||||
x => x.statuses.size === 1 && x.name === game.i18n.localize(statusMap.get(x.statuses.first()).name)
|
||||
x => x.statuses.size === 1 && x.name === game.i18n.localize(statusMap.get(x.statuses.first())?.name)
|
||||
);
|
||||
for (var status of effect.statuses) {
|
||||
if (!currentStatusActiveEffects.find(x => x.statuses.has(status))) {
|
||||
const statusData = statusMap.get(status);
|
||||
acc.push({
|
||||
name: game.i18n.localize(statusData.name),
|
||||
statuses: [status],
|
||||
img: statusData.icon,
|
||||
tint: effect.tint
|
||||
});
|
||||
if (statusData) {
|
||||
acc.push({
|
||||
name: game.i18n.localize(statusData.name),
|
||||
statuses: [status],
|
||||
img: statusData.icon,
|
||||
tint: effect.tint
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,39 +164,49 @@ export const healingTypes = {
|
|||
}
|
||||
};
|
||||
|
||||
export const conditions = {
|
||||
vulnerable: {
|
||||
id: 'vulnerable',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.vulnerable.name',
|
||||
icon: 'icons/magic/control/silhouette-fall-slip-prone.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.vulnerable.description'
|
||||
},
|
||||
hidden: {
|
||||
id: 'hidden',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.hidden.name',
|
||||
icon: 'icons/magic/perception/silhouette-stealth-shadow.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.hidden.description'
|
||||
},
|
||||
restrained: {
|
||||
id: 'restrained',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.restrained.name',
|
||||
icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.restrained.description'
|
||||
export const defeatedConditions = {
|
||||
defeated: {
|
||||
id: 'defeated',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.defeated.name',
|
||||
img: 'icons/magic/control/fear-fright-mask-orange.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.defeated.description'
|
||||
},
|
||||
unconscious: {
|
||||
id: 'unconscious',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.unconscious.name',
|
||||
icon: 'icons/magic/control/sleep-bubble-purple.webp',
|
||||
img: 'icons/magic/control/sleep-bubble-purple.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.unconscious.description'
|
||||
},
|
||||
dead: {
|
||||
id: 'dead',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.dead.name',
|
||||
icon: 'icons/magic/death/grave-tombstone-glow-teal.webp',
|
||||
img: 'icons/magic/death/grave-tombstone-glow-teal.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.dead.description'
|
||||
}
|
||||
};
|
||||
|
||||
export const conditions = {
|
||||
vulnerable: {
|
||||
id: 'vulnerable',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.vulnerable.name',
|
||||
img: 'icons/magic/control/silhouette-fall-slip-prone.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.vulnerable.description'
|
||||
},
|
||||
hidden: {
|
||||
id: 'hidden',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.hidden.name',
|
||||
img: 'icons/magic/perception/silhouette-stealth-shadow.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.hidden.description'
|
||||
},
|
||||
restrained: {
|
||||
id: 'restrained',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.restrained.name',
|
||||
img: 'icons/magic/control/debuff-chains-shackle-movement-red.webp',
|
||||
description: 'DAGGERHEART.CONFIG.Condition.restrained.description'
|
||||
},
|
||||
...defeatedConditions
|
||||
};
|
||||
|
||||
export const defaultRestOptions = {
|
||||
shortRest: () => ({
|
||||
tendToWounds: {
|
||||
|
|
|
|||
|
|
@ -42,4 +42,32 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a localized label array for this item subtype.
|
||||
* @returns {(string | { value: string, icons: string[] })[]} An array of localized strings and damage label objects.
|
||||
*/
|
||||
_getLabels() {
|
||||
const labels = [];
|
||||
const { roll, range, damage } = this;
|
||||
|
||||
if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`))
|
||||
if (range) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`));
|
||||
|
||||
for (const { value, type } of damage.parts) {
|
||||
const str = Roll.replaceFormulaData(value.getFormula(), this.actor?.getRollData() ?? {});
|
||||
|
||||
const icons = Array.from(type)
|
||||
.map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon)
|
||||
.filter(Boolean);
|
||||
|
||||
if (icons.length === 0) {
|
||||
labels.push(str);
|
||||
} else {
|
||||
labels.push({ value: str, icons });
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
import DHBaseAction from './baseAction.mjs';
|
||||
|
||||
export default class DHMacroAction extends DHBaseAction {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
documentUUID: new fields.DocumentUUIDField({ type: 'Macro' })
|
||||
};
|
||||
}
|
||||
static extraSchemas = [...super.extraSchemas, 'macro'];
|
||||
|
||||
async trigger(event, ...args) {
|
||||
const fixUUID = !this.documentUUID.includes('Macro.') ? `Macro.${this.documentUUID}` : this.documentUUID,
|
||||
const fixUUID = !this.macro.includes('Macro.') ? `Macro.${this.macro}` : this.macro,
|
||||
macro = await fromUuid(fixUUID);
|
||||
try {
|
||||
if (!macro) throw new Error(`No macro found for the UUID: ${this.documentUUID}.`);
|
||||
if (!macro) throw new Error(`No macro found for the UUID: ${this.macro}.`);
|
||||
macro.execute();
|
||||
} catch (error) {
|
||||
ui.notifications.error(error);
|
||||
|
|
|
|||
|
|
@ -106,6 +106,28 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
}, []);
|
||||
options.scrollingTextData = textData;
|
||||
}
|
||||
|
||||
if (changes.system?.resources) {
|
||||
const defeatedSettings = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.Automation
|
||||
).defeated;
|
||||
const typeForDefeated = ['character', 'adversary', 'companion'].find(x => x === this.parent.type);
|
||||
if (defeatedSettings.enabled && typeForDefeated) {
|
||||
const resource = typeForDefeated === 'companion' ? 'stress' : 'hitPoints';
|
||||
if (changes.system.resources[resource]) {
|
||||
const becameMax = changes.system.resources[resource].value === this.resources[resource].max;
|
||||
const wasMax =
|
||||
this.resources[resource].value === this.resources[resource].max &&
|
||||
this.resources[resource].value !== changes.system.resources[resource].value;
|
||||
if (becameMax) {
|
||||
this.parent.toggleDefeated(true);
|
||||
} else if (wasMax) {
|
||||
this.parent.toggleDefeated(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onUpdate(changes, options, userId) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}),
|
||||
attack: new ActionField({
|
||||
initial: {
|
||||
name: 'Attack',
|
||||
name: 'Unarmed Attack',
|
||||
img: 'icons/skills/melee/unarmed-punch-fist-yellow-red.webp',
|
||||
_id: foundry.utils.randomID(),
|
||||
systemPath: 'attack',
|
||||
|
|
@ -394,19 +394,22 @@ export default class DhCharacter extends BaseDataActor {
|
|||
return this.parent.effects.find(x => x.type === 'beastform');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unarmed attackwhen no primary or secondary weapon is equipped.
|
||||
* Returns `null` if either weapon is equipped.
|
||||
* If the actor is in beastform, overrides the attack's name and image.
|
||||
*
|
||||
* @returns {DHAttackAction|null}
|
||||
*/
|
||||
get usedUnarmed() {
|
||||
const primaryWeaponEquipped = this.primaryWeapon?.system?.equipped;
|
||||
const secondaryWeaponEquipped = this.secondaryWeapon?.system?.equipped;
|
||||
return !primaryWeaponEquipped && !secondaryWeaponEquipped
|
||||
? {
|
||||
...this.attack,
|
||||
uuid: this.attack.uuid,
|
||||
id: this.attack.id,
|
||||
name: this.activeBeastform ? 'DAGGERHEART.ITEMS.Beastform.attackName' : this.attack.name,
|
||||
img: this.activeBeastform ? 'icons/creatures/claws/claw-straight-brown.webp' : this.attack.img,
|
||||
actor: this.parent
|
||||
}
|
||||
: null;
|
||||
if (this.primaryWeapon?.system?.equipped || this.secondaryWeapon?.system?.equipped) return null;
|
||||
|
||||
const attack = foundry.utils.deepClone(this.attack);
|
||||
if (this.activeBeastform) {
|
||||
attack.name = 'DAGGERHEART.ITEMS.Beastform.attackName';
|
||||
attack.img = 'icons/creatures/claws/claw-straight-brown.webp';
|
||||
}
|
||||
return attack;
|
||||
}
|
||||
|
||||
get sheetLists() {
|
||||
|
|
@ -599,7 +602,20 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
const baseHope = this.resources.hope.value + (this.companion?.system?.resources?.hope ?? 0);
|
||||
let baseHope = this.resources.hope.value;
|
||||
if (this.companion) {
|
||||
for (let levelKey in this.companion.system.levelData.levelups) {
|
||||
const level = this.companion.system.levelData.levelups[levelKey];
|
||||
for (let selection of level.selections) {
|
||||
switch (selection.type) {
|
||||
case 'hope':
|
||||
this.resources.hope.max += selection.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
||||
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,12 +40,14 @@ export default class DhCompanion extends BaseDataActor {
|
|||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({}),
|
||||
value: new fields.NumberField({ integer: true, initial: 0 })
|
||||
value: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
description: new fields.StringField(),
|
||||
core: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
{
|
||||
initial: {
|
||||
experience1: { value: 2 },
|
||||
experience2: { value: 2 }
|
||||
experience1: { value: 2, core: true },
|
||||
experience2: { value: 2, core: true }
|
||||
}
|
||||
}
|
||||
),
|
||||
|
|
@ -134,6 +136,23 @@ export default class DhCompanion extends BaseDataActor {
|
|||
}
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, userId) {
|
||||
const allowed = await super._preUpdate(changes, options, userId);
|
||||
if (allowed === false) return;
|
||||
|
||||
/* The first two experiences are always marked as core */
|
||||
if (changes.system?.experiences && Object.keys(this.experiences).length < 2) {
|
||||
const experiences = new Set(Object.keys(this.experiences));
|
||||
const changeExperiences = new Set(Object.keys(changes.system.experiences));
|
||||
const newExperiences = Array.from(changeExperiences.difference(experiences));
|
||||
|
||||
for (var i = 0; i < Math.min(newExperiences.length, 2 - experiences.size); i++) {
|
||||
const experience = newExperiences[i];
|
||||
changes.system.experiences[experience].core = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
if (this.partner) {
|
||||
await this.partner.update({ 'system.companion': null });
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
if (this.hasTarget) {
|
||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||
this.currentTargets = this.getTargetList();
|
||||
// this.registerTargetHook();
|
||||
|
||||
if (this.targetMode === true && this.hasRoll) {
|
||||
this.targetShort = this.targets.reduce(
|
||||
|
|
|
|||
|
|
@ -8,4 +8,10 @@ export default class DhCombatant extends foundry.abstract.TypeDataModel {
|
|||
actionTokens: new fields.NumberField({ required: true, integer: true, initial: 3 })
|
||||
};
|
||||
}
|
||||
|
||||
get isDefeated() {
|
||||
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions;
|
||||
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
|
||||
return this.defeated || this.actor?.statuses.intersection(defeatedConditions)?.size;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ export { default as BeastformField } from './beastformField.mjs';
|
|||
export { default as DamageField } from './damageField.mjs';
|
||||
export { default as HealingField } from './healingField.mjs';
|
||||
export { default as RollField } from './rollField.mjs';
|
||||
export { default as MacroField } from './macroField.mjs';
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
|
|||
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }),
|
||||
custom: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({ label: 'Custom Formula' }),
|
||||
formula: new FormulaField({ label: 'Formula' })
|
||||
formula: new FormulaField({ label: 'Formula', initial: "" })
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
7
module/data/fields/action/macroField.mjs
Normal file
7
module/data/fields/action/macroField.mjs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
export default class MacroField extends fields.DocumentUUIDField {
|
||||
constructor(context = {}) {
|
||||
super({ type: "Macro" }, context);
|
||||
}
|
||||
}
|
||||
|
|
@ -82,9 +82,10 @@ export class ActionsField extends MappingField {
|
|||
*/
|
||||
export class ActionField extends foundry.data.fields.ObjectField {
|
||||
getModel(value) {
|
||||
if(value && !value.type) value.type = 'attack';
|
||||
return (
|
||||
game.system.api.models.actions.actionsTypes[value.type] ??
|
||||
game.system.api.models.actions.actionsTypes.attack
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +94,6 @@ export class ActionField extends foundry.data.fields.ObjectField {
|
|||
/** @override */
|
||||
_cleanType(value, options) {
|
||||
if (!(typeof value === 'object')) value = {};
|
||||
|
||||
const cls = this.getModel(value);
|
||||
if (cls) return cls.cleanData(value, options);
|
||||
return value;
|
||||
|
|
|
|||
|
|
@ -144,7 +144,8 @@ export default class DHArmor extends AttachableItem {
|
|||
* @returns {(string | { value: string, icons: string[] })[]} An array of localized strings and damage label objects.
|
||||
*/
|
||||
_getLabels() {
|
||||
const labels = [`${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.baseScore}`];
|
||||
const labels = [];
|
||||
if(this.baseScore) labels.push(`${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.baseScore}`)
|
||||
return labels;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ export default class DHDomainCard extends BaseDataItem {
|
|||
const tags = [
|
||||
game.i18n.localize(`DAGGERHEART.CONFIG.DomainCardTypes.${this.type}`),
|
||||
this.domainLabel,
|
||||
`${game.i18n.localize('DAGGERHEART.GENERAL.levelShort')}: ${this.level}`,
|
||||
`${game.i18n.localize('DAGGERHEART.ITEMS.DomainCard.recallCost')}: ${this.recallCost}`
|
||||
];
|
||||
|
||||
|
|
@ -88,15 +89,16 @@ export default class DHDomainCard extends BaseDataItem {
|
|||
* @returns {(string | { value: string, icons: string[] })[]} An array of localized strings and damage label objects.
|
||||
*/
|
||||
_getLabels() {
|
||||
const labels = [
|
||||
game.i18n.localize(`DAGGERHEART.CONFIG.DomainCardTypes.${this.type}`),
|
||||
this.domainLabel,
|
||||
{
|
||||
const labels = [];
|
||||
|
||||
if (this.type) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.DomainCardTypes.${this.type}`));
|
||||
if (this.domainLabel) labels.push(this.domainLabel);
|
||||
if (this.recallCost) {
|
||||
labels.push({
|
||||
value: `${this.recallCost}`, //converts the number to a string
|
||||
icons: ['fa-bolt']
|
||||
}
|
||||
];
|
||||
|
||||
});
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import AttachableItem from './attachableItem.mjs';
|
||||
import { ActionsField, ActionField } from '../fields/actionField.mjs';
|
||||
import { ActionField } from '../fields/actionField.mjs';
|
||||
|
||||
export default class DHWeapon extends AttachableItem {
|
||||
/** @inheritDoc */
|
||||
|
|
@ -18,12 +18,23 @@ export default class DHWeapon extends AttachableItem {
|
|||
const fields = foundry.data.fields;
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1, label: "DAGGERHEART.GENERAL.Tiers.singular" }),
|
||||
tier: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
initial: 1,
|
||||
min: 1,
|
||||
label: 'DAGGERHEART.GENERAL.Tiers.singular'
|
||||
}),
|
||||
equipped: new fields.BooleanField({ initial: false }),
|
||||
|
||||
//SETTINGS
|
||||
secondary: new fields.BooleanField({ initial: false, label: "DAGGERHEART.ITEMS.Weapon.secondaryWeapon" }),
|
||||
burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, initial: 'oneHanded', label: "DAGGERHEART.GENERAL.burden" }),
|
||||
secondary: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon' }),
|
||||
burden: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.burden,
|
||||
initial: 'oneHanded',
|
||||
label: 'DAGGERHEART.GENERAL.burden'
|
||||
}),
|
||||
weaponFeatures: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.StringField({
|
||||
|
|
@ -209,26 +220,23 @@ export default class DHWeapon extends AttachableItem {
|
|||
* @returns {(string | { value: string, icons: string[] })[]} An array of localized strings and damage label objects.
|
||||
*/
|
||||
_getLabels() {
|
||||
const labels = [];
|
||||
const { roll, range, damage } = this.attack;
|
||||
|
||||
const labels = [
|
||||
game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`),
|
||||
game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`)
|
||||
];
|
||||
if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`));
|
||||
if (range) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`));
|
||||
|
||||
for (const { value, type } of damage.parts) {
|
||||
const str = [value.dice];
|
||||
if (value.bonus) str.push(value.bonus.signedString());
|
||||
const str = Roll.replaceFormulaData(value.getFormula(), this.actor?.getRollData() ?? {});
|
||||
|
||||
const icons = Array.from(type)
|
||||
.map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon)
|
||||
.filter(Boolean);
|
||||
|
||||
const labelValue = str.join('');
|
||||
if (icons.length === 0) {
|
||||
labels.push(labelValue);
|
||||
labels.push(str);
|
||||
} else {
|
||||
labels.push({ value: labelValue, icons });
|
||||
labels.push({ value: str, icons });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -404,7 +404,27 @@ export const defaultCompanionTier = {
|
|||
start: 2,
|
||||
end: 10
|
||||
},
|
||||
initialAchievements: {},
|
||||
initialAchievements: {
|
||||
experience: {
|
||||
nr: 1,
|
||||
modifier: 2
|
||||
}
|
||||
},
|
||||
/* Improved this. Quick solution for companions */
|
||||
extraAchievements: {
|
||||
5: {
|
||||
experience: {
|
||||
nr: 1,
|
||||
modifier: 2
|
||||
}
|
||||
},
|
||||
8: {
|
||||
experience: {
|
||||
nr: 1,
|
||||
modifier: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
availableOptions: 1,
|
||||
domainCardByLevel: 0,
|
||||
options: {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
|||
return acc;
|
||||
}, {})
|
||||
: {};
|
||||
|
||||
const domainCards = [...Array(tier.domainCardByLevel).keys()].reduce((acc, _) => {
|
||||
const id = foundry.utils.randomID();
|
||||
acc[id] = { uuid: null, itemUuid: null, level: i };
|
||||
|
|
@ -42,6 +43,20 @@ export class DhLevelup extends foundry.abstract.DataModel {
|
|||
belongingLevels.push(i);
|
||||
}
|
||||
|
||||
/* Improve. Temporary handling for Companion new experiences */
|
||||
Object.keys(tier.extraAchievements ?? {}).forEach(key => {
|
||||
const level = Number(key);
|
||||
if (level >= startLevel && level <= endLevel) {
|
||||
const levelExtras = tier.extraAchievements[level];
|
||||
if (levelExtras.experience) {
|
||||
levels[level].achievements.experiences[foundry.utils.randomID()] = {
|
||||
name: '',
|
||||
modifier: levelExtras.experience.modifier
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tiers[key] = {
|
||||
name: tier.name,
|
||||
belongingLevels: belongingLevels,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,22 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
showGenericStatusEffects: new fields.BooleanField({
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.showGenericStatusEffects.label'
|
||||
}),
|
||||
extendCharacterDescriptions: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.extendCharacterDescriptions.label'
|
||||
}),
|
||||
extendAdversaryDescriptions: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.extendAdversaryDescriptions.label'
|
||||
}),
|
||||
extendEnvironmentDescriptions: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.extendEnvironmentDescriptions.label'
|
||||
}),
|
||||
extendItemDescriptions: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.extendItemDescriptions.label'
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,36 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.playerCanEditSheet.label'
|
||||
}),
|
||||
defeated: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.enabled.label'
|
||||
}),
|
||||
overlay: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.overlay.label'
|
||||
}),
|
||||
characterDefault: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.defeatedConditions,
|
||||
initial: CONFIG.DH.GENERAL.defeatedConditions.unconscious.id,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
|
||||
}),
|
||||
adversaryDefault: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.defeatedConditions,
|
||||
initial: CONFIG.DH.GENERAL.defeatedConditions.defeated.id,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.adversaryDefault.label'
|
||||
}),
|
||||
companionDefault: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.defeatedConditions,
|
||||
initial: CONFIG.DH.GENERAL.defeatedConditions.defeated.id,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,9 +137,10 @@ export default class DamageRoll extends DHRoll {
|
|||
}
|
||||
|
||||
if (config.isCritical && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
||||
const tmpRoll = Roll.fromTerms(part.roll.terms)._evaluateSync({ maximize: true }),
|
||||
criticalBonus = tmpRoll.total - this.constructor.calculateTotalModifiers(tmpRoll);
|
||||
part.roll.terms.push(...this.formatModifier(criticalBonus));
|
||||
const total = part.roll.dice.reduce((acc, term) => acc + term._faces*term._number, 0);
|
||||
if (total > 0) {
|
||||
part.roll.terms.push(...this.formatModifier(total));
|
||||
}
|
||||
}
|
||||
|
||||
/* To Remove When Reaction System */
|
||||
|
|
|
|||
|
|
@ -222,26 +222,27 @@ export const registerRollDiceHooks = () => {
|
|||
)
|
||||
return;
|
||||
|
||||
const actor = await fromUuid(config.source.actor),
|
||||
updates = [];
|
||||
const actor = await fromUuid(config.source.actor);
|
||||
let updates = [];
|
||||
if (!actor) return;
|
||||
if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ key: 'hope', value: 1 });
|
||||
if (config.roll.isCritical) updates.push({ key: 'stress', value: -1 });
|
||||
if (config.roll.result.duality === -1) updates.push({ key: 'fear', value: 1 });
|
||||
if (config.roll.isCritical || config.roll.result.duality === 1)
|
||||
updates.push({ key: 'hope', value: 1, total: -1, enabled: true });
|
||||
if (config.roll.isCritical) updates.push({ key: 'stress', value: 1, total: -1, enabled: true });
|
||||
if (config.roll.result.duality === -1) updates.push({ key: 'fear', value: 1, total: -1, enabled: true });
|
||||
|
||||
if (config.rerolledRoll) {
|
||||
if (config.rerolledRoll.isCritical || config.rerolledRoll.result.duality === 1)
|
||||
updates.push({ key: 'hope', value: -1 });
|
||||
if (config.rerolledRoll.isCritical) updates.push({ key: 'stress', value: 1 });
|
||||
if (config.rerolledRoll.result.duality === -1) updates.push({ key: 'fear', value: -1 });
|
||||
updates.push({ key: 'hope', value: -1, total: 1, enabled: true });
|
||||
if (config.rerolledRoll.isCritical) updates.push({ key: 'stress', value: -1, total: 1, enabled: true });
|
||||
if (config.rerolledRoll.result.duality === -1)
|
||||
updates.push({ key: 'fear', value: -1, total: 1, enabled: true });
|
||||
}
|
||||
|
||||
if (updates.length) {
|
||||
const target = actor.system.partner ?? actor;
|
||||
if (!['dead', 'unconscious'].some(x => actor.statuses.has(x))) {
|
||||
setTimeout(() => {
|
||||
target.modifyResource(updates);
|
||||
}, 50);
|
||||
if (!['dead', 'defeated', 'unconscious'].some(x => actor.statuses.has(x))) {
|
||||
if (config.rerolledRoll) target.modifyResource(updates);
|
||||
else config.costs = [...(config.costs ?? []), ...updates];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,5 +255,7 @@ export const registerRollDiceHooks = () => {
|
|||
const currentCombatant = game.combat.combatants.get(game.combat.current?.combatantId);
|
||||
if (currentCombatant?.actorId == actor.id) ui.combat.setCombatantSpotlight(currentCombatant.id);
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
|||
|
||||
for (const statusId of this.statuses) {
|
||||
const status = CONFIG.statusEffects.find(s => s.id === statusId);
|
||||
tags.push(game.i18n.localize(status.name));
|
||||
if (status) tags.push(game.i18n.localize(status.name));
|
||||
}
|
||||
|
||||
return tags;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
|||
import { LevelOptionType } from '../data/levelTier.mjs';
|
||||
import DHFeature from '../data/item/feature.mjs';
|
||||
import { damageKeyToNumber } from '../helpers/utils.mjs';
|
||||
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
||||
|
||||
export default class DhpActor extends Actor {
|
||||
/**
|
||||
|
|
@ -142,9 +143,6 @@ export default class DhpActor extends Actor {
|
|||
}, {})
|
||||
});
|
||||
this.update(getUpdate());
|
||||
if (this.system.companion) {
|
||||
this.system.companion.update(getUpdate());
|
||||
}
|
||||
}
|
||||
|
||||
if (subclassFeatureState.class) {
|
||||
|
|
@ -195,10 +193,6 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
});
|
||||
this.sheet.render();
|
||||
|
||||
if (this.system.companion) {
|
||||
this.system.companion.updateLevel(newLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -219,16 +213,6 @@ export default class DhpActor extends Actor {
|
|||
core: true
|
||||
}
|
||||
});
|
||||
|
||||
if (this.system.companion) {
|
||||
await this.system.companion.update({
|
||||
[`system.experiences.${experienceKey}`]: {
|
||||
name: '',
|
||||
value: experience.modifier,
|
||||
core: true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -405,6 +389,7 @@ export default class DhpActor extends Actor {
|
|||
};
|
||||
}
|
||||
|
||||
const levelChange = this.system.levelData.level.changed - this.system.levelData.level.current;
|
||||
await this.update({
|
||||
system: {
|
||||
levelData: {
|
||||
|
|
@ -417,8 +402,21 @@ export default class DhpActor extends Actor {
|
|||
});
|
||||
this.sheet.render();
|
||||
|
||||
if (this.system.companion) {
|
||||
this.system.companion.updateLevel(this.system.levelData.level.changed);
|
||||
if (this.system.companion && !this.system.companion.system.levelData.canLevelUp) {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
title: game.i18n.localize('DAGGERHEART.ACTORS.Character.companionLevelup.confirmTitle')
|
||||
},
|
||||
content: game.i18n.format('DAGGERHEART.ACTORS.Character.companionLevelup.confirmText', {
|
||||
name: this.system.companion.name,
|
||||
levelChange: levelChange
|
||||
})
|
||||
});
|
||||
|
||||
if (!confirmed) return;
|
||||
|
||||
await this.system.companion.updateLevel(this.system.companion.system.levelData.level.current + levelChange);
|
||||
new DhCompanionLevelUp(this.system.companion).render({ force: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -720,4 +718,21 @@ export default class DhpActor extends Actor {
|
|||
value: 1
|
||||
});
|
||||
}
|
||||
|
||||
async toggleDefeated(defeatedState) {
|
||||
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
||||
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions;
|
||||
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
|
||||
if (!defeatedState) {
|
||||
for (let defeatedId of defeatedConditions) {
|
||||
await this.toggleStatusEffect(defeatedId, { overlay: settings.overlay, active: defeatedState });
|
||||
}
|
||||
} else {
|
||||
const noDefeatedConditions = this.statuses.intersection(defeatedConditions).size === 0;
|
||||
if (noDefeatedConditions) {
|
||||
const condition = settings[`${this.type}Default`];
|
||||
await this.toggleStatusEffect(condition, { overlay: settings.overlay, active: defeatedState });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||
targetHook = null;
|
||||
targetSelection = null;
|
||||
|
||||
async renderHTML() {
|
||||
const actor = game.actors.get(this.speaker.actor);
|
||||
|
|
@ -24,7 +23,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
|
||||
/** @inheritDoc */
|
||||
prepareData() {
|
||||
if (this.isAuthor && this.targetSelection === null) this.targetSelection = this.system.targets?.length > 0;
|
||||
if (this.isAuthor && this.targetSelection === undefined) this.targetSelection = this.system.targets?.length > 0;
|
||||
super.prepareData();
|
||||
}
|
||||
|
||||
|
|
@ -70,9 +69,13 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
}
|
||||
}
|
||||
|
||||
if(!game.user.isGM && !this.isAuthor && !this.speakerActor?.isOwner) {
|
||||
const buttons = html.querySelectorAll(".ability-card-footer > .ability-use-button");
|
||||
buttons.forEach(b => b.remove());
|
||||
if(!game.user.isGM) {
|
||||
const applyButtons = html.querySelector(".apply-buttons");
|
||||
applyButtons?.remove();
|
||||
if(!this.isAuthor && !this.speakerActor?.isOwner) {
|
||||
const buttons = html.querySelectorAll(".ability-card-footer > .ability-use-button");
|
||||
buttons.forEach(b => b.remove());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,4 +72,8 @@ export default class DHToken extends TokenDocument {
|
|||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
_shouldRecordMovementHistory() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
const longRest = element.dataset.tooltip?.startsWith('#longRest#');
|
||||
if (shortRest || longRest) {
|
||||
const key = element.dataset.tooltip.slice(shortRest ? 11 : 10);
|
||||
const downtimeOptions = shortRest
|
||||
? CONFIG.DH.GENERAL.defaultRestOptions.shortRest()
|
||||
: CONFIG.DH.GENERAL.defaultRestOptions.longRest();
|
||||
|
||||
const move = downtimeOptions[key];
|
||||
const moves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves[
|
||||
element.dataset.restType
|
||||
].moves;
|
||||
const move = moves[key];
|
||||
const description = await TextEditor.enrichHTML(move.description);
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/downtime.hbs`,
|
||||
|
|
|
|||
|
|
@ -251,13 +251,15 @@ export const adjustRange = (rangeVal, decrease) => {
|
|||
};
|
||||
|
||||
export const updateActorTokens = async (actor, update) => {
|
||||
await actor.prototypeToken.update(update);
|
||||
await actor.prototypeToken.update({ ...update });
|
||||
|
||||
/* Update the tokens in all scenes belonging to Actor */
|
||||
for (let token of actor.getDependentTokens()) {
|
||||
const tokenActor = token.baseActor ?? token.actor;
|
||||
if (tokenActor?.id === actor.id) {
|
||||
await token.update(update);
|
||||
await token.update({
|
||||
...update
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -341,7 +343,7 @@ export const itemAbleRollParse = (value, actor, item) => {
|
|||
const model = isItemTarget ? item : actor;
|
||||
|
||||
try {
|
||||
return Roll.replaceFormulaData(slicedValue, model?.getRollData?.() ?? model);
|
||||
return Roll.replaceFormulaData(slicedValue, isItemTarget || !model?.getRollData ? model : model.getRollData());
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
|
|
@ -370,7 +372,7 @@ export function getScrollTextData(resources, resource, key) {
|
|||
|
||||
export function createScrollText(actor, optionsData) {
|
||||
if (actor && optionsData?.length) {
|
||||
actor.getDependentTokens().forEach(token => {
|
||||
actor.getActiveTokens().forEach(token => {
|
||||
optionsData.forEach(data => {
|
||||
const { text, ...options } = data;
|
||||
canvas.interface.createScrollingText(token.getCenterPoint(), data.text, {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ export const preloadHandlebarsTemplates = async function () {
|
|||
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',
|
||||
'systems/daggerheart/templates/ui/combatTracker/combatTrackerSection.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/damage.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/healing.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/resource.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/uuid.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/macro.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/uses.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/roll.hbs',
|
||||
'systems/daggerheart/templates/actionTypes/save.hbs',
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ const registerMenus = () => {
|
|||
hint: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.variantRules.hint'),
|
||||
icon: CONFIG.DH.SETTINGS.menu.VariantRules.Icon,
|
||||
type: DhVariantRuleSettings,
|
||||
restricted: false
|
||||
restricted: true
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@
|
|||
},
|
||||
"_id": "TCKVaVweyJzhEArX",
|
||||
"systemPath": "actions",
|
||||
"type": "",
|
||||
"type": "attack",
|
||||
"description": "",
|
||||
"img": "icons/creatures/claws/claw-curved-jagged-yellow.webp",
|
||||
"chatDisplay": true,
|
||||
|
|
@ -708,4 +708,4 @@
|
|||
"_id": "89yAh30vaNQOALlz",
|
||||
"sort": 500000,
|
||||
"_key": "!actors!89yAh30vaNQOALlz"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -768,4 +769,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!G7jiltRjgvVhZewm"
|
||||
}
|
||||
}
|
||||
|
|
@ -102,7 +102,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/daggers/dagger-bone-black.webp"
|
||||
"img": "icons/weapons/daggers/dagger-bone-black.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -319,4 +320,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!vNIbYQ4YSzNf0WPE"
|
||||
}
|
||||
}
|
||||
|
|
@ -114,7 +114,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/magic/unholy/beam-ringed-impact-purple.webp"
|
||||
"img": "icons/magic/unholy/beam-ringed-impact-purple.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -817,4 +818,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!WPEOIGfclNJxWb87"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/bows/longbow-recurve-leather-brown.webp"
|
||||
"img": "icons/weapons/bows/longbow-recurve-leather-brown.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -393,4 +394,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!JRhrrEg5UroURiAD"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"roll": {
|
||||
"bonus": 0,
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -514,4 +515,4 @@
|
|||
}
|
||||
],
|
||||
"_key": "!actors!0ts6CGd93lLqGZI5"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -528,4 +529,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!h5RuhzGL17dW5FBT"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"range": ""
|
||||
"range": "",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -1284,4 +1285,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!dgH3fW9FTYLaIDvS"
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/creatures/claws/claw-straight-brown.webp"
|
||||
"img": "icons/creatures/claws/claw-straight-brown.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -467,4 +468,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!71qKDLKO3CsrNkdy"
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -441,4 +442,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!B4LZcGuBAHzyVdzy"
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp"
|
||||
"img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -526,4 +527,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!2UeZ0tEe7AzgSJNd"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
]
|
||||
},
|
||||
"name": "Club",
|
||||
"img": "icons/weapons/clubs/club-banded-barbed-black.webp"
|
||||
"img": "icons/weapons/clubs/club-banded-barbed-black.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -598,4 +599,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!8Zkqk1jU09nKL2fy"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/magic/light/beam-rays-magenta.webp"
|
||||
"img": "icons/magic/light/beam-rays-magenta.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -561,4 +562,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!jDmHqGvzg5wjgmxE"
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -313,4 +314,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!99TqczuQipBmaB8i"
|
||||
}
|
||||
}
|
||||
|
|
@ -102,7 +102,8 @@
|
|||
]
|
||||
},
|
||||
"name": "Fist Slam",
|
||||
"img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp"
|
||||
"img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -631,4 +632,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!uOP5oT9QzXPlnf3p"
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +113,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/daggers/dagger-straight-cracked.webp"
|
||||
"img": "icons/weapons/daggers/dagger-straight-cracked.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -379,4 +380,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!ZxWaWPdzFIUPNC62"
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/daggers/dagger-twin-green.webp"
|
||||
"img": "icons/weapons/daggers/dagger-twin-green.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -459,4 +460,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!CBBuEXAlLKFMJdjg"
|
||||
}
|
||||
}
|
||||
|
|
@ -114,7 +114,8 @@
|
|||
]
|
||||
},
|
||||
"range": "far",
|
||||
"img": "icons/weapons/staves/staff-ornate-purple.webp"
|
||||
"img": "icons/weapons/staves/staff-ornate-purple.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -723,4 +724,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!0NxCSugvKQ4W8OYZ"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"range": ""
|
||||
"range": "",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -453,4 +454,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!tyBOpLfigAhI9bU3"
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +95,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -312,4 +313,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!zx99sOGTXicP4SSD"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/magic/nature/root-vines-grow-brown.webp"
|
||||
"img": "icons/magic/nature/root-vines-grow-brown.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -473,4 +474,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!9x2xY9zwc3xzbXo5"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -384,4 +385,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!pnyjIGxxvurcWmTv"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -502,4 +503,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!kE4dfhqmIQpNd44e"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -654,4 +655,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!2VN3BftageoTTIzu"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/magic/symbols/rune-sigil-rough-white-teal.webp"
|
||||
"img": "icons/magic/symbols/rune-sigil-rough-white-teal.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -439,4 +440,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!SxSOkM4bcVOFyjbo"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -474,4 +475,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!5lphJAgzoqZI3VoG"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"bonus": 0,
|
||||
"type": "attack"
|
||||
},
|
||||
"range": ""
|
||||
"range": "",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -421,4 +422,4 @@
|
|||
}
|
||||
],
|
||||
"_key": "!actors!NoRZ1PqB8N5wcIw0"
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/creatures/claws/claw-hooked-curved.webp"
|
||||
"img": "icons/creatures/claws/claw-hooked-curved.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -512,4 +513,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!tBWHW00epmMnkawe"
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/creatures/claws/claw-straight-brown.webp"
|
||||
"img": "icons/creatures/claws/claw-straight-brown.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -499,4 +500,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!wNzeuQLfLUMvgHlQ"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -568,4 +569,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!wR7cFKrHvRzbzhBT"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"bonus": 0,
|
||||
"type": "attack"
|
||||
},
|
||||
"range": ""
|
||||
"range": "",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -411,4 +412,4 @@
|
|||
}
|
||||
],
|
||||
"_key": "!actors!TLzY1nDw0Bu9Ud40"
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -313,4 +314,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!P7h54ZePFPHpYwvB"
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@
|
|||
"img": "icons/weapons/polearms/spear-flared-steel.webp",
|
||||
"_id": "jmrgFi8AUL6LTbtU",
|
||||
"systemPath": "actions",
|
||||
"type": "",
|
||||
"type": "attack",
|
||||
"description": "",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
|
|
@ -435,4 +435,4 @@
|
|||
"_id": "bfhVWMBUh61b9J6n",
|
||||
"sort": 0,
|
||||
"_key": "!actors!bfhVWMBUh61b9J6n"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
]
|
||||
},
|
||||
"img": "icons/creatures/claws/claw-hooked-barbed.webp",
|
||||
"range": ""
|
||||
"range": "",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -411,4 +412,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!ChwwVqowFw8hJQwT"
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -399,4 +400,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!OsLG2BjaEdTZUJU9"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/staves/staff-animal-skull-bull.webp"
|
||||
"img": "icons/weapons/staves/staff-animal-skull-bull.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -646,4 +647,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!PELRry1vqjBzSAlr"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -452,4 +453,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!8VZIgU12cB3cvlyH"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -484,4 +485,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!YnObCleGjPT7yqEc"
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@
|
|||
"img": "icons/creatures/claws/claw-talons-glowing-orange.webp",
|
||||
"_id": "W2KpXQNCg6Nnorbz",
|
||||
"systemPath": "actions",
|
||||
"type": "",
|
||||
"type": "attack",
|
||||
"description": "",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
|
|
@ -745,4 +745,4 @@
|
|||
"_id": "OMQ0v6PE8s1mSU0K",
|
||||
"sort": 900000,
|
||||
"_key": "!actors!OMQ0v6PE8s1mSU0K"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
"bonus": -2,
|
||||
"type": "attack"
|
||||
},
|
||||
"range": ""
|
||||
"range": "",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -453,4 +454,4 @@
|
|||
}
|
||||
],
|
||||
"_key": "!actors!IIWV4ysJPFPnTP7W"
|
||||
}
|
||||
}
|
||||
|
|
@ -100,7 +100,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -343,4 +344,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!4PfLnaCrOcMdb4dK"
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,8 @@
|
|||
"roll": {
|
||||
"bonus": 1,
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -313,4 +314,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!5s8wSvpyC5rxY5aD"
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -535,4 +536,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!fmfntuJ8mHRCAktP"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -658,4 +659,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!8KWVLWXFhlY2kYx0"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/bows/shortbow-recurve-yellow.webp"
|
||||
"img": "icons/weapons/bows/shortbow-recurve-yellow.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -621,4 +622,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!8mJYMpbLTb8qIOrr"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -632,4 +633,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!dsfB3YhoL5SudvS2"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -600,4 +601,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!xIICT6tEdnA7dKDV"
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/creatures/slimes/slime-movement-dripping-pseudopods-green.webp"
|
||||
"img": "icons/creatures/slimes/slime-movement-dripping-pseudopods-green.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -601,4 +602,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!SHXedd9zZPVfUgUa"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -371,4 +372,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!kabueAo6BALApWqp"
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +95,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/skills/melee/sword-shield-stylized-white.webp"
|
||||
"img": "icons/skills/melee/sword-shield-stylized-white.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -376,4 +377,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!VENwg7xEFcYObjmT"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/weapons/polearms/spear-hooked-rounded.webp"
|
||||
"img": "icons/weapons/polearms/spear-hooked-rounded.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -378,4 +379,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!uRtghKE9mHlII4rs"
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -388,4 +389,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!mK3A5FTx6k8iPU3F"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -665,4 +666,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!i2UNbRvgyoSs07M6"
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"img": "icons/skills/melee/strike-blade-hooked-orange-blue.webp"
|
||||
"img": "icons/skills/melee/strike-blade-hooked-orange-blue.webp",
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -611,4 +612,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!r1mbfSSwKWdcFdAU"
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -572,4 +573,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!6hbqmxDXFOzZJDk4"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@
|
|||
"base": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "attack"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -602,4 +603,4 @@
|
|||
],
|
||||
"effects": [],
|
||||
"_key": "!actors!MI126iMOOobQ1Obn"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue