jshint integration and error fixes
commit
3c2790791d
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"eqeqeq": true,
|
||||
"esnext": true,
|
||||
"forin": true,
|
||||
"freeze": true,
|
||||
"futurehostile": true,
|
||||
"latedef": true,
|
||||
"laxbreak": true,
|
||||
"maxcomplexity": 100,
|
||||
"maxdepth": 3,
|
||||
"maxparams": 5,
|
||||
"noarg": true,
|
||||
"nocomma": true,
|
||||
"node": true,
|
||||
"nonbsp": true,
|
||||
"nonew": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"varstmt": true
|
||||
}
|
|
@ -31,10 +31,16 @@ modindex: $(nsindex)
|
|||
|
||||
standalone: lasertank.js
|
||||
lasertank.js: modindex
|
||||
./node_modules/.bin/browserify -s lasertank --debug src/index.js > "$@"
|
||||
./node_modules/.bin/browserify \
|
||||
-t strictify \
|
||||
-s lasertank \
|
||||
--debug \
|
||||
src/index.js \
|
||||
> "$@"
|
||||
|
||||
test: check
|
||||
check:
|
||||
jshint src/ scripts/
|
||||
@PATH="$(PATH):$(CURDIR)/node_modules/mocha/bin" \
|
||||
mocha --recursive $(TESTARGS)
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
"devDependencies": {
|
||||
"chai": ">=1.9.1",
|
||||
"mocha": ">=1.18.2",
|
||||
"browserify": "~12"
|
||||
"browserify": "~12",
|
||||
"strictify": "~0.2"
|
||||
},
|
||||
|
||||
"licenses": [
|
||||
|
|
|
@ -17,21 +17,30 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
( function()
|
||||
{
|
||||
/* jshint browser:true */
|
||||
/* global lasertank */
|
||||
|
||||
var load_ltg = lasertank.FileLoader( document.getElementById( 'ltg' ) ),
|
||||
load_lvl = lasertank.FileLoader( document.getElementById( 'lvl' ) ),
|
||||
const ltg_input = document.getElementById( 'ltg' ),
|
||||
lvl_input = document.getElementById( 'lvl' ),
|
||||
|
||||
menu_bar = lasertank.ui.MenuBar( document.getElementById( 'menubar' ) ),
|
||||
load_ltg = lasertank.FileLoader( ltg_input, new window.FileReader() ),
|
||||
load_lvl = lasertank.FileLoader( lvl_input, new window.FileReader() ),
|
||||
|
||||
ele_game = document.getElementById( 'game' ),
|
||||
ctx = document.getElementById( 'render' ).getContext( '2d' ),
|
||||
ctx = document.getElementById( 'render' ).getContext( '2d' );
|
||||
|
||||
ltg_data = '',
|
||||
let ltg_data = '',
|
||||
lvl_data = '';
|
||||
|
||||
|
||||
// XXX: relies on side-effects of ctor
|
||||
lasertank.ui.MenuBar( document.getElementById( 'menubar' ) );
|
||||
|
||||
|
||||
load_ltg.onLoad( function( e, data )
|
||||
{
|
||||
if ( e ) throw e;
|
||||
|
@ -40,6 +49,7 @@ load_ltg.onLoad( function( e, data )
|
|||
gamechk();
|
||||
} );
|
||||
|
||||
|
||||
load_lvl.onLoad( function( e, data )
|
||||
{
|
||||
if ( e ) throw e;
|
||||
|
@ -48,6 +58,7 @@ load_lvl.onLoad( function( e, data )
|
|||
gamechk();
|
||||
} );
|
||||
|
||||
|
||||
function gamechk()
|
||||
{
|
||||
if ( !( ltg_data && lvl_data ) ) return;
|
||||
|
@ -55,13 +66,14 @@ function gamechk()
|
|||
// temporary
|
||||
if ( ele_game.className.search( 'opening' ) > -1 ) return;
|
||||
|
||||
lasertank.ClassicGame( ltg_data, lvl_data )
|
||||
lasertank.ClassicGame( document, ltg_data, lvl_data )
|
||||
.on( 'ready', function()
|
||||
{
|
||||
this.renderTo( ctx );
|
||||
this.renderTo( ctx, window );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
// temporary
|
||||
document.getElementById( 'new' ).onclick = function()
|
||||
{
|
||||
|
|
|
@ -17,5 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* jshint browser:true */
|
||||
|
||||
// alert the user on all uncaught errors
|
||||
window.onerror = alert;
|
||||
window.onerror = window.alert;
|
||||
|
|
|
@ -18,18 +18,19 @@
|
|||
*/
|
||||
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
const Class = require( 'easejs' ).Class,
|
||||
Game = require( './Game' ),
|
||||
ClassicGameObjectFactory = require( './ClassicGameObjectFactory' ),
|
||||
ClassicMap = require( './ClassicMap' ),
|
||||
ClassicTileDfn = require( './ClassicTileDfn' ),
|
||||
LtgLoader = require( './LtgLoader' ),
|
||||
MapBounds = require( './MapBounds' ),
|
||||
MapRender = require( './MapRender' ),
|
||||
MapSet = require( './MapSet' ),
|
||||
MapState = require( './MapState' ),
|
||||
ClassicLevel = require( './level/ClassicLevel' ),
|
||||
LevelBounds = require( './level/LevelBounds' ),
|
||||
LevelRender = require( './level/LevelRender' ),
|
||||
LevelSet = require( './level/LevelSet' ),
|
||||
LevelState = require( './level/LevelState' ),
|
||||
TileMasker = require( './TileMasker' );
|
||||
|
||||
|
||||
/**
|
||||
* Facade for the classic (original) game of LaserTank
|
||||
*/
|
||||
|
@ -56,10 +57,10 @@ module.exports = Class( 'ClassicGame' )
|
|||
'private _tileSet': null,
|
||||
|
||||
/**
|
||||
* Set of available maps
|
||||
* @type {MapSet}
|
||||
* Set of available levels
|
||||
* @type {LevelSet}
|
||||
*/
|
||||
'private _mapSet': null,
|
||||
'private _levelSet': null,
|
||||
|
||||
/**
|
||||
* Event handlers
|
||||
|
@ -68,8 +69,8 @@ module.exports = Class( 'ClassicGame' )
|
|||
'private _callback': {},
|
||||
|
||||
/**
|
||||
* Performs map rendering
|
||||
* @type {MapRender}
|
||||
* Performs level rendering
|
||||
* @type {LevelRender}
|
||||
*/
|
||||
'private _render': null,
|
||||
|
||||
|
@ -83,26 +84,31 @@ module.exports = Class( 'ClassicGame' )
|
|||
/**
|
||||
* Initialize game with LTG and LVL data
|
||||
*
|
||||
* The LTG and LVL data can be changed at any time, but are required in the
|
||||
* constructor because they are needed in order for the game to be
|
||||
* The LTG and LVL data can be changed at any time, but are required in
|
||||
* the constructor because they are needed in order for the game to be
|
||||
* functional.
|
||||
*
|
||||
* DOCUMENT is used internally for creating elements; the DOM will not
|
||||
* be manipulated.
|
||||
*
|
||||
* @param {HTMLDocument} document DOM document
|
||||
*
|
||||
* @param {string} ltg_data binary string containing LTG file data
|
||||
* @param {string} lvl_data binary string containing LVL file data
|
||||
*/
|
||||
__construct: function( ltg_data, lvl_data )
|
||||
__construct: function( document, ltg_data, lvl_data )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
this._ltgLoader = LtgLoader();
|
||||
this._masker = TileMasker( ClassicTileDfn() );
|
||||
this._masker = TileMasker( ClassicTileDfn(), document );
|
||||
|
||||
this._gameObjFactory = ClassicGameObjectFactory();
|
||||
|
||||
// load initial tile and map data from the LTG and LVL data
|
||||
// load initial tile and level data from the LTG and LVL data
|
||||
this.setTileData( ltg_data, function()
|
||||
{
|
||||
this.setMapData( lvl_data, function()
|
||||
this.setLevelData( lvl_data, function()
|
||||
{
|
||||
_self._trigger( 'ready' );
|
||||
} );
|
||||
|
@ -113,32 +119,35 @@ module.exports = Class( 'ClassicGame' )
|
|||
/**
|
||||
* Render to the given 2d canvas context
|
||||
*
|
||||
* EVENT_TARGET will be monitored for keypresses.
|
||||
*
|
||||
* @param {CanvasRenderingContext2d} ctx 2d canvas context
|
||||
* @param {*} event_target keyboard event target
|
||||
*
|
||||
* @return {ClassicGame} self
|
||||
*/
|
||||
'public renderTo': function( ctx )
|
||||
'public renderTo': function( ctx, event_target )
|
||||
{
|
||||
// if there is a previous renderer, free its canvas before continuing
|
||||
// (to both clean up and to free any locks, allowing for tile set and
|
||||
// map changes)
|
||||
// if there is a previous renderer, free its canvas before
|
||||
// continuing (to both clean up and to free any locks, allowing for
|
||||
// tile set and level changes)
|
||||
if ( this._render )
|
||||
{
|
||||
this._render.clearCanvas();
|
||||
}
|
||||
|
||||
var map = this._mapSet.getMapByNumber( 1 ),
|
||||
map_state = MapState( map, this._gameObjFactory ),
|
||||
bounds = MapBounds( map );
|
||||
const level = this._levelSet.getLevelByNumber( 1 ),
|
||||
level_state = LevelState( level, this._gameObjFactory ),
|
||||
bounds = LevelBounds( level );
|
||||
|
||||
// render the first map (hardcoded for now)
|
||||
this._render = MapRender( ctx, this._tileSet )
|
||||
.render( map, map_state );
|
||||
// render the first level (hardcoded for now)
|
||||
this._render = LevelRender( ctx, this._tileSet )
|
||||
.render( level, level_state );
|
||||
|
||||
// POC
|
||||
window.onkeydown = function( event )
|
||||
event_target.onkeydown = function( event )
|
||||
{
|
||||
var dir;
|
||||
let dir;
|
||||
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
|
@ -153,7 +162,8 @@ module.exports = Class( 'ClassicGame' )
|
|||
return;
|
||||
}
|
||||
|
||||
map_state.movePlayer( dir, bounds );
|
||||
event.preventDefault();
|
||||
level_state.movePlayer( dir, bounds );
|
||||
};
|
||||
|
||||
return this;
|
||||
|
@ -171,7 +181,7 @@ module.exports = Class( 'ClassicGame' )
|
|||
'public setTileData': function( data, callback )
|
||||
{
|
||||
// get tile metadata
|
||||
var _self = this,
|
||||
const _self = this,
|
||||
meta = this._ltgLoader.fromString( data );
|
||||
|
||||
this._masker.getMaskedTiles( meta.tiles, meta.mask, function( tdata )
|
||||
|
@ -185,16 +195,16 @@ module.exports = Class( 'ClassicGame' )
|
|||
|
||||
|
||||
/**
|
||||
* Set LVL data for maps
|
||||
* Set LVL data for levels
|
||||
*
|
||||
* @param {string} data binary string containing LVL data
|
||||
* @param {function()} callback function to call when complete
|
||||
*
|
||||
* @return {ClassicGame} self
|
||||
*/
|
||||
'public setMapData': function( data, callback )
|
||||
'public setLevelData': function( data, callback )
|
||||
{
|
||||
this._mapSet = MapSet( data, ClassicMap );
|
||||
this._levelSet = LevelSet( data, ClassicLevel );
|
||||
|
||||
callback.call( this.__inst );
|
||||
return this;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
const Class = require( 'easejs' ).Class,
|
||||
GameObjectFactory = require( './GameObjectFactory' ),
|
||||
GameObject = require( './gameobjs/GameObject' ),
|
||||
Tank = require( './gameobjs/Tank' );
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
const Class = require( 'easejs' ).Class,
|
||||
TileDfn = require( './TileDfn' );
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* specs, as it depends on FileReader.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class;
|
||||
const Class = require( 'easejs' ).Class;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -49,8 +49,9 @@ module.exports = Class( 'FileLoader',
|
|||
* Initialize file loader, monitoring the given file element
|
||||
*
|
||||
* @param {HtmlInputElement} element file element to monitor
|
||||
* @param {FileReader} reader file reader
|
||||
*/
|
||||
__construct: function( element )
|
||||
__construct: function( element, reader )
|
||||
{
|
||||
if ( element.type !== 'file' )
|
||||
{
|
||||
|
@ -58,6 +59,7 @@ module.exports = Class( 'FileLoader',
|
|||
}
|
||||
|
||||
this._element = element;
|
||||
this._reader = reader;
|
||||
},
|
||||
|
||||
|
||||
|
@ -100,23 +102,23 @@ module.exports = Class( 'FileLoader',
|
|||
*/
|
||||
'private _loadFile': function( event )
|
||||
{
|
||||
var _self = this,
|
||||
const _self = this,
|
||||
files = event.target.files;
|
||||
|
||||
if ( files.length === 0 ) return;
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function( revent )
|
||||
this._reader.onload = function( revent )
|
||||
{
|
||||
_self._callback.call( this.__inst, null, revent.target.result );
|
||||
};
|
||||
reader.onerror = function( e )
|
||||
|
||||
this._reader.onerror = function( e )
|
||||
{
|
||||
_self._callback.call( this.__inst, e );
|
||||
};
|
||||
|
||||
// load file
|
||||
reader.readAsBinaryString( files[ 0 ] );
|
||||
this._reader.readAsBinaryString( files[ 0 ] );
|
||||
}
|
||||
} );
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Interface = require( 'easejs' ).Interface;
|
||||
const Interface = require( 'easejs' ).Interface;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -50,14 +50,14 @@ module.exports = Interface( 'Game',
|
|||
|
||||
|
||||
/**
|
||||
* Set LVL data for maps
|
||||
* Set LVL data for levels
|
||||
*
|
||||
* @param {string} data binary string containing LVL data
|
||||
* @param {function()} callback function to call when complete
|
||||
*
|
||||
* @return {Game} self
|
||||
*/
|
||||
'public setMapData': [ 'data', 'callback' ],
|
||||
'public setLevelData': [ 'data', 'callback' ],
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Interface = require( 'easejs' ).Interface;
|
||||
const Interface = require( 'easejs' ).Interface;
|
||||
|
||||
|
||||
module.exports = Interface( 'GameObjectFactory',
|
||||
|
|
|
@ -42,7 +42,10 @@
|
|||
* identify the file as a bitmap image.)
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class;
|
||||
/* XXX: remove me! */
|
||||
/* globals btoa */
|
||||
|
||||
const Class = require( 'easejs' ).Class;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -73,7 +76,7 @@ module.exports = Class( 'LtgLoader',
|
|||
*/
|
||||
'public fromString': function( ltg_data )
|
||||
{
|
||||
var mask_offset = this._getMaskOffsetFromData( ltg_data );
|
||||
const mask_offset = this._getMaskOffsetFromData( ltg_data );
|
||||
|
||||
return {
|
||||
name: this._getNameFromData( ltg_data ),
|
||||
|
@ -112,7 +115,7 @@ module.exports = Class( 'LtgLoader',
|
|||
sgmt = this.__self.$( sgmt );
|
||||
}
|
||||
|
||||
var data = String.prototype.substr.apply( ltg_data, sgmt );
|
||||
const data = String.prototype.substr.apply( ltg_data, sgmt );
|
||||
|
||||
return ( stripnull )
|
||||
? data.split( '\x00' )[ 0 ]
|
||||
|
@ -187,8 +190,9 @@ module.exports = Class( 'LtgLoader',
|
|||
// grab the data and don't bother stripping off the null bytes (it would
|
||||
// function the same with them stripped, but let's avoid the confusion
|
||||
// since we are supposed to be working with a 32-bit value)
|
||||
var data = this._getDataSegment( ltg_data, '_POS_MOFF', false ),
|
||||
i = data.length,
|
||||
const data = this._getDataSegment( ltg_data, '_POS_MOFF', false );
|
||||
|
||||
let i = data.length,
|
||||
offset = 0;
|
||||
|
||||
// convert the DWORD entry (little-endian format, 32-bit) into an
|
||||
|
@ -234,7 +238,7 @@ module.exports = Class( 'LtgLoader',
|
|||
*/
|
||||
'private _getGameBitmap': function( ltg_data, mask_offset )
|
||||
{
|
||||
var bmp_offset = this.__self.$( '_OFFSET_HEADER_END' );
|
||||
const bmp_offset = this.__self.$( '_OFFSET_HEADER_END' );
|
||||
|
||||
// return the bitmap data up until the mask offset
|
||||
return ltg_data.substr( bmp_offset, ( mask_offset - bmp_offset ) );
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
* thinice - thin ice
|
||||
*/
|
||||
|
||||
var Interface = require( 'easejs' ).Interface;
|
||||
const Interface = require( 'easejs' ).Interface;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
* rendering.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
const Class = require( 'easejs' ).Class,
|
||||
TileDfn = require( './TileDfn' );
|
||||
|
||||
/**
|
||||
|
@ -77,6 +77,12 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'private _context': null,
|
||||
|
||||
/**
|
||||
* DOM document
|
||||
* @type {HTMLDocument}
|
||||
*/
|
||||
'private _document': null,
|
||||
|
||||
/**
|
||||
* Tile definition to use for all operations
|
||||
* @type {Array.<Array.<string,number>>}
|
||||
|
@ -121,9 +127,13 @@ module.exports = Class( 'TileMasker',
|
|||
* allows us to support *any* type of tile set -- not just those that are
|
||||
* defined by the original game.
|
||||
*
|
||||
* DOCUMENT is used internally for creating elements; the DOM will not
|
||||
* be manipulated.
|
||||
*
|
||||
* @param {TileDfn} tile_dfn tile definition object
|
||||
* @param {HTMLDocument} document DOM document
|
||||
*/
|
||||
__construct: function( tile_dfn )
|
||||
__construct: function( tile_dfn, document )
|
||||
{
|
||||
if ( !( Class.isA( TileDfn, tile_dfn ) ) )
|
||||
{
|
||||
|
@ -137,13 +147,14 @@ module.exports = Class( 'TileMasker',
|
|||
// rather than accepting a context, we will create our own canvas in
|
||||
// memory to perform our operations (it will not be added to the DOM, so
|
||||
// these operations will not be visible to the user)
|
||||
var context = document.createElement( 'canvas' ).getContext( '2d' );
|
||||
let context = document.createElement( 'canvas' ).getContext( '2d' );
|
||||
|
||||
// size the canvas so that it can fit the entire tileset
|
||||
context.canvas.width = this._setWidth;
|
||||
context.canvas.height = this._setHeight;
|
||||
|
||||
this._context = context;
|
||||
this._document = document;
|
||||
},
|
||||
|
||||
|
||||
|
@ -161,7 +172,7 @@ module.exports = Class( 'TileMasker',
|
|||
'private _calcSetDimensions': function( tile_dfn )
|
||||
{
|
||||
// these vars are for clarity
|
||||
var sizes = tile_dfn.getTileDimensions(),
|
||||
const sizes = tile_dfn.getTileDimensions(),
|
||||
n = this._tileDfn.length;
|
||||
|
||||
// store values so that we do not have to make additional calls to our
|
||||
|
@ -201,7 +212,7 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'public getMaskedTiles': function( bmp_game, bmp_mask, callback )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
this._getImageData( bmp_mask, function( data_mask )
|
||||
{
|
||||
|
@ -248,9 +259,7 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'virtual protected getMaskedTileSet': function( data_mask, callback )
|
||||
{
|
||||
var tdata = this._tileDfn,
|
||||
tiles = {},
|
||||
i = -1,
|
||||
const tdata = this._tileDfn,
|
||||
len = tdata.length,
|
||||
|
||||
// shorten the names
|
||||
|
@ -258,15 +267,18 @@ module.exports = Class( 'TileMasker',
|
|||
th = this._tileHeight,
|
||||
xn = this._tilesPerRow;
|
||||
|
||||
let tiles = {},
|
||||
i = -1;
|
||||
|
||||
// create each tile (preserving order, thus no decrementing)
|
||||
while ( ++i < len )
|
||||
{
|
||||
var id = tdata[ i ][ 0 ],
|
||||
mask = tdata[ i ][ 1 ],
|
||||
const id = tdata[ i ][ 0 ],
|
||||
mask = tdata[ i ][ 1 ];
|
||||
|
||||
// calculate the X and Y position of this tile based on the tile
|
||||
// and bitmap dimensions
|
||||
x = ( ( i % xn ) * th ),
|
||||
const x = ( ( i % xn ) * th ),
|
||||
y = ( ( Math.floor( i / xn ) ) * tw );
|
||||
|
||||
// the third index indicates whether or not a mask should be applied
|
||||
|
@ -297,7 +309,7 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'protected appendTileFrame': function( set, id, mask, data )
|
||||
{
|
||||
var prev = set[ id ];
|
||||
const prev = set[ id ];
|
||||
|
||||
set[ id ] = {
|
||||
data: data,
|
||||
|
@ -314,7 +326,7 @@ module.exports = Class( 'TileMasker',
|
|||
|
||||
// if there was a previous entry, set its 'next' entry to our new frame,
|
||||
// expanding the linked list
|
||||
prev && ( prev.next = set[ id ] )
|
||||
if ( prev ) prev.next = set[ id ];
|
||||
},
|
||||
|
||||
|
||||
|
@ -347,18 +359,19 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'virtual protected getMaskedTileData': function( data_mask, x, y )
|
||||
{
|
||||
var raw = this.getTileData( x, y ),
|
||||
const raw = this.getTileData( x, y ),
|
||||
w = raw.width,
|
||||
h = raw.height,
|
||||
mw = data_mask.width,
|
||||
yi = h;
|
||||
mw = data_mask.width;
|
||||
|
||||
let yi = h;
|
||||
|
||||
// apply the mask to the raw tile data (simple and easy-to-understand
|
||||
// algorithm; we can refine it later if need be), looping through each
|
||||
// pixel
|
||||
while ( yi-- )
|
||||
{
|
||||
xi = w;
|
||||
let xi = w;
|
||||
|
||||
while ( xi-- )
|
||||
{
|
||||
|
@ -366,7 +379,7 @@ module.exports = Class( 'TileMasker',
|
|||
// (remember that, although we are dealing with applying the
|
||||
// mask to a single tile, the mask image contains all tiles, so
|
||||
// we must calculate its position accordingly)
|
||||
var mi = ( ( ( yi + y ) * ( mw * 4 ) ) + ( ( xi + x ) * 4 ) ),
|
||||
const mi = ( ( ( yi + y ) * ( mw * 4 ) ) + ( ( xi + x ) * 4 ) ),
|
||||
mr = data_mask.data[ mi ];
|
||||
|
||||
// manipulate the alpha channel of our tile; if the R value for
|
||||
|
@ -414,8 +427,8 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'private _renderImage': function( bmp, callback )
|
||||
{
|
||||
var _self = this,
|
||||
img = new Image();
|
||||
const _self = this,
|
||||
img = this._document.createElement( 'img' );
|
||||
|
||||
img.onload = function()
|
||||
{
|
||||
|
@ -437,7 +450,7 @@ module.exports = Class( 'TileMasker',
|
|||
*/
|
||||
'private _getImageData': function( bmp, callback )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
this._renderImage( bmp, function()
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class;
|
||||
const Class = require( 'easejs' ).Class;
|
||||
|
||||
|
||||
module.exports = Class( 'GameObject',
|
||||
|
@ -44,6 +44,7 @@ module.exports = Class( 'GameObject',
|
|||
},
|
||||
|
||||
|
||||
/* jshint -W098 */
|
||||
'virtual public move': function( dir, c, sc )
|
||||
{
|
||||
// move in the appropriate direction (action has been pre-configured
|
||||
|
@ -52,4 +53,5 @@ module.exports = Class( 'GameObject',
|
|||
|
||||
return this;
|
||||
}
|
||||
/* jshint +W098 */
|
||||
} );
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
const Class = require( 'easejs' ).Class,
|
||||
GameObject = require( './GameObject' );
|
||||
|
||||
|
||||
|
@ -26,12 +26,12 @@ module.exports = Class( 'Tank' )
|
|||
{
|
||||
'override public move': function( direction, c, sc )
|
||||
{
|
||||
var state = [ 'tleft', 'tup', 'tright', 'tdown' ][ direction ];
|
||||
const state = [ 'tleft', 'tup', 'tright', 'tdown' ][ direction ];
|
||||
|
||||
if ( state !== this.getTid() )
|
||||
{
|
||||
sc( state );
|
||||
return;
|
||||
return this;
|
||||
}
|
||||
|
||||
// let parent handle the movement
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
const Class = require( 'easejs' ).Class,
|
||||
Tank = require( '../Tank' );
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Represents a classic map (level)
|
||||
* Represents a classic level
|
||||
*
|
||||
* Copyright (C) 2012, 2015 Mike Gerwitz
|
||||
*
|
||||
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Each map is concatenated in the file and consists of the following
|
||||
* Each level is concatenated in the file and consists of the following
|
||||
* information:
|
||||
*
|
||||
* - Playfield data (game objects), 16x16 multidimensional char array
|
||||
|
@ -27,34 +27,34 @@
|
|||
* - Difficulty, 16-bit integer, little endian
|
||||
*
|
||||
* One can easily calculate the position of the level in a file, given its
|
||||
* number, by multiplying by the size of the data structure (see TLEVEL, LTANK.H
|
||||
* in the original sources).
|
||||
* number, by multiplying by the size of the data structure (see TLEVEL,
|
||||
* LTANK.H in the original sources).
|
||||
*
|
||||
* It is worth mentioning how the playfield data is stored. Since the
|
||||
* multidimensional array is defined as [x][y], the array is created as an
|
||||
* "array of columns", meaning that the data is organized in columns instead of
|
||||
* rows. For example, when viewing the data in a HEX editor that displays 16
|
||||
* bytes per line (e.g. xxd), the map would appear to be mirrored rotated 90
|
||||
* degrees counter-clockwise. To make it easier to visualize, one can create a
|
||||
* map with a number of tunnels in a pattern to take advantage of the ASCII
|
||||
* display.
|
||||
* "array of columns", meaning that the data is organized in columns instead
|
||||
* of rows. For example, when viewing the data in a HEX editor that displays
|
||||
* 16 bytes per line (e.g. xxd), the level would appear to be mirrored
|
||||
* rotated 90 degrees counter-clockwise. To make it easier to visualize, one
|
||||
* can create a level with a number of tunnels in a pattern to take
|
||||
* advantage of the ASCII display.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
Map = require( './Map' );
|
||||
const Class = require( 'easejs' ).Class,
|
||||
Level = require( './Level' );
|
||||
|
||||
|
||||
/**
|
||||
* Represents a classic map, as they exist in the original game.
|
||||
* Represents a classic level, as they exist in the original game.
|
||||
*
|
||||
* Classic maps are 16x16 tiles in size (for a total of 256 tiles).
|
||||
* Classic levels are 16x16 tiles in size (for a total of 256 tiles).
|
||||
*/
|
||||
module.exports = Class( 'ClassicMap' )
|
||||
.implement( Map )
|
||||
module.exports = Class( 'ClassicLevel' )
|
||||
.implement( Level )
|
||||
.extend(
|
||||
{
|
||||
/**
|
||||
* Size of each map in bytes
|
||||
* Size of each level in bytes
|
||||
* @type {number}
|
||||
*/
|
||||
'private const _SIZE': 576,
|
||||
|
@ -70,13 +70,13 @@ module.exports = Class( 'ClassicMap' )
|
|||
'private const _GOSIZE': [ 0, 256 ],
|
||||
|
||||
/**
|
||||
* Offset and length of map name
|
||||
* Offset and length of level name
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
'private const _NAMESIZE': [ 256, 31 ],
|
||||
|
||||
/**
|
||||
* Offset and length of map hint
|
||||
* Offset and length of level hint
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
'private const _HINTSIZE': [ 287, 256 ],
|
||||
|
@ -105,12 +105,13 @@ module.exports = Class( 'ClassicMap' )
|
|||
/**
|
||||
* Colors used to identify tunnels
|
||||
*
|
||||
* These colors will be rendered in the background and will bleed through
|
||||
* the transparent portions of the tile. We use explicit HEX codes rather
|
||||
* than CSS color names because environments may vary the colors used.
|
||||
* These colors will be rendered in the background and will bleed
|
||||
* through the transparent portions of the tile. We use explicit HEX
|
||||
* codes rather than CSS color names because environments may vary the
|
||||
* colors used.
|
||||
*
|
||||
* Taken from ColorList in LTANK2.C in the original sources. Note that there
|
||||
* is an endianness difference.
|
||||
* Taken from ColorList in LTANK2.C in the original sources. Note that
|
||||
* there is an endianness difference.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
|
@ -121,36 +122,36 @@ module.exports = Class( 'ClassicMap' )
|
|||
|
||||
|
||||
/**
|
||||
* Map set data (binary string)
|
||||
* Level set data (binary string)
|
||||
* @type {string}
|
||||
*/
|
||||
'private _data': null,
|
||||
|
||||
/**
|
||||
* Map id (1-indexed)
|
||||
* Level id (1-indexed)
|
||||
* @type {string}
|
||||
*/
|
||||
'private _id': 0,
|
||||
|
||||
/**
|
||||
* Offset of beginning of map data in bytes
|
||||
* Offset of beginning of level data in bytes
|
||||
* @type {number}
|
||||
*/
|
||||
'private _offset': 0,
|
||||
|
||||
|
||||
/**
|
||||
* Initialize map with map data and the given id
|
||||
* Initialize level with level data and the given id
|
||||
*
|
||||
* @param {MapSet} set map set data
|
||||
* @param {number} id 1-indexed map id
|
||||
* @param {LevelSet} set level set data
|
||||
* @param {number} id 1-indexed level id
|
||||
*/
|
||||
__construct: function( data, id )
|
||||
{
|
||||
this._data = ''+( data );
|
||||
this._id = +id;
|
||||
|
||||
// calculate map offset in LVL data
|
||||
// calculate level offset in LVL data
|
||||
this._offset = ( this.__self.$( '_SIZE' ) * ( this._id - 1 ) );
|
||||
},
|
||||
|
||||
|
@ -158,20 +159,20 @@ module.exports = Class( 'ClassicMap' )
|
|||
/**
|
||||
* Retrieve game objects
|
||||
*
|
||||
* The game objects are returned in a manner consistent with the original
|
||||
* sources - in columns, not rows. The reason for this is that the original
|
||||
* game uses a multi-dimensional array [x][y], which creates an array of
|
||||
* columns (TPLAYFIELD, LTANK.H).
|
||||
* The game objects are returned in a manner consistent with the
|
||||
* original sources - in columns, not rows. The reason for this is that
|
||||
* the original game uses a multi-dimensional array [x][y], which
|
||||
* creates an array of columns (TPLAYFIELD, LTANK.H).
|
||||
*
|
||||
* The object data at the requested position will be loaded and converted to
|
||||
* integers (from a binary string).
|
||||
* The object data at the requested position will be loaded and
|
||||
* converted to integers (from a binary string).
|
||||
*
|
||||
* @return {Array.<number>} array of game objects
|
||||
*/
|
||||
'public getObjects': function()
|
||||
{
|
||||
var tiles = this._getDataSegment( '_GOSIZE', false ).split( '' ),
|
||||
i = tiles.length;
|
||||
const tiles = this._getDataSegment( '_GOSIZE', false ).split( '' );
|
||||
let i = tiles.length;
|
||||
|
||||
while ( i-- )
|
||||
{
|
||||
|
@ -192,7 +193,7 @@ module.exports = Class( 'ClassicMap' )
|
|||
{
|
||||
stripnull = ( arguments.length < 2 ) ? true : !!stripnull;
|
||||
|
||||
var s = this.__self.$( name ),
|
||||
const s = this.__self.$( name ),
|
||||
data = this._data.substr( ( this._offset + s[ 0 ] ), s[ 1 ] );
|
||||
|
||||
return ( stripnull )
|
||||
|
@ -202,7 +203,7 @@ module.exports = Class( 'ClassicMap' )
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve map dimensions
|
||||
* Retrieve level dimensions
|
||||
*
|
||||
* @return {Array.<number>} width and height in tiles
|
||||
*/
|
||||
|
@ -213,11 +214,11 @@ module.exports = Class( 'ClassicMap' )
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve map of object codes to their appropriate tiles
|
||||
* Retrieve level of object codes to their appropriate tiles
|
||||
*
|
||||
* @return {Array.<string>}
|
||||
*/
|
||||
'public getObjectTileMap': function()
|
||||
'public getObjectTileLevel': function()
|
||||
{
|
||||
// we return these values here instead of returning, say, a constant,
|
||||
// because we would have to clone it to ensure that our inner state
|
||||
|
@ -235,9 +236,10 @@ module.exports = Class( 'ClassicMap' )
|
|||
/**
|
||||
* Retrieve tunnel color
|
||||
*
|
||||
* The color will be rendered in the background and will bleed through the
|
||||
* transparent portions of the tile. We use explicit HEX codes rather than
|
||||
* CSS color names because environments may vary the colors used.
|
||||
* The color will be rendered in the background and will bleed through
|
||||
* the transparent portions of the tile. We use explicit HEX codes
|
||||
* rather than CSS color names because environments may vary the colors
|
||||
* used.
|
||||
*
|
||||
* @param {number} oid tunnel object id
|
||||
*
|
||||
|
@ -245,9 +247,9 @@ module.exports = Class( 'ClassicMap' )
|
|||
*/
|
||||
'public getTunnelColor': function( oid )
|
||||
{
|
||||
// get the tunnel id by stripping off the tunnel bitmask and then grab
|
||||
// the associated color
|
||||
var tunnel_id = ( ( +oid ^ this.__self.$( '_TMASK' ) ) / 2 );
|
||||
// get the tunnel id by stripping off the tunnel bitmask and then
|
||||
// grab the associated color
|
||||
const tunnel_id = ( ( +oid ^ this.__self.$( '_TMASK' ) ) / 2 );
|
||||
|
||||
return this.__self.$( '_TCOLORS' )[ tunnel_id ] || 'black';
|
||||
},
|
||||
|
@ -265,79 +267,81 @@ module.exports = Class( 'ClassicMap' )
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve map name
|
||||
* Retrieve level name
|
||||
*
|
||||
* @return {string} map name
|
||||
* @return {string} level name
|
||||
*/
|
||||
'public getMapName': function()
|
||||
'public getLevelName': function()
|
||||
{
|
||||
return this._getDataSegment( '_NAMESIZE' );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve map author name
|
||||
* Retrieve level author name
|
||||
*
|
||||
* @return {string} map author name
|
||||
* @return {string} level author name
|
||||
*/
|
||||
'public getMapAuthor': function()
|
||||
'public getLevelAuthor': function()
|
||||
{
|
||||
return this._getDataSegment( '_AUTHORSIZE' );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve map hint
|
||||
* Retrieve level hint
|
||||
*
|
||||
* @return {string} map hint
|
||||
* @return {string} level hint
|
||||
*/
|
||||
'public getMapHint': function()
|
||||
'public getLevelHint': function()
|
||||
{
|
||||
return this._getDataSegment( '_HINTSIZE' );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve map difficulty
|
||||
* Retrieve level difficulty
|
||||
*
|
||||
* The map difficulty will be returned as a 0-indexed value between 0 and 4,
|
||||
* with 0 representing "kids" and 4 representing "deadly".
|
||||
* The level difficulty will be returned as a 0-indexed value between 0
|
||||
* and 4, with 0 representing "kids" and 4 representing "deadly".
|
||||
*
|
||||
* The original game uses a bitmask for this value (thus the 16-bit
|
||||
* integer), which is really of no particular use. For simplicity's sake, we
|
||||
* will convert it.
|
||||
* integer), which is really of no particular use. For simplicity's
|
||||
* sake, we will convert it.
|
||||
*
|
||||
* @return {number} 0-indexed difficulty level
|
||||
*/
|
||||
'public getMapDifficulty': function()
|
||||
'public getLevelDifficulty': function()
|
||||
{
|
||||
var val = this._getDataSegment( '_DIFFSIZE', false ),
|
||||
i = val.length,
|
||||
const val = this._getDataSegment( '_DIFFSIZE', false );
|
||||
|
||||
let i = val.length,
|
||||
n = 0;
|
||||
|
||||
// first, convert the value to an integer (from little-endian)
|
||||
while ( i-- ) n += ( val.charCodeAt( i ) << ( 8 * i ) );
|
||||
|
||||
// Finally, convert to a simple 0-4 value to represent difficulty by
|
||||
// taking the binary logarithm of the value (lg(n); original game uses
|
||||
// bitmasks). For those who do not understand logarithms, the concept
|
||||
// here is simple: if we are given a difficulty of "hard" (value of 8),
|
||||
// that has a binary representation of: 1000. We are interested in the
|
||||
// position of the 1-bit. Since each bit position is an exponent of two,
|
||||
// we can reverse that calculation with a binary logarithm. So, log2(8),
|
||||
// also written as lg(8), is equal to 3, since 2^3 = 8. Similarly,
|
||||
// "deadly" = 16 = 0001 0000 => lg(16) = 4, and "kids" = 1 = 0001 =>
|
||||
// lg(1) = 0. This gives us a 0-indexed difficulty value.
|
||||
// taking the binary logarithm of the value (lg(n); original game
|
||||
// uses bitmasks). For those who do not understand logarithms, the
|
||||
// concept here is simple: if we are given a difficulty of "hard"
|
||||
// (value of 8), that has a binary representation of: 1000. We are
|
||||
// interested in the position of the 1-bit. Since each bit position
|
||||
// is an exponent of two, we can reverse that calculation with a
|
||||
// binary logarithm. So, log2(8), also written as lg(8), is equal to
|
||||
// 3, since 2^3 = 8. Similarly, "deadly" = 16 = 0001 0000 => lg(16)
|
||||
// = 4, and "kids" = 1 = 0001 => lg(1) = 0. This gives us a
|
||||
// 0-indexed difficulty value.
|
||||
return ( Math.log( n ) / Math.log( 2 ) );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve size of map in bytes
|
||||
* Retrieve size of level in bytes
|
||||
*
|
||||
* @return {number} size of map in bytes
|
||||
* @return {number} size of level in bytes
|
||||
*/
|
||||
'public static getMapSize': function()
|
||||
'public static getLevelSize': function()
|
||||
{
|
||||
return this.$( '_SIZE' );
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* The details on exactly how the map data is stored is left to specific
|
||||
* The details on exactly how the level data is stored is left to specific
|
||||
* implementations. However, the following is common to each file format:
|
||||
*
|
||||
* - All game objects for the playfield should be returned in columns rather
|
||||
|
@ -29,26 +29,26 @@
|
|||
* tunnel identified by index 0 is 0x40, index 1 is 0x42, and so on.
|
||||
*/
|
||||
|
||||
var Interface = require( 'easejs' ).Interface;
|
||||
const Interface = require( 'easejs' ).Interface;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a map (level)
|
||||
* Represents a game level
|
||||
*
|
||||
* Maps simply act as basic wrappers around a set of maps, returning only the
|
||||
* data associated with the requested map. This allows the data to be lazily
|
||||
* sliced out of the map file.
|
||||
* Levels simply act as basic wrappers around a set of maps, returning only the
|
||||
* data associated with the requested level. This allows the data to be lazily
|
||||
* sliced out of the level file.
|
||||
*
|
||||
* Note that this interface specifies a constructor definition; this allows it
|
||||
* to be used in place of a separate Factory class.
|
||||
*/
|
||||
module.exports = Interface( 'Map',
|
||||
module.exports = Interface( 'Level',
|
||||
{
|
||||
/**
|
||||
* Initialize map with map data and the given id
|
||||
* Initialize level with level data and the given id
|
||||
*
|
||||
* @param {MapSet} set map set data
|
||||
* @param {number} id 1-indexed map id
|
||||
* @param {LevelSet} set level set data
|
||||
* @param {number} id 1-indexed level id
|
||||
*/
|
||||
__construct: [ 'set', 'id' ],
|
||||
|
||||
|
@ -67,7 +67,7 @@ module.exports = Interface( 'Map',
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve map dimensions
|
||||
* Retrieve level dimensions
|
||||
*
|
||||
* @return {Array.<number>} width and height in tiles
|
||||
*/
|
||||
|
@ -75,11 +75,11 @@ module.exports = Interface( 'Map',
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve map of object codes to their appropriate tiles
|
||||
* Retrieve level of object codes to their appropriate tiles
|
||||
*
|
||||
* @return {Array.<string>}
|
||||
*/
|
||||
'public getObjectTileMap': [],
|
||||
'public getObjectTileLevel': [],
|
||||
|
||||
|
||||
/**
|
||||
|
@ -106,44 +106,44 @@ module.exports = Interface( 'Map',
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve map name
|
||||
* Retrieve level name
|
||||
*
|
||||
* @return {string} map name
|
||||
* @return {string} level name
|
||||
*/
|
||||
'public getMapName': [],
|
||||
'public getLevelName': [],
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve map author name
|
||||
* Retrieve level author name
|
||||
*
|
||||
* @return {string} map author name
|
||||
* @return {string} level author name
|
||||
*/
|
||||
'public getMapAuthor': [],
|
||||
'public getLevelAuthor': [],
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve map hint
|
||||
* Retrieve level hint
|
||||
*
|
||||
* @return {string} map hint
|
||||
* @return {string} level hint
|
||||
*/
|
||||
'public getMapHint': [],
|
||||
'public getLevelHint': [],
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve map difficulty
|
||||
* Retrieve level difficulty
|
||||
*
|
||||
* The map difficulty should be returned as a 0-indexed value between 0 and
|
||||
* 4, with 0 representing "kids" and 4 representing "deadly".
|
||||
* The level difficulty should be returned as a 0-indexed value between
|
||||
* 0 and 4, with 0 representing "kids" and 4 representing "deadly".
|
||||
*
|
||||
* @return {number} 0-indexed difficulty level
|
||||
*/
|
||||
'public getMapDifficulty': [],
|
||||
'public getLevelDifficulty': [],
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve size of map in bytes
|
||||
* Retrieve size of level in bytes
|
||||
*
|
||||
* @return {number} size of map in bytes
|
||||
* @return {number} size of level in bytes
|
||||
*/
|
||||
'public static getMapSize': []
|
||||
'public static getLevelSize': []
|
||||
} );
|
|
@ -17,11 +17,11 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
MapBounds = require( './MapBounds' );
|
||||
const Class = require( 'easejs' ).Class,
|
||||
LevelBounds = require( './LevelBounds' );
|
||||
|
||||
|
||||
module.exports = Class( 'MapAction',
|
||||
module.exports = Class( 'LevelAction',
|
||||
{
|
||||
// arranged by keycode
|
||||
'const D__MIN': 0,
|
||||
|
@ -43,9 +43,9 @@ module.exports = Class( 'MapAction',
|
|||
|
||||
__construct: function( bounds, move_callback )
|
||||
{
|
||||
if ( !( Class.isA( MapBounds, bounds ) ) )
|
||||
if ( !( Class.isA( LevelBounds, bounds ) ) )
|
||||
{
|
||||
throw TypeError( 'Invalid MapBounds provided' );
|
||||
throw TypeError( 'Invalid LevelBounds provided' );
|
||||
}
|
||||
|
||||
this._dir = this.__self.$( 'D_UP' );
|
||||
|
@ -57,7 +57,7 @@ module.exports = Class( 'MapAction',
|
|||
|
||||
'public move': function()
|
||||
{
|
||||
var method = [
|
||||
const method = [
|
||||
'getLeftPos',
|
||||
'getUpperPos',
|
||||
'getRightPos',
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Handles map boundaries for collision detection and movement
|
||||
* Handles level boundaries for collision detection and movement
|
||||
*
|
||||
* Copyright (C) 2012, 2015 Mike Gerwitz
|
||||
*
|
||||
|
@ -17,45 +17,46 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
Map = require( './Map' );
|
||||
const Class = require( 'easejs' ).Class,
|
||||
Level = require( './Level' );
|
||||
|
||||
|
||||
/**
|
||||
* Calculates map bounding box
|
||||
* Calculates level bounding box
|
||||
*
|
||||
* This simply encapsulates the process of determining whether a given position
|
||||
* is against an edge of the map.
|
||||
* This simply encapsulates the process of determining whether a given
|
||||
* position is against an edge of the level.
|
||||
*/
|
||||
module.exports = Class( 'MapBounds',
|
||||
module.exports = Class( 'LevelBounds',
|
||||
{
|
||||
/**
|
||||
* Map width (number of tiles)
|
||||
* Level width (number of tiles)
|
||||
* @type {number}
|
||||
*/
|
||||
'private _mw': 0,
|
||||
|
||||
/**
|
||||
* Map height (number of tiles)
|
||||
* Level height (number of tiles)
|
||||
* @type {number}
|
||||
*/
|
||||
'private _mh': 0,
|
||||
|
||||
|
||||
/**
|
||||
* Initialize bounding box for a given map
|
||||
* Initialize bounding box for a given level
|
||||
*
|
||||
* @param {Map} map map for which bounds should be calculated
|
||||
* @param {Level} level level for which bounds should be calculated
|
||||
*/
|
||||
__construct: function( map )
|
||||
__construct: function( level )
|
||||
{
|
||||
if ( !( Class.isA( Map, map ) ) )
|
||||
if ( !( Class.isA( Level, level ) ) )
|
||||
{
|
||||
throw TypeError( 'Invalid Map provided' );
|
||||
throw TypeError( 'Invalid Level provided' );
|
||||
}
|
||||
|
||||
// we are only interested in the dimensions of the map
|
||||
var dimen = map.getDimensions();
|
||||
// we are only interested in the dimensions of the level
|
||||
const dimen = level.getDimensions();
|
||||
|
||||
this._mw = dimen[ 0 ];
|
||||
this._mh = dimen[ 1 ];
|
||||
},
|
||||
|
@ -64,7 +65,7 @@ module.exports = Class( 'MapBounds',
|
|||
/**
|
||||
* Retrieve the tile position above the given position
|
||||
*
|
||||
* If the given tile position is at the top of the map, then the given
|
||||
* If the given tile position is at the top of the level, then the given
|
||||
* position will be returned.
|
||||
*
|
||||
* @param {number} pos original tile position
|
||||
|
@ -82,8 +83,8 @@ module.exports = Class( 'MapBounds',
|
|||
/**
|
||||
* Retrieve the tile position below the given position
|
||||
*
|
||||
* If the given tile position is at the bottom of the map, then the given
|
||||
* position will be returned.
|
||||
* If the given tile position is at the bottom of the level, then the
|
||||
* given position will be returned.
|
||||
*
|
||||
* @param {number} pos original tile position
|
||||
*
|
||||
|
@ -100,8 +101,8 @@ module.exports = Class( 'MapBounds',
|
|||
/**
|
||||
* Retrieve the tile position to the left of the given position
|
||||
*
|
||||
* If the given tile position is at the leftmost column of the map, then the
|
||||
* given position will be returned.
|
||||
* If the given tile position is at the leftmost column of the level,
|
||||
* then the given position will be returned.
|
||||
*
|
||||
* @param {number} pos original tile position
|
||||
*
|
||||
|
@ -119,8 +120,8 @@ module.exports = Class( 'MapBounds',
|
|||
/**
|
||||
* Retrieve the tile position to the right of the given position
|
||||
*
|
||||
* If the given tile position is at the rightmost column of the map, then
|
||||
* the given position will be returned.
|
||||
* If the given tile position is at the rightmost column of the level,
|
||||
* then the given position will be returned.
|
||||
*
|
||||
* @param {number} pos original tile position
|
||||
*
|
||||
|
@ -136,7 +137,7 @@ module.exports = Class( 'MapBounds',
|
|||
|
||||
|
||||
/**
|
||||
* Determines if the given position is in the topmost row of the map
|
||||
* Determines if the given position is in the topmost row of the level
|
||||
*
|
||||
* @param {number} pos tile position
|
||||
*
|
||||
|
@ -144,14 +145,14 @@ module.exports = Class( 'MapBounds',
|
|||
*/
|
||||
'public isAtTop': function( pos )
|
||||
{
|
||||
// since tile positions are zero-indexed, we know that we're at the top
|
||||
// if the map height divides the position
|
||||
// since tile positions are zero-indexed, we know that we're at the
|
||||
// top if the level height divides the position
|
||||
return ( pos % this._mh === 0 );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Determines if the given position is in the bottom row of the map
|
||||
* Determines if the given position is in the bottom row of the level
|
||||
*
|
||||
* @param {number} pos tile position
|
||||
*
|
||||
|
@ -165,7 +166,8 @@ module.exports = Class( 'MapBounds',
|
|||
|
||||
|
||||
/**
|
||||
* Determines if the given position is in the leftmost column of the map
|
||||
* Determines if the given position is in the leftmost column of the
|
||||
* level
|
||||
*
|
||||
* @param {number} pos tile position
|
||||
*
|
||||
|
@ -179,7 +181,8 @@ module.exports = Class( 'MapBounds',
|
|||
|
||||
|
||||
/**
|
||||
* Determines if the given position is in the rightmost column of the map
|
||||
* Determines if the given position is in the rightmost column of the
|
||||
* level
|
||||
*
|
||||
* @param {number} pos tile position
|
||||
*
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Renders a given map
|
||||
* Renders a given level
|
||||
*
|
||||
* Copyright (C) 2012, 2015 Mike Gerwitz
|
||||
*
|
||||
|
@ -17,20 +17,20 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
MapState = require( './MapState' );
|
||||
const Class = require( 'easejs' ).Class,
|
||||
LevelState = require( './LevelState' );
|
||||
|
||||
|
||||
/**
|
||||
* Renders a map to a canvas
|
||||
* Renders a level to a canvas
|
||||
*/
|
||||
module.exports = Class( 'MapRender',
|
||||
module.exports = Class( 'LevelRender',
|
||||
{
|
||||
/**
|
||||
* Property to hold lock bit on canvas element
|
||||
* @type {string}
|
||||
*/
|
||||
'private const _LOCK': '__$$MapRenderLock$$',
|
||||
'private const _LOCK': '__$$LevelRenderLock$$',
|
||||
|
||||
/**
|
||||
* Animation interval in milliseconds
|
||||
|
@ -40,7 +40,7 @@ module.exports = Class( 'MapRender',
|
|||
|
||||
|
||||
/**
|
||||
* 2d context to which map should be drawn
|
||||
* 2d context to which level should be drawn
|
||||
* @type {CanvasRenderingContext2d}
|
||||
*/
|
||||
'private _ctx': null,
|
||||
|
@ -67,8 +67,8 @@ module.exports = Class( 'MapRender',
|
|||
/**
|
||||
* Initialize renderer with a canvas context and a tile set
|
||||
*
|
||||
* An additional canvas of equal dimensions will be created and laid atop of
|
||||
* the provided canvas to render masked game objects.
|
||||
* An additional canvas of equal dimensions will be created and laid
|
||||
* atop of the provided canvas to render masked game objects.
|
||||
*
|
||||
* @param {CanvasRenderingContext2d} ctx canvas 2d context
|
||||
* @param {Object} tiles tile set to render
|
||||
|
@ -79,7 +79,7 @@ module.exports = Class( 'MapRender',
|
|||
this._tiles = tiles;
|
||||
|
||||
// ensure that we are exclusively rendering to this canvas (no other
|
||||
// MapRenders)
|
||||
// LevelRenders)
|
||||
this._lockCanvas();
|
||||
|
||||
this._ctxObj = this._getObjCanvas();
|
||||
|
@ -87,22 +87,24 @@ module.exports = Class( 'MapRender',
|
|||
|
||||
|
||||
/**
|
||||
* Lock the canvas to prevent other MapRender instances from rendering to it
|
||||
* Lock the canvas to prevent other LevelRender instances from rendering
|
||||
* to it
|
||||
*
|
||||
* The purpose of this is to provide feedback to the user/developer in the
|
||||
* event that multiple MapRender instances are attempting to render to the
|
||||
* same canvas, which would certainly cause display issues and confusion.
|
||||
* The purpose of this is to provide feedback to the user/developer in
|
||||
* the event that multiple LevelRender instances are attempting to
|
||||
* render to the same canvas, which would certainly cause display issues
|
||||
* and confusion.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _lockCanvas': function()
|
||||
{
|
||||
var o = this._ctx,
|
||||
const o = this._ctx,
|
||||
l = this.__self.$( '_LOCK' );
|
||||
|
||||
// simple one-line check to both set the lock and fail if the lock is
|
||||
// already set (implying that something else is already rendering to the
|
||||
// canvas)
|
||||
// simple one-line check to both set the lock and fail if the lock
|
||||
// is already set (implying that something else is already rendering
|
||||
// to the canvas)
|
||||
if ( ( o[ l ] ^= 1 ) !== 1 )
|
||||
{
|
||||
// reset the lock
|
||||
|
@ -110,24 +112,24 @@ module.exports = Class( 'MapRender',
|
|||
|
||||
throw Error(
|
||||
'Could not set exclusive lock on canvas (in use by another ' +
|
||||
'MapRender instance)'
|
||||
'LevelRender instance)'
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Remove exclusive lock on canvas to permit other MapRender instances to
|
||||
* render to it
|
||||
* Remove exclusive lock on canvas to permit other LevelRender instances
|
||||
* to render to it
|
||||
*
|
||||
* This will also destroy the overlay canvas that the masked objects were
|
||||
* rendered to. The remaining canvas will not be cleared.
|
||||
* This will also destroy the overlay canvas that the masked objects
|
||||
* were rendered to. The remaining canvas will not be cleared.
|
||||
*
|
||||
* @return {MapRender} self
|
||||
* @return {LevelRender} self
|
||||
*/
|
||||
'public freeCanvas': function()
|
||||
{
|
||||
var c = this._ctxObj.canvas;
|
||||
const c = this._ctxObj.canvas;
|
||||
|
||||
// clear any running animations
|
||||
this._clearAnimation();
|
||||
|
@ -148,7 +150,8 @@ module.exports = Class( 'MapRender',
|
|||
*/
|
||||
'private _getObjCanvas': function()
|
||||
{
|
||||
var canvas = this._ctx.canvas,
|
||||
const canvas = this._ctx.canvas,
|
||||
document = this._getDocument( canvas ),
|
||||
canvas_obj = document.createElement( 'canvas' );
|
||||
|
||||
// mimic the dimensions and positions of the original canvas
|
||||
|
@ -166,25 +169,42 @@ module.exports = Class( 'MapRender',
|
|||
|
||||
|
||||
/**
|
||||
* Render the provided map
|
||||
* Get HTMLDocument node from element ELEMENT
|
||||
*
|
||||
* @param {Map} map map to render
|
||||
* ELEMENT must be on a DOM. This allows us to always reference the
|
||||
* proper document node without being coupled with the browser's
|
||||
* window.document, which may not be what we're interested in.
|
||||
*
|
||||
* @return {MapRender} self
|
||||
* @param {HTMLElement} element reference element
|
||||
*
|
||||
* @return {HTMLDocument} document node
|
||||
*/
|
||||
'public render': function( map, map_state )
|
||||
'private _getDocument': function( element )
|
||||
{
|
||||
if ( !( Class.isA( MapState, map_state ) ) )
|
||||
return ( element.parentElement === null )
|
||||
? element.parentNode
|
||||
: this._getDocument( element.parentElement );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Render the provided level
|
||||
*
|
||||
* @param {Level} level level to render
|
||||
*
|
||||
* @return {LevelRender} self
|
||||
*/
|
||||
'public render': function( level, level_state )
|
||||
{
|
||||
throw TypeError( 'Invalid MapState provided' );
|
||||
if ( !( Class.isA( LevelState, level_state ) ) )
|
||||
{
|
||||
throw TypeError( 'Invalid LevelState provided' );
|
||||
}
|
||||
|
||||
var objs = map.getObjects(),
|
||||
size = map.getDimensions(),
|
||||
omap = map.getObjectTileMap(),
|
||||
const objs = level.getObjects(),
|
||||
size = level.getDimensions(),
|
||||
sizex = size[ 0 ],
|
||||
sizey = size[ 1 ],
|
||||
i = objs.length,
|
||||
|
||||
// tiles to animate
|
||||
anim = [],
|
||||
|
@ -196,10 +216,10 @@ module.exports = Class( 'MapRender',
|
|||
|
||||
this._clearCanvases();
|
||||
|
||||
var _self = this;
|
||||
map_state.onChange( function( obj, pos )
|
||||
const _self = this;
|
||||
level_state.onChange( function( obj, pos )
|
||||
{
|
||||
var oid = objs[ pos ],
|
||||
const oid = objs[ pos ],
|
||||
tid = ( obj ) ? obj.getTid() : 'dirt',
|
||||
tile = ( _self._tiles[ tid ] || {} ).first,
|
||||
|
||||
|
@ -214,9 +234,9 @@ module.exports = Class( 'MapRender',
|
|||
}
|
||||
|
||||
// tunnels are handled a bit differently than other objects
|
||||
if ( map.isObjectTunnel( oid ) )
|
||||
if ( level.isObjectTunnel( oid ) )
|
||||
{
|
||||
_self._renderTunnel( x, y, map.getTunnelColor( oid ) );
|
||||
_self._renderTunnel( x, y, level.getTunnelColor( oid ) );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -229,10 +249,10 @@ module.exports = Class( 'MapRender',
|
|||
_self._drawTile( tile, x, y );
|
||||
} );
|
||||
|
||||
map_state.flush();
|
||||
level_state.flush();
|
||||
|
||||
// render each object (remember, we're dealing with columns, not rows;
|
||||
// see Map.getObjects())
|
||||
// render each object (remember, we're dealing with columns, not
|
||||
// rows; see Level.getObjects())
|
||||
|
||||
this._beginAnimation( anim );
|
||||
|
||||
|
@ -241,12 +261,12 @@ module.exports = Class( 'MapRender',
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve a vector representing the x and y position coordinates of a tile
|
||||
* position
|
||||
* Retrieve a vector representing the x and y position coordinates of a
|
||||
* tile position
|
||||
*
|
||||
* @param {number} pos tile position
|
||||
* @param {number} sizex number of horizontal tiles in map
|
||||
* @param {number} sizey number of vertical tiles in map
|
||||
* @param {number} sizex number of horizontal tiles in level
|
||||
* @param {number} sizey number of vertical tiles in level
|
||||
* @param {number} w tile width
|
||||
* @param {number} h tile height
|
||||
*
|
||||
|
@ -264,26 +284,27 @@ module.exports = Class( 'MapRender',
|
|||
/**
|
||||
* Clears overlay canvas
|
||||
*
|
||||
* This should be used before first rendering a map to ensure that any
|
||||
* artifacts from previous map renderings will be erased.
|
||||
* This should be used before first rendering a level to ensure that any
|
||||
* artifacts from previous level renderings will be erased.
|
||||
*
|
||||
* We need only clear the overlay canvas, because the lower canvas will
|
||||
* always be overwritten with tiles in every location. Because none of the
|
||||
* tiles written to the lower canvas are masked, nothing from the previous
|
||||
* render would ever peek through (of course, putImageData() would overwrite
|
||||
* it even if that were the case). As such, clearing the lower canvas would
|
||||
* simply be a waste of time and only serve to degrade performance
|
||||
* (especially if this is being used with maps larger than the classic
|
||||
* 16x16).
|
||||
* always be overwritten with tiles in every location. Because none of
|
||||
* the tiles written to the lower canvas are masked, nothing from the
|
||||
* previous render would ever peek through (of course, putImageData()
|
||||
* would overwrite it even if that were the case). As such, clearing the
|
||||
* lower canvas would simply be a waste of time and only serve to
|
||||
* degrade performance (especially if this is being used with levels
|
||||
* larger than the classic 16x16).
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _clearCanvases': function()
|
||||
{
|
||||
var ctx = this._ctxObj,
|
||||
const ctx = this._ctxObj,
|
||||
c = ctx.canvas;
|
||||
|
||||
// we need only clear the overlay (to which masked tiles are rendered)
|
||||
// we need only clear the overlay (to which masked tiles are
|
||||
// rendered)
|
||||
ctx.clearRect( 0, 0, c.width, c.height );
|
||||
},
|
||||
|
||||
|
@ -297,7 +318,7 @@ module.exports = Class( 'MapRender',
|
|||
*/
|
||||
'private _canAnimate': function( tid )
|
||||
{
|
||||
var tdata = this._tiles[ tid ];
|
||||
const tdata = this._tiles[ tid ];
|
||||
return ( tdata.next !== tdata );
|
||||
},
|
||||
|
||||
|
@ -305,9 +326,10 @@ module.exports = Class( 'MapRender',
|
|||
/**
|
||||
* Draw the tile identified by the given id
|
||||
*
|
||||
* The tile will be drawn to the appropriate canvas depending on whether or
|
||||
* not it has been masked. If it does have a mask, it will be drawn to the
|
||||
* overlaying canvas and the dirt tile will be drawn underneath it.
|
||||
* The tile will be drawn to the appropriate canvas depending on whether
|
||||
* or not it has been masked. If it does have a mask, it will be drawn
|
||||
* to the overlaying canvas and the dirt tile will be drawn underneath
|
||||
* it.
|
||||
*
|
||||
* @param {string} tid tile id
|
||||
* @param {number} x left position
|
||||
|
@ -317,7 +339,7 @@ module.exports = Class( 'MapRender',
|
|||
*/
|
||||
'private _drawTile': function( tile, x, y )
|
||||
{
|
||||
var ctx = ( tile.masked ) ? this._ctxObj : this._ctx;
|
||||
const ctx = ( tile.masked ) ? this._ctxObj : this._ctx;
|
||||
|
||||
ctx.putImageData( tile.data, x, y );
|
||||
|
||||
|
@ -338,8 +360,8 @@ module.exports = Class( 'MapRender',
|
|||
* Render the given tunnel
|
||||
*
|
||||
* The tunnel background color (which will peek through the mask) is
|
||||
* rendered to the base canvas, whereas the tunnel tile itself is rendered
|
||||
* on the overlaying canvas.
|
||||
* rendered to the base canvas, whereas the tunnel tile itself is
|
||||
* rendered on the overlaying canvas.
|
||||
*
|
||||
* @param {number} x left position
|
||||
* @param {number} y top position
|
||||
|
@ -349,7 +371,7 @@ module.exports = Class( 'MapRender',
|
|||
*/
|
||||
'private _renderTunnel': function( x, y, color )
|
||||
{
|
||||
var tdata = this._tiles.tunnel.data;
|
||||
const tdata = this._tiles.tunnel.data;
|
||||
|
||||
// fill tile with the appropriate background color for this tile
|
||||
this._ctx.fillStyle = color;
|
||||
|
@ -363,8 +385,8 @@ module.exports = Class( 'MapRender',
|
|||
/**
|
||||
* Begin basic tile animation
|
||||
*
|
||||
* At each animation interval, each tile will be advanced a single frame and
|
||||
* rendered atop of the previous.
|
||||
* At each animation interval, each tile will be advanced a single frame
|
||||
* and rendered atop of the previous.
|
||||
*
|
||||
* @param {Array.<Array.<Object,number,number>>} anim array of tiles to
|
||||
* animate; tdata,x,y
|
||||
|
@ -373,32 +395,32 @@ module.exports = Class( 'MapRender',
|
|||
*/
|
||||
'private _beginAnimation': function( anim )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
// clear any existing rendering animations
|
||||
this._clearAnimation();
|
||||
|
||||
return this._animTimer = setInterval( function()
|
||||
return ( this._animTimer = setInterval( function()
|
||||
{
|
||||
var i = anim.length;
|
||||
let i = anim.length;
|
||||
|
||||
while ( i-- )
|
||||
{
|
||||
var cur = anim[ i ];
|
||||
const cur = anim[ i ];
|
||||
|
||||
// draw next frame
|
||||
cur[ 0 ] = cur[ 0 ].next;
|
||||
_self._drawTile.apply( _self, anim[ i ] );
|
||||
}
|
||||
}, this.__self.$( '_ANIM_INTERVAL' ) );
|
||||
}, this.__self.$( '_ANIM_INTERVAL' ) ) );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Clear any running animation timers
|
||||
*
|
||||
* It is important that this be done when a MapRender instance is done being
|
||||
* used, or it will remain in memory indefinitely!
|
||||
* It is important that this be done when a LevelRender instance is done
|
||||
* being used, or it will remain in memory indefinitely!
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
|
@ -17,22 +17,20 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Maps (the term "level" is used in the game) are stored in a fixed-width LVL
|
||||
* file.
|
||||
* Levels are stored in a fixed-width LVL file.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class;
|
||||
|
||||
const Class = require( 'easejs' ).Class;
|
||||
|
||||
|
||||
/**
|
||||
* Handles delegation of LVL data
|
||||
*
|
||||
* This acts as a Map factory, leaving all processing responsibilities to the
|
||||
* Map instance. Consequently, any custom map format would be supported,
|
||||
* provided that the appropriate Map is handling it.
|
||||
* This acts as a Level factory, leaving all processing responsibilities to
|
||||
* the Level instance. Consequently, any custom level format would be
|
||||
* supported, provided that the appropriate Level is handling it.
|
||||
*/
|
||||
module.exports = Class( 'MapSet',
|
||||
module.exports = Class( 'LevelSet',
|
||||
{
|
||||
/**
|
||||
* Raw level set data (binary)
|
||||
|
@ -41,61 +39,62 @@ module.exports = Class( 'MapSet',
|
|||
'private _data': '',
|
||||
|
||||
/**
|
||||
* Constructor used to create new map instances
|
||||
* Constructor used to create new level instances
|
||||
* @type {Function}
|
||||
*/
|
||||
'private _mapCtor': null,
|
||||
'private _levelCtor': null,
|
||||
|
||||
/**
|
||||
* Number of maps in the given LVL data
|
||||
* Number of levels in the given LVL data
|
||||
* @type {number}
|
||||
*/
|
||||
'private _mapCount': 0,
|
||||
'private _levelCount': 0,
|
||||
|
||||
|
||||
/**
|
||||
* Initialize map set with LVL data and a Map constructor
|
||||
* Initialize level set with LVL data and a Level constructor
|
||||
*
|
||||
* The Map constructor is used in place of a separate Map factory.
|
||||
* The Level constructor is used in place of a separate Level factory.
|
||||
*
|
||||
* @param {string} data binary LVL data
|
||||
* @param {Map} map_ctor Map constructor
|
||||
* @param {Level} level_ctor Level constructor
|
||||
*/
|
||||
__construct: function( data, map_ctor )
|
||||
__construct: function( data, level_ctor )
|
||||
{
|
||||
this._data = ''+( data );
|
||||
this._mapCtor = map_ctor;
|
||||
this._levelCtor = level_ctor;
|
||||
|
||||
// perform a simple integrity check on the provided data
|
||||
this._mapDataCheck();
|
||||
this._levelDataCheck();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Perform a simple map data integrity check
|
||||
* Perform a simple level data integrity check
|
||||
*
|
||||
* This is intended to throw an error if we believe the LVL data to be
|
||||
* invalid, or if the LVL data is invalid for the given Map constructor.
|
||||
* The check will simply ensure that the map size (in bytes) divides into
|
||||
* the total LVL size (in bytes) without any remainder.
|
||||
* invalid, or if the LVL data is invalid for the given Level
|
||||
* constructor. The check will simply ensure that the level size (in
|
||||
* bytes) divides into the total LVL size (in bytes) without any
|
||||
* remainder.
|
||||
*
|
||||
* This is by no means fool-proof, but it should catch most.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _mapDataCheck': function()
|
||||
'private _levelDataCheck': function()
|
||||
{
|
||||
var n = ( this._data.length / this._mapCtor.getMapSize() );
|
||||
const n = ( this._data.length / this._levelCtor.getLevelSize() );
|
||||
|
||||
// if the result is not an integer, then it is either not an LVL, the
|
||||
// file is corrupt, or we were given the wrong Map constructor
|
||||
// if the result is not an integer, then it is either not an LVL,
|
||||
// the file is corrupt, or we were given the wrong Level constructor
|
||||
if ( n % 1 )
|
||||
{
|
||||
throw Error( 'Invalid or corrupt LVL data' );
|
||||
}
|
||||
|
||||
// we already calculated it, so we may as well store it
|
||||
this._mapCount = n;
|
||||
this._levelCount = n;
|
||||
},
|
||||
|
||||
|
||||
|
@ -104,19 +103,19 @@ module.exports = Class( 'MapSet',
|
|||
*
|
||||
* @param {number} id number of level to load, 1-indexed
|
||||
*/
|
||||
'public getMapByNumber': function( id )
|
||||
'public getLevelByNumber': function( id )
|
||||
{
|
||||
return this._mapCtor( this._data, id );
|
||||
return this._levelCtor( this._data, id );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the number of maps in the LVL file
|
||||
* Retrieve the number of levels in the LVL file
|
||||
*
|
||||
* @return {number} number of maps
|
||||
* @return {number} number of levels
|
||||
*/
|
||||
'public getMapCount': function()
|
||||
'public getLevelCount': function()
|
||||
{
|
||||
return this._mapCount;
|
||||
return this._levelCount;
|
||||
},
|
||||
} );
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Represents the current state of a map
|
||||
* Represents the current state of a level
|
||||
*
|
||||
* Copyright (C) 2012, 2015 Mike Gerwitz
|
||||
*
|
||||
|
@ -17,16 +17,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class,
|
||||
MapAction = require( './MapAction' ),
|
||||
GameObjectFactory = require( './GameObjectFactory' ),
|
||||
GameObject = require( './gameobjs/GameObject' );
|
||||
const Class = require( 'easejs' ).Class,
|
||||
LevelAction = require( './LevelAction' ),
|
||||
GameObjectFactory = require( '../GameObjectFactory' ),
|
||||
GameObject = require( '../gameobjs/GameObject' );
|
||||
|
||||
|
||||
/**
|
||||
* Represents the current state of a map
|
||||
* Represents the current state of a level
|
||||
*/
|
||||
module.exports = Class( 'MapState',
|
||||
module.exports = Class( 'LevelState',
|
||||
{
|
||||
/**
|
||||
* Game object factory
|
||||
|
@ -47,7 +47,7 @@ module.exports = Class( 'MapState',
|
|||
'private _player': null,
|
||||
|
||||
/**
|
||||
* Game objects representing every object on the map
|
||||
* Game objects representing every object on the level
|
||||
* @type {GameObject}
|
||||
*/
|
||||
'private _objs': [],
|
||||
|
@ -60,39 +60,41 @@ module.exports = Class( 'MapState',
|
|||
|
||||
|
||||
/**
|
||||
* Initializes map state with a given map and factory with which to create
|
||||
* game objects
|
||||
* Initializes level state with a given level and factory with which to
|
||||
* create game objects
|
||||
*
|
||||
* Game objects influence map state rules, therefore fundamental game logic
|
||||
* may be altered simply by passing in a custom GameObjectFactory instance.
|
||||
* Game objects influence level state rules, therefore fundamental game
|
||||
* logic may be altered simply by passing in a custom GameObjectFactory
|
||||
* instance.
|
||||
*
|
||||
* @param {Map} map game map
|
||||
* @param {Level} level game level
|
||||
* @param {GameObjectFactory} obj_factory game object factory
|
||||
*/
|
||||
__construct: function( map, obj_factory )
|
||||
__construct: function( level, obj_factory )
|
||||
{
|
||||
if ( !( Class.isA( GameObjectFactory, obj_factory ) ) )
|
||||
{
|
||||
throw TypeError( 'Invalid GameObjectFactory provided' );
|
||||
}
|
||||
|
||||
// initialize game objects based on the initial map state
|
||||
// initialize game objects based on the initial level state
|
||||
this._objFactory = obj_factory;
|
||||
this._initObjects( map.getObjects(), map.getObjectTileMap() );
|
||||
this._initObjects( level.getObjects(), level.getObjectTileLevel() );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Flush map state, triggering the change event for each game object
|
||||
* Flush level state, triggering the change event for each game object
|
||||
*
|
||||
* This may be used to perform an initial rendering or re-draw of the entire
|
||||
* map. Note that this should not be used to re-render the map after
|
||||
* movements or state changes, as that would not be performant (especially
|
||||
* since the map size could be arbitrarily large).
|
||||
* This may be used to perform an initial rendering or re-draw of the
|
||||
* entire level. Note that this should not be used to re-render the
|
||||
* level after movements or state changes, as that would not be
|
||||
* performant (especially since the level size could be arbitrarily
|
||||
* large).
|
||||
*/
|
||||
'public flush': function()
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
// emit the change event for each game object
|
||||
this._forEachObj( function( obj, pos )
|
||||
|
@ -105,20 +107,20 @@ module.exports = Class( 'MapState',
|
|||
/**
|
||||
* Register an object change callback
|
||||
*
|
||||
* Registers a continuation to be called when a game object changes state
|
||||
* (a state change may represent an object transforming into another, a
|
||||
* movement, or anything else that requires re-rendering).
|
||||
* Registers a continuation to be called when a game object changes
|
||||
* state (a state change may represent an object transforming into
|
||||
* another, a movement, or anything else that requires re-rendering).
|
||||
*
|
||||
* TODO: use event base
|
||||
*
|
||||
* The continuation will be passed the game object in its new state its tile
|
||||
* position. If the game object is null, then it is to be assumed that the
|
||||
* object no longer exists (e.g. has moved to another location) and should
|
||||
* be cleared.
|
||||
* The continuation will be passed the game object in its new state its
|
||||
* tile position. If the game object is null, then it is to be assumed
|
||||
* that the object no longer exists (e.g. has moved to another location)
|
||||
* and should be cleared.
|
||||
*
|
||||
* @param {function(GameObject,number)} callback continuation
|
||||
*
|
||||
* @return {MapState} self
|
||||
* @return {LevelState} self
|
||||
*/
|
||||
'public onChange': function( callback )
|
||||
{
|
||||
|
@ -130,11 +132,11 @@ module.exports = Class( 'MapState',
|
|||
/**
|
||||
* Emit a change event for the given object
|
||||
*
|
||||
* States that an object's state has changed; see the onChange() method for
|
||||
* additional information. A change may not necessarily imply that the
|
||||
* object itself has changed---the change may simply represent a new
|
||||
* position or---in the case of a null object---that the position has been
|
||||
* cleared of an object.
|
||||
* States that an object's state has changed; see the onChange() method
|
||||
* for additional information. A change may not necessarily imply that
|
||||
* the object itself has changed---the change may simply represent a new
|
||||
* position or---in the case of a null object---that the position has
|
||||
* been cleared of an object.
|
||||
*
|
||||
* @param {GameObject} obj the game object that has updated, or null
|
||||
* @param {number} pos tile position of the game object
|
||||
|
@ -143,8 +145,8 @@ module.exports = Class( 'MapState',
|
|||
*/
|
||||
'private _emitChange': function( obj, pos )
|
||||
{
|
||||
var i = -1,
|
||||
l = this._stateCallbacks.length;
|
||||
const l = this._stateCallbacks.length;
|
||||
let i = -1;
|
||||
|
||||
while ( ++i < l )
|
||||
{
|
||||
|
@ -153,7 +155,7 @@ module.exports = Class( 'MapState',
|
|||
|
||||
if ( obj === null )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
this._objs[ pos ].forEach( function( o )
|
||||
{
|
||||
if ( o === null ) return;
|
||||
|
@ -165,25 +167,25 @@ module.exports = Class( 'MapState',
|
|||
|
||||
|
||||
/**
|
||||
* Initialize game objects for the map's original (default) state
|
||||
* Initialize game objects for the level's original (default) state
|
||||
*
|
||||
* All necessary game objects will be created to represent all objects on
|
||||
* the map at its default state. Effectively, this creates the default map
|
||||
* state.
|
||||
* All necessary game objects will be created to represent all objects
|
||||
* on the level at its default state. Effectively, this creates the
|
||||
* default level state.
|
||||
*
|
||||
* @param {Array.<number>} objs game object data (object ids)
|
||||
* @param {Array.<string>} objmap map from object ids to their tile ids
|
||||
* @param {Array.<string>} objlevel level from object ids to their tile ids
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'private _initObjects': function( objs, objmap )
|
||||
'private _initObjects': function( objs, objlevel )
|
||||
{
|
||||
var i = objs.length;
|
||||
let i = objs.length;
|
||||
|
||||
while ( i-- )
|
||||
{
|
||||
var val = objs[ i ],
|
||||
obj = this._createObj( objmap[ val ] );
|
||||
const val = objs[ i ],
|
||||
obj = this._createObj( objlevel[ val ] );
|
||||
|
||||
this._objs[ i ] = [];
|
||||
this._addObj( obj, i );
|
||||
|
@ -198,14 +200,14 @@ module.exports = Class( 'MapState',
|
|||
|
||||
|
||||
/**
|
||||
* Creates a game object from a given tile id and (optionally) a previous
|
||||
* object
|
||||
* Creates a game object from a given tile id and (optionally) a
|
||||
* previous object
|
||||
*
|
||||
* A previous game object may be provided if state is to be transferred
|
||||
* between objects---that is, the transformation of one game object into
|
||||
* another may require a certain transfer of information. If no such game
|
||||
* object is provided, then the game object will be created with its default
|
||||
* state.
|
||||
* another may require a certain transfer of information. If no such
|
||||
* game object is provided, then the game object will be created with
|
||||
* its default state.
|
||||
*
|
||||
* @param {string} tid tile id
|
||||
* @param {GameObject?} from optional game object for state change data
|
||||
|
@ -214,9 +216,10 @@ module.exports = Class( 'MapState',
|
|||
*/
|
||||
'private _createObj': function( tid, from )
|
||||
{
|
||||
var obj = this._objFactory.createObject( tid );
|
||||
const obj = this._objFactory.createObject( tid );
|
||||
|
||||
// if a previous object was provided, copy over its mutable attributes
|
||||
// if a previous object was provided, copy over its mutable
|
||||
// attributes
|
||||
if ( from )
|
||||
{
|
||||
from.cloneTo( obj );
|
||||
|
@ -227,7 +230,7 @@ module.exports = Class( 'MapState',
|
|||
|
||||
|
||||
/**
|
||||
* Invokes a continuation for each game object on the map
|
||||
* Invokes a continuation for each game object on the level
|
||||
*
|
||||
* The continuation will be called with the game object and its tile
|
||||
* position.
|
||||
|
@ -251,7 +254,8 @@ module.exports = Class( 'MapState',
|
|||
/**
|
||||
* Add a game object at the given tile position
|
||||
*
|
||||
* It is an error to provide an invalid tile position or non-game object.
|
||||
* It is an error to provide an invalid tile position or non-game
|
||||
* object.
|
||||
*
|
||||
* @param {GameObject} obj game object to add
|
||||
* @param {number} pos tile position
|
||||
|
@ -273,22 +277,22 @@ module.exports = Class( 'MapState',
|
|||
* Replaces the given game object at the given tile position with a new game
|
||||
* object
|
||||
*
|
||||
* If the given game object can be found at the given tile position, then it
|
||||
* will be replaced with the new given game object. If it cannot be found,
|
||||
* then it will be added at the given tile position without any replacement
|
||||
* being made (effectively an append), unless the given replacement object
|
||||
* is null.
|
||||
* If the given game object can be found at the given tile position,
|
||||
* then it will be replaced with the new given game object. If it cannot
|
||||
* be found, then it will be added at the given tile position without
|
||||
* any replacement being made (effectively an append), unless the given
|
||||
* replacement object is null.
|
||||
*
|
||||
* If appending, the object will be placed in any open space (represented by
|
||||
* a null); ``open'' space is created when an object is replaced with null,
|
||||
* which has the effect of removing an object entirely (with no
|
||||
* replacement).
|
||||
* If appending, the object will be placed in any open space
|
||||
* (represented by a null); ``open'' space is created when an object is
|
||||
* replaced with null, which has the effect of removing an object
|
||||
* entirely (with no replacement).
|
||||
*
|
||||
* The change will result in the notification of any observers that have
|
||||
* registered continuations for game object state changes.
|
||||
*
|
||||
* It is an error to provide an unknown tile position or a replacement that
|
||||
* is not a game object.
|
||||
* It is an error to provide an unknown tile position or a replacement
|
||||
* that is not a game object.
|
||||
*
|
||||
* @param {GameObject} cur game object to replace (or null)
|
||||
* @param {GameObject} newobj replacement game object
|
||||
|
@ -301,8 +305,7 @@ module.exports = Class( 'MapState',
|
|||
*/
|
||||
'private _replaceObj': function( cur, newobj, pos )
|
||||
{
|
||||
var o = this._objs[ pos ],
|
||||
i = o.length;
|
||||
const o = this._objs[ pos ];
|
||||
|
||||
// type checks
|
||||
if ( !( Array.isArray( o ) ) )
|
||||
|
@ -316,10 +319,9 @@ module.exports = Class( 'MapState',
|
|||
throw TypeError( "Invalid GameObject or null provided: " + newobj );
|
||||
}
|
||||
|
||||
var free = null;
|
||||
let i = o.length,
|
||||
free = null;
|
||||
|
||||
( function()
|
||||
{
|
||||
while ( i-- )
|
||||
{
|
||||
if ( o[ i ] === cur )
|
||||
|
@ -338,7 +340,6 @@ module.exports = Class( 'MapState',
|
|||
if ( newobj === null ) return;
|
||||
else if ( free ) o[ i ] = newobj;
|
||||
else o.push( newobj );
|
||||
} )();
|
||||
|
||||
// notify observers of the change
|
||||
this._emitChange( newobj, pos );
|
||||
|
@ -369,8 +370,8 @@ module.exports = Class( 'MapState',
|
|||
/**
|
||||
* Move a game object from one tile position to another
|
||||
*
|
||||
* This has the direct effect of (a) removing the given game object from its
|
||||
* original position and (b) adding it to its new position.
|
||||
* This has the direct effect of (a) removing the given game object from
|
||||
* its original position and (b) adding it to its new position.
|
||||
*
|
||||
* It is an error to specify an object that is not a game object, or to
|
||||
* specify tile positions that do not exist.
|
||||
|
@ -395,8 +396,8 @@ module.exports = Class( 'MapState',
|
|||
* Initializes player game object and tile position references
|
||||
*
|
||||
* These references exist purely for performance, preventing the need to
|
||||
* scan for game objects that may represent the player. This also allows for
|
||||
* any arbitrary game object to represent the "player".
|
||||
* scan for game objects that may represent the player. This also allows
|
||||
* for any arbitrary game object to represent the "player".
|
||||
*
|
||||
* @param {GameObject} obj game object representing the player
|
||||
* @param {number} pos player tile position
|
||||
|
@ -411,11 +412,12 @@ module.exports = Class( 'MapState',
|
|||
/**
|
||||
* Changes the state of a game object at a given tile position
|
||||
*
|
||||
* The "state" of a game object is represented by the object's type. If the
|
||||
* state is unchanged, then no action will be taken. Otherwise, the game
|
||||
* object at the given tile position, if available, will be replaced with a
|
||||
* new game object representing the given state. If a game object cannot be
|
||||
* found at the given tile position, then it will be added.
|
||||
* The "state" of a game object is represented by the object's type. If
|
||||
* the state is unchanged, then no action will be taken. Otherwise, the
|
||||
* game object at the given tile position, if available, will be
|
||||
* replaced with a new game object representing the given state. If a
|
||||
* game object cannot be found at the given tile position, then it will
|
||||
* be added.
|
||||
*
|
||||
* @param {GameObject} cur current game object
|
||||
* @param {string} state new object state
|
||||
|
@ -435,7 +437,7 @@ module.exports = Class( 'MapState',
|
|||
}
|
||||
|
||||
// replace game object with a new one
|
||||
var newobj = this._createObj( state, cur );
|
||||
const newobj = this._createObj( state, cur );
|
||||
this._replaceObj( cur, newobj, pos );
|
||||
|
||||
return newobj;
|
||||
|
@ -448,8 +450,9 @@ module.exports = Class( 'MapState',
|
|||
* Produces a continuation that will perform a state change on the given
|
||||
* game object. The desired state should be passed to the continuation.
|
||||
*
|
||||
* If an additional continuation c is provided, it will be invoked after the
|
||||
* state change and may be used to process the resulting game object.
|
||||
* If an additional continuation c is provided, it will be invoked after
|
||||
* the state change and may be used to process the resulting game
|
||||
* object.
|
||||
*
|
||||
* @param {GameObject} cur game object to alter
|
||||
* @param {number} pos game object tile position
|
||||
|
@ -460,11 +463,11 @@ module.exports = Class( 'MapState',
|
|||
*/
|
||||
'private _createStateCallback': function( cur, pos, c )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
return function( state )
|
||||
{
|
||||
var newobj = _self._changeState( cur, state, pos );
|
||||
const newobj = _self._changeState( cur, state, pos );
|
||||
|
||||
if ( typeof c === 'function' )
|
||||
{
|
||||
|
@ -478,11 +481,11 @@ module.exports = Class( 'MapState',
|
|||
* Creates a callback to move a game object to a new tile position
|
||||
*
|
||||
* Produces a continuation that will perform a tile position move on the
|
||||
* given game object. The desired direction of movement should be passed to
|
||||
* the continuation (see MapAction for direction codes).
|
||||
* given game object. The desired direction of movement should be passed
|
||||
* to the continuation (see LevelAction for direction codes).
|
||||
*
|
||||
* If an additional continuation c is provided, it will be invoked after the
|
||||
* movement and may be used to process the new position.
|
||||
* If an additional continuation c is provided, it will be invoked after
|
||||
* the movement and may be used to process the new position.
|
||||
*
|
||||
* @param {GameObject} cur game object to alter
|
||||
* @param {number} pos game object tile position
|
||||
|
@ -493,7 +496,7 @@ module.exports = Class( 'MapState',
|
|||
*/
|
||||
'private _createMoveCallback': function( obj, pos, c )
|
||||
{
|
||||
var _self = this;
|
||||
const _self = this;
|
||||
|
||||
return function( dest )
|
||||
{
|
||||
|
@ -511,23 +514,23 @@ module.exports = Class( 'MapState',
|
|||
/**
|
||||
* Move a player in the given direction
|
||||
*
|
||||
* The directions, as defined in MapAction, are: 0:left, 1:up, 2:right,
|
||||
* 3:down.
|
||||
* The directions, as defined in LevelAction, are: 0:left, 1:up,
|
||||
* 2:right, 3:down.
|
||||
*
|
||||
* XXX: the bounds argument is temporary
|
||||
*
|
||||
* @param {number} direction direction code
|
||||
* @param {MapBounds} bounds map boundaries
|
||||
* @param {LevelBounds} bounds level boundaries
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
'public movePlayer': function( direction, bounds )
|
||||
{
|
||||
var _self = this,
|
||||
const _self = this,
|
||||
player = this._player;
|
||||
|
||||
// XXX: tightly coupled
|
||||
var action = MapAction(
|
||||
const action = LevelAction(
|
||||
bounds,
|
||||
this._createMoveCallback( player, this._playerPos, function( pos )
|
||||
{
|
||||
|
@ -535,10 +538,14 @@ module.exports = Class( 'MapState',
|
|||
} )
|
||||
);
|
||||
|
||||
var sc = this._createStateCallback( player, this._playerPos, function( o )
|
||||
const sc = this._createStateCallback(
|
||||
player,
|
||||
this._playerPos,
|
||||
function( o )
|
||||
{
|
||||
_self._player = o;
|
||||
} );
|
||||
}
|
||||
);
|
||||
|
||||
action.direction = direction;
|
||||
action.srcPos = this._playerPos;
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var Class = require( 'easejs' ).Class;
|
||||
const Class = require( 'easejs' ).Class;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -68,17 +68,16 @@ module.exports = Class( 'MenuBar',
|
|||
*/
|
||||
'private _initMenuActivation': function()
|
||||
{
|
||||
var _self = this,
|
||||
id = this._bar.id,
|
||||
const id = this._bar.id,
|
||||
menus = this._bar.parentNode.querySelectorAll( '#'+id+' > li > a' ),
|
||||
i = menus.length,
|
||||
|
||||
click = function( event )
|
||||
{
|
||||
event.target.parentNode.parentNode.className += ' focus';
|
||||
return false;
|
||||
};
|
||||
|
||||
let i = menus.length;
|
||||
|
||||
// on menu click, apply focus class (this allows the menu to be opened
|
||||
// properly on click rather than a simple CSS hover menu)
|
||||
while ( i-- )
|
||||
|
@ -103,7 +102,7 @@ module.exports = Class( 'MenuBar',
|
|||
*/
|
||||
'private _hookMenuMouseOut': function()
|
||||
{
|
||||
var _self = this,
|
||||
const _self = this,
|
||||
bar = this._bar;
|
||||
|
||||
this._bar.addEventListener( 'mouseout', function( event )
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var major = @MAJOR@,
|
||||
let major = @MAJOR@,
|
||||
minor = @MINOR@,
|
||||
rev = @REV@,
|
||||
suffix = '@SUFFIX@',
|
||||
|
|
|
@ -73,12 +73,12 @@
|
|||
Your browser does not support the canvas element.
|
||||
</canvas>
|
||||
|
||||
<canvas id="canvas_map" width="512" height="512"></canvas>
|
||||
<canvas id="canvas_level" width="512" height="512"></canvas>
|
||||
|
||||
<script src="../lasertank.js"></script>
|
||||
<script>
|
||||
var ctx = document.getElementById( 'canvas' ).getContext( '2d' ),
|
||||
ctxmap = document.getElementById( 'canvas_map' ).getContext( '2d' ),
|
||||
ctxlevel = document.getElementById( 'canvas_level' ).getContext( '2d' ),
|
||||
ltg = document.getElementById( 'ltg' ),
|
||||
lvl = document.getElementById( 'lvl' ),
|
||||
|
||||
|
@ -104,8 +104,11 @@
|
|||
reader.onload = function( event )
|
||||
{
|
||||
var loader = lasertank.LtgLoader(),
|
||||
masker = lasertank.TileMasker( lasertank.ClassicTileDfn() ),
|
||||
meta = loader.fromString( event.target.result ),
|
||||
masker = lasertank.TileMasker(
|
||||
lasertank.ClassicTileDfn(),
|
||||
document
|
||||
),
|
||||
|
||||
bmp_game = document.getElementById( 'bmp_game' ),
|
||||
bmp_mask = document.getElementById( 'bmp_mas' );
|
||||
|
@ -175,8 +178,8 @@
|
|||
}
|
||||
}, 200 );
|
||||
|
||||
// trigger map change (in case of page refresh or tile set change
|
||||
// after map is already loaded)
|
||||
// trigger level change (in case of page refresh or tile set change
|
||||
// after level is already loaded)
|
||||
lvlChange();
|
||||
} );
|
||||
|
||||
|
@ -201,18 +204,18 @@
|
|||
|
||||
reader.onload = function( event )
|
||||
{
|
||||
var map_set = lasertank.MapSet(
|
||||
var level_set = lasertank.level.LevelSet(
|
||||
event.target.result,
|
||||
lasertank.ClassicMap
|
||||
lasertank.level.ClassicLevel
|
||||
);
|
||||
|
||||
// clean up any previous render and create a new one to render the
|
||||
// chosen level with our chosen tile set
|
||||
render && render.freeCanvas();
|
||||
render = lasertank.MapRender( ctxmap, tile_set );
|
||||
render = lasertank.level.LevelRender( ctxlevel, tile_set );
|
||||
|
||||
var lvlsel = document.getElementById( 'lvl_id' ),
|
||||
count = map_set.getMapCount();
|
||||
count = level_set.getLevelCount();
|
||||
|
||||
lvlsel.innerHTML = '';
|
||||
for ( var i = 1; i <= count; i++ )
|
||||
|
@ -228,23 +231,23 @@
|
|||
|
||||
function lvlchange()
|
||||
{
|
||||
var map = map_set.getMapByNumber( lvlsel.selectedIndex + 1 );
|
||||
var level = level_set.getLevelByNumber( lvlsel.selectedIndex + 1 );
|
||||
render.render(
|
||||
map,
|
||||
lasertank.MapState(
|
||||
map,
|
||||
level,
|
||||
lasertank.level.LevelState(
|
||||
level,
|
||||
lasertank.ClassicGameObjectFactory()
|
||||
)
|
||||
);
|
||||
|
||||
document.getElementById( 'lvl_name' ).innerHTML =
|
||||
map.getMapName();
|
||||
level.getLevelName();
|
||||
document.getElementById( 'lvl_author' ).innerHTML =
|
||||
map.getMapAuthor();
|
||||
level.getLevelAuthor();
|
||||
document.getElementById( 'lvl_diff' ).innerHTML =
|
||||
map.getMapDifficulty();
|
||||
level.getLevelDifficulty();
|
||||
document.getElementById( 'lvl_hint' ).innerHTML =
|
||||
map.getMapHint();
|
||||
level.getLevelHint();
|
||||
};
|
||||
|
||||
lvlchange();
|
||||
|
|
Loading…
Reference in New Issue