fvtt-rolemaster-frp/module/sheets/apps/rmfrp_dice_roller.js

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);
});
}
}