Newer
Older
rpg / apps / game / tools / checks / shadows.mjs
/**
 * Сценарий shadows — тени мира (блобы актёров + направленные тени tall-объектов).
 * Математика sunShadow чистая и покрыта юнит-тестами; здесь проверяем, что
 * тени в игре ползут за солнцем и гаснут ночью — визуально, по скриншотам
 * в ключевые часы (утро/полдень/вечер/ночь).
 * 1) новая игра (8:00): baseline — утренние тени влево;
 * 2) setTime 13: полдень — короткие тени под объектами;
 * 3) setTime 19: вечер — тени вправо;
 * 4) setTime 23: ночь — теней нет;
 * 5) setTime 8 обратно + шаг: сцена жива, время применилось.
 * Запуск: node tools/agent.mjs run tools/checks/shadows.mjs
 */
import { withChecks } from '../lib.mjs';

export default async function ({ pretty }) {
    return withChecks(
        'shadows',
        async (t) => {
            const { c } = t;
            const setTime = async (hours) => {
                const ok = await t.ctx.agent.command('scene:setTime', { hours });
                c.expect(ok === true, `scene:setTime ${hours}h не применился`, ok);
                return ok;
            };
            await c.run('новая игра 8:00: baseline, утренние тени влево', async () => {
                await t.boot();
                // пережидаем fade-переход меню→локация (скриншот в fade тёмен)
                await t.ctx.agent.waitFor('!s.transitioning', { timeoutTicks: 600 });
                // ручные шаги без рендера не обновляют канвас: рисуем кадры явно
                await t.ctx.agent.step(10, { render: true });
                const s = await t.ctx.agent.snapshot();
                c.expect(s.scene === 'location', 'не в локации после boot', s.scene);
                await t.ctx.page.screenshot({ path: '/tmp/rpg_shadow_morning.png' });
                return null;
            });
            await c.run('13:00: полдень, короткие тени', async () => {
                await setTime(13);
                await t.ctx.agent.step(2);
                await t.ctx.page.screenshot({ path: '/tmp/rpg_shadow_noon.png' });
                return null;
            });
            await c.run('19:00: вечер, тени вправо', async () => {
                await setTime(19);
                await t.ctx.agent.step(2);
                await t.ctx.page.screenshot({ path: '/tmp/rpg_shadow_evening.png' });
                return null;
            });
            await c.run('23:00: ночь, теней нет', async () => {
                await setTime(23);
                await t.ctx.agent.step(2);
                await t.ctx.page.screenshot({ path: '/tmp/rpg_shadow_night.png' });
                return null;
            });
            await c.run('возврат к 8:00: время применилось, сцена жива', async () => {
                await setTime(8);
                await t.ctx.agent.step(5);
                const s = await t.ctx.agent.snapshot();
                c.expect(s.scene === 'location', 'сцена не жива после setTime', s.scene);
                return null;
            });
        },
        { pretty }
    );
}