/**
* Сценарий big_house — большой дом 2×2 в Звенце (первый проп с footprint):
* 1) коллизия: footprint непроходим, соседний тайл проходим;
* 2) scene:walk в дом — false, approach — к соседу;
* 3) глубина: герой с юга (перед домом) и с севера (за домом) — скриншоты.
* Запуск: node tools/agent.mjs run tools/checks/big_house.mjs
*/
import { withChecks } from '../lib.mjs';
export default async function () {
return withChecks(
'big_house',
async (t) => {
const { c } = t;
await c.run('снапшот: проп дома в collision-слое', async () => {
await t.boot();
await t.sleepEnemies();
await t.goToArea('zvenets', { x: 54, y: 28 });
const s = await t.ctx.agent.snapshot();
// collision-слой снапшота отдаёт пропы без id — ищем по footprint.
const prop = (s.collision.props ?? []).find((p) => p.x === 46 && p.y === 24);
c.expect(!!prop, 'проп (46,24) 2×2 не в collision-слое', s.collision.props);
c.expect(prop && prop.w === 2 && prop.h === 2, 'footprint пропа не 2×2', prop);
const idx = (x, y) => y * s.collision.width + x;
c.expect(
s.collision.blocked[idx(46, 24)] === 1 && s.collision.blocked[idx(47, 25)] === 1,
'клетки footprint пропа не заблокированы'
);
return null;
});
await c.run('scene:walkable: дом непроходим, сосед свободен', async () => {
const walk = (x, y) => t.ctx.agent.command('scene:walkable', { x, y });
c.expect((await walk(46, 24)) === false, 'северо-запад дома проходим');
c.expect((await walk(47, 25)) === false, 'юго-восток дома проходим');
c.expect((await walk(48, 24)) === true, 'тайл восточнее дома заблокирован');
return null;
});
await c.run('scene:walk в дом — false, approach — к соседу', async () => {
await t.ctx.agent.command('scene:teleport', { x: 48, y: 24 });
await t.ctx.agent.waitFor('!s.transitioning', { timeoutTicks: 60 });
const walked = await t.ctx.agent.command('scene:walk', { x: 46, y: 24 });
c.expect(walked === false, 'scene:walk провёл героя в дом', walked);
const dest = await t.ctx.agent.approach(46, 24);
c.expect(dest !== null, 'approach к дому не нашёл соседа');
return null;
});
await c.run('глубина: герой с юга и с севера дома', async () => {
const shot = async (name) => {
await t.ctx.agent.step(2, { render: true });
await t.ctx.page.screenshot({ path: `/tmp/rpg_big_house_${name}.png` });
};
const teleport = async (x, y) => {
await t.ctx.agent.command('scene:teleport', { x, y });
await t.ctx.agent.waitFor('!s.transitioning', { timeoutTicks: 60 });
const s = await t.ctx.agent.snapshot();
c.expect(
s.hero.tile.x === x && s.hero.tile.y === y,
`телепорт в (${x},${y}) не удался`,
s.hero.tile
);
};
// Юг: герой вплотную перед домом — перекрывает его низ.
await teleport(46, 26);
await shot('south');
// Север: дом ближе к камере — перекрывает героя целиком.
await teleport(46, 23);
await shot('north');
return null;
});
const inv = await t.ctx.agent.invariants();
const errs = inv.filter((i) => i.severity === 'error');
c.expect(errs.length === 0, 'инварианты с пропом не чисты', errs);
}
);
}