mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-19 00:19:03 +01:00
[Feature] Death moves and Fate rolls (#1463)
* Update the death move descriptions * Renamed to DhDeathMove * Partial Fate Roll creation and Fate Roll Enricher (/fr) * Hide stuff not required for fate roll * Hide formula display; code removal; start to add Fear die as a choice for Fate roll * Fix chat message display; start moving towards supporting Hope and Fear for Fate roll * /fr now supports type=X, where X is Hope or Fear, if not supplied, defaults to Hope * Fixed DSN rolling; removed console messages; chat message clean up * Add localisation entry * Trying to sort out the button for the fate roll * Style the fate message based on Hope/Fear colors. * Partial improvement on the fate template buttons - chat display is correct, but the roll dialog is wrong * Fixed enricher button; localization fixes; debug cleanup * Error checking for the fate type parsing in all potential problem locations * Added localization for the fate type parsing error * Start on Avoid Death death move * debug stuff * More death moves setup/testing * Avoid fate scars update in place, with scars migrating to an integer value. * Remove some debug code; add Blaze Of Glory shell * Start on Guaranteed Critical for Blaze of Glory * Partial implementation of Blaze of Glory * Dice/critical checks/tests * Moved detection of guaranteed critical to before the roll dialog is created, so it can be skipped; removed debug code * Remove debug * Update Blaze of Glory effect description * Risk It All - critical roll - clear all stress and HP * Auto remove all marked stress and HP for Risk It All, if Hope value rolled covers it. * Display the Death Move description in chat expanded if the appropriate config setting is on * Made the Blaze of Glory ActiveEffect image use configured version * Update the current Hope value if the scar value change affects it * Scars management in the Character details editor * Separate less file for the Death Moves instead of reusing Downtime * Added result messages to the Death Move chat output and removed debug statements * Some localization, style and smaller changes * Fixed RiskItAll resource handling method * Risk It All success chat message start * [Add] Hope/Scar Interplay (#1531) * Migrated character.maxHope to homebrew settings * Added a visual for scars * . * . * Pass the hope value in the button data; skeleton risk it all dialog to fill out. * Start on risk it dialog * More dialog stuff * Remove non-existent field * Dialog templating and logic * . * Ensure effect is Applied to Actor (#1547) Co-authored-by: Chris Ryan <chrisr@blackhole> * [Fix] 1548 - Standalone Item Add Actions (#1549) * Fixed so that items not on an actor don't error out on creating actions * Fixed deletion of items error * Raised version * Fix the sliders to do the correct maximums * Pass the actor id through the button; fix /dr and /fr flavor text * Remove debug message --------- Co-authored-by: Chris Ryan <chrisr@blackhole> Co-authored-by: WBHarry <williambjrklund@gmail.com> Co-authored-by: WBHarry <89362246+WBHarry@users.noreply.github.com>
This commit is contained in:
parent
3103a40c26
commit
9d75157e17
38 changed files with 1166 additions and 258 deletions
|
|
@ -3,3 +3,4 @@ export { default as D20Roll } from './d20Roll.mjs';
|
|||
export { default as DamageRoll } from './damageRoll.mjs';
|
||||
export { default as DHRoll } from './dhRoll.mjs';
|
||||
export { default as DualityRoll } from './dualityRoll.mjs';
|
||||
export { default as FateRoll } from './fateRoll.mjs';
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export default class DualityRoll extends D20Roll {
|
|||
constructor(formula, data = {}, options = {}) {
|
||||
super(formula, data, options);
|
||||
this.rallyChoices = this.setRallyChoices();
|
||||
this.guaranteedCritical = options.guaranteedCritical;
|
||||
}
|
||||
|
||||
static messageType = 'dualityRoll';
|
||||
|
|
@ -25,29 +26,23 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
get dHope() {
|
||||
// if ( !(this.terms[0] instanceof foundry.dice.terms.Die) ) return;
|
||||
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
return this.dice[0];
|
||||
// return this.#hopeDice;
|
||||
}
|
||||
|
||||
set dHope(faces) {
|
||||
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
this.terms[0].faces = this.getFaces(faces);
|
||||
// this.#hopeDice = `d${face}`;
|
||||
this.dice[0].faces = this.getFaces(faces);
|
||||
}
|
||||
|
||||
get dFear() {
|
||||
// if ( !(this.terms[1] instanceof foundry.dice.terms.Die) ) return;
|
||||
if (!(this.dice[1] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
return this.dice[1];
|
||||
// return this.#fearDice;
|
||||
}
|
||||
|
||||
set dFear(faces) {
|
||||
if (!(this.dice[1] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
this.dice[1].faces = this.getFaces(faces);
|
||||
// this.#fearDice = `d${face}`;
|
||||
}
|
||||
|
||||
get dAdvantage() {
|
||||
|
|
@ -90,26 +85,29 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
get isCritical() {
|
||||
if (this.guaranteedCritical) return true;
|
||||
if (!this.dHope._evaluated || !this.dFear._evaluated) return;
|
||||
return this.dHope.total === this.dFear.total;
|
||||
}
|
||||
|
||||
get withHope() {
|
||||
if (!this._evaluated) return;
|
||||
if (!this._evaluated || this.guaranteedCritical) return;
|
||||
return this.dHope.total > this.dFear.total;
|
||||
}
|
||||
|
||||
get withFear() {
|
||||
if (!this._evaluated) return;
|
||||
if (!this._evaluated || this.guaranteedCritical) return;
|
||||
return this.dHope.total < this.dFear.total;
|
||||
}
|
||||
|
||||
get totalLabel() {
|
||||
const label = this.withHope
|
||||
? 'DAGGERHEART.GENERAL.hope'
|
||||
: this.withFear
|
||||
? 'DAGGERHEART.GENERAL.fear'
|
||||
: 'DAGGERHEART.GENERAL.criticalSuccess';
|
||||
const label = this.guaranteedCritical
|
||||
? 'DAGGERHEART.GENERAL.guaranteedCriticalSuccess'
|
||||
: this.isCritical
|
||||
? 'DAGGERHEART.GENERAL.criticalSuccess'
|
||||
: this.withHope
|
||||
? 'DAGGERHEART.GENERAL.hope'
|
||||
: 'DAGGERHEART.GENERAL.fear';
|
||||
|
||||
return game.i18n.localize(label);
|
||||
}
|
||||
|
|
@ -178,6 +176,21 @@ export default class DualityRoll extends D20Roll {
|
|||
return modifiers;
|
||||
}
|
||||
|
||||
static async buildConfigure(config = {}, message = {}) {
|
||||
config.dialog ??= {};
|
||||
config.guaranteedCritical = config.data?.parent?.appliedEffects.reduce((a, c) => {
|
||||
const change = c.changes.find(ch => ch.key === 'system.rules.roll.guaranteedCritical');
|
||||
if (change) a = true;
|
||||
return a;
|
||||
}, false);
|
||||
|
||||
if (config.guaranteedCritical) {
|
||||
config.dialog.configure = false;
|
||||
}
|
||||
|
||||
return super.buildConfigure(config, message);
|
||||
}
|
||||
|
||||
getActionChangeKeys() {
|
||||
const changeKeys = new Set([`system.bonuses.roll.${this.options.actionType}`]);
|
||||
|
||||
|
|
@ -223,7 +236,7 @@ export default class DualityRoll extends D20Roll {
|
|||
|
||||
data.hope = {
|
||||
dice: roll.dHope.denomination,
|
||||
value: roll.dHope.total,
|
||||
value: this.guaranteedCritical ? 0 : roll.dHope.total,
|
||||
rerolled: {
|
||||
any: roll.dHope.results.some(x => x.rerolled),
|
||||
rerolls: roll.dHope.results.filter(x => x.rerolled)
|
||||
|
|
@ -231,7 +244,7 @@ export default class DualityRoll extends D20Roll {
|
|||
};
|
||||
data.fear = {
|
||||
dice: roll.dFear.denomination,
|
||||
value: roll.dFear.total,
|
||||
value: this.guaranteedCritical ? 0 : roll.dFear.total,
|
||||
rerolled: {
|
||||
any: roll.dFear.results.some(x => x.rerolled),
|
||||
rerolls: roll.dFear.results.filter(x => x.rerolled)
|
||||
|
|
@ -243,7 +256,7 @@ export default class DualityRoll extends D20Roll {
|
|||
};
|
||||
data.result = {
|
||||
duality: roll.withHope ? 1 : roll.withFear ? -1 : 0,
|
||||
total: roll.dHope.total + roll.dFear.total,
|
||||
total: this.guaranteedCritical ? 0 : roll.dHope.total + roll.dFear.total,
|
||||
label: roll.totalLabel
|
||||
};
|
||||
|
||||
|
|
|
|||
85
module/dice/fateRoll.mjs
Normal file
85
module/dice/fateRoll.mjs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
|
||||
import D20Roll from './d20Roll.mjs';
|
||||
import { setDiceSoNiceForHopeFateRoll, setDiceSoNiceForFearFateRoll } from '../helpers/utils.mjs';
|
||||
|
||||
export default class FateRoll extends D20Roll {
|
||||
constructor(formula, data = {}, options = {}) {
|
||||
super(formula, data, options);
|
||||
}
|
||||
|
||||
static messageType = 'fateRoll';
|
||||
|
||||
static DefaultDialog = D20RollDialog;
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize(`DAGGERHEART.GENERAL.fateRoll`);
|
||||
}
|
||||
|
||||
get dHope() {
|
||||
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
return this.dice[0];
|
||||
}
|
||||
|
||||
set dHope(faces) {
|
||||
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
this.dice[0].faces = this.getFaces(faces);
|
||||
}
|
||||
|
||||
get dFear() {
|
||||
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
return this.dice[0];
|
||||
}
|
||||
|
||||
set dFear(faces) {
|
||||
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
this.dice[0].faces = this.getFaces(faces);
|
||||
}
|
||||
|
||||
get isCritical() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get fateDie() {
|
||||
return this.data.fateType;
|
||||
}
|
||||
|
||||
static getHooks(hooks) {
|
||||
return [...(hooks ?? []), 'Fate'];
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
static fromData(data) {
|
||||
data.terms[0].class = foundry.dice.terms.Die.name;
|
||||
return super.fromData(data);
|
||||
}
|
||||
|
||||
createBaseDice() {
|
||||
if (this.dice[0] instanceof foundry.dice.terms.Die) {
|
||||
this.terms = [this.terms[0]];
|
||||
return;
|
||||
}
|
||||
this.terms[0] = new foundry.dice.terms.Die({ faces: 12 });
|
||||
}
|
||||
|
||||
static async buildEvaluate(roll, config = {}, message = {}) {
|
||||
await super.buildEvaluate(roll, config, message);
|
||||
|
||||
if (roll.fateDie === 'Hope') {
|
||||
await setDiceSoNiceForHopeFateRoll(roll, config.roll.fate.dice);
|
||||
} else {
|
||||
await setDiceSoNiceForFearFateRoll(roll, config.roll.fate.dice);
|
||||
}
|
||||
}
|
||||
|
||||
static postEvaluate(roll, config = {}) {
|
||||
const data = super.postEvaluate(roll, config);
|
||||
|
||||
data.fate = {
|
||||
dice: roll.fateDie === 'Hope' ? roll.dHope.denomination : roll.dFear.denomination,
|
||||
value: roll.fateDie === 'Hope' ? roll.dHope.total : roll.dFear.total,
|
||||
fateDie: roll.fateDie
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue