Compare commits

..

No commits in common. "87ee0276037a4734893b9b767245f4a4ffc8db28" and "221b84726d30ba9a6e25f24bc2f422e283a68ffb" have entirely different histories.

8 changed files with 79 additions and 140 deletions

View file

@ -1,5 +1,4 @@
import { ResourceUpdateMap } from '../../data/action/baseAction.mjs'; import { ResourceUpdateMap } from '../../data/action/baseAction.mjs';
import { ChatDamageData } from '../../data/chat-message/chatDamageData.mjs';
import { MemberData } from '../../data/tagTeamData.mjs'; import { MemberData } from '../../data/tagTeamData.mjs';
import { getCritDamageBonus, shouldUseHopeFearAutomation } from '../../helpers/utils.mjs'; import { getCritDamageBonus, shouldUseHopeFearAutomation } from '../../helpers/utils.mjs';
import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
@ -237,6 +236,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected); const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected);
const critSelected = !selectedRoll ? undefined : (selectedRoll?.rollData?.options?.roll?.isCritical ?? false); const critSelected = !selectedRoll ? undefined : (selectedRoll?.rollData?.options?.roll?.isCritical ?? false);
const damage = data.rollData?.options?.damage;
return { return {
...data, ...data,
@ -247,8 +247,8 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
hasRolled: Boolean(data.rollData), hasRolled: Boolean(data.rollData),
rollOptions, rollOptions,
damageRollOptions, damageRollOptions,
damage: data.damageRollData, damage: damage,
critDamage: await this.getCriticalDamage(data.damageRollData), critDamage: await this.getCriticalDamage(damage),
useCritDamage: critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical) useCritDamage: critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical)
}; };
} }
@ -609,20 +609,47 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
); );
} }
async getCriticalDamage(origDamage) { async getCriticalDamage(damage) {
const newDamage = origDamage ? ChatDamageData.fromJSON(JSON.stringify(origDamage)) : null; const newDamage = foundry.utils.deepClone(damage);
for (let key in newDamage?.types ?? {}) { for (let key in newDamage) {
const damage = newDamage.types[key]; var damage = newDamage[key];
const criticalDamage = await getCritDamageBonus(damage.roll.formula); damage.formula = '';
if (!criticalDamage) continue; damage.total = 0;
const criticalTerm = new foundry.dice.terms.NumericTerm({ number: criticalDamage, evaluated: true }); for (let part of damage.parts) {
criticalTerm.evaluate(); const criticalDamage = await getCritDamageBonus(part.formula);
damage.roll = await Roll.fromTerms([ if (criticalDamage) {
...origDamage.types[key].roll.terms, part.modifierTotal += criticalDamage;
new foundry.dice.terms.OperatorTerm({ operator: '+' }), part.total += criticalDamage;
criticalTerm 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;
}
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; return newDamage;
@ -658,34 +685,29 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
if (!baseMainRoll?.rollData || !baseSecondaryRoll) return null; if (!baseMainRoll?.rollData || !baseSecondaryRoll) return null;
const mainRoll = new MemberData(baseMainRoll.toObject()); const mainRoll = new MemberData(baseMainRoll.toObject());
mainRoll.damageRollData = baseMainRoll.damageRollData ? const secondaryRollData = new MemberData(baseSecondaryRoll.toObject()).rollData;
ChatDamageData.fromJSON(JSON.stringify(baseMainRoll.damageRollData)) : null;
const secondaryRoll = new MemberData(baseSecondaryRoll.toObject());
secondaryRoll.damageRollData = baseSecondaryRoll.damageRollData ?
ChatDamageData.fromJSON(JSON.stringify(baseSecondaryRoll.damageRollData)) : null;
const systemData = mainRoll.rollData.options; const systemData = mainRoll.rollData.options;
const isCritical = overrideIsCritical ?? systemData.roll.isCritical; const isCritical = overrideIsCritical ?? systemData.roll.isCritical;
if (isCritical) mainRoll.damageRollData = await this.getCriticalDamage(systemData.damageRollData); if (isCritical) systemData.damage = await this.getCriticalDamage(systemData.damage);
if (secondaryRoll.damageRollData) { if (secondaryRollData?.options.hasDamage) {
const secondaryDamage = (displayVersion ? overrideIsCritical : isCritical) const secondaryDamage = (displayVersion ? overrideIsCritical : isCritical)
? await this.getCriticalDamage(secondaryRoll.damageRollData) ? await this.getCriticalDamage(secondaryRollData.options.damage)
: secondaryRoll.damageRollData; : secondaryRollData.options.damage;
if (mainRoll.damageRollData) { if (systemData.damage) {
for (const [key, damage] of Object.entries(secondaryDamage.types ?? {})) { for (const [key, damage] of Object.entries(secondaryDamage ?? {})) {
if (key in mainRoll.damageRollData.types) { if (key in systemData.damage) {
mainRoll.damageRollData.types[key].roll = Roll.fromTerms([ systemData.damage[key].formula = [systemData.damage[key]?.formula, damage.formula]
...baseMainRoll.damageRollData.types[key].roll.terms, .filter(x => x)
new foundry.dice.terms.OperatorTerm({ operator: '+' }), .join(' + ');
...baseSecondaryRoll.damageRollData.types[key].roll.terms systemData.damage[key].total += damage.total;
]); systemData.damage[key].parts.push(...damage.parts);
} else { } else {
mainRoll.damageRollData.types[key] = damage; systemData.damage[key] = damage;
} }
} }
} else { } else {
mainRoll.damageRollData = secondaryDamage; systemData.damage = secondaryDamage;
} }
} }
@ -740,23 +762,13 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
const mainActor = this.party.system.partyMembers.find(x => x.uuid === mainRoll.options.source.actor); const mainActor = this.party.system.partyMembers.find(x => x.uuid === mainRoll.options.source.actor);
mainRoll.options.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle'); 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()
};
for (const type of Object.keys(joinedRoll.damageRollData.types)) {
systemData.damage.types[type].roll = joinedRoll.damageRollData.types[type].roll.toJSON();
}
const cls = getDocumentClass('ChatMessage'), const cls = getDocumentClass('ChatMessage'),
msgData = { msgData = {
type: 'dualityRoll', type: 'dualityRoll',
user: game.user.id, user: game.user.id,
title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'), title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'),
speaker: cls.getSpeaker({ actor: mainActor }), speaker: cls.getSpeaker({ actor: mainActor }),
system: systemData, system: mainRoll.options,
rolls: [JSON.stringify(joinedRoll.roll)], rolls: [JSON.stringify(joinedRoll.roll)],
sound: null, sound: null,
flags: { core: { RollTable: true } } flags: { core: { RollTable: true } }

View file

@ -3,7 +3,6 @@ import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayFie
import TagTeamData from '../tagTeamData.mjs'; import TagTeamData from '../tagTeamData.mjs';
import GroupRollData from '../groupRollData.mjs'; import GroupRollData from '../groupRollData.mjs';
import { GoldField } from '../fields/actorField.mjs'; import { GoldField } from '../fields/actorField.mjs';
import { ChatDamageData } from '../chat-message/chatDamageData.mjs';
export default class DhParty extends BaseDataActor { export default class DhParty extends BaseDataActor {
/** @inheritdoc */ /** @inheritdoc */
@ -49,15 +48,6 @@ export default class DhParty extends BaseDataActor {
} }
} }
prepareDerivedData() {
for (const memberKey in this.tagTeam.members) {
const member = this.tagTeam.members[memberKey];
member.damageRollData = member.rollData?.options.damage ?
ChatDamageData.fromJSON(JSON.stringify(member.rollData.options.damage)) : null;
member.damageRollData?.prepareRolls();
}
}
_onCreate(data, options, userId) { _onCreate(data, options, userId) {
super._onCreate(data, options, userId); super._onCreate(data, options, userId);

View file

@ -1,8 +1,7 @@
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
import { triggerChatRollFx } from '../helpers/utils.mjs'; import { triggerChatRollFx } from '../helpers/utils.mjs';
import BaseRoll from './baseRoll.mjs';
export default class DHRoll extends BaseRoll { export default class DHRoll extends Roll {
baseTerms = []; baseTerms = [];
constructor(formula, data = {}, options = {}) { constructor(formula, data = {}, options = {}) {
super(formula, data, foundry.utils.mergeObject(options, { roll: [] }, { overwrite: false })); super(formula, data, foundry.utils.mergeObject(options, { roll: [] }, { overwrite: false }));

View file

@ -1,20 +0,0 @@
import { MigrationHandlerBase } from './base.mjs';
export class Migration_2_6_0 extends MigrationHandlerBase {
version = '2.6.0';
/** @inheritdoc */
async updateActorSource(actor) {
if (actor.type === 'party') {
return {
_id: actor._id,
system: {
tagTeam: {
initiator: null,
members: _replace({})
}
}
};
}
}
}

View file

@ -1,9 +1,8 @@
/** /**
* @import DHItem from "../../documents/item.mjs"; * @import DHItem from "../../documents/item.mjs";
* @import DhActor from "../../documents/actor.mjs";
*/ */
/**
/**
* The base class of an async migration. * The base class of an async migration.
* These are generally run between versions for things that require compendiums or must be done in post. * These are generally run between versions for things that require compendiums or must be done in post.
* The migrate() functions calls the various updateXSource() functions. * The migrate() functions calls the various updateXSource() functions.
@ -23,16 +22,6 @@ export class MigrationHandlerBase {
return null; return null;
} }
/**
* Update a world actor
* @param {DhActor} actor
* @returns {Promise<object>}
* @protected
*/
async updateActorSource(actor) {
return null;
}
async migrate() { async migrate() {
// todo: handle more than just migrating effects. Right now this can only migrate effects // todo: handle more than just migrating effects. Right now this can only migrate effects
// NOTE: the preload is hardcoded, we should not hardcode it // NOTE: the preload is hardcoded, we should not hardcode it
@ -71,39 +60,10 @@ export class MigrationHandlerBase {
} }
}; };
const updateActor = async actor => { for (const actor of game.actors) {
const actorUpdate = await this.updateActorSource(actor);
if (actorUpdate) {
batch.push({
action: 'update',
documentName: 'Actor',
updates: [actorUpdate]
});
}
const aeUpdates = [];
for (const item of actor.items) { for (const item of actor.items) {
await updateItem(item); await updateItem(item);
} }
for (const effect of actor.effects) {
const changes = await this.updateActiveEffectSource(effect.toObject(), { parent: actor });
if (changes) aeUpdates.push(changes);
}
if (aeUpdates.length) {
batch.push({
action: 'update',
documentName: 'ActiveEffect',
updates: aeUpdates,
parent: actor
});
}
}
for (const actor of game.actors) {
await updateActor(actor);
progress.advance(); progress.advance();
} }
for (const item of game.items) { for (const item of game.items) {

View file

@ -1,6 +1,5 @@
import { defaultRestOptions } from '../config/generalConfig.mjs'; import { defaultRestOptions } from '../config/generalConfig.mjs';
import { Migration_2_5_2 } from './migration-handlers/2_5_2.mjs'; import { Migration_2_5_2 } from './migration-handlers/2_5_2.mjs';
import { Migration_2_6_0 } from './migration-handlers/2_6_0.mjs';
export async function runMigrations() { export async function runMigrations() {
let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion); let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion);
@ -330,8 +329,7 @@ export async function runMigrations() {
/* -------------------------------------------- */ /* -------------------------------------------- */
const migrations = [ const migrations = [
new Migration_2_5_2(), new Migration_2_5_2()
new Migration_2_6_0()
].filter(m => m.version && foundry.utils.isNewerVersion(m.version, lastMigrationVersion)); ].filter(m => m.version && foundry.utils.isNewerVersion(m.version, lastMigrationVersion));
for (const handler of migrations) { for (const handler of migrations) {

View file

@ -1,25 +1,25 @@
{{#each damage.types as |damage key|}} {{#each damage as |damage key|}}
<div class="roll-data {{#if isCritical}}critical{{/if}}"> <div class="roll-data {{#if isCritical}}critical{{/if}}">
<div class="duality-label"> <div class="duality-label">
<span>{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}:</span> <span>{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}:</span>
<span>{{damage.roll.total}}</span> <span>{{damage.total}}</span>
</div> </div>
{{#with damage.roll}} {{#each damage.parts as |part|}}
<div class="roll-dice-container"> <div class="roll-dice-container">
{{#each this.dice as |dice index|}} {{#each part.dice as |dice index|}}
<a class="roll-dice" data-action="rerollDamageDice" data-member-key="{{../../../key}}" data-damage-key="{{@../../key}}" data-dice="{{index}}"> <a class="roll-dice" data-action="rerollDamageDice" data-member-key="{{../../../key}}" data-damage-key="{{@../../key}}" data-part="{{@../index}}" data-dice="{{index}}">
<span class="dice-label">{{dice.total}}</span> <span class="dice-label">{{dice.total}}</span>
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" dice.denomination ".svg"}}" /> <img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" dice.dice ".svg"}}" />
</a> </a>
{{#unless @last}} {{#unless @last}}
<span class="roll-operator">+</span> <span class="roll-operator">+</span>
{{/unless}} {{/unless}}
{{/each}} {{/each}}
{{#if this.modifierTotal}} {{#if part.modifierTotal}}
{{#if this.dice.length}}<span class="roll-operator">{{#if (gte this.modifierTotal 0)}}+{{else}}-{{/if}}</span>{{/if}} {{#if part.dice.length}}<span class="roll-operator">{{#if (gte part.modifierTotal 0)}}+{{else}}-{{/if}}</span>{{/if}}
<span class="roll-value">{{positive this.modifierTotal}}</span> <span class="roll-value">{{positive part.modifierTotal}}</span>
{{/if}} {{/if}}
</div> </div>
{{/with}} {{/each}}
</div> </div>
{{/each}} {{/each}}

View file

@ -6,22 +6,22 @@
{{#if hintText}} {{#if hintText}}
<div class="hint">{{localize hintText}}</div> <div class="hint">{{localize hintText}}</div>
{{else}} {{else}}
{{#if joinedRoll.rollData}} {{#if joinedRoll.roll}}
<div class="result-container"> <div class="result-container">
<span class="result-section-label">{{localize "DAGGERHEART.GENERAL.dualityRoll"}}</span> <span class="result-section-label">{{localize "DAGGERHEART.GENERAL.dualityRoll"}}</span>
<div class="result-info"> <div class="result-info">
<div class="damage-info">{{joinedRoll.rollData.total}}</div> <div class="damage-info">{{joinedRoll.roll.total}}</div>
<div>{{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.roll.totalLabel}}</div> <div>{{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.roll.totalLabel}}</div>
</div> </div>
</div> </div>
{{/if}} {{/if}}
{{#if joinedRoll.damageRollData}} {{#if joinedRoll.rollData.options.hasDamage}}
<div class="result-container"> <div class="result-container">
<span class="result-section-label">{{localize "DAGGERHEART.GENERAL.damage"}}</span> <span class="result-section-label">{{localize "DAGGERHEART.GENERAL.damage"}}</span>
{{#each joinedRoll.damageRollData.types as |damage key|}} {{#each joinedRoll.rollData.options.damage as |damage key|}}
<div class="result-info"> <div class="result-info">
<div>{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}</div> <div>{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}</div>
<div class="damage-info">{{damage.roll.total}}</div> <div class="damage-info">{{damage.total}}</div>
</div> </div>
{{/each}} {{/each}}
</div> </div>