Added LVL metadata retrieval methods to ClassicMap
parent
822e1e6d05
commit
f037dff705
|
@ -57,14 +57,41 @@ ltjs.ClassicMap = Class( 'ClassicMap' )
|
||||||
'private const _SIZE': 576,
|
'private const _SIZE': 576,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game object size
|
* Game object offset and size
|
||||||
*
|
*
|
||||||
* The game objects are stores as a 16x16 multi-dimensional signed char
|
* The game objects are stores as a 16x16 multi-dimensional signed char
|
||||||
* array (in the C sources).
|
* array (in the C sources).
|
||||||
*
|
*
|
||||||
* @type {number}
|
* @type {Array.<number>}
|
||||||
*/
|
*/
|
||||||
'private const _GOSIZE': 256,
|
'private const _GOSIZE': [ 0, 256 ],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset and length of map name
|
||||||
|
* @type {Array.<number>}
|
||||||
|
*/
|
||||||
|
'private const _NAMESIZE': [ 256, 31 ],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset and length of map hint
|
||||||
|
* @type {Array.<number>}
|
||||||
|
*/
|
||||||
|
'private const _HINTSIZE': [ 287, 256 ],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset and length of author name
|
||||||
|
* @type {Array.<number>}
|
||||||
|
*/
|
||||||
|
'private const _AUTHORSIZE': [ 543, 31 ],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset and length of difficulty level
|
||||||
|
*
|
||||||
|
* 16-bit integer, little-endian
|
||||||
|
*
|
||||||
|
* @type {Array.<number>}
|
||||||
|
*/
|
||||||
|
'private const _DIFFSIZE': [ 574, 2 ],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tunnel bitmask
|
* Tunnel bitmask
|
||||||
|
@ -102,6 +129,12 @@ ltjs.ClassicMap = Class( 'ClassicMap' )
|
||||||
*/
|
*/
|
||||||
'private _id': 0,
|
'private _id': 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset of beginning of map data in bytes
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
'private _offset': 0,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize map with map data and the given id
|
* Initialize map with map data and the given id
|
||||||
|
@ -113,6 +146,9 @@ ltjs.ClassicMap = Class( 'ClassicMap' )
|
||||||
{
|
{
|
||||||
this._data = ''+( data );
|
this._data = ''+( data );
|
||||||
this._id = +id;
|
this._id = +id;
|
||||||
|
|
||||||
|
// calculate map offset in LVL data
|
||||||
|
this._offset = ( this.__self.$( '_SIZE' ) * ( this._id - 1 ) );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,32 +160,15 @@ ltjs.ClassicMap = Class( 'ClassicMap' )
|
||||||
* game uses a multi-dimensional array [x][y], which creates an array of
|
* game uses a multi-dimensional array [x][y], which creates an array of
|
||||||
* columns (TPLAYFIELD, LTANK.H).
|
* columns (TPLAYFIELD, LTANK.H).
|
||||||
*
|
*
|
||||||
|
* 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
|
* @return {Array.<number>} array of game objects
|
||||||
*/
|
*/
|
||||||
'public getObjects': function()
|
'public getObjects': function()
|
||||||
{
|
{
|
||||||
// calculate offset in LVL file
|
var tiles = this._getDataSegment( '_GOSIZE', false ).split( '' ),
|
||||||
var offset = ( this.__self.$( '_SIZE' ) * ( this._id - 1 ) );
|
i = tiles.length;
|
||||||
return this._getMapData( offset );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the map data (game objects only) at the requested offset
|
|
||||||
*
|
|
||||||
* The object data at the requested position will be loaded and converted to
|
|
||||||
* integers (from a binary string).
|
|
||||||
*
|
|
||||||
* @param {number} offset offset of the requested map data
|
|
||||||
*
|
|
||||||
* @return {Array.<number>} converted map data
|
|
||||||
*/
|
|
||||||
'private _getMapData': function( offset )
|
|
||||||
{
|
|
||||||
var tiles = this._data.substr( offset, this.__self.$( '_GOSIZE' ) )
|
|
||||||
.split( '' ),
|
|
||||||
|
|
||||||
i = tiles.length;
|
|
||||||
|
|
||||||
while ( i-- )
|
while ( i-- )
|
||||||
{
|
{
|
||||||
|
@ -160,6 +179,25 @@ ltjs.ClassicMap = Class( 'ClassicMap' )
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve segment of data
|
||||||
|
*
|
||||||
|
* @param {string} name name of constant containing segment dfn
|
||||||
|
* @param {=boolean} stripnull whether to strip null bytes (default true)
|
||||||
|
*/
|
||||||
|
'private _getDataSegment': function( name, stripnull )
|
||||||
|
{
|
||||||
|
stripnull = ( arguments.length < 2 ) ? true : !!stripnull;
|
||||||
|
|
||||||
|
var s = this.__self.$( name ),
|
||||||
|
data = this._data.substr( ( this._offset + s[ 0 ] ), s[ 1 ] );
|
||||||
|
|
||||||
|
return ( stripnull )
|
||||||
|
? data.split( '\0' )[ 0 ]
|
||||||
|
: data;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve map dimensions
|
* Retrieve map dimensions
|
||||||
*
|
*
|
||||||
|
@ -223,6 +261,74 @@ ltjs.ClassicMap = Class( 'ClassicMap' )
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map name
|
||||||
|
*
|
||||||
|
* @return {string} map name
|
||||||
|
*/
|
||||||
|
'public getMapName': function()
|
||||||
|
{
|
||||||
|
return this._getDataSegment( '_NAMESIZE' );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map author name
|
||||||
|
*
|
||||||
|
* @return {string} map author name
|
||||||
|
*/
|
||||||
|
'public getMapAuthor': function()
|
||||||
|
{
|
||||||
|
return this._getDataSegment( '_AUTHORSIZE' );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map hint
|
||||||
|
*
|
||||||
|
* @return {string} map hint
|
||||||
|
*/
|
||||||
|
'public getMapHint': function()
|
||||||
|
{
|
||||||
|
return this._getDataSegment( '_HINTSIZE' );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map 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 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.
|
||||||
|
*
|
||||||
|
* @return {number} 0-indexed difficulty level
|
||||||
|
*/
|
||||||
|
'public getMapDifficulty': function()
|
||||||
|
{
|
||||||
|
var val = this._getDataSegment( '_DIFFSIZE', false ),
|
||||||
|
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.
|
||||||
|
return ( Math.log( n ) / Math.log( 2 ) );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve size of map in bytes
|
* Retrieve size of map in bytes
|
||||||
*
|
*
|
||||||
|
|
35
lib/Map.js
35
lib/Map.js
|
@ -103,6 +103,41 @@ ltjs.Map = Interface( 'Map',
|
||||||
'public isObjectTunnel': [ 'object_id' ],
|
'public isObjectTunnel': [ 'object_id' ],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map name
|
||||||
|
*
|
||||||
|
* @return {string} map name
|
||||||
|
*/
|
||||||
|
'public getMapName': [],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map author name
|
||||||
|
*
|
||||||
|
* @return {string} map author name
|
||||||
|
*/
|
||||||
|
'public getMapAuthor': [],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map hint
|
||||||
|
*
|
||||||
|
* @return {string} map hint
|
||||||
|
*/
|
||||||
|
'public getMapHint': [],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve map difficulty
|
||||||
|
*
|
||||||
|
* The map 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': [],
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve size of map in bytes
|
* Retrieve size of map in bytes
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue