mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-22 23:43:37 +02:00
Implemented group attack logic
This commit is contained in:
parent
02cca277da
commit
54fab46b66
12 changed files with 154 additions and 11 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 groupAttackNr = data.damageOptions.groupAttack?.nr;
|
||||
if (typeof groupAttackNr !== 'number' || groupAttackNr % 1 !== 0) {
|
||||
data.damageOptions.groupAttack.nr = 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.nr = groupAttackTokens.length;
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
hasSave: this.hasSave,
|
||||
onSave: this.save?.damageMod,
|
||||
isDirect: !!this.damage?.direct,
|
||||
damageOptions: this.damage?.groupAttack ? {} : null,
|
||||
selectedMessageMode: game.settings.get('core', 'messageMode'),
|
||||
data: this.getRollData(),
|
||||
evaluate: this.hasRoll,
|
||||
|
|
@ -280,6 +281,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
|
||||
? {
|
||||
nr: Math.max(groupAttackTokens.length, 1),
|
||||
range: this.damage.groupAttack
|
||||
}
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
DHBaseAction.applyKeybindings(config);
|
||||
return config;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,27 @@ 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 { custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting;
|
||||
const sceneMeasurements = canvas.scene?.flags.daggerheart?.rangeMeasurement;
|
||||
const globalMeasurements = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.variantRules
|
||||
).rangeMeasurement;
|
||||
const rangeSettings = sceneMeasurements?.setting === custom.id ? sceneMeasurements : globalMeasurements;
|
||||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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?.nr > 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.nr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue