import { Tile } from "./Tile.js";
import { DirectionMap, Directions, framesPerStep, stepDurationInMs } from "./Globals.js";
/**
 * This class draws player-sprite and makes it move.
 */
export class Player extends Tile {
    constructor(mainScene, column, row, level) {
        super(mainScene, column, row, "player", level);
        this.mainScene = mainScene;
        this.column = column;
        this.row = row;
        this.level = level;
        /**
         * To achieve a responsive player we store keyboard-events so that fast players can
         * type ahead of time and we process events with constant speed later.
         *
         * cursorState[direction] is the point in time that the corresponding arrow key has last been evaluated
         */
        this.cursorState = { "up": 0, "down": 0, "left": 0, "right": 0 };
        /**
         * Store keyboard events that need processing later
         */
        this.cursorHistory = [];
        /**
         * Store how much frames to wait until next player-step
         */
        this.framesToWait = framesPerStep;
        this.cursors = this.scene.input.keyboard.createCursorKeys();
        // This makes scene.update call the update-method of this class each 1/60 s.
        // Beware: Don't forget to remove Listener when this object gets destroyed!
        this.scene.events.addListener('update', this.update, this);
    }
    update() {
        let time = performance.now();
        /**
         * Check if state of cursor-keys changed. Store cursor-key-events in queue (cursorHistory).
         */
        for (let direction of Directions) {
            if (this.cursors[direction].isDown) {
                // if key is held down: constant type rate (each stepDurationInMs milliseconds)
                if (time - this.cursorState[direction] > stepDurationInMs) {
                    this.cursorHistory.push(direction);
                    this.cursorState[direction] = time;
                }
            }
            else {
                // if key is up: allow next keydown immediately
                if (this.cursorState[direction]) {
                    this.cursorState[direction] = 0;
                }
            }
        }
        /**
         * Time for next player-step?
         *
         * => Then get next cursorkey-event from event-queue (cursorHistory) and evaluate it.
         *
         * If cursorkey-events don't lead to player movement then don't reset this.framesToWait so
         * that next player-step is considered in 1/60 s. This keeps player-sprite responsive to cursor-events.
         */
        this.framesToWait--;
        if (this.framesToWait <= 0) {
            let moved = false; // set to true if player gets moved.
            while (this.cursorHistory.length > 0 && !moved) {
                let direction = this.cursorHistory.shift(); // shift() returns element with index 0 and removes it from array
                // calculate new position ( = old position "+ direction")
                let newColumn = this.column + DirectionMap[direction].dx;
                let newRow = this.row + DirectionMap[direction].dy;
                /**
                 * We don't need to check if newColumn/newRow is inside array boundaries of
                 * array this.level.tiles as each level is surrounded by an iron wall.
                 */
                let columnList = this.level.tiles[newColumn];
                // fetch tile at player's potentially new position
                let tileAtNewPosition = columnList[newRow];
                if (tileAtNewPosition == null) {
                    moved = true; // empty tile => move player!
                }
                else {
                    switch (tileAtNewPosition.kind) {
                        case "sand":
                            columnList[newRow] = null;
                            moved = true;
                            this.destroyTile(tileAtNewPosition);
                            break;
                        case "gemstone":
                            columnList[newRow] = null;
                            moved = true;
                            let camera = this.scene.cameras.main;
                            let that = this;
                            this.mainScene.getScoreScene()
                                .animatePlayerCollectingGem(tileAtNewPosition.x - camera.scrollX, tileAtNewPosition.y - camera.scrollY, () => {
                                if (that.mainScene.getScoreBoard().gems == 0) {
                                    that.level.door.open();
                                }
                            });
                            tileAtNewPosition.destroy();
                            break;
                        case "doorbottom":
                        case "doortop":
                            moved = true;
                            if (this.level.door.isOpen) {
                                this.mainScene.nextLevel();
                            }
                            return;
                            break;
                        case "enemy1":
                        case "enemy2":
                            this.mainScene.gameOver();
                            return;
                            break;
                    }
                }
                if (moved) {
                    // move player sprite slowly to new position and update tile-Array
                    this.goTo(newColumn, newRow);
                    // reset framesToWait so that player doesn't move too fast:
                    this.framesToWait = framesPerStep;
                }
            }
        }
    }
    /**
     * Slowly fade out tile and destroy it subsequent
     * @param tile
     */
    destroyTile(tile) {
        this.scene.tweens.add({
            targets: tile,
            alpha: 0,
            duration: stepDurationInMs,
            onComplete: () => {
                tile.destroy();
            }
        });
    }
    /**
     * remove event listener and destroy player-object
     * @returns
     */
    destroy() {
        if (this.scene == null)
            return;
        this.scene.events.removeListener('update', this.update);
        super.destroy();
    }
}
//# sourceMappingURL=Player.js.map