Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
WebJCS 1.3.3 | djazz | Utility | 10 |
"use strict";
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element) {
window.setTimeout(callback, 1000 / 10);
};
})();
// From http://stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
/*function sortObject(o) {
var sorted = {};
var key;
var a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort(function (a, b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
});
for (key = 0; key < a.length; key+=1) {
sorted[a[key]] = o[a[key]];
}
return sorted;
};*/
var alphaSort = function (a) {
a.sort(function (a, b) {
a = a.title;
b = b.title;
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
});
};
var trimNull = function (str) {
str = str.replace(/^\0\0*/, '');
var ws = /\0/;
var i = str.length;
while (ws.test(str.charAt(--i)));
return str.slice(0, i + 1);
};
function cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
if(typeof(obj[i]) === "object")
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
}
return clone;
};
var WebJCS = (function (global, undefined) {
var fs;
var createCookie = function (name, value, days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
global.document.cookie = name+"="+value+expires+"; path=/";
};
var readCookie = function (name) {
var nameEQ = name + "=";
var ca = global.document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return '';
};
var contentSection = global.document.getElementById('content');
var tilesetdiv = global.document.getElementById('tilesetdiv');
var layerdiv = global.document.querySelector("#layerdiv");
var layercanvas = global.document.getElementById("layercanvas");
var animsdrag = global.document.querySelector("#animsdrag");
animsdrag.isDragging = false;
var animsdiv = global.document.querySelector("#animsdiv");
var animscanvas = global.document.querySelector("#animscanvas");
var removeAnimFrame = global.document.querySelector("#removeAnimFrame");
var moveAnimUp = global.document.querySelector("#moveAnimUp");
var moveAnimDown = global.document.querySelector("#moveAnimDown");
var parallaxdrag = global.document.querySelector("#parallaxdrag");
parallaxdrag.isDragging = false;
var parallaxdiv = global.document.querySelector("#parallaxdiv");
var parallaxcanvas = global.document.querySelector("#parallaxcanvas");
var parallaxLight = global.document.getElementById('parallaxLight');
var pxLightOutput = global.document.getElementById('pxLightOutput');
var pxLightLevel = 100;
var lightcanvas = global.document.createElement('canvas');
var lightc = lightcanvas.getContext('2d');
var chatPanel = global.document.getElementById('chatPanel');
var chatResizer = global.document.getElementById('chatResizer');
var chatUserlist = global.document.getElementById('chatUserlist');
var chatContent = global.document.getElementById('chatContent');
var chatInput = global.document.getElementById('chatInput');
var chatSend = global.document.getElementById('chatSend');
var pingDiv = document.getElementById('ping');
var pingVal = document.getElementById('pingval');
var layerbuttons = global.document.querySelector("#layerbuttons");
var clearLayerButton = global.document.getElementById('clearLayerButton');
var layerpropertiesbutton = global.document.getElementById('layerpropertiesbutton');
var layerpropertiesform = global.document.forms['layerpropertiesform'];
var levelpropertiesform = global.document.forms['levelpropertiesform'];
var selecteventform = global.document.forms['selecteventform'];
var animpropertiesform = global.document.forms['animpropertiesform'];
var tmpHelpStrings;
var toolbarLayerName = global.document.getElementById('toolbarLayerName');
var lc = layercanvas.getContext("2d");
var pxc = parallaxcanvas.getContext("2d");
var anc = animscanvas.getContext("2d");
var lightBgColor = localStorage['WebJCS_lightBgColor'] || 'rgb(72, 48, 168)';
var darkBgColor = localStorage['WebJCS_darkBgColor'] || 'rgb(32, 24, 80)';
global.document.getElementById('lightBgColorPicker').textContent = lightBgColor;
global.document.getElementById('darkBgColorPicker').textContent = darkBgColor;
var fpsSpan = global.document.getElementById('fpsSpan');
var fps = 0;
var stats = new Stats();
stats.domElement = stats.getDomElement();
stats.domElement.style.position = 'absolute';
stats.domElement.style.right = '0px';
stats.domElement.style.bottom = '0px';
stats.domElement.style.zIndex = '0';
parallaxdiv.appendChild(stats.domElement);
var eventPointers = {
230: 240,
/*95: 234,
246: 234,
21: 130*/
};
var eventPointerCache = [];
var zoomlevelSpan = global.document.querySelector('#zoomlevel');
var frameOffset = 0;
var dynamicTileCache = [];
var layernames = ['Foreground layer #2', 'Foreground layer #1', 'Sprite foreground layer', 'Sprite layer', 'Background layer #1', 'Background layer #2', 'Background layer #3', 'Background layer'];
var fixJ2L = function () {
selectedTiles = [[{'id': 0, 'animated': false, 'flipped': false, 'event': 0}]];
selectedSource = 'tileset';
animSelection = false;
J2L = {
'fileName': 'Untitled.j2l',
'LEVEL_INFO':
{
'JcsHorizontal': 0,
'SecurityEnvelope1': 0,
'JcsVertical': 0,
'SecurityEnvelope2': 0,
'SecEnvAndLayer': 0,
'MinimumAmbient': 64,
'StartingAmbient': 64,
'AnimsUsed': 0,
'SplitScreenDivider': 0,
'IsItMultiplayer': 0,
'StreamSize': 0,
'LevelName': 'Untitled',
'Tileset': '',
'BonusLevel': '',
'NextLevel': '',
'SecretLevel': '',
'MusicFile': '',
'HelpString': ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
'LayerProperties': [0, 0, 0, 0, 0, 0, 0, 3],
'LayerUnknown1': [0, 0, 0, 0, 0, 0, 0, 0],
'IsLayerUsed': [0, 0, 0, 1, 0, 0, 0, 0],
'LayerWidth': [864, 576, 256, 256, 171, 114, 76, 8],
'JJ2LayerWidth': [864, 576, 256, 256, 171, 114, 76, 8],
'LayerHeight': [216, 144, 64, 64, 43, 29, 19, 8],
'LayerUnknown2': [-300, -200, -100, 0, 100, 200, 300, 400],
'LayerUnknown3': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'LayerXSpeed': [3.375, 2.25, 1, 1, 0.6666717529296875, 0.4444580078125, 0.2963104248046875, 0],
'LayerYSpeed': [3.375, 2.25, 1, 1, 0.6666717529296875, 0.4444580078125, 0.2963104248046875, 0],
'LayerAutoXSpeed': [0, 0, 0, 0, 0, 0, 0, 0],
'LayerAutoYSpeed': [0, 0, 0, 0, 0, 0, 0, 0],
'LayerUnknown4': [0, 0, 0, 0, 0, 0, 0, 0],
'LayerRGB1': [0, 0, 0],
'LayerRGB2': [0, 0, 0],
'LayerRGB3': [0, 0, 0],
'LayerRGB4': [0, 0, 0],
'LayerRGB5': [0, 0, 0],
'LayerRGB6': [0, 0, 0],
'LayerRGB7': [0, 0, 0],
'LayerRGB8': [0, 0, 0],
'StaticTiles': 1024
},
'HEADER_INFO':
{
'Copyright': 'Jazz Jackrabbit 2 Data File...',
'Identifier': 'LEVL',
'PasswordHash': 0,
'HideLevel': 0,
'LevelName': 'Untitled',
'Version': 513,
'FileSize': 0,
'CRC32': 0,
'CSize1': 0,
'USize1': 0,
'CSize2': 0,
'USize2': 0,
'CSize3': 0,
'USize3': 0,
'CSize4': 0,
'USize4': 0
},
'ANIMS': [],
'MAX_TILES': 1024,
'isTSF': false,
'LEVEL': [, , , , , , , ],
'TilesetProperties':
{
'TileEvent': [],
'TileUnknown1': [],
'TileType': [],
'TileUnknown2': []
}
};
J2L.EVENTS = new Uint32Array(J2L.LEVEL_INFO.LayerWidth[3]*J2L.LEVEL_INFO.LayerHeight[3]);
setTimeout(function () {
updateEventPointers();
}, 0);
var l = 8;
var x, y, w, h;
for(l=0; l < 8; l+=1) {
J2L.LEVEL[l] = [];
w = J2L.LEVEL_INFO.LayerWidth[l];
h = J2L.LEVEL_INFO.LayerHeight[l];
for(x=0; x < w; x+=1) {
J2L.LEVEL[l][x] = [];
for(y=0; y < h; y+=1) {
J2L.LEVEL[l][x][y] = {'flipped': false, 'animated': false, 'id': 0};
}
}
}
var i;
for(i=0; i < J2L.MAX_TILES; i+=1) {
J2L.TilesetProperties.TileEvent[i] = 0;
J2L.TilesetProperties.TileUnknown1[i] = 0;
J2L.TilesetProperties.TileType[i] = 0;
J2L.TilesetProperties.TileUnknown2[i] = 0;
}
global.document.title = "Jazz Creation Station - "+J2L.LEVEL_INFO.LevelName+" - "+J2L.fileName;
};
var J2L;
var J2T;
var currentLayer = 3;
var changeLayer = function (l) {
layerbuttons.childNodes[currentLayer].className = '';
layerbuttons.childNodes[l].className = 'selected';
currentLayer = l;
toolbarLayerName.textContent = "Layer "+(l+1)+": "+layernames[l];
layermenu[0].node.className = layermenu[1].node.className = layermenu[2].node.className = currentLayer === 3 ? '' : 'disabled';
};
var scrollbars = {
'layers':
{
gripPosition: [0, 0],
contentSize: [0, 0],
scrollSize: [0, 0],
gripSize: [0, 0],
scroll: [0, 0],
offset: [0, 0],
bar: ""
},
'anims':
{
gripPosition: [0, 0],
contentSize: [0, 0],
scrollSize: [0, 0],
gripSize: [0, 0],
scroll: [0, 0],
offset: [0, 0],
bar: ""
},
'tileset':
{
gripPosition: [0, 0],
contentSize: [0, 0],
scrollSize: [0, 0],
gripSize: [0, 0],
scroll: [0, 0],
offset: [0, 0],
bar: ""
}
};
var scrollingWhat = "";
var scrollarrow = new Image(); scrollarrow.src = "media/icons/scroll-arrow.png";
var unknownTile = new Image(); unknownTile.src = "media/images/unknown-tile.png";
var mousetarget = null;
var mousepos = false;
var mousedownpos = false;
var mousedownscroll = false;
var whichmouse = 0;
var tileSelection = false;
var animSelection = false;
var holdingShiftKey = false;
var holdingCtrlKey = false;
var holdingFlipKey = false;
var holdingTileTypeKey = false;
var isBSelecting = false;
var BSelectStart = [0, 0];
var BSelection = [0, 0, 0, 0];
var holdingBKey = false;
var windowFocus = true;
var selectedTiles = [[{'id': 0, 'animated': false, 'flipped': false, 'event': 0}]];
var selectedSource = 'tileset';
var selectedEvent = 0;
var selectEventPos = [0, 0, null];
var oldEvent = {'id': 0, 'params': []};
var starttime = 0;
var selectTileset = global.document.querySelector("#selectTileset");
var tilesetTypePicker = global.document.querySelector("#tilesetType");
var tilePositionDiv = global.document.querySelector("#tilePositionDiv");
var eventInfoSpan = global.document.querySelector("#eventInfoSpan");
var tilesetTypeSelected = 2;
var tilesetcanvas = global.document.querySelector("#tilesetcanvas");
var tilec = tilesetcanvas.getContext('2d');
var currentTileset = new Image();
var currentTilesetMask = new Image();
var zoomin = global.document.querySelector("#zoomin");
var zoomout = global.document.querySelector("#zoomout");
var zoomlevel = 1;
var tilesets = [];
var tile_url = "", mask_url = "";
var toggleMask = global.document.querySelector("#toggleMask");
var toggleEvents = global.document.querySelector("#toggleEvents");
var saveParallaxBtn = global.document.querySelector("#saveparallax");
var toggleParallaxEvents = global.document.querySelector("#toggleParallaxEvents");
var toggleTexturedBg = global.document.getElementById('toggleTexturedBg');
var toggleAnimMask = global.document.querySelector("#toggleAnimMask");
var showLayerMask = false;
var showLayerEvents = true;
var showParallaxEvents = true;
var showTexturedBg = true;
var showAnimMask = false;
var diffColors = ["white", "yellow", "red", "#F0F"];
var JCSini;
var ANIMS = false;
var undoStack = [];
var redoStack = [];
var toggleTileCacheVar = localStorage['WebJCS_toggleTileCache'] === '1';
var toggleEventLinksVar = localStorage['WebJCS_toggleEventLinks'] === '1';
var handleUndoRedo = function (newPart, isRedo) {
if(socket && socket.readyState === 1) {
sendUpdate(newPart);
}
switch(newPart.what) {
case 'layer':
newPart.selection = updateTiles(newPart.layer, newPart.startX, newPart.startY, newPart.width, newPart.height, newPart.selection, newPart.includeEmpty);
updateEventPointers();
break;
case 'event':
var oldEvt = 0;
oldEvt = J2L.EVENTS[newPart.x+J2L.LEVEL_INFO.LayerWidth[3]*newPart.y]
J2L.EVENTS[newPart.x+J2L.LEVEL_INFO.LayerWidth[3]*newPart.y] = newPart.event;
newPart.event = oldEvt;
updateEventPointers();
break;
default:
console.log('UNDO/REDO DEBUG:', newPart, undoStack, redoStack);
break;
}
};
var doUndo = function () {
if(undoStack.length === 0) return;
var newPart = undoStack.pop();
handleUndoRedo(newPart, false);
redoStack.push(newPart);
if(undoStack.length === 0) menuUndo.className = 'disabled';
menuRedo.className = '';
};
var doRedo = function () {
if(redoStack.length === 0) return;
var newPart = redoStack.pop();
handleUndoRedo(newPart, true);
undoStack.push(newPart);
if(redoStack.length === 0) menuRedo.className = 'disabled';
menuUndo.className = '';
};
var clearUndoHistory = function () {
menuUndo.className = 'disabled';
menuRedo.className = 'disabled';
undoStack = [];
redoStack = [];
};
var Popup = popup(global);
global.hidePopup = Popup.hide; // Can be accessed through buttons etc..
var menuNewLevel = function () {
Popup.hide();
Colorpicker.hide();
if(confirm("Are you sure you want to create a new level?")) {
//document.location.reload();
if(socket && socket.readyState === 1) {
sendUpdate({what: 'new'});
}
else {
fixJ2L();
changeTileset(0);
clearUndoHistory();
}
}
};
var menuOpenLevel = function () {
Popup.hide();
Colorpicker.hide();
getFileList(function (err, results) {
if(err) {
alert('Could not read list of files');
return;
}
global.document.forms['openlevelform'].reset();
Popup.open('openlevel');
var levellist = global.document.querySelector("#openlevel #levellist");
levellist.options.length = 0;
var i, l = results.length;
var levels = [];
for(i=0; i < l; i+=1) {
if(results[i].substr(-4, 4).toLowerCase() !== '.j2l') {
continue;
}
levels.push(results[i]);
}
levels.sort(function (a, b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
});
l = levels.length;
for(i=0; i < l; i+=1) {
levellist.add(new Option(levels[i], levels[i]), null);
}
});
};
makeMainMenu(global.document.getElementById('menubar'), [
{
name: 'File',
items: [
{name: 'New', action: menuNewLevel, key: 'Alt+N', icon: 'new'},
{name: 'Open...', action: menuOpenLevel, key: 'Ctrl+O', icon: 'open'},
,
{name: 'Save', action: function () {
writeLevel({save: true});
}, icon: 'save', disabled: true},
{name: 'Save As...', action: function () {
writeLevel({save: true, newfile: true});
}, key: 'Ctrl+Shift+S', icon: 'saveas'},
{name: 'Save & Run', action: function () {
writeLevel({run: true, save: true});
}, key: 'Ctrl+Shift+R', disabled: true},
{name: 'Run', action: function () {
writeLevel({run: true, save: false});
}, key: 'Ctrl+R', disabled: serverInfo.isCollab}
]
},
{
name: 'Tools',
items: [
{name: 'Undo', action: doUndo, disabled: true, id: 'menuUndo', key: 'Ctrl+Z'},
{name: 'Redo', action: doRedo, disabled: true, id: 'menuRedo', key: 'Ctrl+Shift+Z'},
,
{name: 'Level properties...', action: function () {
global.document.forms['levelpropertiesform'].reset();
Popup.open('levelproperties');
tmpHelpStrings = [];
for(var i=0; i < 16; i+=1) {
tmpHelpStrings[i] = J2L.LEVEL_INFO.HelpString[i];
}
var lpform = global.document.forms['levelpropertiesform'];
lpform.leveltitle.value = J2L.LEVEL_INFO.LevelName;
lpform.nextlevel.value = J2L.LEVEL_INFO.NextLevel;
lpform.secretlevel.value = J2L.LEVEL_INFO.SecretLevel;
lpform.bonuslevel.value = J2L.LEVEL_INFO.BonusLevel;
lpform.musicfile.value = J2L.LEVEL_INFO.MusicFile;
lpform.minlightslider.value = J2L.LEVEL_INFO.MinimumAmbient/0.64;
lpform.minlightnumber.value = Math.round(J2L.LEVEL_INFO.MinimumAmbient/0.64);
lpform.startlightslider.value = J2L.LEVEL_INFO.StartingAmbient/0.64;
lpform.startlightnumber.value = Math.round(J2L.LEVEL_INFO.StartingAmbient/0.64);
if(J2L.LEVEL_INFO.SplitScreenDivider > 0)
lpform.splitscreenradio[1].checked = true;
if(J2L.LEVEL_INFO.IsItMultiplayer > 0)
lpform.isMultiplayer.setAttribute('on');
else
lpform.isMultiplayer.setAttribute('off');
if(J2L.HEADER_INFO.HideLevel > 0)
lpform.hideLevel.setAttribute('on');
else
lpform.hideLevel.setAttribute('off');
helpStringEditor.value = tmpHelpStrings[0].replace(/\@/g, "\n");
updateHelpStringPreview();
}},
{name: 'Level password...', disabled: true},
,
{name: 'Settings', action: function () {
global.document.forms['settingsform'].reset();
Popup.open('settings');
var lightBgColorPicker = global.document.querySelector('#lightBgColorPicker');
var darkBgColorPicker = global.document.querySelector('#darkBgColorPicker');
lightBgColorPicker.onchange = function (color, cstr) {
lightBgColor = cstr;
localStorage['WebJCS_lightBgColor'] = cstr;
//redraw(0, true);
requestAnimFrame(function () {redraw(0, true);}, layercanvas);
};
lightBgColorPicker.onupdate = function (color, cstr) {
lightBgColor = cstr;
};
lightBgColorPicker.oncancel = function (oldcolor, cstr) {
lightBgColor = cstr;
};
darkBgColorPicker.onchange = function (color, cstr) {
darkBgColor = cstr;
localStorage['WebJCS_darkBgColor'] = cstr;
//redraw(0, true);
requestAnimFrame(function () {redraw(0, true);}, layercanvas);
};
darkBgColorPicker.onupdate = function (color, cstr) {
darkBgColor = cstr;
};
darkBgColorPicker.oncancel = function (oldcolor, cstr) {
darkBgColor = cstr;
};
var toggleTileCache = global.document.getElementById('toggleTileCache');
toggleTileCache.set(localStorage['WebJCS_toggleTileCache'] === '1');
toggleTileCache.addEventListener('click', function () {
localStorage['WebJCS_toggleTileCache'] = toggleTileCache.get()? '1' : '0';
toggleTileCacheVar = toggleTileCache.get();
}, false);
var toggleEventLinks = global.document.getElementById('toggleEventLinks');
toggleEventLinks.set(localStorage['WebJCS_toggleEventLinks'] !== '0');
toggleEventLinks.addEventListener('click', function () {
localStorage['WebJCS_toggleEventLinks'] = toggleEventLinks.get()? '1' : '0';
toggleEventLinksVar = toggleEventLinks.get();
}, false);
}/*, icon: 'HTML5_Performance_16'*/}
]
},
{
name: 'Help',
items: [
{name: 'Howto JCS', href: 'http://ninjadodo.net/htjcs/'},
{name: 'JcsRef', href: 'http://www.jazz2online.com/jcsref/index.php?&menu=topics'},
,
{name: 'About', action: function () {
Popup.open('about');
}}
]
}
]);
var menuUndo = document.getElementById('menuUndo');
var menuRedo = document.getElementById('menuRedo');
Popup.add('settings', 'settingspopup', function (res) {
});
Popup.add('openlevel', 'openlevel', function (res) {
Popup.open('loadinglevel');
if(res === 1) {
var openfieldlevel = global.document.querySelector('#openlevel #openfieldlevel');
if(openfieldlevel.files[0]===undefined) return;
var handle = openfieldlevel.files[0];
var fd = new FormData();
fd.append('level', handle);
uploadAndParse(fd, function (err, data) {
var datastr = '';
Array.prototype.slice.apply(data).forEach(function (v, i, a) {
datastr += String.fromCharCode(v);
});
switch(datastr) {
case "checksum error":
alert("Could not load level: Checksum error\nFile is broken");
Popup.close();
break;
default:
if(socket && socket.readyState === 1) {
/*socket.emit('level', {
data: datastr,
filename: handle.name
});*/
sendLevel(handle.name, data);
}
else {
loadlevel(data, handle.name);
clearUndoHistory();
}
break;
}
});
}
else if(res === 2) {
var levellist = global.document.querySelector('#openlevel #levellist');
if(levellist.selectedIndex > -1 && levellist.options[levellist.selectedIndex].value !== undefined) {
var filename = levellist.options[levellist.selectedIndex].value;
parseFile(filename, function (err, data) {
var datastr = '';
Array.prototype.slice.apply(data).forEach(function (v, i, a) {
datastr += String.fromCharCode(v);
});
if(socket && socket.readyState === 1) {
/*socket.emit('level', {
data: datastr,
filename: filename
});*/
sendLevel(filename, data);
}
else {
loadlevel(data, filename);
clearUndoHistory();
}
});
}
}
});
Popup.add('opentileset', 'opentileset', function (res) {
if(res.files[0]===undefined) return;
var handle = res.files[0];
var file;
var reader;
for(var i=0; i < res.files.length; i+=1) {
file = res.files[i];
if(file.fileName.toLowerCase().substr(-4, 4) === '.j2t') { // Check if it's a .j2t file
reader = new FileReader();
reader.onloadend = (function (file) {
return function (e) { // File content arrived
if(e.target.readyState !== FileReader.DONE) return;
var res = this.result;
if(res.substr(180, 4) === "TILE") { // Is it a tileset?
var tilesetTitle = trimNull(res.substr(180+4+4, 32)); // Get the title of the tileset
var v = res.substr(180+4+4+32, 2);
var buf = new ArrayBuffer(2);
var uint8 = new Uint8Array(buf);
var i;
for(i=0; i < 2; i+=1) {
uint8[i] = v.charCodeAt(i);
}
var ver = new Uint16Array(buf)[0];
fs.root.getFile(file.fileName, {create: true}, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
fileWriter.write(file);
var tileset = {'name': file.fileName, 'title': tilesetTitle, 'version': ver};
for(var i=0; i < tilesets.length; i+=1) {
if(tilesets[i].name === file.fileName) {
tilesets[i] = tileset;
break;
}
}
if(i === tilesets.length) {
tilesets.push(tileset);
}
var si = 0;
var oldTileset = "" || selectTileset.options[selectTileset.selectedIndex].value;
alphaSort(tilesets);
selectTileset.length = 1;
var opt;
for(i=0; i < tilesets.length; i+=1) {
opt = new Option(tilesets[i].title, tilesets[i].name);
if(tilesets[i].version === 513) {
opt.className = "TSF";
}
selectTileset.add(opt, null);
if(oldTileset === tilesets[i].name) {
si = i+1;
}
}
selectTileset.selectedIndex = si;
selectTileset.disabled = false;
}, fileSystemError);
}, fileSystemError);
}
};
})(file);
reader.readAsBinaryString(file);
}
}
});
Popup.add('about', 'about');
Popup.add('levelproperties', 'levelproperties', function (res) {
var lpform = levelpropertiesform;
J2L.LEVEL_INFO.LevelName = J2L.HEADER_INFO.LevelName = lpform.leveltitle.value.substring(0, 32);
J2L.LEVEL_INFO.NextLevel = lpform.nextlevel.value.substring(0, 32);
J2L.LEVEL_INFO.SecretLevel = lpform.secretlevel.value.substring(0, 32);
J2L.LEVEL_INFO.BonusLevel = lpform.bonuslevel.value.substring(0, 32);
J2L.LEVEL_INFO.MusicFile = lpform.musicfile.value.substring(0, 32);
J2L.LEVEL_INFO.MinimumAmbient = ~~Math.max((+lpform.minlightslider.value || 100)*0.64, 0);
J2L.LEVEL_INFO.StartingAmbient = ~~Math.max((+lpform.startlightslider.value || 100)*0.64, 0);
J2L.LEVEL_INFO.SplitScreenDivider = lpform.splitscreenradio[1].checked? 1 : 0;
J2L.LEVEL_INFO.IsItMultiplayer = lpform.isMultiplayer.getAttribute('on') !== null;
J2L.HEADER_INFO.HideLevel = lpform.hideLevel.getAttribute('on') !== null;
for(var i = 0; i < 16; i+=1) {
J2L.LEVEL_INFO.HelpString[i] = tmpHelpStrings[i].substring(0, 512);
}
global.document.title = "Jazz Creation Station - "+J2L.HEADER_INFO.LevelName+" - "+J2L.fileName;
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'levelprop',
levelName: J2L.LEVEL_INFO.LevelName,
nextLevel: J2L.LEVEL_INFO.NextLevel,
secretLevel: J2L.LEVEL_INFO.SecretLevel,
bonusLevel: J2L.LEVEL_INFO.BonusLevel,
musicFile: J2L.LEVEL_INFO.MusicFile,
minLight: J2L.LEVEL_INFO.MinimumAmbient,
startLight: J2L.LEVEL_INFO.StartingAmbient,
splitScreen: J2L.LEVEL_INFO.SplitScreenDivider,
multiPlayer: J2L.LEVEL_INFO.IsItMultiplayer,
hideLevel: J2L.HEADER_INFO.HideLevel ? 1 : 0,
helpString: J2L.LEVEL_INFO.HelpString
});
}
});
Popup.add('loadinglevel', 'loadinglevel', undefined, {closable: false});
Popup.add('loadingtileset', 'loadingtileset', undefined, {closable: false});
Popup.add('saving', 'saving', undefined, {closable: false});
Popup.add('layerproperties', 'layerproperties', function (res) {
});
Popup.add('animproperties', 'animproperties', function () {
var animId = Math.round(animpropertiesform.animID.value);
J2L.ANIMS[animId].FPS = Math.round(Math.min(255, animpropertiesform.animSpeedSlider.value));
J2L.ANIMS[animId].FramesBetweenCycles = Math.round(animpropertiesform.animFrameWait.value);
J2L.ANIMS[animId].RandomAdder = Math.round(animpropertiesform.animRandomAdder.value);
J2L.ANIMS[animId].PingPongWait = Math.round(animpropertiesform.animPingPongWait.value);
J2L.ANIMS[animId].IsItPingPong = animpropertiesform.animPingPong.get()? 1 : 0;
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'anims',
type: 'props',
anim: animId,
fps: J2L.ANIMS[animId].FPS,
frameWait: J2L.ANIMS[animId].FramesBetweenCycles,
randomAdder: J2L.ANIMS[animId].RandomAdder,
pingPongWait: J2L.ANIMS[animId].PingPongWait,
isItPingPong: J2L.ANIMS[animId].IsItPingPong
});
}
});
Popup.add('selectevent', 'selectevent', function () {
// selectEventPos[x, y, target];
var x = selectEventPos[0];
var y = selectEventPos[1];
updateEvent();
var evt = createEvent(oldEvent.id, selecteventform.eventType.selectedIndex, selecteventform.illuminate.getAttribute('on') !== null, 0, oldEvent.params);
var oldEvt = 0;
if(selectEventPos[2] === layercanvas) {
oldEvt = J2L.EVENTS[x+J2L.LEVEL_INFO.LayerWidth[3]*y];
J2L.EVENTS[x+J2L.LEVEL_INFO.LayerWidth[3]*y] = evt;
updateEventPointers();
}
else {
oldEvt = J2L.TilesetProperties.TileEvent[x+10*y];
J2L.TilesetProperties.TileEvent[x+10*y] = evt;
}
if(evt !== oldEvt && selectEventPos[2] === layercanvas) {
var oldPart = {
what: 'event',
event: oldEvt,
where: 'layer',
x: x,
y: y
};
undoStack.push(oldPart);
redoStack = [];
menuUndo.className = '';
menuRedo.className = 'disabled';
}
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'event',
event: evt,
where: selectEventPos[2] === layercanvas ? 'layer' : 'tileset',
x: x,
y: y
});
}
selectedEvent = evt;
oldEvent.id = 0;
oldEvent.params = [];
});
var selectEventList = global.document.getElementById('eventlist');
var selectEventFilter = selecteventform.eventfilter;
var selectEventListType = selecteventform.listtype;
var selectEventParameters = global.document.getElementById('selecteventparameters');
var createEvent = function (id, difficulty, illumi, unknownbit, parameters) {
if(selecteventform.generator.getAttribute('on') !== null) {
id = 216;
}
else if(id === 0) {
return 0;
}
var paramsamount = Math.min(JCSini.Events[id].length - 5, parameters.length);
var offset = 0;
var params = 0;
var paramArray = [];
var isSigned = false;
var bits = 0;
var pmax = 0, pmin = 0;
for(var i = 0; i < paramsamount; i+=1) {
bits = JCSini.Events[id][5+i][1];
isSigned = bits < 0;
bits = Math.abs(bits);
if(isSigned) {
pmax = Math.pow(2, bits-1)-1;
pmin = -Math.pow(2, bits-1);
}
else {
pmax = Math.pow(2, bits)-1;
pmin = 0;
}
parameters[i] = Math.max(Math.min(parameters[i], pmax), pmin);
if(isSigned && parameters[i] < 0)
parameters[i] = + Math.pow(2, bits) + parameters[i];
params |= parameters[i] << offset;
offset += bits;
}
return (id & 255) | ((difficulty & 3) << 8) | ((illumi & 1) << 10) | ((unknownbit & 1) << 11) | ((params) << 12);
};
var updateEventList = function (oldID) {
selectEventList.innerHTML = "";
var container = global.document.createElement('div');
if(selectEventListType.selectedIndex === 0) {
var listener = function (id) {
return function (e) {
oldEvent.id = id;
updateEvent();
};
};
var topnode = global.document.createElement('ul');
var oldEventNode = null;
topnode.className = "tree";
var counter = 0;
var recursive = function (subtree, parent) {
var listItem;
subtree.sort(function (a, b) {
if(typeof a === 'object') {
var c = a[0];
}
else {
var c = JCSini.Events[a][0];
}
if(typeof b === 'object') {
var d = b[0];
}
else {
var d = JCSini.Events[b][0];
}
if (c < d)
return -1;
if (c > d)
return 1;
return 0;
});
for(var i=0, l = subtree.length; i < l; i+=1) {
listItem = global.document.createElement('li');
if(typeof subtree[i] === 'object' && subtree[i].length > 0) {
var label = global.document.createElement('label')
label.textContent = subtree[i][0];
var id = 'selectEventTree_'+(counter++);
label.setAttribute('for', id);
listItem.appendChild(label);
var checkbox = global.document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = id;
listItem.appendChild(checkbox);
var subnode = global.document.createElement('ul');
listItem.appendChild(subnode);
recursive(subtree[i].slice(1, subtree[i].length), subnode);
}
else {
listItem.className = 'item';
var label = global.document.createElement('label');
var radio = global.document.createElement('input');
var id = 'selectEventTree_radio_'+subtree[i];
radio.type = 'radio';
radio.name = "selectEventTree_radio";
radio.id = id;
radio.addEventListener('change', listener(subtree[i]), false);
if(subtree[i] === oldID) {
oldEventNode = radio;
}
label.setAttribute('for', id);
if(subtree[i] === 'MCE') {
}
else {
var eventname = JCSini.Events[subtree[i]][0];
if(eventname.toLowerCase().indexOf(selectEventFilter.value.toLowerCase().trim()) === -1) continue;
label.innerHTML = eventname + " <span style=\"color: rgba(0, 0, 0, 0.15);\">("+subtree[i]+")</span>";
listItem.appendChild(radio);
listItem.appendChild(label);
}
}
parent.appendChild(listItem);
}
};
recursive(eventTree, topnode);
var spaceAbove = 0;
if(oldEventNode) {
oldEventNode.checked = true;
var stepCategory = oldEventNode;
while(stepCategory && stepCategory !== topnode) {
spaceAbove += stepCategory.offsetTop || 0;
stepCategory = stepCategory.parentNode;
if(stepCategory && stepCategory.childNodes[1] && stepCategory.childNodes[1].nodeName.toLowerCase() === 'input') {
stepCategory.childNodes[1].checked = true;
}
}
}
container.className = 'eventtree';
container.appendChild(topnode);
}
else {
var isAlpha = selectEventListType.selectedIndex === 1;
var topnode = global.document.createElement('select');
topnode.size = 2;
var eventlist = JCSini.Events.slice(0); // Make a copy
if(isAlpha) {
eventlist.sort(function (a, b) {
if(a[0] === b[0]) return 0;
else if(a[0] < b[0]) return -1;
else return 1;
});
}
var si = -1;
var len = 0;
var option;
for(var i=0; i < 256; i+=1) {
if(eventlist[i][0].toLowerCase().indexOf(selectEventFilter.value.toLowerCase().trim()) === -1) continue;
option = new Option(eventlist[i][0]+" ("+eventlist[i].id+")", eventlist[i].id);
topnode.add(option, null);
if(eventlist[i].id === oldID) {
si = len;
}
len+=1;
}
topnode.selectedIndex = si;
var selectScroll = si > -1
var listchange = function () {
if(this.selectedIndex > -1) {
oldEvent.id = this.options[this.selectedIndex].value;
updateEvent();
}
};
topnode.addEventListener('change', listchange, false);
topnode.addEventListener('keyup', listchange, false);
container.className = 'eventselect';
container.appendChild(topnode);
}
selectEventList.appendChild(container);
if(oldEventNode && oldEventNode.parentNode) {
oldEventNode.parentNode.scrollIntoView(false);
}
if(selectScroll) {
topnode.scrollTop = (si+1)*(topnode.scrollHeight / topnode.options.length) - topnode.offsetHeight/2;
}
};
selectEventFilter.addEventListener('input', function (e) {
updateEventList(oldEvent.id);
}, false);
(function () {
var listTypeChange = function (e) {
localStorage.selectEventListType = this.selectedIndex;
updateEventList(oldEvent.id);
};
selectEventListType.addEventListener('change', listTypeChange, false);
selectEventListType.addEventListener('keyup', listTypeChange, false);
})();
var updateEvent = function (firstOpen) {
var isGenerator = false;
var id = oldEvent.id;
if(selecteventform.generator.getAttribute('on') !== null) {
oldEvent.params[0] = id;
isGenerator = true;
id = 216;
}
var paramsamount = JCSini.Events[id].length - 5;
oldEvent.params.length = paramsamount;
var params = oldEvent.params;
var isSigned = false;
var bitcount = 0;
var pmax = 0;
var pmin = 0;
var paramHTML = [];
var oldParams = selectEventParameters.querySelectorAll('input');
for(var i=0; i < paramsamount; i+=1) {
bitcount = Math.abs(JCSini.Events[id][5+i][1]);
isSigned = JCSini.Events[id][5+i][1] < 0;
if(isSigned) {
pmax = Math.pow(2, bitcount-1)-1;
pmin = -Math.pow(2, bitcount-1);
}
else {
pmax = Math.pow(2, bitcount)-1;
pmin = 0;
}
var oldParam = params[i];
if(!firstOpen) {
params[i] = Math.max(Math.min(id === 216 && i === 0 ? params[i] : ((oldParams[oldParams.length-1-i] && +oldParams[oldParams.length-1-i].value)), pmax), pmin);
if(isNaN(params[i])) params[i] = oldParam;
}
if(isNaN(params[i])) params[i] = 0;
paramHTML.push("<div>"+JCSini.Events[id][5+i][0]+"</div><input type=number value='"+params[i]+"' min='"+pmin+"' max='"+pmax+"' step=1>");
}
selectEventParameters.innerHTML = paramHTML.reverse().join("");
var newParams = selectEventParameters.querySelectorAll('input');
var paramInput = function (i) {
return function (e) {
if(i === 0 && selecteventform.generator.getAttribute('on') !== null) {
oldEvent.id = +this.value;
}
};
};
var paramBlur = function (i) {
return function (e) {
if(i === 0 && selecteventform.generator.getAttribute('on') !== null) {
updateEventList(+this.value);
}
};
};
for(var i=0; i < newParams.length; i+=1) {
newParams[newParams.length-1-i].addEventListener('input', paramInput(i), false);
newParams[newParams.length-1-i].addEventListener('blur', paramBlur(i), false);
}
};
var tileReachable = function (offx, offy, target) {
if(target === layercanvas) {
var tilex = Math.floor((offx + scrollbars.layers.scroll[0])/(32*zoomlevel));
var tiley = Math.floor((offy + scrollbars.layers.scroll[1])/(32*zoomlevel));
var maxw = J2L.LEVEL_INFO.LayerWidth[currentLayer];
var maxh = J2L.LEVEL_INFO.LayerHeight[currentLayer];
var outside = mouseOnScrollbars('layers', layercanvas.offsetWidth, layercanvas.offsetHeight, offx, offy, {which: 3});
}
else {
var tilex = Math.floor(offx/32);
var tiley = Math.floor((offy + scrollbars.tileset.scroll[1])/32);
var maxw = 10;
var maxh = currentTileset.height/32;
var outside = mouseOnScrollbars('tileset', tilesetcanvas.offsetWidth, tilesetcanvas.offsetHeight, offx, offy, {which: 3});
}
if(tilex < 0 || tiley < 0 || tilex >= maxw || tiley >= maxh || outside) {
return false;
}
return [tilex, tiley];
};
var selectEvent = function (offx, offy, target) {
var tile = tileReachable(offx, offy, target);
if(!tile) return false;
if((target === layercanvas && currentLayer === 3) || target === tilesetcanvas) {
selectEventPos = [tile[0], tile[1], target];
var evt = target === layercanvas ? J2L.EVENTS[tile[0] + J2L.LEVEL_INFO.LayerWidth[3]*tile[1]] : J2L.TilesetProperties.TileEvent[tile[0] + 10*tile[1]];
var id = evt & 255;
var isGenerator = false;
var difficulty = (evt & (Math.pow(2, 10)-1)) >> 8; // bits 10-8 (2)
var illumi = (evt & (Math.pow(2, 11)-1)) >> 10 // bits 10-11 (1)
var unknownbit = (evt & (Math.pow(2, 12)-1)) >> 11 // bits 10-11 (1)
var params = (evt & (Math.pow(2, 32)-1)) >> 12; // bits 12-32 (20)
var paramsamount = JCSini.Events[id].length - 5;
var paramoffset = 0;
var param = 0;
var paramArray = [];
for(var i=0; i < paramsamount; i+=1) {
param = (params & (Math.pow(2, paramoffset+Math.abs(JCSini.Events[id][5+i][1]))-1)) >> paramoffset;
if(JCSini.Events[id][5+i][1] < 0 && param > Math.pow(2, Math.abs(JCSini.Events[id][5+i][1])-1))
param -= Math.pow(2, Math.abs(JCSini.Events[id][5+i][1]));
paramArray.push(param);
paramoffset += Math.abs(JCSini.Events[id][5+i][1]);
}
if(id === 216) {
id = paramArray[0];
isGenerator = true;
}
Popup.open('selectevent');
selecteventform.reset();
selectEventListType.selectedIndex = +localStorage.selectEventListType || 0;
if(isGenerator)
selecteventform.generator.setAttribute('on');
else
selecteventform.generator.removeAttribute('on');
if(illumi)
selecteventform.illuminate.setAttribute('on');
else
selecteventform.illuminate.removeAttribute('on');
selecteventform.eventType.selectedIndex = difficulty;
oldEvent.id = id;
oldEvent.params = paramArray;
updateEventList(id);
updateEvent(true);
}
else return false;
//alert("Select event is not implemented yet.");
};
var grabEvent = function (offx, offy, target) {
var tile = tileReachable(offx, offy, target);
if(!tile) return false;
if(target === layercanvas && currentLayer === 3) {
selectedEvent = J2L.EVENTS[tile[0] + J2L.LEVEL_INFO.LayerWidth[3]*tile[1]];
}
else if(target === tilesetcanvas) {
selectedEvent = J2L.TilesetProperties.TileEvent[tile[0] + 10*tile[1]];
}
else return false;
};
var pasteEvent = function (offx, offy, target) {
var tile = tileReachable(offx, offy, target);
if(!tile) return false;
var oldEvt = 0;
if(target === layercanvas && currentLayer === 3) {
oldEvt = J2L.EVENTS[tile[0] + J2L.LEVEL_INFO.LayerWidth[3]*tile[1]];
J2L.EVENTS[tile[0] + J2L.LEVEL_INFO.LayerWidth[3]*tile[1]] = selectedEvent;
updateEventPointers();
}
else if(target === tilesetcanvas) {
oldEvt = J2L.TilesetProperties.TileEvent[tile[0] + 10*tile[1]];
J2L.TilesetProperties.TileEvent[tile[0] + 10*tile[1]] = selectedEvent;
}
else return false;
if(selectedEvent !== oldEvt && target === layercanvas && currentLayer === 3) {
var oldPart = {
what: 'event',
event: oldEvt,
where: 'layer',
x: tile[0],
y: tile[1]
};
undoStack.push(oldPart);
redoStack = [];
menuUndo.className = '';
menuRedo.className = 'disabled';
}
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'event',
event: selectedEvent,
where: target === layercanvas ? 'layer' : 'tileset',
x: tile[0],
y: tile[1]
});
}
};
var changeTileType = function (type) {
return function (offx, offy, target) {
var tile = tileReachable(offx, offy, target);
if(!tile) return false;
var pos = tile[0] + 10*tile[1];
if(pos === 0) return;
J2L.TilesetProperties.TileType[pos] = type;
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'tiletype',
type: type,
pos: pos
});
}
};
};
var tilesetmenu = contextmenu.create('tileset', [
{title: 'Select event', onclick: selectEvent},
{title: 'Grab event', onclick: grabEvent},
{title: 'Paste event', onclick: pasteEvent},
,
{title: 'Tile type', sub: [
{title: 'Normal', onclick: changeTileType(0)},
{title: 'Translucent', onclick: changeTileType(1)},
{title: 'Caption', onclick: changeTileType(4)}
]}
]);
var layermenu = contextmenu.create('layer', [
{title: 'Select event', onclick: selectEvent},
{title: 'Grab event', onclick: grabEvent},
{title: 'Paste event', onclick: pasteEvent}
]);
contextmenu.bind(tilesetcanvas, 'tileset', function (offx, offy) {
var tile = tileReachable(offx, offy, tilesetcanvas);
if(!tile) {
return false;
}
else {
layermenu[0].node.className = layermenu[1].node.className = layermenu[2].node.className = currentLayer === 3 ? '' : 'disabled';
}
});
contextmenu.bind(layercanvas, 'layer', function (offx, offy) {
var tile = tileReachable(offx, offy, layercanvas);
if(!tile) {
return false;
}
else {
layermenu[0].node.className = layermenu[1].node.className = layermenu[2].node.className = currentLayer === 3 ? '' : 'disabled';
}
});
var helpStringSelect = levelpropertiesform.helpStringSelect;
var helpStringEditor = levelpropertiesform.helpStringEditor;
var helpStringPreviewCanvas = global.document.getElementById('helpStringPreviewCanvas');
var hsc = helpStringPreviewCanvas.getContext('2d');
var helpStringCharCount = global.document.getElementById('helpStringCharCount');
var updateHelpStringPreview = function (e) {
if(helpStringEditor.value.length > 512)
helpStringEditor.value = helpStringEditor.value.substring(0, 512);
helpStringCharCount.textContent = helpStringEditor.value.length;
var lines = helpStringEditor.value.replace(/\@/g, "\n").trim().split("\n");
var w = Math.max(jjFont.width(lines.join("@"), 1), 1);
var h = lines.length*16;
if(helpStringPreviewCanvas.width !== w)
helpStringPreviewCanvas.width = w;
if(helpStringPreviewCanvas.height !== h)
helpStringPreviewCanvas.height = h;
hsc.clearRect(0, 0, w, h);
jjFont.draw(hsc, lines.join("@"), 0, 0, 1, 'left', 0);
};
(function () { // Prepare
var sliders = global.document.querySelectorAll('#minlightslider, #startlightslider');
var finetuning = global.document.querySelectorAll('#minlightnumber, #startlightnumber');
var sliderChange = function (i) {
return function (e) {
finetuning[i].value = Math.round(this.value);
};
};
var tuneBlur = function (i) {
return function (e) {
var value = Math.min(Math.max(Math.round(finetuning[i].value*0.64)/0.64, 0), 127);
finetuning[i].value = Math.round(value);
sliders[i].value = value;
};
};
for(var i=0; i < sliders.length; i+=1) {
sliders[i].addEventListener('change', sliderChange(i), false);
finetuning[i].addEventListener('blur', tuneBlur(i), false);
}
animpropertiesform.animSpeedSlider.addEventListener('change', function (e) {
animpropertiesform.animSpeedInput.value = parseInt(this.value, 10);
}, false);
animpropertiesform.animSpeedInput.addEventListener('blur', function (e) {
animpropertiesform.animSpeedSlider.value = this.value = Math.max(0, Math.round(this.value));
}, false);
for(i=0; i < 8; i+=1) {
layerpropertiesform.editlayer.add(new Option((i+1)+": "+layernames[i], i), null);
}
var oldId = 0;
var changeHelpStringID = function () {
var id = helpStringSelect.selectedIndex;
helpStringEditor.value = tmpHelpStrings[id].replace(/\@/g, "\n");
updateHelpStringPreview();
oldId = id;
};
helpStringSelect.addEventListener('change', changeHelpStringID, false);
helpStringSelect.addEventListener('keyup', changeHelpStringID, false);
helpStringEditor.addEventListener('input', updateHelpStringPreview, false);
helpStringEditor.addEventListener('blur', function (e) {
tmpHelpStrings[helpStringSelect.selectedIndex] = helpStringEditor.value.replace(/\n/g, "@").substring(0, 512);
}, false);
var keys = ['#', '§', '|'];
var hsKeys = global.document.getElementById('helpStringKeys');
var node;
var hsKeyClick = function (i) {
var key = keys[i];
return function (e) {
var fullText = helpStringEditor.value;
var insertPos = helpStringEditor.selectionStart;
helpStringEditor.value = fullText.substring(0, insertPos) + key + fullText.substring(insertPos, fullText.length);
helpStringEditor.focus();
helpStringEditor.selectionStart += 1;
updateHelpStringPreview();
};
};
for(var i=0; i < keys.length; i+=1) {
node = global.document.createElement('input');
node.type = 'button';
node.value = keys[i];
node.addEventListener('click', hsKeyClick(i), false);
hsKeys.appendChild(node);
}
})();
var trimNull = function (str) {
var str = str.replace(/^\0\0*/, ''),
ws = /\0/,
i = str.length;
while (ws.test(str.charAt(--i)));
return str.slice(0, i + 1);
};
var unpackStruct = function (formatCodes, arr) {
var bufStr = '';
var byteArray = new Uint8Array(arr);
for(var i=0, l = byteArray.length; i < l; i+=1) {
bufStr += String.fromCharCode(byteArray[i]);
}
var buffer = new DataView(byteArray.buffer);
var offset = 0;
var output = {};
var part;
for(var i=0; i < formatCodes.length; i+=1) {
var len = formatCodes[i][2] === undefined ? 1 : Math.max(1, parseInt(formatCodes[i][2], 10));
var name = formatCodes[i][1];
var type = [
formatCodes[i][0].substring(0, 1),
parseInt(formatCodes[i][0].substring(1), 10)
];
var doArray = len > 1;
var bufFunc = 'get' + (type[0].toLowerCase()==='u'? 'Ui':'I') + 'nt' + type[1];
if(doArray) {
output[name] = [];
}
for(var j=0; j < len; j+=1) {
if(type[0].toLowerCase() === 'c') {
part = bufStr.substring(offset, offset+type[1]);
if(type[0] === 'C') {
part = trimNull(part);
}
offset += type[1];
}
else if(type[0].toLowerCase() === 'u' || type[0].toLowerCase() === 's') {
part = buffer[bufFunc](offset, true);
offset += type[1]/8; // number of bytes, not bits
}
if(doArray) {
output[name][j] = part;
}
else {
output[name] = part;
}
}
}
return output;
};
var packStruct = function (struct, data) {
'use strict';
var binaryData = [];
var dataCursor = 0;
struct.forEach(function (type, i) {
var repeats = 1;
if(typeof type === 'object') {
repeats = type[1];
type = type[0];
}
type = [
type.substring(0, 1),
parseInt(type.substring(1), 10)
];
var bufFunc = (type[0].toLowerCase()==='u'? 'Ui':'I') + 'nt' + type[1] + 'Array';
for(var j=0; j < repeats; j++) {
if(type[0].toLowerCase() === 'c') {
var part = data[dataCursor].substring(0, type[1]);
var pad = type[0] === 'C' ? 0x00 : 0x20;
for(var k=0; k < type[1]; k++) {
binaryData.push(part.charCodeAt(k) || pad);
}
}
else if(type[0].toLowerCase() === 'u' || type[0].toLowerCase() === 's') {
Array.prototype.slice.call(new Uint8Array(new global[bufFunc]([data[dataCursor]]).buffer), 0).forEach(function (x) {
binaryData.push(x);
});
}
dataCursor++;
}
});
return new Uint8Array(binaryData).buffer;
};
var getBinary = function (code, buf) {
var type = [
code.substring(0, 1),
parseInt(code.substring(1), 10)
];
buf = new Uint8Array(buf);
var bufFunc = (type[0].toLowerCase()==='u'? 'Ui':'I') + 'nt' + type[1] + 'Array';
return new global[bufFunc](buf.buffer)[0];
};
var hasLoadedApp = false;
var incDecClient = function (doInc) {
var X = new XMLHttpRequest();
X.open("POST", '/node/?'+(doInc?'inc':'dec')+'client', false);
X.send();
};
global.addEventListener('load', function () {
incDecClient(true);
hasLoadedApp = true;
}, false);
global.addEventListener('unload', function () {
if(!hasLoadedApp) {
incDecClient(true);
}
incDecClient(false);
}, false);
global.addEventListener('beforeunload', function () {
if(!socket) {
return "Are you sure you want to exit?";
}
}, false);
var XHR2 = function (uri, data, callback, progress) {
var X = new XMLHttpRequest();
X.open("POST", uri, true);
var fd = new FormData();
for (var i in data) {
if(data.hasOwnProperty(i)) {
fd.append(i, data[i]);
}
}
if(typeof callback === 'function') {
X.addEventListener('load', function (e) {
callback(X);
}, false);
}
if(typeof progress === 'function') {
X.upload.addEventListener('progress', function (e) {
progress(e);
});
}
X.send(fd);
return X;
};
var readFileHeaderInfo = function (callback) {
var X = new XMLHttpRequest();
X.open("GET", '/node/?getheader', true);
X.addEventListener('load', function (e) {
if(X.status !== 200) {
callback(true, []);
}
else {
callback(false, JSON.parse(X.response));
}
});
X.send();
};
var readFile = function (filename, callback, returnBuffer) {
var X = new XMLHttpRequest();
X.open("GET", '/node/?file='+encodeURIComponent(filename), true);
X.responseType = 'arraybuffer';
X.addEventListener('load', function (e) {
if(X.status !== 200) {
callback(true, returnBuffer? new Uint8Array(0) : '');
}
else {
var data = new Uint8Array(X.response);
if(returnBuffer) {
callback(false, data);
}
else {
var file = '';
for(var i=0, l = data.length; i < l; i+=1) {
file += String.fromCharCode(data[i]);
}
callback(false, file);
}
}
});
X.send();
};
var getFileList = function (callback) {
var X = new XMLHttpRequest();
X.open("GET", '/node/?files', true);
X.addEventListener('load', function (e) {
if(X.status !== 200) {
callback(true, []);
}
else {
callback(false, JSON.parse(X.response));
}
});
X.send();
};
var parseFile = function (filename, callback, onprogr) {
var X = new XMLHttpRequest();
var st = Date.now();
X.open("GET", '/node/?parse='+encodeURIComponent(filename), true);
//X.overrideMimeType("text/plain; charset=x-user-defined");
X.responseType = 'arraybuffer';
X.addEventListener('load', function (e) {
if(X.status !== 200) {
callback(true, new Uint8Array([]));
}
else {
var data = new Uint8Array(X.response);
/*for(var i=0; i < X.response.length; i+=1) {
data[i] = X.response.charCodeAt(i) & 0xFF;
}*/
console.log('Parsed the file in '+(Date.now() - st)/1000+'s');
callback(false, data);
}
});
var maxProgr = 0;
if(typeof onprogr === 'function') {
X.addEventListener('progress', function (e) {
maxProgr = Math.max(maxProgr, e.loaded/e.total);
onprogr(maxProgr);
});
}
X.send();
};
var uploadAndParse = function (form, callback) {
var X = new XMLHttpRequest();
var st = Date.now();
X.open("POST", '/node/?parsedata', true);
X.overrideMimeType("text/plain; charset=x-user-defined");
X.addEventListener('load', function (e) {
if(X.status !== 200) {
callback(true, '');
}
else {
var data = new Uint8Array(X.response.length);
for(var i=0; i < X.response.length; i+=1) {
data[i] = X.response.charCodeAt(i) & 0xFF;
}
console.log('Uploaded and parsed the file in '+(Date.now() - st)/1000+'s');
callback(false, data);
}
});
X.send(form);
};
var uploadAndSave = function (blob, filename, options, callback) {
var X = new XMLHttpRequest();
var st = Date.now();
X.open("POST", '/node/?savelevel', true);
X.overrideMimeType("text/plain; charset=x-user-defined");
var fd = new FormData();
fd.append('filedata', blob);
fd.append('filename', filename);
fd.append('doRun', !!options.run);
fd.append('doSave', !!options.save);
X.addEventListener('load', function (e) {
if(X.status !== 200) {
callback(true, '');
}
else {
var data = new Uint8Array(X.response.length);
for(var i=0; i < X.response.length; i+=1) {
data[i] = X.response.charCodeAt(i) & 0xFF;
}
console.log('Uploaded and saved the file in '+(Date.now() - st)/1000+'s');
callback(false, data);
}
});
X.send(fd);
};
var defaultJCSini = "";
var loadJCSini = function (data) {
data = (data || defaultJCSini).split("\n");
var i, l = data.length;
var matches;
var lastTitle = "";
var obj = {};
var tmp;
for(i=0; i < l; i+=1) {
data[i] = data[i].trim();
if(data[i] === "" || data[i][0] === ";") continue;
matches = data[i].match(/^\[(.*)\]$/);
if(matches !== null) {
lastTitle = matches[1];
obj[lastTitle] = [];
continue;
}
matches = data[i].match(/^(.*)=(.*)$/);
tmp = matches[2].split("|");
if(tmp.length === 4 && lastTitle === 'Events') {
tmp.push("");
}
tmp.forEach(function (v, k, a) {
v = v.trim();
if(k >= 5 && lastTitle === 'Events') {
v = v.split(":");
v[1] = +v[1];
}
a[k] = v;
});
tmp.id = +matches[1];
obj[lastTitle][+matches[1]] = tmp;
}
JCSini = obj;
};
(function () {
var X = new XMLHttpRequest();
X.open("GET", 'JCS.ini', true);
X.addEventListener('load', function (e) {
if(X.status !== 200) {
defaultJCSini = oldJCSini;
}
else {
defaultJCSini = X.responseText;
}
loadJCSini();
});
X.send();
}());
var XYid = function (x, y, w) {
return x+(y*w);
};
var idXY = function (tileID, w) {
var divBy=1;
if(tileID>=w) {divBy=w;}
return [(tileID%w), (tileID-(tileID%w))/divBy];
};
var loadlevel = function (file, filename, auto) {
Popup.open('loadinglevel');
var levloadprogr = global.document.querySelector("#levelloadingprogress");
global.document.querySelector("#loadlevelname").innerText = filename;
levloadprogr.style.width = "0%";
level(file, function (data) { // Successful read
for(var i in data) {
if(data.hasOwnProperty(i))
J2L[i] = data[i];
}
/*for(i=211; i < J2L.Streams[0].length; i+=512) {
console.log((i-211)/512, J2L.Streams[0].substr(i, 512).replace(/\|/g, ""));
}*/
//console.log(J2L, J2L.Streams[0].substr(J2L.LEVEL_INFO.normalStreamLength+512, 512).split("\0"), J2L.Streams[0].substr(J2L.LEVEL_INFO.normalStreamLength+512, 512).split("\0").length);
J2L.fileName = filename;
var pos, i, l = J2L.EVENTS.length, lw = J2L.LEVEL_INFO.LayerWidth[3];
/*for(i=0; i < l; i+=1) {
pos = idXY(i, lw);
J2L.LEVEL[3][pos[0]][pos[1]].event = J2L.EVENTS[i];
}*/
//delete J2L.EVENTS;
changeLayer(J2L.LEVEL_INFO.SecEnvAndLayer & 15);
scrollbars.layers.scroll = [J2L.LEVEL_INFO.JcsHorizontal, J2L.LEVEL_INFO.JcsVertical];
global.document.title = "Jazz Creation Station - "+J2L.LEVEL_INFO.LevelName+" - "+J2L.fileName;
Popup.hide();
levloadprogr.style.width = "0%";
var si = 0;
alphaSort(tilesets);
var l = tilesets.length;
for(var i=0; i < l; i+=1) {
si+=1;
if(tilesets[i].name.toLowerCase() === data.LEVEL_INFO.Tileset.toLowerCase()) {
break;
}
}
if(i === l) {
si = 0;
}
if(si === 0 && data.LEVEL_INFO.Tileset !== "") {
alert("Couldn't find tileset \""+data.LEVEL_INFO.Tileset+"\"");
}
else {
changeTileset(0, auto);
changeTileset(si, auto);
}
animSelection = false;
updateEventPointers();
}, function (x) { // Progress update
var p = Math.round(x*100)+"%";
levloadprogr.style.width = p;
}, function (err) { // Error occured
Popup.hide();
levloadprogr.style.width = "0%";
alert("Error: Couldn't read level!\n"+err);
});
};
var loadtileset = function (filename) {
Popup.open('loadingtileset');
var si = selectTileset.selectedIndex;
var tileloadprogr = global.document.querySelector("#tilesetloadingprogress");
global.document.querySelector("#loadtilesetname").innerText = selectTileset.options[si].textContent;
tileloadprogr.style.width = "0%";
parseFile(filename, function (err, file) { // Successful read
var firstFive = unpackStruct([['c5']], file.subarray(0, 5));
if(firstFive === 'error') {
alert('Error parsing J2T file, it\'s corrupted');
Popup.hide();
tileloadprogr.style.width = "0%";
}
if(err) {
alert('Error reading '+filename);
Popup.hide();
tileloadprogr.style.width = "0%";
}
var headerSize = 262;
var headerStruct = [
['c180', 'Copyright'],
['c4', 'Identifier'],
['u32', 'Signature'],
['C32', 'TilesetName'],
['u16', 'Version'],
['u32', 'FileSize'],
['s32', 'Checksum'],
['u32', 'StreamSizes', 8]
];
var header = unpackStruct(headerStruct, file.subarray(0, headerSize));
if(header.Identifier !== 'TILE') alert('Not a tileset');
/*if(header.Checksum !== crc32(file.subarray(headerSize))) {
console.error('Error: J2T file corrupt; Checksum error');
}*/
var isTSF = header.Version === 0x201;
var maxTiles = isTSF ? 4096 : 1024;
var filestr = '';
for(var i=0, l = file.length; i < l; i+=1) {
filestr += String.fromCharCode(file[i]);
}
var offset = headerSize;
var streams = [];
for(var i=0; i < 4; i+=1) {
streams[i] = filestr.substring(offset, offset+header.StreamSizes[i*2+1]);
streams[i] = streams[i].split('');
for(var j=0, l = streams[i].length; j < l; j+=1) {
streams[i][j] = streams[i][j].charCodeAt(0) & 0xFF;
}
streams[i] = new Uint8Array(streams[i]);
offset += header.StreamSizes[i*2+1];
}
var tilesetInfoStruct = [
['u32', 'Palette', 256],
['u32', 'TileCount'],
['u8', 'EmptyTile', maxTiles],
['u8', 'Unknown1', maxTiles],
['u32', 'ImageAddress', maxTiles],
['u32', 'Unknown2', maxTiles],
['u32', 'TMaskAddress', maxTiles],
['u32', 'Unknown3', maxTiles],
['u32', 'MaskAddress', maxTiles],
['u32', 'FMaskAddress', maxTiles]
];
var tilesetInfo = unpackStruct(tilesetInfoStruct, streams[0]);
J2T = {};
J2T.Palette = tilesetInfo.Palette;
var tilesetImage = streams[1];
var tilesetMask = streams[3];
J2T.tilesetMask = tilesetMask;
J2T.maskAddress = tilesetInfo.MaskAddress;
tileloadprogr.style.width = "66%";
setTimeout(function () {
var tilesetname = header.TilesetName;
var tilesetcanvas = global.document.createElement("canvas");
var tilec = tilesetcanvas.getContext("2d");
tilesetcanvas.width = 320;
var tilecount = tilesetInfo.TileCount;
var tileh = tilesetcanvas.height = 32*Math.ceil(tilecount/10);
var imgdata = tilec.createImageData(32, 32);
var imgd = imgdata.data;
var maxTiles = isTSF ? 4096 : 1024;
var tilecache = [];
var i, j, x, y, tile, index, color, pos, cachepos, masked, mbyte, pixpos;
for (i=0; i < tilecount; i+=1) {
tile = tilesetInfo.ImageAddress[i];
if(tile === 0) { continue; }
pos = idXY(i, 10);
if(tilecache[tile] !== undefined) {
cachepos = idXY(tilecache[tile], 10);
tilec.drawImage(tilesetcanvas, cachepos[0]*32, cachepos[1]*32, 32, 32, pos[0]*32, pos[1]*32, 32, 32);
}
else {
tilecache[tile] = i;
for(j=0; j < 4096 /* 32x32x4 */; j+=4) {
index = tilesetImage[tile+j/4];
if(index > 1) {
color = tilesetInfo.Palette[index];
imgd[j + 0] = color & 0xFF;
imgd[j + 1] = (color >> 8) & 0xFF;
imgd[j + 2] = (color >> 16) & 0xFF;
imgd[j + 3] = 255;
}
else {
imgd[j + 3] = 0;
}
}
tilec.putImageData(imgdata, pos[0]*32, pos[1]*32);
}
}
tile_url = tilesetcanvas.toDataURL("image/png");
tileloadprogr.style.width = "83%";
setTimeout(function () {
tilec.clearRect(0, 0, 320, tileh);
tilecache = [];
for (i=0; i < tilecount; i+=1) {
tile = tilesetInfo.MaskAddress[i];
if(tile === 0) { continue; }
pos = idXY(i, 10);
if(tilecache[tile] !== undefined) {
cachepos = idXY(tilecache[tile], 10);
tilec.drawImage(tilesetcanvas, cachepos[0]*32, cachepos[1]*32, 32, 32, pos[0]*32, pos[1]*32, 32, 32);
}
else {
tilecache[tile] = i;
for (x=0; x < 128; x+=1) {
mbyte = tilesetMask[tile+x];
for (y=0; y < 8; y+=1) {
color = 0;
if(tile > 0) {
masked = (mbyte & Math.pow(2, y)); //bit value
if(masked > 0) {
color = 255;
}
}
pixpos = ((x * 8) + y)*4; //bit index, for position
imgd[pixpos + 0] = 0;
imgd[pixpos + 1] = 0;
imgd[pixpos + 2] = 0;
imgd[pixpos + 3] = color;
}
}
tilec.putImageData(imgdata, pos[0]*32, pos[1]*32);
}
}
mask_url = tilesetcanvas.toDataURL("image/png");
tilesetcanvas.width = 1;
tilesetcanvas.height = 1;
var totalSize = tile_url.length + mask_url.length;
currentTileset.src = tile_url;
currentTilesetMask.src = mask_url;
tileloadprogr.style.width = "100%";
setTimeout(function () {
Popup.hide();
tileloadprogr.style.width = "0%";
}, 300);
}, 300);
}, 300);
}, function (x) { // Progress update
tileloadprogr.style.width = Math.round(x*50)+"%";
});
};
var checkIfLayerIsUsed = function (l) {
if(l === 3) return 1;
var i, j;
var w = J2L.LEVEL_INFO.LayerWidth[l];
var h = J2L.LEVEL_INFO.LayerHeight[l];
for(i=0; i < w; i+=1) {
for(j=0; j < h; j+=1) {
if(J2L.LEVEL[l][i][j].id > 0 || J2L.LEVEL[l][i][j].animated) {
return 1;
}
}
}
return 0;
};
var updateDynamicTileCache = function () {
//var st = Date.now();
setTimeout(function () {
updateDynamicTileCache();
}, 3*1000);
if(!toggleTileCacheVar) return;
var isTSF = false;
var version = isTSF?0x203:0x202;
var staticTiles = (isTSF?4096:1024) - J2L.ANIMS.length;
var MAX_TILES = (isTSF?4096:1024);
var map = [], tmp, hasAnimAndEvent, tile;
var jcslw, lw, lh, realWidth;
var l, i, j, k, animEventComboCount = 0;
for(l = 0; l < 8; l+=1) {
map[l] = [];
//J2L.LEVEL_INFO.IsLayerUsed[l] = checkIfLayerIsUsed(l);
//if(J2L.LEVEL_INFO.IsLayerUsed[l] === 0) continue;
jcslw = J2L.LEVEL_INFO.LayerWidth[l];
lw = jcslw*(J2L.LEVEL_INFO.LayerProperties[l] & 1 === 1? 4:1);
lh = J2L.LEVEL_INFO.LayerHeight[l];
realWidth = Math.ceil(jcslw/4)*4;
for(j = 0; j < lh; j+=1) {
for(i = 0; i < realWidth; i+=4) {
tmp = [0, 0, 0, 0];
hasAnimAndEvent = false;
for(k = 0; k < 4; k+=1) {
if(i+k < jcslw) {
tile = J2L.LEVEL[l][i+k][j];
tmp[k] = tile.id + (tile.flipped?MAX_TILES:0) + (tile.animated?staticTiles:0);
if(l === 3 && tile.animated && J2L.EVENTS[i+k+j*lw] > 0) {
hasAnimAndEvent = true;
}
}
}
map[l].push({
str: tmp.join(','), // Make it to a string
newWord: hasAnimAndEvent
});
}
}
}
var dict = {'0,0,0,0': 0}; // Initialize dictionary with the empty word
var tileCache = [];
var lastDictId = 1;
for(i=0; i < 8; i+=1) {
tileCache[i] = [];
for(j=0; j < map[i].length; j+=1) {
if(dict[map[i][j].str] === undefined || map[i][j].newWord) {
dict[map[i][j].str] = lastDictId++;
}
tileCache[i].push(dict[map[i][j].str]);
}
}
dynamicTileCache = tileCache;
//console.log("Updated dynamic tilecache in", (Date.now() - st)/1000, "s");
};
var writeLevel = function (options) {
Popup.open("saving");
var saveprogress = global.document.querySelector("#savingprogress");
var saving = global.document.querySelector("#saving");
saveprogress.style.width = "0%";
global.document.querySelector("#savinglevelname").textContent = trimNull(J2L.LEVEL_INFO.LevelName);
var copyright = " Jazz Jackrabbit 2 Data File\r\n\r\n"+
" Retail distribution of this data is prohibited without\r\n"+
" written permission from Epic MegaGames, Inc.\r\n\r\n\x1A";
var isTSF = false;
var version = isTSF?0x203:0x202;
var i, j, k, w, h;
var staticTiles = (isTSF?4096:1024) - J2L.ANIMS.length;
var MAX_TILES = (isTSF?4096:1024);
var streams = [0, 0, 0, 0];
var streamSizes = [0, 0, 0, 0];
var map = [];
var tmp;
var l;
/*var viewBytes = function (b) {
var i, s = "";
for(i=0; i < b.length; i+=1) {
s += b[i].toString(16)+" ";
}
console.log(s);
};*/
var realWidth;
var hasAnimAndEvent;
var animEventComboCount = 0;
var tilesetNeedsFlipped = {};
var animNeedsFlip = {};
var tile;
for(l = 0; l < 8; l+=1) {
J2L.LEVEL_INFO.IsLayerUsed[l] = checkIfLayerIsUsed(l);
map[l] = [];
J2L.LEVEL_INFO.JJ2LayerWidth[l] = J2L.LEVEL_INFO.LayerWidth[l]*(J2L.LEVEL_INFO.LayerProperties[l] & 1 === 1? 4:1);
if(J2L.LEVEL_INFO.IsLayerUsed[l] === 0) continue;
w = J2L.LEVEL_INFO.JJ2LayerWidth[l];
h = J2L.LEVEL_INFO.LayerHeight[l];
var tileW = 1;
realWidth = Math.ceil(w/4)*4;
for(j = 0; j < h; j+=1) {
for(i = 0; i < realWidth; i+=4) {
tmp = [0, 0, 0, 0];
hasAnimAndEvent = false;
for(k = 0; k < 4; k+=1) {
if(i+k < w) {
tile = J2L.LEVEL[l][(i+k) % (J2L.LEVEL_INFO.LayerWidth[l])][j];
tmp[k] = tile.id + (tile.flipped?MAX_TILES:0) + (tile.animated?staticTiles:0);
if(l === 3 && tile.animated && J2L.EVENTS[i+k+j*w] > 0) {
hasAnimAndEvent = true;
}
if(tile.flipped && !tile.animated) {
tilesetNeedsFlipped[tile.id] = true;
}
else if(tile.flipped) {
animNeedsFlip[tile.id] = true;
}
}
}
map[l].push({
str: tmp.join(','), // Make it to a string
newWord: hasAnimAndEvent
});
}
}
}
var dict = {'0,0,0,0': 0};
var tileCache = [];
var lastDictId = 1;
var dictionary = ['0,0,0,0'];
for(i=0; i < 8; i+=1) {
for(j=0; j < map[i].length; j+=1) {
if(dict[map[i][j].str] === undefined || map[i][j].newWord) {
dict[map[i][j].str] = lastDictId++;
}
tileCache.push(dict[map[i][j].str]);
dictionary[dict[map[i][j].str]] = map[i][j].str.split(",");
}
}
var words = new Uint16Array(dictionary.length*4);
var wordOffset = 0;
for(i=0; i < dictionary.length; i++) {
tmp = dictionary[i];//.split(",");
for(k = 0; k < 4; k+=1) {
words[wordOffset+k] = +tmp[k];
}
wordOffset+=4;
}
streamSizes[2] = words.byteLength;
streams[2] = words.buffer;
streamSizes[2] = streams[2].byteLength;
var dictstream = new Uint16Array(tileCache.length);
for(i = 0; i < tileCache.length; i+=1) {
dictstream[i] = tileCache[i];
}
streams[3] = dictstream.buffer;
streamSizes[3] = streams[3].byteLength;
var animOffset = 8813+MAX_TILES*7;
var streamLength = animOffset + 128*137;
var arbuf = new ArrayBuffer(streamLength);
var buf = new DataView(arbuf);
buf.setUint16(0, ~~(scrollbars.layers.scroll[0]), true); // JcsHorizontal
buf.setUint16(4, ~~(scrollbars.layers.scroll[1]), true); // JcsVertical
buf.setUint8(8, currentLayer, true); // SecEnvAndLayer
buf.setUint8(9, J2L.LEVEL_INFO.MinimumAmbient);
buf.setUint8(10, J2L.LEVEL_INFO.StartingAmbient);
buf.setUint16(11, J2L.ANIMS.length, true);
buf.setUint8(13, J2L.LEVEL_INFO.SplitScreenDivider);
buf.setUint8(14, J2L.LEVEL_INFO.IsItMultiplayer);
buf.setUint32(15, streamLength, true);
J2L.LEVEL_INFO.Tileset = selectTileset.options[selectTileset.selectedIndex] !== undefined ? selectTileset.options[selectTileset.selectedIndex].value:"";
if(J2L.LEVEL_INFO.LevelName === "") {
J2L.LEVEL_INFO.LevelName = "Untitled";
}
for(i=0; i < 32; i+=1) {
buf.setUint8(19+i, J2L.LEVEL_INFO.LevelName.charCodeAt(i) || 0);
buf.setUint8(19+i+32*1, J2L.LEVEL_INFO.Tileset.charCodeAt(i) || 0);
buf.setUint8(19+i+32*2, J2L.LEVEL_INFO.BonusLevel.charCodeAt(i) || 0);
buf.setUint8(19+i+32*3, J2L.LEVEL_INFO.NextLevel.charCodeAt(i) || 0);
buf.setUint8(19+i+32*4, J2L.LEVEL_INFO.SecretLevel.charCodeAt(i) || 0);
buf.setUint8(19+i+32*5, J2L.LEVEL_INFO.MusicFile.charCodeAt(i) || 0);
}
for(i=0; i < J2L.LEVEL_INFO.HelpString.length; i+=1) {
for(j=0; j < J2L.LEVEL_INFO.HelpString[i].length; j+=1) {
buf.setUint8(211+512*i+j, J2L.LEVEL_INFO.HelpString[i].charCodeAt(j) || " ");
}
}
for(i=0; i < 8; i+=1) {
buf.setUint32(8403+i*4, J2L.LEVEL_INFO.LayerProperties[i], true);
/* 8 unknowns */
buf.setUint8 (8403+8*4+8+i, J2L.LEVEL_INFO.IsLayerUsed[i]);
buf.setUint32(8403+8*4+8+8+i*4, J2L.LEVEL_INFO.LayerWidth[i], true);
buf.setUint32(8403+8*4+8+8+8*4+i*4, J2L.LEVEL_INFO.JJ2LayerWidth[i], true);
buf.setUint32(8403+8*4+8+8+8*4+8*4+i*4, J2L.LEVEL_INFO.LayerHeight[i], true);
buf.setInt32(8403+8*4+8+8+8*4+8*4+8*4+i*4, i*100-300, true);
/* 18*4 unknowns */
buf.setInt32(8403+8*4+8+8+8*4+8*4+8*4+8*4+18*4+i*4, J2L.LEVEL_INFO.LayerXSpeed[i]*65536, true);
buf.setInt32(8403+8*4+8+8+8*4+8*4+8*4+8*4+18*4+8*4+i*4, J2L.LEVEL_INFO.LayerYSpeed[i]*65536, true);
buf.setInt32(8403+8*4+8+8+8*4+8*4+8*4+8*4+18*4+8*4+8*4+i*4, J2L.LEVEL_INFO.LayerAutoXSpeed[i]*65536, true);
buf.setInt32(8403+8*4+8+8+8*4+8*4+8*4+8*4+18*4+8*4+8*4+8*4+i*4, J2L.LEVEL_INFO.LayerAutoYSpeed[i]*65536, true);
/* 8 unknowns */
}
for(i=0; i < 3; i+=1) {
// Ugly...
buf.setUint8(8787+3*0+i, J2L.LEVEL_INFO.LayerRGB1[i]);
buf.setUint8(8787+3*1+i, J2L.LEVEL_INFO.LayerRGB2[i]);
buf.setUint8(8787+3*2+i, J2L.LEVEL_INFO.LayerRGB3[i]);
buf.setUint8(8787+3*3+i, J2L.LEVEL_INFO.LayerRGB4[i]);
buf.setUint8(8787+3*4+i, J2L.LEVEL_INFO.LayerRGB5[i]);
buf.setUint8(8787+3*5+i, J2L.LEVEL_INFO.LayerRGB6[i]);
buf.setUint8(8787+3*6+i, J2L.LEVEL_INFO.LayerRGB7[i]);
buf.setUint8(8787+3*7+i, J2L.LEVEL_INFO.LayerRGB8[i]);
}
buf.setUint16(8811, staticTiles, true);
var frames = 0;
for(i=0; i < J2L.ANIMS.length; i+=1) {
buf.setUint16(animOffset + i*137, J2L.ANIMS[i].FramesBetweenCycles, true);
buf.setUint16(animOffset + i*137 + 2, J2L.ANIMS[i].RandomAdder, true);
buf.setUint16(animOffset + i*137 + 4, J2L.ANIMS[i].PingPongWait, true);
buf.setUint8(animOffset + i*137 + 6, J2L.ANIMS[i].IsItPingPong);
buf.setUint8(animOffset + i*137 + 7, J2L.ANIMS[i].FPS);
frames = Math.min(J2L.ANIMS[i].Tiles.length, 64);
buf.setUint8(animOffset + i*137 + 8, frames);
for(j=0; j < frames; j+=1) {
buf.setUint16(animOffset + i*137 + 9 + j*2, J2L.ANIMS[i].Tiles[j].id + (J2L.ANIMS[i].Tiles[j].flipped?MAX_TILES:0) + (J2L.ANIMS[i].Tiles[j].animated?staticTiles:0), true);
if(animNeedsFlip[i] === true && !J2L.ANIMS[i].Tiles[j].animated) {
tilesetNeedsFlipped[J2L.ANIMS[i].Tiles[j].id] = true;
}
else if(animNeedsFlip[i] === true) {
animNeedsFlip[J2L.ANIMS[i].Tiles[j].id] = true;
}
if(J2L.ANIMS[i].Tiles[j].flipped && !J2L.ANIMS[i].Tiles[j].animated) {
tilesetNeedsFlipped[J2L.ANIMS[i].Tiles[j].id] = true;
}
else if(J2L.ANIMS[i].Tiles[j].flipped) {
animNeedsFlip[J2L.ANIMS[i].Tiles[j].id] = true;
}
//tilesetNeedsFlipped[J2L.ANIMS[i].Tiles[j].id] = true;
}
}
for(i=1; i < staticTiles; i+=1) {
buf.setUint32(8813+i*4, J2L.TilesetProperties.TileEvent[i], true);
buf.setUint8(8813+4*MAX_TILES+i, tilesetNeedsFlipped[i] === true ? 1 : 0); // Flipped tiles in tileset, so JJ2 know what flipped tiles to load from flipped tileset image ;D
buf.setUint8(8813+MAX_TILES*4+MAX_TILES+i, J2L.TilesetProperties.TileType[i], true);
/* skip MAX_TILES bytes */
}
/*var levelinfo = "";
for(i=0; i < arbuf.byteLength; i+=1) {
levelinfo += String.fromCharCode(buf.getUint8(i));
}*/
streams[0] = arbuf;
streamSizes[0] = streams[0].byteLength;
w = J2L.LEVEL_INFO.LayerWidth[3];
h = J2L.LEVEL_INFO.LayerHeight[3];
arbuf = new ArrayBuffer(w*h*4);
buf = new DataView(arbuf);
for(i=0; i < w; i+=1) {
for(j=0; j < h; j+=1) {
buf.setUint32((i+(j*w))*4, J2L.EVENTS[i+w*j] || 0, true);
}
}
/*var events = "";
for(i=0; i < arbuf.byteLength; i+=1) {
events += String.fromCharCode(buf.getUint8(i));
}*/
streams[1] = arbuf;
streamSizes[1] = streams[1].byteLength;
arbuf = new ArrayBuffer(262);
buf = new DataView(arbuf);
for(i=0; i < 180; i+=1) {
buf.setUint8(i, copyright.charCodeAt(i));
}
buf.setInt32(180+3, 0xBABE, false); // Password
var identifier = "LEVL";
for(i=0; i < 4; i+=1) {
buf.setUint8(180+i, identifier.charCodeAt(i));
}
buf.setUint8(180+4+3, J2L.HEADER_INFO.HideLevel);
for(i=0; i < J2L.HEADER_INFO.LevelName.length; i+=1) {
buf.setUint8(180+4+3+1+i, J2L.HEADER_INFO.LevelName.charCodeAt(i) || 0);
}
var allBuffers = new Uint8Array(streamSizes[0]+streamSizes[1]+streamSizes[2]+streamSizes[3]);
var offset = 0;
for(i=0; i < 4; i+=1) {
allBuffers.set(new Uint8Array(streams[i]), offset);
offset+= streamSizes[i];
}
buf.setUint16(180+4+3+1+32, version, true);
//buf.setUint32(180+4+3+1+32+2, 262+allBuffers.length, true);
//buf.setInt32(180+4+3+1+32+2+4, crc32(allBuffers), true); // CRC32 of level
for(i=0; i < 4; i+=1) {
//buf.setUint32(230+i*8, 0, true);
buf.setUint32(230+i*8+4, streamSizes[i], true);
}
/*var bb = new BlobBuilder();
bb.append(arbuf); // Header
bb.append(allBuffers.buffer); // Streams
var blob = bb.getBlob("application/octet-stream");*/
var blob = new Blob([new Uint8Array(arbuf), allBuffers]);
uploadAndSave(blob, J2L.fileName, {run: !!options.run, save: !!options.save, newfile: !!options.newfile}, function (err, data) {
if(!err && data.length > 0) {
/*var bb = new BlobBuilder();
bb.append(data.buffer);
var blob = bb.getBlob("application/octet-stream");*/
var blob = new Blob([data]);
//webkitURL.createObjectURL(blob)
saveAs(blob, J2L.fileName);
}
Popup.hide();
});
/*fs.root.getFile(J2L.fileName, {create: true}, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function(e) {
Popup.hide();
if(confirm("Download saved level?")) {
global.document.location = fileEntry.toURL();
}
};
fileWriter.write(blob);
}, fileSystemError);
}, fileSystemError);*/
};
var updateTiles = function (layer, startX, startY, maxw, maxh, selection, includeEmpty) {
var oldSelection = [];
var lw = J2L.LEVEL_INFO.LayerWidth[layer];
var lh = J2L.LEVEL_INFO.LayerHeight[layer];
var isIdenticalCount = 0;
var totalCount = 0;
for(var x = 0; x < maxw; x+=1) {
oldSelection[x] = [];
for(var y = 0; y < maxh; y+=1) {
oldSelection[x][y] = {};
if(x+startX < lw && y+startY < lh) {
oldSelection[x][y] = {
'id': 0,
'animated': false,
'flipped': false,
'event': 0
};
oldSelection[x][y] = {
'id': J2L.LEVEL[layer][x+startX][y+startY].id,
'animated': J2L.LEVEL[layer][x+startX][y+startY].animated,
'flipped': J2L.LEVEL[layer][x+startX][y+startY].flipped,
'event': layer === 3 ? J2L.EVENTS[x+startX + lw * (y+startY)] || 0 : 0
};
if(selection[x] && selection[x][y] && (includeEmpty || selection[x][y].id > 0 || selection[x][y].animated || (selection.length===1 && selection[x].length === 1))) {
J2L.LEVEL[layer][x+startX][y+startY] = {'id': selection[x][y].id, 'animated': selection[x][y].animated, 'flipped': selection[x][y].flipped};
if(layer === 3) {
J2L.EVENTS[x+startX + lw * (y+startY)] = selection[x][y].event || 0;
}
if(oldSelection[x][y].id === selection[x][y].id &&
oldSelection[x][y].animated === selection[x][y].animated &&
oldSelection[x][y].flipped === selection[x][y].flipped &&
oldSelection[x][y].event === J2L.EVENTS[x+startX + lw * (y+startY)]) {
isIdenticalCount++;
}
totalCount++;
}
}
}
}
return isIdenticalCount === totalCount ? false : oldSelection;
};
/*var freeRef = function (obj) {
var chi, cou, len, nam;
chi = obj.childNodes;
if(chi) {
len = chi.length;
for (cou = 0; cou < len; cou++) {
freeRef(obj.childNodes[cou]);
}
}
chi = obj.attributes;
if(chi) {
len = chi.length;
for(cou = 0; cou < len; cou++) {
nam = chi[cou].name;
if(typeof(obj[nam]) === 'function') {
obj[nam] = null;
}
}
}
};*/
var mousedowndrag = function (e) {
if(e.which === 1) {
var node = this.parentNode.parentNode.parentNode;
var nodebounding = node.getBoundingClientRect();
this.offsetY = (e.pageY - nodebounding.top);
this.isDragging = true;
}
chatInput.blur();
e.preventDefault();
return false;
};
var mousedownlayers = function (e) {
var layerbounding = layercanvas.getBoundingClientRect();
var offsetX = e.pageX - layerbounding.left;
var offsetY = e.pageY - layerbounding.top;
mousedownscroll = [scrollbars.layers.scroll[0], scrollbars.layers.scroll[1]];
if(e.which === 1) {
layercanvas.isDragging = true;
}
else if(e.which === 2) {
layercanvas.isPanning = true;
}
var w = layerdiv.offsetWidth;
var h = layerdiv.offsetHeight;
if(mouseOnScrollbars('layers', w, h, offsetX, offsetY, e)) {
}
else {
winmove(e);
}
chatInput.blur();
e.preventDefault();
};
var mousedownanims = function (e) {
var animsbounding = animscanvas.getBoundingClientRect();
var offsetX = e.pageX /*- animsbounding.left*/;
var offsetY = e.pageY - animsbounding.top;
animscanvas.isDragging = true;
var btn = e.which;
var w = animsdiv.offsetWidth;
var h = animsdiv.offsetHeight;
if(mouseOnScrollbars('anims', w, h, offsetX, offsetY, e)) {
}
else if(btn === 1) {
var offx = e.pageX /*- animscanvas.offsetLeft*/ + scrollbars.anims.scroll[0];
var offy = e.pageY - animsbounding.top + scrollbars.anims.scroll[1];
var anx = 0;
var any = Math.floor(offy/32);
if(e.pageX > 32+4) anx = Math.floor((offx-4)/32);
if(!holdingCtrlKey) {
animSelection = false;
if((any <= J2L.ANIMS.length && anx === 0) || (J2L.ANIMS[any] && anx-2 < J2L.ANIMS[any].Frames)) {
animSelection = [anx, any];
}
if(anx === 0 && any < J2L.ANIMS.length) {
selectedTiles = [[{'id': any, 'animated': true, 'flipped': false, 'event': 0}]];
selectedSource = 'anims';
}
}
else if(holdingCtrlKey && anx === 0 && any < J2L.ANIMS.length) {
var id = any;
var addWhere;
if(animSelection !== false) {
if(animSelection[0] === 0 && animSelection[1] === J2L.ANIMS.length) {
J2L.ANIMS.push({
'FramesBetweenCycles': 0,
'RandomAdder': 0,
'PingPongWait': 0,
'IsItPingPong': 0,
'FPS': 10,
'Frames': 0,
'Tiles': []
});
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'anims',
type: 'new'
});
}
}
addWhere = J2L.ANIMS[animSelection[1]].Frames;
if(animSelection[0] > 0) {
addWhere = animSelection[0]-1;
}
J2L.ANIMS[animSelection[1]].Tiles.splice(addWhere, 0, {'id': id, 'animated': true, 'flipped': holdingFlipKey});
J2L.ANIMS[animSelection[1]].Frames+=1;
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'anims',
type: 'frame',
anim: animSelection[1],
pos: addWhere,
tile: {'id': id, 'animated': true, 'flipped': holdingFlipKey}
});
}
}
}
}
else if(btn === 3) {
var offy = e.pageY - animsbounding.top + scrollbars.anims.scroll[1];
var any = Math.floor(offy/32);
if(e.pageX < 32 && any < J2L.ANIMS.length) {
animpropertiesform.animID.value = any;
animpropertiesform.animSpeedSlider.value = animpropertiesform.animSpeedInput.value = J2L.ANIMS[any].FPS;
animpropertiesform.animFrameWait.value = J2L.ANIMS[any].FramesBetweenCycles;
animpropertiesform.animRandomAdder.value = J2L.ANIMS[any].RandomAdder;
animpropertiesform.animPingPongWait.value = J2L.ANIMS[any].PingPongWait;
animpropertiesform.animPingPong.set(!!J2L.ANIMS[any].IsItPingPong);
Popup.open('animproperties');
}
}
chatInput.blur();
e.preventDefault();
return false;
};
var moveAnim = function (updown) {
return function (e) {
if(animSelection !== false && animSelection[0] === 0 && animSelection[1] < J2L.ANIMS.length && animSelection[1]+updown < J2L.ANIMS.length && animSelection[1]+updown > -1) {
var tmpHolder = J2L.ANIMS[animSelection[1]];
J2L.ANIMS[animSelection[1]] = J2L.ANIMS[animSelection[1]+updown];
J2L.ANIMS[animSelection[1]+updown] = tmpHolder;
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'anims',
type: 'move',
anim: animSelection[1],
by: updown
});
}
animSelection[1]+=updown;
}
};
};
var delAnimFrame = function () {
if(animSelection !== false && animSelection[1] < J2L.ANIMS.length && animSelection[0]-1 < J2L.ANIMS[animSelection[1]].Frames) {
if(animSelection[0] > 0) {
J2L.ANIMS[animSelection[1]].Frames-=1;
J2L.ANIMS[animSelection[1]].Tiles.splice(animSelection[0]-1, 1);
if(socket && socket.readyState === 1) {
sendUpdate({
what: 'anims',
type: 'delFrame',
anim: animSelection[1],
frame: animSelection[0]-1
});
}
}
if(animSelection[0] === 0 || J2L.ANIMS[animSelection[1]].Frames === 0) {
J2L.ANIMS.splice(animSelection[1], 1);
[preview ends here]
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.