mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-21 15:03:37 +02:00
Merged with main
This commit is contained in:
commit
9bea8d6a97
64 changed files with 1556 additions and 441 deletions
|
|
@ -22,6 +22,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
|||
},
|
||||
actions: {
|
||||
toggleSelectedEffect: this.toggleSelectedEffect,
|
||||
updateGroupAttack: this.updateGroupAttack,
|
||||
toggleCritical: this.toggleCritical,
|
||||
submitRoll: this.submitRoll
|
||||
},
|
||||
|
|
@ -64,15 +65,40 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
|||
context.hasSelectedEffects = Boolean(Object.keys(this.selectedEffects).length);
|
||||
context.selectedEffects = this.selectedEffects;
|
||||
|
||||
context.damageOptions = this.config.damageOptions;
|
||||
context.rangeOptions = CONFIG.DH.GENERAL.groupAttackRange;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static updateRollConfiguration(_event, _, formData) {
|
||||
const { ...rest } = foundry.utils.expandObject(formData.object);
|
||||
foundry.utils.mergeObject(this.config.roll, rest.roll);
|
||||
foundry.utils.mergeObject(this.config.modifiers, rest.modifiers);
|
||||
this.config.selectedMessageMode = rest.selectedMessageMode;
|
||||
const data = foundry.utils.expandObject(formData.object);
|
||||
foundry.utils.mergeObject(this.config.roll, data.roll);
|
||||
foundry.utils.mergeObject(this.config.modifiers, data.modifiers);
|
||||
this.config.selectedMessageMode = data.selectedMessageMode;
|
||||
|
||||
if (data.damageOptions) {
|
||||
const numAttackers = data.damageOptions.groupAttack?.numAttackers;
|
||||
if (typeof numAttackers !== 'number' || numAttackers % 1 !== 0) {
|
||||
data.damageOptions.groupAttack.numAttackers = null;
|
||||
}
|
||||
|
||||
foundry.utils.mergeObject(this.config.damageOptions, data.damageOptions);
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
static updateGroupAttack() {
|
||||
const targets = Array.from(game.user.targets);
|
||||
if (targets.length === 0)
|
||||
return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noTokenTargeted'));
|
||||
|
||||
const actorId = this.roll.data.parent.id;
|
||||
const range = this.config.damageOptions.groupAttack.range;
|
||||
const groupAttackTokens = game.system.api.fields.ActionFields.DamageField.getGroupAttackTokens(actorId, range);
|
||||
|
||||
this.config.damageOptions.groupAttack.numAttackers = groupAttackTokens.length;
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
...member.toObject(),
|
||||
uuid: member.uuid,
|
||||
id: member.id,
|
||||
selected: false
|
||||
selected: false,
|
||||
owned: member.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||
}));
|
||||
this.intiator = null;
|
||||
|
||||
this.initiator = null;
|
||||
this.openForAllPlayers = true;
|
||||
|
||||
this.tabGroups.application = Object.keys(party.system.tagTeam.members).length
|
||||
|
|
@ -80,6 +82,18 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
for (const element of htmlElement.querySelectorAll('.roll-type-select'))
|
||||
element.addEventListener('change', this.updateRollType.bind(this));
|
||||
|
||||
htmlElement
|
||||
.querySelector('.initiator-member-field')
|
||||
?.addEventListener('input', this.updateInitiatorMemberField.bind(this));
|
||||
|
||||
htmlElement
|
||||
.querySelector('.initiator-cost-field')
|
||||
?.addEventListener('input', this.updateInitiatorCostField.bind(this));
|
||||
|
||||
htmlElement
|
||||
.querySelector('.openforall-field')
|
||||
?.addEventListener('change', this.updateOpenForAllField.bind(this));
|
||||
}
|
||||
|
||||
_configureRenderParts(options) {
|
||||
|
|
@ -135,9 +149,12 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
const selectedMembers = partContext.memberSelection.filter(x => x.selected);
|
||||
|
||||
partContext.allSelected = selectedMembers.length === 2;
|
||||
partContext.canStartTagTeam = partContext.allSelected && this.initiator;
|
||||
partContext.canStartTagTeam =
|
||||
partContext.allSelected && this.initiator?.memberId && typeof this.initiator?.cost === 'number';
|
||||
partContext.initiator = this.initiator;
|
||||
partContext.initiatorOptions = selectedMembers.map(x => ({ value: x.id, label: x.name }));
|
||||
partContext.initiatorOptions = selectedMembers
|
||||
.filter(actor => actor.owned)
|
||||
.map(x => ({ value: x.id, label: x.name }));
|
||||
partContext.initiatorDisabled = !selectedMembers.length;
|
||||
partContext.openForAllPlayers = this.openForAllPlayers;
|
||||
|
||||
|
|
@ -230,14 +247,15 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
|
||||
static async updateData(event, _, formData) {
|
||||
const { initiator, openForAllPlayers, ...partyData } = foundry.utils.expandObject(formData.object);
|
||||
this.initiator = initiator;
|
||||
this.openForAllPlayers = openForAllPlayers !== undefined ? openForAllPlayers : this.openForAllPlayers;
|
||||
const partyData = foundry.utils.expandObject(formData.object);
|
||||
|
||||
this.updatePartyData(partyData, this.getUpdatingParts(event.target));
|
||||
}
|
||||
|
||||
async updatePartyData(update, updatingParts, options = { render: true }) {
|
||||
if (!game.users.activeGM)
|
||||
return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.gmRequired'));
|
||||
|
||||
const gmUpdate = async update => {
|
||||
await this.party.update(update);
|
||||
this.render({ parts: updatingParts });
|
||||
|
|
@ -348,8 +366,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 !== undefined ? member.rollData.options.damage : true;
|
||||
const damageFinished = member.rollData?.options?.hasDamage ? Boolean(member.rollData.options.damage) : true;
|
||||
|
||||
rollsAreFinished = rollsAreFinished && rollFinished && damageFinished;
|
||||
rollIsSelected = rollIsSelected || member.selected;
|
||||
|
|
@ -374,6 +391,23 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
);
|
||||
}
|
||||
|
||||
updateInitiatorMemberField(event) {
|
||||
if (!this.initiator) this.initiator = {};
|
||||
this.initiator.memberId = event.target.value;
|
||||
this.render();
|
||||
}
|
||||
|
||||
updateInitiatorCostField(event) {
|
||||
if (!this.initiator) this.initiator = {};
|
||||
this.initiator.cost = event.target.value ? Number.parseInt(event.target.value) : null;
|
||||
this.render();
|
||||
}
|
||||
|
||||
updateOpenForAllField(event) {
|
||||
this.openForAllPlayers = event.target.checked;
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async #removeRoll(_, button) {
|
||||
this.updatePartyData(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ export default class DHActionConfig extends DHActionBaseConfig {
|
|||
|
||||
static async addEffect(_event) {
|
||||
if (!this.action.effects) return;
|
||||
const effectData = this._addEffectData.bind(this)();
|
||||
const data = this.action.toObject();
|
||||
|
||||
const created = await this.action.item.createEmbeddedDocuments('ActiveEffect', [
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default class DhMeasuredTemplate extends foundry.canvas.placeables.Measur
|
|||
|
||||
static getRangeLabels(distanceValue, settings) {
|
||||
let result = { distance: distanceValue, units: '' };
|
||||
if (!settings.enabled) return result;
|
||||
if (!settings.enabled || !canvas.scene) return result;
|
||||
|
||||
const sceneRangeMeasurement = canvas.scene.flags.daggerheart?.rangeMeasurement;
|
||||
const { disable, custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,14 @@ export const range = {
|
|||
}
|
||||
};
|
||||
|
||||
export const groupAttackRange = {
|
||||
melee: range.melee,
|
||||
veryClose: range.veryClose,
|
||||
close: range.close,
|
||||
far: range.far,
|
||||
veryFar: range.veryFar
|
||||
};
|
||||
|
||||
/* circle|cone|rect|ray used to be CONST.MEASURED_TEMPLATE_TYPES. Hardcoded for now */
|
||||
export const templateTypes = {
|
||||
CIRCLE: 'circle',
|
||||
|
|
@ -484,7 +492,7 @@ export const defaultRestOptions = {
|
|||
value: {
|
||||
custom: {
|
||||
enabled: true,
|
||||
formula: '@system.armorScore'
|
||||
formula: '@system.armorScore.max'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -708,14 +716,14 @@ const getDiceSoNiceSFX = sfxOptions => {
|
|||
if (sfxOptions.critical && criticalAnimationData.class) {
|
||||
return {
|
||||
specialEffect: criticalAnimationData.class,
|
||||
options: {}
|
||||
options: { ...criticalAnimationData.options }
|
||||
};
|
||||
}
|
||||
|
||||
if (sfxOptions.higher && sfxOptions.data.higher) {
|
||||
return {
|
||||
specialEffect: sfxOptions.data.higher.class,
|
||||
options: {}
|
||||
options: { ...sfxOptions.data.higher.options }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -280,6 +280,26 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
}
|
||||
};
|
||||
|
||||
if (this.damage) {
|
||||
config.isDirect = this.damage.direct;
|
||||
|
||||
const groupAttackTokens = this.damage.groupAttack
|
||||
? game.system.api.fields.ActionFields.DamageField.getGroupAttackTokens(
|
||||
this.actor.id,
|
||||
this.damage.groupAttack
|
||||
)
|
||||
: null;
|
||||
|
||||
config.damageOptions = {
|
||||
groupAttack: this.damage.groupAttack
|
||||
? {
|
||||
numAttackers: Math.max(groupAttackTokens.length, 1),
|
||||
range: this.damage.groupAttack
|
||||
}
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
DHBaseAction.applyKeybindings(config);
|
||||
return config;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ export default class ArmorChange extends foundry.abstract.DataModel {
|
|||
label: 'Armor',
|
||||
defaultPriority: 20,
|
||||
handler: (actor, change, _options, _field, replacementData) => {
|
||||
const parsedMax = itemAbleRollParse(change.value.max, actor, change.effect.parent);
|
||||
const baseParsedMax = itemAbleRollParse(change.value.max, actor, change.effect.parent);
|
||||
const parsedMax = new Roll(baseParsedMax).evaluateSync().total;
|
||||
game.system.api.documents.DhActiveEffect.applyChange(
|
||||
actor,
|
||||
{
|
||||
|
|
@ -110,6 +111,8 @@ export default class ArmorChange extends foundry.abstract.DataModel {
|
|||
};
|
||||
|
||||
get isSuppressed() {
|
||||
if (!this.parent.parent?.actor) return false;
|
||||
|
||||
switch (this.value.interaction) {
|
||||
case CONFIG.DH.GENERAL.activeEffectArmorInteraction.active.id:
|
||||
return !this.parent.parent?.actor.system.armor;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
action: new fields.StringField()
|
||||
}),
|
||||
damage: new fields.ObjectField(),
|
||||
damageOptions: new fields.ObjectField(),
|
||||
costs: new fields.ArrayField(new fields.ObjectField()),
|
||||
successConsumed: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,12 @@ export default class DamageField extends fields.SchemaField {
|
|||
initial: false,
|
||||
label: 'DAGGERHEART.ACTIONS.Settings.includeBase.label'
|
||||
}),
|
||||
direct: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.CONFIG.DamageType.direct.name' })
|
||||
direct: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.CONFIG.DamageType.direct.name' }),
|
||||
groupAttack: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.groupAttackRange,
|
||||
blank: true,
|
||||
label: 'DAGGERHEART.ACTIONS.Settings.groupAttack.label'
|
||||
})
|
||||
};
|
||||
super(damageFields, options, context);
|
||||
}
|
||||
|
|
@ -224,6 +229,22 @@ export default class DamageField extends fields.SchemaField {
|
|||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.players)
|
||||
);
|
||||
}
|
||||
|
||||
static getGroupAttackTokens(actorId, range) {
|
||||
if (!canvas.scene) return [];
|
||||
|
||||
const targets = Array.from(game.user.targets);
|
||||
const rangeSettings = canvas.scene?.rangeSettings;
|
||||
if (!rangeSettings) return [];
|
||||
|
||||
const maxDistance = rangeSettings[range];
|
||||
return canvas.scene.tokens.filter(x => {
|
||||
if (x.actor?.id !== actorId) return false;
|
||||
if (targets.every(target => x.object.distanceTo(target) > maxDistance)) return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class DHActionDiceData extends foundry.abstract.DataModel {
|
||||
|
|
@ -232,7 +253,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
|
|||
return {
|
||||
multiplier: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.multiplierTypes,
|
||||
initial: 'prof',
|
||||
initial: 'flat',
|
||||
label: 'DAGGERHEART.ACTIONS.Config.damage.multiplier',
|
||||
nullable: false,
|
||||
required: true
|
||||
|
|
@ -244,7 +265,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
|
|||
}),
|
||||
dice: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceTypes,
|
||||
initial: 'd6',
|
||||
initial: CONFIG.DH.GENERAL.diceTypes.d6,
|
||||
label: 'DAGGERHEART.GENERAL.Dice.single',
|
||||
nullable: false,
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -89,13 +89,13 @@ class ResourcesField extends fields.TypedObjectField {
|
|||
*/
|
||||
_getField(path) {
|
||||
if (path.length === 0) return this;
|
||||
const first = path.shift();
|
||||
if (first === this.element.name) return this.element_getField(path);
|
||||
const name = path.pop();
|
||||
if (name === this.element.name) return this.element_getField(path);
|
||||
|
||||
const resources = CONFIG.DH.RESOURCE[this.actorType].all;
|
||||
if (first in resources) {
|
||||
if (name in resources) {
|
||||
const field = this.element._getField(path);
|
||||
field.label = resources[first].label;
|
||||
field.label = resources[name].label;
|
||||
return field;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
initial: null,
|
||||
blank: true,
|
||||
choices: CONFIG.DH.GENERAL.diceSoNiceSFXClasses
|
||||
}),
|
||||
options: new foundry.data.fields.SchemaField({
|
||||
muteSound: new foundry.data.fields.BooleanField()
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ export default class DamageRoll extends DHRoll {
|
|||
constructFormula(config) {
|
||||
this.options.isCritical = config.isCritical;
|
||||
for (const [index, part] of this.options.roll.entries()) {
|
||||
const isHitpointPart = part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id;
|
||||
part.roll = new Roll(Roll.replaceFormulaData(part.formula, config.data));
|
||||
part.roll.terms = Roll.parse(part.roll.formula, config.data);
|
||||
if (part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
||||
|
|
@ -169,7 +170,16 @@ export default class DamageRoll extends DHRoll {
|
|||
);
|
||||
}
|
||||
|
||||
if (config.isCritical && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
||||
if (config.damageOptions.groupAttack?.numAttackers > 1 && isHitpointPart) {
|
||||
const damageTypes = [foundry.dice.terms.Die, foundry.dice.terms.NumericTerm];
|
||||
for (const term of part.roll.terms) {
|
||||
if (damageTypes.some(type => term instanceof type)) {
|
||||
term.number *= config.damageOptions.groupAttack.numAttackers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.isCritical && isHitpointPart) {
|
||||
const total = part.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0);
|
||||
if (total > 0) {
|
||||
part.roll.terms.push(...this.formatModifier(total));
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ export default class DHRoll extends Roll {
|
|||
return (this._formula = this.constructor.getFormula(this.terms));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Calculate total modifiers of any rolls, including non-dh rolls.
|
||||
* This exists because damage rolls still may receive base roll classes
|
||||
*/
|
||||
|
|
@ -256,7 +256,7 @@ export default class DHRoll extends Roll {
|
|||
if (!roll.terms[i].isDeterministic) continue;
|
||||
const termTotal = roll.terms[i].total;
|
||||
if (typeof termTotal === 'number') {
|
||||
const multiplier = roll.terms[i - 1]?.operator === " - " ? -1 : 1;
|
||||
const multiplier = roll.terms[i - 1]?.operator === ' - ' ? -1 : 1;
|
||||
modifierTotal += multiplier * termTotal;
|
||||
}
|
||||
}
|
||||
|
|
@ -272,7 +272,7 @@ export default class DHRoll extends Roll {
|
|||
const changeKeys = this.getActionChangeKeys();
|
||||
return (
|
||||
this.options.effects?.reduce((acc, effect) => {
|
||||
if (effect.system.changes.some(x => changeKeys.some(key => x.key.includes(key)))) {
|
||||
if (effect.system.changes.some(x => changeKeys.some(key => x.key?.includes(key)))) {
|
||||
acc[effect.id] = {
|
||||
id: effect.id,
|
||||
name: effect.name,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
import DualityDie from './dualityDie.mjs';
|
||||
import HopeDie from './hopeDie.mjs';
|
||||
import FearDie from './fearDie.mjs';
|
||||
import AdvantageDie from './advantageDie.mjs';
|
||||
import DisadvantageDie from './disadvantageDie.mjs';
|
||||
|
||||
export const diceTypes = {
|
||||
DualityDie,
|
||||
HopeDie,
|
||||
FearDie,
|
||||
AdvantageDie,
|
||||
DisadvantageDie
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,9 +43,10 @@ export default class DualityDie extends foundry.dice.terms.Die {
|
|||
options: { appearance: {} }
|
||||
};
|
||||
|
||||
const preset = await getDiceSoNicePreset(diceSoNice[key], faces);
|
||||
diceSoNiceRoll.dice[0].options.appearance = preset.appearance;
|
||||
diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile;
|
||||
const diceAppearance = await this.getDiceSoNiceAppearance(options.liveRoll.roll);
|
||||
diceSoNiceRoll.dice[0].options.appearance = diceAppearance.appearance;
|
||||
diceSoNiceRoll.dice[0].options.modelFile = diceAppearance.modelFile;
|
||||
diceSoNiceRoll.dice[0].results = diceSoNiceRoll.dice[0].results.filter(x => x.active);
|
||||
|
||||
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
|
||||
} else {
|
||||
|
|
@ -59,4 +60,11 @@ export default class DualityDie extends foundry.dice.terms.Die {
|
|||
this.#updateResources(oldDuality, newDuality, options.liveRoll.actor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by extending classes HopeDie and FearDie
|
||||
*/
|
||||
async getDiceSoNiceAppearance() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
module/dice/die/fearDie.mjs
Normal file
9
module/dice/die/fearDie.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { getDiceSoNicePresets } from '../../config/generalConfig.mjs';
|
||||
import DualityDie from './dualityDie.mjs';
|
||||
|
||||
export default class FearDie extends DualityDie {
|
||||
async getDiceSoNiceAppearance(roll) {
|
||||
const { fear } = await getDiceSoNicePresets(roll, this.denomination, this.denomination);
|
||||
return fear;
|
||||
}
|
||||
}
|
||||
9
module/dice/die/hopeDie.mjs
Normal file
9
module/dice/die/hopeDie.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { getDiceSoNicePresets } from '../../config/generalConfig.mjs';
|
||||
import DualityDie from './dualityDie.mjs';
|
||||
|
||||
export default class HopeDie extends DualityDie {
|
||||
async getDiceSoNiceAppearance(roll) {
|
||||
const { hope } = await getDiceSoNicePresets(roll, this.denomination, this.denomination);
|
||||
return hope;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
get dHope() {
|
||||
if (!(this.dice[0] instanceof game.system.api.dice.diceTypes.DualityDie)) this.createBaseDice();
|
||||
if (!(this.dice[0] instanceof game.system.api.dice.diceTypes.HopeDie)) this.createBaseDice();
|
||||
return this.dice[0];
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
get dFear() {
|
||||
if (!(this.dice[1] instanceof game.system.api.dice.diceTypes.DualityDie)) this.createBaseDice();
|
||||
if (!(this.dice[1] instanceof game.system.api.dice.diceTypes.FearDie)) this.createBaseDice();
|
||||
return this.dice[1];
|
||||
}
|
||||
|
||||
|
|
@ -68,8 +68,8 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
get extraDice() {
|
||||
const { DualityDie, AdvantageDie, DisadvantageDie } = game.system.api.dice.diceTypes;
|
||||
return this.dice.filter(x => ![DualityDie, AdvantageDie, DisadvantageDie].some(die => x instanceof die));
|
||||
const { HopeDie, FearDie, AdvantageDie, DisadvantageDie } = game.system.api.dice.diceTypes;
|
||||
return this.dice.filter(x => ![HopeDie, FearDie, AdvantageDie, DisadvantageDie].some(die => x instanceof die));
|
||||
}
|
||||
|
||||
setRallyChoices() {
|
||||
|
|
@ -125,8 +125,8 @@ export default class DualityRoll extends D20Roll {
|
|||
|
||||
/** @inheritDoc */
|
||||
static fromData(data) {
|
||||
data.terms[0].class = 'DualityDie';
|
||||
data.terms[2].class = 'DualityDie';
|
||||
data.terms[0].class = 'HopeDie';
|
||||
data.terms[2].class = 'FearDie';
|
||||
if (data.options.roll.advantage?.type && data.terms[4]?.faces) {
|
||||
data.terms[4].class = data.options.roll.advantage.type === 1 ? 'AdvantageDie' : 'DisadvantageDie';
|
||||
}
|
||||
|
|
@ -135,18 +135,18 @@ export default class DualityRoll extends D20Roll {
|
|||
|
||||
createBaseDice() {
|
||||
if (
|
||||
this.dice[0] instanceof game.system.api.dice.diceTypes.DualityDie &&
|
||||
this.dice[1] instanceof game.system.api.dice.diceTypes.DualityDie
|
||||
this.dice[0] instanceof game.system.api.dice.diceTypes.HopeDie &&
|
||||
this.dice[1] instanceof game.system.api.dice.diceTypes.FearDie
|
||||
) {
|
||||
this.terms = [this.terms[0], this.terms[1], this.terms[2]];
|
||||
return;
|
||||
}
|
||||
|
||||
this.terms[0] = new game.system.api.dice.diceTypes.DualityDie({
|
||||
this.terms[0] = new game.system.api.dice.diceTypes.HopeDie({
|
||||
faces: this.data.rules.dualityRoll?.defaultHopeDice ?? 12
|
||||
});
|
||||
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
|
||||
this.terms[2] = new game.system.api.dice.diceTypes.DualityDie({
|
||||
this.terms[2] = new game.system.api.dice.diceTypes.FearDie({
|
||||
faces: this.data.rules.dualityRoll?.defaultFearDice ?? 12
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,16 @@
|
|||
import DHToken from './token.mjs';
|
||||
|
||||
export default class DhScene extends Scene {
|
||||
get rangeSettings() {
|
||||
const { custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting;
|
||||
const sceneMeasurements = this.flags.daggerheart?.rangeMeasurement;
|
||||
const globalMeasurements = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.variantRules
|
||||
).rangeMeasurement;
|
||||
return sceneMeasurements?.setting === custom.id ? sceneMeasurements : globalMeasurements;
|
||||
}
|
||||
|
||||
/** A map of `TokenDocument` IDs embedded in this scene long with new dimensions from actor size-category changes */
|
||||
#sizeSyncBatch = new Map();
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export default class DhTokenManager {
|
|||
: this.#actor;
|
||||
const tokenData = await actor.getTokenDocument();
|
||||
const result = await canvas.scene.createEmbeddedDocuments('Token', [
|
||||
{ ...tokenData, x: this.#activePreview.document.x, y: this.#activePreview.document.y }
|
||||
{ ...tokenData.toObject(), x: this.#activePreview.document.x, y: this.#activePreview.document.y }
|
||||
]);
|
||||
|
||||
this.#activePreview = undefined;
|
||||
|
|
|
|||
|
|
@ -63,14 +63,12 @@ export const renderMeasuredTemplate = async event => {
|
|||
const usedAngle =
|
||||
type === CONE ? (angle ?? CONFIG.MeasuredTemplate.defaults.angle) : type === INFRONT ? '180' : undefined;
|
||||
|
||||
let baseDistance = range;
|
||||
if (Number.isNaN(Number(range))) {
|
||||
baseDistance = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement[
|
||||
range
|
||||
];
|
||||
}
|
||||
let baseDistance = getTemplateDistance(range);
|
||||
|
||||
const dimensionConstant = game.scenes.active.grid.size / game.scenes.active.grid.distance;
|
||||
const { grid, distance } = CONFIG.Scene.documentClass.schema.fields.grid.fields;
|
||||
const sceneGridSize = canvas.scene?.grid.size ?? grid.size.initial;
|
||||
const sceneGridDistance = canvas.scene?.grid.distance ?? distance.getInitialValue();
|
||||
const dimensionConstant = sceneGridSize / sceneGridDistance;
|
||||
|
||||
baseDistance *= dimensionConstant;
|
||||
|
||||
|
|
@ -115,3 +113,11 @@ export const renderMeasuredTemplate = async event => {
|
|||
{ create: true }
|
||||
);
|
||||
};
|
||||
|
||||
const getTemplateDistance = range => {
|
||||
const rangeNumber = Number(range);
|
||||
if (!Number.isNaN(rangeNumber)) return rangeNumber;
|
||||
|
||||
const settings = canvas.scene?.rangeSettings;
|
||||
return settings ? settings[range] : 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { defaultRestOptions } from '../config/generalConfig.mjs';
|
||||
import { RefreshType, socketEvent } from './socket.mjs';
|
||||
|
||||
export async function runMigrations() {
|
||||
|
|
@ -341,6 +342,18 @@ export async function runMigrations() {
|
|||
|
||||
lastMigrationVersion = '2.0.0';
|
||||
}
|
||||
|
||||
if (foundry.utils.isNewerVersion('2.0.4', lastMigrationVersion)) {
|
||||
const downtimeMoves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew);
|
||||
if (downtimeMoves.restMoves.longRest.moves.repairArmor) {
|
||||
await downtimeMoves.updateSource({
|
||||
'restMoves.longRest.moves.repairArmor': defaultRestOptions.longRest().repairArmor
|
||||
});
|
||||
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, downtimeMoves.toObject());
|
||||
}
|
||||
|
||||
lastMigrationVersion = '2.0.4';
|
||||
}
|
||||
//#endregion
|
||||
|
||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue