mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
[Feature] Beastform Compendium (#434)
* Various fixes * Added fixes to make beastforms work * . * Added all SRD beastforms
This commit is contained in:
parent
0fe6c4066a
commit
187a0dc090
80 changed files with 6189 additions and 89 deletions
|
|
@ -164,7 +164,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
title: this.item.name,
|
||||
source: {
|
||||
item: this.item._id,
|
||||
action: this._id
|
||||
action: this._id,
|
||||
actor: this.actor.uuid
|
||||
},
|
||||
dialog: {},
|
||||
type: this.type,
|
||||
|
|
@ -191,7 +192,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
difficulty: this.roll?.difficulty,
|
||||
formula: this.roll.getFormula(),
|
||||
bonus: this.roll.bonus,
|
||||
advantage: CONFIG.DH.ACTIONS.advandtageState[this.roll.advState].value
|
||||
advantage: CONFIG.DH.ACTIONS.advantageState[this.roll.advState].value
|
||||
};
|
||||
if (this.roll?.type === 'diceSet') roll.lite = true;
|
||||
|
||||
|
|
@ -256,6 +257,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
/* EFFECTS */
|
||||
async applyEffects(event, data, targets) {
|
||||
targets ??= data.system.targets;
|
||||
const force = true; /* Where should this come from? */
|
||||
if (!this.effects?.length || !targets.length) return;
|
||||
let effects = this.effects;
|
||||
targets.forEach(async token => {
|
||||
|
|
|
|||
|
|
@ -4,15 +4,13 @@ import DHBaseAction from './baseAction.mjs';
|
|||
export default class DhBeastformAction extends DHBaseAction {
|
||||
static extraSchemas = [...super.extraSchemas, 'beastform'];
|
||||
|
||||
async use(event, ...args) {
|
||||
async use(_event, ...args) {
|
||||
const beastformConfig = this.prepareBeastformConfig();
|
||||
|
||||
const abort = await this.handleActiveTransformations();
|
||||
if (abort) return;
|
||||
|
||||
const item = args[0];
|
||||
|
||||
const { selected, evolved, hybrid } = await BeastformDialog.configure(beastformConfig, item);
|
||||
const { selected, evolved, hybrid } = await BeastformDialog.configure(beastformConfig, this.item);
|
||||
if (!selected) return;
|
||||
|
||||
await this.transform(selected, evolved, hybrid);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,23 @@
|
|||
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
|
||||
|
||||
const resistanceField = reductionLabel =>
|
||||
const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
resistance: new foundry.data.fields.BooleanField({ initial: false }),
|
||||
immunity: new foundry.data.fields.BooleanField({ initial: false }),
|
||||
reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0, label: reductionLabel })
|
||||
resistance: new foundry.data.fields.BooleanField({
|
||||
initial: false,
|
||||
label: `${resistanceLabel}.label`,
|
||||
hint: `${resistanceLabel}.hint`
|
||||
}),
|
||||
immunity: new foundry.data.fields.BooleanField({
|
||||
initial: false,
|
||||
label: `${immunityLabel}.label`,
|
||||
hint: `${immunityLabel}.hint`
|
||||
}),
|
||||
reduction: new foundry.data.fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: `${reductionLabel}.label`,
|
||||
hint: `${reductionLabel}.hint`
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -40,8 +53,16 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
if (this.metadata.isNPC) schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||
if (this.metadata.hasResistances)
|
||||
schema.resistance = new fields.SchemaField({
|
||||
physical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.physicalReduction'),
|
||||
magical: resistanceField('DAGGERHEART.GENERAL.DamageResistance.magicalReduction')
|
||||
physical: resistanceField(
|
||||
'DAGGERHEART.GENERAL.DamageResistance.physicalResistance',
|
||||
'DAGGERHEART.GENERAL.DamageResistance.physicalImmunity',
|
||||
'DAGGERHEART.GENERAL.DamageResistance.physicalReduction'
|
||||
),
|
||||
magical: resistanceField(
|
||||
'DAGGERHEART.GENERAL.DamageResistance.magicalResistance',
|
||||
'DAGGERHEART.GENERAL.DamageResistance.magicalImmunity',
|
||||
'DAGGERHEART.GENERAL.DamageResistance.magicalReduction'
|
||||
)
|
||||
});
|
||||
return schema;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ export default class DhCharacter extends BaseDataActor {
|
|||
severe: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold'
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
|
||||
}),
|
||||
major: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
|
||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold'
|
||||
})
|
||||
}),
|
||||
experiences: new fields.TypedObjectField(
|
||||
|
|
@ -112,7 +112,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
value: {
|
||||
custom: {
|
||||
enabled: true,
|
||||
formula: '@system.rules.attack.damage.value'
|
||||
formula: '@profd4'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -244,10 +244,19 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}),
|
||||
attack: new fields.SchemaField({
|
||||
damage: new fields.SchemaField({
|
||||
value: new fields.StringField({
|
||||
diceIndex: new fields.NumberField({
|
||||
integer: true,
|
||||
min: 0,
|
||||
max: 5,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.attack.damage.dice.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.attack.damage.dice.hint'
|
||||
}),
|
||||
bonus: new fields.NumberField({
|
||||
required: true,
|
||||
initial: '@profd4',
|
||||
label: 'DAGGERHEART.GENERAL.Rules.attack.damage.value.label'
|
||||
initial: 0,
|
||||
min: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.attack.damage.bonus.label'
|
||||
})
|
||||
}),
|
||||
roll: new fields.SchemaField({
|
||||
|
|
@ -462,6 +471,12 @@ export default class DhCharacter extends BaseDataActor {
|
|||
};
|
||||
}
|
||||
|
||||
get basicAttackDamageDice() {
|
||||
const diceTypes = Object.keys(CONFIG.DH.GENERAL.diceTypes);
|
||||
const attackDiceIndex = Math.max(Math.min(this.rules.attack.damage.diceIndex, 5), 0);
|
||||
return diceTypes[attackDiceIndex];
|
||||
}
|
||||
|
||||
static async unequipBeforeEquip(itemToEquip) {
|
||||
const primary = this.primaryWeapon,
|
||||
secondary = this.secondaryWeapon;
|
||||
|
|
@ -547,12 +562,16 @@ export default class DhCharacter extends BaseDataActor {
|
|||
const baseHope = this.resources.hope.value + (this.companion?.system?.resources?.hope ?? 0);
|
||||
this.resources.hope.value = Math.min(baseHope, this.resources.hope.max);
|
||||
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;
|
||||
|
||||
this.attack.damage.parts[0].value.custom.formula = `@prof${this.basicAttackDamageDice}${this.rules.attack.damage.bonus ? ` + ${this.rules.attack.damage.bonus}` : ''}`;
|
||||
}
|
||||
|
||||
getRollData() {
|
||||
const data = super.getRollData();
|
||||
|
||||
return {
|
||||
...data,
|
||||
basicAttackDamageDice: this.basicAttackDamageDice,
|
||||
tier: this.tier,
|
||||
level: this.levelData.level.current
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,25 +8,38 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
|||
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities }),
|
||||
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
|
||||
advState: new fields.StringField({ choices: CONFIG.DH.ACTIONS.advandtageState, initial: 'neutral' }),
|
||||
advState: new fields.StringField({
|
||||
choices: CONFIG.DH.ACTIONS.advantageState,
|
||||
initial: 'neutral'
|
||||
}),
|
||||
diceRolling: new fields.SchemaField({
|
||||
multiplier: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceSetNumbers,
|
||||
initial: 'prof',
|
||||
label: 'Dice Number'
|
||||
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.multiplier'
|
||||
}),
|
||||
flatMultiplier: new fields.NumberField({
|
||||
nullable: true,
|
||||
initial: 1,
|
||||
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.flatMultiplier'
|
||||
}),
|
||||
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
|
||||
dice: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceTypes,
|
||||
initial: 'd6',
|
||||
label: 'Dice Type'
|
||||
initial: CONFIG.DH.GENERAL.diceTypes.d6,
|
||||
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.dice'
|
||||
}),
|
||||
compare: new fields.StringField({
|
||||
choices: CONFIG.DH.ACTIONS.diceCompare,
|
||||
initial: 'above',
|
||||
label: 'Should be'
|
||||
nullable: true,
|
||||
initial: null,
|
||||
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.compare'
|
||||
}),
|
||||
treshold: new fields.NumberField({ initial: 1, integer: true, min: 1, label: 'Treshold' })
|
||||
treshold: new fields.NumberField({
|
||||
integer: true,
|
||||
nullable: true,
|
||||
initial: null,
|
||||
label: 'DAGGERHEART.ACTIONS.RollField.diceRolling.threshold'
|
||||
})
|
||||
}),
|
||||
useDefault: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
|
|
@ -41,7 +54,11 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
|||
this.diceRolling.multiplier === 'flat'
|
||||
? this.diceRolling.flatMultiplier
|
||||
: `@${this.diceRolling.multiplier}`;
|
||||
formula = `${multiplier}${this.diceRolling.dice}cs${CONFIG.DH.ACTIONS.diceCompare[this.diceRolling.compare].operator}${this.diceRolling.treshold}`;
|
||||
if (this.diceRolling.compare && this.diceRolling.threshold) {
|
||||
formula = `${multiplier}${this.diceRolling.dice}cs${CONFIG.DH.ACTIONS.diceCompare[this.diceRolling.compare].operator}${this.diceRolling.treshold}`;
|
||||
} else {
|
||||
formula = `${multiplier}${this.diceRolling.dice}`;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
formula = '';
|
||||
|
|
|
|||
|
|
@ -35,7 +35,13 @@ export default class FormulaField extends foundry.data.fields.StringField {
|
|||
|
||||
/** @inheritDoc */
|
||||
_validateType(value) {
|
||||
const roll = new Roll(value.replace(/@([a-z.0-9_-]+)/gi, '1'));
|
||||
/* A bit suss, but seems to work */
|
||||
let roll = null;
|
||||
try {
|
||||
roll = new Roll(value.replace(/@([a-z.0-9_-]+)/gi, '1'));
|
||||
} catch (_) {
|
||||
roll = new Roll(value.replace(/@([a-z.0-9_-]+)/gi, 'd6'));
|
||||
}
|
||||
roll.evaluateSync({ strict: false });
|
||||
if (this.options.deterministic && !roll.isDeterministic)
|
||||
throw new Error(`must not contain dice terms: ${value}`);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import AttachableItem from './attachableItem.mjs';
|
||||
import { ActionsField } from '../fields/actionField.mjs';
|
||||
import { armorFeatures } from '../../config/itemConfig.mjs';
|
||||
|
||||
export default class DHArmor extends AttachableItem {
|
||||
|
|
|
|||
|
|
@ -94,10 +94,13 @@ export default class DHBeastform extends BaseDataItem {
|
|||
return false;
|
||||
}
|
||||
|
||||
const features = await this.parent.parent.createEmbeddedDocuments(
|
||||
'Item',
|
||||
this.features.map(x => x.toObject())
|
||||
);
|
||||
const beastformFeatures = [];
|
||||
for (let featureData of this.features) {
|
||||
const feature = await foundry.utils.fromUuid(featureData.uuid);
|
||||
beastformFeatures.push(feature.toObject());
|
||||
}
|
||||
|
||||
const features = await this.parent.parent.createEmbeddedDocuments('Item', beastformFeatures);
|
||||
|
||||
const extraEffects = await this.parent.parent.createEmbeddedDocuments(
|
||||
'ActiveEffect',
|
||||
|
|
@ -152,12 +155,14 @@ export default class DHBeastform extends BaseDataItem {
|
|||
_onCreate(_data, _options, userId) {
|
||||
if (userId !== game.user.id) return;
|
||||
|
||||
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||
{
|
||||
type: 'beastform',
|
||||
name: game.i18n.localize('DAGGERHEART.ITEMS.Beastform.beastformEffect'),
|
||||
img: 'icons/creatures/abilities/paw-print-pair-purple.webp'
|
||||
}
|
||||
]);
|
||||
if (!this.parent.effects.find(x => x.type === 'beastform')) {
|
||||
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||
{
|
||||
type: 'beastform',
|
||||
name: game.i18n.localize('DAGGERHEART.ITEMS.Beastform.beastformEffect'),
|
||||
img: 'icons/creatures/abilities/paw-print-pair-purple.webp'
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue