/* * This file is part of Deliantra clientV. * * Copyright (©) 2012 Marek Olszewski * * Deliantra clientV is free software: you can redistribute it and/or * modify it under the terms of the Affero GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public Licens * and the GNU General Public License along with this program. If not, see * . * * The authors can be reached via e-mail to */ function getPassword() { return document.getElementById("password").value.trim(); } function getLogin() { return document.getElementById("login").value.trim(); } function main() { for ( var i = 0;i < cfColor.length; ++i ) { var r = cfColor[i][0]*255; var g = cfColor[i][1]*255; var b = cfColor[i][2]*255; cfColor[i] = "RGB(" + r + "," + g + "," + b + ")"; } for (var i = 0; i < 255; ++i) { keys.states[i] = 0; }; if (isMainCalled == true) { return; } isMainCalled = true; window.WebSocket = window.WebSocket || window.MozWebSocket; if (window.WebSocket) { canvas = document.createElement("canvas"); var sw = canvas.width = window.innerWidth - 10; var sh = canvas.height = window.innerHeight - 10; var dx = Math.floor(sw / 64); var dy = Math.floor((sh) / 64); dx = dy = Math.min(dx, dy); stage = { stageWidth: sw, stageHeight: sh }; xMapWindow = createWindow("map", dx * 64 + 30, dy * 64 + 30, 0, 120); xMapWindow.style.top = (sh - xMapWindow.height() - 20) + "px"; xMapWindow.show(false); canvas.width = xMapWindow.width() - 10; canvas.height = xMapWindow.height() - 25; xFloorWindow = createWindow("floor", Math.floor((sw - xMapWindow.width() - 30) / 2), 350, xMapWindow.width() + 30, stage.stageHeight - 20 - 350); xFloorWindow.show(false); xPlayerWindow = createWindow("player", sw - 30, sh - 30, 10, 10); //xPlayerWindow.show(false); xPlayerWindow.contents.innerHTML = ""; var buttons = ["Statistics", "Skills", "SpellBook", "Inventory"]; var div = document.createElement("div"); div.className = "buttons_widnow_content"; xPlayerWindow.contents.appendChild(div); for (var i = 0; i < buttons.length; ++i) { var button = document.createElement("input"); button.type = "button"; button.value = buttons[i] + " (F" + (i + 2) + ")"; button.addEventListener("click", showPlayerTab); div.appendChild(button); } div = document.createElement("div"); div.className = "player_widnow_content"; xPlayerWindow.contents.appendChild(div); div = document.createElement("div"); div.className = "floor_widnow_content"; xPlayerWindow.contents.appendChild(div); div = document.createElement("div"); div.className = "spellbook_widnow_content"; xPlayerWindow.contents.appendChild(div); div = document.createElement("div"); div.className = "skills_widnow_content"; xPlayerWindow.contents.appendChild(div); div = document.createElement("div"); div.className = "statistics_widnow_content"; xPlayerWindow.contents.appendChild(div); hideAllPlayerTabs(); xPlayerWindow.show(false); ctx = canvas.getContext('2d'); xLoginWindow = createLoginWindow(); appendToBody(xLoginWindow); //autoComplete(); window.addEventListener("click", onClick); window.addEventListener("contextmenu", onClick); window.addEventListener("mousemove", onMouseMove); window.addEventListener("mouseup", onMouseUp); //document.getElementsByTagName("body")[0].addEventListener("contextmenu",onClick); //document.addEventListener("contextmenu",onClick); xBarsWindow = createWindow("bars", 250, 300, sw - 280, sh - 320); var barsCanvas = $_("canvas"); barsCanvas.width = xBarsWindow.sw = xBarsWindow.width() - 20; barsCanvas.height = xBarsWindow.sh = xBarsWindow.height() - 20; xBarsWindow.contents.appendChild(barsCanvas); xBarsWindow.ctx = barsCanvas.getContext("2d"); xBarsWindow.ctx.fillStyle = "#000"; xBarsWindow.ctx.fillRect(0, 0, xBarsWindow.sw, xBarsWindow.sh); xBarsWindow.show(false); xInfoWindow = createWindow("info", 300, 200, -400, -300); xInfoWindow.show(false); xCommmandWindow = createCommandWindow(); xCommmandWindow.show(false); xChatBoxWindow = createWindow("chatbox", sw - xMapWindow.width() - 20, 300, sw - (sw - xMapWindow.width() - 20), 10); xChatBoxWindow.buttonsContainer = $_("div"); xChatBoxWindow.contents.appendChild(xChatBoxWindow.buttonsContainer); xChatBoxWindow.channelContainer = $_("div"); xChatBoxWindow.channelContainer.style.height = "100%"; xChatBoxWindow.contents.appendChild(xChatBoxWindow.channelContainer); } }; var playerTabs = ["player_widnow_content", "floor_widnow_content", "spellbook_widnow_content", "skills_widnow_content", "statistics_widnow_content"]; function getItemById(itmid) { var itm = findItem(myItems, itmid); if (itm) { return itm; } itm = findItem(floorItems, itmid); if (itm) { return itm; } for (var s in containers) { if (typeof(containers[s]) == typeof({})) { itm = findItem(containers[s], itmid); if (itm) { return itm; } } } } function removeItemEx(itmid) { removeItem(myItems, itmid); removeItem(floorItems, itmid); for (var s in containers) { if (typeof(containers[s]) == typeof({})) { removeItem(containers[s], itmid); } } } var exti = { nextId: 100, getNextId: function() { return this.nextId++; } }; /** * HANDLE FEEDS FROM SERVER */ function feed_upditem(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = "upditem ".length; var flags = buff.readUint8(); var tag = buff.readUint32(); var itm = getItemById(tag); if (!itm) { return; } if (flags & UPD_LOCATION) { removeItemEx(tag); var container = buff.readUint32(); if (container == player.tag) { myItems.push(itm); } else if (container == 0) { floorItems.push(itm); } else { if (!typof(containers["container_" + container]) == typeof([])) { containers["container_" + container] = []; } containers["container_" + container].push(itm); } } if (flags & UPD_FLAGS) itm.flags = buff.readUint32(); if (flags & UPD_WEIGHT) itm.weight = buff.readUint32(); //$item->{weight} = unpack "l", pack "L", unpack "N", substr $data, 0, 4, "" ; if (flags & UPD_FACE) itm.face = buff.readUint32(); if ((itm.flags & F_OPEN)) { secondaryContainer = tag; updateItemsList(); } //TODO: finish it! /* if ($flags & UPD_NAME) { my $len = unpack "C", substr $data, 0, 1, ""; my $names = substr $data, 0, $len, ""; utf8::decode $names; @$item{qw(name name_pl)} = split /\x00/, $names; } $item->{anim} = unpack "n", substr $data, 0, 2, "" if $flags & UPD_ANIM; $item->{animspeed} = TICK * unpack "C", substr $data, 0, 1, "" if $flags & UPD_ANIMSPEED; $item->{nrof} = unpack "N", substr $data, 0, 4, "" if $flags & UPD_NROF; $item->{mtime} = time; if ($item->{tag} == $self->{player}{tag}) { $self->player_update ($self->{player} = $item); } else { $self->item_update ($item); } */ } function feed_delitem(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = 8; while (buff.position < dataAsArray.length) { var itmid = buff.readUint32(); removeItemEx(itmid); if (typeof(containers["container_" + itmid]) == typeof({})) { containers["container_" + itmid] = []; } } updateItemsList(); } function findItem(items, itmid) { for (var i = items.length - 1; i >= 0; --i) { if (items[i].itemId == itmid) { return items[i]; } } return null; } function removeItem(items, itmid) { for (var i = items.length - 1; i >= 0; --i) { if (items[i].itemId == itmid) { items.splice(i, 1); } } updateItemsList(); } function feed_ex(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = 3; var len = buff.unpack_w(); var str = buff.readString(len); xInfoWindow.contents.innerHTML = str.split("\n").join("
") + "shift+click - drop,move or pickup item"; } function feed_query(data, dataAsArray) { switch (String.fromCharCode(dataAsArray[6])) { case "0": //var login = prompt("What is your name? (login names are case-sensitive):"); doSend("reply " + getLogin()); return true; break; case "2": // The original message is "Do you want to continue playing?", so the actual reply to the server is inverted. if (window.confirm("Would you like to stop playing Deliantra?")) { doSend("reply n") userUsedBedToReality = true; } else { doSend("reply y") userUsedBedToReality = false; } return true; break; case "4": //var password = prompt("What is your password?"); doSend("reply " + getPassword()); return true; break; default: var response = window.prompt(data.substring(8)); if (response != null) { doSend("reply " + response); return true; } break; } return false; } function feed_version(data, dataAsArray) { var smapsize = Math.floor(xMapWindow.width() / 64); mapsize.width = mapsize.height = parseInt(smapsize); smapsize = smapsize + "x" + smapsize; map_clear(); doSend('setup tileset '+myTileset +' excmd 1 smoothing 1 mapinfocmd 1 facecache 1 newmapcmd 1 extmap 1 fxix 3 darkness 1 extcmd 2 msg 2 frag 0 map1acmd 1 spellmon 2 itemcmd 2 exp64 1 widget 1 lzf 0 mapsize ' + smapsize); window.addEventListener("keydown", function(e) { if (skipKeyTest) { return; } if (keys.states[e.keyCode] == 0) { onKeyDown(e.keyCode); } keys.states[e.keyCode] = 1; try { e.preventDefault(); } catch(e) { } return false; }); window.addEventListener("keyup", function(e) { if (skipKeyTest) { return; } if (keys.states[e.keyCode] == 1) { onKeyUp(e.keyCode); } keys.states[e.keyCode] = 0; try { e.preventDefault(); } catch(e) { } //isRunning = false; return false; }); channels_add({ id: "log" }); channels_add({ id: "map" }); channels_add({ id: "debug" }); return false; } function feed_setup(data, dataAsArray) { doSend('exti ["http_faceurl", ' + exti.getNextId() + ']'); } function feed_map1a(stringData, data) { scroll_map(dx, dy); dx = dy = 0; var x, y; var index = 6; while (index < data.length - 2) { var flags = (data[index++] << 8) + data[index++]; x = ((flags >> 10) & 63); y = ((flags >> 4) & 63); cell = map_get_cell(x, y); if (! (flags & 15)) { clear_cell(cell); //ctx.clearRect(x<<6,(y<<6),64,64); continue; } if (cell.darkness == 0) { cell.darkness = 256; } if ((flags & 8)) { do { var cmd = 0; var ext = 0; ext = data[index++]; cmd = ext & 0x7f; if (cmd < 4) { cell.darkness = 255 - ext * 64 + 1; } else if (cmd == 5) { cell.stat_width = 1; cell.stat_hp = data[index++]; } else if (cmd == 6) { // monster width cell.stat_width = data[index++] + 1; } else if (cmd == 0x47) { if (data[index] == 1) cell.player = data[index + 1]; else if (data[index] == 2) cell.player = data[index + 2] + (data[index + 1] << 8); else if (data[index] == 3) cell.player = data[index + 3] + (data[index + 2] << 8) + (data[index + 1] << 16); else if (data[index] == 4) cell.player = data[index + 4] + (data[index + 3] << 8) + (data[index + 2] << 16) + (data[index + 1] << 24); index += data[index] + 1; } else if (cmd == 8) // cell flags cell.flags = data[index++]; else if (ext & 0x40) // unknown, multibyte => skip index += data[index] + 1; else index++; } while (ext & 0x80); } for (var z = 0; z <= 2; ++z) if ((flags & (4 >> z))) { var face = (data[index++] << 8) + data[index++]; //need_facenum (face); cell.tiles[z] = face; } //Map[y][x]=cell; } drawMap(); return true; } function feed_ext(data, dataAsArray) { var o = JSON.parse ( data.substr ( 4 ) ); //writeToScreen(data.substr(4)); if ( o[0] == "command_list" ) { //commandsAll = []; /* * ["command_list",7892,7893,7890] */ for ( var i = 1 ; i < o.length ; ++ i ){ Faces.request ( o [ i ] , "json" , function ( tileInfo ) { commandsAll [ i ] = tileInfo.resource; }); } } else if (o[0] == "channel_info" ) { var channel_info = o[1]; channels_add(channel_info); return true; } else if ( o[0] == "capabilities" ) { var p = { ret : -1 }; o[2].each ( function ( e, i, p ) { if ( e.length >= 3 && typeof ( e [ 2 ] ) == typeof ( 1 ) && parseInt( e [ 2 ] )== 1 && typeof ( e[3] ) == typeof ( 1 ) && parseInt( e[3] )== 64 ) { p.ret = e[0]; return true; } } , p ); myTileset = p.ret >= 0 ? p.ret : 0; } else { var replyID = parseInt(o[0].split("-")[1]); if (replyID == 100) { baseURL = o[1]; if (baseURL.charAt(0) == "/") { var uri = $_('a'); uri.href = wsUri; baseURL = uri.protocol + "//" + uri.host + baseURL; baseURL = baseURL.replace(/^ws/i, "http"); } doSend('exti ["resource",' + exti.getNextId() + ',"exp_table"]'); } else if (replyID == 101) { expTableFacenum = parseInt(o[1]); Faces.request(expTableFacenum, "json", function(tileInfo) { expTable = (tileInfo.resource); }); doSend('exti ["resource",' + exti.getNextId() + ', "skill_info", "spell_paths"]'); } else if (replyID == 102) { Faces.request(parseInt(o[1]), "json", function(faceInfo) { skillNames = (faceInfo.resource); }); Faces.request(parseInt(o[2]), "json", function(faceInfo) { spellPaths = (faceInfo.resource);; }); /*Faces.request(parseInt(o[3]), "json", function(faceInfo) { commandsAll = ( faceInfo.resource ); expandCommandList ( ); });*/ doSend("addme"); } else { } //writeToScreen(data); } return false; } function feed_replyinfo(data) { return false; } function feed_item2(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = 6; var container = buff.readUint32(); while (buff.position < buff.length) { var item = new Item(); item.itemId = buff.readUint32(); item.flags = buff.readUint32(); item.weight = buff.readUint32(); item.face = buff.readUint32(); var len = (buff.readUint8()); var names = (buff.readString(len)).split(String.fromCharCode(0)); item.name = names[0]; item.namepl = ""; if (names.length > 1) item.namepl = names[1]; item.animation_id = buff.readUint16(); item.anim_speed = buff.readUint8(); item.nr_of = buff.readUint32(); item.clientType = buff.readUint16(); item.container = container; if (container == player.tag) { myItems.push(item); } else if (container == 0) { floorItems.push(item); } else { if (typeof(containers['container_' + container]) != typeof([])) { containers['container_' + container] = []; } containers['container_' + container].push(item); } } if (container == 0) { xFloorWindow.contents.innerHTML = ""; for (var i = 0; i < floorItems.length; ++i) { var item = floorItems[i]; if (item.itemId == null || isNaN(item.itemId)) continue; var img = tilesInfo.getImgByFaceNum(item.face); var div = $_("div"); xFloorWindow.contents.appendChild(div); if (img) { div.innerHTML += "
" + (item.nr_of > 1 ? item.namepl : item.name) + (item.nr_of > 1 ? item.nr_of : "") + "
" } else { div.innerHTML += "
" + (item.nr_of > 1 ? item.namepl : item.name) + "
" } div.addEventListener("click", floorInventoryItemClick); div.addEventListener("mouseover", inventoryItemMouseOver); div.addEventListener("mouseout", inventoryItemMouseOut); div.addEventListener("mousemove", inventoryItemMouseMove); } } updateItemsList(); return false; } function Spell() { } function feed_addspell(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = data.indexOf(" ") + 1; while (buff.position < buff.length) { spell = new Spell(); spell.tag = buff.readUint32(); spell.minLevel = buff.readUint16(); spell.castingTime = buff.readUint16(); spell.mana = buff.readUint16(); spell.grace = buff.readUint16(); spell.level = buff.readUint16(); spell.skill = buff.readUint8(); spell.path = buff.readUint32(); spell.face = buff.readUint32(); if (!isNaN(spell.face)){ Faces.request(spell.face,"ui"); } var len = buff.readUint8(); spell.name = buff.readString(len); mySpells.push(spell); Application.spellAdded(spell); } } function feed_delinv(data, dataAsArray) { var container = parseInt(data.split(" ")[1]); if (container == player.tag) { myItems = []; } else if (container != 0) { containers["container_" + container] = []; } else { floorItems = []; } updateItemsList(); return false; } var expTable = []; var spellPaths = []; function feed_fx(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = 3; var out = ""; var type = 0; var nameX = ""; var len; while (buff.position < buff.length) { nameX = ""; var id = buff.unpack_w(); if (id == 0) { buff.readUint8(); type = buff.unpack_w(); continue; } len = buff.readUint8(); for (var i = 0; i < len; ++i) { var c = parseInt(buff.readUint8()); out = ""; out += "0123456789abcdef" [c & 0xf]; out = "0123456789abcdef" [c >> 4] + out; nameX += out; } var faceInfo = Faces.getByNum(id, true); faceInfo.setType(type).setName(nameX); if (faceInfo.isRequested) { faceInfo.load(); } } return false; } function feed_newmap(data, dataAsArray) { //messageBox("newmap"); map_clear(); } function feed_mapinfo(data, dataAsArray) { var parts = data.split(/ /); //map_clear(); return false; } function feed_msg(data, dataAsArray) { var o = null; if (data.indexOf("[") > 0) { o = JSON.parse(data.substr(4)); channels_addMessage(o[1], o) return true; } return false; } function feed_anim(data, dataAsArray) { return false; } function feed_stats(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = "stats".length + 1; while (buff.position < buff.length) { var stat = buff.readUint8(); var value; if (stat_32bit.contains(stat)) { value = buff.readUint32(); } else if (stat == CS_STAT_SPEED || stat == CS_STAT_WEAP_SP) { value = (1 / FLOAT_MULTF) * buff.readUint32(); } else if (stat == CS_STAT_RANGE || stat == CS_STAT_TITLE) { var len = buff.readUint8(); value = buff.readString(len); } else if (stat == CS_STAT_EXP64) { var hi = buff.readUint32(); var lo = buff.readUint32(); value = hi * Math.pow(2, 32) + lo; } else if (stat >= CS_STAT_SKILLINFO && stat < CS_STAT_SKILLINFO + CS_NUM_SKILLS) { var lvl = buff.readUint8(); var hi = buff.readUint32(); var lo = buff.readUint32(); value = [lvl, hi * Math.pow(2, 32) + lo]; if (!myStats[stat]){ Application.skillAdded (skillNames[stat - CS_STAT_SKILLINFO],stat,value); } } else { value = buff.readUint16(); if (value > 60000) { value -= 65536; } } myStats[stat] = value; //stats_update (stat); } return true; } function feed_player(data, dataAsArray) { var buff = new Buffer(dataAsArray); buff.position = "player ".length; //my ($tag, $weight, $face, $name) = unpack "NNN C/a", $data; player.tag = buff.readUint32(); player.weight = buff.readUint32(); player.face = buff.readUint32(); var len = buff.readUint8(); player.name = buff.readString(len); return false; } function feed_drawinfo(data, dataAsArray) { return false; } var tilesInfo = { getImgByFaceNum: function(id) { var fi = Faces.getByNum(id, true); return fi.resource; } } function need_facenum(num) { } function feed_map_scroll(data, dataAsArray, base64data) { data = data.split(/ /); data.shift(); dx += parseInt(data.shift()); dy += parseInt(data.shift()); } var tiles = []; function processExtObj(o) { switch (o[0]) { case "channel_info": channels[o[1].id] = o[1]; channels.list.push(channels[o[1].id]); channels[o[1].id].index = channels.length; channels.length += 1; return true; default: return false; break; } } function doSend(message) { writeToScreen("SENT: " + message); websocket.send(message); } isMainScriptLoaded = true;