/**
* Воксельные пропсы интерактивов (визуал на месте «вьюх» v1): столбы у
* троп, моты (тёплая искра — жизнь!), сундук, записка, прилавок, верёвка
* колокола, резонатор. Штамп строго в тайл 10×10 (урок трека 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 + 4; // центр тайла (10×10)
const bz = def.tile.y * UNIT + 4;
if (def.kind === 'pickup') {
// мот: тёплая искра-столбик (видна издали)
for (let y = 0; y < 3; y++) world.set(bx, GROUND_Y + y, bz, SPARK);
return;
}
if (def.kind === 'signpost') {
for (let y = 0; y < 4; y++) world.set(bx, GROUND_Y + y, bz, WOOD); // столб
for (let dx = -1; dx <= 1; dx++) world.set(bx + dx, GROUND_Y + 4, bz, WOOD_L); // доска
return;
}
if (def.kind === 'container') {
// сундук: деревянный ящик 4×3×3 с металлической крышкой
for (let y = 0; y < 2; y++)
for (let dz = 0; dz < 3; dz++)
for (let dx = 0; dx < 4; dx++) world.set(bx + dx, GROUND_Y + y, bz + dz, WOOD);
for (let dz = 0; dz < 3; dz++)
for (let dx = 0; dx < 4; dx++) world.set(bx + dx, GROUND_Y + 2, bz + dz, METAL);
return;
}
if (def.id === 'note_elder') {
world.set(bx, GROUND_Y, bz, PAPER); // записка: светлый клочок на полу
world.set(bx + 1, GROUND_Y, bz, PAPER);
return;
}
if (def.id === 'bell_rope') {
// верёвка у башни: столбик с деревянной ручкой
for (let y = 0; y < 4; y++) world.set(bx, GROUND_Y + y, bz, METAL);
world.set(bx, GROUND_Y + 4, bz, WOOD);
return;
}
if (def.id === 'clint_resonator') {
// резонатор: медный короб на стальной раме
for (let y = 0; y < 2; y++)
for (let dx = 0; dx < 5; dx++) world.set(bx + dx, GROUND_Y + y, bz, METAL);
for (let y = 2; y < 4; y++)
for (let dx = 0; dx < 4; dx++) world.set(bx + dx, GROUND_Y + y, 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 + 5; y++)
world.set(def.tile.x * UNIT + dx, y, def.tile.y * UNIT + dz, 0);
}