/* * =========================================================================== * * Wolf3D Browser Version GPL Source Code * Copyright (C) 2012 id Software LLC, a ZeniMax Media company. * * This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). * * Wolf3D Browser Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Wolf3D Browser Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License version 2 * along with Wolf3D Browser Source Code. If not, see . * * If you have questions concerning this license, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. * * =========================================================================== */ /** * @namespace * @description Level management */ Wolf.Level = (function() { Wolf.setConsts({ WALL_TILE : 1, PUSHWALL_TILE : (1 << 20), DOOR_TILE : 2, SECRET_TILE : 4, DRESS_TILE : 8, BLOCK_TILE : 16, ACTOR_TILE : 32, DEADACTOR_TILE : 64, POWERUP_TILE : 128, AMBUSH_TILE : 256, EXIT_TILE : 512, SECRETLEVEL_TILE : 1024, ELEVATOR_TILE : (1 << 11), MAPHEADER_SIZE : 49, MAP_SIGNATURE : 0x21444921, TILE_IS_E_TURN : (1 << 12), TILE_IS_NE_TURN : (1 << 13), TILE_IS_N_TURN : (1 << 14), TILE_IS_NW_TURN : (1 << 15), TILE_IS_W_TURN : (1 << 16), TILE_IS_SW_TURN : (1 << 17), TILE_IS_S_TURN : (1 << 18), TILE_IS_SE_TURN : (1 << 19), MAX_POWERUPS : 1000 }); Wolf.setConsts({ SOLID_TILE : (Wolf.WALL_TILE | Wolf.BLOCK_TILE | Wolf.PUSHWALL_TILE), BLOCKS_MOVE_TILE : (Wolf.WALL_TILE | Wolf.BLOCK_TILE | Wolf.PUSHWALL_TILE | Wolf.ACTOR_TILE), WAYPOINT_TILE : (Wolf.TILE_IS_E_TURN | Wolf.TILE_IS_NE_TURN | Wolf.TILE_IS_N_TURN | Wolf.TILE_IS_NW_TURN | Wolf.TILE_IS_W_TURN | Wolf.TILE_IS_SW_TURN | Wolf.TILE_IS_S_TURN | Wolf.TILE_IS_SE_TURN ) }); var statinfo = [ [false, -1], // puddle spr1v [ true, -1], // Green Barrel " [ true, -1], // Table/chairs " [ true, -1], // Floor lamp " [false, -1], // Chandelier " [ true, -1], // Hanged man " [false, Wolf.pow_alpo], // Bad food " [ true, -1], // Red pillar " [ true, -1], // Tree spr2v [false, -1], // Skeleton flat " [ true, -1], // Sink " (SOD:gibs) [ true, -1], // Potted plant " [ true, -1], // Urn " [ true, -1], // Bare table " [false, -1], // Ceiling light " [false, -1], // Kitchen stuff " [ true, -1], // suit of armor spr3v [ true, -1], // Hanging cage " [ true, -1], // SkeletoninCage " [false, -1], // Skeleton relax " [false, Wolf.pow_key1], // Key 1 " [false, Wolf.pow_key2], // Key 2 " [ true, -1], // stuff (SOD:gibs) [false, -1], // stuff [false, Wolf.pow_food], // Good food spr4v [false, Wolf.pow_firstaid], // First aid " [false, Wolf.pow_clip], // Clip " [false, Wolf.pow_machinegun], // Machine gun " [false, Wolf.pow_chaingun], // Gatling gun " [false, Wolf.pow_cross], // Cross " [false, Wolf.pow_chalice], // Chalice " [false, Wolf.pow_bible], // Bible " [false, Wolf.pow_crown], // crown spr5v [false, Wolf.pow_fullheal], // one up " [false, Wolf.pow_gibs], // gibs " [ true, -1], // barrel " [ true, -1], // well " [ true, -1], // Empty well " [false, Wolf.pow_gibs], // Gibs 2 " [ true, -1], // flag " [ true, -1], // Call Apogee spr7v [false, -1], // junk " [false, -1], // junk " [false, -1], // junk " [false, -1], // pots " [ true, -1], // stove " (SOD:gibs) [ true, -1], // spears " (SOD:gibs) [false, -1] // vines " ]; for (var i=0;i= 0x5A && layer1 <= 0x5F) || layer1 == 0x64 || layer1 == 0x65) { // door level.tileMap[x][y] |= Wolf.DOOR_TILE; Wolf.Doors.spawn(level, x, y, layer1); level.areas[x][y] = -2; // door area } else { level.tileMap[x][y] |= Wolf.WALL_TILE; level.wallTexX[x][y] = (layer1-1) * 2 + 1; level.wallTexY[x][y] = (layer1-1) * 2; level.areas[x][y] = -1; // wall area if (layer1 == 0x15) { // elevator level.tileMap[x][y] |= Wolf.ELEVATOR_TILE; } } } else if (layer1 == 0x6a) { // Ambush floor tile level.tileMap[x][y] |= Wolf.AMBUSH_TILE; level.areas[x][y] = -3; // unknown area } else if (layer1 >= Wolf.FIRSTAREA && layer1 < (Wolf.FIRSTAREA + Wolf.NUMAREAS)) { // area if (layer1 == Wolf.FIRSTAREA) { // secret level level.tileMap[x][y] |= Wolf.SECRETLEVEL_TILE; } level.areas[x][y] = layer1 - Wolf.FIRSTAREA;// spawn area } else { level.areas[x][y] = -3; // unknown area } // End of the map data layer } } // JDC: try to replace all the unknown areas with an adjacent area, to // avoid the silent attack / no damage problem when you get an ambush // guard stuck on their original tile for (x=1;x<63;x++) { for (y=1;y<63;y++) { if (level.areas[x][y] != -3) { continue; } if (level.areas[x-1][y] >= 0) { level.areas[x][y] = level.areas[x-1][y]; } else if (level.areas[x+1][y] >= 0) { level.areas[x][y] = level.areas[x+1][y]; } else if (level.areas[x][y-1] >= 0) { level.areas[x][y] = level.areas[x][y-1]; } else if (level.areas[x+1][y+1] >= 0) { level.areas[x][y] = level.areas[x][y+1]; } } } Wolf.Doors.setAreas(level); return level; } /** * @description Read plane data from map data * @private * @param {object} file The file object * @param {number} offset The starting position * @param {number} length The length of the plane data * @param {number} rle The RLE tag * @returns {array} The plane data */ function readPlaneData(file, offset, length, rle) { file.position = offset; var expandedLength = Wolf.File.readUInt16(file), carmackData = Wolf.File.readBytes(file, length - 2), expandedData = carmackExpand(carmackData, expandedLength); return rlewExpand(expandedData.slice(1), 64*64*2, rle); } /** * @description Expand RLE data * @private * @param {array} source The source data * @param {number} length The length of the expanded data * @param {number} rlewtag The RLE tag * @returns {array} The expanded data */ function rlewExpand(source, length, rlewtag) { var value, count, i, end, /* W16 */ inptr = 0, outptr = 0, dest = []; end = outptr + (length >> 1); do { value = source[inptr++]; if (value != rlewtag) { // uncompressed dest[outptr++] = value; } else { // compressed string count = source[inptr++]; value = source[inptr++]; for (i=1;i<=count;++i) { dest[outptr++] = value; } } } while (outptr < end); return dest; } /** * @description Expand Carmackized data * @private * @param {array} source The source data * @param {number} length The length of the expanded data * @returns {array} The expanded data */ function carmackExpand(source, length) { var NEARTAG = 0xA7, FARTAG = 0xA8; var chhigh, offset, /* W32 */ copyptr, outptr, /* W16 */ inptr, /* W8 */ ch, count, /* W16 */ dest; length /= 2; inptr = 0; outptr = 0; dest = []; function W16(b, i) { return b[i] + (b[i+1] << 8); } while (length) { ch = source[inptr] + (source[inptr+1] << 8); //ch = W16(source, inptr); inptr += 2; chhigh = ch >> 8; if (chhigh == NEARTAG) { count = ch & 0xff; if (!count) { // have to insert a word containing the tag byte ch |= source[inptr++]; dest[outptr++] = ch; length--; } else { offset = source[inptr++]; copyptr = outptr - offset; length -= count; while (count--) { dest[outptr++] = dest[copyptr++]; } } } else if (chhigh == FARTAG) { count = ch & 0xff; if (!count) { // have to insert a word containing the tag byte ch |= source[inptr++]; dest[outptr++] = ch; length--; } else { offset = source[inptr] + (source[inptr+1] << 8); //offset = W16(source, inptr); inptr += 2; copyptr = offset; length -= count; while (count--) { dest[outptr++] = dest[copyptr++]; } } } else { dest[outptr++] = ch; length--; } } return dest; } /** * @description Load level data * @memberOf Wolf.Level * @param {string} filename The name of the level file. * @param {function} callback Called with the resulting level object. * @returns {object} The level object. */ function load(filename, callback) { Wolf.File.open(filename, Wolf.MapData, function(error, file) { var level; if (error) { callback(error); } try { level = parseMapData(file); } catch(error) { callback(error); return; } callback(null, level); }); } function reload(level) { return parseMapData(level.file); } /** * @description Spawn an object in the level at the specified position. * @private * @param {object} level The level object. * @param {number} type The object type. * @param {number} x The x coordinate. * @param {number} y The y coordinate. */ function spawnObj(level, type, x, y) { if (type >= 23 && type < 23 + statinfo.length) { // static object spawnStatic(level, type - 23, x, y); return; } switch (type) { case 0x13: // start N level.spawn.x = Wolf.TILE2POS(x); level.spawn.y = Wolf.TILE2POS(y); level.spawn.angle = Wolf.ANG_90; break; case 0x14: // start E level.spawn.x = Wolf.TILE2POS(x); level.spawn.y = Wolf.TILE2POS(y); level.spawn.angle = Wolf.ANG_0; break; case 0x15: // start S level.spawn.x = Wolf.TILE2POS(x); level.spawn.y = Wolf.TILE2POS(y); level.spawn.angle = Wolf.ANG_270; break; case 0x16: // start W level.spawn.x = Wolf.TILE2POS(x); level.spawn.y = Wolf.TILE2POS(y); level.spawn.angle = Wolf.ANG_180; break; case 0x5a: // turn E level.tileMap[x][y] |= Wolf.TILE_IS_E_TURN;//FIXME! break; case 0x5b: // turn NE level.tileMap[x][y] |= Wolf.TILE_IS_NE_TURN;//FIXME! break; case 0x5c: // turn N level.tileMap[x][y] |= Wolf.TILE_IS_N_TURN;//FIXME! break; case 0x5d: // turn NW level.tileMap[x][y] |= Wolf.TILE_IS_NW_TURN;//FIXME! break; case 0x5e: // turn W level.tileMap[x][y] |= Wolf.TILE_IS_W_TURN;//FIXME! break; case 0x5f: // turn SW level.tileMap[x][y] |= Wolf.TILE_IS_SW_TURN;//FIXME! break; case 0x60: // turn S level.tileMap[x][y] |= Wolf.TILE_IS_S_TURN;//FIXME! break; case 0x61: // turn SE level.tileMap[x][y] |= Wolf.TILE_IS_SE_TURN;//FIXME! break; case 0x62: // pushwall modifier level.tileMap[x][y] |= Wolf.SECRET_TILE; level.state.totalSecrets++; break; case 0x63: // Victory trigger level.tileMap[x][y] |= Wolf.EXIT_TILE; break; // spawn guards } // end of switch( type ) } /** * @description Spawn a static object at the specified position. * @private * @param {object} level The level object. * @param {number} type The static object type. * @param {number} x The x coordinate. * @param {number} y The y coordinate. */ function spawnStatic(level, type, x, y) { var sprite, pu; if (statinfo[type].powerup == -1 ) { if (statinfo[type].block) { // blocking static level.tileMap[x][y] |= Wolf.BLOCK_TILE; } else { // dressing static level.tileMap[x][y] |= Wolf.DRESS_TILE; } sprite = Wolf.Sprites.getNewSprite(level); if (!sprite) { return; } Wolf.Sprites.setPos(level, sprite, Wolf.TILE2POS(x), Wolf.TILE2POS(y), 0 ); Wolf.Sprites.setTex(level, sprite, 0, Wolf.SPR_STAT_0 + type); } else { pu = statinfo[type].powerup; Wolf.Powerups.spawn(level, x, y, pu); if (pu == Wolf.pow_cross || pu == Wolf.pow_chalice || pu == Wolf.pow_bible || pu == Wolf.pow_crown || pu == Wolf.pow_fullheal) { level.state.totalTreasure++; // FIXME: move this to Powerup_Spawn Function! } } } var cachedGuard = 0, cachedOfficer = 0, cachedSS = 0, cachedDog = 0, cachedMutant = 0, progress_bar = 0; /** * @description Spawn all actors and mark down special places. * @memberOf Wolf.Level * @param {object} level The level object. * @param {number} skill The difficulty level. */ function scanInfoPlane(level, skill) { var x, y, tile; cachedGuard = 0; cachedOfficer = 0; cachedSS = 0; cachedDog = 0; cachedMutant = 0; progress_bar = 0; for (y = 0;y < 64;++y) { for (x = 0;x < 64;++x) { tile = level.plane2[(63 - y) * 64 + x]; if (!tile) { continue; } switch (tile) { // guard case 180: case 181: case 182: case 183: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 144: case 145: case 146: case 147: if(skill < Wolf.gd_medium) { break; } tile -= 36; case 108: case 109: case 110: case 111: if (!cachedGuard) { Wolf.Sprites.cacheTextures(Wolf.SPR_GRD_S_1, Wolf.SPR_GRD_SHOOT3); cachedGuard = 1; } Wolf.Actors.spawnStand(level, skill, Wolf.en_guard, x, y, tile - 108); break; case 184: case 185: case 186: case 187: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 148: case 149: case 150: case 151: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 112: case 113: case 114: case 115: if (!cachedGuard) { Wolf.Sprites.cacheTextures(Wolf.SPR_GRD_S_1, Wolf.SPR_GRD_SHOOT3); cachedGuard = 1; } Wolf.Actors.spawnPatrol(level, skill, Wolf.en_guard, x, y, tile - 112); break; case 124: Wolf.Actors.spawnDeadGuard(level, skill, Wolf.en_guard, x, y); break; // officer case 188: case 189: case 190: case 191: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 152: case 153: case 154: case 155: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 116: case 117: case 118: case 119: if (!cachedOfficer) { Wolf.Sprites.cacheTextures(Wolf.SPR_OFC_S_1,Wolf.SPR_OFC_SHOOT3); cachedOfficer = 1; } Wolf.Actors.spawnStand(level, skill, Wolf.en_officer, x, y, tile - 116); break; case 192: case 193: case 194: case 195: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 156: case 157: case 158: case 159: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 120: case 121: case 122: case 123: if (!cachedOfficer) { Wolf.Sprites.cacheTextures(Wolf.SPR_OFC_S_1, Wolf.SPR_OFC_SHOOT3); cachedOfficer = 1; } Wolf.Actors.spawnPatrol(level, skill, Wolf.en_officer, x, y, tile - 120); break; // SS case 198: case 199: case 200: case 201: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 162: case 163: case 164: case 165: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 126: case 127: case 128: case 129: if (!cachedSS) { Wolf.Sprites.cacheTextures(Wolf.SPR_SS_S_1, Wolf.SPR_SS_SHOOT3); cachedSS = 1; } Wolf.Actors.spawnStand(level, skill, Wolf.en_ss, x, y, tile - 126); break; case 202: case 203: case 204: case 205: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 166: case 167: case 168: case 169: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 130: case 131: case 132: case 133: if (!cachedSS) { Wolf.Sprites.cacheTextures(Wolf.SPR_SS_S_1, Wolf.SPR_SS_SHOOT3); cachedSS = 1; } Wolf.Actors.spawnPatrol(level, skill, Wolf.en_ss, x, y, tile - 130); break; // dogs case 206: case 207: case 208: case 209: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 170: case 171: case 172: case 173: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 134: case 135: case 136: case 137: if (!cachedDog) { Wolf.Sprites.cacheTextures(Wolf.SPR_DOG_W1_1, Wolf.SPR_DOG_JUMP3); cachedDog = 1; } Wolf.Actors.spawnStand(level, skill, Wolf.en_dog, x, y, tile - 134); break; case 210: case 211: case 212: case 213: if (skill < Wolf.gd_hard) { break; } tile -= 36; case 174: case 175: case 176: case 177: if (skill < Wolf.gd_medium) { break; } tile -= 36; case 138: case 139: case 140: case 141: if (!cachedDog) { Wolf.Sprites.cacheTextures(Wolf.SPR_DOG_W1_1, Wolf.SPR_DOG_JUMP3); cachedDog = 1; } Wolf.Actors.spawnPatrol(level, skill, Wolf.en_dog, x, y, tile - 138); break; // bosses case 214: Wolf.Sprites.cacheTextures(Wolf.SPR_BOSS_W1, Wolf.SPR_BOSS_DIE3); Wolf.Actors.spawnBoss(level, skill, Wolf.en_boss, x, y); break; case 197: Wolf.Sprites.cacheTextures(Wolf.SPR_GRETEL_W1, Wolf.SPR_GRETEL_DIE3); Wolf.Actors.spawnBoss(level, skill, Wolf.en_gretel, x, y); break; case 215: Wolf.Sprites.cacheTextures(Wolf.SPR_GIFT_W1, Wolf.SPR_GIFT_DEAD); Wolf.Actors.spawnBoss(level, skill, Wolf.en_gift, x, y); break; case 179: Wolf.Sprites.cacheTextures(Wolf.SPR_FAT_W1, Wolf.SPR_FAT_DEAD); Wolf.Actors.spawnBoss(level, skill, Wolf.en_fat, x, y); break; case 196: Wolf.Sprites.cacheTextures(Wolf.SPR_SCHABB_W1, Wolf.SPR_HYPO4); Wolf.Actors.spawnBoss(level, skill, Wolf.en_schabbs, x, y); break; case 160: Wolf.Sprites.cacheTextures(Wolf.SPR_FAKE_W1, Wolf.SPR_FAKE_DEAD); Wolf.Actors.spawnBoss(level, skill, Wolf.en_fake, x, y); break; case 178: Wolf.Sprites.cacheTextures(Wolf.SPR_MECHA_W1, Wolf.SPR_HITLER_DIE7); Wolf.Actors.spawnBoss(level, skill, Wolf.en_mecha, x, y); break; // Spear case 106: Wolf.Sprites.cacheTextures(Wolf.SPR_SPECTRE_W1, Wolf.SPR_SPECTRE_F4); Wolf.Actors.spawnBoss(level, skill, Wolf.en_spectre, x, y); break; case 107: Wolf.Sprites.cacheTextures(Wolf.SPR_ANGEL_W1, Wolf.SPR_ANGEL_DEAD); Wolf.Actors.spawnBoss(level, skill, Wolf.en_angel, x, y); break; case 125: Wolf.Sprites.cacheTextures(Wolf.SPR_TRANS_W1, Wolf.SPR_TRANS_DIE3); Wolf.Actors.spawnBoss(level, skill, Wolf.en_trans, x, y); break; case 142: Wolf.Sprites.cacheTextures(Wolf.SPR_UBER_W1, Wolf.SPR_UBER_DEAD); Wolf.Actors.spawnBoss(level, skill, olf.en_uber, x, y); break; case 143: Wolf.Sprites.cacheTextures(Wolf.SPR_WILL_W1, Wolf.SPR_WILL_DEAD); Wolf.Actors.spawnBoss(level, skill, Wolf.en_will, x, y); break; case 161: Wolf.Sprites.cacheTextures(Wolf.SPR_DEATH_W1, Wolf.SPR_DEATH_DEAD); Wolf.Actors.spawnBoss(level, skill, Wolf.en_death, x, y); break; // mutants case 252: case 253: case 254: case 255: if (skill < Wolf.gd_hard) break; tile -= 18; case 234: case 235: case 236: case 237: if (skill < Wolf.gd_medium) break; tile -= 18; case 216: case 217: case 218: case 219: if (!cachedMutant) { Wolf.Sprites.cacheTextures(Wolf.SPR_MUT_S_1, Wolf.SPR_MUT_SHOOT4); cachedMutant = 1; } Wolf.Actors.spawnStand(level, skill, Wolf.en_mutant, x, y, tile - 216); break; case 256: case 257: case 258: case 259: if (skill < Wolf.gd_hard) break; tile -= 18; case 238: case 239: case 240: case 241: if (skill < Wolf.gd_medium ) break; tile -= 18; case 220: case 221: case 222: case 223: if (!cachedMutant) { Wolf.Sprites.cacheTextures(Wolf.SPR_MUT_S_1, Wolf.SPR_MUT_SHOOT4); cachedMutant = 1; } Wolf.Actors.spawnPatrol(level, skill, Wolf.en_mutant, x, y, tile - 220 ); break; // ghosts case 224: Wolf.Sprites.cacheTextures(Wolf.SPR_BLINKY_W1, Wolf.SPR_BLINKY_W2); Wolf.Actors.spawnGhosts(level, skill, Wolf.en_blinky, x, y); break; case 225: Wolf.Sprites.cacheTextures(Wolf.SPR_PINKY_W1, Wolf.SPR_PINKY_W2); Wolf.Actors.spawnGhosts(level, skill, Wolf.en_clyde, x, y); break; case 226: Wolf.Sprites.cacheTextures(Wolf.SPR_CLYDE_W1, Wolf.SPR_CLYDE_W2); Wolf.Actors.spawnGhosts(level, skill, Wolf.en_pinky, x, y); break; case 227: Wolf.Sprites.cacheTextures(Wolf.SPR_INKY_W1, Wolf.SPR_INKY_W2); Wolf.Actors.spawnGhosts(level, skill, Wolf.en_inky, x, y); break; } } } } /** * @description Check if there is a clear line of sight between 2 points. * @memberOf Wolf.Level * @param {number} x1 The x coordinate of point 1. * @param {number} y1 The y coordinate of point 1. * @param {number} x2 The x coordinate of point 2. * @param {number} y2 The y coordinate of point 2. * @param {object} level The level object. * @returns {boolean} True if a straight line between 2 points is unobstructed, otherwise false. */ function checkLine(x1, y1, x2, y2, level) { var xt1, yt1, xt2, yt2, /* tile positions */ x, y, /* current point in !tiles! */ xdist, ydist, xstep, ystep, /* Step value for each whole xy */ deltafrac, /* current point in !1/256 of tile! */ frac, /* Fractional xy stepper */ partial, /* how much to move in our direction to border */ intercept, /* Temp for door code */ FRACBITS = 8; /* Number of bits of fraction */ // get start & end tiles xt1 = x1 >> Wolf.TILESHIFT; yt1 = y1 >> Wolf.TILESHIFT; xt2 = x2 >> Wolf.TILESHIFT; yt2 = y2 >> Wolf.TILESHIFT; xdist = Math.abs(xt2 - xt1); // X distance in tiles ydist = Math.abs(yt2 - yt1); // Y distance in tiles // 1/256 tile precision (TILESHIFT is 16) x1 >>= FRACBITS; y1 >>= FRACBITS; x2 >>= FRACBITS; y2 >>= FRACBITS; if (xdist) { // always positive check only for 0 if (xt2 > xt1) { partial = 256 - (x1 & 0xff); xstep = 1; } else { partial = x1 & 0xff; xstep = -1; } deltafrac = Math.abs(x2 - x1); ystep = ((y2 - y1) << FRACBITS) / deltafrac; frac = y1 + ((ystep * partial) >> FRACBITS); x = xt1 + xstep; xt2 += xstep; do { y = frac >> FRACBITS; frac += ystep; // assert( x >= 0 && x < 64 && y >= 0 && y < 64 ); if (level.tileMap[x][y] & Wolf.WALL_TILE) { return false; // Wall is in path quitting! } if (level.tileMap[x][y] & Wolf.DOOR_TILE ) { // door, see if the door is open enough if (level.state.doorMap[x][y].action != Wolf.dr_open) { if (level.state.doorMap[x][y].action == Wolf.dr_closed) { return false; } // checking vertical doors in action: ->_I_ intercept = ((frac - ystep / 2) & 0xFF) >> 4; // 1/64 of tile if (intercept < (63 - level.state.doorMap[x][y].ticcount)) { return false; } } } x += xstep; } while (x != xt2); } if (ydist) { // always positive check only for 0 if (yt2 > yt1) { partial = 256 - (y1 & 0xff); ystep = 1; } else { partial = y1 & 0xff; ystep = -1; } deltafrac = Math.abs(y2 - y1); xstep = ((x2 - x1) << FRACBITS) / deltafrac; frac = x1 + ((xstep * partial) >> FRACBITS); y = yt1 + ystep; yt2 += ystep; do { x = frac >> FRACBITS; frac += xstep; //assert( x >= 0 && x < 64 && y >= 0 && y < 64 ); if (level.tileMap[x][y] & Wolf.WALL_TILE ) { return false; // Wall is in path quitting! } if (level.tileMap[x][y] & Wolf.DOOR_TILE) { // door, see if the door is open enough if (level.state.doorMap[x][y].action != Wolf.dr_open) { if (level.state.doorMap[x][y].action == Wolf.dr_closed ) { return false; } // checking vertical doors in action: ->_I_ intercept = ((frac - xstep / 2) & 0xFF) >> 4; // 1/64 of tile if (intercept < level.state.doorMap[x][y].ticcount) { return false; } } } y += ystep; } while (y != yt2); } return true; } return { load : load, reload : reload, scanInfoPlane : scanInfoPlane, checkLine : checkLine }; })();