diff options
Diffstat (limited to 'src/engine/entities/FunctionApplication.ts')
-rw-r--r-- | src/engine/entities/FunctionApplication.ts | 180 |
1 files changed, 178 insertions, 2 deletions
diff --git a/src/engine/entities/FunctionApplication.ts b/src/engine/entities/FunctionApplication.ts index 31e3490..24e4eec 100644 --- a/src/engine/entities/FunctionApplication.ts +++ b/src/engine/entities/FunctionApplication.ts @@ -1,7 +1,183 @@ -import { Entity, EntityNames } from "."; +import { + Entity, + EntityNames, + FunctionBox, + Key, + Particles, + makeLambdaTermHighlightComponent, +} from "."; +import { + BoundingBox, + Colliding, + ComponentNames, + Grid, + LambdaTerm, + Sprite, +} from "../components"; +import { + Failure, + IMAGES, + LambdaTransformSound, + SOUNDS, + SPRITE_SPECS, + SpriteSpec, + Sprites, +} from "../config"; +import { Coord2D, Direction } from "../interfaces"; +import { Game } from ".."; +import { Grid as GridSystem, SystemNames } from "../systems"; +import { colors } from "../utils"; +import { + DebrujinifiedLambdaTerm, + SymbolTable, + emitNamed, + interpret, +} from "../../interpreter"; export class FunctionApplication extends Entity { - constructor() { + private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec; + + private symbolTable: SymbolTable; + + constructor(gridPosition: Coord2D, lambdaTerm: string) { super(EntityNames.FunctionApplication); + + this.symbolTable = new SymbolTable(); + this.symbolTable.add("key"); + + const dimension = { + width: FunctionApplication.spriteSpec.width, + height: FunctionApplication.spriteSpec.height, + }; + this.addComponent( + new BoundingBox( + { + x: 0, + y: 0, + }, + dimension, + 0, + ), + ); + + this.addComponent(new Grid(gridPosition)); + + this.addComponent(new LambdaTerm(lambdaTerm)); + + this.addComponent( + new Sprite( + IMAGES.get(FunctionApplication.spriteSpec.sheet)!, + { x: 0, y: 0 }, + dimension, + FunctionApplication.spriteSpec.msPerFrame, + FunctionApplication.spriteSpec.frames, + ), + ); + + this.addComponent(new Colliding(this.handleCollision.bind(this))); + + this.addComponent(makeLambdaTermHighlightComponent(this)); + } + + public handleCollision(game: Game, entity: Entity) { + if (entity.name !== EntityNames.FunctionBox) { + return; + } + + const entityGrid = entity.getComponent<Grid>(ComponentNames.Grid); + if (entityGrid.movingDirection !== Direction.NONE) { + // prevent recursive functionBox -> application creation + return; + } + + const grid = this.getComponent<Grid>(ComponentNames.Grid); + const gridSystem = game.getSystem<GridSystem>(SystemNames.Grid); + const fail = () => { + entityGrid.movingDirection = gridSystem.oppositeDirection( + entityGrid.previousDirection, + ); + entity.addComponent(entityGrid); + + const failureSound = SOUNDS.get(Failure.name)!; + failureSound.play(); + }; + + const applicationTerm = this.getComponent<LambdaTerm>( + ComponentNames.LambdaTerm, + ); + const functionTerm = entity.getComponent<LambdaTerm>( + ComponentNames.LambdaTerm, + ); + const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code); + let result: DebrujinifiedLambdaTerm | null = null; + try { + result = interpret(newCode, this.symbolTable); + } catch (e) { + console.error(e); + fail(); + return; + } + + const { dimension } = gridSystem; + const nextPosition = gridSystem.getNewGridPosition( + grid.gridPosition, + entityGrid.previousDirection, + ); + + let applicationResultingEntity: Entity | null = null; // this should be its own function + if ("abstraction" in result) { + const code = emitNamed(result); + + applicationResultingEntity = new FunctionBox(grid.gridPosition, code); + } else if ("name" in result) { + const { name } = result; + if (name === "key") { + applicationResultingEntity = new Key(grid.gridPosition); + } + } else { + fail(); + return; + } + + game.removeEntity(entity.id); + if (applicationResultingEntity) { + const grid = applicationResultingEntity.getComponent<Grid>( + ComponentNames.Grid, + ); + grid.movingDirection = entityGrid.previousDirection; + applicationResultingEntity.addComponent(grid); + + game.addEntity(applicationResultingEntity); + } + + this.playTransformSound(); + const particles = new Particles({ + center: gridSystem.gridToScreenPosition(nextPosition), + spawnerDimensions: { + width: dimension.width / 2, + height: dimension.height / 2, + }, + particleCount: 10, + spawnerShape: "circle", + particleShape: "circle", + particleMeanSpeed: 0.25, + particleSpeedVariance: 0.15, + particleMeanLife: 150, + particleMeanSize: 2, + particleSizeVariance: 1, + particleLifeVariance: 20, + particleColors: [ + colors.lightAqua, + colors.blue, + colors.green, + colors.lightGreen, + ], + }); + game.addEntity(particles); + } + + private playTransformSound() { + const audio = SOUNDS.get(LambdaTransformSound.name)!; + audio.play(); } } |