Files
feuerwerk/tests/editor/painted-tilemap.test.ts

121 lines
5.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Which tilemap the painting panel and the scene view's brush work on (#142): exactly one placed
* map, selected in the active scene. Everything else – nothing, two objects, the asset itself, a
* map in a scene that is not showing – leaves nothing to paint.
*/
import { describe, expect, it } from 'vitest';
import { CreateAssetCommand } from '../../src/core/commands/assetCommands';
import { PlaceAssetCommand } from '../../src/core/commands/sceneObjectCommands';
import { createEmptyProject } from '../../src/core/model/Project';
import { chooseTool, holdPick, paintedTilemap, pickTile } from '../../src/editor/panels/TilemapPanel';
import { EditorState, objectSelection } from '../../src/editor/state';
function setup() {
const state = new EditorState();
state.loadProject(createEmptyProject('p', 'P'), 1);
const create = (type: 'tilemap' | 'sprite' | 'scene', name: string) => {
const command = new CreateAssetCommand(type, name);
expect(state.execute(command)).toBe(true);
return command.asset.id;
};
// The first scene there is becomes the active one by itself.
const sceneId = create('scene', 'Main');
expect(state.activeScene?.id).toBe(sceneId);
const place = (holderId: string, assetId: string) => {
const command = new PlaceAssetCommand(holderId, assetId, { x: 0, y: 0 });
expect(state.execute(command)).toBe(true);
return command.objectId;
};
const tilemapId = create('tilemap', 'Ground');
return { state, sceneId, tilemapId, create, place };
}
describe('the painted tilemap', () => {
it('is the one placed map selected in the active scene', () => {
const { state, sceneId, tilemapId, place } = setup();
const map = place(sceneId, tilemapId);
state.select(objectSelection(sceneId, [map]));
expect(paintedTilemap(state)).toMatchObject({ objectId: map, asset: { id: tilemapId } });
});
it('is none without a selection, for another object and for the asset itself', () => {
const { state, sceneId, tilemapId, create, place } = setup();
expect(paintedTilemap(state)).toBeNull();
const sprite = place(sceneId, create('sprite', 'Box'));
state.select(objectSelection(sceneId, [sprite]));
expect(paintedTilemap(state)).toBeNull();
state.select({ kind: 'asset', assetId: tilemapId });
expect(paintedTilemap(state)).toBeNull();
});
it('is none while a second object is selected with it, map or not', () => {
const { state, sceneId, tilemapId, create, place } = setup();
const map = place(sceneId, tilemapId);
const other = place(sceneId, tilemapId);
const sprite = place(sceneId, create('sprite', 'Box'));
state.select(objectSelection(sceneId, [map, other], map));
expect(paintedTilemap(state)).toBeNull();
state.select(objectSelection(sceneId, [map, sprite], map));
expect(paintedTilemap(state)).toBeNull();
state.select(objectSelection(sceneId, [map]));
expect(paintedTilemap(state)?.objectId).toBe(map);
});
it('picks with the Pick tool and hands the tile to the painting tool before it (#133)', () => {
const { state, sceneId, tilemapId, place } = setup();
state.select(objectSelection(sceneId, [place(sceneId, tilemapId)]));
chooseTool(state, 'rect');
chooseTool(state, 'pick');
pickTile(state, 'grass');
expect(state.tilemapPaint).toMatchObject({ tool: 'rect', tileId: 'grass' });
// From a tool that does not paint with a tile, the pick goes to the brush.
chooseTool(state, 'erase');
chooseTool(state, 'pick');
pickTile(state, 'wall');
expect(state.tilemapPaint).toMatchObject({ tool: 'brush', tileId: 'wall' });
});
it('picks while Alt is held and goes back to the tool before it on release', () => {
const { state, sceneId, tilemapId, place } = setup();
state.select(objectSelection(sceneId, [place(sceneId, tilemapId)]));
chooseTool(state, 'fill');
expect(holdPick(state, true)).toBe(true);
expect(state.tilemapPaint.tool).toBe('pick');
pickTile(state, 'grass');
expect(state.tilemapPaint).toMatchObject({ tool: 'pick', tileId: 'grass' });
expect(holdPick(state, false)).toBe(true);
expect(state.tilemapPaint).toMatchObject({ tool: 'fill', tileId: 'grass' });
// Held from Select, too: the release brings Select back.
chooseTool(state, 'select');
holdPick(state, true);
holdPick(state, false);
expect(state.tilemapPaint.tool).toBe('select');
});
it('leaves Alt alone without a map, and a tool chosen while holding it stays', () => {
const { state, sceneId, tilemapId, place } = setup();
expect(holdPick(state, true)).toBe(false);
expect(state.tilemapPaint.tool).toBe('select');
const map = place(sceneId, tilemapId);
state.select(objectSelection(sceneId, [map]));
chooseTool(state, 'brush');
holdPick(state, true);
chooseTool(state, 'rect');
expect(holdPick(state, false)).toBe(false);
expect(state.tilemapPaint.tool).toBe('rect');
// Released after the map was deselected: nothing to paint on, so Select.
holdPick(state, true);
state.select(null);
holdPick(state, false);
expect(state.tilemapPaint.tool).toBe('select');
});
it('is none for a map in a scene that is not the one showing', () => {
const { state, tilemapId, create, place } = setup();
const otherScene = create('scene', 'Elsewhere');
const map = place(otherScene, tilemapId);
state.select(objectSelection(otherScene, [map]));
expect(paintedTilemap(state)).toBeNull();
});
});