@blkc-code/render-canvas 0.3.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/draw.d.ts +9 -9
- package/dist/draw.d.ts.map +1 -1
- package/dist/draw.js +73 -305
- package/dist/draw.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/links.d.ts +16 -0
- package/dist/links.d.ts.map +1 -0
- package/dist/links.js +75 -0
- package/dist/links.js.map +1 -0
- package/dist/office.d.ts +2 -0
- package/dist/office.d.ts.map +1 -1
- package/dist/office.js +2 -0
- package/dist/office.js.map +1 -1
- package/dist/pack.d.ts +31 -0
- package/dist/pack.d.ts.map +1 -0
- package/dist/pack.js +10 -0
- package/dist/pack.js.map +1 -0
- package/dist/paint.d.ts +15 -0
- package/dist/paint.d.ts.map +1 -0
- package/dist/paint.js +18 -0
- package/dist/paint.js.map +1 -0
- package/dist/runtime.js +1 -1
- package/dist/runtime.txt +1 -1
- package/dist/types.d.ts +13 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/world.d.ts +15 -11
- package/dist/world.d.ts.map +1 -1
- package/dist/world.js +31 -59
- package/dist/world.js.map +1 -1
- package/dist/worlds/office-data.d.ts +14 -0
- package/dist/worlds/office-data.d.ts.map +1 -0
- package/dist/worlds/office-data.js +52 -0
- package/dist/worlds/office-data.js.map +1 -0
- package/dist/worlds/office-paint.d.ts +13 -0
- package/dist/worlds/office-paint.d.ts.map +1 -0
- package/dist/worlds/office-paint.js +292 -0
- package/dist/worlds/office-paint.js.map +1 -0
- package/package.json +7 -2
- package/src/draw.ts +73 -289
- package/src/index.ts +3 -0
- package/src/links.ts +76 -0
- package/src/office.ts +3 -0
- package/src/pack.ts +36 -0
- package/src/paint.ts +24 -0
- package/src/types.ts +12 -2
- package/src/world.ts +41 -60
- package/src/worlds/office-data.ts +57 -0
- package/src/worlds/office-paint.ts +276 -0
package/dist/draw.d.ts
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
* 16 pixels a tile. The building is drawn once to a layer (drawBuilding); people, screens
|
|
4
4
|
* and anything else that moves are drawn on top each frame (drawWorld).
|
|
5
5
|
*/
|
|
6
|
-
import { type
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
import { type Ctx, type Palette } from "./paint.js";
|
|
7
|
+
import { type Item, type World } from "./world.js";
|
|
8
|
+
export { TILE, type Palette } from "./paint.js";
|
|
9
|
+
/** How one world looks. The engine draws the building, characters and labels around it. */
|
|
10
|
+
export interface Painter {
|
|
11
|
+
furniture(c: Ctx, item: Item, world: World, time: number, palette: Palette): void;
|
|
12
|
+
/** What lights up at night. Call `glow` for anything that does. */
|
|
13
|
+
glow(item: Item, world: World, glow: (x: number, y: number, radius: number, color: string) => void): void;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
export declare function registerPainter(id: string, painter: Painter): void;
|
|
15
16
|
export interface Daylight {
|
|
16
17
|
sky: string;
|
|
17
18
|
sun: string;
|
|
@@ -22,5 +23,4 @@ export declare function daylightAt(hour: number): Daylight;
|
|
|
22
23
|
export declare function drawBuilding(c: Ctx, world: World, palette: Palette, daylight: Daylight): void;
|
|
23
24
|
/** Everything that moves. `building` is the layer from drawBuilding. */
|
|
24
25
|
export declare function drawWorld(c: Ctx, world: World, time: number, palette: Palette, daylight: Daylight, building: CanvasImageSource | undefined, selected?: string): void;
|
|
25
|
-
export {};
|
|
26
26
|
//# sourceMappingURL=draw.d.ts.map
|
package/dist/draw.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draw.d.ts","sourceRoot":"","sources":["../src/draw.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"draw.d.ts","sourceRoot":"","sources":["../src/draw.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAqD,KAAK,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACvG,OAAO,EAAgC,KAAK,IAAI,EAAa,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAG5F,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAIhD,2FAA2F;AAC3F,MAAM,WAAW,OAAO;IACtB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAClF,mEAAmE;IACnE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;CAC3G;AAID,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAElE;AAMD,MAAM,WAAW,QAAQ;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AAErE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAKjD;AAuUD,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAgB7F;AAoED,wEAAwE;AACxE,wBAAgB,SAAS,CACvB,CAAC,EAAE,GAAG,EACN,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,CAgDN"}
|
package/dist/draw.js
CHANGED
|
@@ -3,23 +3,16 @@
|
|
|
3
3
|
* 16 pixels a tile. The building is drawn once to a layer (drawBuilding); people, screens
|
|
4
4
|
* and anything else that moves are drawn on top each frame (drawWorld).
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
function shade(color, amount) {
|
|
16
|
-
if (!color.startsWith("#"))
|
|
17
|
-
return color;
|
|
18
|
-
const hex = color.length === 4 ? `#${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}` : color;
|
|
19
|
-
const n = parseInt(hex.slice(1, 7), 16);
|
|
20
|
-
const channel = (shift) => Math.max(0, Math.min(255, ((n >> shift) & 255) + amount));
|
|
21
|
-
return `rgb(${channel(16)},${channel(8)},${channel(0)})`;
|
|
6
|
+
import { drawLinks, linkRoutes } from "./links.js";
|
|
7
|
+
import { BODY_FONT, LABEL_FONT, OUTLINE, TILE, rect, shade } from "./paint.js";
|
|
8
|
+
import { isSeated, specOf } from "./world.js";
|
|
9
|
+
import { OFFICE_PAINTER } from "./worlds/office-paint.js";
|
|
10
|
+
export { TILE } from "./paint.js";
|
|
11
|
+
const painters = new Map([["office", OFFICE_PAINTER]]);
|
|
12
|
+
export function registerPainter(id, painter) {
|
|
13
|
+
painters.set(id, painter);
|
|
22
14
|
}
|
|
15
|
+
const painterFor = (world) => painters.get(world.pack.id) ?? OFFICE_PAINTER;
|
|
23
16
|
export function daylightAt(hour) {
|
|
24
17
|
if (hour >= 7 && hour < 17)
|
|
25
18
|
return { sky: "#8ed0ff", sun: "rgba(255,244,214,0.10)", night: 0 };
|
|
@@ -240,6 +233,24 @@ function drawFloor(c, room) {
|
|
|
240
233
|
if (noise === 3)
|
|
241
234
|
rect(c, "#596070", x + 3, y + 8, 8, 1);
|
|
242
235
|
break;
|
|
236
|
+
case "hall": {
|
|
237
|
+
// Polished floor, with a runner down the middle of a corridor's length.
|
|
238
|
+
rect(c, "#cfc8b8", x, y, TILE, TILE);
|
|
239
|
+
rect(c, "#bdb6a6", x, y + 15, TILE, 1);
|
|
240
|
+
rect(c, "#bdb6a6", x + 15, y, 1, TILE);
|
|
241
|
+
const along = room.w >= room.h;
|
|
242
|
+
const offset = along ? ty - room.y : tx - room.x;
|
|
243
|
+
const size = along ? room.h : room.w;
|
|
244
|
+
if (along && offset === 0)
|
|
245
|
+
rect(c, "#7f6a55", x, y + 12, TILE, 4);
|
|
246
|
+
if (along && offset === size - 1)
|
|
247
|
+
rect(c, "#7f6a55", x, y, TILE, 4);
|
|
248
|
+
if (!along && offset === 0)
|
|
249
|
+
rect(c, "#7f6a55", x + 12, y, 4, TILE);
|
|
250
|
+
if (!along && offset === size - 1)
|
|
251
|
+
rect(c, "#7f6a55", x, y, 4, TILE);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
243
254
|
case "grass":
|
|
244
255
|
rect(c, "#3f8f4f", x, y, TILE, TILE);
|
|
245
256
|
for (let i = 0; i < 7; i++)
|
|
@@ -263,6 +274,24 @@ const WALL_TOP = "#2a2d48";
|
|
|
263
274
|
const WALL_FACE = "#5c628f";
|
|
264
275
|
const WALL_DARK = "#4a4f78";
|
|
265
276
|
const WALL_LIGHT = "#6d74a4";
|
|
277
|
+
/** Outside the building: lawn, with the odd shrub and tree. */
|
|
278
|
+
function drawGrounds(c, tx, ty) {
|
|
279
|
+
const x = tx * TILE;
|
|
280
|
+
const y = ty * TILE;
|
|
281
|
+
rect(c, (tx + ty) % 2 === 0 ? "#4b8a4f" : "#478549", x, y, TILE, TILE);
|
|
282
|
+
const noise = (tx * 73 + ty * 151) % 29;
|
|
283
|
+
for (let i = 0; i < 4; i++)
|
|
284
|
+
rect(c, "#5a9b5c", x + ((tx * 5 + i * 7) % 15), y + ((ty * 3 + i * 5) % 15), 1, 2);
|
|
285
|
+
if (noise === 4) {
|
|
286
|
+
rect(c, "#2f6a38", x + 3, y + 7, 10, 7);
|
|
287
|
+
rect(c, "#3c7f45", x + 5, y + 8, 5, 3);
|
|
288
|
+
}
|
|
289
|
+
else if (noise === 11) {
|
|
290
|
+
rect(c, "#5b3a22", x + 7, y + 10, 2, 5);
|
|
291
|
+
rect(c, "#24592e", x + 2, y + 1, 12, 10);
|
|
292
|
+
rect(c, "#2f6f3a", x + 4, y + 2, 7, 5);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
266
295
|
function drawWalls(c, world, palette, daylight) {
|
|
267
296
|
const open = new Set();
|
|
268
297
|
for (const room of world.rooms) {
|
|
@@ -278,12 +307,25 @@ function drawWalls(c, world, palette, daylight) {
|
|
|
278
307
|
continue;
|
|
279
308
|
const x = tx * TILE;
|
|
280
309
|
const y = ty * TILE;
|
|
310
|
+
const nearBuilding = (cx, cy) => {
|
|
311
|
+
for (let ay = cy - 1; ay <= cy + 1; ay++) {
|
|
312
|
+
for (let ax = cx - 1; ax <= cx + 1; ax++)
|
|
313
|
+
if (open.has(`${ax},${ay}`) || doors.has(`${ax},${ay}`))
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
};
|
|
318
|
+
if (!nearBuilding(tx, ty)) {
|
|
319
|
+
drawGrounds(c, tx, ty);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
281
322
|
if (open.has(`${tx},${ty + 1}`)) {
|
|
282
323
|
rect(c, WALL_FACE, x, y, TILE, TILE);
|
|
283
324
|
rect(c, WALL_LIGHT, x, y, TILE, 1);
|
|
284
325
|
rect(c, WALL_DARK, x, y + 12, TILE, 4);
|
|
285
326
|
rect(c, palette.primary, x, y + 11, TILE, 1);
|
|
286
|
-
|
|
327
|
+
// Windows look outside, so only an outer wall has them.
|
|
328
|
+
if (tx % 4 === 3 && !nearBuilding(tx, ty - 1) && !world.furniture.some((item) => specOf(world, item).wall && item.x === tx && item.y === ty)) {
|
|
287
329
|
// A window, in the colour of the sky right now.
|
|
288
330
|
rect(c, "#1f2937", x + 1, y + 1, 14, 9);
|
|
289
331
|
rect(c, daylight.sky, x + 2, y + 2, 12, 7);
|
|
@@ -347,10 +389,10 @@ export function drawBuilding(c, world, palette, daylight) {
|
|
|
347
389
|
drawWalls(c, world, palette, daylight);
|
|
348
390
|
for (const item of world.furniture)
|
|
349
391
|
if (item.type === "rug")
|
|
350
|
-
|
|
392
|
+
painterFor(world).furniture(c, item, world, 0, palette);
|
|
351
393
|
for (const item of world.furniture)
|
|
352
|
-
if (
|
|
353
|
-
|
|
394
|
+
if (specOf(world, item).wall)
|
|
395
|
+
painterFor(world).furniture(c, item, world, 0, palette);
|
|
354
396
|
// Light from the windows falling across the floor.
|
|
355
397
|
if (daylight.sun !== "rgba(0,0,0,0)") {
|
|
356
398
|
c.fillStyle = daylight.sun;
|
|
@@ -363,279 +405,6 @@ export function drawBuilding(c, world, palette, daylight) {
|
|
|
363
405
|
}
|
|
364
406
|
}
|
|
365
407
|
}
|
|
366
|
-
function drawDesk(c, x, y, on, time, seed, palette, blocked) {
|
|
367
|
-
rect(c, "#55351d", x + 1, y + 22, 46, 8);
|
|
368
|
-
rect(c, "#6b4427", x + 1, y + 13, 46, 10);
|
|
369
|
-
rect(c, "#8a5a33", x + 1, y + 10, 46, 12);
|
|
370
|
-
rect(c, "#a87545", x + 1, y + 10, 46, 2);
|
|
371
|
-
rect(c, "#3b2413", x + 3, y + 22, 3, 9);
|
|
372
|
-
rect(c, "#3b2413", x + 42, y + 22, 3, 9);
|
|
373
|
-
rect(c, "#55351d", x + 30, y + 23, 12, 7);
|
|
374
|
-
rect(c, "#7c5637", x + 31, y + 24, 10, 2);
|
|
375
|
-
rect(c, "#d4a24e", x + 35, y + 24, 2, 1);
|
|
376
|
-
rect(c, "#7c5637", x + 31, y + 27, 10, 2);
|
|
377
|
-
rect(c, "#d4a24e", x + 35, y + 27, 2, 1);
|
|
378
|
-
// Monitor
|
|
379
|
-
rect(c, OUTLINE, x + 14, y - 3, 20, 15);
|
|
380
|
-
rect(c, "#374151", x + 22, y + 12, 4, 2);
|
|
381
|
-
rect(c, "#4b5563", x + 19, y + 14, 10, 1);
|
|
382
|
-
if (blocked) {
|
|
383
|
-
rect(c, "#3f0f14", x + 15, y - 2, 18, 13);
|
|
384
|
-
if (Math.floor(time * 2) % 2 === 0) {
|
|
385
|
-
rect(c, "#ef4444", x + 23, y, 2, 6);
|
|
386
|
-
rect(c, "#ef4444", x + 23, y + 7, 2, 2);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
else if (on) {
|
|
390
|
-
rect(c, "#0f2a2e", x + 15, y - 2, 18, 13);
|
|
391
|
-
const scroll = Math.floor(time * 3 + (seed % 13));
|
|
392
|
-
for (let line = 0; line < 5; line++) {
|
|
393
|
-
const width = 3 + (((seed >> line) & 7) + (scroll + line) * 7) % 12;
|
|
394
|
-
rect(c, line % 3 === 0 ? palette.primary : line % 3 === 1 ? "#7dd3fc" : "#fcd34d", x + 16 + (line % 2) * 2, y - 1 + line * 2.2, width, 1);
|
|
395
|
-
}
|
|
396
|
-
c.fillStyle = "rgba(125,211,252,0.12)";
|
|
397
|
-
c.fillRect(x + 10, y + 11, 28, 8);
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
rect(c, "#1f2937", x + 15, y - 2, 18, 13);
|
|
401
|
-
rect(c, "#374151", x + 17, y, 3, 1);
|
|
402
|
-
}
|
|
403
|
-
rect(c, "#d1d5db", x + 16, y + 15, 16, 5);
|
|
404
|
-
for (let row = 0; row < 2; row++)
|
|
405
|
-
for (let key = 0; key < 7; key++)
|
|
406
|
-
rect(c, "#9ca3af", x + 17 + key * 2, y + 16 + row * 2, 1, 1);
|
|
407
|
-
rect(c, "#e5e7eb", x + 34, y + 16, 3, 4);
|
|
408
|
-
rect(c, "#f3f4f6", x + 40, y + 13, 5, 5);
|
|
409
|
-
rect(c, palette.primary, x + 40, y + 15, 5, 1);
|
|
410
|
-
rect(c, "#fde68a", x + 4, y + 13, 7, 6);
|
|
411
|
-
rect(c, "#fbbf24", x + 5, y + 15, 5, 1);
|
|
412
|
-
}
|
|
413
|
-
function drawBoard(c, x, y, world) {
|
|
414
|
-
rect(c, "#3a2c1e", x, y - 12, 64, 27);
|
|
415
|
-
rect(c, "#d9c29c", x + 2, y - 10, 60, 23);
|
|
416
|
-
for (let i = 0; i < 40; i++)
|
|
417
|
-
rect(c, "#c9b08a", x + 3 + (i * 37) % 58, y - 9 + (i * 13) % 21, 1, 1);
|
|
418
|
-
const colors = { todo: "#fde68a", doing: "#93c5fd", done: "#86efac" };
|
|
419
|
-
const per = 8;
|
|
420
|
-
world.tasks.slice(0, per * 2).forEach((task, index) => {
|
|
421
|
-
const col = index % per;
|
|
422
|
-
const row = Math.floor(index / per);
|
|
423
|
-
rect(c, "#00000033", x + 5 + col * 7, y - 7 + row * 10, 6, 8);
|
|
424
|
-
rect(c, colors[task.state], x + 4 + col * 7, y - 8 + row * 10, 6, 8);
|
|
425
|
-
rect(c, "#ef4444", x + 6 + col * 7, y - 8 + row * 10, 2, 1);
|
|
426
|
-
rect(c, "#00000040", x + 5 + col * 7, y - 5 + row * 10, 4, 1);
|
|
427
|
-
rect(c, "#00000040", x + 5 + col * 7, y - 3 + row * 10, 3, 1);
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
function drawFurniture(c, item, world, time, palette) {
|
|
431
|
-
const x = item.x * TILE;
|
|
432
|
-
const y = item.y * TILE;
|
|
433
|
-
switch (item.type) {
|
|
434
|
-
case "desk": {
|
|
435
|
-
const seatX = item.x + 1;
|
|
436
|
-
const seatY = item.y + 2;
|
|
437
|
-
const user = world.agents.find((a) => a.seat?.x === seatX && a.seat?.y === seatY && isSeated(a));
|
|
438
|
-
drawDesk(c, x, y, Boolean(user), time, user?.seed ?? 0, palette, user?.state === "blocked");
|
|
439
|
-
break;
|
|
440
|
-
}
|
|
441
|
-
case "coffee":
|
|
442
|
-
rect(c, "#374151", x, y + 2, 32, 14);
|
|
443
|
-
rect(c, "#6b7280", x, y + 2, 32, 2);
|
|
444
|
-
rect(c, OUTLINE, x + 4, y - 9, 15, 15);
|
|
445
|
-
rect(c, "#27272a", x + 5, y - 8, 13, 13);
|
|
446
|
-
rect(c, Math.floor(time * 2) % 2 ? "#ef4444" : "#7f1d1d", x + 15, y - 6, 2, 2);
|
|
447
|
-
rect(c, "#52525b", x + 7, y - 6, 6, 4);
|
|
448
|
-
rect(c, "#f3f4f6", x + 8, y + 3, 5, 4);
|
|
449
|
-
rect(c, "#f3f4f6", x + 23, y - 1, 5, 5);
|
|
450
|
-
rect(c, "#92400e", x + 24, y, 3, 1);
|
|
451
|
-
for (let i = 0; i < 3; i++) {
|
|
452
|
-
c.fillStyle = "rgba(255,255,255,0.5)";
|
|
453
|
-
c.fillRect(x + 9 + Math.round(Math.sin(time * 2 + i) * 1.5), y - 1 - ((time * 8 + i * 4) % 9), 1, 2);
|
|
454
|
-
}
|
|
455
|
-
break;
|
|
456
|
-
case "water":
|
|
457
|
-
rect(c, "#d1d5db", x + 3, y + 3, 10, 13);
|
|
458
|
-
rect(c, "#9ca3af", x + 3, y + 14, 10, 2);
|
|
459
|
-
rect(c, "#60a5fa", x + 4, y - 8, 8, 11);
|
|
460
|
-
rect(c, "#bae6fd", x + 5, y - 7, 2, 9);
|
|
461
|
-
rect(c, "#3b82f6", x + 5, y + 6, 2, 2);
|
|
462
|
-
rect(c, "#ef4444", x + 9, y + 6, 2, 2);
|
|
463
|
-
if (Math.floor(time * 0.4 + item.x) % 5 === 0)
|
|
464
|
-
rect(c, "#e0f2fe", x + 8, y - 2 - ((time * 6) % 7), 1, 1);
|
|
465
|
-
break;
|
|
466
|
-
case "sofa":
|
|
467
|
-
rect(c, shade(palette.primary, -60), x + 1, y - 7, 46, 11);
|
|
468
|
-
rect(c, shade(palette.primary, -30), x + 2, y - 6, 44, 3);
|
|
469
|
-
rect(c, "#4b5563", x, y + 3, 48, 11);
|
|
470
|
-
rect(c, "#6b7280", x + 3, y + 3, 20, 7);
|
|
471
|
-
rect(c, "#6b7280", x + 25, y + 3, 20, 7);
|
|
472
|
-
rect(c, "#374151", x, y + 12, 48, 3);
|
|
473
|
-
rect(c, "#374151", x - 1, y - 2, 4, 16);
|
|
474
|
-
rect(c, "#374151", x + 45, y - 2, 4, 16);
|
|
475
|
-
break;
|
|
476
|
-
case "plant":
|
|
477
|
-
rect(c, "#92400e", x + 4, y + 9, 8, 7);
|
|
478
|
-
rect(c, "#b45309", x + 3, y + 8, 10, 2);
|
|
479
|
-
for (const [lx, ly, lw, lh] of [[6, -3, 4, 11], [2, 0, 5, 6], [9, 1, 5, 6], [4, -6, 3, 6], [9, -5, 3, 5]])
|
|
480
|
-
rect(c, "#15803d", x + lx, y + ly, lw, lh);
|
|
481
|
-
rect(c, "#22c55e", x + 7, y - 3, 2, 8);
|
|
482
|
-
rect(c, "#22c55e", x + 3, y + 1, 2, 3);
|
|
483
|
-
rect(c, "#4ade80", x + 10, y - 4, 1, 3);
|
|
484
|
-
break;
|
|
485
|
-
case "fern":
|
|
486
|
-
rect(c, "#57534e", x + 3, y + 10, 10, 6);
|
|
487
|
-
rect(c, "#78716c", x + 2, y + 9, 12, 2);
|
|
488
|
-
for (let i = 0; i < 7; i++) {
|
|
489
|
-
const lean = i - 3;
|
|
490
|
-
for (let j = 0; j < 5; j++)
|
|
491
|
-
rect(c, j % 2 ? "#16a34a" : "#15803d", x + 7 + lean * (j / 2 + 1), y + 8 - j * 2 + Math.abs(lean), 2, 2);
|
|
492
|
-
}
|
|
493
|
-
break;
|
|
494
|
-
case "board":
|
|
495
|
-
drawBoard(c, x, y, world);
|
|
496
|
-
break;
|
|
497
|
-
case "whiteboard":
|
|
498
|
-
rect(c, "#9ca3af", x, y - 10, 48, 22);
|
|
499
|
-
rect(c, "#f9fafb", x + 2, y - 8, 44, 18);
|
|
500
|
-
rect(c, "#3b82f6", x + 5, y - 5, 14, 1);
|
|
501
|
-
rect(c, "#3b82f6", x + 5, y - 2, 9, 1);
|
|
502
|
-
rect(c, "#ef4444", x + 24, y - 6, 8, 6);
|
|
503
|
-
rect(c, "#f9fafb", x + 25, y - 5, 6, 4);
|
|
504
|
-
rect(c, "#10b981", x + 8, y + 3, 20, 1);
|
|
505
|
-
rect(c, "#10b981", x + 27, y + 2, 1, 3);
|
|
506
|
-
rect(c, "#6b7280", x + 2, y + 10, 44, 2);
|
|
507
|
-
break;
|
|
508
|
-
case "shelf":
|
|
509
|
-
rect(c, "#5b3a21", x, y - 12, 32, 28);
|
|
510
|
-
for (let shelf = 0; shelf < 2; shelf++) {
|
|
511
|
-
rect(c, "#3b2413", x + 2, y - 10 + shelf * 13, 28, 11);
|
|
512
|
-
for (let book = 0; book < 8; book++) {
|
|
513
|
-
const color = ["#ef4444", "#3b82f6", "#10b981", "#f59e0b", "#8b5cf6"][(book * 3 + shelf + item.x) % 5];
|
|
514
|
-
rect(c, color, x + 3 + book * 3, y - 8 + shelf * 13 + (book % 3), 2, 9 - (book % 3));
|
|
515
|
-
rect(c, shade(color, 40), x + 3 + book * 3, y - 6 + shelf * 13, 2, 1);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
break;
|
|
519
|
-
case "server":
|
|
520
|
-
rect(c, OUTLINE, x, y - 13, 16, 29);
|
|
521
|
-
rect(c, "#1f2937", x + 1, y - 12, 14, 27);
|
|
522
|
-
for (let i = 0; i < 5; i++) {
|
|
523
|
-
rect(c, "#111827", x + 2, y - 11 + i * 5, 12, 4);
|
|
524
|
-
const on = Math.floor(time * 3 + i * 2 + item.x) % 3 !== 0;
|
|
525
|
-
rect(c, on ? "#22c55e" : "#14532d", x + 3, y - 10 + i * 5, 1, 1);
|
|
526
|
-
rect(c, i % 2 === 0 ? "#f59e0b" : "#3b82f6", x + 5, y - 10 + i * 5, 1, 1);
|
|
527
|
-
rect(c, "#374151", x + 8, y - 10 + i * 5, 5, 1);
|
|
528
|
-
}
|
|
529
|
-
break;
|
|
530
|
-
case "table":
|
|
531
|
-
rect(c, "#44403c", x + 2, y + 16, 44, 12);
|
|
532
|
-
rect(c, "#78716c", x + 2, y + 3, 44, 14);
|
|
533
|
-
rect(c, "#a8a29e", x + 2, y + 3, 44, 2);
|
|
534
|
-
rect(c, "#f9fafb", x + 10, y + 6, 8, 6);
|
|
535
|
-
rect(c, "#f9fafb", x + 28, y + 8, 8, 6);
|
|
536
|
-
rect(c, "#1f2937", x + 12, y + 8, 4, 1);
|
|
537
|
-
rect(c, "#3b82f6", x + 30, y + 10, 4, 1);
|
|
538
|
-
break;
|
|
539
|
-
case "rug":
|
|
540
|
-
rect(c, palette.primary, x, y, 64, 48);
|
|
541
|
-
c.fillStyle = "rgba(0,0,0,0.42)";
|
|
542
|
-
c.fillRect(x + 3, y + 3, 58, 42);
|
|
543
|
-
rect(c, palette.primary, x + 6, y + 6, 52, 1);
|
|
544
|
-
rect(c, palette.primary, x + 6, y + 41, 52, 1);
|
|
545
|
-
rect(c, palette.primary, x + 6, y + 6, 1, 36);
|
|
546
|
-
rect(c, palette.primary, x + 57, y + 6, 1, 36);
|
|
547
|
-
for (let i = 0; i < 6; i++)
|
|
548
|
-
rect(c, palette.primary, x + 12 + i * 8, y + 22, 4, 4);
|
|
549
|
-
break;
|
|
550
|
-
case "arcade":
|
|
551
|
-
rect(c, OUTLINE, x, y - 14, 16, 30);
|
|
552
|
-
rect(c, "#4c1d95", x + 1, y - 13, 14, 28);
|
|
553
|
-
rect(c, "#111827", x + 3, y - 10, 10, 9);
|
|
554
|
-
rect(c, ["#22c55e", "#ec4899", "#38bdf8"][Math.floor(time * 2) % 3], x + 4 + (Math.floor(time * 4) % 7), y - 8 + (Math.floor(time * 3) % 5), 2, 2);
|
|
555
|
-
rect(c, "#f59e0b", x + 3, y - 13, 10, 2);
|
|
556
|
-
rect(c, "#27272a", x + 2, y + 1, 12, 4);
|
|
557
|
-
rect(c, "#ef4444", x + 4, y + 2, 2, 2);
|
|
558
|
-
rect(c, "#3b82f6", x + 9, y + 2, 2, 2);
|
|
559
|
-
break;
|
|
560
|
-
case "fridge":
|
|
561
|
-
rect(c, OUTLINE, x + 1, y - 12, 14, 28);
|
|
562
|
-
rect(c, "#e5e7eb", x + 2, y - 11, 12, 26);
|
|
563
|
-
rect(c, "#9ca3af", x + 2, y - 3, 12, 1);
|
|
564
|
-
rect(c, "#6b7280", x + 11, y - 8, 1, 3);
|
|
565
|
-
rect(c, "#6b7280", x + 11, y, 1, 5);
|
|
566
|
-
rect(c, "#fde68a", x + 4, y - 9, 3, 3);
|
|
567
|
-
rect(c, "#fca5a5", x + 5, y + 3, 3, 3);
|
|
568
|
-
break;
|
|
569
|
-
case "printer":
|
|
570
|
-
rect(c, "#4b5563", x + 2, y + 8, 12, 8);
|
|
571
|
-
rect(c, OUTLINE, x + 1, y - 2, 14, 11);
|
|
572
|
-
rect(c, "#d1d5db", x + 2, y - 1, 12, 9);
|
|
573
|
-
rect(c, "#f9fafb", x + 4, y - 5 - (Math.floor(time) % 4 === 0 ? 1 : 0), 8, 5);
|
|
574
|
-
rect(c, "#22c55e", x + 11, y + 1, 2, 1);
|
|
575
|
-
rect(c, "#9ca3af", x + 3, y + 5, 10, 1);
|
|
576
|
-
break;
|
|
577
|
-
case "lamp":
|
|
578
|
-
rect(c, "#374151", x + 5, y + 13, 6, 3);
|
|
579
|
-
rect(c, "#4b5563", x + 7, y - 4, 2, 17);
|
|
580
|
-
rect(c, OUTLINE, x + 2, y - 10, 12, 8);
|
|
581
|
-
rect(c, "#fde68a", x + 3, y - 9, 10, 6);
|
|
582
|
-
rect(c, "#fef3c7", x + 4, y - 8, 4, 2);
|
|
583
|
-
break;
|
|
584
|
-
case "beanbag":
|
|
585
|
-
rect(c, OUTLINE, x, y + 3, 16, 13);
|
|
586
|
-
rect(c, shade(palette.primary, -50), x + 1, y + 4, 14, 11);
|
|
587
|
-
rect(c, shade(palette.primary, -20), x + 3, y + 5, 8, 4);
|
|
588
|
-
rect(c, "#00000040", x + 1, y + 13, 14, 2);
|
|
589
|
-
break;
|
|
590
|
-
case "tv":
|
|
591
|
-
rect(c, "#3b2413", x + 2, y + 8, 44, 8);
|
|
592
|
-
rect(c, "#5b3a21", x + 2, y + 8, 44, 2);
|
|
593
|
-
rect(c, OUTLINE, x + 4, y - 14, 40, 22);
|
|
594
|
-
rect(c, "#0b1120", x + 5, y - 13, 38, 20);
|
|
595
|
-
for (let i = 0; i < 9; i++) {
|
|
596
|
-
const h = 2 + ((i * 5 + Math.floor(time * 3)) % 12);
|
|
597
|
-
rect(c, i % 3 === 0 ? palette.primary : i % 3 === 1 ? "#38bdf8" : "#f472b6", x + 8 + i * 4, y + 5 - h, 3, h);
|
|
598
|
-
}
|
|
599
|
-
break;
|
|
600
|
-
case "vending":
|
|
601
|
-
rect(c, OUTLINE, x, y - 14, 16, 30);
|
|
602
|
-
rect(c, "#b91c1c", x + 1, y - 13, 14, 28);
|
|
603
|
-
rect(c, "#0f172a", x + 3, y - 11, 8, 16);
|
|
604
|
-
for (let row = 0; row < 3; row++)
|
|
605
|
-
for (let col = 0; col < 2; col++)
|
|
606
|
-
rect(c, ["#fbbf24", "#34d399", "#60a5fa", "#f472b6"][(row + col * 2) % 4], x + 4 + col * 3, y - 10 + row * 5, 2, 4);
|
|
607
|
-
rect(c, "#d1d5db", x + 12, y - 9, 2, 6);
|
|
608
|
-
rect(c, "#111827", x + 3, y + 8, 10, 4);
|
|
609
|
-
break;
|
|
610
|
-
case "trophy":
|
|
611
|
-
rect(c, "#6b4427", x + 2, y + 8, 12, 8);
|
|
612
|
-
rect(c, "#8a5a33", x + 2, y + 8, 12, 2);
|
|
613
|
-
rect(c, "#78350f", x + 5, y + 5, 6, 3);
|
|
614
|
-
rect(c, "#f59e0b", x + 7, y + 1, 2, 4);
|
|
615
|
-
rect(c, OUTLINE, x + 3, y - 8, 10, 10);
|
|
616
|
-
rect(c, "#fbbf24", x + 4, y - 7, 8, 8);
|
|
617
|
-
rect(c, "#fde68a", x + 5, y - 6, 2, 5);
|
|
618
|
-
rect(c, "#fbbf24", x + 1, y - 6, 3, 1);
|
|
619
|
-
rect(c, "#fbbf24", x + 12, y - 6, 3, 1);
|
|
620
|
-
break;
|
|
621
|
-
case "clock": {
|
|
622
|
-
rect(c, OUTLINE, x + 3, y + 1, 10, 10);
|
|
623
|
-
rect(c, "#f9fafb", x + 4, y + 2, 8, 8);
|
|
624
|
-
rect(c, "#1f2937", x + 8, y + 3, 1, 3);
|
|
625
|
-
rect(c, "#1f2937", x + 8, y + 6, 3, 1);
|
|
626
|
-
break;
|
|
627
|
-
}
|
|
628
|
-
case "poster": {
|
|
629
|
-
const colors = ["#7c3aed", "#0ea5e9", "#db2777", "#059669"];
|
|
630
|
-
const color = colors[(item.x + item.y) % colors.length];
|
|
631
|
-
rect(c, OUTLINE, x + 2, y, 12, 11);
|
|
632
|
-
rect(c, color, x + 3, y + 1, 10, 9);
|
|
633
|
-
rect(c, shade(color, 60), x + 5, y + 3, 6, 3);
|
|
634
|
-
rect(c, "#f9fafb", x + 5, y + 7, 6, 1);
|
|
635
|
-
break;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
408
|
function nameTag(c, agent, selected, width) {
|
|
640
409
|
c.font = LABEL_FONT;
|
|
641
410
|
c.textBaseline = "top";
|
|
@@ -696,7 +465,7 @@ function drawProgress(c, world, palette) {
|
|
|
696
465
|
const w = 96;
|
|
697
466
|
rect(c, "rgba(17,24,39,0.85)", 4, 4, w, 20);
|
|
698
467
|
c.fillStyle = "#ffffff";
|
|
699
|
-
c.fillText(
|
|
468
|
+
c.fillText(`${world.pack.words.quests} ${done}/${world.tasks.length}`, 8, 6.5);
|
|
700
469
|
rect(c, "#374151", 8, 16, w - 8, 4);
|
|
701
470
|
rect(c, palette.primary, 8, 16, Math.round(((w - 8) * done) / world.tasks.length), 4);
|
|
702
471
|
}
|
|
@@ -708,12 +477,18 @@ export function drawWorld(c, world, time, palette, daylight, building, selected)
|
|
|
708
477
|
c.drawImage(building, 0, 0, width, height);
|
|
709
478
|
else
|
|
710
479
|
drawBuilding(c, world, palette, daylight);
|
|
480
|
+
// On the floor, so people and furniture stay in front of the lines.
|
|
481
|
+
if (world.showLinks && world.links.length > 0) {
|
|
482
|
+
world.routes ??= linkRoutes(world);
|
|
483
|
+
drawLinks(c, world.routes, time);
|
|
484
|
+
}
|
|
485
|
+
const painter = painterFor(world);
|
|
711
486
|
const scene = [];
|
|
712
487
|
for (const item of world.furniture) {
|
|
713
|
-
const spec =
|
|
488
|
+
const spec = specOf(world, item);
|
|
714
489
|
if (spec.solid === false)
|
|
715
490
|
continue;
|
|
716
|
-
scene.push({ depth: (item.y + spec.h) * TILE - 2, draw: () =>
|
|
491
|
+
scene.push({ depth: (item.y + spec.h) * TILE - 2, draw: () => painterFor(world).furniture(c, item, world, time, palette) });
|
|
717
492
|
}
|
|
718
493
|
const shown = world.agents.filter((agent) => agent.state !== "away");
|
|
719
494
|
for (const agent of shown)
|
|
@@ -734,15 +509,8 @@ export function drawWorld(c, world, time, palette, daylight, building, selected)
|
|
|
734
509
|
c.fillStyle = gradient;
|
|
735
510
|
c.fillRect(x - radius, y - radius, radius * 2, radius * 2);
|
|
736
511
|
};
|
|
737
|
-
for (const item of world.furniture)
|
|
738
|
-
|
|
739
|
-
glow(item.x * TILE + 8, item.y * TILE, 36, "rgba(253,224,139,0.30)");
|
|
740
|
-
if (item.type === "arcade" || item.type === "vending" || item.type === "tv")
|
|
741
|
-
glow(item.x * TILE + 8, item.y * TILE, 26, "rgba(125,211,252,0.16)");
|
|
742
|
-
if (item.type === "desk" && world.agents.some((a) => a.seat?.x === item.x + 1 && a.seat?.y === item.y + 2 && isSeated(a))) {
|
|
743
|
-
glow(item.x * TILE + 24, item.y * TILE + 8, 30, "rgba(125,211,252,0.26)");
|
|
744
|
-
}
|
|
745
|
-
}
|
|
512
|
+
for (const item of world.furniture)
|
|
513
|
+
painter.glow(item, world, glow);
|
|
746
514
|
c.restore();
|
|
747
515
|
}
|
|
748
516
|
// On top, so tall furniture against a wall can't hide a room's name.
|