Initial commit
This commit is contained in:
71
src/diceRoller/utils/handleRollCommand.ts
Normal file
71
src/diceRoller/utils/handleRollCommand.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { DiceRoller } from "../discord/dice";
|
||||
import { parseDiceUserInput } from "./parseDiceUserInput";
|
||||
import type { DiceParseResult } from "../types";
|
||||
|
||||
export async function handleRollCommand(
|
||||
inputStringFromUser: string,
|
||||
username: string,
|
||||
): Promise<string> {
|
||||
let parsedInputResult: DiceParseResult = { dices: [], mod: 0 };
|
||||
|
||||
try {
|
||||
parsedInputResult = parseDiceUserInput(inputStringFromUser);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) return error.message;
|
||||
}
|
||||
|
||||
const roller = new DiceRoller(username);
|
||||
const resultsMessages: string[] = [];
|
||||
|
||||
if (parsedInputResult.dices.length === 1) {
|
||||
const singleDie = parsedInputResult.dices[0];
|
||||
const { rollResult, message } = await roller.roll(singleDie);
|
||||
|
||||
const mod = parsedInputResult.mod;
|
||||
const finalResult = rollResult + mod;
|
||||
|
||||
let singleLine = `(${singleDie.toString()}) => ${rollResult}`;
|
||||
if (mod !== 0) {
|
||||
const sign = mod > 0 ? "+" : "-";
|
||||
singleLine += ` ${sign}${Math.abs(mod)} = ${finalResult}`;
|
||||
}
|
||||
|
||||
if (message) {
|
||||
singleLine += `\n${message}`;
|
||||
}
|
||||
|
||||
resultsMessages.push(singleLine);
|
||||
} else {
|
||||
resultsMessages.push(`You rolled ${parsedInputResult.dices.length} dice!`);
|
||||
|
||||
let sum = 0;
|
||||
let rollCount = 1;
|
||||
|
||||
for (const dieInput of parsedInputResult.dices) {
|
||||
const { rollResult, message } = await roller.roll(dieInput);
|
||||
sum += rollResult;
|
||||
|
||||
const prefix = `Roll #${rollCount}: `;
|
||||
const suffix = message ? ` **${message}**` : "";
|
||||
|
||||
resultsMessages.push(
|
||||
`${prefix}(d${dieInput.toString()}) => ${rollResult}${suffix}`,
|
||||
);
|
||||
rollCount++;
|
||||
}
|
||||
|
||||
const mod = parsedInputResult.mod;
|
||||
const finalResult = sum + mod;
|
||||
if (mod !== 0) {
|
||||
const sign = mod > 0 ? "+" : "-";
|
||||
|
||||
resultsMessages.push(
|
||||
`Result: ${sum} ${sign} ${Math.abs(mod)} = ${finalResult}`,
|
||||
);
|
||||
} else {
|
||||
resultsMessages.push(`**Final result: ${sum}**`);
|
||||
}
|
||||
}
|
||||
|
||||
return resultsMessages.join("\n");
|
||||
}
|
69
src/diceRoller/utils/parseDiceUserInput.ts
Normal file
69
src/diceRoller/utils/parseDiceUserInput.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Dice } from "../types";
|
||||
|
||||
const ALLOWED_DICE_SIDES = new Set(Object.values(Dice));
|
||||
|
||||
export function parseDiceUserInput(input: string): DiceParseResult {
|
||||
if (typeof input !== "string" || !input.trim()) {
|
||||
throw new Error("Input must be a non-empty string.");
|
||||
}
|
||||
|
||||
let clean = input.toLowerCase().trim();
|
||||
clean = clean.replace(/\b(roll|dice|die)\b/g, "");
|
||||
clean = clean.replace(/\s+/g, "");
|
||||
|
||||
if (/^\d+$/.test(clean)) {
|
||||
const sides = Number.parseInt(clean, 10);
|
||||
if (!ALLOWED_DICE_SIDES.has(sides)) {
|
||||
throw new Error(
|
||||
`Allowed dice sides are ${[...ALLOWED_DICE_SIDES].join(", ")}. Received: ${sides}`,
|
||||
);
|
||||
}
|
||||
return { dices: [sides], mod: 0 };
|
||||
}
|
||||
|
||||
const tokenRegex = /(\d*d\d+|[+\-]\d+)/g;
|
||||
const tokens = clean.match(tokenRegex);
|
||||
|
||||
if (!tokens) {
|
||||
throw new Error(
|
||||
"Unable to parse any dice or modifiers. Examples: '3d6+5', 'd20-2', '2d8+1d6+4'.",
|
||||
);
|
||||
}
|
||||
|
||||
const dices: number[] = [];
|
||||
let mod = 0;
|
||||
|
||||
for (const token of tokens) {
|
||||
if (token.includes("d")) {
|
||||
const [countPart, sidesPart] = token.split("d");
|
||||
|
||||
let diceCount = countPart ? Number.parseInt(countPart, 10) : 1;
|
||||
if (Number.isNaN(diceCount) || diceCount < 1) {
|
||||
diceCount = 1;
|
||||
}
|
||||
|
||||
const sides = Number.parseInt(sidesPart, 10);
|
||||
if (Number.isNaN(sides) || sides <= 0) {
|
||||
throw new Error(`Invalid number of sides: "${sidesPart}"`);
|
||||
}
|
||||
|
||||
if (!ALLOWED_DICE_SIDES.has(sides)) {
|
||||
throw new Error(
|
||||
`Allowed dice sides are ${[...ALLOWED_DICE_SIDES].join(", ")}. Received: ${sides}`,
|
||||
);
|
||||
}
|
||||
|
||||
for (let i = 0; i < diceCount; i++) {
|
||||
dices.push(sides);
|
||||
}
|
||||
} else {
|
||||
const parsedMod = Number.parseInt(token, 10);
|
||||
if (Number.isNaN(parsedMod)) {
|
||||
throw new Error(`Invalid modifier: "${token}"`);
|
||||
}
|
||||
mod += parsedMod;
|
||||
}
|
||||
}
|
||||
|
||||
return { dices, mod };
|
||||
}
|
Reference in New Issue
Block a user