Downloads containing level.function.js

Downloads
Name Author Game Mode Rating
WebJCS 1.3.3Featured Download djazz Utility 10 Download file

File preview

  1. var level = function (filedata, callback, onprogr, handleerror) {
  2.         if(filedata.length === 0) {
  3.                 handleerror('Trying to open an empty file');
  4.                 return;
  5.         }
  6.         var binary2array = function (str) {
  7.                 var l = str.length;
  8.                 var a = new Uint8Array(l);
  9.                 for(var i=0; i < l; i+=1) {
  10.                         a[i] = str.charCodeAt(i) & 0xFF;
  11.                 }
  12.                 return a;
  13.         };
  14.         var HEADER_SIZE = 262;
  15.         var HEADER_STRUCT =
  16.                 "A180Copyright/"+
  17.                 "A4Identifier/"+
  18.                 "A3PasswordHash/"+
  19.                 "CHideLevel/"+
  20.                 "a32LevelName/"+
  21.                 "vVersion/"+
  22.                 "VFileSize/"+
  23.                 "VCRC32/"+
  24.                 "VCSize1/"+
  25.                 "VUSize1/"+
  26.                 "VCSize2/"+
  27.                 "VUSize2/"+
  28.                 "VCSize3/"+
  29.                 "VUSize3/"+
  30.                 "VCSize4/"+
  31.                 "VUSize4";
  32.         var LEVEL_INFO_STRUCT = // By Stijn, modified by djazz
  33.                 'vJcsHorizontal/'+
  34.                 'vSecurityEnvelope1/'+
  35.                 'vJcsVertical/'+
  36.                 'vSecurityEnvelope2/'+
  37.                 'CSecEnvAndLayer/'+
  38.                 'CMinimumAmbient/'+
  39.                 'CStartingAmbient/'+
  40.                 'vAnimsUsed/'+
  41.                 'CSplitScreenDivider/'+
  42.                 'CIsItMultiplayer/'+
  43.                 'VStreamSize/'+
  44.                 'a32LevelName/'+
  45.                 'a32Tileset/'+
  46.                 'a32BonusLevel/'+
  47.                 'a32NextLevel/'+
  48.                 'a32SecretLevel/'+
  49.                 'a32MusicFile/'+
  50.                 'A8192HelpStrings/'+
  51.                 'V8LayerProperties/'+
  52.                 'C8LayerUnknown1/'+
  53.                 'C8IsLayerUsed/'+
  54.                 'V8LayerWidth/'+
  55.                 'V8JJ2LayerWidth/'+
  56.                 'V8LayerHeight/'+
  57.                 'l8LayerUnknown2/'+
  58.                 'V18LayerUnknown3/'+
  59.                 'l8LayerXSpeed/'+
  60.                 'l8LayerYSpeed/'+
  61.                 'l8LayerAutoXSpeed/'+
  62.                 'l8LayerAutoYSpeed/'+
  63.                 'C8LayerUnknown4/'+
  64.                 'C3LayerRGB1/'+
  65.                 'C3LayerRGB2/'+
  66.                 'C3LayerRGB3/'+
  67.                 'C3LayerRGB4/'+
  68.                 'C3LayerRGB5/'+
  69.                 'C3LayerRGB6/'+
  70.                 'C3LayerRGB7/'+
  71.                 'C3LayerRGB8/'+
  72.                 'vStaticTiles'
  73.         var ANIM_STRUCT =
  74.                 "vFramesBetweenCycles/"+
  75.                 "vRandomAdder/"+
  76.                 "vPingPongWait/"+
  77.                 "CIsItPingPong/"+
  78.                 "CFPS/"+
  79.                 "CFrames";
  80.        
  81.         var zfs = function (v) {v=v+'';if(v.length == 1) return "0"+v; return v;};
  82.         var trimNull = function (str) {
  83.                 var str = str.replace(/^\0\0*/, ''),
  84.                          ws = /\0/,
  85.                          i = str.length;
  86.                 while (ws.test(str.charAt(--i)));
  87.                 return str.slice(0, i + 1);
  88.         }
  89.         var unpack = function (formatCode, data) {
  90.                 formatCode = formatCode.replace(/\ /g,"").replace(/\n/g,"").replace(/\r/g,"").replace(/\t/g,"");
  91.                 var readOffset = 0;
  92.                 var adder = false;
  93.                 var struct = {};
  94.                 var bytelength = 0;
  95.                 var tmpbytes = "";
  96.                 var tmpvalue = "";
  97.                 var pusher = 1;
  98.                 formatCode = formatCode.split("/");
  99.                 var matches;
  100.                 for(var i=0; i < formatCode.length; i+=1) {
  101.                         if(formatCode==="") {
  102.                                 continue;
  103.                         }
  104.                         matches = formatCode[i].match(/(^[a-zA-Z])(\*|\d+)(\w+$)/);
  105.                         if(matches===null) {
  106.                                 matches = formatCode[i].match(/(^[a-zA-Z])(\*|\d+)(\w?$)/);
  107.                         }
  108.                         if(matches===null) {
  109.                                 matches = formatCode[i].match(/(^[a-zA-Z])(\*|\d?)(\w+$)/);
  110.                         }
  111.                         if(matches===null) {
  112.                                 matches = formatCode[i].match(/(^[a-zA-Z])(\*|\d?)(\w?$)/);
  113.                         }
  114.                         if(matches===null) {
  115.                                 throw new SyntaxError("'"+formatCode[i]+"' is an invalid formatcode");
  116.                                 return false;
  117.                         }
  118.                         adder = false;
  119.                         if(matches[2]==='*') {
  120.                                 adder = true;
  121.                                 matches[2] = data.length - readOffset;
  122.                                 formatCode = formatCode.splice(i, formatCode.length - i);
  123.                         }
  124.                         else if(matches[2]!=='') {
  125.                                 adder = true;
  126.                         }
  127.                         else {
  128.                                 matches[2] = "1";
  129.                         }
  130.  
  131.                         switch(matches[1]) {
  132.                                 case "a":
  133.                                 case "A":
  134.                                         if(readOffset > data.length) {
  135.                                                 return struct;
  136.                                         }
  137.                                         tmpvalue = data.substr(readOffset, +matches[2]);
  138.                                         if(matches[1]==="a") {
  139.                                                 tmpvalue = trimNull(tmpvalue);
  140.                                         }
  141.                                         if(matches[3].length > 0) {
  142.                                                 struct[matches[3]] = tmpvalue
  143.                                         }
  144.                                         else {
  145.                                                 struct[pusher+++''] = tmpvalue;
  146.                                         }
  147.                                         readOffset+=+matches[2];
  148.                                         break;
  149.                                 case "c":
  150.                                 case "C":
  151.                                 case "v":
  152.                                 case "V":
  153.                                 case "l":
  154.                                 case "x":
  155.                                         bytelength = 2;
  156.                                         if(matches[1]==='V' || matches[1]==='l') {
  157.                                                 bytelength = 4;
  158.                                         }
  159.                                         else if(matches[1].toUpperCase()==="C" || matches[1]==='x') {
  160.                                                 bytelength = 1;
  161.                                         }
  162.                                         if(adder) {
  163.                                                 struct[matches[3]] = [];
  164.                                         }
  165.                                         for(var j=0; j < matches[2]; j+=1) {
  166.                                                 if(readOffset+bytelength > data.length) {
  167.                                                         return struct;
  168.                                                 }
  169.                                                 tmpbytes = data.substr(readOffset, bytelength);
  170.                                                 tmpvalue = '';
  171.                                                 for(var b=bytelength-1; b >=0 ; b-=1) {
  172.                                                         tmpvalue += zfs(tmpbytes.charCodeAt(b).toString(16));
  173.                                                 }
  174.                                                 if(matches[1]!=='x') {
  175.                                                         tmpvalue = parseInt(tmpvalue, 16);
  176.                                                         if(matches[1]==='l' || matches[1]==='c') {
  177.                                                                 tmpvalue &= 0xFFFFFFFF;
  178.                                                         }
  179.                                                         if(matches[3].length > 0) {
  180.                                                                 if(adder) {
  181.                                                                         struct[matches[3]][j] = tmpvalue;
  182.                                                                 }
  183.                                                                 else {
  184.                                                                         struct[matches[3]] = tmpvalue;
  185.                                                                 }
  186.                                                         }
  187.                                                         else {
  188.                                                                 struct[pusher+++''] = tmpvalue;
  189.                                                         }
  190.                                                 }
  191.                        
  192.                                                 readOffset+=bytelength;
  193.                                         }
  194.                
  195.                                         break;
  196.        
  197.                         }
  198.                 }
  199.                 return struct;
  200.         }
  201.         var str_pad = function (input, pad_length, pad_string, pad_type) {
  202.                  // http://kevin.vanzonneveld.net
  203.                  // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  204.                  // + namespaced by: Michael White (http://getsprink.com)
  205.                  // +      input by: Marco van Oort
  206.                  // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
  207.                  // *     example 1: str_pad('Kevin van Zonneveld', 30, '-=', 'STR_PAD_LEFT');
  208.                  // *     returns 1: '-=-=-=-=-=-Kevin van Zonneveld'
  209.                  // *     example 2: str_pad('Kevin van Zonneveld', 30, '-', 'STR_PAD_BOTH');
  210.                  // *     returns 2: '------Kevin van Zonneveld-----'
  211.  
  212.                  var half = '', pad_to_go;
  213.  
  214.                  var str_pad_repeater = function (s, len) {
  215.                          var collect = '', i;
  216.  
  217.                          while (collect.length < len) {collect += s;}
  218.                          collect = collect.substr(0,len);
  219.  
  220.                          return collect;
  221.                  };
  222.  
  223.                  input += '';
  224.                  pad_string = pad_string !== undefined ? pad_string : ' ';
  225.                  
  226.                  if (pad_type != 'STR_PAD_LEFT' && pad_type != 'STR_PAD_RIGHT' && pad_type != 'STR_PAD_BOTH') { pad_type = 'STR_PAD_RIGHT'; }
  227.                  if ((pad_to_go = pad_length - input.length) > 0) {
  228.                          if (pad_type == 'STR_PAD_LEFT') { input = str_pad_repeater(pad_string, pad_to_go) + input; }
  229.                          else if (pad_type == 'STR_PAD_RIGHT') { input = input + str_pad_repeater(pad_string, pad_to_go); }
  230.                          else if (pad_type == 'STR_PAD_BOTH') {
  231.                              half = str_pad_repeater(pad_string, Math.ceil(pad_to_go/2));
  232.                              input = half + input + half;
  233.                              input = input.substr(0, pad_length);
  234.                          }
  235.                  }
  236.  
  237.                  return input;
  238.         };
  239.        
  240.         var output = {};
  241.         var i, j, x, y, w, h, l;
  242.         var progress = 0;
  243.         var pos;
  244.        
  245.         var timeStart = new Date();
  246.         var file = filedata;
  247.         var filedata = '';
  248.         Array.prototype.slice.apply(file).forEach(function (v, i, a) {
  249.                 filedata += String.fromCharCode(v);
  250.         });
  251.         // Get header
  252.         var HEADER_INFO = unpack(HEADER_STRUCT, filedata.substr(0, HEADER_SIZE));
  253.         progress+=0.05;
  254.         //console.log(crc32(filedata.substr(262)), HEADER_INFO.CRC32);
  255.         //self.postMessage({'progress': progress});
  256.         if(HEADER_INFO.Identifier !== 'LEVL') {
  257.                 //self.postMessage({'error': 'wrong identifier'});
  258.                 //self.close();
  259.                 handleerror('Wrong identifier:' +HEADER_INFO.Identifier+"\nIs the file a J2L level?");
  260.                 return;
  261.         }
  262.        
  263.         // Some good-to-have variables
  264.         var isTSF = (HEADER_INFO.Version === 0x203);
  265.         var MAX_TILES = isTSF ? 4096 : 1024;
  266.         // Get the streams
  267.         var offset = HEADER_SIZE;
  268.         var Streams = [];
  269.         for(i=0; i < 4; i+=1) {
  270.                 Streams[i] = filedata.substr(offset, HEADER_INFO["USize"+(i+1)]);
  271.                 offset += HEADER_INFO["USize"+(i+1)];
  272.                 progress+=0.1/4;
  273.                 //self.postMessage({'progress': progress});
  274.         }
  275.        
  276.         // Get level info & fix some values
  277.         var LEVEL_INFO = unpack(LEVEL_INFO_STRUCT, Streams[0]);
  278.         if(LEVEL_INFO.LayerXSpeed === undefined) {
  279.                 //self.postMessage({'error': JSON.stringify(LEVEL_INFO)});
  280.                 //self.close();
  281.                 handleerror("file corrupt");
  282.                 return;
  283.         }
  284.        
  285.         for(i=0; i < 8; i+=1) {
  286.                 LEVEL_INFO['LayerXSpeed'][i] /= 65536;
  287.                 LEVEL_INFO['LayerYSpeed'][i] /= 65536;
  288.                 LEVEL_INFO['LayerAutoXSpeed'][i] /= 65536;
  289.                 LEVEL_INFO['LayerAutoYSpeed'][i] /= 65536;
  290.                 progress+=0.05/8;
  291.                 //self.postMessage({'progress': progress});
  292.         }
  293.         LEVEL_INFO.HelpString = [];
  294.         for(i=0;i<16;i++) {
  295.                 LEVEL_INFO.HelpString[i] = trimNull(LEVEL_INFO['HelpStrings'].substr(i*512, 512));
  296.                 progress+=0.05/16;
  297.                 //self.postMessage({'progress': progress});
  298.         }
  299.        
  300.         // Tileset Properties
  301.         var tilesetPropertiesOffset = 8813;
  302.         var TilesetPropertiesStruct =
  303.                 "V"+MAX_TILES+"TileEvent/"+
  304.                 "C"+MAX_TILES+"IsEachTileFlipped/"+
  305.                 "C"+MAX_TILES+"TileType/"+
  306.                 "C"+MAX_TILES+"TileUnknown2";
  307.         var TilesetProperties = unpack(TilesetPropertiesStruct, Streams[0].substr(tilesetPropertiesOffset));
  308.        
  309.         // Animations
  310.         var animOffset = tilesetPropertiesOffset + MAX_TILES*7;
  311.         var ANIMS = [];
  312.         for(i=0; i < LEVEL_INFO.AnimsUsed; i+=1) {
  313.                 ANIMS[i] = unpack(ANIM_STRUCT, Streams[0].substr(animOffset + i*137, 137)); // 137 = 9 + 64*2
  314.                 ANIMS[i].Tiles = [];
  315.                 for(j=0; j < ANIMS[i].Frames; j+=1) {
  316.                         id = unpack("v", Streams[0].substr(animOffset + i*137 + 9 + j*2, 2))[1];
  317.                         ANIMS[i].Tiles[j] = {};
  318.                         ANIMS[i].Tiles[j]['flipped'] = false;
  319.                         ANIMS[i].Tiles[j]['animated'] = false;
  320.                         if(id > MAX_TILES) {
  321.                                 id -= MAX_TILES;
  322.                                 ANIMS[i].Tiles[j]['flipped'] = true;
  323.                         }
  324.                         if(id >= LEVEL_INFO['StaticTiles']) {
  325.                                 id -= LEVEL_INFO['StaticTiles'];
  326.                                 ANIMS[i].Tiles[j]['animated'] = true;
  327.                         }
  328.                         ANIMS[i].Tiles[j]['id'] = id;
  329.                 }
  330.                 progress+=0.05/LEVEL_INFO.AnimsUsed;
  331.                 //self.postMessage({'progress': progress});
  332.         }
  333.         var normalStreamLength = animOffset + LEVEL_INFO.AnimsUsed*137;
  334.         LEVEL_INFO.normalStreamLength = normalStreamLength;
  335.        
  336.         // Events
  337.         //var raw_events = unpack("V"+Streams[1].length/4+"Events", Streams[1]).Events;
  338.         var raw_events = new Uint32Array(binary2array(Streams[1]).buffer);
  339.         /*var EVENTS = [];
  340.         var len = Streams[1].length/4;
  341.         for(i=0; i < len; i+=1) {
  342.                 event = raw_events[i];
  343.                 EVENTS[i] = 0;
  344.                 progress+=0.1/len;
  345.                 if(i % 500 === 0) {
  346.                         //self.postMessage({'progress': progress});
  347.                 }
  348.                 if(event===0) continue;
  349.                 EVENTS[i] = event;
  350.                 //EVENTS[i]['Bitfield'] = str_pad(event.toString(2), 32, "0", 'STR_PAD_LEFT');
  351.                 //EVENTS[i]['Id'] = parseInt(EVENTS[i]['Bitfield'].substr(-8,8), 2);
  352.                 //EVENTS[i]['Stuff'] = substr($EVENTS[$key]['Bitfield'],-8-4,4);
  353.         }*/
  354.        
  355.         // Dictionary
  356.         var DICT = [];
  357.         //var dictList = unpack("v"+Streams[2].length/2+"Dict", Streams[2]).Dict;
  358.         var dictList = new Uint16Array(binary2array(Streams[2]).buffer);
  359.         var id = 0;
  360.         len = Streams[2].length/8;
  361.         for(i=0; i < len; i+=1) {
  362.                 DICT[i] = [];
  363.                 for(j=0; j < 4; j+=1) {
  364.                         DICT[i][j] = {};
  365.                         id = dictList[i*4+j];
  366.                         var oldid = id;
  367.                         DICT[i][j]['flipped'] = false;
  368.                         DICT[i][j]['animated'] = false;
  369.                         if(id > MAX_TILES) {
  370.                                 id -= MAX_TILES;
  371.                                 DICT[i][j]['flipped'] = true;
  372.                         }
  373.                         if(id >= LEVEL_INFO['StaticTiles']) {
  374.                                 id -= LEVEL_INFO['StaticTiles'];
  375.                                 DICT[i][j]['animated'] = true;
  376.                         }
  377.                         DICT[i][j]['id'] = id;
  378.                 }
  379.                 progress+=0.1/len;
  380.                 if(i % 100 === 0) {
  381.                         //self.postMessage({'progress': progress});
  382.                 }
  383.         }
  384.        
  385.         progress = 0.5;
  386.         //self.postMessage({'progress': progress});
  387.         var steps = 0;
  388.        
  389.         // Create the level
  390.         var LEVEL = [];
  391.         for(l=0; l < 8; l+=1) {
  392.                 LEVEL[l] = [];
  393.                 w = LEVEL_INFO.LayerWidth[l];
  394.                 h = LEVEL_INFO.LayerHeight[l];
  395.                 for(x=0; x < w; x+=1) {
  396.                         LEVEL[l][x] = [];
  397.                         for(y=0; y < h; y+=1) {
  398.                                 LEVEL[l][x][y] = {'flipped': false, 'animated': false, 'id': 0};
  399.                                 steps += 1;
  400.                         }
  401.                 }
  402.         }
  403.        
  404.         progress = 0.6;
  405.         //self.postMessage({'progress': progress});
  406.        
  407.         var wordOffset = 0;
  408.         var wordID = 0;
  409.         var realWidth = 0;
  410.         //var wordList = unpack("v"+Streams[3].length/2+"Words", Streams[3]).Words;
  411.         var wordList = new Uint16Array(binary2array(Streams[3]).buffer);
  412.        
  413.         progress+=0.1;
  414.         //self.postMessage({'progress': progress});
  415.        
  416.         for(l=0; l < 8; l+=1) {
  417.                 progress+=0.28/8;
  418.                 //self.postMessage({'progress': progress});
  419.                 if(LEVEL_INFO['IsLayerUsed'][l]===0) continue;
  420.                 w = LEVEL_INFO.LayerWidth[l];
  421.                 h = LEVEL_INFO.LayerHeight[l];
  422.                 realWidth = Math.ceil(w/4)*4;
  423.                 if(LEVEL_INFO.LayerProperties[l] & 1 === 1) {
  424.                         realWidth = Math.ceil(LEVEL_INFO.JJ2LayerWidth[l]/4)*4;
  425.                 }
  426.                 for(y=0; y < h; y+=1) {
  427.                         for(x=0; x < realWidth; x+=4) {
  428.                                         wordID = wordList[wordOffset];
  429.                                         for(t=0; t < 4; t+=1) {
  430.                                                 if(x+t >= w) break;
  431.                                                 LEVEL[l][x+t][y] = DICT[wordID][t];
  432.                                         }
  433.                                         wordOffset+=1;
  434.                         }
  435.                 }
  436.         }
  437.        
  438.         progress=1;
  439.         //self.postMessage({'progress': progress});
  440.         var timeEnd = new Date();
  441.        
  442.        
  443.         LEVEL_INFO.ExtraData = Streams[0].substr(normalStreamLength);
  444.        
  445.         output.HEADER_INFO = HEADER_INFO;
  446.         output.isTSF = isTSF;
  447.         output.MAX_TILES = MAX_TILES;
  448.         output.LEVEL_INFO = LEVEL_INFO;
  449.         output.TilesetProperties = TilesetProperties;
  450.         output.ANIMS = ANIMS;
  451.         output.EVENTS = raw_events;
  452.         output.LEVEL = LEVEL;
  453.         output.duration = (timeEnd-timeStart)/1000;
  454.         console.log("Level loaded in "+output.duration+" seconds");
  455.         callback(output);
  456.        
  457.        
  458.         /*var i, j, x, y, w, h, event, offset;
  459.         var work = new Worker('level.worker.js');
  460.         work.addEventListener("message", function (e) {
  461.                 var data = e.data;
  462.                 if(data.progress !== undefined && typeof onprogr === 'function') {
  463.                         onprogr(data.progress);
  464.                         //console.log(data.progress);
  465.                        
  466.                 }
  467.                 else if(data.error !== undefined) {
  468.                         handleerror(data.error);
  469.                 }
  470.                 else {
  471.                         onprogr(1);
  472.                         setTimeout(function () {
  473.                                 callback(data);
  474.                         }, 100);
  475.                 }
  476.                
  477.         }, false);
  478.         work.addEventListener("error", function (e) {
  479.                 handleerror(JSON.stringify(e));
  480.         }, false);
  481.         work.postMessage({'filedata': filedata});*/
  482. };
  483.