mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-07-22 02:19:54 +02:00
Merge branch 'main' into feature/reload-check
This commit is contained in:
commit
e2414b167a
496 changed files with 4622 additions and 5735 deletions
|
|
@ -315,15 +315,15 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
|
|||
|
||||
const beastformEffect = selected.effects.find(x => x.type === 'beastform');
|
||||
for (const traitBonus of app.modifications.traitBonuses) {
|
||||
const existingChange = beastformEffect.changes.find(
|
||||
const existingChange = beastformEffect.system.changes.find(
|
||||
x => x.key === `system.traits.${traitBonus.trait}.value`
|
||||
);
|
||||
if (existingChange) {
|
||||
existingChange.value = Number.parseInt(existingChange.value) + traitBonus.bonus;
|
||||
} else {
|
||||
beastformEffect.changes.push({
|
||||
beastformEffect.system.changes.push({
|
||||
key: `system.traits.${traitBonus.trait}.value`,
|
||||
mode: 2,
|
||||
type: 'add',
|
||||
priority: null,
|
||||
value: traitBonus.bonus
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,7 +51,11 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
|||
const context = await super._prepareContext(_options);
|
||||
context.config = CONFIG.DH;
|
||||
context.title = this.config.title ?? this.title;
|
||||
context.formula = this.roll.constructFormula(this.config);
|
||||
|
||||
const { damageFormula, resourceFormulas } = this.roll.constructFormulas(this.config);
|
||||
context.damageFormula = damageFormula;
|
||||
context.resourceFormulas = resourceFormulas;
|
||||
|
||||
context.hasHealing = this.config.hasHealing;
|
||||
context.directDamage = this.config.directDamage;
|
||||
context.selectedMessageMode = this.config.selectedMessageMode;
|
||||
|
|
@ -73,7 +77,11 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
|||
|
||||
static updateRollConfiguration(_event, _, formData) {
|
||||
const data = foundry.utils.expandObject(formData.object);
|
||||
foundry.utils.mergeObject(this.config.roll, data.roll);
|
||||
|
||||
if (this.config.damageFormula)
|
||||
foundry.utils.mergeObject(this.config.damageFormula, data.damageFormula);
|
||||
|
||||
foundry.utils.mergeObject(this.config.resourceFormulas, data.resourceFormulas);
|
||||
foundry.utils.mergeObject(this.config.modifiers, data.modifiers);
|
||||
this.config.selectedMessageMode = data.selectedMessageMode;
|
||||
|
||||
|
|
|
|||
|
|
@ -139,13 +139,15 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
name: game.i18n.localize('DAGGERHEART.CONFIG.DeathMoves.blazeOfGlory.name'),
|
||||
description: game.i18n.localize('DAGGERHEART.CONFIG.DeathMoves.blazeOfGlory.description'),
|
||||
img: CONFIG.DH.GENERAL.deathMoves.blazeOfGlory.img,
|
||||
changes: [
|
||||
{
|
||||
key: 'system.rules.roll.guaranteedCritical',
|
||||
mode: 2,
|
||||
value: 'true'
|
||||
}
|
||||
]
|
||||
system: {
|
||||
changes: [
|
||||
{
|
||||
key: 'system.rules.roll.guaranteedCritical',
|
||||
type: 'add',
|
||||
value: 'true'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
|
|
@ -183,8 +185,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
|
||||
if (result === undefined) return;
|
||||
|
||||
const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
||||
.expandRollMessage?.desc;
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
|
||||
const msg = {
|
||||
|
|
@ -200,7 +200,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
img: this.selectedMove.img,
|
||||
description: game.i18n.localize(this.selectedMove.description),
|
||||
result: result,
|
||||
open: autoExpandDescription ? 'open' : '',
|
||||
showRiskItAllButton: this.showRiskItAllButton,
|
||||
riskItAllButtonLabel: this.riskItAllButtonLabel,
|
||||
riskItAllHope: this.riskItAllHope
|
||||
|
|
|
|||
|
|
@ -196,9 +196,6 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
.filter(x => x.testUserPermission(game.user, 'LIMITED'))
|
||||
.filter(x => x.uuid !== this.actor.uuid);
|
||||
|
||||
const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
||||
.expandRollMessage?.desc;
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = {
|
||||
user: game.user.id,
|
||||
|
|
@ -219,8 +216,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
actor: { name: this.actor.name, img: this.actor.img },
|
||||
moves: moves,
|
||||
characters: characters,
|
||||
selfId: this.actor.uuid,
|
||||
open: autoExpandDescription ? 'open' : ''
|
||||
selfId: this.actor.uuid
|
||||
}
|
||||
),
|
||||
flags: {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ResourceUpdateMap } from '../../data/action/baseAction.mjs';
|
||||
import { shouldUseHopeFearAutomation } from '../../helpers/utils.mjs';
|
||||
import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
import Party from '../sheets/actors/party.mjs';
|
||||
import PartySheet from '../sheets/actors/party.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
|||
|
||||
this.party = party;
|
||||
this.partyMembers = party.system.partyMembers
|
||||
.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type))
|
||||
.filter(x => PartySheet.DICE_ROLL_ACTOR_TYPES.includes(x.type))
|
||||
.map(member => ({
|
||||
...member.toObject(),
|
||||
uuid: member.uuid,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { ResourceUpdateMap } from '../../data/action/baseAction.mjs';
|
||||
import { ChatDamageData } from '../../data/chat-message/chatDamageData.mjs';
|
||||
import { MemberData } from '../../data/tagTeamData.mjs';
|
||||
import { getCritDamageBonus, shouldUseHopeFearAutomation } from '../../helpers/utils.mjs';
|
||||
import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
import Party from '../sheets/actors/party.mjs';
|
||||
import PartySheet from '../sheets/actors/party.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
this.usesTagTeamHopeCost = true;
|
||||
this.party = party;
|
||||
this.partyMembers = party.system.partyMembers
|
||||
.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type))
|
||||
.filter(x => PartySheet.DICE_ROLL_ACTOR_TYPES.includes(x.type))
|
||||
.map(member => ({
|
||||
...member.toObject(),
|
||||
uuid: member.uuid,
|
||||
|
|
@ -140,7 +141,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
const hasRolled = Boolean(data.rollData);
|
||||
if (!hasRolled) return false;
|
||||
|
||||
return !data.rollData.options.hasDamage || Boolean(data.rollData.options.damage);
|
||||
return !data.rollData.options.hasDamage || data.damageRollData.active;
|
||||
});
|
||||
|
||||
return context;
|
||||
|
|
@ -181,7 +182,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected);
|
||||
const critSelected = !selectedRoll
|
||||
? undefined
|
||||
: (selectedRoll?.rollData?.options?.roll?.isCritical ?? false);
|
||||
: (selectedRoll?.roll?.isCritical ?? false);
|
||||
|
||||
partContext.hintText = await this.getInfoTexts(this.party.system.tagTeam.members);
|
||||
partContext.joinedRoll = await this.getJoinedRoll({
|
||||
|
|
@ -208,6 +209,16 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
const rollOptions = [];
|
||||
const damageRollOptions = [];
|
||||
|
||||
if (actor?.system.usedUnarmed) {
|
||||
damageRollOptions.push({
|
||||
value: actor.system.attack.uuid,
|
||||
label: actor.system.usedUnarmed.name,
|
||||
group: actor.name,
|
||||
baseAction: actor.system.attack
|
||||
});
|
||||
}
|
||||
|
||||
for (const item of actor?.items ?? []) {
|
||||
if (!item.system.metadata.hasActions) continue;
|
||||
const actions = [...item.system.actions, ...(item.system.attack ? [item.system.attack] : [])];
|
||||
|
|
@ -225,8 +236,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
|
||||
const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected);
|
||||
const critSelected = !selectedRoll ? undefined : (selectedRoll?.rollData?.options?.roll?.isCritical ?? false);
|
||||
const damage = data.rollData?.options?.damage;
|
||||
const critSelected = !selectedRoll ? undefined : (selectedRoll?.roll?.isCritical ?? false);
|
||||
|
||||
return {
|
||||
...data,
|
||||
|
|
@ -237,9 +247,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
hasRolled: Boolean(data.rollData),
|
||||
rollOptions,
|
||||
damageRollOptions,
|
||||
damage: damage,
|
||||
critDamage: await this.getCriticalDamage(damage),
|
||||
useCritDamage: critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical)
|
||||
damage: data.damageRollData,
|
||||
critDamage: await this.getCriticalDamage(data.damageRollData),
|
||||
useCritDamage: critSelected || (critSelected === undefined && data.roll?.isCritical)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -369,7 +379,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
let rollIsSelected = false;
|
||||
for (const member of Object.values(members)) {
|
||||
const rollFinished = Boolean(member.rollData);
|
||||
const damageFinished = member.rollData?.options?.hasDamage ? Boolean(member.rollData.options.damage) : true;
|
||||
const damageFinished = member.rollData?.options?.hasDamage ? member.damageRollData.active : true;
|
||||
|
||||
rollsAreFinished = rollsAreFinished && rollFinished && damageFinished;
|
||||
rollIsSelected = rollIsSelected || member.selected;
|
||||
|
|
@ -530,17 +540,10 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
await action.workflow.get('damage').execute(config, null, true);
|
||||
if (!config.damage) return;
|
||||
|
||||
const current = this.party.system.tagTeam.members[memberKey].rollData;
|
||||
|
||||
await this.updatePartyData(
|
||||
{
|
||||
[`system.tagTeam.members.${memberKey}.rollData`]: {
|
||||
...current,
|
||||
options: {
|
||||
...current.options,
|
||||
damage: config.damage
|
||||
}
|
||||
}
|
||||
[`system.tagTeam.members.${memberKey}.damageRollData`]: config.damage
|
||||
},
|
||||
this.getUpdatingParts(button)
|
||||
);
|
||||
|
|
@ -548,15 +551,11 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
static async #removeDamageRoll(_, button) {
|
||||
const { memberKey } = button.dataset;
|
||||
const current = this.party.system.tagTeam.members[memberKey].rollData;
|
||||
this.updatePartyData(
|
||||
{
|
||||
[`system.tagTeam.members.${memberKey}.rollData`]: {
|
||||
...current,
|
||||
options: {
|
||||
...current.options,
|
||||
damage: null
|
||||
}
|
||||
[`system.tagTeam.members.${memberKey}.damageRollData`]: {
|
||||
main: null,
|
||||
resources: _replace({})
|
||||
}
|
||||
},
|
||||
this.getUpdatingParts(button)
|
||||
|
|
@ -564,89 +563,44 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
|
||||
static async #rerollDamageDice(_, button) {
|
||||
const { memberKey, damageKey, part, dice } = button.dataset;
|
||||
const { isResource, memberKey, damageKey, diceIndex, resultIndex } = button.dataset;
|
||||
const memberData = this.party.system.tagTeam.members[memberKey];
|
||||
const partData = memberData.rollData.options.damage[damageKey].parts[part];
|
||||
const activeDiceResultKey = Object.keys(partData.dice[dice].results).find(
|
||||
index => partData.dice[dice].results[index].active
|
||||
);
|
||||
const { parsedRoll, rerolledDice } = await game.system.api.dice.DamageRoll.reroll(
|
||||
partData,
|
||||
dice,
|
||||
activeDiceResultKey
|
||||
);
|
||||
|
||||
const rollData = this.party.system.tagTeam.members[memberKey].rollData;
|
||||
rollData.options.damage[damageKey].parts = rollData.options.damage[damageKey].parts.map((damagePart, index) => {
|
||||
if (index !== Number.parseInt(part)) return damagePart;
|
||||
|
||||
return {
|
||||
...damagePart,
|
||||
total: parsedRoll.total,
|
||||
dice: rerolledDice
|
||||
};
|
||||
});
|
||||
rollData.options.damage[damageKey].total = rollData.options.damage[damageKey].parts.reduce((acc, part) => {
|
||||
acc += part.total;
|
||||
return acc;
|
||||
}, 0);
|
||||
await memberData.damageRollData.rerollDamageDie(isResource, damageKey, diceIndex, resultIndex);
|
||||
|
||||
const basePath = `system.tagTeam.members.${memberKey}.damageRollData`;
|
||||
const updatePath = isResource ? `${basePath}.resources.${damageKey}` : `${basePath}.main`;
|
||||
const updateValue = isResource ?
|
||||
memberData.damageRollData.resources[damageKey] : memberData.damageRollData.main;
|
||||
this.updatePartyData(
|
||||
{
|
||||
[`system.tagTeam.members.${memberKey}.rollData`]: rollData
|
||||
[updatePath]: updateValue.toJSON()
|
||||
},
|
||||
this.getUpdatingParts(button)
|
||||
);
|
||||
}
|
||||
|
||||
async getCriticalDamage(damage) {
|
||||
const newDamage = foundry.utils.deepClone(damage);
|
||||
for (let key in newDamage) {
|
||||
var damage = newDamage[key];
|
||||
damage.formula = '';
|
||||
damage.total = 0;
|
||||
|
||||
for (let part of damage.parts) {
|
||||
const criticalDamage = await getCritDamageBonus(part.formula);
|
||||
if (criticalDamage) {
|
||||
part.modifierTotal += criticalDamage;
|
||||
part.total += criticalDamage;
|
||||
part.formula = `${part.dice.map(x => x.formula).join(' + ')} + ${part.modifierTotal}`;
|
||||
part.roll = new Roll(part.formula);
|
||||
}
|
||||
|
||||
damage.formula = [damage.formula, part.formula].filter(x => x).join(' + ');
|
||||
damage.total += part.total;
|
||||
async getCriticalDamage(origDamage) {
|
||||
const newDamage = origDamage ? ChatDamageData.fromJSON(JSON.stringify(origDamage)) : null;
|
||||
if (newDamage?.main) {
|
||||
const criticalDamage = await getCritDamageBonus(newDamage.main.formula);
|
||||
if (criticalDamage) {
|
||||
const criticalTerm = new foundry.dice.terms.NumericTerm({ number: criticalDamage, evaluated: true });
|
||||
criticalTerm.evaluate();
|
||||
newDamage.main = await Roll.fromTerms([
|
||||
...origDamage.main.terms,
|
||||
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
|
||||
criticalTerm
|
||||
]);
|
||||
newDamage.main.options = foundry.utils.deepClone(origDamage.main.options);
|
||||
}
|
||||
}
|
||||
|
||||
return newDamage;
|
||||
}
|
||||
|
||||
async getNonCriticalDamage(config) {
|
||||
const newDamage = foundry.utils.deepClone(config.damage);
|
||||
for (let key in newDamage) {
|
||||
var damage = newDamage[key];
|
||||
damage.formula = '';
|
||||
damage.total = 0;
|
||||
|
||||
for (let part of damage.parts) {
|
||||
const critDamageBonus = await getCritDamageBonus(part.formula);
|
||||
part.modifierTotal -= critDamageBonus;
|
||||
part.total -= critDamageBonus;
|
||||
part.formula = `${part.dice.map(x => x.formula).join(' + ')} + ${part.modifierTotal}`;
|
||||
part.roll = new Roll(part.formula);
|
||||
|
||||
damage.formula = [damage.formula, part.formula].filter(x => x).join(' + ');
|
||||
damage.total += part.total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newDamage;
|
||||
}
|
||||
|
||||
static async #selectRoll(_, button) {
|
||||
const { memberKey } = button.dataset;
|
||||
|
||||
this.updatePartyData(
|
||||
{
|
||||
[`system.tagTeam.members`]: Object.entries(this.party.system.tagTeam.members).reduce(
|
||||
|
|
@ -657,7 +611,12 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
{}
|
||||
)
|
||||
},
|
||||
this.getUpdatingParts(button)
|
||||
/* Selecting a roll must update all member sections hbs to display the correct damage information incase of a critical */
|
||||
[
|
||||
...Object.keys(this.party.system.tagTeam.members),
|
||||
this.constructor.PARTS.rollSelection.id,
|
||||
this.constructor.PARTS.result.id
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -675,29 +634,65 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
if (!baseMainRoll?.rollData || !baseSecondaryRoll) return null;
|
||||
|
||||
const mainRoll = new MemberData(baseMainRoll.toObject());
|
||||
const secondaryRollData = new MemberData(baseSecondaryRoll.toObject()).rollData;
|
||||
const systemData = mainRoll.rollData.options;
|
||||
const isCritical = overrideIsCritical ?? systemData.roll.isCritical;
|
||||
if (isCritical) systemData.damage = await this.getCriticalDamage(systemData.damage);
|
||||
mainRoll.damageRollData = baseMainRoll.damageRollData ?
|
||||
ChatDamageData.fromJSON(JSON.stringify(baseMainRoll.damageRollData)) : null;
|
||||
const secondaryRoll = new MemberData(baseSecondaryRoll.toObject());
|
||||
secondaryRoll.damageRollData = baseSecondaryRoll.damageRollData ?
|
||||
ChatDamageData.fromJSON(JSON.stringify(baseSecondaryRoll.damageRollData)) : null;
|
||||
|
||||
if (secondaryRollData?.options.hasDamage) {
|
||||
const isCritical = overrideIsCritical ?? mainRoll.roll.isCritical;
|
||||
if (isCritical) mainRoll.damageRollData = await this.getCriticalDamage(mainRoll.damageRollData);
|
||||
|
||||
if (secondaryRoll.damageRollData) {
|
||||
const secondaryDamage = (displayVersion ? overrideIsCritical : isCritical)
|
||||
? await this.getCriticalDamage(secondaryRollData.options.damage)
|
||||
: secondaryRollData.options.damage;
|
||||
if (systemData.damage) {
|
||||
for (const [key, damage] of Object.entries(secondaryDamage ?? {})) {
|
||||
if (key in systemData.damage) {
|
||||
systemData.damage[key].formula = [systemData.damage[key]?.formula, damage.formula]
|
||||
.filter(x => x)
|
||||
.join(' + ');
|
||||
systemData.damage[key].total += damage.total;
|
||||
systemData.damage[key].parts.push(...damage.parts);
|
||||
? await this.getCriticalDamage(secondaryRoll.damageRollData)
|
||||
: secondaryRoll.damageRollData;
|
||||
if (mainRoll.damageRollData) {
|
||||
if (secondaryDamage.main) {
|
||||
if (mainRoll.damageRollData.main) {
|
||||
mainRoll.damageRollData.main = Roll.fromTerms([
|
||||
...baseMainRoll.damageRollData.main.terms,
|
||||
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
|
||||
...baseSecondaryRoll.damageRollData.main.terms
|
||||
]);
|
||||
|
||||
/* Joining the roll.options of both rolls */
|
||||
const joinedDamageTypes = new Set([
|
||||
...baseMainRoll.damageRollData.main.options.damageTypes,
|
||||
...baseSecondaryRoll.damageRollData.main.options.damageTypes
|
||||
]);
|
||||
mainRoll.damageRollData.main.options = {
|
||||
...baseMainRoll.damageRollData.main.options,
|
||||
damageTypes: [...joinedDamageTypes]
|
||||
};
|
||||
} else {
|
||||
systemData.damage[key] = damage;
|
||||
mainRoll.damageRollData.main = secondaryDamage.main;
|
||||
}
|
||||
}
|
||||
|
||||
for (const [key, damage] of Object.entries(secondaryDamage.resources ?? {})) {
|
||||
if (key in mainRoll.damageRollData.resources) {
|
||||
mainRoll.damageRollData.resources[key] = Roll.fromTerms([
|
||||
...baseMainRoll.damageRollData.resources[key].terms,
|
||||
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
|
||||
...baseSecondaryRoll.damageRollData.resources[key].terms
|
||||
]);
|
||||
|
||||
/* Joining the roll.options of both rolls */
|
||||
const joinedDamageTypes = new Set([
|
||||
...baseMainRoll.damageRollData.resources[key].options.damageTypes,
|
||||
...baseSecondaryRoll.damageRollData.resources[key].options.damageTypes
|
||||
]);
|
||||
mainRoll.damageRollData.resources[key].options = {
|
||||
...baseMainRoll.damageRollData.resources[key].options,
|
||||
damageTypes: [...joinedDamageTypes]
|
||||
};
|
||||
} else {
|
||||
mainRoll.damageRollData.resources[key] = damage;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
systemData.damage = secondaryDamage;
|
||||
mainRoll.damageRollData = secondaryDamage;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -752,13 +747,27 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
const mainActor = this.party.system.partyMembers.find(x => x.uuid === mainRoll.options.source.actor);
|
||||
mainRoll.options.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle');
|
||||
|
||||
/* This could assumably be done better. For some reason rolls don't get correctly done through rollData.toJSON */
|
||||
const systemData = {
|
||||
...mainRoll.options,
|
||||
damage: joinedRoll.damageRollData?.toJSON()
|
||||
};
|
||||
|
||||
if (joinedRoll.damageRollData.main) {
|
||||
systemData.damage.main = joinedRoll.damageRollData.toJSON();
|
||||
}
|
||||
for (const type of Object.keys(joinedRoll.damageRollData?.resources ?? {})) {
|
||||
systemData.damage.resources[type] = joinedRoll.damageRollData.resources[type].toJSON();
|
||||
}
|
||||
|
||||
const cls = getDocumentClass('ChatMessage'),
|
||||
msgData = {
|
||||
type: 'dualityRoll',
|
||||
user: game.user.id,
|
||||
title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'),
|
||||
speaker: cls.getSpeaker({ actor: mainActor }),
|
||||
system: mainRoll.options,
|
||||
system: systemData,
|
||||
rolls: [JSON.stringify(joinedRoll.roll)],
|
||||
sound: null,
|
||||
flags: { core: { RollTable: true } }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getUnusedDamageTypes } from '../../helpers/utils.mjs';
|
||||
import { DHDamageData } from '../../data/fields/action/damageField.mjs';
|
||||
import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs';
|
||||
|
||||
const { ApplicationV2 } = foundry.applications.api;
|
||||
|
|
@ -31,8 +31,10 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
|||
removeElement: this.removeElement,
|
||||
removeTransformActor: this.removeTransformActor,
|
||||
editEffect: this.editEffect,
|
||||
addDamage: this.addDamage,
|
||||
removeDamage: this.removeDamage,
|
||||
addDamage: this.#onAddDamage,
|
||||
removeDamage: this.#onRemoveDamage,
|
||||
addDamageResource: this.#onAddDamageResource,
|
||||
removeDamageResource: this.#onRemoveDamageResource,
|
||||
editDoc: this.editDoc,
|
||||
addTrigger: this.addTrigger,
|
||||
removeTrigger: this.removeTrigger,
|
||||
|
|
@ -157,9 +159,9 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
|||
context.tabs = this._getTabs(this.constructor.TABS);
|
||||
context.config = CONFIG.DH;
|
||||
if (this.action.damage) {
|
||||
context.allDamageTypesUsed = !getUnusedDamageTypes(this.action.damage.parts).length;
|
||||
|
||||
if (this.action.damage.hasOwnProperty('includeBase') && this.action.type === 'attack')
|
||||
const allKeys = Object.keys(CONFIG.DH.GENERAL.healingTypes);
|
||||
context.allDamageTypesUsed = allKeys.every(k => k in this.action._source.damage.resources);
|
||||
if (this.action.damage?.main?.hasOwnProperty('includeBase') && this.action.type === 'attack')
|
||||
context.hasBaseDamage = !!this.action.parent.attack;
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +255,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
|||
const submitData = this._prepareSubmitData(event, formData);
|
||||
|
||||
const data = foundry.utils.mergeObject(this.action.toObject(), submitData);
|
||||
this.action = await this.action.update(data);
|
||||
this.action = (await this.action.update(data)) ?? this.action;
|
||||
|
||||
this.sheetUpdate?.(this.action);
|
||||
this.render();
|
||||
|
|
@ -299,53 +301,70 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
|||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
static addDamage(_event) {
|
||||
if (!this.action.damage.parts) return;
|
||||
/** @this DHActionBaseConfig */
|
||||
static #onAddDamage() {
|
||||
if (!this.action.damage || this.action.damage?.main) return;
|
||||
|
||||
const choices = getUnusedDamageTypes(this.action._source.damage.parts);
|
||||
const data = this.action.toObject();
|
||||
data.damage.main = {
|
||||
...DHDamageData.schema.getInitialValue(),
|
||||
applyTo: 'hitPoints',
|
||||
type: 'physical'
|
||||
};
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
/** @this DHActionBaseConfig */
|
||||
static #onRemoveDamage() {
|
||||
if (!this.action.damage?.main) return;
|
||||
const data = this.action.toObject();
|
||||
data.damage.main = null;
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
/** @this DHActionBaseConfig */
|
||||
static #onAddDamageResource(_event) {
|
||||
if (!this.action.damage) return;
|
||||
|
||||
const allKeys = Object.keys(CONFIG.DH.GENERAL.healingTypes);
|
||||
const unused = allKeys.filter(k => !(k in this.action._source.damage.resources));
|
||||
const choices = unused.map(k => ({ value: k, label: _loc(CONFIG.DH.GENERAL.healingTypes[k].label) }));
|
||||
const content = new foundry.data.fields.StringField({
|
||||
label: game.i18n.localize('Damage Type'),
|
||||
label: _loc('DAGGERHEART.GENERAL.Resource.single'),
|
||||
choices,
|
||||
required: true
|
||||
}).toFormGroup(
|
||||
{},
|
||||
{
|
||||
name: 'type',
|
||||
localize: true,
|
||||
nameAttr: 'value',
|
||||
labelAttr: 'label'
|
||||
}
|
||||
).outerHTML;
|
||||
}).toFormGroup({}, {
|
||||
name: 'type',
|
||||
localize: true,
|
||||
nameAttr: 'value',
|
||||
labelAttr: 'label'
|
||||
}).outerHTML;
|
||||
|
||||
const callback = (_, button) => {
|
||||
const data = this.action.toObject();
|
||||
const type = choices[button.form.elements.type.value].value;
|
||||
const part = this.action.schema.fields.damage.fields.parts.element.getInitialValue();
|
||||
part.applyTo = type;
|
||||
if (type === CONFIG.DH.GENERAL.healingTypes.hitPoints.id)
|
||||
part.type = this.action.schema.fields.damage.fields.parts.element.fields.type.element.initial;
|
||||
|
||||
data.damage.parts[type] = part;
|
||||
data.damage.resources[type] = {
|
||||
...this.action.schema.fields.damage.fields.resources.element.getInitialValue(),
|
||||
applyTo: type
|
||||
};
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
};
|
||||
|
||||
const typeDialog = new foundry.applications.api.DialogV2({
|
||||
buttons: [
|
||||
foundry.utils.mergeObject(
|
||||
{
|
||||
action: 'ok',
|
||||
label: 'Confirm',
|
||||
icon: 'fas fa-check',
|
||||
default: true
|
||||
},
|
||||
{ callback: callback }
|
||||
)
|
||||
{
|
||||
action: 'ok',
|
||||
label: 'Confirm',
|
||||
icon: 'fas fa-check',
|
||||
default: true,
|
||||
callback
|
||||
}
|
||||
],
|
||||
content: content,
|
||||
rejectClose: false,
|
||||
modal: false,
|
||||
window: {
|
||||
title: game.i18n.localize('Add Damage')
|
||||
title: _loc('DAGGERHEART.ACTIONS.Config.damage.addResource')
|
||||
},
|
||||
position: { width: 300 }
|
||||
});
|
||||
|
|
@ -353,12 +372,12 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
|||
typeDialog.render(true);
|
||||
}
|
||||
|
||||
static removeDamage(_event, button) {
|
||||
if (!this.action.damage.parts) return;
|
||||
/** @this DHActionBaseConfig */
|
||||
static #onRemoveDamageResource(_event, button) {
|
||||
if (!this.action.damage?.resources) return;
|
||||
const data = this.action.toObject();
|
||||
const key = button.dataset.key;
|
||||
delete data.damage.parts[key];
|
||||
data.damage.parts[`${key}`] = _del;
|
||||
data.damage.resources[key] = _del;
|
||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
|
|||
.querySelector('.stacking-change-checkbox')
|
||||
?.addEventListener('change', this.stackingChangeToggle.bind(this));
|
||||
|
||||
htmlElement
|
||||
.querySelector('.range-dependence-change-checkbox')
|
||||
?.addEventListener('change', this.rangeDependenceChangeToggle.bind(this));
|
||||
|
||||
htmlElement
|
||||
.querySelector('.armor-change-checkbox')
|
||||
?.addEventListener('change', this.armorChangeToggle.bind(this));
|
||||
|
|
@ -224,6 +228,20 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
|
|||
return this.submit({ updateData: { system: systemData } });
|
||||
}
|
||||
|
||||
rangeDependenceChangeToggle(event) {
|
||||
const rangeFields = this.document.system.schema.fields.rangeDependence.fields;
|
||||
const systemData = {
|
||||
rangeDependence: event.target.checked
|
||||
? _replace({
|
||||
type: rangeFields.type.initial,
|
||||
target: rangeFields.target.initial,
|
||||
range: rangeFields.range.initial
|
||||
})
|
||||
: null
|
||||
};
|
||||
return this.submit({ updateData: { system: systemData } });
|
||||
}
|
||||
|
||||
armorChangeToggle(event) {
|
||||
if (event.target.checked) {
|
||||
this.addArmorChange();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { DHDamageData } from '../../data/fields/action/damageField.mjs';
|
||||
import DHBaseActorSettings from '../sheets/api/actor-setting.mjs';
|
||||
|
||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||
|
|
@ -8,8 +9,10 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
|
|||
classes: ['adversary-settings'],
|
||||
position: { width: 455, height: 'auto' },
|
||||
actions: {
|
||||
addExperience: DHAdversarySettings.#addExperience,
|
||||
removeExperience: DHAdversarySettings.#removeExperience
|
||||
addExperience: this.#onAddExperience,
|
||||
removeExperience: this.#onRemoveExperience,
|
||||
addDamage: this.#onAddDamage,
|
||||
removeDamage: this.#onRemoveDamage
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -71,7 +74,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
|
|||
* Adds a new experience entry to the actor.
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #addExperience() {
|
||||
static async #onAddExperience() {
|
||||
const newExperience = {
|
||||
name: 'Experience',
|
||||
modifier: 0
|
||||
|
|
@ -83,7 +86,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
|
|||
* Removes an experience entry from the actor.
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #removeExperience(_, target) {
|
||||
static async #onRemoveExperience(_, target) {
|
||||
const experience = this.actor.system.experiences[target.dataset.experience];
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
|
|
@ -98,4 +101,28 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
|
|||
|
||||
await this.actor.update({ [`system.experiences.${target.dataset.experience}`]: _del });
|
||||
}
|
||||
|
||||
/**
|
||||
* @this DHAdversarySettings
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static #onAddDamage() {
|
||||
this.actor.update({
|
||||
'system.attack.damage.main': {
|
||||
...DHDamageData.schema.getInitialValue(),
|
||||
applyTo: 'hitPoints',
|
||||
type: 'physical'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @this DHAdversarySettings
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static #onRemoveDamage() {
|
||||
this.actor.update({
|
||||
'system.attack.damage.main': null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
module/applications/sheets/actors/_types.d.ts
vendored
10
module/applications/sheets/actors/_types.d.ts
vendored
|
|
@ -1,8 +1,18 @@
|
|||
import DhCompanion from '../../../data/actor/companion.mjs';
|
||||
import DhParty from '../../../data/actor/party.mjs';
|
||||
import DhpActor from '../../../documents/actor.mjs';
|
||||
|
||||
declare module './companion.mjs' {
|
||||
export default interface DhCompanionSheet {
|
||||
actor: DhpActor<DhCompanion>;
|
||||
document: DhpActor<DhCompanion>;
|
||||
}
|
||||
}
|
||||
|
||||
declare module './party.mjs' {
|
||||
export default interface PartySheet {
|
||||
actor: DhpActor<DhParty>;
|
||||
document: DhpActor<DhParty>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -915,7 +915,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
const doc = await getDocFromElement(button);
|
||||
const { available } = this.document.system.loadoutSlot;
|
||||
if (doc.system.inVault && !available && !doc.system.loadoutIgnore) {
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached'));
|
||||
return ui.notifications.warn('DAGGERHEART.UI.Notifications.loadoutMaxReached', { localize: true });
|
||||
}
|
||||
|
||||
await doc?.update({ 'system.inVault': !doc.system.inVault });
|
||||
|
|
@ -1216,10 +1216,22 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
if (this.document.uuid === item.parent?.uuid) {
|
||||
// Check for same actor drag/drop attempts
|
||||
const isSameActor = this.document.uuid === item.parent?.uuid;
|
||||
const loadoutFieldset = event.target.closest('[data-in-vault]');
|
||||
const vaulting = loadoutFieldset?.dataset.inVault === 'true';
|
||||
if (isSameActor && loadoutFieldset && item.type === 'domainCard' && vaulting !== item.system.inVault) {
|
||||
// This is likely an attempt to vault or unvault an item
|
||||
const { available } = this.document.system.loadoutSlot;
|
||||
if (!vaulting && !available && !item.system.loadoutIgnore) {
|
||||
return ui.notifications.warn('DAGGERHEART.UI.Notifications.loadoutMaxReached', { localize: true });
|
||||
}
|
||||
return item.update({ 'system.inVault': vaulting });
|
||||
} else if (isSameActor) {
|
||||
return super._onDropItem(event, item);
|
||||
}
|
||||
|
||||
// Handle beastforms
|
||||
if (item.type === 'beastform') {
|
||||
if (this.document.effects.find(x => x.type === 'beastform')) {
|
||||
return ui.notifications.warn(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import DaggerheartMenu from '../../sidebar/tabs/daggerheartMenu.mjs';
|
|||
import { socketEvent } from '../../../systemRegistration/socket.mjs';
|
||||
import DhpActor from '../../../documents/actor.mjs';
|
||||
|
||||
export default class Party extends DHBaseActorSheet {
|
||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||
|
||||
export default class PartySheet extends DHBaseActorSheet {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
|
|
@ -24,17 +26,17 @@ export default class Party extends DHBaseActorSheet {
|
|||
resizable: true
|
||||
},
|
||||
actions: {
|
||||
openDocument: Party.#openDocument,
|
||||
deletePartyMember: Party.#deletePartyMember,
|
||||
toggleHope: Party.#toggleHope,
|
||||
toggleHitPoints: Party.#toggleHitPoints,
|
||||
toggleStress: Party.#toggleStress,
|
||||
toggleArmorSlot: Party.#toggleArmorSlot,
|
||||
tempBrowser: Party.#tempBrowser,
|
||||
refeshActions: Party.#refeshActions,
|
||||
triggerRest: Party.#triggerRest,
|
||||
tagTeamRoll: Party.#tagTeamRoll,
|
||||
groupRoll: Party.#groupRoll
|
||||
openDocument: PartySheet.#onOpenDocument,
|
||||
deletePartyMember: PartySheet.#onDeletePartyMember,
|
||||
toggleHope: PartySheet.#onToggleHope,
|
||||
toggleHitPoints: PartySheet.#onToggleHitPoints,
|
||||
toggleStress: PartySheet.#onToggleStress,
|
||||
toggleArmorSlot: PartySheet.#onToggleArmorSlot,
|
||||
tempBrowser: PartySheet.#onTempBrowser,
|
||||
refreshActions: PartySheet.#onRefreshActions,
|
||||
triggerRest: PartySheet.#onTriggerRest,
|
||||
tagTeamRoll: PartySheet.#onTagTeamRoll,
|
||||
groupRoll: PartySheet.#onGroupRoll
|
||||
},
|
||||
dragDrop: [{ dragSelector: '[data-item-id]', dropSelector: null }]
|
||||
};
|
||||
|
|
@ -72,6 +74,23 @@ export default class Party extends DHBaseActorSheet {
|
|||
this._createSearchFilter();
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
_toggleDisabled(disabled) {
|
||||
// Overriden to only disable text inputs by default if the user is a member
|
||||
const isMember = this.actor.system.partyMembers.some(
|
||||
m => m.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||
);
|
||||
if (!isMember) return super._toggleDisabled(disabled);
|
||||
|
||||
const form = this.form;
|
||||
for (const input of form.querySelectorAll('input:not([type=search]), .editor.prosemirror')) {
|
||||
input.disabled = disabled;
|
||||
}
|
||||
for (const element of form.querySelectorAll('.input[contenteditable]')) {
|
||||
element.classList.toggle('disabled', disabled);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Prepare Context */
|
||||
/* -------------------------------------------- */
|
||||
|
|
@ -198,8 +217,16 @@ export default class Party extends DHBaseActorSheet {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Event handlers */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static async #openDocument(_, target) {
|
||||
/**
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onOpenDocument(_, target) {
|
||||
const uuid = target.dataset.uuid;
|
||||
const document = await foundry.utils.fromUuid(uuid);
|
||||
document?.sheet?.render(true);
|
||||
|
|
@ -207,9 +234,10 @@ export default class Party extends DHBaseActorSheet {
|
|||
|
||||
/**
|
||||
* Toggles a hope resource value.
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #toggleHope(_, target) {
|
||||
static async #onToggleHope(_, target) {
|
||||
const hopeValue = Number.parseInt(target.dataset.value);
|
||||
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||
const newValue = actor.system.resources.hope.value >= hopeValue ? hopeValue - 1 : hopeValue;
|
||||
|
|
@ -219,9 +247,10 @@ export default class Party extends DHBaseActorSheet {
|
|||
|
||||
/**
|
||||
* Toggles a hp resource value.
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #toggleHitPoints(_, target) {
|
||||
static async #onToggleHitPoints(_, target) {
|
||||
const hitPointsValue = Number.parseInt(target.dataset.value);
|
||||
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||
const newValue = actor.system.resources.hitPoints.value >= hitPointsValue ? hitPointsValue - 1 : hitPointsValue;
|
||||
|
|
@ -231,9 +260,10 @@ export default class Party extends DHBaseActorSheet {
|
|||
|
||||
/**
|
||||
* Toggles a stress resource value.
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #toggleStress(_, target) {
|
||||
static async #onToggleStress(_, target) {
|
||||
const stressValue = Number.parseInt(target.dataset.value);
|
||||
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||
const newValue = actor.system.resources.stress.value >= stressValue ? stressValue - 1 : stressValue;
|
||||
|
|
@ -243,9 +273,10 @@ export default class Party extends DHBaseActorSheet {
|
|||
|
||||
/**
|
||||
* Toggles a armor slot resource value.
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #toggleArmorSlot(_, target) {
|
||||
static async #onToggleArmorSlot(_, target) {
|
||||
const actor = await foundry.utils.fromUuid(target.dataset.actorId);
|
||||
const { value, max } = actor.system.armorScore;
|
||||
const inputValue = Number.parseInt(target.dataset.value);
|
||||
|
|
@ -258,12 +289,19 @@ export default class Party extends DHBaseActorSheet {
|
|||
|
||||
/**
|
||||
* Opens Compedium Browser
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #tempBrowser(_, target) {
|
||||
static async #onTempBrowser(_, target) {
|
||||
new ItemBrowser().render({ force: true });
|
||||
}
|
||||
|
||||
static async #refeshActions() {
|
||||
/**
|
||||
* @todo Is this unused?
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onRefreshActions() {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
title: 'New Section',
|
||||
|
|
@ -281,7 +319,11 @@ export default class Party extends DHBaseActorSheet {
|
|||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
static async #triggerRest(_, button) {
|
||||
/**
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onTriggerRest(_, button) {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
title: game.i18n.localize(`DAGGERHEART.APPLICATIONS.Downtime.${button.dataset.type}.title`),
|
||||
|
|
@ -304,6 +346,30 @@ export default class Party extends DHBaseActorSheet {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onDeletePartyMember(event, target) {
|
||||
const doc = await foundry.utils.fromUuid(target.closest('[data-uuid]')?.dataset.uuid);
|
||||
if (!event.shiftKey) {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
title: game.i18n.format('DAGGERHEART.ACTORS.Party.RemoveConfirmation.title', {
|
||||
name: doc.name
|
||||
})
|
||||
},
|
||||
content: game.i18n.format('DAGGERHEART.ACTORS.Party.RemoveConfirmation.text', { name: doc.name })
|
||||
});
|
||||
|
||||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
const currentMembers = this.document.system.partyMembers.map(x => x.uuid);
|
||||
const newMembersList = currentMembers.filter(uuid => uuid !== doc.uuid);
|
||||
await this.document.update({ 'system.partyMembers': newMembersList });
|
||||
}
|
||||
|
||||
static async downtimeMoveQuery({ actorId, downtimeType }) {
|
||||
const actor = await foundry.utils.fromUuid(actorId);
|
||||
if (!actor || !actor?.isOwner) return;
|
||||
|
|
@ -312,11 +378,19 @@ export default class Party extends DHBaseActorSheet {
|
|||
});
|
||||
}
|
||||
|
||||
static async #tagTeamRoll() {
|
||||
/**
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onTagTeamRoll() {
|
||||
new game.system.api.applications.dialogs.TagTeamDialog(this.document).render({ force: true });
|
||||
}
|
||||
|
||||
static async #groupRoll(_params) {
|
||||
/**
|
||||
* @this PartySheet
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onGroupRoll(_params) {
|
||||
new game.system.api.applications.dialogs.GroupRollDialog(this.document).render({ force: true });
|
||||
}
|
||||
|
||||
|
|
@ -460,11 +534,10 @@ export default class Party extends DHBaseActorSheet {
|
|||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
async _onDropActor(event, document) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||
if (document instanceof DhpActor && Party.ALLOWED_ACTOR_TYPES.includes(document.type)) {
|
||||
if (document instanceof DhpActor && PartySheet.ALLOWED_ACTOR_TYPES.includes(document.type)) {
|
||||
const currentMembers = this.document.system.partyMembers.map(x => x.uuid);
|
||||
if (currentMembers.includes(data.uuid)) {
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.duplicateCharacter'));
|
||||
|
|
@ -477,24 +550,4 @@ export default class Party extends DHBaseActorSheet {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
static async #deletePartyMember(event, target) {
|
||||
const doc = await foundry.utils.fromUuid(target.closest('[data-uuid]')?.dataset.uuid);
|
||||
if (!event.shiftKey) {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
title: game.i18n.format('DAGGERHEART.ACTORS.Party.RemoveConfirmation.title', {
|
||||
name: doc.name
|
||||
})
|
||||
},
|
||||
content: game.i18n.format('DAGGERHEART.ACTORS.Party.RemoveConfirmation.text', { name: doc.name })
|
||||
});
|
||||
|
||||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
const currentMembers = this.document.system.partyMembers.map(x => x.uuid);
|
||||
const newMembersList = currentMembers.filter(uuid => uuid !== doc.uuid);
|
||||
await this.document.update({ 'system.partyMembers': newMembersList });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
addFeature: DHBaseItemSheet.#addFeature,
|
||||
deleteFeature: DHBaseItemSheet.#deleteFeature,
|
||||
addResource: DHBaseItemSheet.#addResource,
|
||||
removeResource: DHBaseItemSheet.#removeResource
|
||||
removeResource: DHBaseItemSheet.#removeResource,
|
||||
editGMNote: DHBaseItemSheet.#onEditGMNote
|
||||
},
|
||||
dragDrop: [
|
||||
{ dragSelector: null, dropSelector: '.drop-section' },
|
||||
|
|
@ -76,10 +77,16 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
/**@inheritdoc */
|
||||
async _preparePartContext(partId, context, options) {
|
||||
await super._preparePartContext(partId, context, options);
|
||||
const TextEditor = foundry.applications.ux.TextEditor.implementation;
|
||||
|
||||
switch (partId) {
|
||||
case 'description':
|
||||
context.enrichedDescription = await this.document.system.getEnrichedDescription();
|
||||
context.enrichedDescription = await this.document.system.getEnrichedDescription({ gmNotes: false });
|
||||
context.enrichedGMNotes = await TextEditor.implementation.enrichHTML(this.item.system.gmNotes, {
|
||||
relativeTo: this.item,
|
||||
rollData: this.item.getRollData(),
|
||||
secrets: this.item.isOwner
|
||||
})
|
||||
break;
|
||||
case 'effects':
|
||||
await this._prepareEffectsContext(context, options);
|
||||
|
|
@ -331,4 +338,45 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the Add GM Note button being pressed. This is only used when an item has no GM notes.
|
||||
* Later edits to a GM note instead go through the normal editor toggle workflow.
|
||||
* @this DHBaseItemSheet
|
||||
*/
|
||||
static #onEditGMNote() {
|
||||
// Open the editor, which might be hidden. We remove the css class to hide temporarily
|
||||
// so that menu auto resizing functions properly.
|
||||
const editor = this.element.querySelector('prose-mirror[name="system.gmNotes"]');
|
||||
const wasHidden = editor.classList.contains('hide-if-inactive');
|
||||
editor.classList.remove('hide-if-inactive');
|
||||
editor.open = true;
|
||||
window.setTimeout(() => {
|
||||
if (wasHidden) editor.classList.add('hide-if-inactive');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
// Render an add gmnotes button if there are no set GM notes.
|
||||
// We need to re-render on close since its possible to prosemirror to close *without* triggering a full re-render
|
||||
if (game.user.isGM && !this.item.system.gmNotes) {
|
||||
const description = this.element.querySelector('[name="system.description"]');
|
||||
const addButton = () => {
|
||||
if (description.querySelector('[data-action=editGMNote]')) return;
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.classList.add('icon', 'toggle', 'fa-regular', 'fa-note-medical');
|
||||
button.dataset.action = 'editGMNote';
|
||||
button.dataset.tooltip = 'DAGGERHEART.ITEMS.Base.addGMNote';
|
||||
description.appendChild(button);
|
||||
}
|
||||
|
||||
addButton();
|
||||
description.addEventListener('close', () => addButton());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
const message = game.messages.get(li.dataset.messageId);
|
||||
return message.system.hasRoll && (game.user.isGM || message.isAuthor);
|
||||
},
|
||||
callback: async li => {
|
||||
onClick: async (_event, li) => {
|
||||
const message = game.messages.get(li.dataset.messageId);
|
||||
const reroll = await message.rolls[0].reroll({ liveRoll: true });
|
||||
message.update({ rolls: [reroll] });
|
||||
|
|
@ -126,7 +126,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
: false;
|
||||
return (game.user.isGM || message.isAuthor) && hasRolledDamage;
|
||||
},
|
||||
callback: async li => {
|
||||
onClick: async (_event, li) => {
|
||||
const message = game.messages.get(li.dataset.messageId);
|
||||
const update = await message.system.getRerolledDamage();
|
||||
message.update(update);
|
||||
|
|
@ -182,28 +182,15 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
}
|
||||
|
||||
async onRollSimple(event, message) {
|
||||
const buttonType = event.target.dataset.type ?? 'damage',
|
||||
total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0),
|
||||
damages = {
|
||||
hitPoints: {
|
||||
parts: [
|
||||
{
|
||||
applyTo: 'hitPoints',
|
||||
damageTypes: [],
|
||||
total
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
targets = Array.from(game.user.targets);
|
||||
|
||||
const buttonType = event.target.dataset.type ?? 'damage';
|
||||
const total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0);
|
||||
const targets = Array.from(game.user.targets);
|
||||
if (targets.length === 0)
|
||||
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelected'));
|
||||
|
||||
targets.forEach(target => {
|
||||
if (buttonType === 'healing') target.actor.takeHealing(damages);
|
||||
else target.actor.takeDamage(damages);
|
||||
});
|
||||
for (const target of targets) {
|
||||
if (buttonType === 'healing') target.actor.takeHealing({ hitPoints: total });
|
||||
else target.actor.takeDamage({ total });
|
||||
}
|
||||
}
|
||||
|
||||
async abilityUseButton(event, message) {
|
||||
|
|
@ -259,26 +246,17 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
}
|
||||
|
||||
const message = game.messages.get(messageData._id);
|
||||
const target = event.target.closest('[data-die-index]');
|
||||
const target = event.target.closest('[data-result]');
|
||||
|
||||
if (target.dataset.type === 'damage') {
|
||||
const { damageType, part, dice, result } = target.dataset;
|
||||
const damagePart = message.system.damage[damageType].parts[part];
|
||||
const { parsedRoll, rerolledDice } = await game.system.api.dice.DamageRoll.reroll(damagePart, dice, result);
|
||||
const damageParts = message.system.damage[damageType].parts.map((damagePart, index) => {
|
||||
if (index !== Number(part)) return damagePart;
|
||||
return {
|
||||
...damagePart,
|
||||
total: parsedRoll.total,
|
||||
dice: rerolledDice
|
||||
};
|
||||
});
|
||||
const updateMessage = game.messages.get(message._id);
|
||||
await updateMessage.update({
|
||||
[`system.damage.${damageType}`]: {
|
||||
total: parsedRoll.total,
|
||||
parts: damageParts
|
||||
}
|
||||
const { isResource, damageType, dice, result } = target.dataset;
|
||||
await message.system.damage.rerollDamageDie(isResource, damageType, dice, result);
|
||||
|
||||
const updatePath = isResource ? `system.damage.resources.${damageType}` : 'system.damage.main';
|
||||
const updateValue = isResource ?
|
||||
message.system.damage.resources[damageType] : message.system.damage.main;
|
||||
await message.update({
|
||||
[updatePath]: updateValue.toJSON()
|
||||
});
|
||||
} else {
|
||||
const rerollDice = message.system.roll.dice[target.dataset.dieIndex];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue