207 lines
5.5 KiB
TypeScript
207 lines
5.5 KiB
TypeScript
import { Evaluated } from "@league-of-foundry-developers/foundry-vtt-types/src/foundry/client/dice/roll";
|
|
import { M5Character } from "../actors/M5Character";
|
|
import { M5EwResult, M5RollData, M5RollResult } from "../M5Base";
|
|
|
|
export class M5Roll { // extends Roll<M5RollData>
|
|
static readonly TEMPLATE_PATH = "systems/midgard5/templates/chat/roll-m5.hbs"
|
|
|
|
public _evaluated: boolean = false
|
|
public _total: number = 0
|
|
public pool: PoolTerm = null
|
|
|
|
constructor(public data: M5RollData, public actor: any, public label: string) {
|
|
//super(null)
|
|
//this.data = rollData
|
|
}
|
|
|
|
// @ts-ignore
|
|
//override evaluate(options?: InexactPartial<RollTerm.EvaluationOptions>): Evaluated<Roll<M5RollData>> | Promise<Evaluated<Roll<M5RollData>>> {
|
|
evaluate() {
|
|
const indexMap = new Map<number, string>()
|
|
const rollNames = Object.keys(this.data.rolls)
|
|
const rolls = rollNames.filter(rollName => this.data.rolls[rollName].enabled).map((rollName, index) => {
|
|
indexMap.set(index, rollName)
|
|
const formula = this.data.rolls[rollName]
|
|
const roll = new Roll(formula.formula, this.data)
|
|
return roll
|
|
})
|
|
|
|
this.pool = PoolTerm.fromRolls(rolls)
|
|
console.log("evaluate", this._evaluated, this.pool)
|
|
return this.pool.evaluate({ async: true }).then(results => {
|
|
this._total = 0
|
|
|
|
results.rolls.forEach((roll, index) => {
|
|
const rollIndex = indexMap.get(index)
|
|
const rollResult = this.data.rolls[rollIndex] as M5RollResult
|
|
|
|
rollResult.result = roll.result
|
|
rollResult.total = roll.total
|
|
rollResult.totalStr = roll.total.toString()
|
|
|
|
this._total += roll.total
|
|
|
|
let rowRes = M5EwResult.TBD
|
|
let face100 = -1
|
|
|
|
roll.dice.forEach((d, dIndex) => {
|
|
rollResult.dice[dIndex.toString()] = d.total
|
|
|
|
if (rowRes === M5EwResult.TBD && dIndex === 0) {
|
|
if (d.faces === 20) {
|
|
//if (rollResult.type === "ew") {
|
|
if (d.total === 1)
|
|
rowRes = M5EwResult.FUMBLE
|
|
else if (d.total === 20)
|
|
rowRes = M5EwResult.CRITICAL
|
|
else if (d.total >= 16)
|
|
rowRes = M5EwResult.HIGH
|
|
} else if (d.faces === 100) {
|
|
face100 = d.total as number
|
|
}
|
|
}
|
|
})
|
|
|
|
const parseResult = M5Roll.parseDiceSides(rollResult.formula)
|
|
//console.log("evaluate roll", parseResult)
|
|
if (parseResult?.sides === 20) {
|
|
if (roll.total < 20) {
|
|
if (rowRes === M5EwResult.TBD || rowRes === M5EwResult.HIGH)
|
|
rowRes = M5EwResult.FAIL
|
|
} else {
|
|
if (rowRes === M5EwResult.TBD)
|
|
rowRes = M5EwResult.PASS
|
|
}
|
|
} else if (face100 >= 0) {
|
|
const threshold100 = roll.total + face100
|
|
const threshold = Math.floor(threshold100 / 10)
|
|
if (face100 === 100) {
|
|
if (rowRes === M5EwResult.TBD)
|
|
rowRes = M5EwResult.FUMBLE
|
|
} else if (roll.total < 0) {
|
|
if (rowRes === M5EwResult.TBD)
|
|
rowRes = M5EwResult.FAIL
|
|
} else if (face100 <= threshold) {
|
|
if (rowRes === M5EwResult.TBD)
|
|
rowRes = M5EwResult.CRITICAL
|
|
} else {
|
|
if (rowRes === M5EwResult.TBD)
|
|
rowRes = M5EwResult.PASS
|
|
}
|
|
}
|
|
rollResult.css = rowRes
|
|
})
|
|
|
|
this.data.res.label = this.label
|
|
|
|
this._evaluated = true
|
|
return this
|
|
})
|
|
}
|
|
|
|
async render(): Promise<string> {
|
|
return renderTemplate(M5Roll.TEMPLATE_PATH, this.data)
|
|
}
|
|
|
|
async toMessage() {
|
|
if (!this._evaluated)
|
|
await this.evaluate()
|
|
|
|
const rMode = (game as Game).settings.get("core", "rollMode")
|
|
|
|
const chatData = {
|
|
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
|
|
content: await this.render(),
|
|
speaker: ChatMessage.getSpeaker({actor: this.actor}),
|
|
sound: CONFIG.sounds.dice,
|
|
roll: Roll.fromTerms([this.pool])
|
|
}
|
|
|
|
ChatMessage.applyRollMode(chatData, rMode)
|
|
return ChatMessage.create(chatData)
|
|
}
|
|
|
|
static fromAttribute(actor: any, attributeKey: string) {
|
|
const character = actor as M5Character
|
|
const attribute = character.attribute(attributeKey)
|
|
|
|
const rollData = actor.getRollData() as M5RollData
|
|
rollData.i = attribute.value + attribute.bonus
|
|
rollData.rolls["0"] = {
|
|
formula: "@i - 1d100",
|
|
enabled: true,
|
|
label: (game as Game).i18n.localize("midgard5.pw"),
|
|
result: "",
|
|
total: 0,
|
|
totalStr: "",
|
|
dice: {},
|
|
css: ""
|
|
} as M5RollResult
|
|
|
|
return new M5Roll(rollData, actor, (game as Game).i18n.localize(`midgard5.actor-${attributeKey}-long`))
|
|
}
|
|
|
|
static brawl(actor: any) {
|
|
const rollData = actor.getRollData() as M5RollData
|
|
rollData.i = {
|
|
attackBonus: 0,
|
|
damageBonus: 0
|
|
}
|
|
|
|
rollData.rolls["0"] = {
|
|
formula: "1d20 + @c.calc.stats.brawl + @c.calc.stats.attackBonus + @i.attackBonus",
|
|
enabled: true,
|
|
label: (game as Game).i18n.localize("midgard5.attack"),
|
|
result: "",
|
|
total: 0,
|
|
totalStr: "",
|
|
dice: {},
|
|
css: ""
|
|
} as M5RollResult
|
|
|
|
rollData.rolls["1"] = {
|
|
formula: "1d6 - 4 + @c.calc.stats.damageBonus + @i.damageBonus",
|
|
enabled: true,
|
|
label: (game as Game).i18n.localize("midgard5.damage"),
|
|
result: "",
|
|
total: 0,
|
|
totalStr: "",
|
|
dice: {},
|
|
css: ""
|
|
} as M5RollResult
|
|
|
|
return new M5Roll(rollData, actor, (game as Game).i18n.localize("midgard5.brawl"))
|
|
}
|
|
|
|
static parseDiceSides(formula: string): FormulaParseResult {
|
|
const ewMatcher: RegExp = /\d*[dD]20/g
|
|
const pwMatcher: RegExp = /(\d+)\s*\-\s*\d*[dD]100/g
|
|
|
|
let res = formula.match(ewMatcher)
|
|
if (res && !!res[0]) {
|
|
return {
|
|
sides: 20,
|
|
type: "ew",
|
|
threshold: null
|
|
}
|
|
}
|
|
|
|
res = formula.match(pwMatcher)
|
|
if (res && !!res[1]) {
|
|
return {
|
|
sides: 100,
|
|
type: "pw",
|
|
threshold: parseInt(res[1])
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
}
|
|
|
|
interface FormulaParseResult {
|
|
sides: number,
|
|
type: string,
|
|
threshold: number
|
|
}
|