mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
parent
3176438293
commit
ad9e0aa558
9 changed files with 153 additions and 40 deletions
|
|
@ -407,7 +407,11 @@
|
|||
"rerollDice": "Reroll Dice"
|
||||
}
|
||||
},
|
||||
|
||||
"CLASS": {
|
||||
"Feature": {
|
||||
"rallyDice": "Bardic Rally Dice"
|
||||
}
|
||||
},
|
||||
"CONFIG": {
|
||||
"ActionType": {
|
||||
"passive": "Passive",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
if (this.roll) {
|
||||
context.roll = this.roll;
|
||||
context.rollType = this.roll?.constructor.name;
|
||||
context.rallyDie = this.roll.rallyChoices;
|
||||
context.experiences = Object.keys(this.config.data.experiences).map(id => ({
|
||||
id,
|
||||
...this.config.data.experiences[id]
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
|
||||
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage'),
|
||||
primaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.primaryWeapon'),
|
||||
secondaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.primaryWeapon')
|
||||
secondaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.secondaryWeapon')
|
||||
}),
|
||||
healing: bonusField('DAGGERHEART.GENERAL.Healing.healingAmount'),
|
||||
range: new fields.SchemaField({
|
||||
|
|
@ -121,7 +121,13 @@ export default class DhCharacter extends BaseDataActor {
|
|||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Range.other'
|
||||
})
|
||||
})
|
||||
}),
|
||||
rally: new fields.ArrayField(
|
||||
new fields.StringField(),
|
||||
{
|
||||
label: 'DAGGERHEART.CLASS.Feature.rallyDice'
|
||||
}
|
||||
)
|
||||
}),
|
||||
companion: new ForeignDocumentUUIDField({ type: 'Actor', nullable: true, initial: null }),
|
||||
rules: new fields.SchemaField({
|
||||
|
|
|
|||
|
|
@ -25,8 +25,11 @@ const stressDamageReductionRule = localizationPath =>
|
|||
|
||||
const bonusField = label =>
|
||||
new fields.SchemaField({
|
||||
bonus: new fields.NumberField({ integer: true, initial: 0, label }),
|
||||
dice: new fields.ArrayField(new fields.StringField())
|
||||
bonus: new fields.NumberField({ integer: true, initial: 0, label: `${game.i18n.localize(label)} Value` }),
|
||||
dice: new fields.ArrayField(
|
||||
new fields.StringField(),
|
||||
{ label: `${game.i18n.localize(label)} Dice` }
|
||||
)
|
||||
});
|
||||
|
||||
export { attributeField, resourceField, stressDamageReductionRule, bonusField };
|
||||
|
|
|
|||
|
|
@ -39,11 +39,13 @@ export default class D20Roll extends DHRoll {
|
|||
}
|
||||
|
||||
get hasAdvantage() {
|
||||
return this.options.roll.advantage === this.constructor.ADV_MODE.ADVANTAGE;
|
||||
const adv = this.options.roll.advantage.type ?? this.options.roll.advantage;
|
||||
return adv === this.constructor.ADV_MODE.ADVANTAGE;
|
||||
}
|
||||
|
||||
get hasDisadvantage() {
|
||||
return this.options.roll.advantage === this.constructor.ADV_MODE.DISADVANTAGE;
|
||||
const adv = this.options.roll.advantage.type ?? this.options.roll.advantage;
|
||||
return adv === this.constructor.ADV_MODE.DISADVANTAGE;
|
||||
}
|
||||
|
||||
static applyKeybindings(config) {
|
||||
|
|
@ -91,7 +93,7 @@ export default class D20Roll extends DHRoll {
|
|||
configureModifiers() {
|
||||
this.applyAdvantage();
|
||||
|
||||
this.baseTerms = foundry.utils.deepClone(this.terms);
|
||||
this.baseTerms = foundry.utils.deepClone(this.dice);
|
||||
|
||||
this.options.roll.modifiers = this.applyBaseBonus();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@ import { setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
|
|||
|
||||
export default class DualityRoll extends D20Roll {
|
||||
_advantageFaces = 6;
|
||||
_advantageNumber = 1;
|
||||
_rallyIndex;
|
||||
|
||||
constructor(formula, data = {}, options = {}) {
|
||||
super(formula, data, options);
|
||||
this.rallyChoices = this.setRallyChoices();
|
||||
}
|
||||
|
||||
static messageType = 'dualityRoll';
|
||||
|
|
@ -51,6 +54,35 @@ export default class DualityRoll extends D20Roll {
|
|||
this._advantageFaces = this.getFaces(faces);
|
||||
}
|
||||
|
||||
get advantageNumber() {
|
||||
return this._advantageNumber;
|
||||
}
|
||||
|
||||
set advantageNumber(value) {
|
||||
this._advantageNumber = Number(value);
|
||||
}
|
||||
|
||||
setRallyChoices() {
|
||||
return this.data?.parent?.effects.reduce((a,c) => {
|
||||
const change = c.changes.find(ch => ch.key === 'system.bonuses.rally');
|
||||
if(change) a.push({ value: c.id, label: change.value });
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
|
||||
get dRally() {
|
||||
if(!this.rallyFaces) return null;
|
||||
if(this.hasDisadvantage || this.hasAdvantage)
|
||||
return this.dice[3];
|
||||
else
|
||||
return this.dice[2];
|
||||
}
|
||||
|
||||
get rallyFaces() {
|
||||
const rallyChoice = this.rallyChoices?.find(r => r.value === this._rallyIndex)?.label;
|
||||
return rallyChoice ? this.getFaces(rallyChoice) : null;
|
||||
}
|
||||
|
||||
get isCritical() {
|
||||
if (!this.dHope._evaluated || !this.dFear._evaluated) return;
|
||||
return this.dHope.total === this.dFear.total;
|
||||
|
|
@ -66,10 +98,6 @@ export default class DualityRoll extends D20Roll {
|
|||
return this.dHope.total < this.dFear.total;
|
||||
}
|
||||
|
||||
get hasBarRally() {
|
||||
return null;
|
||||
}
|
||||
|
||||
get totalLabel() {
|
||||
const label = this.withHope
|
||||
? 'DAGGERHEART.GENERAL.hope'
|
||||
|
|
@ -98,24 +126,20 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
applyAdvantage() {
|
||||
if (this.hasAdvantage || this.hasDisadvantage) {
|
||||
const dieFaces = this.advantageFaces,
|
||||
bardRallyFaces = this.hasBarRally,
|
||||
advDie = new foundry.dice.terms.Die({ faces: dieFaces });
|
||||
if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces)
|
||||
this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }));
|
||||
if (bardRallyFaces) {
|
||||
const rallyDie = new foundry.dice.terms.Die({ faces: bardRallyFaces });
|
||||
if (this.hasAdvantage) {
|
||||
advDie = new foundry.dice.terms.Die({ faces: dieFaces, number: this.advantageNumber });
|
||||
if(this.advantageNumber > 1) advDie.modifiers = ['kh'];
|
||||
this.terms.push(
|
||||
new foundry.dice.terms.PoolTerm({
|
||||
terms: [advDie.formula, rallyDie.formula],
|
||||
modifiers: ['kh']
|
||||
})
|
||||
new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }),
|
||||
advDie
|
||||
);
|
||||
} else if (this.hasDisadvantage) {
|
||||
this.terms.push(advDie, new foundry.dice.terms.OperatorTerm({ operator: '+' }), rallyDie);
|
||||
}
|
||||
} else if (this.hasAdvantage || this.hasDisadvantage) this.terms.push(advDie);
|
||||
if(this.rallyFaces)
|
||||
this.terms.push(
|
||||
new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }),
|
||||
new foundry.dice.terms.Die({ faces: this.rallyFaces })
|
||||
);
|
||||
}
|
||||
|
||||
applyBaseBonus() {
|
||||
|
|
@ -138,6 +162,7 @@ export default class DualityRoll extends D20Roll {
|
|||
|
||||
static postEvaluate(roll, config = {}) {
|
||||
super.postEvaluate(roll, config);
|
||||
|
||||
config.roll.hope = {
|
||||
dice: roll.dHope.denomination,
|
||||
value: roll.dHope.total
|
||||
|
|
@ -146,12 +171,19 @@ export default class DualityRoll extends D20Roll {
|
|||
dice: roll.dFear.denomination,
|
||||
value: roll.dFear.total
|
||||
};
|
||||
config.roll.rally = {
|
||||
dice: roll.dRally?.denomination,
|
||||
value: roll.dRally?.total
|
||||
};
|
||||
config.roll.result = {
|
||||
duality: roll.withHope ? 1 : roll.withFear ? -1 : 0,
|
||||
total: roll.dHope.total + roll.dFear.total,
|
||||
label: roll.totalLabel
|
||||
};
|
||||
|
||||
if(roll._rallyIndex && roll.data?.parent)
|
||||
roll.data.parent.deleteEmbeddedDocuments('ActiveEffect', [roll._rallyIndex]);
|
||||
|
||||
setDiceSoNiceForDualityRoll(roll, config.roll.advantage.type);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,26 @@ export default class DHToken extends TokenDocument {
|
|||
|
||||
return bars.concat(values);
|
||||
}
|
||||
|
||||
static _getTrackedAttributesFromSchema(schema, _path=[]) {
|
||||
const attributes = {bar: [], value: []};
|
||||
for ( const [name, field] of Object.entries(schema.fields) ) {
|
||||
const p = _path.concat([name]);
|
||||
if ( field instanceof foundry.data.fields.NumberField ) attributes.value.push(p);
|
||||
if ( field instanceof foundry.data.fields.ArrayField ) attributes.value.push(p);
|
||||
const isSchema = field instanceof foundry.data.fields.SchemaField;
|
||||
const isModel = field instanceof foundry.data.fields.EmbeddedDataField;
|
||||
if ( isSchema || isModel ) {
|
||||
const schema = isModel ? field.model.schema : field;
|
||||
const isBar = schema.has && schema.has("value") && schema.has("max");
|
||||
if ( isBar ) attributes.bar.push(p);
|
||||
else {
|
||||
const inner = this.getTrackedAttributes(schema, p);
|
||||
attributes.bar.push(...inner.bar);
|
||||
attributes.value.push(...inner.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
{{/if}}
|
||||
{{/each}}
|
||||
</fieldset>
|
||||
<fieldset class="modifier-container one-column">
|
||||
<fieldset class="modifier-container {{#if (eq @root.rollType 'DualityRoll')}}two-columns{{else}}one-column{{/if}}">
|
||||
<legend>Modifiers</legend>
|
||||
<div class="nest-inputs">
|
||||
<button class="advantage-chip flex1 {{#if (eq advantage 1)}}selected{{/if}}" data-action="updateIsAdvantage" data-advantage="1">
|
||||
|
|
@ -107,13 +107,27 @@
|
|||
{{/if}}
|
||||
<span class="label">{{localize "DAGGERHEART.GENERAL.Disadvantage.full"}}</span>
|
||||
</button>
|
||||
</div>
|
||||
{{#unless (eq @root.rollType 'D20Roll')}}
|
||||
<select name="roll.dice.advantageFaces">
|
||||
<div class="nest-inputs">
|
||||
<select name="roll.dice.advantageNumber"{{#unless advantage}} disabled{{/unless}}>
|
||||
{{#times 10}}
|
||||
<option value="{{add this 1}}" {{#if (eq @root.roll.advantageNumber (add this 1))}} selected{{/if}}>{{add this 1}}</option>
|
||||
{{/times}}
|
||||
</select>
|
||||
<select name="roll.dice.advantageFaces"{{#unless advantage}} disabled{{/unless}}>
|
||||
{{selectOptions diceOptions selected=@root.roll.dAdvantage.denomination}}
|
||||
</select>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<input type="text" value="{{extraFormula}}" name="extraFormula" placeholder="Situational Bonus">
|
||||
{{/unless}}
|
||||
{{#if @root.rallyDie.length}}
|
||||
<span class="formula-label">{{localize "DAGGERHEART.CLASS.Feature.rallyDice"}}</span>
|
||||
<select name="roll.dice._rallyIndex">
|
||||
{{selectOptions @root.rallyDie blank="" selected=@root.roll._rallyIndex}}
|
||||
</select>
|
||||
{{/if}}
|
||||
{{#if (eq @root.rollType 'DualityRoll')}}<span class="formula-label">Situational Bonus</span>{{/if}}
|
||||
<input type="text" value="{{extraFormula}}" name="extraFormula" placeholder="{{#if (eq @root.rollType 'DualityRoll')}}Ex: 1d6 + 5{{else}}Situational Bonus{{/if}}">
|
||||
</fieldset>
|
||||
{{/unless}}
|
||||
<span class="formula-label"><b>Formula:</b> {{@root.formula}}</span>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@
|
|||
{{localize "DAGGERHEART.GENERAL.Disadvantage.full"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if roll.rally.dice}}
|
||||
<div class="duality-modifier">
|
||||
{{localize "DAGGERHEART.CLASS.Feature.rallyDice"}} {{roll.rally.dice}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="dice-result">
|
||||
<div class="dice-formula">{{roll.formula}}</div>
|
||||
|
|
@ -38,7 +43,7 @@
|
|||
<div class="dice-title">{{localize "DAGGERHEART.GENERAL.hope"}}</div>
|
||||
<div class="dice-inner-container hope" title="{{localize "DAGGERHEART.GENERAL.hope"}}">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d12-grey.svg"/>
|
||||
<img class="dice" src="../icons/svg/{{roll.hope.dice}}-grey.svg"/>
|
||||
</div>
|
||||
<div class="dice-value">{{roll.hope.value}}</div>
|
||||
</div>
|
||||
|
|
@ -49,7 +54,7 @@
|
|||
<div class="dice-title">{{localize "DAGGERHEART.GENERAL.fear"}}</div>
|
||||
<div class="dice-inner-container fear" title="{{localize "DAGGERHEART.GENERAL.fear"}}">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d12-grey.svg"/>
|
||||
<img class="dice" src="../icons/svg/{{roll.fear.dice}}-grey.svg"/>
|
||||
</div>
|
||||
<div class="dice-value">{{roll.fear.value}}</div>
|
||||
</div>
|
||||
|
|
@ -72,7 +77,7 @@
|
|||
<div class="dice-container">
|
||||
<div class="dice-inner-container {{#if (eq roll.advantage.type 1)}}advantage{{else}}disadvantage{{/if}}">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/d6-grey.svg"/>
|
||||
<img class="dice" src="../icons/svg/{{roll.advantage.dice}}-grey.svg"/>
|
||||
</div>
|
||||
<div class="dice-value">{{roll.advantage.value}}</div>
|
||||
</div>
|
||||
|
|
@ -82,6 +87,30 @@
|
|||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if roll.rally.dice}}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">
|
||||
<span>1{{roll.rally.dice}}</span>
|
||||
</span>
|
||||
<span class="part-total">{{roll.rally.value}}</span>
|
||||
</header>
|
||||
<div class="flexrow">
|
||||
<ol class="dice-rolls">
|
||||
<li class="roll die {{roll.rally.dice}}">
|
||||
<div class="dice-container">
|
||||
<div class="dice-inner-container">
|
||||
<div class="dice-wrapper">
|
||||
<img class="dice" src="../icons/svg/{{roll.rally.dice}}-grey.svg"/>
|
||||
</div>
|
||||
<div class="dice-value">{{roll.rally.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#each roll.extra as | extra | }}
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue