daggerheart/module/data/chat-message/actorRoll.mjs

179 lines
6.5 KiB
JavaScript

const fields = foundry.data.fields;
const targetsField = () =>
new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({}),
actorId: new fields.StringField({}),
name: new fields.StringField({}),
img: new fields.StringField({}),
difficulty: new fields.NumberField({ integer: true, nullable: true }),
evasion: new fields.NumberField({ integer: true }),
hit: new fields.BooleanField({ initial: false }),
saved: new fields.SchemaField({
result: new fields.NumberField(),
success: new fields.BooleanField({ nullable: true, initial: null })
})
})
);
export const originItemField = () =>
new fields.SchemaField({
type: new fields.StringField({
choices: CONFIG.DH.ITEM.originItemType,
initial: CONFIG.DH.ITEM.originItemType.itemCollection
}),
itemPath: new fields.StringField(),
actionIndex: new fields.StringField()
});
export default class DHActorRoll extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
title: new fields.StringField(),
roll: new fields.ObjectField(),
targets: targetsField(),
hasRoll: new fields.BooleanField({ initial: false }),
hasDamage: new fields.BooleanField({ initial: false }),
hasHealing: new fields.BooleanField({ initial: false }),
hasEffect: new fields.BooleanField({ initial: false }),
hasSave: new fields.BooleanField({ initial: false }),
hasTarget: new fields.BooleanField({ initial: false }),
isDirect: new fields.BooleanField({ initial: false }),
isCritical: new fields.BooleanField({ initial: false }),
onSave: new fields.StringField(),
source: new fields.SchemaField({
actor: new fields.StringField(),
item: new fields.StringField(),
originItem: originItemField(),
action: new fields.StringField()
}),
damage: new fields.ObjectField(),
costs: new fields.ArrayField(new fields.ObjectField()),
successConsumed: new fields.BooleanField({ initial: false }),
};
}
get actionActor() {
if (!this.source.actor) return null;
return fromUuidSync(this.source.actor);
}
get actionItem() {
const actionActor = this.actionActor;
if (!actionActor || !this.source.item) return null;
switch (this.source.originItem.type) {
case CONFIG.DH.ITEM.originItemType.restMove:
const restMoves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves;
return Array.from(foundry.utils.getProperty(restMoves, `${this.source.originItem.itemPath}`).actions)[
this.source.originItem.actionIndex
];
default:
const item = actionActor.items.get(this.source.item);
return item ? item.system.actionsList?.find(a => a.id === this.source.action) : null;
}
}
get action() {
const { actionActor, actionItem: itemAction } = this;
if (!this.source.action) return null;
if (itemAction) return itemAction;
else if (actionActor?.system.attack?._id === this.source.action) return actionActor.system.attack;
return null;
}
get targetMode() {
return this.parent.targetSelection;
}
set targetMode(mode) {
if (!this.parent.isAuthor) return;
this.parent.targetSelection = mode;
this.registerTargetHook();
this.updateTargets();
}
get hitTargets() {
return this.currentTargets.filter(t => t.hit || !this.hasRoll || !this.targetMode);
}
async updateTargets() {
if (!ui.chat.collection.get(this.parent.id)) return;
let targets;
if (this.targetMode) targets = this.targets;
else
targets = Array.from(game.user.targets).map(t =>
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
);
await this.parent.update({
flags: {
[game.system.id]: {
targets: targets,
targetMode: this.targetMode
}
}
});
}
registerTargetHook() {
if (!this.parent.isAuthor || !this.hasTarget) return;
if (this.targetMode && this.parent.targetHook !== null) {
Hooks.off('targetToken', this.parent.targetHook);
return (this.parent.targetHook = null);
} else if (!this.targetMode && this.parent.targetHook === null) {
return (this.parent.targetHook = Hooks.on(
'targetToken',
foundry.utils.debounce(this.updateTargets.bind(this), 50)
));
}
}
prepareDerivedData() {
if (this.hasTarget) {
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
this.currentTargets = this.getTargetList();
// this.registerTargetHook();
if (this.hasRoll) {
this.targetShort = this.targets.reduce(
(a, c) => {
if (c.hit) a.hit += 1;
else a.miss += 1;
return a;
},
{ hit: 0, miss: 0 }
);
}
if (this.hasSave) this.setPendingSaves();
}
this.canViewSecret = this.parent.speakerActor?.testUserPermission(game.user, 'OBSERVER');
this.canButtonApply = game.user.isGM; //temp
this.isGM = game.user.isGM; //temp
}
getTargetList() {
const targets =
this.targetMode && this.parent.isAuthor
? this.targets
: (this.parent.getFlag(game.system.id, 'targets') ?? this.targets),
reactionRolls = this.parent.getFlag(game.system.id, 'reactionRolls');
if (reactionRolls) {
Object.entries(reactionRolls).forEach(([k, r]) => {
const target = targets.find(t => t.id === k);
if (target) target.saved = r;
});
}
return targets;
}
setPendingSaves() {
this.pendingSaves = this.targetMode
? this.targets.filter(target => target.hit && target.saved.success === null).length > 0
: this.currentTargets.filter(target => target.saved.success === null).length > 0;
}
}