89 lines
3.7 KiB
TypeScript
89 lines
3.7 KiB
TypeScript
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import { DS4 } from "../../config";
|
|
import { getGame } from "../../helpers";
|
|
import { createCheckRoll } from "../../rolls/check-factory";
|
|
import notifications from "../../ui/notifications";
|
|
import { DS4Item } from "../item";
|
|
|
|
import type { AttackType } from "./weapon-data-source";
|
|
|
|
export class DS4Weapon extends DS4Item {
|
|
override prepareDerivedData(): void {
|
|
this.data.data.rollable = this.data.data.equipped;
|
|
}
|
|
|
|
override async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
|
|
const game = getGame();
|
|
if (!this.data.data.equipped) {
|
|
return notifications.warn(
|
|
game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", {
|
|
name: this.name,
|
|
id: this.id,
|
|
type: this.data.type,
|
|
}),
|
|
);
|
|
}
|
|
|
|
if (!this.actor) {
|
|
throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id }));
|
|
}
|
|
|
|
const ownerDataData = this.actor.data.data;
|
|
const weaponBonus = this.data.data.weaponBonus;
|
|
const combatValue = await this.getCombatValueKeyForAttackType(this.data.data.attackType);
|
|
const checkTargetNumber = ownerDataData.combatValues[combatValue].total + weaponBonus;
|
|
|
|
const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker });
|
|
await createCheckRoll(checkTargetNumber, {
|
|
rollMode: getGame().settings.get("core", "rollMode"),
|
|
maximumCoupResult: ownerDataData.rolling.maximumCoupResult,
|
|
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult,
|
|
flavor: "DS4.ItemWeaponCheckFlavor",
|
|
flavorData: { actor: speaker.alias ?? this.actor.name, weapon: this.name },
|
|
speaker,
|
|
});
|
|
|
|
Hooks.callAll("ds4.rollItem", this);
|
|
}
|
|
|
|
private async getCombatValueKeyForAttackType(attackType: AttackType): Promise<"meleeAttack" | "rangedAttack"> {
|
|
if (attackType === "meleeRanged") {
|
|
const { melee, ranged } = { ...DS4.i18n.attackTypes };
|
|
const identifier = "attack-type-selection";
|
|
return Dialog.prompt({
|
|
title: getGame().i18n.localize("DS4.DialogAttackTypeSelection"),
|
|
content: await renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", {
|
|
selects: [
|
|
{
|
|
label: getGame().i18n.localize("DS4.AttackType"),
|
|
identifier,
|
|
options: { melee, ranged },
|
|
},
|
|
],
|
|
}),
|
|
label: getGame().i18n.localize("DS4.GenericOkButton"),
|
|
callback: (html) => {
|
|
const selectedAttackType = html.find(`#${identifier}`).val();
|
|
if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") {
|
|
throw new Error(
|
|
getGame().i18n.format("DS4.ErrorUnexpectedAttackType", {
|
|
actualType: selectedAttackType,
|
|
expectedTypes: "'melee', 'ranged'",
|
|
}),
|
|
);
|
|
}
|
|
return `${selectedAttackType}Attack` as const;
|
|
},
|
|
});
|
|
} else {
|
|
return `${attackType}Attack` as const;
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface DS4Weapon {
|
|
data: foundry.data.ItemData & { type: "weapon"; _source: { type: "weapon" } };
|
|
}
|