diff --git a/src/components/workers/engine/layout.js b/src/components/workers/engine/layout.js index 29b598d..7fa6aef 100644 --- a/src/components/workers/engine/layout.js +++ b/src/components/workers/engine/layout.js @@ -60,8 +60,9 @@ function splitRooms(n) { return Array.from({ length: n }, (_, i) => ({ x: ROOM_X0 + i * w, w: i === n - 1 ? ROOM_W - w * (n - 1) : w })) } -// Orte für Effekte: Briefkasten am Pult, Tresor, Schublade im Archiv und ein Punkt rechts außerhalb des Turms. -// Fehlt die Etage im Layout (nur bei eigenen Etagenlisten), ist der Ort null. +// Orte für Effekte: Briefkasten am Pult (Spitze), Tresor (Mitte der Tür), Schublade im Archiv (erster Aktenschrank, rechts neben +// Arne; rooms.js zeichnet die Schränke ab Raum + 100) und ein Punkt rechts außerhalb des Turms. Der Test in workersRooms.test.mjs +// prüft, dass die Zeichnung jeden dieser Orte trifft. Fehlt die Etage im Layout (nur bei eigenen Etagenlisten), ist der Ort null. function buildSpots(floors) { const at = (floorId, dx, dy) => { const f = floors.find((fl) => fl.id === floorId) @@ -72,7 +73,7 @@ function buildSpots(floors) { pult: at('freigabe', 93, -15), tresor, aussen: tresor && { x: WORLD.w + 4, y: tresor.y - 1 }, - archiv: at('keller', 88, -16), + archiv: at('keller', 106, -16), } } diff --git a/src/components/workers/engine/rooms.js b/src/components/workers/engine/rooms.js index e42d82a..4cd4429 100644 --- a/src/components/workers/engine/rooms.js +++ b/src/components/workers/engine/rooms.js @@ -251,7 +251,8 @@ export const ROOM_DRAWERS = Object.freeze({ label(ctx, `${total} Deals`, r.x + 138, r.g - 15, { size: 11, color: PAL.ink, weight: 600 }) }, - // Archiv & Register: Kartons links, vier Aktenschränke rechts der Figur (beim Arbeiten springt je eine Schublade auf), Zähler der Bot-Leads + // Archiv & Register: Kartons links, vier Aktenschränke rechts der Figur (beim Arbeiten springt je eine Schublade auf), Zähler der Bot-Leads. + // Der erste Schrank (x + 100 ... + 112) trägt den Effektort layout.spots.archiv (Mitte, oberste Schublade): dort verschwindet das Blatt. archiv(ctx, r) { drawBox(ctx, r.x + 14, r.g - 9) drawBox(ctx, r.x + 31, r.g - 9) @@ -288,9 +289,12 @@ function drawRoom(ctx, room, floor, index, t, look) { color: TEAM[room.team] ?? PAL.metal2, look, } - if (!grey) tint(ctx, room.x, floor.top, room.w, floor.h, r.color, TINT_ALPHA) + // Teamfarbton hat jeder Raum, auch ein grauer (die Grautönung kommt darüber) + tint(ctx, room.x, floor.top, room.w, floor.h, r.color, TINT_ALPHA) if (index > 0) px(ctx, room.x, floor.top, 1, floor.h, DIVIDER) - // Das Schild steht oben mittig und verdrängt den Titel; Name und Branche erkennt man an Möbeln und Icon + // Der Titel steht in der obersten Zeile des Raums. Im grauen Raum nimmt das Schild (44 breit, 8 hoch) diese Zeile ein: + // über dem Hut der schlafenden Figur sind nur 6 Zeilen frei, Titel (3,3) und Schild (8) passen in den 46 breiten + // Such-Räumen, den einzigen, die grau sein können, nicht übereinander. Name und Branche zeigen dort Möbel und Icon. if (!grey) label(ctx, room.title, room.x + 2, floor.top + 1, { size: 10, color: PAL.mute, weight: 500 }) if (Object.hasOwn(ROOM_DRAWERS, room.kind)) ROOM_DRAWERS[room.kind](ctx, r) if (grey) { diff --git a/tests/unit/workersLayout.test.mjs b/tests/unit/workersLayout.test.mjs index 32cf550..d63d769 100644 --- a/tests/unit/workersLayout.test.mjs +++ b/tests/unit/workersLayout.test.mjs @@ -71,7 +71,7 @@ test('19 Worker haben genau einen Platz im eigenen Raum; Freigabe und Tresor ohn assert.equal(homeOf(layout, 'otto').y, 13) assert.equal(homeOf(layout, 'kim').y, 49) assert.deepEqual(layout.floors.filter((f) => f.rooms.some((r) => !r.workerId)).map((f) => f.id), ['freigabe', 'tresor']) - assert.deepEqual(layout.spots, { pult: { x: 135, y: 186 }, tresor: { x: 163, y: 213 }, aussen: { x: 324, y: 212 }, archiv: { x: 130, y: 231 } }) + assert.deepEqual(layout.spots, { pult: { x: 135, y: 186 }, tresor: { x: 163, y: 213 }, aussen: { x: 324, y: 212 }, archiv: { x: 148, y: 231 } }) }) test('Platz zentriert in der Raumbreite (Otto 24 breit, sonst 12)', () => { diff --git a/tests/unit/workersRooms.test.mjs b/tests/unit/workersRooms.test.mjs index f13faee..b7c8969 100644 --- a/tests/unit/workersRooms.test.mjs +++ b/tests/unit/workersRooms.test.mjs @@ -238,3 +238,62 @@ test('Gebäude: Layout ohne Etagen zeichnet nichts und wirft nicht', () => { assert.doesNotThrow(() => B.drawTower(m.ctx, { floors: [], homes: {}, spots: {} }, 1, { at: () => false })) assert.doesNotThrow(() => R.drawRooms(m.ctx, { floors: [], homes: {}, spots: {} }, 1, R.createLook())) }) + +// ---- Fix-Runde 1: Zeichnung und Effektorte, graue Räume ---- + +// Rechtecke der Raumzeichnung, die den Mittelpunkt der Einheitszelle (x, y) überdecken; die Tönung, die den ganzen Raum füllt, zählt nicht +const hitsAt = (floorId, spot, look = R.createLook()) => { + const floor = layout.floors.find((f) => f.id === floorId) + const full = Math.max(...floor.rooms.map((r) => r.w)) * 3 + const m = makeCtx() + R.drawRooms(m.ctx, { ...layout, floors: [floor] }, 1, look) + const cx = spot.x * 3 + 1 + const cy = spot.y * 3 + 1 + return m.rects.filter((r) => r.w < full && cx >= r.x && cx < r.x + r.w && cy >= r.y && cy < r.y + r.h) +} + +test('Zeichnung trifft den Spot: Briefkasten am Pult, Spitze genau bei spots.pult', () => { + const spot = layout.spots.pult + assert.ok(hitsAt('freigabe', spot).some((r) => r.fill === TEAM.freigabe), 'Briefkasten unter dem Spot') + // Spitze: eine Zeile darüber ist kein Briefkasten mehr + assert.ok(!hitsAt('freigabe', { x: spot.x, y: spot.y - 1 }).some((r) => r.fill === TEAM.freigabe)) +}) + +test('Zeichnung trifft den Spot: Tresortür in der Mitte von spots.tresor', () => { + const hit = hitsAt('tresor', layout.spots.tresor) + assert.ok(hit.some((r) => r.fill === PAL.metal2 && r.w === 22 * 3 && r.h === 20 * 3), 'Tresorkörper unter dem Spot') + // die 6 × 6 große Türplatte (x + 8 ... x + 14) umschließt den Spot + assert.ok(hit.some((r) => r.fill === PAL.metal && r.w === 6 * 3 && r.h === 6 * 3), 'Türplatte unter dem Spot') +}) + +test('Zeichnung trifft den Spot: Schublade eines Aktenschranks bei spots.archiv, nicht auf Arne', () => { + const spot = layout.spots.archiv + const hit = hitsAt('keller', spot) + // oberste Schubladenfront (10 × 5) des ersten Aktenschranks + assert.ok(hit.some((r) => r.fill === PAL.metal && r.w === 10 * 3 && r.h === 5 * 3), 'Schubladenfront unter dem Spot') + assert.ok(hit.some((r) => r.fill === PAL.metal2 && r.w === 12 * 3), 'Schrankkorpus unter dem Spot') + // Arnes Platz (Körper 12 breit, 14 hoch, Hut ab y - 2) liegt nicht auf dem Spot + const arne = layout.homes.arne + assert.ok(!(spot.x >= arne.x && spot.x < arne.x + 12 && spot.y >= arne.y - 2 && spot.y < arne.y + 14)) +}) + +test('grauer Raum: Teamfarbton bleibt, das Schild ersetzt den Titel (kein Platz für beides)', () => { + const floor = layout.floors.find((f) => f.id === 'anfragen') + const room = floor.rooms.find((r) => r.id === 'kleinanzeigen') + assert.equal(room.w, 46) + const run = (look) => { + const m = makeCtx() + R.drawRooms(m.ctx, { ...layout, floors: [{ ...floor, rooms: [room] }] }, 1, look) + return m + } + const normal = run(looks()) + const grey = run(looks({ greyRooms: new Set(['kleinanzeigen']) })) + const tintRects = (m) => m.rects.filter((r) => r.fill === TEAM[room.team] && r.w === room.w * 3 && r.h === floor.h * 3) + assert.equal(tintRects(normal).length, 1) + assert.equal(tintRects(grey).length, 1, 'Teamfarbton auch im grauen Raum') + assert.ok(grey.alphas.includes(0.1) && grey.alphas.includes(0.45), 'Teamfarbton 0,10, darüber die Grautönung 0,45') + assert.ok(normal.texts.some((x) => x.text === room.title)) + assert.ok(!grey.texts.some((x) => x.text === room.title), 'im grauen Raum steht das Schild an der Stelle des Titels') + assert.equal(grey.texts.filter((x) => x.text === SIGN).length, 1) + assert.equal(normal.texts.filter((x) => x.text === SIGN).length, 0) +})