API Docs for:
Show:

File: src/game.js

(function(root) {
    'use strict';

    /**
    * Container for all game objects.
    * Handles updating the state of game objects each turn.
    * Listens for player input to trigger and resolve new turns.
    * @class Game
    * @constructor
    */
    var Game = function Game() {

        // un-populated instance of Array2d
        this.map = new RL.Map(this);
        this.entityManager = new RL.ObjectManager(this, RL.Entity);
        this.renderer = new RL.Renderer(this);
        this.console = new RL.Console(this);
        this.lighting = new RL.LightingROT(this);

        // player purposefully not added to entity manager (matter of preference)
        this.player = new RL.Player(this);

        // make sure "this" is this instance of Game when this.onKeyAction is called
        this.onKeyAction = this.onKeyAction.bind(this);
        this.onClick = this.onClick.bind(this);
        this.onHover = this.onHover.bind(this);

        this.input = new RL.Input(this.onKeyAction);
        this.mouse = new RL.Mouse(this.onClick, this.onHover);

        var el = this.renderer.canvas;
        this.mouse.startListening(el);
    };

    Game.prototype = {
        constructor: Game,

        /**
        * The current map.
        * @property map
        * @type Array2d
        */
        map: null,

        /**
        * The current entityManager.
        * @property entityManager
        * @type EntityManager
        */
        entityManager: null,

        /**
        * The current Lighting.
        * @property lighting
        * @type Lighting
        */
        lighting: null,

        /**
        * The current renderer.
        * @property renderer
        * @type Renderer
        */
        renderer: null,

        /**
        * The current console.
        * @property console
        * @type Console
        */
        console: null,

        /**
        * The current player.
        * @property player
        * @type Player
        */
        player: null,

        /**
        * The current input.
        * @property input
        * @type Input
        */
        input: null,

        /**
        * The current mouse.
        * @property mouse
        * @type Mouse
        */
        mouse: null,

        /**
        * If true input actions are ignored.
        * @property gameOver
        * @type {Bool}
        */
        gameOver: false,

        /**
         * If true the map will be drawn even if `this.player.update(action)` returns false.
         * `this.queueDraw` is set to false after every update.
         * @property queueDraw
         * @type {Boolean}
         */
        queueDraw: false,

        /**
        * Sets the size of the map resizing this.map and this.entityManager.
        * @method setMapSize
        * @param {Number} width - Width in tilse to set map and entityManager to.
        * @param {Number} height - Height in tilse to set map and entityManager to.
        */
        setMapSize: function(width, height){
            this.map.setSize(width, height);
            this.player.fov.setSize(width, height);
            this.entityManager.setSize(width, height);
            this.lighting.setSize(width, height);
        },

        /**
        * Starts the game.
        * @method start
        */
        start: function() {
            // set player position (player is not added to the enitity manager)
            this.entityManager.add(this.player.x, this.player.y, this.player);
            this.player.updateFov();
            this.lighting.update();
            this.renderer.setCenter(this.player.x, this.player.y);
            this.renderer.draw();
        },

        /**
        * Handles user input actions.
        * @method onKeyAction
        * @param {String} action - Action triggered by user input.
        */
        onKeyAction: function(action) {
            if(!this.gameOver){
                var result = this.player.update(action);
                if(result){

                    this.entityManager.update(this.player);
                    this.player.updateFov();

                    this.lighting.update();
                    this.renderer.setCenter(this.player.x, this.player.y);
                    this.renderer.draw();

                } else if(this.queueDraw){
                    this.renderer.draw();
                }
            }
            this.queueDraw = false;
        },

        /**
        * Handles tile mouse click events.
        * @method onClick
        * @param {Number} x - Mouse x coord relative to window.
        * @param {Number} y - Mouse y coord relative to window.
        */
        onClick: function(x, y){
            var coords = this.renderer.mouseToTileCoords(x, y),
                tile = this.map.get(coords.x, coords.y);
            if(!tile){
                return;
            }
            var entityTile = this.entityManager.get(tile.x, tile.y);
            if(entityTile){
                this.console.log('Looks like a <strong>' + entityTile.name + '</strong> standing on a <strong>' + tile.name + '</strong> to me.');
            }
            else{
                this.console.log('Looks like a <strong>' + tile.name + '</strong> to me.');
            }
        },

        /**
        * Handles tile mouse hover events
        * @method onHover
        * @param {Number} x - Mouse x coord relative to window.
        * @param {Number} y - Mouse y coord relative to window.
        */
        onHover: function(x, y){
            var coords = this.renderer.mouseToTileCoords(x, y),
                tile = this.map.get(coords.x, coords.y);
            if(tile){
                this.renderer.hoveredTileX = tile.x;
                this.renderer.hoveredTileY = tile.y;
            } else {
                this.renderer.hoveredTileX = null;
                this.renderer.hoveredTileY = null;
            }
            this.renderer.draw();
        },

        /**
         * Gets all objects at tile position
         * @method getObjectsAtPostion
         * @param  {Number} x
         * @param  {Number} y
         * @return {Array}
         */
        getObjectsAtPostion: function(x, y){
            var result = [];

            var entity = this.entityManager.get(x, y);
            if(entity){
                result.push(entity);
            }

            // add items or any other objects that can be placed at a tile coord position

            return result;
        },

        /**
        * Checks if an entity can move through a map tile.
        * This does NOT check for entities on the tile blocking movement.
        * This is where code for special cases changing an entity's ability to pass through a tile should be placed.
        * Things like flying, swimming and ghosts moving through walls.
        * @method entityCanMoveThrough
        * @param {Entity} entity - The entity to check.
        * @param {Number} x - The x map tile coord to check.
        * @param {Number} y - The y map tile coord to check.
        * @return {Bool}
        */
        entityCanMoveThrough: function(entity, x, y){
            var tile = this.map.get(x, y);
            // if tile blocks movement
            if(!tile || !tile.passable){
                return false;
            }
            return true;
        },

        /**
        * Checks if an entity can move through and into a map tile and that tile is un-occupied.
        * @method entityCanMoveTo
        * @param {Entity} entity - The entity to check.
        * @param {Number} x - The x map tile coord to check.
        * @param {Number} y - The y map tile coord to check.
        * @return {Bool}
        */
        entityCanMoveTo: function(entity, x, y){
            if(!this.entityCanMoveThrough(entity, x, y)){
                return false;
            }
            // check if occupied by entity
            if(this.entityManager.get(x, y)){
                return false;
            }
            return true;
        },

        /**
        * Changes the position of an entity on the map.
        * Updates entity position in this.entityManager and calls tile.onEntityEnter.
        * `this.entityCanMoveTo()` should always be checked first.
        * @method entityMoveTo
        * @param {Entity} entity - The entity to move.
        * @param {Number} x - The tile map x coord to move to.
        * @param {Number} y - The tile map y coord to move to.
        */
        entityMoveTo: function(entity, x, y){
            this.entityManager.move(x, y, entity);
            var tile = this.map.get(x, y);
            if(tile){
                tile.onEntityEnter(entity);
            }
        },

        /**
        * Checks if a map tile can be seen through.
        * This is where code for special cases like smoke, fog, x-ray vision can be implemented by checking the entity param.
        * @method entityCanSeeThrough
        * @param {Number} x - The x map tile coord to check.
        * @param {Number} y - The y map tile coord to check.
        * @return {Bool}
        */
        entityCanSeeThrough: function(entity, x, y){
            var tile = this.map.get(x, y);
            return tile && !tile.blocksLos;
        },

    };

    root.RL.Game = Game;

}(this));