Files
leggenda-del-regolo/src/engine/torch.js
T

90 lines
4.9 KiB
JavaScript

// Primo piano della fessura, disegnato alla risoluzione del gioco. Il quadro è la tela
// della foto del 2007 fornita da Andrea; il ritaglio viene eseguito solo nel disegno.
import { ambientHash as hash } from './ambient.js';
export function drawTorch(ctx, c, def, picture) {
const [x, y] = c.beam;
ctx.save();
ctx.fillStyle = '#090c10';
ctx.fillRect(0, 0, 640, 360);
// Muratura irregolare, muschio e giunti profondi.
for (let row = 0; row < 7; row++) for (let col = 0; col < 10; col++) {
const n = row * 10 + col, px = col * 73 - (row % 2) * 36, py = 24 + row * 47;
ctx.fillStyle = ['#4b4940', '#555247', '#3e443c', '#615b4b'][Math.floor(hash(n + 1) * 4)];
ctx.fillRect(px + 2, py + 2, 68, 42);
ctx.fillStyle = '#73705b';
ctx.fillRect(px + 5, py + 3, 61, 2);
ctx.fillStyle = '#282e29';
ctx.fillRect(px + 3, py + 39, 65, 4);
for (let k = 0; k < 6; k++) {
ctx.fillStyle = k % 2 ? '#424b35' : '#77715a';
ctx.fillRect(px + 7 + Math.floor(hash(n * 9 + k) * 54), py + 7 + Math.floor(hash(n * 13 + k) * 28), 3, 2);
}
}
// Il vano si perde dietro il muro; il quadro è appoggiato a terra, senza cornice dorata.
ctx.fillStyle = '#111617';
ctx.beginPath();
[[250, 84], [470, 67], [533, 135], [527, 288], [247, 300], [271, 231]].forEach(([a, b], i) => i ? ctx.lineTo(a, b) : ctx.moveTo(a, b));
ctx.closePath(); ctx.fill();
if (c.found >= 1) {
ctx.save();
ctx.translate(350, 224); ctx.rotate(-0.09);
ctx.fillStyle = '#242320'; ctx.fillRect(-48, -79, 98, 144);
if (picture) ctx.drawImage(picture, ...def.crop, -46, -77, 92, 138);
else {
// Anche se l'immagine non arriva il ritrovamento resta comprensibile e giocabile.
ctx.fillStyle = '#a6a67c'; ctx.fillRect(-46, -77, 92, 138);
ctx.fillStyle = '#e4d8ac'; ctx.beginPath(); ctx.moveTo(-43, 54); ctx.lineTo(0, -50); ctx.lineTo(10, -50); ctx.lineTo(25, 54); ctx.fill();
ctx.fillStyle = '#a83e2f'; ctx.fillRect(-6, 0, 12, 21); ctx.fillRect(-17, 0, 34, 5);
}
ctx.restore();
}
const eyes = c.found === 2 && c.step === 'reveal';
if (eyes) {
ctx.fillStyle = '#e5bd51';
for (const ex of [447, 470]) {
ctx.fillRect(ex, 134, 13, 8); ctx.fillRect(ex + 3, 132, 7, 12);
ctx.fillStyle = '#151912'; ctx.fillRect(ex + 6, 133, 2, 10);
ctx.fillStyle = '#fff1ad'; ctx.fillRect(ex + 3, 135, 2, 2);
ctx.fillStyle = '#e5bd51';
}
}
// Oscuramento radiale: il centro caldo lascia leggibile il dettaglio, fuori è quasi nero.
const light = ctx.createRadialGradient(x, y, 16, x, y, 112);
light.addColorStop(0, 'rgba(8,10,15,0)');
light.addColorStop(0.42, 'rgba(8,10,15,0.12)');
light.addColorStop(0.75, 'rgba(4,6,10,0.8)');
light.addColorStop(1, 'rgba(3,5,9,0.985)');
ctx.fillStyle = light; ctx.fillRect(0, 0, 640, 360);
// Qualche granello di polvere attraversa il fascio, senza lampeggiamenti.
for (let i = 0; i < 15; i++) {
const px = (hash(i + 100) * 640 + c.age * (2 + hash(i) * 3)) % 640;
const py = (hash(i + 200) * 360 + c.age * 2) % 360;
const distance = Math.hypot(px - x, py - y);
if (distance < 83) { ctx.fillStyle = `rgba(233,216,165,${0.35 * (1 - distance / 83)})`; ctx.fillRect(Math.round(px), Math.round(py), 1, 1); }
}
// Pietra vicina ai bordi: il giocatore guarda attraverso una fessura.
ctx.fillStyle = '#181b1c';
for (const points of [[[0, 0], [77, 0], [60, 97], [85, 178], [53, 278], [95, 360], [0, 360]],
[[640, 0], [568, 0], [594, 104], [564, 194], [583, 265], [552, 360], [640, 360]]]) {
ctx.beginPath(); points.forEach(([a, b], i) => i ? ctx.lineTo(a, b) : ctx.moveTo(a, b)); ctx.closePath(); ctx.fill();
}
// Torcia impugnata sul bordo inferiore, il puntatore resta libero per cercare.
ctx.save();
ctx.translate(430, 328); ctx.rotate((x - 320) / 1100);
const rect = (color, ...box) => { ctx.fillStyle = color; ctx.fillRect(...box); };
rect('#372722', 7, -2, 30, 44); rect('#9b6849', 10, 0, 24, 42);
rect('#c18c61', 11, 0, 11, 38); rect('#50382e', 29, 10, 5, 32);
// Corpo rosso e bordo metallico, come l'icona della torcia nell'inventario.
rect('#171c20', -16, -28, 28, 62); rect('#762e27', -13, -18, 21, 50);
rect('#a74330', -11, -17, 7, 46); rect('#4a2925', 4, -17, 4, 49);
for (let i = 0; i < 5; i++) rect('#482924', -12, 10 + i * 4, 20, 1);
rect('#343b3b', -19, -29, 34, 12); rect('#93998a', -17, -29, 30, 3);
rect('#d8ce9f', -15, -31, 26, 3); rect('#777c71', -17, -24, 3, 6);
rect('#d0a078', 4, -5, 14, 8); rect('#a37350', 4, 2, 14, 2);
for (let i = 0; i < 3; i++) { rect('#bf8b60', 4, 6 + i * 8, 17, 6); rect('#71503c', 5, 12 + i * 8, 16, 2); }
rect('#dfb58b', 6, -4, 5, 3);
ctx.restore();
ctx.restore();
}