puzzlescript
Version:
Play PuzzleScript games in your terminal!
678 lines • 31.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AstBuilder = void 0;
const colors_1 = require("../colors");
const collisionLayer_1 = require("../models/collisionLayer");
const colors_2 = require("../models/colors");
const game_1 = require("../models/game");
const metadata_1 = require("../models/metadata");
const rule_1 = require("../models/rule");
const tile_1 = require("../models/tile");
const winCondition_1 = require("../models/winCondition");
const util_1 = require("../util");
const ast = __importStar(require("./astTypes"));
const RULE_DIRECTION_LIST = [
util_1.RULE_DIRECTION.UP,
util_1.RULE_DIRECTION.DOWN,
util_1.RULE_DIRECTION.LEFT,
util_1.RULE_DIRECTION.RIGHT
];
const RULE_DIRECTION_SET = new Set(RULE_DIRECTION_LIST);
function removeNulls(ary) {
// return ary.filter(a => !!a)
// TypeScript-friendly version
const ret = [];
for (const item of ary) {
if (item) {
ret.push(item);
}
}
return ret;
}
function cacheSetAndGet(cache, obj) {
const key = obj.toKey();
if (!cache.has(key)) {
cache.set(key, obj);
}
return cache.get(key);
}
function relativeDirectionToAbsolute(currentDirection, relativeModifier) {
let currentDir;
switch (currentDirection) {
case util_1.RULE_DIRECTION.RIGHT:
currentDir = 0;
break;
case util_1.RULE_DIRECTION.UP:
currentDir = 1;
break;
case util_1.RULE_DIRECTION.LEFT:
currentDir = 2;
break;
case util_1.RULE_DIRECTION.DOWN:
currentDir = 3;
break;
default:
throw new Error(`BUG! Invalid rule direction "${currentDirection}`);
}
switch (relativeModifier) {
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_RIGHT:
currentDir += 0;
break;
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_UP:
currentDir += 1;
break;
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_LEFT:
currentDir += 2;
break;
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_DOWN:
currentDir += 3;
break;
default:
throw new Error(`BUG! invalid relative direction "${relativeModifier}"`);
}
switch (currentDir % 4) {
case 0:
return util_1.RULE_DIRECTION.RIGHT;
case 1:
return util_1.RULE_DIRECTION.UP;
case 2:
return util_1.RULE_DIRECTION.LEFT;
case 3:
return util_1.RULE_DIRECTION.DOWN;
default:
throw new Error(`BUG! Incorrectly computed rule direction "${currentDirection}" "${relativeModifier}"`);
}
}
class AstBuilder {
constructor(code) {
this.code = code;
this.tileCache = new Map();
this.soundCache = new Map();
}
build(root) {
const source = this.toSource({ _sourceOffset: 0 });
const metadata = new metadata_1.GameMetadata();
root.metadata.forEach((pair) => {
let value;
if (typeof pair.value === 'object' && pair.value.type) {
switch (pair.value.type) {
case ast.COLOR_TYPE.HEX8:
case ast.COLOR_TYPE.HEX6:
case ast.COLOR_TYPE.NAME:
{
const v = pair.value;
value = this.buildColor(v, metadata.colorPalette);
}
break;
case 'WIDTH_AND_HEIGHT':
{
const v = pair.value;
const v2 = v;
value = new metadata_1.Dimension(v2.width, v2.height);
}
break;
default:
throw new Error(`BUG: Invalid type at this point in time: ${pair.value}`);
}
}
else {
value = pair.value;
}
metadata._setValue(pair.type, value);
});
const sprites = root.sprites.map((n) => this.buildSprite(n, metadata.colorPalette));
// assign an index to each GameSprite
sprites.forEach((sprite, index) => {
sprite.allSpritesBitSetIndex = index;
});
// Load the legend items up (used in Rules and Levels later on)
const legendItems = root.legendItems.map((n) => this.buildLegendItem(n));
const sounds = root.sounds.map((n) => this.buildSound(n));
const collisionLayers = root.collisionLayers.map((n) => this.buildCollisionLayer(n));
const simpleRules = this.buildSimpleRules(root.rules);
const winConditions = root.winConditions.map((n) => this.buildWinConditon(n));
const levels = root.levels.map((n) => this.buildLevel(n));
return new game_1.GameData(source, root.title, metadata, sprites, legendItems, sounds, collisionLayers, simpleRules, winConditions, levels);
}
buildSprite(node, colorPalette) {
let ret;
if (node.type === ast.SPRITE_TYPE.WITH_PIXELS) {
const source = this.toSource(node);
const colors = node.colors.map((n) => this.buildColor(n, colorPalette));
const pixels = node.pixels.map((row) => {
return row.map((col) => {
if (col === '.') {
return new colors_2.TransparentColor(source);
}
else {
return colors[col] || new colors_2.TransparentColor(source);
}
});
}); // Pixel colors are 0-indexed.
ret = new tile_1.GameSpritePixels(source, node.name, node.mapChar, pixels);
}
else {
ret = new tile_1.GameSpriteSingleColor(this.toSource(node), node.name, node.mapChar, node.colors.map((n) => this.buildColor(n, colorPalette)));
}
this.cacheAdd(node.name, ret);
if (node.mapChar) {
this.cacheAdd(node.mapChar, ret);
}
return ret;
}
buildColor(node, colorPalette) {
const source = this.toSource(node);
const currentColorPalette = colorPalette || 'arnecolors';
switch (node.type) {
case ast.COLOR_TYPE.HEX8:
case ast.COLOR_TYPE.HEX6:
return new colors_2.HexColor(source, node.value);
case ast.COLOR_TYPE.NAME:
if (node.value.toUpperCase() === 'TRANSPARENT') {
return new colors_2.TransparentColor(source);
}
else {
// Look up the color
const hex = (0, colors_1.lookupColorPalette)(currentColorPalette, node.value);
if (hex) {
return new colors_2.HexColor(source, hex);
}
else {
return new colors_2.TransparentColor(source);
}
}
default:
throw new Error(`Unsupported type ${node}`);
}
}
buildLegendItem(node) {
const source = this.toSource(node);
switch (node.type) {
case ast.TILE_TYPE.SIMPLE:
if (!node.tile) {
throw new Error(`BUG!!!!!!`);
}
{
const ret = new tile_1.GameLegendTileSimple(source, node.name, this.cacheGet(node.tile));
this.cacheAdd(node.name, ret);
return ret;
}
case ast.TILE_TYPE.AND:
if (!node.tiles) {
throw new Error(`BUG!!!!!!`);
}
{
const ret = new tile_1.GameLegendTileAnd(source, node.name, node.tiles.map((n) => this.cacheGet(n)));
this.cacheAdd(node.name, ret);
return ret;
}
case ast.TILE_TYPE.OR:
if (!node.tiles) {
throw new Error(`BUG!!!!!!`);
}
{
const ret = new tile_1.GameLegendTileOr(source, node.name, node.tiles.map((n) => this.cacheGet(n)));
this.cacheAdd(node.name, ret);
return ret;
}
default:
throw new Error(`Unsupported type ${node}`);
}
}
buildCollisionLayer(node) {
const source = this.toSource(node);
return new collisionLayer_1.CollisionLayer(source, node.tiles.map((n) => this.cacheGet(n)));
}
buildSound(node) {
switch (node.type) {
case 'SOUND_SFX':
this.soundCacheAdd(node.soundEffect, node);
return node;
case 'SOUND_WHEN':
return node;
case 'SOUND_SPRITE_MOVE':
case 'SOUND_SPRITE_DIRECTION':
case 'SOUND_SPRITE_EVENT':
return Object.assign(Object.assign({}, node), { sprite: this.cacheGet(node.sprite) });
default:
throw new Error(`Unsupported type ${node}`);
}
}
buildCommand(node) {
switch (node.type) {
case ast.COMMAND_TYPE.SFX:
if (!this.soundCacheHas(node.sound)) {
return null;
}
const sound = this.soundCacheGet(node.sound);
return Object.assign(Object.assign({}, node), { sound });
case ast.COMMAND_TYPE.AGAIN:
case ast.COMMAND_TYPE.CANCEL:
case ast.COMMAND_TYPE.MESSAGE:
case ast.COMMAND_TYPE.CHECKPOINT:
case ast.COMMAND_TYPE.RESTART:
case ast.COMMAND_TYPE.WIN:
return node;
default:
throw new Error(`Unsupported type ${node}`);
}
}
buildWinConditon(node) {
const source = this.toSource(node);
switch (node.type) {
case ast.WIN_CONDITION_TYPE.ON:
return new winCondition_1.WinConditionOn(source, node.qualifier, this.cacheGet(node.tile), this.cacheGet(node.onTile));
case ast.WIN_CONDITION_TYPE.SIMPLE:
return new winCondition_1.WinConditionSimple(source, node.qualifier, this.cacheGet(node.tile));
default:
throw new Error(`Unsupported type ${node}`);
}
}
buildLevel(node) {
switch (node.type) {
case ast.LEVEL_TYPE.MESSAGE:
return node;
case ast.LEVEL_TYPE.MAP:
return Object.assign(Object.assign({}, node), { cells: node.cells.map((row) => row.map((cell) => this.cacheGet(cell))) });
default:
throw new Error(`Unsupported type ${node}`);
}
}
buildSimpleRules(rules) {
// Simplify the rules by de-duplicating them
const ruleCache = new Map();
const bracketCache = new Map();
const neighborCache = new Map();
const tileCache = new Map();
const simpleRules = rules.map((n) => this.simplifyRule(n, ruleCache, bracketCache, neighborCache, tileCache));
return simpleRules;
}
simplifyRule(node, ruleCache, bracketCache, neighborCache, tileCache) {
const source = this.toSource(node);
switch (node.type) {
case ast.RULE_TYPE.LOOP: {
const subRules = node.rules.map((n) => this.simplifyRule(n, ruleCache, bracketCache, neighborCache, tileCache));
return new rule_1.SimpleRuleLoop(source, false /*isRandom*/, subRules);
}
case ast.RULE_TYPE.GROUP:
// Extra checks to make TypeScript happy
if (node.rules[0]) {
const firstRule = node.rules[0];
const isRandom = !!firstRule.isRandom;
const subRules = node.rules.map((n) => this.simplifyRule(n, ruleCache, bracketCache, neighborCache, tileCache));
// if (rules.length === 1) {
// return rules[0]
// }
return new rule_1.SimpleRuleGroup(source, isRandom, subRules);
}
throw new Error(`BUG!!!!!!`);
case ast.RULE_TYPE.SIMPLE: {
/**
* Expands this Rule into multiple `SimpleRule` objects.
*
* For example, `HORIZONTAL [ > player ] -> [ < crate ]` gets expanded to the following `SimpleRule`s:
*
* - `LEFT [ LEFT player ] -> [ RIGHT crate ]`
* - `RIGHT [ RIGHT player ] -> [ LEFT crate ]`
*
* The `SimpleRule`s only have absolute directions
* rather than the relative ones specified in the original game code.
*/
const isRandom = !!node.isRandom;
const conditions = node.conditions;
const actions = node.actions;
// Check if valid
if (conditions.length !== actions.length && actions.length !== 0) {
throw new Error(`Left side has "${conditions.length}" conditions and right side has "${actions.length}" actions!`);
}
if (conditions.length === actions.length) {
// do nothing
}
else if (actions.length !== 0) {
throw new Error(`Invalid Rule. The number of brackets on the right must match the structure of the left hand side or be 0`);
}
const simpleRules = this.rule_convertToMultiple(node).map((r) => this.rule_toSimple(r, ruleCache, bracketCache, neighborCache, tileCache));
// If the brackets are all the same object then that means we can just output 1 rule
// (the brackets don't have any directions. Otherwise they would not have been
// deduplicated as part of the .toKey() and cacheGetAndSet)
const isDuplicate = simpleRules.length === 1 || (!node.isRandom && simpleRules[1] && simpleRules[0].canCollapseBecauseBracketsMatch(simpleRules[1]));
if (isDuplicate) {
simpleRules[0].subscribeToCellChanges();
// we still need it to be in a RuleGroup
// so the Rule can be evaluated multiple times (not just once)
return new rule_1.SimpleRuleGroup(source, isRandom, [simpleRules[0]]);
}
else {
for (const rule of simpleRules) {
rule.subscribeToCellChanges();
}
return new rule_1.SimpleRuleGroup(source, isRandom, simpleRules);
}
}
default:
throw new Error(`Unsupported type ${node}`);
}
}
rule_toSimple(node, ruleCache, bracketCache, neighborCache, tileCache) {
const source = this.toSource(node);
const directions = this.rule_getDirectionModifiers(node);
const commands = removeNulls(node.commands.map((n) => this.buildCommand(n)));
if (directions.length !== 1) {
throw new Error(`BUG: should have exactly 1 direction by now but found the following: "${directions}"`);
}
// Check if the condition matches the action. If so, we can simplify evaluation.
const conditionBrackets = node.conditions.map((x) => this.bracket_toSimple(x, directions[0], ruleCache, bracketCache, neighborCache, tileCache));
const actionBrackets = node.actions.map((x) => this.bracket_toSimple(x, directions[0], ruleCache, bracketCache, neighborCache, tileCache));
for (let index = 0; index < conditionBrackets.length; index++) {
const action = actionBrackets[index];
// Skip rules with no action bracket `[ > Player ] -> CHECKPOINT`
if (!action) {
continue;
}
}
return cacheSetAndGet(ruleCache, new rule_1.SimpleRule(source, conditionBrackets, actionBrackets, commands, node.isLate, node.isRigid, node.debugFlag));
}
rule_convertToMultiple(node) {
let rulesToConvert = [];
let convertedRules = [];
for (const direction of this.rule_getDirectionModifiers(node)) {
const expandedDirection = this.rule_clone(node, direction, null, null);
rulesToConvert.push(expandedDirection);
}
const expandModifiers = new Map();
expandModifiers.set(ast.RULE_MODIFIER.HORIZONTAL, [util_1.RULE_DIRECTION.LEFT, util_1.RULE_DIRECTION.RIGHT]);
expandModifiers.set(ast.RULE_MODIFIER.VERTICAL, [util_1.RULE_DIRECTION.UP, util_1.RULE_DIRECTION.DOWN]);
expandModifiers.set(ast.RULE_MODIFIER.MOVING, [util_1.RULE_DIRECTION.UP, util_1.RULE_DIRECTION.DOWN, util_1.RULE_DIRECTION.LEFT, util_1.RULE_DIRECTION.RIGHT, util_1.RULE_DIRECTION.ACTION]);
let didExpandRulesToConvert;
do {
didExpandRulesToConvert = false;
for (const rule of rulesToConvert) {
let didExpand = false;
const direction = this.rule_getDirectionModifiers(rule)[0];
if (this.rule_getDirectionModifiers(rule).length !== 1) {
throw new Error(`BUG: should have already expanded the rule to only contian one direction`);
}
for (const [nameToExpand, variations] of expandModifiers) {
if (this.rule_hasModifier(rule, nameToExpand)) {
for (const variation of variations) {
convertedRules.push(this.rule_clone(rule, direction, nameToExpand, variation));
didExpand = true;
didExpandRulesToConvert = true;
}
}
}
if (!didExpand) {
// Try expanding PARALLEL and ORTHOGONAL (since they depend on the rule direction)
let perpendiculars;
let parallels;
switch (direction) {
case util_1.RULE_DIRECTION.UP:
case util_1.RULE_DIRECTION.DOWN:
perpendiculars = [util_1.RULE_DIRECTION.LEFT, util_1.RULE_DIRECTION.RIGHT];
parallels = [util_1.RULE_DIRECTION.UP, util_1.RULE_DIRECTION.DOWN];
break;
case util_1.RULE_DIRECTION.LEFT:
case util_1.RULE_DIRECTION.RIGHT:
perpendiculars = [util_1.RULE_DIRECTION.UP, util_1.RULE_DIRECTION.DOWN];
parallels = [util_1.RULE_DIRECTION.LEFT, util_1.RULE_DIRECTION.RIGHT];
break;
default:
throw new Error(`BUG: There must be some direction`);
}
if (perpendiculars && parallels) {
const orthoParallels = [
{ nameToExpand: ast.RULE_MODIFIER.ORTHOGONAL, variations: perpendiculars },
{ nameToExpand: ast.RULE_MODIFIER.PERPENDICULAR, variations: perpendiculars },
{ nameToExpand: ast.RULE_MODIFIER.PARALLEL, variations: parallels }
];
for (const { nameToExpand, variations } of orthoParallels) {
if (this.rule_hasModifier(rule, nameToExpand)) {
for (const variation of variations) {
convertedRules.push(this.rule_clone(rule, direction, nameToExpand, variation));
didExpand = true;
didExpandRulesToConvert = true;
}
}
}
}
}
// If nothing was expanded and this is the current rule
// then just keep it
if (!didExpand) {
convertedRules.push(rule);
}
}
rulesToConvert = convertedRules;
convertedRules = [];
} while (didExpandRulesToConvert);
return rulesToConvert;
}
rule_clone(node, direction, nameToExpand, newName) {
const conditions = node.conditions.map((bracket) => this.bracket_clone(bracket, direction, nameToExpand, newName));
const actions = node.actions.map((bracket) => this.bracket_clone(bracket, direction, nameToExpand, newName));
// retain LATE and RIGID but discard the rest of the modifiers
let directionModifier;
switch (direction) {
case util_1.RULE_DIRECTION.UP:
directionModifier = ast.RULE_MODIFIER.UP;
break;
case util_1.RULE_DIRECTION.DOWN:
directionModifier = ast.RULE_MODIFIER.DOWN;
break;
case util_1.RULE_DIRECTION.LEFT:
directionModifier = ast.RULE_MODIFIER.LEFT;
break;
case util_1.RULE_DIRECTION.RIGHT:
directionModifier = ast.RULE_MODIFIER.RIGHT;
break;
default:
throw new Error(`BUG: Invalid direction "${direction}"`);
}
return Object.assign(Object.assign({}, node), { directions: [directionModifier], conditions, actions });
}
rule_getDirectionModifiers(node) {
// Convert HORIZONTAL and VERTICAL to 2:
if (node.directions.indexOf(ast.RULE_MODIFIER.HORIZONTAL) >= 0) {
return [util_1.RULE_DIRECTION.LEFT, util_1.RULE_DIRECTION.RIGHT];
}
if (node.directions.indexOf(ast.RULE_MODIFIER.VERTICAL) >= 0) {
return [util_1.RULE_DIRECTION.UP, util_1.RULE_DIRECTION.DOWN];
}
const directions = node.directions.filter((m) => RULE_DIRECTION_SET.has(m)).map((d) => {
switch (d) {
case ast.RULE_MODIFIER.UP:
return util_1.RULE_DIRECTION.UP;
case ast.RULE_MODIFIER.DOWN:
return util_1.RULE_DIRECTION.DOWN;
case ast.RULE_MODIFIER.LEFT:
return util_1.RULE_DIRECTION.LEFT;
case ast.RULE_MODIFIER.RIGHT:
return util_1.RULE_DIRECTION.RIGHT;
default:
throw new Error(`BUG: Invalid rule direction "${d}"`);
}
});
if (directions.length === 0) {
return RULE_DIRECTION_LIST;
}
else {
return directions;
}
}
rule_hasModifier(node, modifier) {
for (const bracket of node.conditions) {
for (const neighbor of this.rule_getAllBracketNeighbors(bracket)) {
for (const t of neighbor.tileWithModifiers) {
if (t.direction === modifier) { // HACK: cast to string
return true;
}
}
}
}
return false;
}
rule_getAllBracketNeighbors(node) {
switch (node.type) {
case ast.BRACKET_TYPE.SIMPLE:
return node.neighbors;
case ast.BRACKET_TYPE.ELLIPSIS:
return [...node.beforeNeighbors, ...node.afterNeighbors];
default:
throw new Error(`Unsupported type ${node}`);
}
}
bracket_clone(node, direction, nameToExpand, newName) {
switch (node.type) {
case ast.BRACKET_TYPE.SIMPLE:
const neighbors = node.neighbors.map((n) => this.neighbor_clone(n, direction, nameToExpand, newName));
return Object.assign(Object.assign({}, node), { neighbors });
case ast.BRACKET_TYPE.ELLIPSIS:
const beforeNeighbors = node.beforeNeighbors.map((n) => this.neighbor_clone(n, direction, nameToExpand, newName));
const afterNeighbors = node.afterNeighbors.map((n) => this.neighbor_clone(n, direction, nameToExpand, newName));
return Object.assign(Object.assign({}, node), { beforeNeighbors, afterNeighbors });
default:
throw new Error(`Unsupported type ${node}`);
}
}
neighbor_clone(node, direction, nameToExpand, newName) {
return Object.assign(Object.assign({}, node), { tileWithModifiers: node.tileWithModifiers.map((t) => this.tile_clone(t, direction, nameToExpand, newName)) });
}
tile_clone(node, direction, nameToExpand, newName) {
switch (node.direction) {
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_UP:
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_DOWN:
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_LEFT:
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_RIGHT:
const modifier = relativeDirectionToAbsolute(direction, node.direction);
return Object.assign(Object.assign({}, node), { direction: modifier });
case nameToExpand:
return Object.assign(Object.assign({}, node), { direction: newName });
case util_1.RULE_DIRECTION.UP:
case util_1.RULE_DIRECTION.DOWN:
case util_1.RULE_DIRECTION.LEFT:
case util_1.RULE_DIRECTION.RIGHT:
case util_1.RULE_DIRECTION.ACTION:
case util_1.RULE_DIRECTION.STATIONARY:
case util_1.RULE_DIRECTION.RANDOMDIR:
case null:
case undefined:
return node;
default:
return node; // throw new Error(`BUG: Unsupported tile direction ${JSON.stringify(node)}`)
}
}
bracket_toSimple(node, direction, ruleCache, bracketCache, neighborCache, tileCache) {
const source = this.toSource(node);
switch (node.type) {
case ast.BRACKET_TYPE.SIMPLE:
const neighbors = node.neighbors.map((x) => this.neighbor_toSimple(x, neighborCache, tileCache));
return cacheSetAndGet(bracketCache, new rule_1.SimpleBracket(source, direction, neighbors, node.debugFlag));
case ast.BRACKET_TYPE.ELLIPSIS:
const beforeEllipsis = node.beforeNeighbors.map((x) => this.neighbor_toSimple(x, neighborCache, tileCache));
const afterEllipsis = node.afterNeighbors.map((x) => this.neighbor_toSimple(x, neighborCache, tileCache));
return cacheSetAndGet(bracketCache, new rule_1.SimpleEllipsisBracket(source, direction, beforeEllipsis, afterEllipsis, node.debugFlag));
default:
throw new Error(`Unsupported type ${node}`);
}
}
neighbor_toSimple(node, neighborCache, tileCache) {
const source = this.toSource(node);
// Collapse duplicate tiles into one.
// e.g. Cyber-Lasso has the following rule:
// ... -> [ ElectricFloor Powered no ElectricFloor Claimed ]
//
// ElectricFloor occurs twice (one is negated)
// We keep the first and remove the rest
const tilesMap = new Map();
for (const t of node.tileWithModifiers) {
if (!tilesMap.has(t.tile)) {
tilesMap.set(t.tile, t);
}
}
const tileWithModifiers = [...tilesMap.values()];
const simpleTilesWithModifier = new Set(removeNulls(tileWithModifiers.map((x) => this.tile_toSimple(x, tileCache))));
return cacheSetAndGet(neighborCache, new rule_1.SimpleNeighbor(source, simpleTilesWithModifier, node.debugFlag));
}
tile_toSimple(node, tileCache) {
const source = this.toSource(node);
// Some games mistakenly use SFX# in a bracket when the SFX should be in the commands list after the brackets
if (!this.cacheHas(node.tile)) {
return null;
}
const tile = this.cacheGet(node.tile);
let direction;
switch (node.direction) {
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_UP:
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_DOWN:
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_LEFT:
case util_1.RULE_DIRECTION_RELATIVE.RELATIVE_RIGHT:
throw new Error(`BUG: Relative directions should have been resolved by now`);
default:
direction = node.direction || null; // could be undefined (causes problems when evaluating)
}
return cacheSetAndGet(tileCache, new rule_1.SimpleTileWithModifier(source, node.isNegated, node.isRandom, direction, tile, node.debugFlag));
}
toSource(node) {
return {
code: this.code,
sourceOffset: node._sourceOffset
};
}
cacheHas(name) {
return this.tileCache.has(name.toLowerCase());
}
cacheAdd(name, value) {
if (this.tileCache.has(name.toLowerCase())) {
throw new Error(`BUG??? duplicate definition of ${name}`);
}
this.tileCache.set(name.toLowerCase(), value);
}
cacheGet(name) {
const value = this.tileCache.get(name.toLowerCase());
if (value) {
return value;
}
else {
throw new Error(`BUG: Could not find tile named ${name}`);
}
}
soundCacheAdd(name, value) {
if (this.soundCache.has(name.toLowerCase())) {
throw new Error(`BUG??? duplicate definition of ${name}`);
}
this.soundCache.set(name.toLowerCase(), value);
}
soundCacheGet(name) {
const value = this.soundCache.get(name.toLowerCase());
if (value) {
return value;
}
else {
throw new Error(`BUG: Could not find sound named ${name}`);
}
}
soundCacheHas(name) {
return this.soundCache.has(name.toLowerCase());
}
}
exports.AstBuilder = AstBuilder;
//# sourceMappingURL=astBuilder.js.map