From 7f4268f960f018cd9a81e3f37cb0f4a0ca2d98d7 Mon Sep 17 00:00:00 2001 From: Dylan Pizzo Date: Mon, 6 Jan 2025 21:06:13 -0800 Subject: [PATCH] Add debt and potion --- src/dominiontext.ts | 105 ++++++++++++++++++++++++++++++++++++++++++-- src/draw.ts | 46 ++++++++++++------- src/sampleData.ts | 6 +-- 3 files changed, 135 insertions(+), 22 deletions(-) diff --git a/src/dominiontext.ts b/src/dominiontext.ts index 500cf19..0017ccf 100644 --- a/src/dominiontext.ts +++ b/src/dominiontext.ts @@ -5,7 +5,9 @@ export type Piece = | { type: "text"; text: string; isBold?: boolean; isItalic?: boolean } | { type: "space" } | { type: "break" } - | { type: "coin"; text: string }; + | { type: "coin"; text: string } + | { type: "debt"; text: string } + | { type: "potion"; text: string }; type PromiseOr = T | Promise; @@ -163,7 +165,96 @@ const coinPiece = pieceDef({ }, }); -const pieceDefs = [textPiece, spacePiece, breakPiece, coinPiece]; +const debtPiece = pieceDef({ + type: "debt", + measure(context, _piece) { + context.save(); + const metrics = context.measureText(" "); + const height = + metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; + const coinImage = getImage("debt"); + context.restore(); + return { + type: "content", + width: coinImage.width * (height / coinImage.height), + ascent: metrics.fontBoundingBoxAscent, + descent: metrics.fontBoundingBoxDescent, + }; + }, + render(context, piece, x, y, measure) { + context.save(); + // context.fillStyle = "yellow"; + const height = measure.ascent + measure.descent; + // context.fillRect(x, y - measure.ascent, measure.width, height); + context.drawImage( + getImage("debt"), + x, + y - measure.ascent, + measure.width, + height + ); + const fontInfo = parseFont(context.font); + fontInfo.family = ["DominionSpecial"]; + fontInfo.weight = "bold"; + fontInfo.size = parseInt(fontInfo.size.toString()) * 1.2; + const font = stringifyFont(fontInfo); + context.font = font; + context.fillStyle = "white"; + context.textAlign = "center"; + context.fillText(piece.text, x + measure.width / 2, y); + context.restore(); + }, +}); + +const potionPiece = pieceDef({ + type: "potion", + measure(context, _piece) { + context.save(); + const metrics = context.measureText(" "); + const height = + metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; + const coinImage = getImage("potion"); + context.restore(); + return { + type: "content", + width: coinImage.width * (height / coinImage.height), + ascent: metrics.fontBoundingBoxAscent, + descent: metrics.fontBoundingBoxDescent, + }; + }, + render(context, piece, x, y, measure) { + context.save(); + // context.fillStyle = "yellow"; + const height = measure.ascent + measure.descent; + // context.fillRect(x, y - measure.ascent, measure.width, height); + context.drawImage( + getImage("potion"), + x, + y - measure.ascent, + measure.width, + height + ); + const fontInfo = parseFont(context.font); + fontInfo.family = ["DominionSpecial"]; + fontInfo.weight = "bold"; + fontInfo.size = parseInt(fontInfo.size.toString()) * 1.2; + const font = stringifyFont(fontInfo); + context.font = font; + context.fillStyle = "white"; + context.textAlign = "center"; + context.fillText(piece.text, x + measure.width / 2, y); + context.restore(); + }, +}); + +const pieceDefs = [ + textPiece, + spacePiece, + breakPiece, + coinPiece, + debtPiece, + potionPiece, +]; const tools: PieceTools = {} as any; @@ -267,7 +358,7 @@ export const renderDominionText = async ( pieces: Piece[], x: number, y: number, - maxWidth: number + maxWidth = Infinity ) => { const { lines, height } = await measureDominionText( context, @@ -325,6 +416,14 @@ export const parse = (text: string): Piece[] => { const end = text.slice(i).match(/\$\d*/)![0].length; pieces.push({ type: "coin", text: text.slice(i + 1, i + end) }); i += end - 1; + } else if (char === "@") { + const end = text.slice(i).match(/@\d*/)![0].length; + pieces.push({ type: "debt", text: text.slice(i + 1, i + end) }); + i += end - 1; + } else if (char === "^") { + const end = text.slice(i).match(/\^\d*/)![0].length; + pieces.push({ type: "potion", text: text.slice(i + 1, i + end) }); + i += end - 1; } else if (char === "+") { const match = text.slice(i).match(/\+\d* \S+/); if (match) { diff --git a/src/draw.ts b/src/draw.ts index 2db83c5..d2aed09 100644 --- a/src/draw.ts +++ b/src/draw.ts @@ -51,6 +51,14 @@ const imageList = [ key: "coin", src: "/static/assets/Coin.png", }, + { + key: "debt", + src: "/static/assets/Debt.png", + }, + { + key: "potion", + src: "/static/assets/Potion.png", + }, ]; export const loadImages = async () => { @@ -124,6 +132,7 @@ const drawStandardCard = async ( ): Promise => { const w = context.canvas.width; const h = context.canvas.height; + let size; context.save(); // Draw the image const image = await loadImage(card.image); @@ -151,8 +160,15 @@ const drawStandardCard = async ( context.drawImage(colorImage(getImage("card-brown"), "#ff9911"), 0, 0); context.drawImage(getImage("card-description-focus"), 44, 1094); // Draw the name - context.font = "78pt DominionTitle"; - await renderDominionText(context, parse(card.title), w / 2, 220, 1100); + size = 78; + context.font = `${size}pt DominionTitle`; + while ( + (await measureDominionText(context, parse(card.title))).width > 1050 + ) { + size -= 1; + context.font = `${size}pt DominionTitle`; + } + await renderDominionText(context, parse(card.title), w / 2, 220); // Draw the description context.font = "60pt DominionText"; await renderDominionText( @@ -163,7 +179,7 @@ const drawStandardCard = async ( 1000 ); // Draw the types - let size = 65; + size = 65; context.font = `${size}pt DominionTitle`; while ( ( @@ -185,18 +201,18 @@ const drawStandardCard = async ( ); // Draw the cost context.font = "90pt DominionText"; - await renderDominionText(context, parse(card.cost), 210, 1940, 200); + const costMeasure = await measureDominionText(context, parse(card.cost)); + await renderDominionText( + context, + parse(card.cost), + 130 + costMeasure.width / 2, + 1940 + ); // Draw the preview if (card.preview) { context.font = "90pt DominionText"; - await renderDominionText(context, parse(card.preview), 200, 210, 200); - await renderDominionText( - context, - parse(card.preview), - w - 200, - 210, - 200 - ); + await renderDominionText(context, parse(card.preview), 200, 210); + await renderDominionText(context, parse(card.preview), w - 200, 210); } // Draw the icon // Draw the author credit @@ -210,8 +226,7 @@ const drawStandardCard = async ( context, parse(card.author), w - 150 - authorMeasure.width / 2, - 2035, - w / 2 - 150 + 2035 ); // Draw the artist credit const artistMeasure = await measureDominionText( @@ -222,8 +237,7 @@ const drawStandardCard = async ( context, parse(card.artist), 155 + artistMeasure.width / 2, - 2035, - w / 2 - 150 + 2035 ); // Restore the context context.restore(); diff --git a/src/sampleData.ts b/src/sampleData.ts index c50152a..1a8d37f 100644 --- a/src/sampleData.ts +++ b/src/sampleData.ts @@ -15,7 +15,7 @@ export const sampleCard1: DominionCard = { artist: "Dall-E", author: "John Doe", version: "", - cost: "$", + cost: "@8", preview: "", }; @@ -35,12 +35,12 @@ export const sampleCard2: DominionCard = { export const sampleCard3: DominionCard = { orientation: "card", title: "Silver", - description: "$2", + description: "$2\n\n+@2", types: [TYPE_TREASURE], image: "", artist: "", author: "", version: "", - cost: "$3", + cost: "$3^", preview: "", };