Files
tickte-system/src/components/workers/engine/layout.js
T
ClaudeandClaude Sonnet 5.5 1aabbef3ab Workers P2: Archiv-Spot auf den ersten Aktenschrank, Teamfarbton auch im grauen Raum
Der Effektort spots.archiv lag auf Arne (x 130, y 231) statt auf einem gezeichneten Schrank; er sitzt jetzt in der Mitte der obersten Schublade des ersten Aktenschranks (x 148). Graue Räume behalten den Teamfarbton (Alpha 0,10) unter der Grautönung; das Schild ersetzt dort weiter den Titel (Platz). Neue Tests: Zeichnung trifft den Spot für pult, tresor, archiv; grauer Raum mit Tint ohne Titel.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 02:41:35 +00:00

135 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Hochhaus-Layout als Daten: Etagen, Räume und Heimatplätze der Figuren in der Welt 320 × 256 (Übersicht §3).
// Zeichnen (rooms, building) und Regie (director) lesen nur diese Tabelle; ein neuer Raum ist eine Zeile in
// ROOM_META plus eine Rolle. Kein React, kein Appwrite, kein window/document.
import { ROLES, FLOORS, FLOOR_TITLES, ROOM_TITLES } from '../../../lib/workersRoster.js'
export const WORLD = Object.freeze({ w: 320, h: 256 })
export const FLOOR_PITCH = 23 // Etage 22 hoch plus eine Bodenlinie
export const BRIDGE_H = 34 // die Kommandobrücke (Etage 0) ist höher
const TOP0 = 6 // Oberkante der Brücke
const FLOOR_H = 22
const ROOM_X0 = 42 // Räume stehen zwischen x 42 und 228 (Schacht und Etagenschilder liegen daneben)
const ROOM_W = 186
const HOME_DY = 14 // Figurenhöhe: Platz y = Boden - 14
const OTTO_DY = 27 // Otto steht höher (Kommandomütze, 24 breit)
const OTTO_W = 24
const WORKER_W = 12
const CAB_H = 21 // Kabinenhöhe des Aufzugs (lift.js importiert layout.js, nicht umgekehrt)
const meta = (kind, team) => Object.freeze({ kind, team })
// Raum -> Art der Zeichnung und Teamfarbe (Schlüssel aus TEAM in sprites.js)
export const ROOM_META = Object.freeze({
bruecke: meta('bruecke', 'freigabe'),
netz: meta('radar', 'radar'),
kleinanzeigen: meta('inbox', 'radar'),
portale: meta('feed', 'radar'),
foren: meta('board', 'radar'),
aerzte: meta('scout', 'aerzte'),
handwerk: meta('scout', 'handwerk'),
selbst: meta('scout', 'selbst'),
laden: meta('scout', 'laden'),
waage: meta('waage', 'bewertung'),
mail: meta('mail', 'freigabe'),
forum: meta('schreiber', 'freigabe'),
posteingang: meta('sortier', 'freigabe'),
abschluss: meta('vertrag', 'freigabe'),
tisch1: meta('tisch', 'werkstatt'),
tisch2: meta('tisch', 'werkstatt'),
tisch3: meta('tisch', 'werkstatt'),
pruefung: meta('pruefung', 'pruefung'),
pult: meta('pult', 'freigabe'),
tresor: meta('tresor', 'tresor'),
archiv: meta('archiv', 'archiv'),
})
// Räume ohne Worker: stehen in ihrer Etage hinter den Räumen der Rollen
const WORKERLESS = Object.freeze({ freigabe: ['pult'], tresor: ['tresor'] })
// Etage i: Brücke oben, danach im Raster 23 (Oberkante 41, 64, 87, ...); floorY ist die Bodenlinie
function floorBox(i) {
const h = i === 0 ? BRIDGE_H : FLOOR_H
const top = i === 0 ? TOP0 : TOP0 + BRIDGE_H + 1 + FLOOR_PITCH * (i - 1)
return { top, floorY: top + h, h }
}
// n Räume teilen die Breite gleichmäßig; der letzte nimmt den Rest (4 Räume: 46, 46, 46, 48)
function splitRooms(n) {
const w = Math.floor(ROOM_W / 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 (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)
return f ? { x: ROOM_X0 + dx, y: f.floorY + dy } : null
}
const tresor = at('tresor', 121, -11)
return {
pult: at('freigabe', 93, -15),
tresor,
aussen: tresor && { x: WORLD.w + 4, y: tresor.y - 1 },
archiv: at('keller', 106, -16),
}
}
// Layout aus Rollen und Etagenliste (Standard: das Rollen-Register). Wirft bei unbekanntem Raum oder unbekannter Etage.
export function buildLayout(roles = ROLES, floors = FLOORS) {
for (const r of roles) {
if (!Object.hasOwn(ROOM_META, r.room)) throw new Error(`Unbekannter Raum: ${r.room}`)
if (!floors.includes(r.floor)) throw new Error(`Unbekannte Etage: ${r.floor}`)
}
const homes = {}
const list = floors.map((id, index) => {
const box = floorBox(index)
const entries = roles.filter((r) => r.floor === id).map((r) => ({ id: r.room, workerId: r.workerId }))
for (const room of WORKERLESS[id] ?? []) entries.push({ id: room, workerId: null })
const slots = splitRooms(entries.length)
const rooms = entries.map((e, k) => {
const { kind, team } = ROOM_META[e.id]
return { id: e.id, kind, title: ROOM_TITLES[e.id], team, x: slots[k].x, w: slots[k].w, workerId: e.workerId }
})
for (const room of rooms) {
if (!room.workerId) continue
const otto = room.workerId === 'otto'
const x = room.x + Math.floor((room.w - (otto ? OTTO_W : WORKER_W)) / 2)
homes[room.workerId] = { x, y: box.floorY - (otto ? OTTO_DY : HOME_DY), floor: index, room: room.id }
}
return { id, index, title: FLOOR_TITLES[id] ?? id, top: box.top, floorY: box.floorY, h: box.h, rooms }
})
return { floors: list, homes, spots: buildSpots(list) }
}
// Etagenindex zur Kennung; unbekannt -> -1
export function floorIndex(layout, id) {
return layout.floors.findIndex((f) => f.id === id)
}
// Raum zur Kennung; unbekannt -> null
export function roomById(layout, roomId) {
for (const f of layout.floors) {
const room = f.rooms.find((r) => r.id === roomId)
if (room) return room
}
return null
}
// Heimatplatz des Workers; unbekannte Kennung (auch Prototyp-Namen) -> null
export function homeOf(layout, workerId) {
return typeof workerId === 'string' && Object.hasOwn(layout.homes, workerId) ? layout.homes[workerId] : null
}
// Standhöhe einer Figur auf Etage i (obere Kante des 14 hohen Körpers)
export function fy(layout, i) {
return layout.floors[i].floorY - HOME_DY
}
// Oberkante der Aufzugkabine, wenn sie auf Etage i hält
export function cabTop(layout, i) {
return layout.floors[i].floorY - CAB_H
}