mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 11:41:08 +01:00
Merge branch 'main' into feature/death-moves
This commit is contained in:
commit
562c404534
53 changed files with 581 additions and 162 deletions
|
|
@ -32,6 +32,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
|||
icon: 'fa-solid fa-gears'
|
||||
},
|
||||
actions: {
|
||||
editCurrencyIcon: this.changeCurrencyIcon,
|
||||
addItem: this.addItem,
|
||||
editItem: this.editItem,
|
||||
removeItem: this.removeItem,
|
||||
|
|
@ -115,6 +116,45 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
|||
this.render();
|
||||
}
|
||||
|
||||
static async changeCurrencyIcon(_, target) {
|
||||
const type = target.dataset.currency;
|
||||
const currentIcon = this.settings.currency[type].icon;
|
||||
const icon = await foundry.applications.api.DialogV2.input({
|
||||
classes: ['daggerheart', 'dh-style', 'change-currency-icon'],
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/settings/homebrew-settings/change-currency-icon.hbs',
|
||||
{ currentIcon }
|
||||
),
|
||||
window: {
|
||||
title: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.currency.changeIcon'),
|
||||
icon: 'fa-solid fa-coins'
|
||||
},
|
||||
render: (_, dialog) => {
|
||||
const icon = dialog.element.querySelector('.displayed-icon i');
|
||||
const input = dialog.element.querySelector('input');
|
||||
const reset = dialog.element.querySelector('button[data-action=reset]');
|
||||
input.addEventListener('input', () => {
|
||||
icon.classList.value = input.value;
|
||||
});
|
||||
reset.addEventListener('click', () => {
|
||||
const currencyField = DhHomebrew.schema.fields.currency.fields[type];
|
||||
const initial = currencyField.fields.icon.getInitialValue();
|
||||
input.value = icon.classList.value = initial;
|
||||
});
|
||||
},
|
||||
ok: {
|
||||
callback: (_, button) => button.form.elements.icon.value
|
||||
}
|
||||
});
|
||||
|
||||
if (icon !== null) {
|
||||
await this.settings.updateSource({
|
||||
[`currency.${type}.icon`]: icon
|
||||
});
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
static async addItem(_, target) {
|
||||
const { type } = target.dataset;
|
||||
if (['shortRest', 'longRest'].includes(type)) {
|
||||
|
|
|
|||
|
|
@ -685,8 +685,6 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
ability: abilityLabel
|
||||
})
|
||||
});
|
||||
|
||||
if (result) game.system.api.fields.ActionFields.CostField.execute.call(this, result);
|
||||
}
|
||||
|
||||
//TODO: redo toggleEquipItem method
|
||||
|
|
|
|||
|
|
@ -178,6 +178,80 @@ export default function DHApplicationMixin(Base) {
|
|||
_attachPartListeners(partId, htmlElement, options) {
|
||||
super._attachPartListeners(partId, htmlElement, options);
|
||||
this._dragDrop.forEach(d => d.bind(htmlElement));
|
||||
|
||||
// Handle delta inputs
|
||||
for (const deltaInput of htmlElement.querySelectorAll('input[data-allow-delta]')) {
|
||||
deltaInput.dataset.numValue = deltaInput.value;
|
||||
deltaInput.inputMode = 'numeric';
|
||||
deltaInput.pattern = '^[+=\\-]?\d*';
|
||||
|
||||
const handleUpdate = (delta = 0) => {
|
||||
const min = Number(deltaInput.min) || 0;
|
||||
const max = Number(deltaInput.max) || Infinity;
|
||||
const current = Number(deltaInput.dataset.numValue);
|
||||
const rawNumber = Number(deltaInput.value);
|
||||
if (Number.isNaN(rawNumber)) {
|
||||
deltaInput.value = delta ? Math.clamp(current + delta, min, max) : current;
|
||||
return;
|
||||
}
|
||||
|
||||
const newValue =
|
||||
deltaInput.value.startsWith('+') || deltaInput.value.startsWith('-')
|
||||
? Math.clamp(current + rawNumber + delta, min, max)
|
||||
: Math.clamp(rawNumber + delta, min, max);
|
||||
deltaInput.value = deltaInput.dataset.numValue = newValue;
|
||||
};
|
||||
|
||||
// Force valid characters while inputting
|
||||
deltaInput.addEventListener('input', () => {
|
||||
deltaInput.value = /[+=\-]?\d*/.exec(deltaInput.value)?.at(0) ?? deltaInput.value;
|
||||
});
|
||||
|
||||
// Recreate Keyup/Keydown support
|
||||
deltaInput.addEventListener('keydown', event => {
|
||||
const step = event.key === 'ArrowUp' ? 1 : event.key === 'ArrowDown' ? -1 : 0;
|
||||
if (step !== 0) {
|
||||
handleUpdate(step);
|
||||
deltaInput.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
});
|
||||
|
||||
// Mousewheel while focused support
|
||||
deltaInput.addEventListener(
|
||||
'wheel',
|
||||
event => {
|
||||
if (deltaInput === document.activeElement) {
|
||||
event.preventDefault();
|
||||
handleUpdate(Math.sign(-1 * event.deltaY));
|
||||
deltaInput.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
deltaInput.addEventListener('change', () => {
|
||||
handleUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
// Handle contenteditable
|
||||
for (const input of htmlElement.querySelectorAll('[contenteditable][data-property]')) {
|
||||
const property = input.dataset.property;
|
||||
input.addEventListener("blur", () => {
|
||||
const selection = document.getSelection();
|
||||
if (input.contains(selection.anchorNode)) {
|
||||
selection.empty();
|
||||
}
|
||||
this.document.update({ [property]: input.textContent });
|
||||
});
|
||||
|
||||
input.addEventListener("keydown", event => {
|
||||
if (event.key === "Enter") input.blur();
|
||||
});
|
||||
|
||||
// Chrome sometimes add <br>, which aren't a problem for the value but are for the placeholder
|
||||
input.addEventListener("input", () => input.querySelectorAll("br").forEach((i) => i.remove()));
|
||||
}
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
|
|
|
|||
|
|
@ -245,7 +245,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
});
|
||||
|
||||
if (!result) return;
|
||||
await game.system.api.fields.ActionFields.CostField.execute.call({ actor }, result);
|
||||
|
||||
const newMessageData = foundry.utils.deepClone(message.system);
|
||||
foundry.utils.setProperty(newMessageData, `${path}.result`, result.roll);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
actions: {
|
||||
requestSpotlight: this.requestSpotlight,
|
||||
toggleSpotlight: this.toggleSpotlight,
|
||||
setActionTokens: this.setActionTokens,
|
||||
openCountdowns: this.openCountdowns
|
||||
setActionTokens: this.setActionTokens
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -57,21 +56,26 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
|
||||
const adversaries = context.turns?.filter(x => x.isNPC) ?? [];
|
||||
const characters = context.turns?.filter(x => !x.isNPC) ?? [];
|
||||
const spotlightQueueEnabled = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.SpotlightRequestQueue
|
||||
);
|
||||
|
||||
const spotlightRequests = characters
|
||||
?.filter(x => !x.isNPC)
|
||||
?.filter(x => !x.isNPC && spotlightQueueEnabled)
|
||||
.filter(x => x.system.spotlight.requestOrderIndex > 0)
|
||||
.sort((a, b) => {
|
||||
const valueA = a.system.spotlight.requestOrderIndex;
|
||||
const valueB = b.system.spotlight.requestOrderIndex;
|
||||
|
||||
return valueA - valueB;
|
||||
});
|
||||
|
||||
Object.assign(context, {
|
||||
actionTokens: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).actionTokens,
|
||||
adversaries,
|
||||
characters: characters?.filter(x => !x.isNPC).filter(x => x.system.spotlight.requestOrderIndex == 0),
|
||||
characters: characters
|
||||
?.filter(x => !x.isNPC)
|
||||
.filter(x => !spotlightQueueEnabled || x.system.spotlight.requestOrderIndex == 0),
|
||||
spotlightRequests
|
||||
});
|
||||
}
|
||||
|
|
@ -161,9 +165,13 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
|
||||
if (this.viewed.turn !== toggleTurn) {
|
||||
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.spotlight.id);
|
||||
if (combatant.actor.type === 'character') {
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.characterSpotlight.id);
|
||||
await updateCountdowns(
|
||||
CONFIG.DH.GENERAL.countdownProgressionTypes.spotlight.id,
|
||||
CONFIG.DH.GENERAL.countdownProgressionTypes.characterSpotlight.id
|
||||
);
|
||||
} else {
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.spotlight.id);
|
||||
}
|
||||
|
||||
const autoPoints = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).actionPoints;
|
||||
|
|
|
|||
|
|
@ -245,14 +245,20 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
|
|||
return super.close(options);
|
||||
}
|
||||
|
||||
static async updateCountdowns(progressType) {
|
||||
/**
|
||||
* Sends updates of the countdowns to the GM player. Since this is asynchronous, be sure to
|
||||
* update all the countdowns at the same time.
|
||||
*
|
||||
* @param {...any} progressTypes Countdowns to be updated
|
||||
*/
|
||||
static async updateCountdowns(...progressTypes) {
|
||||
const { countdownAutomation } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
|
||||
if (!countdownAutomation) return;
|
||||
|
||||
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
||||
const updatedCountdowns = Object.keys(countdownSetting.countdowns).reduce((acc, key) => {
|
||||
const countdown = countdownSetting.countdowns[key];
|
||||
if (countdown.progress.type === progressType && countdown.progress.current > 0) {
|
||||
if (progressTypes.indexOf(countdown.progress.type) !== -1 && countdown.progress.current > 0) {
|
||||
acc.push(key);
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +266,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
|
|||
}, []);
|
||||
|
||||
const countdownData = countdownSetting.toObject();
|
||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, {
|
||||
const settings = {
|
||||
...countdownData,
|
||||
countdowns: Object.keys(countdownData.countdowns).reduce((acc, key) => {
|
||||
const countdown = foundry.utils.deepClone(countdownData.countdowns[key]);
|
||||
|
|
@ -271,14 +277,12 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
|
|||
acc[key] = countdown;
|
||||
return acc;
|
||||
}, {})
|
||||
};
|
||||
await emitAsGM(GMUpdateEvent.UpdateCountdowns,
|
||||
DhCountdowns.gmSetSetting.bind(settings),
|
||||
settings, null, {
|
||||
refreshType: RefreshType.Countdown
|
||||
});
|
||||
|
||||
const data = { refreshType: RefreshType.Countdown };
|
||||
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||
action: socketEvent.Refresh,
|
||||
data
|
||||
});
|
||||
Hooks.callAll(socketEvent.Refresh, data);
|
||||
}
|
||||
|
||||
async _onRender(context, options) {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica
|
|||
async removeEffect(event) {
|
||||
const element = event.target.closest('.effect-container');
|
||||
const effects = DhEffectsDisplay.getTokenEffects();
|
||||
const effect = effects.find(x => x.id === element.id);
|
||||
const effect = effects.find(x => x.id === element.dataset.effectId);
|
||||
await effect.delete();
|
||||
this.render();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ export const BPModifiers = {
|
|||
increaseDamage: {
|
||||
sort: 2,
|
||||
description: 'DAGGERHEART.CONFIG.BPModifiers.increaseDamage.description',
|
||||
effectTargetTypes: ['adversary'],
|
||||
effects: [
|
||||
{
|
||||
name: 'DAGGERHEART.CONFIG.BPModifiers.increaseDamage.effect.name',
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ export const gameSettings = {
|
|||
LevelTiers: 'LevelTiers',
|
||||
Countdowns: 'Countdowns',
|
||||
LastMigrationVersion: 'LastMigrationVersion',
|
||||
TagTeamRoll: 'TagTeamRoll'
|
||||
TagTeamRoll: 'TagTeamRoll',
|
||||
SpotlightRequestQueue: 'SpotlightRequestQueue',
|
||||
};
|
||||
|
||||
export const actionAutomationChoices = {
|
||||
|
|
|
|||
|
|
@ -193,8 +193,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
async use(event) {
|
||||
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
||||
|
||||
if (this.chatDisplay) await this.toChat();
|
||||
|
||||
let config = this.prepareConfig(event);
|
||||
if (!config) return;
|
||||
|
||||
|
|
@ -211,6 +209,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
|
||||
if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return;
|
||||
|
||||
if (this.chatDisplay) await this.toChat();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import { defaultRestOptions } from '../../config/generalConfig.mjs';
|
||||
import { ActionsField } from '../fields/actionField.mjs';
|
||||
|
||||
const currencyField = (initial, label) =>
|
||||
const currencyField = (initial, label, icon) =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
enabled: new foundry.data.fields.BooleanField({ required: true, initial: true }),
|
||||
label: new foundry.data.fields.StringField({
|
||||
required: true,
|
||||
initial,
|
||||
label
|
||||
})
|
||||
}),
|
||||
icon: new foundry.data.fields.StringField({ required: true, nullable: false, blank: true, initial: icon })
|
||||
});
|
||||
|
||||
export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||
|
|
@ -45,10 +46,22 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
initial: 'Gold',
|
||||
label: 'DAGGERHEART.SETTINGS.Homebrew.currency.currencyName'
|
||||
}),
|
||||
coins: currencyField('Coins', 'DAGGERHEART.SETTINGS.Homebrew.currency.coinName'),
|
||||
handfuls: currencyField('Handfuls', 'DAGGERHEART.SETTINGS.Homebrew.currency.handfulName'),
|
||||
bags: currencyField('Bags', 'DAGGERHEART.SETTINGS.Homebrew.currency.bagName'),
|
||||
chests: currencyField('Chests', 'DAGGERHEART.SETTINGS.Homebrew.currency.chestName')
|
||||
coins: currencyField(
|
||||
'Coins',
|
||||
'DAGGERHEART.SETTINGS.Homebrew.currency.coinName',
|
||||
'fa-solid fa-coin-front'
|
||||
),
|
||||
handfuls: currencyField(
|
||||
'Handfuls',
|
||||
'DAGGERHEART.SETTINGS.Homebrew.currency.handfulName',
|
||||
'fa-solid fa-coins'
|
||||
),
|
||||
bags: currencyField('Bags', 'DAGGERHEART.SETTINGS.Homebrew.currency.bagName', 'fa-solid fa-sack'),
|
||||
chests: currencyField(
|
||||
'Chests',
|
||||
'DAGGERHEART.SETTINGS.Homebrew.currency.chestName',
|
||||
'fa-solid fa-treasure-chest'
|
||||
)
|
||||
}),
|
||||
restMoves: new fields.SchemaField({
|
||||
longRest: new fields.SchemaField({
|
||||
|
|
@ -139,22 +152,10 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
/** @inheritDoc */
|
||||
_initializeSource(source, options = {}) {
|
||||
source = super._initializeSource(source, options);
|
||||
source.currency.coins = {
|
||||
enabled: source.currency.coins.enabled ?? true,
|
||||
label: source.currency.coins.label || source.currency.coins
|
||||
};
|
||||
source.currency.handfuls = {
|
||||
enabled: source.currency.handfuls.enabled ?? true,
|
||||
label: source.currency.handfuls.label || source.currency.handfuls
|
||||
};
|
||||
source.currency.bags = {
|
||||
enabled: source.currency.bags.enabled ?? true,
|
||||
label: source.currency.bags.label || source.currency.bags
|
||||
};
|
||||
source.currency.chests = {
|
||||
enabled: source.currency.chests.enabled ?? true,
|
||||
label: source.currency.chests.label || source.currency.chests
|
||||
};
|
||||
for (const type of ['coins', 'handfuls', 'bags', 'chests']) {
|
||||
const initial = this.schema.fields.currency.fields[type].getInitialValue();
|
||||
source.currency[type] = foundry.utils.mergeObject(initial, source.currency[type], { inplace: false });
|
||||
}
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ export default class DhVariantRules extends foundry.abstract.DataModel {
|
|||
label: 'DAGGERHEART.CONFIG.Range.close.name'
|
||||
}),
|
||||
far: new fields.NumberField({ required: true, initial: 60, label: 'DAGGERHEART.CONFIG.Range.far.name' })
|
||||
}),
|
||||
massiveDamage: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.VariantRules.FIELDS.massiveDamage.enabled.label'
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,6 +237,51 @@ export default class DHRoll extends Roll {
|
|||
}
|
||||
}
|
||||
|
||||
async function automateHopeFear(config) {
|
||||
const automationSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
|
||||
const hopeFearAutomation = automationSettings.hopeFear;
|
||||
if (!config.source?.actor ||
|
||||
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
|
||||
config.actionType === 'reaction' ||
|
||||
config.tagTeamSelected ||
|
||||
config.skips?.resources)
|
||||
return;
|
||||
const actor = await fromUuid(config.source.actor);
|
||||
let updates = [];
|
||||
if (!actor) return;
|
||||
|
||||
if (config.rerolledRoll) {
|
||||
if (config.roll.result.duality != config.rerolledRoll.result.duality) {
|
||||
const hope = (config.roll.isCritical || config.roll.result.duality === 1 ? 1 : 0)
|
||||
- (config.rerolledRoll.isCritical || config.rerolledRoll.result.duality === 1 ? 1 : 0);
|
||||
const stress = (config.roll.isCritical ? 1 : 0) - (config.rerolledRoll.isCritical ? 1 : 0);
|
||||
const fear = (config.roll.result.duality === -1 ? 1 : 0)
|
||||
- (config.rerolledRoll.result.duality === -1 ? 1 : 0)
|
||||
|
||||
if (hope !== 0)
|
||||
updates.push({ key: 'hope', value: hope, total: -1 * hope, enabled: true });
|
||||
if (stress !== 0)
|
||||
updates.push({ key: 'stress', value: -1 * stress, total: stress, enabled: true });
|
||||
if (fear !== 0)
|
||||
updates.push({ key: 'fear', value: fear, total: -1 * fear, enabled: true });
|
||||
}
|
||||
} else {
|
||||
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 (updates.length) {
|
||||
const target = actor.system.partner ?? actor;
|
||||
if (!['dead', 'defeated', 'unconscious'].some(x => actor.statuses.has(x))) {
|
||||
await target.modifyResource(updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const registerRollDiceHooks = () => {
|
||||
Hooks.on(`${CONFIG.DH.id}.postRollDuality`, async (config, message) => {
|
||||
const automationSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
|
||||
|
|
@ -247,45 +292,16 @@ export const registerRollDiceHooks = () => {
|
|||
!config.skips?.updateCountdowns
|
||||
) {
|
||||
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.actionRoll.id);
|
||||
|
||||
if (config.roll.result.duality === -1) {
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.fear.id);
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.actionRoll.id,
|
||||
CONFIG.DH.GENERAL.countdownProgressionTypes.fear.id);
|
||||
} else {
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.actionRoll.id);
|
||||
}
|
||||
}
|
||||
|
||||
const hopeFearAutomation = automationSettings.hopeFear;
|
||||
if (
|
||||
!config.source?.actor ||
|
||||
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
|
||||
config.actionType === 'reaction' ||
|
||||
config.tagTeamSelected ||
|
||||
config.skips?.resources
|
||||
)
|
||||
return;
|
||||
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, 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, 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', 'defeated', 'unconscious'].some(x => actor.statuses.has(x))) {
|
||||
if (config.rerolledRoll) target.modifyResource(updates);
|
||||
else config.costs = [...(config.costs ?? []), ...updates];
|
||||
}
|
||||
}
|
||||
await automateHopeFear(config);
|
||||
|
||||
if (!config.roll.hasOwnProperty('success') && !config.targets?.length) return;
|
||||
|
||||
|
|
@ -296,7 +312,5 @@ export const registerRollDiceHooks = () => {
|
|||
const currentCombatant = game.combat.combatants.get(game.combat.current?.combatantId);
|
||||
if (currentCombatant?.actorId == actor.id) ui.combat.setCombatantSpotlight(currentCombatant.id);
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -262,8 +262,7 @@ export default class DualityRoll extends D20Roll {
|
|||
targets: message.system.targets,
|
||||
tagTeamSelected: Object.values(tagTeamSettings.members).some(x => x.messageId === message._id),
|
||||
roll: newRoll,
|
||||
rerolledRoll:
|
||||
newRoll.result.duality !== message.system.roll.result.duality ? message.system.roll : undefined
|
||||
rerolledRoll: message.system.roll
|
||||
});
|
||||
return { newRoll, parsedRoll };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,7 +526,7 @@ export default class DhpActor extends Actor {
|
|||
|
||||
/**@inheritdoc */
|
||||
getRollData() {
|
||||
const rollData = super.getRollData();
|
||||
const rollData = super.getRollData().clone();
|
||||
rollData.name = this.name;
|
||||
rollData.system = this.system.getRollData();
|
||||
rollData.prof = this.system.proficiency ?? 1;
|
||||
|
|
@ -679,6 +679,10 @@ export default class DhpActor extends Actor {
|
|||
return updates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resources are modified asynchronously, so be careful not to update the same resource in
|
||||
* quick succession.
|
||||
*/
|
||||
async modifyResource(resources) {
|
||||
if (!resources?.length) return;
|
||||
|
||||
|
|
@ -761,6 +765,10 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
|
||||
convertDamageToThreshold(damage) {
|
||||
const massiveDamageEnabled=game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).massiveDamage.enabled;
|
||||
if (massiveDamageEnabled && damage >= (this.system.damageThresholds.severe * 2)) {
|
||||
return 4;
|
||||
}
|
||||
return damage >= this.system.damageThresholds.severe ? 3 : damage >= this.system.damageThresholds.major ? 2 : 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export default class DhpCombat extends Combat {
|
|||
...effect,
|
||||
name: game.i18n.localize(effect.name),
|
||||
description: game.i18n.localize(effect.description),
|
||||
effectTargetTypes: grouping.effectTargetTypes ?? [],
|
||||
flags: {
|
||||
[`${CONFIG.DH.id}.${CONFIG.DH.FLAGS.combatToggle}`]: {
|
||||
category: toggle.category,
|
||||
|
|
@ -45,11 +46,7 @@ export default class DhpCombat extends Combat {
|
|||
for (let actor of actors) {
|
||||
await actor.createEmbeddedDocuments(
|
||||
'ActiveEffect',
|
||||
effects.map(effect => ({
|
||||
...effect,
|
||||
name: game.i18n.localize(effect.name),
|
||||
description: game.i18n.localize(effect.description)
|
||||
}))
|
||||
effects.filter(x => x.effectTargetTypes.includes(actor.type))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
{
|
||||
item: item,
|
||||
description: item.system?.enrichedDescription ?? item.enrichedDescription,
|
||||
config: CONFIG.DH
|
||||
config: CONFIG.DH,
|
||||
allDomains: CONFIG.DH.DOMAIN.allDomains()
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ foundry.dice.terms.Die.prototype.selfCorrecting = function (modifier) {
|
|||
};
|
||||
|
||||
export const getDamageKey = damage => {
|
||||
return ['none', 'minor', 'major', 'severe', 'any'][damage];
|
||||
return ['none', 'minor', 'major', 'severe', 'massive','any'][damage];
|
||||
};
|
||||
|
||||
export const getDamageLabel = damage => {
|
||||
|
|
@ -225,7 +225,8 @@ export const damageKeyToNumber = key => {
|
|||
minor: 1,
|
||||
major: 2,
|
||||
severe: 3,
|
||||
any: 4
|
||||
massive: 4,
|
||||
any: 5
|
||||
}[key];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@ export const registerDHSettings = () => {
|
|||
registerMenuSettings();
|
||||
registerMenus();
|
||||
registerNonConfigSettings();
|
||||
|
||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightRequestQueue, {
|
||||
name: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.SpotlightRequestQueue.name'),
|
||||
label: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.SpotlightRequestQueue.label'),
|
||||
hint: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.SpotlightRequestQueue.hint'),
|
||||
scope: 'world',
|
||||
config: true,
|
||||
type: Boolean,
|
||||
onChange: () => ui.combat.render(),
|
||||
})
|
||||
};
|
||||
|
||||
const registerMenuSettings = () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue