2024-04-30 11:05:57 +00:00
|
|
|
import { Canvas, createCanvas, loadImage, SKRSContext2D } from "@napi-rs/canvas";
|
2024-04-10 21:47:46 +00:00
|
|
|
import {
|
|
|
|
GenerateBattlerOptions,
|
|
|
|
Colour,
|
|
|
|
Opponents,
|
2024-08-13 13:27:22 +00:00
|
|
|
CommunityOpponents
|
2024-04-10 21:47:46 +00:00
|
|
|
PlayerActions,
|
|
|
|
} from "./types";
|
|
|
|
|
|
|
|
export const validColours = Object.entries(Colour).map((x) => x[0]);
|
2024-08-13 13:30:45 +00:00
|
|
|
export const validOpponents = [
|
|
|
|
...Object.entries(Opponents).map((x) => x[0]),
|
|
|
|
...Object.entries(CommunityOpponents).map((x) => x[0])
|
|
|
|
];
|
2024-04-10 21:47:46 +00:00
|
|
|
export const validPlayerActions = Object.entries(PlayerActions).map((x) => x[1]);
|
|
|
|
|
|
|
|
export async function generateBattler(
|
|
|
|
opts: GenerateBattlerOptions & { direction?: "right" | "left" },
|
|
|
|
): Promise<Canvas> {
|
|
|
|
// Image dimensions
|
|
|
|
const canvas = createCanvas(1280, 1280);
|
|
|
|
const context = canvas.getContext("2d");
|
|
|
|
if (!validColours.includes(opts.colour)) opts.colour = Colour.Black;
|
|
|
|
|
|
|
|
// Load + draw the necessary images
|
|
|
|
|
|
|
|
// [Glow]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.glow && opts.glow !== "None") {
|
|
|
|
const glow = await loadImage(`./assets/glows/${opts.glow}.png`);
|
|
|
|
context.drawImage(glow, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
|
|
|
// [Back]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.back && opts.back !== "None") {
|
|
|
|
const back = await loadImage(`./assets/backs/${opts.back}.png`)
|
|
|
|
context.drawImage(back, 0, 0, canvas.width, canvas.height)
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
|
|
|
// [Base]
|
|
|
|
const base = await loadImage(`./assets/bases/${opts.colour || "Black"}.png`);
|
|
|
|
context.drawImage(base, 0, 0, canvas.width, canvas.height);
|
|
|
|
|
2024-04-30 10:57:50 +00:00
|
|
|
// [Upper Bottom]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.upperBottom && opts.upperBottom !== "None") {
|
|
|
|
const face = await loadImage(`./assets/upperBottom/${opts.face}.png`);
|
|
|
|
context.drawImage(face, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-30 10:57:50 +00:00
|
|
|
|
|
|
|
// [Bottom]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.bottom && opts.bottom !== "None") {
|
|
|
|
const bottom = await loadImage(`./assets/bottoms/${opts.bottom}.png`);
|
|
|
|
context.drawImage(bottom, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-30 10:57:50 +00:00
|
|
|
|
|
|
|
// [Top]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.top && opts.top !== "None") {
|
|
|
|
const top = await loadImage(`./assets/tops/${opts.top}.png`);
|
|
|
|
context.drawImage(top, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
|
|
|
|
2024-04-10 21:47:46 +00:00
|
|
|
// [Face]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.face && opts.face !== "None") {
|
|
|
|
const face = await loadImage(`./assets/faces/${opts.face}.png`);
|
|
|
|
context.drawImage(face, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
2024-04-30 10:57:50 +00:00
|
|
|
// [Hair]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.hair && opts.hair !== "None") {
|
|
|
|
const face = await loadImage(`./assets/hair/${opts.hair}.png`);
|
|
|
|
context.drawImage(face, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-30 10:57:50 +00:00
|
|
|
|
2024-04-10 21:47:46 +00:00
|
|
|
// [Hat]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.hat && opts.hat !== "None") {
|
|
|
|
const hat = await loadImage(`./assets/hats/${opts.hat}.png`);
|
|
|
|
context.drawImage(hat, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
|
|
|
// [Eyes]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.eye && opts.eye !== "None") {
|
|
|
|
const eye = await loadImage(`./assets/eyes/${opts.eye}.png`);
|
|
|
|
context.drawImage(eye, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
2024-04-30 10:57:50 +00:00
|
|
|
// [Upper Top]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.upperTop && opts.upperTop !== "None") {
|
|
|
|
const eye = await loadImage(`./assets/upperTop/${opts.upperTop}.png`);
|
|
|
|
context.drawImage(eye, 0, 0, canvas.width, canvas.height);
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
|
|
|
// [Neck]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.neck && opts.neck !== "None") {
|
|
|
|
const neck = await loadImage(`./assets/necks/${opts.neck}.png`)
|
|
|
|
context.drawImage(neck, 0, 0, canvas.width, canvas.height)
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
|
|
|
// [Buddy]
|
2024-04-30 11:24:37 +00:00
|
|
|
try {
|
|
|
|
if (opts.buddy && opts.buddy !== "None") {
|
|
|
|
const buddy = await loadImage(`./assets/buddies/${opts.buddy}.png`)
|
|
|
|
context.drawImage(buddy, 0, 0, canvas.width, canvas.height)
|
|
|
|
}
|
|
|
|
} catch (err) { }
|
2024-04-10 21:47:46 +00:00
|
|
|
|
|
|
|
if (opts.direction && opts.direction == "left") {
|
|
|
|
let flipped = createCanvas(1280, 1280);
|
|
|
|
let flippedCtx = flipped.getContext("2d");
|
|
|
|
|
|
|
|
flippedCtx.scale(-1, 1);
|
|
|
|
flippedCtx.drawImage(canvas, -canvas.width, 0, canvas.width, canvas.height);
|
|
|
|
|
|
|
|
return flipped;
|
|
|
|
}
|
|
|
|
|
|
|
|
return canvas;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function drawText(pos: [number, number], text: string, colour: string, outline: { colour: string, width: number }, ctx: SKRSContext2D) {
|
|
|
|
ctx.strokeStyle = outline.colour;
|
|
|
|
ctx.lineWidth = outline.width;
|
|
|
|
ctx.fillStyle = colour;
|
|
|
|
|
|
|
|
ctx.strokeText(text, pos[0], pos[1])
|
|
|
|
ctx.fillText(text, pos[0], pos[1])
|
|
|
|
}
|
|
|
|
|
|
|
|
export const applyText = (canvas: Canvas, text: string, width: number) => {
|
|
|
|
const context = canvas.getContext('2d');
|
|
|
|
|
|
|
|
// Declare a base size of the font
|
|
|
|
let fontSize = 175;
|
|
|
|
|
|
|
|
do {
|
|
|
|
// Assign the font to the context and decrement it so it can be measured again
|
|
|
|
context.font = `${fontSize -= 10}px Lilita One`;
|
|
|
|
// Compare pixel width of the text to the canvas minus the approximate avatar size
|
|
|
|
} while (context.measureText(text).width > width);
|
|
|
|
|
|
|
|
// Return the result to use in the actual canvas
|
|
|
|
return context.font;
|
|
|
|
};
|