type Component = (ctx: CanvasRenderingContext2D) => void function base(fill: string, stroke?: string, stroke_width?: number): Component { return c => { c.fillStyle = fill; c.strokeStyle = stroke ?? "black"; c.lineWidth = stroke_width ?? 0.05 c.lineJoin = "miter" c.lineCap = "square" c.fillRect( -0.5, -0.5, 1, 1 ) if (stroke) c.strokeRect( -0.5 + c.lineWidth / 2, -0.5 + c.lineWidth / 2, 1 - c.lineWidth, 1 - c.lineWidth ) } } function rect(inset: number, fill: string, stroke?: string, stroke_width?: number): Component { return c => { c.fillStyle = fill; c.strokeStyle = stroke ?? "black"; c.lineWidth = stroke_width ?? 0.05 c.lineJoin = "round" c.lineCap = "round" c.fillRect( -0.5 + inset, -0.5 + inset, 1 - inset * 2, 1 - inset * 2 ) if (stroke) c.strokeRect( -0.5 + inset, -0.5 + inset, 1 - inset * 2, 1 - inset * 2 ) } } function circle(radius: number, fill: string, stroke?: string, stroke_width?: number): Component { return c => { c.fillStyle = fill; c.strokeStyle = stroke ?? "black"; c.lineWidth = stroke_width ?? 0.05 c.beginPath() c.arc(0.0, 0.0, radius, 0, Math.PI * 2) if (stroke) c.stroke() c.fill() } } function cross(size: number, stroke: string, stroke_width = 0.05): Component { return c => { c.strokeStyle = stroke c.lineWidth = stroke_width c.lineCap = "round" c.beginPath() c.moveTo(-size, -size) c.lineTo(size, size) c.moveTo(size, -size) c.lineTo(-size, size) c.stroke() } } function arrange_items(...items: string[]): Component[] { return items.flatMap((item, index) => { const t = index / items.length * Math.PI * 2. const radius = items.length == 1 ? 0 : (0.4 / items.length) const off_x = Math.sin(t) * radius const off_y = Math.cos(t) * radius const scale = 1. / Math.sqrt(items.length) return c => { for (const comp of ITEMS[item]) { c.save() c.translate(off_x, off_y) c.scale(scale, scale) comp(c) c.restore() } } }) } const door: Component = c => { c.fillStyle = "#ff9843" c.fillRect(-0.5, -0.1, 1, 0.2) } const plate = [circle(0.4, "#b6b6b6", "#f7f7f7", 0.02)]; export const FALLBACK_ITEM: Component[] = [circle(0.3, "#f0f")]; export const ITEMS: { [key: string]: Component[] } = { "raw-steak": [circle(0.3, "#cc3705")], "steak": [circle(0.3, "#702200")], "flour": [circle(0.3, "#d8c9c2")], "dough": [circle(0.3, "#b38d7d")], "bread": [circle(0.3, "#853e20")], "tomato": [circle(0.3, "#d63838")], "sliced-tomato": [circle(0.3, "#d16363", "#d63838", 0.08)], "plate": plate, "dirty-plate": [circle(0.4, "#947a6f", "#d3a187", 0.02)], "steak-meal": [...plate, ...arrange_items("steak")], "burger-meal": [...plate, ...arrange_items("bread", "steak")], "sliced-tomato-meal": [...plate, ...arrange_items("sliced-tomato")], "tomatosteak-meal": [...plate, ...arrange_items("tomato", "steak")], "tomatoburger-meal": [...plate, ...arrange_items("bread", "steak", "tomato")], } const table = [base("rgb(133, 76, 38)")]; const floor = [base("#333", "#222", 0.05)]; const counter = [base("rgb(182, 172, 164)")]; const crate = (i: string) => [base("#60701e", "#b9da37", 0.05), ...ITEMS[i]]; export const FALLBACK_TILE: Component[] = [base("#f0f")]; export const TILES: { [key: string]: Component[] } = { "floor": floor, "table": table, "counter": counter, "door": [...floor, door], "chair": [...floor, circle(0.45, "rgb(136, 83, 41)")], "wall": [base("rgb(0, 14, 56)")], "window": [base("rgb(233, 233, 233)")], "cuttingboard": [...counter, rect(0.3, "rgb(158, 236, 68)", "rgb(158, 236, 68)", 0.2)], "trash": [...floor, circle(0.4, "rgb(20, 20, 20)"), cross(0.3, "rgb(90, 36, 36)")], "sink": [base("rgb(131, 129, 161)", "rgb(177, 174, 226)", 0.2)], "oven": [base("rgb(241, 97, 61)", "rgb(109, 84, 84)", 0.3)], "pan": [...counter, circle(0.4, "#444", "#999")], "flour-crate": crate("flour"), "dirty-plate-crate": crate("dirty-plate"), "raw-steak-crate": crate("raw-steak"), "tomato-crate": crate("tomato"), }