mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
Feature/443 adversary action roll type (#456)
* Some tests * Filter types choices * Resource/Uses max as FormulaField * Removed isReversed on item resources * Stuffs --------- Co-authored-by: WBHarry <williambjrklund@gmail.com>
This commit is contained in:
parent
2608c4a5ae
commit
8e516df7cb
19 changed files with 172 additions and 86 deletions
|
|
@ -716,7 +716,7 @@
|
||||||
"name": "Hope",
|
"name": "Hope",
|
||||||
"abbreviation": "HO"
|
"abbreviation": "HO"
|
||||||
},
|
},
|
||||||
"armorStack": {
|
"armorSlot": {
|
||||||
"name": "Armor Slot",
|
"name": "Armor Slot",
|
||||||
"abbreviation": "AS"
|
"abbreviation": "AS"
|
||||||
},
|
},
|
||||||
|
|
@ -1381,6 +1381,7 @@
|
||||||
"imagePath": "Image Path",
|
"imagePath": "Image Path",
|
||||||
"inactiveEffects": "Inactive Effects",
|
"inactiveEffects": "Inactive Effects",
|
||||||
"inventory": "Inventory",
|
"inventory": "Inventory",
|
||||||
|
"itemResource": "Item Resource",
|
||||||
"level": "Level",
|
"level": "Level",
|
||||||
"levelUp": "Level Up",
|
"levelUp": "Level Up",
|
||||||
"loadout": "Loadout",
|
"loadout": "Loadout",
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
await super.close({});
|
await super.close({});
|
||||||
}
|
}
|
||||||
|
|
||||||
static async armorStackQuery({ actorId, damage, type }) {
|
static async armorSlotQuery({ actorId, damage, type }) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const actor = await fromUuid(actorId);
|
const actor = await fromUuid(actorId);
|
||||||
if (!actor || !actor?.isOwner) reject();
|
if (!actor || !actor?.isOwner) reject();
|
||||||
|
|
|
||||||
|
|
@ -108,9 +108,11 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
||||||
context.hasBaseDamage = !!this.action.parent.attack;
|
context.hasBaseDamage = !!this.action.parent.attack;
|
||||||
context.getEffectDetails = this.getEffectDetails.bind(this);
|
context.getEffectDetails = this.getEffectDetails.bind(this);
|
||||||
context.costOptions = this.getCostOptions();
|
context.costOptions = this.getCostOptions();
|
||||||
|
context.getRollTypeOptions = this.getRollTypeOptions();
|
||||||
context.disableOption = this.disableOption.bind(this);
|
context.disableOption = this.disableOption.bind(this);
|
||||||
context.isNPC = this.action.actor?.isNPC;
|
context.isNPC = this.action.actor?.isNPC;
|
||||||
context.baseSaveDifficulty = this.action.actor?.baseSaveDifficulty;
|
context.baseSaveDifficulty = this.action.actor?.baseSaveDifficulty;
|
||||||
|
context.baseAttackBonus = this.action.actor?.system.attack?.roll.bonus;
|
||||||
context.hasRoll = this.action.hasRoll;
|
context.hasRoll = this.action.hasRoll;
|
||||||
|
|
||||||
const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers;
|
const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers;
|
||||||
|
|
@ -131,14 +133,23 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
||||||
const resource = this.action.parent.resource;
|
const resource = this.action.parent.resource;
|
||||||
if (resource) {
|
if (resource) {
|
||||||
options[this.action.parent.parent.id] = {
|
options[this.action.parent.parent.id] = {
|
||||||
label: this.action.parent.parent.name,
|
label: "DAGGERHEART.GENERAL.itemResource",
|
||||||
group: 'TYPES.Actor.character'
|
group: 'Global'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRollTypeOptions() {
|
||||||
|
const types = foundry.utils.deepClone(CONFIG.DH.GENERAL.rollTypes);
|
||||||
|
if(!this.action.actor) return types;
|
||||||
|
Object.values(types).forEach(t => {
|
||||||
|
if(this.action.actor.type !== 'character' && t.playerOnly) delete types[t.id];
|
||||||
|
})
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
disableOption(index, costOptions, choices) {
|
disableOption(index, costOptions, choices) {
|
||||||
const filtered = foundry.utils.deepClone(costOptions);
|
const filtered = foundry.utils.deepClone(costOptions);
|
||||||
Object.keys(filtered).forEach(o => {
|
Object.keys(filtered).forEach(o => {
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ export const healingTypes = {
|
||||||
label: 'DAGGERHEART.CONFIG.HealingType.hope.name',
|
label: 'DAGGERHEART.CONFIG.HealingType.hope.name',
|
||||||
abbreviation: 'DAGGERHEART.CONFIG.HealingType.hope.abbreviation'
|
abbreviation: 'DAGGERHEART.CONFIG.HealingType.hope.abbreviation'
|
||||||
},
|
},
|
||||||
armorStack: {
|
armorSlot: {
|
||||||
id: 'armorStack',
|
id: 'armorSlot',
|
||||||
label: 'DAGGERHEART.CONFIG.HealingType.armorStack.name',
|
label: 'DAGGERHEART.CONFIG.HealingType.armorSlot.name',
|
||||||
abbreviation: 'DAGGERHEART.CONFIG.HealingType.armorStack.abbreviation'
|
abbreviation: 'DAGGERHEART.CONFIG.HealingType.armorSlot.abbreviation'
|
||||||
},
|
},
|
||||||
fear: {
|
fear: {
|
||||||
id: 'fear',
|
id: 'fear',
|
||||||
|
|
@ -199,7 +199,7 @@ export const defaultRestOptions = {
|
||||||
actionType: 'action',
|
actionType: 'action',
|
||||||
chatDisplay: false,
|
chatDisplay: false,
|
||||||
healing: {
|
healing: {
|
||||||
applyTo: healingTypes.armorStack.id,
|
applyTo: healingTypes.armorSlot.id,
|
||||||
value: {
|
value: {
|
||||||
custom: {
|
custom: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
@ -287,7 +287,7 @@ export const defaultRestOptions = {
|
||||||
actionType: 'action',
|
actionType: 'action',
|
||||||
chatDisplay: false,
|
chatDisplay: false,
|
||||||
healing: {
|
healing: {
|
||||||
applyTo: healingTypes.armorStack.id,
|
applyTo: healingTypes.armorSlot.id,
|
||||||
value: {
|
value: {
|
||||||
custom: {
|
custom: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
@ -425,8 +425,8 @@ export const refreshTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const abilityCosts = {
|
export const abilityCosts = {
|
||||||
hp: {
|
hitPoints: {
|
||||||
id: 'hp',
|
id: 'hitPoints',
|
||||||
label: 'DAGGERHEART.CONFIG.HealingType.hitPoints.name',
|
label: 'DAGGERHEART.CONFIG.HealingType.hitPoints.name',
|
||||||
group: 'Global'
|
group: 'Global'
|
||||||
},
|
},
|
||||||
|
|
@ -473,11 +473,13 @@ export const rollTypes = {
|
||||||
},
|
},
|
||||||
spellcast: {
|
spellcast: {
|
||||||
id: 'spellcast',
|
id: 'spellcast',
|
||||||
label: 'DAGGERHEART.CONFIG.RollTypes.spellcast.name'
|
label: 'DAGGERHEART.CONFIG.RollTypes.spellcast.name',
|
||||||
|
playerOnly: true
|
||||||
},
|
},
|
||||||
trait: {
|
trait: {
|
||||||
id: 'trait',
|
id: 'trait',
|
||||||
label: 'DAGGERHEART.CONFIG.RollTypes.trait.name'
|
label: 'DAGGERHEART.CONFIG.RollTypes.trait.name',
|
||||||
|
playerOnly: true
|
||||||
},
|
},
|
||||||
diceSet: {
|
diceSet: {
|
||||||
id: 'diceSet',
|
id: 'diceSet',
|
||||||
|
|
|
||||||
|
|
@ -604,7 +604,7 @@ export const weaponFeatures = {
|
||||||
img: 'icons/skills/melee/hand-grip-sword-strike-orange.webp',
|
img: 'icons/skills/melee/hand-grip-sword-strike-orange.webp',
|
||||||
cost: [
|
cost: [
|
||||||
{
|
{
|
||||||
type: 'armorStack',
|
type: 'armorSlot',
|
||||||
value: 1
|
value: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -185,13 +185,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
|
|
||||||
prepareRoll() {
|
prepareRoll() {
|
||||||
const roll = {
|
const roll = {
|
||||||
modifiers: this.modifiers,
|
baseModifiers: this.roll.getModifier(),
|
||||||
trait: this.roll?.trait,
|
|
||||||
label: 'Attack',
|
label: 'Attack',
|
||||||
type: this.actionType,
|
type: this.actionType,
|
||||||
difficulty: this.roll?.difficulty,
|
difficulty: this.roll?.difficulty,
|
||||||
formula: this.roll.getFormula(),
|
formula: this.roll.getFormula(),
|
||||||
bonus: this.roll.bonus,
|
|
||||||
advantage: CONFIG.DH.ACTIONS.advantageState[this.roll.advState].value
|
advantage: CONFIG.DH.ACTIONS.advantageState[this.roll.advState].value
|
||||||
};
|
};
|
||||||
if (this.roll?.type === 'diceSet') roll.lite = true;
|
if (this.roll?.type === 'diceSet') roll.lite = true;
|
||||||
|
|
@ -205,6 +203,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
|
|
||||||
async consume(config) {
|
async consume(config) {
|
||||||
const usefulResources = foundry.utils.deepClone(this.actor.system.resources);
|
const usefulResources = foundry.utils.deepClone(this.actor.system.resources);
|
||||||
|
|
||||||
for (var cost of config.costs) {
|
for (var cost of config.costs) {
|
||||||
if (cost.keyIsID) {
|
if (cost.keyIsID) {
|
||||||
usefulResources[cost.key] = {
|
usefulResources[cost.key] = {
|
||||||
|
|
@ -225,19 +224,16 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
keyIsID: resource.keyIsID
|
keyIsID: resource.keyIsID
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
console.log(resources)
|
||||||
await this.actor.modifyResource(resources);
|
await this.actor.modifyResource(resources);
|
||||||
if (config.uses?.enabled) {
|
if (config.uses?.enabled)
|
||||||
const newActions = foundry.utils.getProperty(this.item.system, this.systemPath).map(x => x.toObject());
|
this.update({ 'uses.value': this.uses.value + 1 });
|
||||||
newActions[this.index].uses.value++;
|
|
||||||
await this.item.update({ [`system.${this.systemPath}`]: newActions });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
/* ROLL */
|
/* ROLL */
|
||||||
get hasRoll() {
|
get hasRoll() {
|
||||||
return !!this.roll?.type || !!this.roll?.bonus;
|
return !!this.roll?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
get modifiers() {
|
get modifiers() {
|
||||||
|
|
@ -301,17 +297,16 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
/* SAVE */
|
/* SAVE */
|
||||||
async rollSave(actor, event, message) {
|
async rollSave(actor, event, message) {
|
||||||
if (!actor) return;
|
if (!actor) return;
|
||||||
return actor
|
return actor.diceRoll({
|
||||||
.diceRoll({
|
event,
|
||||||
event,
|
title: 'Roll Save',
|
||||||
title: 'Roll Save',
|
roll: {
|
||||||
roll: {
|
trait: this.save.trait,
|
||||||
trait: this.save.trait,
|
difficulty: this.save.difficulty ?? this.actor?.baseSaveDifficulty,
|
||||||
difficulty: this.save.difficulty ?? this.actor?.baseSaveDifficulty,
|
type: 'reaction'
|
||||||
type: 'reaction'
|
},
|
||||||
},
|
data: actor.getRollData()
|
||||||
data: actor.getRollData()
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSaveMessage(result, message, targetId) {
|
updateSaveMessage(result, message, targetId) {
|
||||||
|
|
@ -324,7 +319,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
else updateMsg();
|
else updateMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
static rollSaveQuery({ actionId, actorId, event, message }) {
|
static rollSaveQuery({ actionId, actorId, event, message }) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const actor = await fromUuid(actorId),
|
const actor = await fromUuid(actorId),
|
||||||
action = await fromUuid(actionId);
|
action = await fromUuid(actionId);
|
||||||
|
|
|
||||||
|
|
@ -563,6 +563,12 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
||||||
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;
|
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;
|
||||||
|
|
||||||
|
this.resources.armor = {
|
||||||
|
value: this.armor.system.marks.value,
|
||||||
|
max: this.armorScore,
|
||||||
|
isReversed: true
|
||||||
|
};
|
||||||
|
|
||||||
this.attack.damage.parts[0].value.custom.formula = `@prof${this.basicAttackDamageDice}${this.rules.attack.damage.bonus ? ` + ${this.rules.attack.damage.bonus}` : ''}`;
|
this.attack.damage.parts[0].value.custom.formula = `@prof${this.basicAttackDamageDice}${this.rules.attack.damage.bonus ? ` + ${this.rules.attack.damage.bonus}` : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,19 @@ export default class CostField extends fields.ArrayField {
|
||||||
}
|
}
|
||||||
|
|
||||||
static calcCosts(costs) {
|
static calcCosts(costs) {
|
||||||
|
console.log(costs, CostField.getResources.call(this, costs))
|
||||||
|
const resources = CostField.getResources.call(this, costs);
|
||||||
return costs.map(c => {
|
return costs.map(c => {
|
||||||
c.scale = c.scale ?? 1;
|
c.scale = c.scale ?? 1;
|
||||||
c.step = c.step ?? 1;
|
c.step = c.step ?? 1;
|
||||||
c.total = c.value * c.scale * c.step;
|
c.total = c.value + ((c.scale - 1) * c.step);
|
||||||
c.enabled = c.hasOwnProperty('enabled') ? c.enabled : true;
|
c.enabled = c.hasOwnProperty('enabled') ? c.enabled : true;
|
||||||
|
c.max = c.key === 'fear'
|
||||||
|
? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear)
|
||||||
|
: resources[c.key].isReversed
|
||||||
|
? resources[c.key].max
|
||||||
|
: resources[c.key].value
|
||||||
|
if(c.scalable) c.maxStep = Math.floor(c.max / c.step);
|
||||||
return c;
|
return c;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -51,9 +59,11 @@ export default class CostField extends fields.ArrayField {
|
||||||
const resources = CostField.getResources.call(this, realCosts);
|
const resources = CostField.getResources.call(this, realCosts);
|
||||||
return realCosts.reduce(
|
return realCosts.reduce(
|
||||||
(a, c) =>
|
(a, c) =>
|
||||||
a && resources[c.key].isReversed
|
!resources[c.key]
|
||||||
? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max
|
? a
|
||||||
: resources[c.key]?.value >= (c.total ?? c.value),
|
: a && resources[c.key].isReversed
|
||||||
|
? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max
|
||||||
|
: resources[c.key]?.value >= (c.total ?? c.value),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -61,10 +71,11 @@ export default class CostField extends fields.ArrayField {
|
||||||
static getResources(costs) {
|
static getResources(costs) {
|
||||||
const actorResources = this.actor.system.resources;
|
const actorResources = this.actor.system.resources;
|
||||||
const itemResources = {};
|
const itemResources = {};
|
||||||
for (var itemResource of costs) {
|
for (let itemResource of costs) {
|
||||||
if (itemResource.keyIsID) {
|
if (itemResource.keyIsID) {
|
||||||
itemResources[itemResource.key] = {
|
itemResources[itemResource.key] = {
|
||||||
value: this.parent.resource.value ?? 0
|
value: this.parent.resource.value ?? 0,
|
||||||
|
max: CostField.formatMax.call(this, this.parent?.resource?.max)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -79,4 +90,13 @@ export default class CostField extends fields.ArrayField {
|
||||||
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
||||||
return realCosts;
|
return realCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static formatMax(max) {
|
||||||
|
max ??= 0;
|
||||||
|
if (isNaN(max)) {
|
||||||
|
const roll = Roll.replaceFormulaData(max, this.getRollData());
|
||||||
|
max = roll.total;
|
||||||
|
}
|
||||||
|
return Number(max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,43 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
return formula;
|
return formula;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getModifier() {
|
||||||
|
const modifiers = [];
|
||||||
|
if(!this.parent?.actor) return modifiers;
|
||||||
|
switch (this.parent.actor.type) {
|
||||||
|
case 'character':
|
||||||
|
const trait = this.useDefault || !this.trait ? (this.parent.item.system.attack.roll.trait ?? 'agility') : this.trait;
|
||||||
|
if(this.type === CONFIG.DH.GENERAL.rollTypes.attack.id || this.type === CONFIG.DH.GENERAL.rollTypes.trait.id)
|
||||||
|
modifiers.push(
|
||||||
|
{
|
||||||
|
label: `DAGGERHEART.CONFIG.Traits.${trait}.name`,
|
||||||
|
value: this.parent.actor.system.traits[trait].value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else if(this.type === CONFIG.DH.GENERAL.rollTypes.spellcast.id)
|
||||||
|
modifiers.push(
|
||||||
|
{
|
||||||
|
label: `DAGGERHEART.CONFIG.RollTypes.spellcast.name`,
|
||||||
|
value: this.parent.actor.system.spellcastModifier
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 'companion':
|
||||||
|
case 'adversary':
|
||||||
|
if(this.type === CONFIG.DH.GENERAL.rollTypes.attack.id)
|
||||||
|
modifiers.push(
|
||||||
|
{
|
||||||
|
label: 'Bonus to Hit',
|
||||||
|
value: this.bonus ?? this.parent.actor.system.attack.roll.bonus
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class RollField extends fields.EmbeddedDataField {
|
export default class RollField extends fields.EmbeddedDataField {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
import FormulaField from "../formulaField.mjs";
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class UsesField extends fields.SchemaField {
|
export default class UsesField extends fields.SchemaField {
|
||||||
constructor(options = {}, context = {}) {
|
constructor(options = {}, context = {}) {
|
||||||
const usesFields = {
|
const usesFields = {
|
||||||
value: new fields.NumberField({ nullable: true, initial: null }),
|
value: new fields.NumberField({ nullable: true, initial: null }),
|
||||||
max: new fields.NumberField({ nullable: true, initial: null }),
|
max: new FormulaField({ nullable: true, initial: null, deterministic: true }),
|
||||||
recovery: new fields.StringField({
|
recovery: new fields.StringField({
|
||||||
choices: CONFIG.DH.GENERAL.refreshTypes,
|
choices: CONFIG.DH.GENERAL.refreshTypes,
|
||||||
initial: null,
|
initial: null,
|
||||||
|
|
@ -33,6 +35,11 @@ export default class UsesField extends fields.SchemaField {
|
||||||
|
|
||||||
static hasUses(uses) {
|
static hasUses(uses) {
|
||||||
if (!uses) return true;
|
if (!uses) return true;
|
||||||
return (uses.hasOwnProperty('enabled') && !uses.enabled) || uses.value + 1 <= uses.max;
|
let max = uses.max ?? 0;
|
||||||
|
if(isNaN(max)) {
|
||||||
|
const roll = new Roll(Roll.replaceFormulaData(uses.max, this.getRollData())).evaluateSync();
|
||||||
|
max = roll.total;
|
||||||
|
}
|
||||||
|
return (uses.hasOwnProperty('enabled') && !uses.enabled) || uses.value + 1 <= max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
import { addLinkedItemsDiff, updateLinkedItemApps } from '../../helpers/utils.mjs';
|
import { addLinkedItemsDiff, updateLinkedItemApps } from '../../helpers/utils.mjs';
|
||||||
import { ActionsField } from '../fields/actionField.mjs';
|
import { ActionsField } from '../fields/actionField.mjs';
|
||||||
|
import FormulaField from '../fields/formulaField.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
initial: CONFIG.DH.ITEM.itemResourceTypes.simple
|
initial: CONFIG.DH.ITEM.itemResourceTypes.simple
|
||||||
}),
|
}),
|
||||||
value: new fields.NumberField({ integer: true, min: 0, initial: 0 }),
|
value: new fields.NumberField({ integer: true, min: 0, initial: 0 }),
|
||||||
max: new fields.StringField({ nullable: true, initial: null }),
|
max: new FormulaField({ nullable: true, initial: null, deterministic: true }),
|
||||||
icon: new fields.StringField(),
|
icon: new fields.StringField(),
|
||||||
recovery: new fields.StringField({
|
recovery: new fields.StringField({
|
||||||
choices: CONFIG.DH.GENERAL.refreshTypes,
|
choices: CONFIG.DH.GENERAL.refreshTypes,
|
||||||
|
|
|
||||||
|
|
@ -124,13 +124,7 @@ export default class D20Roll extends DHRoll {
|
||||||
}
|
}
|
||||||
|
|
||||||
applyBaseBonus() {
|
applyBaseBonus() {
|
||||||
const modifiers = [];
|
const modifiers = foundry.utils.deepClone(this.options.roll.baseModifiers) ?? [];
|
||||||
|
|
||||||
if (this.options.roll.bonus)
|
|
||||||
modifiers.push({
|
|
||||||
label: 'Bonus to Hit',
|
|
||||||
value: this.options.roll.bonus
|
|
||||||
});
|
|
||||||
|
|
||||||
modifiers.push(...this.getBonus(`roll.${this.options.type}`, `${this.options.type?.capitalize()} Bonus`));
|
modifiers.push(...this.getBonus(`roll.${this.options.type}`, `${this.options.type?.capitalize()} Bonus`));
|
||||||
modifiers.push(
|
modifiers.push(
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,7 @@ export default class DhpActor extends Actor {
|
||||||
this.system.armor &&
|
this.system.armor &&
|
||||||
this.#canReduceDamage(hpDamage.value, hpDamage.damageTypes)
|
this.#canReduceDamage(hpDamage.value, hpDamage.damageTypes)
|
||||||
) {
|
) {
|
||||||
const armorStackResult = await this.owner.query('armorStack', {
|
const armorSlotResult = await this.owner.query('armorSlot', {
|
||||||
actorId: this.uuid,
|
actorId: this.uuid,
|
||||||
damage: hpDamage.value,
|
damage: hpDamage.value,
|
||||||
type: [...hpDamage.damageTypes]
|
type: [...hpDamage.damageTypes]
|
||||||
|
|
@ -490,11 +490,11 @@ export default class DhpActor extends Actor {
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (armorStackResult) {
|
if (armorSlotResult) {
|
||||||
const { modifiedDamage, armorSpent, stressSpent } = armorStackResult;
|
const { modifiedDamage, armorSpent, stressSpent } = armorSlotResult;
|
||||||
updates.find(u => u.key === 'hitPoints').value = modifiedDamage;
|
updates.find(u => u.key === 'hitPoints').value = modifiedDamage;
|
||||||
updates.push(
|
updates.push(
|
||||||
...(armorSpent ? [{ value: armorSpent, key: 'armorStack' }] : []),
|
...(armorSpent ? [{ value: armorSpent, key: 'armor' }] : []),
|
||||||
...(stressSpent ? [{ value: stressSpent, key: 'stress' }] : [])
|
...(stressSpent ? [{ value: stressSpent, key: 'stress' }] : [])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -569,6 +569,7 @@ export default class DhpActor extends Actor {
|
||||||
armor: { target: this.system.armor, resources: {} },
|
armor: { target: this.system.armor, resources: {} },
|
||||||
items: {}
|
items: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
resources.forEach(r => {
|
resources.forEach(r => {
|
||||||
if (r.keyIsID) {
|
if (r.keyIsID) {
|
||||||
updates.items[r.key] = {
|
updates.items[r.key] = {
|
||||||
|
|
@ -584,7 +585,7 @@ export default class DhpActor extends Actor {
|
||||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) + r.value
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) + r.value
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'armorStack':
|
case 'armor':
|
||||||
updates.armor.resources['system.marks.value'] = Math.max(
|
updates.armor.resources['system.marks.value'] = Math.max(
|
||||||
Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore),
|
Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore),
|
||||||
0
|
0
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export default class RegisterHandlebarsHelpers {
|
||||||
includes: this.includes,
|
includes: this.includes,
|
||||||
times: this.times,
|
times: this.times,
|
||||||
damageFormula: this.damageFormula,
|
damageFormula: this.damageFormula,
|
||||||
|
formulaValue: this.formulaValue,
|
||||||
damageSymbols: this.damageSymbols,
|
damageSymbols: this.damageSymbols,
|
||||||
rollParsed: this.rollParsed,
|
rollParsed: this.rollParsed,
|
||||||
hasProperty: foundry.utils.hasProperty,
|
hasProperty: foundry.utils.hasProperty,
|
||||||
|
|
@ -39,6 +40,15 @@ export default class RegisterHandlebarsHelpers {
|
||||||
return instances.join(traitTotal > 0 ? ' + ' : ' - ');
|
return instances.join(traitTotal > 0 ? ' + ' : ' - ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static formulaValue(formula, item) {
|
||||||
|
if(isNaN(formula)) {
|
||||||
|
const data = item.getRollData.bind(item)(),
|
||||||
|
roll = new Roll(Roll.replaceFormulaData(formula, data)).evaluateSync();
|
||||||
|
formula = roll.total;
|
||||||
|
}
|
||||||
|
return formula;
|
||||||
|
}
|
||||||
|
|
||||||
static damageSymbols(damageParts) {
|
static damageSymbols(damageParts) {
|
||||||
const symbols = [...new Set(damageParts.reduce((a, c) => a.concat([...c.type]), []))].map(
|
const symbols = [...new Set(damageParts.reduce((a, c) => a.concat([...c.type]), []))].map(
|
||||||
p => CONFIG.DH.GENERAL.damageTypes[p].icon
|
p => CONFIG.DH.GENERAL.damageTypes[p].icon
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ export const registerSocketHooks = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const registerUserQueries = () => {
|
export const registerUserQueries = () => {
|
||||||
CONFIG.queries.armorStack = DamageReductionDialog.armorStackQuery;
|
CONFIG.queries.armorSlot = DamageReductionDialog.armorSlotQuery;
|
||||||
CONFIG.queries.reactionRoll = game.system.api.models.actions.actionsTypes.base.rollSaveQuery;
|
CONFIG.queries.reactionRoll = game.system.api.models.actions.actionsTypes.base.rollSaveQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
{{#each source as |cost index|}}
|
{{#each source as |cost index|}}
|
||||||
<div class="nest-inputs">
|
<div class="nest-inputs">
|
||||||
{{formField ../fields.scalable label="Scalable" value=cost.scalable name=(concat "cost." index ".scalable") classes="checkbox"}}
|
{{formField ../fields.scalable label="Scalable" value=cost.scalable name=(concat "cost." index ".scalable") classes="checkbox"}}
|
||||||
{{formField ../fields.key choices=(@root.disableOption index @root.costOptions ../source) label="Resource" value=cost.key name=(concat "cost." index ".key") localize=true}}
|
{{formField ../fields.key choices=(@root.disableOption index @root.costOptions ../source) label="Resource" value=cost.key name=(concat "cost." index ".key") localize=true blank=false}}
|
||||||
{{formField ../fields.value label="Amount" value=cost.value name=(concat "cost." index ".value")}}
|
{{formField ../fields.value label="Amount" value=cost.value name=(concat "cost." index ".value")}}
|
||||||
{{formField ../fields.step label="Step" value=cost.step name=(concat "cost." index ".step") disabled=(not cost.scalable)}}
|
{{formField ../fields.step label="Step" value=cost.step name=(concat "cost." index ".step") disabled=(not cost.scalable)}}
|
||||||
<a class="btn" data-tooltip="{{localize "CONTROLS.CommonDelete"}}" data-action="removeElement" data-index="{{index}}"><i class="fas fa-trash"></i></a>
|
<a class="btn" data-tooltip="{{localize "CONTROLS.CommonDelete"}}" data-action="removeElement" data-index="{{index}}"><i class="fas fa-trash"></i></a>
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,27 @@
|
||||||
Roll
|
Roll
|
||||||
{{#if @root.hasBaseDamage}}{{formInput fields.useDefault name="roll.useDefault" value=source.useDefault dataset=(object tooltip="Use default Item values" tooltipDirection="UP")}}{{/if}}
|
{{#if @root.hasBaseDamage}}{{formInput fields.useDefault name="roll.useDefault" value=source.useDefault dataset=(object tooltip="Use default Item values" tooltipDirection="UP")}}{{/if}}
|
||||||
</legend>
|
</legend>
|
||||||
{{#if @root.isNPC}}
|
|
||||||
{{formField fields.bonus label="Bonus" name="roll.bonus" value=source.bonus}}
|
{{formField fields.type label="Type" name="roll.type" value=source.type localize=true choices=@root.getRollTypeOptions}}
|
||||||
{{formField fields.advState label= "Advantage State" name="roll.advState" value=source.advState localize=true}}
|
{{#if (eq source.type "diceSet")}}
|
||||||
|
<div class="nest-inputs">
|
||||||
|
{{formField fields.diceRolling.fields.multiplier name="roll.diceRolling.multiplier" value=source.diceRolling.multiplier localize=true}}
|
||||||
|
{{#if (eq source.diceRolling.multiplier 'flat')}}{{formField fields.diceRolling.fields.flatMultiplier value=source.diceRolling.flatMultiplier name="roll.diceRolling.flatMultiplier" localize=true }}{{/if}}
|
||||||
|
{{formField fields.diceRolling.fields.dice name="roll.diceRolling.dice" value=source.diceRolling.dice localize=true}}
|
||||||
|
{{formField fields.diceRolling.fields.compare name="roll.diceRolling.compare" value=source.diceRolling.compare localize=true blank=""}}
|
||||||
|
{{formField fields.diceRolling.fields.treshold name="roll.diceRolling.treshold" value=source.diceRolling.treshold localize=true}}
|
||||||
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{formField fields.type label="Type" name="roll.type" value=source.type localize=true}}
|
<div class="nest-inputs">
|
||||||
{{#if (eq source.type "diceSet")}}
|
{{#unless (eq source.type 'spellcast')}}
|
||||||
<div class="nest-inputs">
|
{{#if @root.isNPC}}
|
||||||
{{formField fields.diceRolling.fields.multiplier name="roll.diceRolling.multiplier" value=source.diceRolling.multiplier localize=true}}
|
{{formField fields.bonus label="Bonus" name="roll.bonus" value=source.bonus placeholder=@root.baseAttackBonus disabled=(not source.type)}}
|
||||||
{{#if (eq source.diceRolling.multiplier 'flat')}}{{formField fields.diceRolling.fields.flatMultiplier value=source.diceRolling.flatMultiplier name="roll.diceRolling.flatMultiplier" localize=true }}{{/if}}
|
{{else}}
|
||||||
{{formField fields.diceRolling.fields.dice name="roll.diceRolling.dice" value=source.diceRolling.dice localize=true}}
|
{{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true disabled=(not source.type)}}
|
||||||
{{formField fields.diceRolling.fields.compare name="roll.diceRolling.compare" value=source.diceRolling.compare localize=true blank=""}}
|
{{/if}}
|
||||||
{{formField fields.diceRolling.fields.treshold name="roll.diceRolling.treshold" value=source.diceRolling.treshold localize=true}}
|
{{/unless}}
|
||||||
</div>
|
{{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty disabled=(not source.type)}}
|
||||||
{{else}}
|
{{formField fields.advState label= "Advantage State" name="roll.advState" value=source.advState localize=true disabled=(not source.type)}}
|
||||||
<div class="nest-inputs">
|
</div>
|
||||||
{{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true disabled=(not source.type)}}
|
|
||||||
{{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty disabled=(not source.type)}}
|
|
||||||
{{formField fields.advState label= "Advantage State" name="roll.advState" value=source.advState localize=true}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
<input name="uses.enabled" type="checkbox"{{#if uses.enabled}} checked{{/if}}>
|
<input name="uses.enabled" type="checkbox"{{#if uses.enabled}} checked{{/if}}>
|
||||||
<label for="uses.enabled">Uses</label>
|
<label for="uses.enabled">Uses</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>{{log @root}}
|
||||||
<label class="modifier-label">{{uses.value}}/{{uses.max}}</label>
|
<label class="modifier-label">{{uses.value}}/{{formulaValue uses.max @root.rollConfig.data}}</label>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#each costs as | cost index |}}
|
{{#each costs as | cost index |}}
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
<label>{{label}}</label>
|
<label>{{label}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if scalable}}
|
{{#if (and scalable (gt maxStep 1))}}
|
||||||
<input type="range" value="{{scale}}" min="1" max="10" step="{{step}}" name="costs.{{index}}.scale">
|
<input type="range" value="{{scale}}" min="1" max="{{maxStep}}" step="1" name="costs.{{index}}.scale">
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<label class="modifier-label">{{total}}/10</label>
|
<label class="modifier-label">{{total}}/{{max}}</label>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
<h2 class="tooltip-title">{{item.name}}</h2>
|
<h2 class="tooltip-title">{{item.name}}</h2>
|
||||||
<img class="tooltip-image" src="{{item.img}}" />
|
<img class="tooltip-image" src="{{item.img}}" />
|
||||||
<div class="tooltip-description">{{{description}}}</div>
|
<div class="tooltip-description">{{{description}}}</div>
|
||||||
|
|
||||||
{{#if item.uses.max}}
|
{{#if item.uses.max}}
|
||||||
<h4 class="tooltip-sub-title">{{localize "DAGGERHEART.GENERAL.uses"}}</h4>
|
<h4 class="tooltip-sub-title">{{localize "DAGGERHEART.GENERAL.uses"}}</h4>
|
||||||
<div class="tooltip-information-section triple spaced">
|
<div class="tooltip-information-section triple spaced">
|
||||||
|
|
@ -12,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="tooltip-information">
|
<div class="tooltip-information">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.max"}}</label>
|
<label>{{localize "DAGGERHEART.GENERAL.max"}}</label>
|
||||||
<div>{{item.uses.max}}</div>
|
<div>{{formulaValue item.uses.max item}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tooltip-information">
|
<div class="tooltip-information">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.recovery"}}</label>
|
<label>{{localize "DAGGERHEART.GENERAL.recovery"}}</label>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue