228 lines
8.0 KiB
JavaScript
228 lines
8.0 KiB
JavaScript
|
|
export default class RMFRPToolsDiceRoller extends FormApplication {
|
|
|
|
constructor(item, actor) {
|
|
super();
|
|
this.item = foundry.utils.duplicate(item);
|
|
this.actor = actor;
|
|
this.itemName = item.name;
|
|
this.characterBonus = Number(item.system.total_bonus);
|
|
this.stunnedModifier = actor.getStunnedModifier()
|
|
this.rollType = [
|
|
{ value: "one_to_onehundred", text: "1-100", selected: false },
|
|
{ value: "open_ended", text: "Open-Ended", selected: true },
|
|
{ value: "high_open_ended", text: "High Open-Ended", selected: false },
|
|
{ value: "low_open_ended", text: "Low Open-Ended", selected: false }
|
|
];
|
|
|
|
// Process weapon case
|
|
if (this.item.type == "skill" && this.item.system.category.includes("Weapon")) {
|
|
let weapon = this.actor.items.find(i => i.type == "weapon" && this.item._id == i.system.skill);
|
|
if ( !weapon ) {
|
|
ui.notifications.error("Weapon not found for skill: " + this.item.name);
|
|
return
|
|
}
|
|
this.weapon = weapon
|
|
this.characterBonus += Number(weapon.system.weapon_bonus);
|
|
}
|
|
|
|
}
|
|
|
|
static get defaultOptions() {
|
|
return foundry.utils.mergeObject(super.defaultOptions, {
|
|
classes: ["form"],
|
|
title: "Rolemaster Dice Roller",
|
|
popOut: true,
|
|
width: 480,
|
|
height: 440,
|
|
template: "systems/fvtt-rolemaster-frp/templates/sheets/apps/app_dice_roller.html"
|
|
});
|
|
}
|
|
|
|
getData() {
|
|
|
|
// Send data to the template
|
|
return {
|
|
itemName: this.itemName,
|
|
characterBonus: this.characterBonus,
|
|
selectOptions: this.rollType,
|
|
woundsModifier: this.actor.system.modifiers.woundsModifier,
|
|
weapon: this?.weapon,
|
|
targetArmorClass: 1,
|
|
config: CONFIG.rmfrp,
|
|
difficulty: 0,
|
|
combatSituation: 0,
|
|
lightningModifier: 0,
|
|
darknessModifier: 0,
|
|
hitsPerRound: 0,
|
|
isStunned: this.actor.system.state.stunned,
|
|
stunnedModifier: this.stunnedModifier
|
|
};
|
|
}
|
|
|
|
activateListeners(html) {
|
|
super.activateListeners(html);
|
|
}
|
|
|
|
async _updateObject(event, formData) {
|
|
console.log("Rolling Dice");
|
|
console.log(formData);
|
|
console.log(event);
|
|
this.roll(event.submitter?.dataset?.value, formData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async showDiceSoNice(roll, rollMode) {
|
|
if (game.modules.get("dice-so-nice")?.active) {
|
|
if (game.dice3d) {
|
|
let whisper = null;
|
|
let blind = false;
|
|
rollMode = rollMode ?? game.settings.get("core", "rollMode");
|
|
switch (rollMode) {
|
|
case "blindroll": //GM only
|
|
blind = true;
|
|
case "gmroll": //GM + rolling player
|
|
whisper = this.getUsers(user => user.isGM);
|
|
break;
|
|
case "roll": //everybody
|
|
whisper = this.getUsers(user => user.active);
|
|
break;
|
|
case "selfroll":
|
|
whisper = [game.user.id];
|
|
break;
|
|
}
|
|
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async roll(rollKey, formData) {
|
|
let baseRoll = await new Roll("1d100").roll();
|
|
await this.showDiceSoNice(baseRoll, game.settings.get("core", "rollMode"))
|
|
let rollType = this.rollType.find(r => r.value == rollKey)?.text;
|
|
let rollData = {
|
|
name: this.itemName,
|
|
weapon: this?.weapon,
|
|
rollKey: rollKey,
|
|
rollType: rollType,
|
|
difficulty: Number(formData.difficulty),
|
|
targetArmorClass: Number(formData?.targetArmorClass || 1),
|
|
combatSituation: Number(formData?.combatSituation || 0),
|
|
lightningModifier: Number(formData?.lightningModifier || 0),
|
|
darknessModifier: Number(formData?.darknessModifier || 0),
|
|
characterBonus: Number(this.characterBonus),
|
|
woundsModifier: Number(this.actor.system.modifiers.woundsModifier),
|
|
hitsPerRound: Number(formData.hitsPerRound),
|
|
isStunned: this.actor.system.state.stunned,
|
|
stunnedModifier: this.stunnedModifier,
|
|
rolls: [baseRoll],
|
|
}
|
|
if (baseRoll.result == 66) {
|
|
rollData.content = "You rolled a 66!";
|
|
}
|
|
// Process the for low open ended rolls
|
|
if (rollKey === "open_ended" || rollKey === "low_open_ended") {
|
|
if (baseRoll.result < 6) {
|
|
rollData.lowopen = true
|
|
let newRoll = await new Roll("-1d100").roll();
|
|
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
|
|
rollData.rolls.push(newRoll);
|
|
while (newRoll.result > 95) {
|
|
newRoll = await new Roll("-1d100").roll();
|
|
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
|
|
rollData.rolls.push(newRoll);
|
|
}
|
|
}
|
|
}
|
|
// Process the for high open ended rolls
|
|
if (rollKey === "open_ended" || rollKey === "high_open_ended") {
|
|
if (baseRoll.result > 95) {
|
|
rollData.highopen = true
|
|
let newRoll = await new Roll("1d100").roll();
|
|
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
|
|
rollData.rolls.push(newRoll);
|
|
while (newRoll.result > 95) {
|
|
newRoll = await new Roll("1d100").roll();
|
|
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
|
|
rollData.rolls.push(newRoll);
|
|
}
|
|
}
|
|
}
|
|
// Compute total of rolls
|
|
rollData.totalRolls = rollData.rolls.reduce((acc, roll) => Number(acc) + Number(roll.result), 0);
|
|
rollData.totalFinal = rollData.totalRolls + Number(rollData.combatSituation) +
|
|
Number(rollData.lightningModifier) +
|
|
Number(rollData.darknessModifier) +
|
|
Number(this.actor.system.modifiers.woundsModifier) +
|
|
Number(formData.difficulty) +
|
|
Number(rollData.hitsPerRound) +
|
|
Number(rollData.stunnedModifier) +
|
|
Number(this.characterBonus);
|
|
console.log(">>> Roll Data: ", rollData);
|
|
|
|
// Manage weapon table
|
|
|
|
if (this.weapon) {
|
|
let hasFumble = false
|
|
if ( rollData.totalRolls <= this.weapon.system.fumble_value ) {
|
|
hasFumble = true
|
|
}
|
|
|
|
let attackResult = game.rmfrp.attackTables.getAttackRollResult(this.weapon.system.attack_table, rollData.totalFinal, rollData.targetArmorClass)
|
|
if ( !attackResult) {
|
|
ui.notifications.error("Attack table not found: " + this.weapon.system.attack_table);
|
|
return
|
|
}
|
|
if (typeof attackResult == "object") { // Why ?????
|
|
attackResult = attackResult[String(rollData.targetArmorClass)];
|
|
}
|
|
console.log("Attack Result: ", attackResult);
|
|
rollData.attackResult = attackResult;
|
|
// Is it a a critical ?
|
|
let critical = attackResult.match(/(\d+)(\w)?(\w)?/);
|
|
if (critical && critical[2]) {
|
|
if ( critical[2] === "F") {
|
|
hasFumble = true
|
|
} else {
|
|
let criticalTable = this.weapon.system.critical_table
|
|
if ( !criticalTable ) {
|
|
ui.notifications.error("Critical table not found for weapon: " + this.weapon.name);
|
|
return
|
|
}
|
|
let criticalResult = await game.rmfrp.attackTables.getCriticalResult(criticalTable, critical[2]);
|
|
rollData.criticalResult = criticalResult;
|
|
console.log("Critical Result: ", criticalResult);
|
|
}
|
|
}
|
|
|
|
if (hasFumble) {
|
|
let fumbleResult = await game.rmfrp.attackTables.getFumbleRollResult(this.weapon.system.fumble_table, this.weapon.system.fumble_column)
|
|
if ( !fumbleResult) {
|
|
ui.notifications.error("Fumble table not found: " + this.weapon.system.attack_table);
|
|
return
|
|
}
|
|
rollData.fumbleResult = fumbleResult;
|
|
}
|
|
|
|
}
|
|
|
|
// Define the Chat Message Template
|
|
let chatTemplate = "systems/fvtt-rolemaster-frp/templates/chat/chat_dice_roll.html";
|
|
console.log("Final rollData", rollData)
|
|
|
|
// Pass the Data through to be used in the Chat Message
|
|
let chatData = rollData
|
|
// Render the Rolls to the Chat Window
|
|
renderTemplate(chatTemplate, chatData).then((html) => {
|
|
let chatOptions = {
|
|
flavor: rollType,
|
|
rollMode: game.settings.get("core", "rollMode"),
|
|
content: html,
|
|
};
|
|
ChatMessage.create(chatOptions);
|
|
});
|
|
}
|
|
|
|
}
|