UNPKG

puzzlescript

Version:

Play PuzzleScript games in your terminal!

905 lines (715 loc) 19 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-env jasmine */ const engine_1 = require("./engine"); const parser_1 = __importDefault(require("./parser/parser")); const util_1 = require("./util"); function parseEngine(code) { const { data } = parser_1.default.parse(code); const engine = new engine_1.LevelEngine(data); engine.setLevel(0); return { engine, data }; } describe('Directions', () => { beforeEach(() => { (0, util_1.clearRandomValuesForTesting)(); }); it('"randomly" generates integers', () => { expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(3); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(3); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(3); expect((0, util_1.nextRandom)(4)).toBe(3); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(0); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(0); expect((0, util_1.nextRandom)(4)).toBe(3); expect((0, util_1.nextRandom)(4)).toBe(3); expect((0, util_1.nextRandom)(4)).toBe(0); expect((0, util_1.nextRandom)(4)).toBe(0); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(0); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(0); expect((0, util_1.nextRandom)(4)).toBe(2); expect((0, util_1.nextRandom)(4)).toBe(1); expect((0, util_1.nextRandom)(4)).toBe(1); }); it('Marks a sprite when it wants to move', () => { const { engine, data } = parseEngine(` title foo realtime_interval .01 ======== OBJECTS ======== Background green Player blue ======= LEGEND ======= . = Background P = Player ================ COLLISIONLAYERS ================ Background Player === RULES === RIGHT [ Player ] -> [ > Player ] ======= LEVELS ======= P. `); const player = data.getSpriteByName('player'); const { changedCells } = engine.tickUpdateCells(); expect(engine.toSnapshot()).toMatchSnapshot(); // Once these sprites actually move, we neet to separate engine.tick() into multiple steps: // 1. Update all the cells with new sprites and the wantsToMove directions // 2. Move all the sprites that want to move // 3. Late: Update all the cells with new sprites ... // 4. Late: Move all the sprites that want to move // next tick for all the AGAIN rules expect(engine.getCurrentLevel().getCells()[0][0].getWantsToMove(player)).toBe('RIGHT'); // Ensure only 1 cell was marked for update expect(changedCells.size).toBe(1); }); it('Moves the sprite', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green Player blue ======= LEGEND ======= . = Background P = Player ================ COLLISIONLAYERS ================ Background Player === RULES === RIGHT [ Player ] -> [ > Player ] ======= LEVELS ======= P. `); const { changedCells } = engine.tick(); // expect(engine.toSnapshot()).toMatchSnapshot() const player = data.getSpriteByName('player'); expect(engine.getCurrentLevel().getCells()[0][1].getSpritesAsSet().has(player)).toBe(true); // Ensure both cells were marked for re-rendering expect(changedCells.size).toBe(2); expect(changedCells).toContain(engine.getCurrentLevel().getCells()[0][0]); expect(changedCells).toContain(engine.getCurrentLevel().getCells()[0][1]); }); it('Does not move the sprite if it collides with a sprite in another cell (same collisionlayer)', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green Player blue Wall brown ======= LEGEND ======= . = Background P = Player W = Wall ================ COLLISIONLAYERS ================ Background Player, Wall === RULES === RIGHT [ Player ] -> [ > Player ] ======= LEVELS ======= PW `); engine.tick(); // expect(engine.toSnapshot()).toMatchSnapshot() const player = data.getSpriteByName('player'); expect(engine.getCurrentLevel().getCells()[0][1].getSpritesAsSet().has(player)).toBe(false); expect(engine.getCurrentLevel().getCells()[0][0].getSpritesAsSet().has(player)).toBe(true); // Make sure the wantsToMove flag is cleared expect(engine.getCurrentLevel().getCells()[0][0].getWantsToMove(player)).toBe('STATIONARY'); // nothing actually changed visually // expect(changedCells.size).toBe(0) }); it('Does not move the sprite when ACTION is added to it', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green Player blue ======= LEGEND ======= . = Background P = Player ================ COLLISIONLAYERS ================ Background Player === RULES === [ Player ] -> [ ACTION Player ] ======= LEVELS ======= P. `); engine.tick(); // expect(engine.toSnapshot()).toMatchSnapshot() const player = data.getSpriteByName('player'); expect(engine.getCurrentLevel().getCells()[0][0].getSpritesAsSet().has(player)).toBe(true); // Make sure the wantsToMove flag is cleared expect(engine.getCurrentLevel().getCells()[0][0].getWantsToMove(player)).toBe('STATIONARY'); // nothing actually changed visually // expect(changedCells.size).toBe(0) }); it('Randomly decides whether to add the sprite using "RANDOM" in a bracket', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green Player blue one white black 00000 00000 00100 00000 00000 two white black 00000 01000 00000 00010 00000 three white black 00000 01000 00100 00010 00000 ======= LEGEND ======= . = Background P = Player DieSide = one OR two OR three ================ COLLISIONLAYERS ================ Background Player DieSide === RULES === (set direction so it is only evaluated once) LEFT [ Background NO DieSide ] -> [ Background RANDOM DieSide ] ======= LEVELS ======= P. `); (0, util_1.setRandomValuesForTesting)([0, 1]); engine.tick(); expect((0, util_1.getRandomSeed)()).toBe(2 + 1); // Add one because the background sprite was added to the level? (weird) // expect(engine.toSnapshot()).toMatchSnapshot() const two = data.getSpriteByName('two'); const three = data.getSpriteByName('three'); // Check that one popped up (because we set the "random" values above) // Because the OR is stuck into a set, rather than a list, the 1st item is "three", not "one" const threeCells = [...three.getCellsThatMatch()]; expect(threeCells.length).toBe(1); expect(engine.getCurrentLevel().getCells()[0][1].getSpritesAsSet().has(two /*three*/)).toBe(true); }); it('Moves the sprite in a "random" direction using "RANDOMDIR" in a bracket', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green Player blue ======= LEGEND ======= . = Background P = Player ================ COLLISIONLAYERS ================ Background Player === RULES === RIGHT [ Player ] -> [ RANDOMDIR Player ] ======= LEVELS ======= ..... ..... ..P.. ..... ..... `); (0, util_1.setRandomValuesForTesting)([2, 1]); const { changedCells } = engine.tick(); // expect(engine.toSnapshot()).toMatchSnapshot() const player = data.getSpriteByName('player'); expect(engine.getCurrentLevel().getCells()[2][2].getSpritesAsSet().has(player)).toBe(false); // Check that the player is around thir previous location let playerCells = [...player.getCellsThatMatch()]; let playerCell = playerCells[0]; expect(playerCells.length).toBe(1); expect(engine.getCurrentLevel().getCells()[playerCell.rowIndex][playerCell.colIndex].getSpritesAsSet().has(player)).toBe(true); // Ensure 2 cells were marked for re-rendering expect(changedCells.size).toBe(2); expect(changedCells).toContain(engine.getCurrentLevel().getCells()[2][2]); expect(changedCells).toContain(engine.getCurrentLevel().getCells()[playerCell.rowIndex][playerCell.colIndex]); engine.tick(); // Check that the player is no longer in the spot they were expect(engine.getCurrentLevel().getCells()[playerCell.rowIndex][playerCell.colIndex].getSpritesAsSet().has(player)).toBe(false); // Check that the player is around thir previous location playerCells = [...player.getCellsThatMatch()]; playerCell = playerCells[0]; expect(playerCells.length).toBe(1); expect(engine.getCurrentLevel().getCells()[playerCell.rowIndex][playerCell.colIndex].getSpritesAsSet().has(player)).toBe(true); }); it('supports STATIONARY modifier (simple)', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== background green player blue incorrect red ======= LEGEND ======= . = Background P = player ================ COLLISIONLAYERS ================ Background player incorrect === RULES === RIGHT [ player ] -> [ > player ] [ STATIONARY player ] -> [ incorrect ] ======= LEVELS ======= P. `); const player = data.getSpriteByName('player'); const incorrect = data.getSpriteByName('incorrect'); engine.tick(); const playerCells = [...player.getCellsThatMatch()]; const playerCell = playerCells[0]; const incorrectCells = [...incorrect.getCellsThatMatch()]; expect(incorrectCells.length).toBe(0); expect(playerCells.length).toBe(1); expect(playerCell.rowIndex).toBe(0); expect(playerCell.colIndex).toBe(1); }); it('supports STATIONARY modifier with other sprites that are added', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green player blue cooldown transparent ======= LEGEND ======= . = Background P = player ================ COLLISIONLAYERS ================ Background player cooldown === RULES === RIGHT [ STATIONARY player NO cooldown ] -> [ > player > cooldown ] ======= LEVELS ======= ... .P. ... `); const player = data.getSpriteByName('player'); const cooldown = data.getSpriteByName('cooldown'); engine.tick(); const playerCells = [...player.getCellsThatMatch()]; const playerCell = playerCells[0]; expect(player.getCellsThatMatch().size).toBe(1); expect(playerCell.rowIndex).toBe(1); expect(playerCell.colIndex).toBe(2); // Check that there REALLY is only 1 Player sprite expect(engine.getCurrentLevel().getCells()[0][1].getSpritesAsSet().has(player)).toBe(false); expect(engine.getCurrentLevel().getCells()[1][0].getSpritesAsSet().has(player)).toBe(false); expect(engine.getCurrentLevel().getCells()[2][1].getSpritesAsSet().has(player)).toBe(false); // Check that the cooldown sprite was also added expect(engine.getCurrentLevel().getCells()[1][2].getSpritesAsSet().has(cooldown)).toBe(true); }); it('supports setting STATIONARY so sprites do not move', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green player blue ======= LEGEND ======= . = Background P = player ================ COLLISIONLAYERS ================ Background player === RULES === RIGHT [ STATIONARY player ] -> [ > player ] [ > player ] -> [ STATIONARY player ] ======= LEVELS ======= P. `); const player = data.getSpriteByName('player'); engine.tick(); const playerCells = [...player.getCellsThatMatch()]; const playerCell = playerCells[0]; expect(player.getCellsThatMatch().size).toBe(1); expect(playerCell.rowIndex).toBe(0); expect(playerCell.colIndex).toBe(0); // Check that there REALLY is only 1 Player sprite expect(engine.getCurrentLevel().getCells()[0][0].getSpritesAsSet().has(player)).toBe(true); expect(engine.getCurrentLevel().getCells()[0][1].getSpritesAsSet().has(player)).toBe(false); }); it('puts a top hat on the player (beam islands)', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green player yellow playertop yellow ======= LEGEND ======= . = Background P = player ================ COLLISIONLAYERS ================ Background player playertop === RULES === UP [ player | ] -> [ player | playertop ] ======= LEVELS ======= . P `); const playerTop = data.getSpriteByName('playertop'); engine.tick(); const playerTopCells = [...playerTop.getCellsThatMatch()]; const playerTopCell = playerTopCells[0]; expect(playerTop.getCellsThatMatch().size).toBe(1); expect(playerTopCell.rowIndex).toBe(0); expect(playerTopCell.colIndex).toBe(0); // Check that there REALLY is only 1 Player sprite expect(engine.getCurrentLevel().getCells()[0][0].getSpritesAsSet().has(playerTop)).toBe(true); }); it('Supports trivial tile negation', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green player yellow culprit transparent wrong transparent correct transparent ======= LEGEND ======= . = Background Z = culprit ================ COLLISIONLAYERS ================ Background player culprit wrong correct === RULES === [ NO culprit ] -> [ wrong ] [ NO player ] -> [ correct ] ======= LEVELS ======= Z `); const wrong = data.getSpriteByName('wrong'); const correct = data.getSpriteByName('correct'); engine.tick(); expect(wrong.getCellsThatMatch().size).toBe(0); expect(correct.getCellsThatMatch().size).toBe(1); }); it('Supports tile negation (slightly more complicated)', () => { const { engine, data } = parseEngine(` title foo ========= OBJECTS ========= Background blue Player #f7e26b #000000 01010 .000. .0.0. ..... ..... temp E Transparent yellow ....1 ....1 ....1 ....1 ....1 wrong Transparent red 1...1 .1.1. ..1.. .1.1. 1...1 ======== LEGEND ======== @ = Player . = background ======== SOUNDS ======== ================= COLLISIONLAYERS ================= Background temp wrong Player ======= RULES ======= ( Preparation ) [ Player ] -> [ temp ] (This rule is the culprit) RIGHT [ NO temp ] -> [ wrong ] =============== WINCONDITIONS =============== ======== LEVELS ======== @ `); const wrong = data.getSpriteByName('wrong'); engine.tick(); expect(wrong.getCellsThatMatch().size).toBe(0); }); it('Uses the absolute direction when moving a sprite, not the relative one in the rule (e.g. "[ < player ]" )', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background green Player blue ======= LEGEND ======= . = Background P = Player ================ COLLISIONLAYERS ================ Background Player === RULES === LEFT [ Player ] -> [ ^ Player ] ======= LEVELS ======= P . `); const { changedCells } = engine.tickUpdateCells(); // expect(engine.toSnapshot()).toMatchSnapshot() const player = data.getSpriteByName('player'); expect(engine.getCurrentLevel().getCells()[1][0].getSpritesAsSet().has(player)).toBe(false); // Check that the player is around thir previous location let playerCells = [...player.getCellsThatMatch()]; expect(playerCells.length).toBe(1); expect(engine.getCurrentLevel().getCells()[0][0].getSpritesAsSet().has(player)).toBe(true); expect(engine.getCurrentLevel().getCells()[0][0].getWantsToMove(player)).toBe('DOWN'); engine.tickMoveSprites(changedCells); // Check that the player is no longer in the spot they were playerCells = [...player.getCellsThatMatch()]; expect(playerCells.length).toBe(1); expect(engine.getCurrentLevel().getCells()[1][0].getSpritesAsSet().has(player)).toBe(true); }); it('removes the match when an OR tile loses its direction', () => { const { engine, data } = parseEngine(` title foo ======== OBJECTS ======== Background gray Player yellow Crate brown Wrong red ======= LEGEND ======= . = Background X = Player AND Crate Movable = Player OR Crate ================ COLLISIONLAYERS ================ Background Player Crate Wrong === RULES === RIGHT [ Player ] -> [ > Player ] RIGHT [ > Player ] -> [ Player ] (remove the wantsToMove on the Player. The next rule should no longer match ) RIGHT [ > Movable ] -> [ Wrong ] ======= LEVELS ======= X. `); engine.tick(); // expect(engine.toSnapshot()).toMatchSnapshot() const wrong = data.getSpriteByName('Wrong'); expect(engine.getCurrentLevel().getCells()[0][0].getSpritesAsSet().has(wrong)).toBe(false); expect(wrong.getCellsThatMatch().size).toBe(0); }); }); //# sourceMappingURL=directions.spec.js.map