/**
* Воксельные пропсы интерактивов (визуал на месте «вьюх» v1): столбы у
* троп, моты (тёплая искра — жизнь!), сундук, записка, прилавок, верёвка
* колокола, резонатор. Штамп строго в тайл 5×5 (урок трека 15: вылезать
* на соседей нельзя). clearProp снимает проп и возвращает землю.
*/
import type { VoxelWorld } from '@rpg/engine';
import type { InteractableDef } from './data/interactables';
import { GROUND_Y, UNIT } from './areas';
// Слоты палитры сцены (общие с main.ts)
const WOOD = 4; // R1 — дерево тёмное
const WOOD_L = 8; // R2 — светлое дерево
const METAL = 10; // M1 — металл
const SPARK = 9; // B1 — тёплая искра (жизнь!)
const PAPER = 7; // P6 — свет камня (бумага)
/** Проп существует? (моты — искра; остальное — телеса) */
export function hasProp(def: InteractableDef): boolean {
return def.kind === 'pickup' || def.kind === 'signpost' || def.kind === 'container'
|| def.id === 'bell_rope' || def.id === 'note_elder' || def.id === 'clint_resonator';
}
/** Поставить проп интерактива в его тайл (детерминированно, без ГПСЧ). */
export function stampProp(world: VoxelWorld, def: InteractableDef): void {
if (!hasProp(def)) return;
const bx = def.tile.x * UNIT + 2; // центр тайла
const bz = def.tile.y * UNIT + 2;
if (def.kind === 'pickup') {
// мот: тёплая искра-столбик (видна издали)
world.set(bx, GROUND_Y, bz, SPARK);
world.set(bx, GROUND_Y + 1, bz, SPARK);
return;
}
if (def.kind === 'signpost') {
world.set(bx, GROUND_Y, bz, WOOD); // столб
world.set(bx, GROUND_Y + 1, bz, WOOD);
world.set(bx, GROUND_Y + 2, bz, WOOD_L); // доска
return;
}
if (def.kind === 'container') {
// сундук: деревянный ящик 2×2×2 с металлической кромкой
world.set(bx, GROUND_Y, bz, WOOD);
world.set(bx + 1, GROUND_Y, bz, WOOD);
world.set(bx, GROUND_Y, bz + 1, WOOD);
world.set(bx + 1, GROUND_Y, bz + 1, WOOD);
world.set(bx, GROUND_Y + 1, bz, METAL);
return;
}
if (def.id === 'note_elder') {
world.set(bx, GROUND_Y, bz, PAPER); // записка: светлый клочок на полу
return;
}
if (def.id === 'bell_rope') {
// верёвка у башни: столбик с деревянной ручкой
world.set(bx, GROUND_Y, bz, METAL);
world.set(bx, GROUND_Y + 1, bz, METAL);
world.set(bx, GROUND_Y + 2, bz, WOOD);
return;
}
if (def.id === 'clint_resonator') {
// резонатор: медный короб на стальной раме
world.set(bx, GROUND_Y, bz, METAL);
world.set(bx + 1, GROUND_Y, bz, METAL);
world.set(bx + 2, GROUND_Y, bz, METAL);
world.set(bx, GROUND_Y + 1, bz, WOOD_L);
world.set(bx + 1, GROUND_Y + 1, bz, WOOD_L);
return;
}
}
/** Убрать проп (подбор мота/сундука): снять штамп, вернуть землю. */
export function clearProp(world: VoxelWorld, def: InteractableDef): void {
if (!hasProp(def)) return;
for (let dz = 0; dz < UNIT; dz++)
for (let dx = 0; dx < UNIT; dx++)
for (let y = GROUND_Y; y <= GROUND_Y + 2; y++)
world.set(def.tile.x * UNIT + dx, y, def.tile.y * UNIT + dz, 0);
}