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