diff --git a/xtrn/lord2/l2cfg.js b/xtrn/lord2/l2cfg.js new file mode 100644 index 0000000000000000000000000000000000000000..ddea53cba5463b1591f4c3b361706b5ba618ad5e --- /dev/null +++ b/xtrn/lord2/l2cfg.js @@ -0,0 +1,276 @@ +'use strict'; + +js.load_path_list.unshift(js.exec_dir+"dorkit/"); +load("dorkit.js", "-l"); +require("l2lib.js", "Player_Def"); + +function menu(title, blank_line, opts, cur) +{ + var legal = ''; + var i; + var ret; + var y; + var idx; + var done = false; + if (cur === undefined) + cur = 0; + var mctx = { + title:title, + blank_line:blank_line, + opts:opts, + cur:cur + }; + + function draw_menu() { + sclrscr(); + lw(mctx.title); + dk.console.cleareol(); + sln(''); + if (mctx.blank_line) + sln(''); + y = scr.pos.y; + conio.setcursortype(0); + for (i = 0; i < mctx.opts.length; i++) { + legal += mctx.opts[i].shortcut[0].toUpperCase(); + lw(mctx.opts[i].text); + dk.console.cleareol(); + sln(''); + } + } + + draw_menu(); + while(!done) { + dk.console.attr.value = 2; + dk.console.gotoxy(0, y + mctx.cur); + lw(ascii(251)); + ret = getkey().toUpperCase(); + dk.console.gotoxy(0, y + mctx.cur); + lw(' '); + switch(ret) { + case 'KEY_UP': + case '8': + mctx.cur--; + if (mctx.cur < 0) + mctx.cur = mctx.opts.length - 1; + break; + case 'KEY_DOWN': + case '2': + mctx.cur++; + if (mctx.cur >= mctx.opts.length) + mctx.cur = 0; + break; + case 'KEY_HOME': + case '7': + mctx.cur = 0; + break; + case 'KEY_END': + case '1': + mctx.cur = mctx.opts.length - 1; + break; + default: + idx = legal.indexOf(ret); + if (idx === -1) + break; + mctx.cur = idx; + // Fall-through + case '\r': + done = mctx.opts[mctx.cur].callback(mctx); + if (!done) + draw_menu(); + break; + } + } + conio.setcursortype(2); + return ret; +} + +dk.console.clear(); +menu('`r0`c `r1 `%LORD II: CONFIGURE JS `r0', true, [ + {text:' `2(`%G`2)ame Options', shortcut:'G', callback:function() { + sclrscr(); + sln(''); + sln(''); + menu('`r0`c `r1`%LORD II OPTION EDITOR`r0', true, [ + {text:' `2(`0A`2) Path to favorite text editor: `0' + game.editor, shortcut:'A', callback:function(ctx) { + dk.console.gotoxy(36, 4); + game.editor = dk.console.getstr({edit:game.editor, crlf:false, input_box:true, attr:new Attribute(31), sel_attr:new Attribute(112), len:40}); + ctx.opts[ctx.cur].text = ' `2(`0A`2) Path to favorite text editor: `0' + game.editor; + }}, + {text:' `2(`0B`2) Milliseconds between each poll: `0' + game.delay, shortcut:'B', callback:function(ctx) { + dk.console.gotoxy(38, 5); + game.delay = parseInt(dk.console.getstr({edit:game.delay.toString(), crlf:false, input_box:true, attr:new Attribute(31), sel_attr:new Attribute(112), len:7, max:999999, min:1, integer:true}), 10); + ctx.opts[ctx.cur].text = ' `2(`0B`2) Milliseconds between each poll: `0' + game.delay; + }}, + {text:' `2(`0D`2) Days of inactivity until deletion: `0' + game.deldays, shortcut:'C', callback:function(ctx) { + dk.console.gotoxy(41, 6); + game.deldays = parseInt(dk.console.getstr({edit:game.deldays.toString(), crlf:false, input_box:true, attr:new Attribute(31), sel_attr:new Attribute(112), len:7, max:999999, min:1, integer:true}), 10); + ctx.opts[ctx.cur].text = ' `2(`0D`2) Days of inactivity until deletion: `0' + game.deldays; + }}, + {text:' `2(`0E`2) Buffer extra keystrokes? (can make movement faster): `0' + (game.buffer ? '`%Yes' : '`4No'), shortcut:'E', callback:function(ctx) { + if (game.buffer) + game.buffer = 0; + else + game.buffer = 1; + ctx.opts[ctx.cur].text = ' `2(`0E`2) Buffer extra keystrokes? (can make movement faster): `0' + (game.buffer ? '`%Yes' : '`4No'); + }}, + {text:' `2(`0Q`2) Quit', shortcut:'Q', callback:function() {return true}} + ]); + return false; + }}, + {text:' `2(`%W`2)orld Editor', shortcut:'W', callback:function() { + var ch; + var x = 0; + var y = 0; + var block = y * 80 + x; + var redraw = 1; + var showname = false; + var tmap; + var emap; + var mname; + var fname; + var f; + + function edit_map(mapnum) { + map = load_map(mapnum + 1); + + if (map === null || map === undefined) + return; + + draw_map(); + getkey(); + } + + function update_details() { + dk.console.gotoxy(0, 20); + lw('`r0`2X:`0'+(x+1)+' `2Y:`0'+(y+1)+' `2Block: `%'+pretty_int(block+1)+' `2Map: `%'+world.mapdatindex[block]+' `$(`%E`$)xtract'); + dk.console.cleareol(); + if (showname) { + mname = 'Unused'; + if (world.mapdatindex[block] > 0) { + tmap = load_map(block + 1); + mname = tmap.name; + } + dk.console.gotoxy(2, 22); + lw('`2Map name : `0'+mname); + dk.console.cleareol(); + } + dk.console.gotoxy(0, 23); + lw('`r0 `$Enter to edit/create map. (`%F`$)orce assign. (`%T`$)og visibility. (`%S`$)how Name `%Q`$uit.'); + dk.console.gotoxy(x, y); + conio.setcursortype(1); + } + + function draw_screen() { + overheadmap(true); + } + + while(1) { + block = y * 80 + x; + if (redraw) + draw_screen(); + update_details(); + redraw = false; + ch = getkey().toUpperCase(); + conio.setcursortype(0); + switch(ch) { + case 'KEY_UP': + case '8': + if (--y < 0) + y = 19; + break; + case 'KEY_DOWN': + case '2': + if (++y >= 20) + y = 0; + break; + case 'KEY_LEFT': + case '4': + if (--x < 0) + x = 79; + break; + case 'KEY_RIGHT': + case '6': + if (++x >= 80) + x = 0; + break; + case '\r': + edit_map(block); + redraw = true; + break; + case 'E': + if (world.mapdatindex[block] < 1) { + dk.console.gotoxy(2, 23); + lw('`%No map to export at this location. `2(press a key)'); + dk.console.cleareol(); + getkey(); + break; + } + dk.console.gotoxy(2, 23); + lw('`2`r0Save/append this map to what file? '); + dk.console.cleareol(); + fname = dk.console.getstr({edit:'crap.dat', crlf:false, input_box:true, attr:new Attribute(31), sel_addr:new Attribute(112), len:40}); + f = new RecordFile(fname, Map_Def); + if (f === null) { + dk.console.gotoxy(2, 23); + lw('`%Unable to open `0'+fname+' `2(press a key)'); + dk.console.cleareol(); + getkey(); + break; + } + else { + tmap = load_map(block + 1); + if (tmap === null) { + dk.console.gotoxy(2, 23); + lw('`%No map to export at this location. `2(press a key)'); + dk.console.cleareol(); + getkey(); + break; + } + emap = f.new(); + if (emap === null || emap === undefined) { + dk.console.gotoxy(2, 23); + lw('`%Error creating new record in file. `2(press a key)'); + dk.console.cleareol(); + getkey(); + break; + } + Map_Def.forEach(function(prop) { + emap[prop.prop] = tmap[prop.prop]; + }); + emap.put(); + dk.console.gotoxy(2, 23); + lw('`%MAP ADDED AS RECORD '+f.length+' `2(press a key)'); + dk.console.cleareol(); + getkey(); + } + break; + case 'F': + dk.console.gotoxy(26, 20); + lw('`0Force block to reference physical map record '); + world.mapdatindex[block] = parseInt(dk.console.getstr({integer:true, edit:world.mapdatindex[block].toString(), crlf:false, input_box:true, attr:new Attribute(95), sel_attr:new Attribute(112), len:6, min:0, max:1600}), 10); + redraw = true; + break; + case 'T': + world.hideonmap[block] = !world.hideonmap[block]; + redraw = true; + break; + case 'S': + showname = !showname; + redraw = true; + break; + case 'Q': + return false; + } + } + }}, + {text:' `2(`%U`2)se Player Editor', shortcut:'U', callback:function() {}}, + {text:' `2(`%I`2)tem Editor', shortcut:'I', callback:function() {}}, + {text:' `2(`%R`2)eset Game', shortcut:'R', callback:function() {}}, + {text:' `2(`4Q`2)uit & Save', shortcut:'Q', callback:function() { + dk.console.gotoxy(0, 23); + lln(' `0Saving changes. Thanks for using this product.'); + game.put(); + world.put(); + return true + }} +]); diff --git a/xtrn/lord2/l2lib.js b/xtrn/lord2/l2lib.js new file mode 100644 index 0000000000000000000000000000000000000000..22bc94d1880e60606a31771116427a9696f55d90 --- /dev/null +++ b/xtrn/lord2/l2lib.js @@ -0,0 +1,1595 @@ +require("recordfile.js", "RecordFile"); +var scr; +if (dk.console.local_io !== undefined) + scr = dk.console.local_io.screen; +if (scr === undefined && dk.console.local_screen !== undefined) + scr = dk.console.local_screen; +if (scr === undefined && dk.console.remote_screen !== undefined) + scr = dk.console.remote_screen; +if (scr === undefined) + throw new Error('No usable screen!'); + +var UCASE = false; +var matchcase = true; +function getfname(str) +{ + str = str.replace(/\\/g,'/'); + if (matchcase) { + var ec = file_getcase(js.exec_dir + str); + + if (ec !== undefined) { + return ec; + } + } + if (UCASE) { + return js.exec_dir + str.toUpperCase(); + } + if (str.indexOf(maildir) === 0) { + str = str.toLowerCase().replace(/([\\\/])([^\/\\]+)$/, function(m, p1, p2) { return p1 + p2.toUpperCase(); }); + return js.exec_dir + str; + } + return js.exec_dir + str.toLowerCase(); +} + +var Player_Def = [ + { // 0 + prop:'name', + type:'PString:25', + def:'' + }, + { // 26 (1a) + prop:'realname', + type:'PString:40', + def:'' + }, + { // 67 (43) + prop:'money', + type:'SignedInteger', + def:0 + }, + { // 71 (47) + prop:'bank', + type:'SignedInteger', + def:0 + }, + { // 75 (4b) + prop:'experience', + type:'SignedInteger', + def:0 + }, + { // 79 (4f) + prop:'lastdayon', + type:'SignedInteger16', + def:-1 + }, + { // 81 (51) + prop:'love', + type:'SignedInteger16', + def:0 + }, + { // 83 (53) + prop:'weaponnumber', + type:'SignedInteger8', + def:0 + }, + { // 84 (54) + prop:'armournumber', + type:'SignedInteger8', + def:0 + }, + { // 85 (55) + prop:'race', + type:'PString:30', + def:'' + }, + { // 116 (74) + prop:'sexmale', + type:'SignedInteger16', + def:0 + }, + { // 118 (76) + prop:'onnow', + type:'Integer8', + def:0 + }, + { // 119 (77) + prop:'battle', + type:'Integer8', + def:0 + }, + { // 120 (78) + prop:'dead', + type:'SignedInteger16', + def:0 + }, + { // 122 (7a) + prop:'busy', + type:'SignedInteger16', + def:0 + }, + { // 124 (7c) + prop:'deleted', + type:'SignedInteger16', + def:0 + }, + { // 126 (7e) + prop:'nice', + type:'SignedInteger16', + def:0 + }, + { // 128 (80) + prop:'map', + type:'SignedInteger16', + def:0 + }, + { // 130 (82) + prop:'e6', + type:'SignedInteger16', + def:0 + }, + { // 132 (84) + prop:'x', + type:'SignedInteger16', + def:0 + }, + { // 134 (86) + prop:'y', + type:'SignedInteger16', + def:0 + }, + { // 136 (88) + prop:'i', + type:'Array:99:SignedInteger16', + def:eval('var aret = []; while(aret.length < 99) aret.push(0); aret;') + }, + { // 334 (14e) + prop:'p', + type:'Array:99:SignedInteger', + def:eval('var aret = []; while(aret.length < 99) aret.push(0); aret;') + }, + { // 720 (2d0) + prop:'t', + type:'Array:99:Integer8', + def:eval('var aret = []; while(aret.length < 99) aret.push(0); aret;') + }, + { // 819 (333) + prop:'lastsaved', + type:'SignedInteger', + def:-1 + }, + { // 823 (337) + prop:'lastdayplayed', + type:'SignedInteger', + def:-1 + }, + { // 827 (33b) + prop:'lastmap', + type:'SignedInteger16', + def:-1 + }, + { // 829 (33d) + prop:'extra', + type:'String:354', + def:'' + } +]; + +var Map_Def = [ + { + prop:'name', + type:'PString:30', + def:'' + }, + { + prop:'mapinfo', + type:{ + array:80*20, + recordDef:[ + { + prop:'forecolour', + type:'SignedInteger8', + def:7 + }, + { + prop:'backcolour', + type:'SignedInteger8', + def:0 + }, + { + prop:'ch', + type:'String:1', + def:' ' + }, + { + prop:'t', + type:'SignedInteger16', + def:0 + }, + { + prop:'terrain', + type:'SignedInteger8', + def:0 + }, + ] + }, + }, + { + prop:'hotspots', + type:{ + array:10, + recordDef:[ + { + prop:'warptomap', + type:'SignedInteger16', + def:0 + }, + { + prop:'hotspotx', + type:'SignedInteger8', + def:0 + }, + { + prop:'hotspoty', + type:'SignedInteger8', + def:0 + }, + { + prop:'warptox', + type:'SignedInteger8', + def:0 + }, + { + prop:'warptoy', + type:'SignedInteger8', + def:0 + }, + { + prop:'refsection', + type:'PString:12', + def:'' + }, + { + prop:'reffile', + type:'PString:12', + def:'' + }, + { + prop:'extra', + type:'String:100', + def:'' + }, + ] + } + }, + { + prop:'battleodds', + type:'SignedInteger', + def:0 + }, + { + prop:'reffile', + type:'PString:12', + def:'' + }, + { + prop:'refsection', + type:'PString:12', + def:'' + }, + { + prop:'nofighting', + type:'Boolean', + def:true + }, + { + prop:'extra', + type:'String:469', + def:'' + } +]; + +var World_Def = [ + { + prop:'name', + type:'PString:60', + def:'' + }, + { + prop:'mapdatindex', + type:'Array:1600:SignedInteger16', + def:new Array(1600) + }, + { + prop:'v', + type:'Array:40:SignedInteger', + def:new Array(40) + }, + { + prop:'s', + type:'Array:10:PString:80', + def:new Array(10) + }, + { + prop:'time', + type:'SignedInteger', + def:0 + }, + { + prop:'hideonmap', + type:'Array:1600:Integer8', + def:new Array(1600) + }, + { + prop:'extra', + type:'String:396', + def:'' + } +] + +var Item_Def = [ + { + prop:'name', + type:'PString:30', + def:'' + }, + { + prop:'hitaction', + type:'PString:40', + def:'' + }, + { + prop:'useonce', + type:'Boolean', + def:false + }, + { + prop:'armour', + type:'Boolean', + def:false + }, + { + prop:'weapon', + type:'Boolean', + def:false + }, + { + prop:'sell', + type:'Boolean', + def:false + }, + { + prop:'used', + type:'Boolean', + def:false + }, + { + prop:'value', + type:'SignedInteger', + def:false + }, + { + prop:'breakage', + type:'SignedInteger16', + def:false + }, + { + prop:'maxbuy', + type:'SignedInteger16', + def:false + }, + { + prop:'defence', + type:'SignedInteger16', + def:false + }, + { + prop:'strength', + type:'SignedInteger16', + def:false + }, + { + prop:'eat', + type:'SignedInteger16', + def:false + }, + { + prop:'refsection', + type:'PString:12', + def:false + }, + { + prop:'useaction', + type:'PString:30', + def:false + }, + { + prop:'description', + type:'PString:30', + def:false + }, + { + prop:'questitem', + type:'Boolean', + def:false + }, + { + prop:'extra', + type:'String:37', + def:false + }, +]; + +var Update_Def = [ + { + prop:'x', + type:'SignedInteger8', + def:0 + }, + { + prop:'y', + type:'SignedInteger8', + def:0 + }, + { + prop:'map', + type:'SignedInteger16', + def:155 + }, + { + prop:'onnow', + type:'Integer8', + def:0 + }, + { + prop:'busy', + type:'Integer8', + def:0 + }, + { + prop:'battle', + type:'Integer8', + def:0 + }, +]; + +var Game_Def = [ + { + prop:'pad0', + type:'String:8', + def:'' + }, + // Offset 8 is days to deletion + { + prop:'deldays', + type:'Integer', + def:15 + }, + + { + prop:'pad1', + type:'String:150', + def:'' + }, + // Offset 162 is path to editor + { + prop:'editor', + type:'PString:40', + def:'' + }, + { + prop:'pad4', + type:'String:20', + def:'' + }, + // Offset 223 is 32-bit delay + { + prop:'delay', + type:'Integer', + def:100 + }, + // Offset 223 and 227 seem to be the version maybe? + { + prop:'pad2', + type:'String:4', + def:'' + }, + // Offset 231 is buffer strokes + { + prop:'buffer', + type:'Integer8', + def:1 + }, + { + prop:'pad3', + type:'String:1990', + def:'' + } +]; + +function getkeyw() +{ + var timeout = time() + 60 * 5; + var tl; + var now; + + do { + now = time(); + // TODO: dk.console.getstr() doesn't support this stuff... (yet) + tl = (dk.user.seconds_remaining + dk.user.seconds_remaining_from - 30) - now; + if (tl < 1) { + // TODO message etc + exit(0); + } + if (now >= timeout) { + // TODO message etc + exit(0); + } + } while(!dk.console.waitkey(1000)); + return dk.console.getkey(); +} + +var curlinenum = 1; +var curcolnum = 1; +var morechk = true; +var morestr = '`2<`0MORE`2>'; +// Reads a key +function getkey() +{ + var ch; + var a; + + curlinenum = 1; + ch = '\x00'; + do { + ch = getkeyw(); + if (ch === null || ch.length < 1) { + ch = '\x00'; + } + } while (ch === '\x00'); + + return ch; +} + +function remove_colour(str) +{ + if (typeof str !== 'string') + return str; + str = str.replace(/`[0-9\!-^]/g, ''); + str = str.replace(/`r[0-7]/g, ''); + return str; +} + +function clean_str(str) +{ + var ret = ''; + var i; + + for (i = 0; i < str.length; i += 1) { + if (str[i] === '$') { + // Just skip it. + } + else if (str[i] !== '`') { + ret += str[i]; + } + else { + switch (str[i+1]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '!': + case '@': + case '#': + case '$': + case '%': + ret += str[i]; + break; + default: + i += 1; + } + } + } + + // TODO: This is where badwords replacements should happen... + + return ret; +} + +function superclean(str) +{ + return remove_colour(expand_ticks(replace_vars(str))); +} + +function lord_to_ansi(str) +{ + var ret = '\x1b[0m'; + var i; + var bg = ''; + var bright = false; + + for (i=0; i<str.length; i += 1) { + if (str[i] === '`') { + i += 1; + switch(str[i]) { + case 'c': + ret += '\x1b[2J\x1b[H\r\n\r\n'; + break; + case '1': + if (bright) + ret += '\x1b[0;34'+bg+'m'; + else + ret += '\x1b[34m'; + bright = false; + break; + case '^': + if (bright) + ret += '\x1b[0;30'+bg+'m'; + else + ret += '\x1b[30m'; + bright = false; + break; + case '*': + // TODO: This may not do 41... + if (bright) { + ret += '\x1b[0;30;41m'; + } + else + ret += '\x1b[30;41m'; + bg = ';41'; + bright = false; + break; + case '2': + if (bright) + ret += '\x1b[0;32'+bg+'m'; + else + ret += '\x1b[32m'; + bright = false; + break; + case '3': + if (bright) + ret += '\x1b[0;36'+bg+'m'; + else + ret += '\x1b[36m'; + bright = false; + break; + case '4': + if (bright) + ret += '\x1b[0;31'+bg+'m'; + else + ret += '\x1b[31m'; + bright = false; + break; + case '5': + if (bright) + ret += '\x1b[0;35'+bg+'m'; + else + ret += '\x1b[35m'; + bright = false; + break; + case '6': + if (bright) + ret += '\x1b[0;33;'+bg+'m'; + else + ret += '\x1b[33m'; + bright = false; + break; + case '7': + if (bright) + ret += '\x1b[0;37'+bg+'m'; + else + ret += '\x1b[37m'; + bright = false; + break; + case '8': + if (bright) + ret += '\x1b[30m'; + else + ret += '\x1b[1;30m'; + bright = true; + break; + case '9': + if (bright) + ret += '\x1b[34m'; + else + ret += '\x1b[1;34m'; + bright = true; + break; + case '0': + if (bright) + ret += '\x1b[32m'; + else + ret += '\x1b[1;32m'; + bright = true; + break; + case '!': + if (bright) + ret += '\x1b[36m'; + else + ret += '\x1b[1;36m'; + bright = true; + break; + case '@': + if (bright) + ret += '\x1b[31m'; + else + ret += '\x1b[1;31m'; + bright = true; + break; + case '#': + if (bright) + ret += '\x1b[35m'; + else + ret += '\x1b[1;35m'; + bright = true; + break; + case '$': + if (bright) + ret += '\x1b[33m'; + else + ret += '\x1b[1;33m'; + bright = true; + break; + case '%': + if (bright) + ret += '\x1b[37m'; + else + ret += '\x1b[1;37m'; + bright = true; + break; + case 'r': + i += 1; + switch(str[i]) { + case '0': + ret += '\x1b[40m'; + bg = ''; + break; + case '1': + ret += '\x1b[44m'; + bg = ';44'; + break; + case '2': + ret += '\x1b[42m'; + bg = ';42' + break; + case '3': + ret += '\x1b[43m'; + bg = ';43'; + break; + case '4': + ret += '\x1b[41m'; + bg = ';41'; + break; + case '5': + ret += '\x1b[45m'; + bg = ';45'; + break; + case '6': + ret += '\x1b[47m'; + bg = ';47'; + break; + case '7': + ret += '\x1b[46m'; + bg = ';46'; + break; + } + break; + } + } + else { + ret += str[i]; + } + } + return ret; +} + +function displen(str) +{ + return superclean(str).length; +} + +// FRONTPAD is broken on colour codes. +// It doesn't ignore colour codes. +function broken_displen(str) +{ + var i; + + str = expand_ticks(replace_vars(str)); + return str.length; +} + +function sw(str) { + if (str === '') { + return; + } + if (str === '\r\n') { + curcolnum = 1; + } + dk.console.print(str); + if (str !== '\r\n') { + curcolnum += str.length; + } +} + +function sln(str) +{ + // *ALL* CRLFs should be sent from here! + if (str !== '') { + sw(str); + } + sw('\r\n'); + curlinenum += 1; + if (morechk) { + if (curlinenum > 24) { + more(); + curlinenum = 1; + } + } + else { + curlinenum = 1; + } +} + +function sclrscr() +{ + var oa = dk.console.attr.value; + + dk.console.clear(); + dk.console.attr.value = oa; + curlinenum = 1; +} + +function clearrows(start, end) +{ + var row; + + if (end === undefined) + end = start; + + dk.console.attr.value = 2; + for (row = start; row <= end; row++) { + dk.console.gotoxy(0, row); + dk.console.cleareol(); + } +} + +function foreground(col) +{ + if (col > 15) { + col = 0x80 | (col & 0x0f); + } + dk.console.attr.value = (dk.console.attr.value & 0x70) | col; +} + +function background(col) +{ + if (col > 7 || col < 0) { + return; + } + dk.console.attr.value = (dk.console.attr.value & 0x8f) | (col << 4); +} + +function more() +{ + var oa = dk.console.attr.value; + + curlinenum = 1; + lw('`r0`2 '+morestr); + getkey(); + dk.console.print('\r'); + dk.console.cleareol(); + dk.console.attr.value = oa; +} + +function handle_lordcodes(str) +{ + var i; + var to; + var oop; + var snip = ''; + var lwch; + + for (i=0; i<str.length; i += 1) { + if (str[i] === '`') { + sw(snip); + snip = ''; + i += 1; + if (i >= str.length) { + break; + } + switch(str[i]) { + case 'k': + case 'K': + more(); + break; + case 'w': + case 'W': + mswait(100); + break; + case 'l': + case 'L': + mswait(500); + break; + case '1': // BLUE + foreground(1); + break; + case '2': // GREEN + foreground(2); + break; + case '3': // CYAN + foreground(3); + break; + case '4': // RED + foreground(4); + break; + case '5': // MAGENTA + foreground(5); + break; + case '6': // YELLOW + foreground(6); + break; + case '7': // WHITE/GRAY + foreground(7); + break; + case '8': + foreground(8); + break; + case '9': + foreground(9); + break; + case '0': + foreground(10); + break; + case '!': + foreground(11); + break; + case '@': + foreground(12); + break; + case '#': + foreground(13); + break; + case '$': + foreground(14); + break; + case '%': + foreground(15); + break; + case '^': + case '*': + foreground(0); + break; + case 'b': + case 'B': + foreground(20); // Blinking red + break; + case 'c': + case 'C': + sclrscr(); + sln(''); + sln(''); + break; + case 'y': + case 'Y': + foreground(30); // Blinking yellow + break; + case 'r': + case 'R': + i += 1; + if (i >= str.length) { + break; + } + switch (str[i]) { + case '0': + background(0); + break; + case '1': + background(1); + break; + case '2': + background(2); + break; + case '3': + background(3); + break; + case '4': + background(4); + break; + case '5': + background(5); + break; + case '6': + background(6); + break; + case '7': + background(7); + break; + } + break; + } + } + else { + snip += str[i]; + } + } + sw(snip); +} + +function lw(str) { + str = replace_vars(str); + handle_lordcodes(str); +} + +function lln(str) +{ + lw(str); + sln(''); +} + +function repeat_chars(ch, len) +{ + var r = ''; + var i; + + for (i = 0; i < len; i++) + r += ch; + return r; +} + +function spaces(len) +{ + return repeat_chars(' ', len); +} + +function space_pad(str, len) +{ + var dl = displen(str); + var alen = Math.abs(len); + + while (dl < alen) { + if (len < 0) + str = ' ' + str; + else + str += ' '; + dl++; + } + + return str; +} + +function pretty_int(int, rpad) +{ + var ret = parseInt(int, 10).toString(); + var i; + if (rpad === undefined) + rpad = 0; + + for (i = ret.length - 3; i > 0; i-= 3) { + ret = ret.substr(0, i)+','+ret.substr(i); + } + ret = space_pad(ret, rpad); + return ret; +} + +function clamp_integer(v, s) +{ + var i = parseInt(v, 10); + if (isNaN(i)) + throw new Error('Invalid integer (' + s + '): ' + v); + + switch(s) { + case 's8': + if (i > 127) + i = 127; + else if (i < -128) + i = -128; + break; + case '8': + if (i >255) + i = 255; + else if (i < 0) + i = 0; + break; + case 's16': + if (i > 32767) + i = 32767; + else if (i < -32768) + i = -32768 + break; + case '16': + if (i > 65535) + i = 65535; + else if (i < 0) + i = 0; + break; + case 's32': + if (i > 2147483647) + i = 2147483647; + else if (i < -2147483648) + i = -2147483648; + break; + case '32': + if (i > 4294967295) + i = 4294967295; + else if (i < 0) + i = 0; + break; + default: + throw new Error('Invalid clamp style '+s); + } + return i; +} + +var state = { + time:0 +}; +var files = {}; +var vars = { + version:{type:'const', val:103}, + 'nil':{type:'const', val:''}, + '`n':{type:'fn', get:function() { return player.name } }, + '`e':{type:'fn', get:function() { return getvar('enemy'); } }, + '`g':{type:'int', val:3}, // TODO: >= 3 is ANSI or something... + '`x':{type:'const', val:' '}, + '`d':{type:'const', val:'\b'}, + '`\\':{type:'const', val:'\r\n'}, + '`*':{type:'const', val:dk.connection.node}, + x:{type:'fn', get:function() { return player.x }, set:function(x) { player.x = clamp_integer(x, 's8'); } }, + y:{type:'fn', get:function() { return player.y }, set:function(y) { player.y = clamp_integer(y, 's8'); } }, + map:{type:'fn', get:function() { return player.map }, set:function(map) { player.map = clamp_integer(map, 's16') } }, + dead:{type:'fn', get:function() { return player.dead }, set:function(dead) { player.dead = clamp_integer(dead, 's8') } }, + sexmale:{type:'fn', get:function() { return player.sexmale }, set:function(sexmale) { player.sexmale = clamp_integer(sexmale, 's16') } }, + narm:{type:'fn', get:function() { return player.armournumber }, set:function(narm) { player.armournumber = clamp_integer(narm, 's8') } }, + nwep:{type:'fn', get:function() { return player.weaponnumber }, set:function(nwep) { player.weaponnumber = clamp_integer(nwep, 's8') } }, + money:{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, + gold:{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, + bank:{type:'fn', get:function() { return player.bank }, set:function(bank) { player.bank = clamp_integer(bank, 's32') } }, + enemy:{type:'str', val:''}, + local:{type:'fn', get:function() { return (dk.system.mode === 'local' ? 5 : 0) } }, + blockpassable:{type:'fn', get:function() { return (map.mapinfo[getpoffset()].terrain === 1 ? 1 : 0); } }, + '&realname':{type:'const', val:dk.user.full_name}, + '&date':{type:'fn', get:function() { var d = new Date(); return format('%02d/%02d/%02d', d.getMonth()+1, d.getDate(), d.getYear()%100); }, set:function(x) { throw new Error('Attempt to set date at '+fname+':'+line); } }, + // DOCUMENTED in LORD 2 but non-functional. + //'&nicedate':{type:'fn', get:function() { var d = new Date(); return format('%d:%02d on %02d/%02d/%02d', d.getHours() % 12, d.getMinutes(), d.getMonth()+1, d.getDate(), d.getYear()%100); }, set:function(x) { throw new Error('Attempt to set nicedate at '+fname+':'+line); } }, + // Implemented in LORD 2 (but not documented) + '&quickdate':{type:'fn', get:function() { var d = new Date(); return format('%d:%02d on %02d/%02d/%02d', d.getHours() % 12, d.getMinutes(), d.getMonth()+1, d.getDate(), d.getYear()%100); }, set:function(x) { throw new Error('Attempt to set nicedate at '+fname+':'+line); } }, + 's&armour':{type:'fn', get:function() { if (player.armournumber === 0) return ''; return items[player.armournumber - 1].name; } }, + 's&arm_num':{type:'fn', get:function() { if (player.armournumber === 0) return 0; return items[player.armournumber - 1].defence; } }, + 's&weapon':{type:'fn', get:function() { if (player.weaponnumber === 0) return ''; return items[player.weaponnumber - 1].name; } }, + 's&wep_num':{type:'fn', get:function() { if (player.weaponnumber === 0) return 0; return items[player.weaponnumber - 1].strength; } }, + 's&son':{type:'fn', get:function() { return player.sexmale === 1 ? 'son' : 'daughter' }}, + 's&boy':{type:'fn', get:function() { return player.sexmale === 1 ? 'boy' : 'girl' }}, + 's&man':{type:'fn', get:function() { return player.sexmale === 1 ? 'man' : 'lady' }}, + 's&sir':{type:'fn', get:function() { return player.sexmale === 1 ? 'sir' : 'ma\'am' }}, + 's&him':{type:'fn', get:function() { return player.sexmale === 1 ? 'him' : 'her' }}, + 's&his':{type:'fn', get:function() { return player.sexmale === 1 ? 'his' : 'her' }}, + 's&he':{type:'fn', get:function() { return player.sexmale === 1 ? 'he' : 'she' }}, + '&money':{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, + '&gold':{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, + '&bank':{type:'fn', get:function() { return player.bank }, set:function(bank) { player.bank = clamp_integer(bank, 's32') } }, + '&lastx':{type:'fn', get:function() { return player.lastx }, set:function(bank) { player.lastx = clamp_integer(bank, 's8') } }, + '&lasty':{type:'fn', get:function() { return player.lasty }, set:function(bank) { player.lasty = clamp_integer(bank, 's8') } }, + '&map':{type:'fn', get:function() { return player.map } }, + '&lmap':{type:'fn', get:function() { return player.lastmap } }, + '&time':{type:'fn', get:function() { return state.time }, set:function(x) { throw new Error('attempt to set &time'); } }, + '&timeleft':{type:'fn', get:function() { return parseInt((dk.user.seconds_remaining + dk.user.seconds_remaining_from - time()) / 60, 10) } }, + '&sex':{type:'fn', get:function() { return player.sexmale }, set:function(sexmale) { player.sexmale = clamp_integer(sexmale, 's16') } }, + '&playernum':{type:'fn', get:function() { return player.Record + 1 } }, + '&totalaccounts':{type:'fn', get:function() { return pfile.length } }, + responce:{type:'int', val:0}, + response:{type:'fn', get:function() { return vars.responce.val; }, set:function(val) { vars.responce.val = clamp_integer(val, 's32') } }, +}; +var i; +for (i = 0; i < 40; i++) { + vars[format('`v%02d', i+1)] = {type:'fn', get:eval('function() { return world.v['+i+'] }'), set:eval('function(val) { world.v['+i+'] = clamp_integer(val, "s32"); }')}; +} +for (i = 0; i < 10; i++) { + vars[format('`s%02d', i+1)] = {type:'fn', get:eval('function() { return world.s['+i+'] }'), set:eval('function(val) { world.s['+i+'] = val.substr(0, 80); }')}; +} +for (i = 0; i < 99; i++) { + vars[format('`p%02d', i+1)] = {type:'fn', get:eval('function() { return player.p['+i+'] }'), set:eval('function(val) { player.p['+i+'] = clamp_integer(val, "s32"); }')}; + vars[format('`t%02d', i+1)] = {type:'fn', get:eval('function() { return player.t['+i+'] }'), set:eval('function(val) { player.t['+i+'] = clamp_integer(val, "8"); }')}; + vars[format('`i%02d', i+1)] = {type:'fn', get:eval('function() { return player.i['+i+'] }'), set:eval('function(val) { player.i['+i+'] = clamp_integer(val, "s16"); }')}; + vars[format('`+%02d', i+1)] = {type:'fn', get:eval('function() { return items['+i+'].name }'), set:eval('function(val) { throw new Error("Attempt to set item '+i+' name"); }')}; +} + +function setvar(name, val) { + var t; + + name = name.toLowerCase(); + if (vars[name] === undefined) + throw new Error('Attempt to set invalid variable '+name); + switch(vars[name].type) { + case 'int': + t = parseInt(val); + if (isNaN(t)) + throw new Error('Invalid value '+val+' assigned to '+name); + if (t > 2147483647) + t = 2147483648; + if (t < -2147483648) + t = -2147483648; + vars[name].val = t; + break; + case 'str': + vars[name].val = val.toString(); + break; + case 'const': + throw new Error('Attempt to set const value '+name); + case 'bool': + if (val) + vars[name].val = true; + else + vars[name].val = false; + break; + case 'fn': + vars[name].set(val); + break; + default: + throw new Error('Unhandled var type '+vars[name].type); + } +} + +function getvar(name, replacing) { + var uc = false; + var lc = false; + var ret; + + if (vars[name.toLowerCase()] === undefined) { + if (replacing === true) + return name; + return replace_vars(name); + } + if (name.substr(0, 2) === 'S&') + uc = true; + if (name.substr(0, 2) === 's&') + lc = true; + name = name.toLowerCase(); + switch(vars[name].type) { + case 'int': + case 'str': + case 'const': + ret = vars[name].val; + break; + case 'bool': + if (vars[name].val) + ret = 1; + ret = 0; + break; + case 'fn': + ret = vars[name].get(); + break; + default: + throw new Error('Unhandled var type '+vars[name].type); + } + if (uc || lc) + ret = ret.toString(); + if (uc) + ret = ret.substr(0, 1).toUpperCase() + ret.substr(1); + if (lc) + ret = ret.substr(0, 1).toLowerCase() + ret.substr(1); + return ret; +} + +function getsvar(name, vname) +{ + var v = getvar(name); + var fv = getvar(vname); + + if (typeof fv === 'string' && typeof v !== 'string') + return replace_vars(name); + return v; +} + +function expand_ticks(str) +{ + if (typeof str !== 'string') + return str; + str = str.replace(/`w/ig, ''); + str = str.replace(/`l/ig, ''); + str = str.replace(/`c/ig, ''); + return str; +} + +function replace_vars(str) +{ + if (typeof str !== 'string') + return str; + str = str.replace(/([Ss]?&[A-Za-z]+)/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[Vv][0-4][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[Ss][0-1][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[Pp][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[Tt][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[Ii][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[Ii][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`\+[0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); + str = str.replace(/(`[nexdNEXD\\\*])/g, function(m, r1) { return getvar(r1, true); }); + return str; +} + +function getoffset(x, y) { + return (x * 20 + y); +} + +function draw_map() { + var x; + var y; + var off; + var mi; + var s; + + // We can't auto-load the players map here because of ORACLE2.REF in CNW + if (map === null || map === undefined) + map = load_map(player.map); + + dk.console.attr.value = 7; + // No need to clear screen since we're overwriting the whole thing. + // TODO: If dk.console had a function to clear to end of screen, that would help. + last_draw = undefined; + for (y = 0; y < 20; y++) { + for (x = 0; x < 80; x++) { + off = getoffset(x,y); + mi = map.mapinfo[off]; + foreground(mi.forecolour); + background(mi.backcolour); + dk.console.gotoxy(x, y); + if (x == 79) + dk.console.cleareol(); + dk.console.print(mi.ch === '' ? ' ' : mi.ch); + } + } + clearrows(21, dk.console.rows - 1); + other_players = {}; +} + +function load_map(mapnum) +{ + return mfile.get(world.mapdatindex[mapnum - 1] - 1); +} + +function box_top(width, title) +{ + var str; + + str = '`r1`0'+ascii(218) + repeat_chars(ascii(196), parseInt(((width - 2) - displen(title)) / 2, 10)) + title + '`r1`0'; + str += repeat_chars(ascii(196), (width - 1) - displen(str)); + str += ascii(191); + return str; +} + +function box_bottom(width) +{ + return '`r1`0'+ascii(192)+repeat_chars(ascii(196), (width - 2))+ascii(217); +} + +function box_middle(width, text, highlight) +{ + var str = '`r1`0'+ascii(179)+' '; + if (highlight) + str += '`r5'; + str += text; + str += '`r1`0'; + str += spaces((width - 1) - displen(str)); + str += ascii(179); + return str; +} + +function draw_box(y, title, lines, width) +{ + var x; + + if (width === undefined) { + width = displen(title) + 6; + lines.forEach(function(l) { + var len = displen(l) + 6; + if (len > width) + width = len; + }); + } + + x = Math.floor((80-width) / 2); + + dk.console.gotoxy(x, y); + lw(box_top(width, title)); + lines.forEach(function(l, i) { + dk.console.gotoxy(x, y + i + 1); + lw(box_middle(width, l)); + }); + dk.console.gotoxy(x, y + lines.length + 1); + lw(box_bottom(width)); + return {width:width, y:y, x:x}; +} + +function load_items() +{ + var i; + + for (i = 0; i < ifile.length; i++) + items.push(ifile.get(i)); +} + +function load_players() +{ + var i; + var p; + + players = []; + for (i = 0; i < pfile.length; i++) { + p = pfile.get(i); + players.push({x:p.x, y:p.y, map:p.map, onnow:p.onnow, busy:p.busy, battle:p.battle, deleted:p.deleted}); + } +} + +function load_game() +{ + if (gfile.length > 0) + game = gfile.get(0); + else { + game = gfile.new(); + game.put(); + } +} + +function build_index() +{ + var i; + var p; + var u; + + for (i = 0; i < pfile.length; i++) { + u = ufile.get(i); + if (u === null) { + u = ufile.new(); + p = pfile.Get(i); + u.x = p.x; + u.y = p.y; + u.map = p.map; + u.onnow = p.onnow; + u.busy = p.busy; + u.battle = p.battle; + u.deleted = p.deleted; + u.put(); + } + } +} + +function erase(x, y) { + var off = getoffset(x,y); + var mi; + var attr = dk.console.attr.value; + + if (map !== undefined) { + mi = map.mapinfo[off]; + foreground(mi.forecolour); + background(mi.backcolour); + dk.console.gotoxy(x, y); + dk.console.print(mi.ch === '' ? ' ' : mi.ch); + dk.console.attr.value = attr; + } +} + +function get_inventory() +{ + var inv = []; + for (i = 0; i < 99; i++) { + if (player.i[i] > 0) + inv.push(i+1); + } + return inv; +} + +function ranked_players(prop) +{ + var i; + var ret = []; + var pl; + + for (i = 0; i < pfile.length; i++) { + pl = pfile.get(i); + if (pl.deleted === 1) + continue; + ret.push(pfile.get(i)); + } + + function sortfunc(a, b) { + function getprop(pl) { + var ret; + var op = player; + + player = pl; + ret = getvar(prop); + player = op; + } + + var ap, bp; + + if (prop !== undefined) { + ap = getprop(a); + bp = getprop(b); + if (ap !== bp) + return bp - ap; + } + if (a.p[0] !== b.p[0]) + return b.p[0] - a.p[0]; + if (a.p[8] !== b.p[8]) + return b.p[8] - a.p[8]; + if (a.p[17] !== b.p[17]) + return b.p[17] - a.p[17]; + if ((a.money + a.bank) !== (b.money + b.bank)) + return (b.money + b.bank) - (a.money + a.bank); + if (a.p[18] !== b.p[18]) + return b.p[18] - a.p[18]; + if (a.p[2] !== b.p[2]) + return b.p[2] - a.p[2]; + if (a.p[33] !== b.p[33]) + return b.p[33] - a.p[33]; + if (a.p[35] !== b.p[35]) + return b.p[35] - a.p[35]; + } + + return ret.sort(sortfunc); +} + +function overheadmap(showhidden) +{ + var off; + var x, y; + + dk.console.gotoxy(0, 0); + for (y = 0; y < 20; y++) { + dk.console.gotoxy(0, y); + for (x = 0; x < 80; x++) { + off = y * 80 + x; + if (world.mapdatindex[off] < 1) + background(1); + else if (world.hideonmap[off]) { + if (showhidden) + background(3); + else + background(1); + } + else + background(2); + lw(' '); + } + } + clearrows(20, 25); +} + +function getpoffset() { + return (player.x - 1)*20+(player.y - 1); +} + +var player; +var players = []; +var map; +var world; +var game; +var items = []; +var other_players = {}; +var pfile = new RecordFile(getfname('trader.dat'), Player_Def); +var mfile = new RecordFile(getfname('map.dat'), Map_Def); +var wfile = new RecordFile(getfname('world.dat'), World_Def); +var ifile = new RecordFile(getfname('items.dat'), Item_Def); +var ufile = new RecordFile(getfname('update.tmp'), Update_Def); +if (ufile.length < pfile.length) { + build_index(); +} +var gfile = new RecordFile(getfname('game.dat'), Game_Def); +var maildir = getfname('mail'); + +if (!file_isdir(maildir)) { + mkdir(maildir); + if (!file_isdir(maildir)) + throw new Error('Unable to create mail directory'); +} +maildir = backslash(maildir).replace(js.exec_dir, ''); +world = wfile.get(0); +load_players(); +load_items(); +load_game(); + diff --git a/xtrn/lord2/lord2.js b/xtrn/lord2/lord2.js index f7f3ca2da8272b55bf7bdc072319b36a496da09d..9f661e1ce39fad48b40c339f42b7a8a0ddded6c2 100644 --- a/xtrn/lord2/lord2.js +++ b/xtrn/lord2/lord2.js @@ -15,23 +15,9 @@ if (js.global.console !== undefined) { console.ctrlkey_passthru = '+[UOPTKZ'; } -var scr; -if (dk.console.local_io !== undefined) - scr = dk.console.local_io.screen; -if (scr === undefined && dk.console.local_screen !== undefined) - scr = dk.console.local_screen; -if (scr === undefined && dk.console.remote_screen !== undefined) - scr = dk.console.remote_screen; -if (scr === undefined) - throw new Error('No usable screen!'); -require("recordfile.js", "RecordFile"); - -var player; -var players = []; +require("l2lib.js", 'Player_Def'); + var update_rec; -var map; -var world; -var game; var killfiles = []; var enemy = undefined; var saved_cursor = {x:0, y:0}; @@ -40,493 +26,6 @@ var time_warnings = []; var file_pos = {con:0}; var last_draw; -var items = []; -var other_players = {}; -var Player_Def = [ - { // 0 - prop:'name', - type:'PString:25', - def:'' - }, - { // 26 (1a) - prop:'realname', - type:'PString:40', - def:'' - }, - { // 67 (43) - prop:'money', - type:'SignedInteger', - def:0 - }, - { // 71 (47) - prop:'bank', - type:'SignedInteger', - def:0 - }, - { // 75 (4b) - prop:'experience', - type:'SignedInteger', - def:0 - }, - { // 79 (4f) - prop:'lastdayon', - type:'SignedInteger16', - def:-1 - }, - { // 81 (51) - prop:'love', - type:'SignedInteger16', - def:0 - }, - { // 83 (53) - prop:'weaponnumber', - type:'SignedInteger8', - def:0 - }, - { // 84 (54) - prop:'armournumber', - type:'SignedInteger8', - def:0 - }, - { // 85 (55) - prop:'race', - type:'PString:30', - def:'' - }, - { // 116 (74) - prop:'sexmale', - type:'SignedInteger16', - def:0 - }, - { // 118 (76) - prop:'onnow', - type:'Integer8', - def:0 - }, - { // 119 (77) - prop:'battle', - type:'Integer8', - def:0 - }, - { // 120 (78) - prop:'dead', - type:'SignedInteger16', - def:0 - }, - { // 122 (7a) - prop:'busy', - type:'SignedInteger16', - def:0 - }, - { // 124 (7c) - prop:'deleted', - type:'SignedInteger16', - def:0 - }, - { // 126 (7e) - prop:'nice', - type:'SignedInteger16', - def:0 - }, - { // 128 (80) - prop:'map', - type:'SignedInteger16', - def:0 - }, - { // 130 (82) - prop:'e6', - type:'SignedInteger16', - def:0 - }, - { // 132 (84) - prop:'x', - type:'SignedInteger16', - def:0 - }, - { // 134 (86) - prop:'y', - type:'SignedInteger16', - def:0 - }, - { // 136 (88) - prop:'i', - type:'Array:99:SignedInteger16', - def:eval('var aret = []; while(aret.length < 99) aret.push(0); aret;') - }, - { // 334 (14e) - prop:'p', - type:'Array:99:SignedInteger', - def:eval('var aret = []; while(aret.length < 99) aret.push(0); aret;') - }, - { // 720 (2d0) - prop:'t', - type:'Array:99:Integer8', - def:eval('var aret = []; while(aret.length < 99) aret.push(0); aret;') - }, - { // 819 (333) - prop:'lastsaved', - type:'SignedInteger', - def:-1 - }, - { // 823 (337) - prop:'lastdayplayed', - type:'SignedInteger', - def:-1 - }, - { // 827 (33b) - prop:'lastmap', - type:'SignedInteger16', - def:-1 - }, - { // 829 (33d) - prop:'extra', - type:'String:354', - def:'' - } -]; - -var Map_Def = [ - { - prop:'name', - type:'PString:30', - def:'' - }, - { - prop:'mapinfo', - type:{ - array:80*20, - recordDef:[ - { - prop:'forecolour', - type:'SignedInteger8', - def:7 - }, - { - prop:'backcolour', - type:'SignedInteger8', - def:0 - }, - { - prop:'ch', - type:'String:1', - def:' ' - }, - { - prop:'t', - type:'SignedInteger16', - def:0 - }, - { - prop:'terrain', - type:'SignedInteger8', - def:0 - }, - ] - }, - }, - { - prop:'hotspots', - type:{ - array:10, - recordDef:[ - { - prop:'warptomap', - type:'SignedInteger16', - def:0 - }, - { - prop:'hotspotx', - type:'SignedInteger8', - def:0 - }, - { - prop:'hotspoty', - type:'SignedInteger8', - def:0 - }, - { - prop:'warptox', - type:'SignedInteger8', - def:0 - }, - { - prop:'warptoy', - type:'SignedInteger8', - def:0 - }, - { - prop:'refsection', - type:'PString:12', - def:0 - }, - { - prop:'reffile', - type:'PString:12', - def:0 - }, - { - prop:'extra', - type:'String:100', - def:'' - }, - ] - } - }, - { - prop:'battleodds', - type:'SignedInteger', - def:0 - }, - { - prop:'reffile', - type:'PString:12', - def:'' - }, - { - prop:'refsection', - type:'PString:12', - def:'' - }, - { - prop:'nofighting', - type:'Boolean', - def:true - }, - { - prop:'extra', - type:'String:469', - def:'' - } -]; - -var World_Def = [ - { - prop:'name', - type:'PString:60', - def:'' - }, - { - prop:'mapdatindex', - type:'Array:1600:SignedInteger16', - def:new Array(1600) - }, - { - prop:'v', - type:'Array:40:SignedInteger', - def:new Array(40) - }, - { - prop:'s', - type:'Array:10:PString:80', - def:new Array(10) - }, - { - prop:'time', - type:'SignedInteger', - def:0 - }, - { - prop:'hideonmap', - type:'Array:1600:Integer8', - def:new Array(1600) - }, - { - prop:'extra', - type:'String:396', - def:'' - } -] - -var Item_Def = [ - { - prop:'name', - type:'PString:30', - def:'' - }, - { - prop:'hitaction', - type:'PString:40', - def:'' - }, - { - prop:'useonce', - type:'Boolean', - def:false - }, - { - prop:'armour', - type:'Boolean', - def:false - }, - { - prop:'weapon', - type:'Boolean', - def:false - }, - { - prop:'sell', - type:'Boolean', - def:false - }, - { - prop:'used', - type:'Boolean', - def:false - }, - { - prop:'value', - type:'SignedInteger', - def:false - }, - { - prop:'breakage', - type:'SignedInteger16', - def:false - }, - { - prop:'maxbuy', - type:'SignedInteger16', - def:false - }, - { - prop:'defence', - type:'SignedInteger16', - def:false - }, - { - prop:'strength', - type:'SignedInteger16', - def:false - }, - { - prop:'eat', - type:'SignedInteger16', - def:false - }, - { - prop:'refsection', - type:'PString:12', - def:false - }, - { - prop:'useaction', - type:'PString:30', - def:false - }, - { - prop:'description', - type:'PString:30', - def:false - }, - { - prop:'questitem', - type:'Boolean', - def:false - }, - { - prop:'extra', - type:'String:37', - def:false - }, -]; - -var Update_Def = [ - { - prop:'x', - type:'SignedInteger8', - def:0 - }, - { - prop:'y', - type:'SignedInteger8', - def:0 - }, - { - prop:'map', - type:'SignedInteger16', - def:155 - }, - { - prop:'onnow', - type:'Integer8', - def:0 - }, - { - prop:'busy', - type:'Integer8', - def:0 - }, - { - prop:'battle', - type:'Integer8', - def:0 - }, -]; - -var Game_Def = [ - { - prop:'pad0', - type:'String:8', - def:'' - }, - // Offset 8 is days to deletion - { - prop:'deldays', - type:'Integer', - def:15 - }, - { - prop:'pad1', - type:'String:211', - def:'' - }, - // Offset 223 is 32-bit delay - { - prop:'delay', - type:'Integer', - def:100 - }, - // Offset 223 and 227 seem to be the version maybe? - { - prop:'pad2', - type:'String:4', - def:'' - }, - // Offset 231 is buffer strokes - { - prop:'buffer', - type:'Integer8', - def:1 - }, - { - prop:'pad3', - type:'String:1990', - def:'' - } -]; - -var UCASE = false; -var matchcase = true; -function getfname(str) -{ - str = str.replace(/\\/g,'/'); - if (matchcase) { - var ec = file_getcase(js.exec_dir + str); - - if (ec !== undefined) { - return ec; - } - } - if (UCASE) { - return js.exec_dir + str.toUpperCase(); - } - if (str.indexOf(maildir) === 0) { - str = str.toLowerCase().replace(/([\\\/])([^\/\\]+)$/, function(m, p1, p2) { return p1 + p2.toUpperCase(); }); - return js.exec_dir + str; - } - return js.exec_dir + str.toLowerCase(); -} - function savetime() { var n = new Date(); @@ -534,797 +33,6 @@ function savetime() return n.getHours()*60 + n.getMinutes(); } -function clamp_integer(v, s) -{ - var i = parseInt(v, 10); - if (isNaN(i)) - throw new Error('Invalid integer (' + s + '): ' + v); - - switch(s) { - case 's8': - if (i > 127) - i = 127; - else if (i < -128) - i = -128; - break; - case '8': - if (i >255) - i = 255; - else if (i < 0) - i = 0; - break; - case 's16': - if (i > 32767) - i = 32767; - else if (i < -32768) - i = -32768 - break; - case '16': - if (i > 65535) - i = 65535; - else if (i < 0) - i = 0; - break; - case 's32': - if (i > 2147483647) - i = 2147483647; - else if (i < -2147483648) - i = -2147483648; - break; - case '32': - if (i > 4294967295) - i = 4294967295; - else if (i < 0) - i = 0; - break; - default: - throw new Error('Invalid clamp style '+s); - } - return i; -} - -var state = { - time:0 -}; -var files = {}; -var vars = { - version:{type:'const', val:103}, - 'nil':{type:'const', val:''}, - '`n':{type:'fn', get:function() { return player.name } }, - '`e':{type:'fn', get:function() { return getvar('enemy'); } }, - '`g':{type:'int', val:3}, // TODO: >= 3 is ANSI or something... - '`x':{type:'const', val:' '}, - '`d':{type:'const', val:'\b'}, - '`\\':{type:'const', val:'\r\n'}, - '`*':{type:'const', val:dk.connection.node}, - x:{type:'fn', get:function() { return player.x }, set:function(x) { player.x = clamp_integer(x, 's8'); } }, - y:{type:'fn', get:function() { return player.y }, set:function(y) { player.y = clamp_integer(y, 's8'); } }, - map:{type:'fn', get:function() { return player.map }, set:function(map) { player.map = clamp_integer(map, 's16') } }, - dead:{type:'fn', get:function() { return player.dead }, set:function(dead) { player.dead = clamp_integer(dead, 's8') } }, - sexmale:{type:'fn', get:function() { return player.sexmale }, set:function(sexmale) { player.sexmale = clamp_integer(sexmale, 's16') } }, - narm:{type:'fn', get:function() { return player.armournumber }, set:function(narm) { player.armournumber = clamp_integer(narm, 's8') } }, - nwep:{type:'fn', get:function() { return player.weaponnumber }, set:function(nwep) { player.weaponnumber = clamp_integer(nwep, 's8') } }, - money:{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, - gold:{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, - bank:{type:'fn', get:function() { return player.bank }, set:function(bank) { player.bank = clamp_integer(bank, 's32') } }, - enemy:{type:'str', val:''}, - local:{type:'fn', get:function() { return (dk.system.mode === 'local' ? 5 : 0) } }, - blockpassable:{type:'fn', get:function() { return (map.mapinfo[getpoffset()].terrain === 1 ? 1 : 0); } }, - '&realname':{type:'const', val:dk.user.full_name}, - '&date':{type:'fn', get:function() { var d = new Date(); return format('%02d/%02d/%02d', d.getMonth()+1, d.getDate(), d.getYear()%100); }, set:function(x) { throw new Error('Attempt to set date at '+fname+':'+line); } }, - // DOCUMENTED in LORD 2 but non-functional. - //'&nicedate':{type:'fn', get:function() { var d = new Date(); return format('%d:%02d on %02d/%02d/%02d', d.getHours() % 12, d.getMinutes(), d.getMonth()+1, d.getDate(), d.getYear()%100); }, set:function(x) { throw new Error('Attempt to set nicedate at '+fname+':'+line); } }, - // Implemented in LORD 2 (but not documented) - '&quickdate':{type:'fn', get:function() { var d = new Date(); return format('%d:%02d on %02d/%02d/%02d', d.getHours() % 12, d.getMinutes(), d.getMonth()+1, d.getDate(), d.getYear()%100); }, set:function(x) { throw new Error('Attempt to set nicedate at '+fname+':'+line); } }, - 's&armour':{type:'fn', get:function() { if (player.armournumber === 0) return ''; return items[player.armournumber - 1].name; } }, - 's&arm_num':{type:'fn', get:function() { if (player.armournumber === 0) return 0; return items[player.armournumber - 1].defence; } }, - 's&weapon':{type:'fn', get:function() { if (player.weaponnumber === 0) return ''; return items[player.weaponnumber - 1].name; } }, - 's&wep_num':{type:'fn', get:function() { if (player.weaponnumber === 0) return 0; return items[player.weaponnumber - 1].strength; } }, - 's&son':{type:'fn', get:function() { return player.sexmale === 1 ? 'son' : 'daughter' }}, - 's&boy':{type:'fn', get:function() { return player.sexmale === 1 ? 'boy' : 'girl' }}, - 's&man':{type:'fn', get:function() { return player.sexmale === 1 ? 'man' : 'lady' }}, - 's&sir':{type:'fn', get:function() { return player.sexmale === 1 ? 'sir' : 'ma\'am' }}, - 's&him':{type:'fn', get:function() { return player.sexmale === 1 ? 'him' : 'her' }}, - 's&his':{type:'fn', get:function() { return player.sexmale === 1 ? 'his' : 'her' }}, - 's&he':{type:'fn', get:function() { return player.sexmale === 1 ? 'he' : 'she' }}, - '&money':{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, - '&gold':{type:'fn', get:function() { return player.money }, set:function(money) { player.money = clamp_integer(money, 's32') } }, - '&bank':{type:'fn', get:function() { return player.bank }, set:function(bank) { player.bank = clamp_integer(bank, 's32') } }, - '&lastx':{type:'fn', get:function() { return player.lastx }, set:function(bank) { player.lastx = clamp_integer(bank, 's8') } }, - '&lasty':{type:'fn', get:function() { return player.lasty }, set:function(bank) { player.lasty = clamp_integer(bank, 's8') } }, - '&map':{type:'fn', get:function() { return player.map } }, - '&lmap':{type:'fn', get:function() { return player.lastmap } }, - '&time':{type:'fn', get:function() { return state.time }, set:function(x) { throw new Error('attempt to set &time'); } }, - '&timeleft':{type:'fn', get:function() { return parseInt((dk.user.seconds_remaining + dk.user.seconds_remaining_from - time()) / 60, 10) } }, - '&sex':{type:'fn', get:function() { return player.sexmale }, set:function(sexmale) { player.sexmale = clamp_integer(sexmale, 's16') } }, - '&playernum':{type:'fn', get:function() { return player.Record + 1 } }, - '&totalaccounts':{type:'fn', get:function() { return pfile.length } }, - responce:{type:'int', val:0}, - response:{type:'fn', get:function() { return vars.responce.val; }, set:function(val) { vars.responce.val = clamp_integer(val, 's32') } }, -}; -var i; -for (i = 0; i < 40; i++) { - vars[format('`v%02d', i+1)] = {type:'fn', get:eval('function() { return world.v['+i+'] }'), set:eval('function(val) { world.v['+i+'] = clamp_integer(val, "s32"); }')}; -} -for (i = 0; i < 10; i++) { - vars[format('`s%02d', i+1)] = {type:'fn', get:eval('function() { return world.s['+i+'] }'), set:eval('function(val) { world.s['+i+'] = val.substr(0, 80); }')}; -} -for (i = 0; i < 99; i++) { - vars[format('`p%02d', i+1)] = {type:'fn', get:eval('function() { return player.p['+i+'] }'), set:eval('function(val) { player.p['+i+'] = clamp_integer(val, "s32"); }')}; - vars[format('`t%02d', i+1)] = {type:'fn', get:eval('function() { return player.t['+i+'] }'), set:eval('function(val) { player.t['+i+'] = clamp_integer(val, "8"); }')}; - vars[format('`i%02d', i+1)] = {type:'fn', get:eval('function() { return player.i['+i+'] }'), set:eval('function(val) { player.i['+i+'] = clamp_integer(val, "s16"); }')}; - vars[format('`+%02d', i+1)] = {type:'fn', get:eval('function() { return items['+i+'].name }'), set:eval('function(val) { throw new Error("Attempt to set item '+i+' name"); }')}; -} - -function getkeyw() -{ - var timeout = time() + 60 * 5; - var tl; - var now; - - do { - now = time(); - // TODO: dk.console.getstr() doesn't support this stuff... (yet) - tl = (dk.user.seconds_remaining + dk.user.seconds_remaining_from - 30) - now; - if (tl < 1) { - // TODO message etc - exit(0); - } - if (now >= timeout) { - // TODO message etc - exit(0); - } - } while(!dk.console.waitkey(1000)); - return dk.console.getkey(); -} - -var curlinenum = 1; -var curcolnum = 1; -var morechk = true; -var morestr = '`2<`0MORE`2>'; -// Reads a key -function getkey() -{ - var ch; - var a; - - curlinenum = 1; - ch = '\x00'; - do { - ch = getkeyw(); - if (ch === null || ch.length < 1) { - ch = '\x00'; - } - } while (ch === '\x00'); - - return ch; -} - -function remove_colour(str) -{ - if (typeof str !== 'string') - return str; - str = str.replace(/`[0-9\!-^]/g, ''); - str = str.replace(/`r[0-7]/g, ''); - return str; -} - -function setvar(name, val) { - var t; - - name = name.toLowerCase(); - if (vars[name] === undefined) - throw new Error('Attempt to set invalid variable '+name); - switch(vars[name].type) { - case 'int': - t = parseInt(val); - if (isNaN(t)) - throw new Error('Invalid value '+val+' assigned to '+name); - if (t > 2147483647) - t = 2147483648; - if (t < -2147483648) - t = -2147483648; - vars[name].val = t; - break; - case 'str': - vars[name].val = val.toString(); - break; - case 'const': - throw new Error('Attempt to set const value '+name); - case 'bool': - if (val) - vars[name].val = true; - else - vars[name].val = false; - break; - case 'fn': - vars[name].set(val); - break; - default: - throw new Error('Unhandled var type '+vars[name].type); - } -} - -function getvar(name, replacing) { - var uc = false; - var lc = false; - var ret; - - if (vars[name.toLowerCase()] === undefined) { - if (replacing === true) - return name; - return replace_vars(name); - } - if (name.substr(0, 2) === 'S&') - uc = true; - if (name.substr(0, 2) === 's&') - lc = true; - name = name.toLowerCase(); - switch(vars[name].type) { - case 'int': - case 'str': - case 'const': - ret = vars[name].val; - break; - case 'bool': - if (vars[name].val) - ret = 1; - ret = 0; - break; - case 'fn': - ret = vars[name].get(); - break; - default: - throw new Error('Unhandled var type '+vars[name].type); - } - if (uc || lc) - ret = ret.toString(); - if (uc) - ret = ret.substr(0, 1).toUpperCase() + ret.substr(1); - if (lc) - ret = ret.substr(0, 1).toLowerCase() + ret.substr(1); - return ret; -} - -function getsvar(name, vname) -{ - var v = getvar(name); - var fv = getvar(vname); - - if (typeof fv === 'string' && typeof v !== 'string') - return replace_vars(name); - return v; -} - -function expand_ticks(str) -{ - if (typeof str !== 'string') - return str; - str = str.replace(/`w/ig, ''); - str = str.replace(/`l/ig, ''); - str = str.replace(/`c/ig, ''); - return str; -} - -function replace_vars(str) -{ - if (typeof str !== 'string') - return str; - str = str.replace(/([Ss]?&[A-Za-z]+)/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[Vv][0-4][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[Ss][0-1][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[Pp][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[Tt][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[Ii][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[Ii][0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`\+[0-9][0-9])/g, function(m, r1) { return getvar(r1, true); }); - str = str.replace(/(`[nexdNEXD\\\*])/g, function(m, r1) { return getvar(r1, true); }); - return str; -} - -function clean_str(str) -{ - var ret = ''; - var i; - - for (i = 0; i < str.length; i += 1) { - if (str[i] === '$') { - // Just skip it. - } - else if (str[i] !== '`') { - ret += str[i]; - } - else { - switch (str[i+1]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '!': - case '@': - case '#': - case '$': - case '%': - ret += str[i]; - break; - default: - i += 1; - } - } - } - - // TODO: This is where badwords replacements should happen... - - return ret; -} - -function superclean(str) -{ - return remove_colour(expand_ticks(replace_vars(str))); -} - -function lord_to_ansi(str) -{ - var ret = '\x1b[0m'; - var i; - var bg = ''; - var bright = false; - - for (i=0; i<str.length; i += 1) { - if (str[i] === '`') { - i += 1; - switch(str[i]) { - case 'c': - ret += '\x1b[2J\x1b[H\r\n\r\n'; - break; - case '1': - if (bright) - ret += '\x1b[0;34'+bg+'m'; - else - ret += '\x1b[34m'; - bright = false; - break; - case '^': - if (bright) - ret += '\x1b[0;30'+bg+'m'; - else - ret += '\x1b[30m'; - bright = false; - break; - case '*': - // TODO: This may not do 41... - if (bright) { - ret += '\x1b[0;30;41m'; - } - else - ret += '\x1b[30;41m'; - bg = ';41'; - bright = false; - break; - case '2': - if (bright) - ret += '\x1b[0;32'+bg+'m'; - else - ret += '\x1b[32m'; - bright = false; - break; - case '3': - if (bright) - ret += '\x1b[0;36'+bg+'m'; - else - ret += '\x1b[36m'; - bright = false; - break; - case '4': - if (bright) - ret += '\x1b[0;31'+bg+'m'; - else - ret += '\x1b[31m'; - bright = false; - break; - case '5': - if (bright) - ret += '\x1b[0;35'+bg+'m'; - else - ret += '\x1b[35m'; - bright = false; - break; - case '6': - if (bright) - ret += '\x1b[0;33;'+bg+'m'; - else - ret += '\x1b[33m'; - bright = false; - break; - case '7': - if (bright) - ret += '\x1b[0;37'+bg+'m'; - else - ret += '\x1b[37m'; - bright = false; - break; - case '8': - if (bright) - ret += '\x1b[30m'; - else - ret += '\x1b[1;30m'; - bright = true; - break; - case '9': - if (bright) - ret += '\x1b[34m'; - else - ret += '\x1b[1;34m'; - bright = true; - break; - case '0': - if (bright) - ret += '\x1b[32m'; - else - ret += '\x1b[1;32m'; - bright = true; - break; - case '!': - if (bright) - ret += '\x1b[36m'; - else - ret += '\x1b[1;36m'; - bright = true; - break; - case '@': - if (bright) - ret += '\x1b[31m'; - else - ret += '\x1b[1;31m'; - bright = true; - break; - case '#': - if (bright) - ret += '\x1b[35m'; - else - ret += '\x1b[1;35m'; - bright = true; - break; - case '$': - if (bright) - ret += '\x1b[33m'; - else - ret += '\x1b[1;33m'; - bright = true; - break; - case '%': - if (bright) - ret += '\x1b[37m'; - else - ret += '\x1b[1;37m'; - bright = true; - break; - case 'r': - i += 1; - switch(str[i]) { - case '0': - ret += '\x1b[40m'; - bg = ''; - break; - case '1': - ret += '\x1b[44m'; - bg = ';44'; - break; - case '2': - ret += '\x1b[42m'; - bg = ';42' - break; - case '3': - ret += '\x1b[43m'; - bg = ';43'; - break; - case '4': - ret += '\x1b[41m'; - bg = ';41'; - break; - case '5': - ret += '\x1b[45m'; - bg = ';45'; - break; - case '6': - ret += '\x1b[47m'; - bg = ';47'; - break; - case '7': - ret += '\x1b[46m'; - bg = ';46'; - break; - } - break; - } - } - else { - ret += str[i]; - } - } - return ret; -} - -function displen(str) -{ - return superclean(str).length; -} - -// FRONTPAD is broken on colour codes. -// It doesn't ignore colour codes. -function broken_displen(str) -{ - var i; - - str = expand_ticks(replace_vars(str)); - return str.length; -} - -function sw(str) { - if (str === '') { - return; - } - if (str === '\r\n') { - curcolnum = 1; - } - dk.console.print(str); - if (str !== '\r\n') { - curcolnum += str.length; - } -} - -function sln(str) -{ - // *ALL* CRLFs should be sent from here! - if (str !== '') { - sw(str); - } - sw('\r\n'); - curlinenum += 1; - if (morechk) { - if (curlinenum > 24) { - more(); - curlinenum = 1; - } - } - else { - curlinenum = 1; - } -} - -function sclrscr() -{ - var oa = dk.console.attr.value; - - dk.console.clear(); - dk.console.attr.value = oa; - curlinenum = 1; -} - -function clearrows(start, end) -{ - var row; - - if (end === undefined) - end = start; - - dk.console.attr.value = 2; - for (row = start; row <= end; row++) { - dk.console.gotoxy(0, row); - dk.console.cleareol(); - } -} - -function foreground(col) -{ - if (col > 15) { - col = 0x80 | (col & 0x0f); - } - dk.console.attr.value = (dk.console.attr.value & 0x70) | col; -} - -function background(col) -{ - if (col > 7 || col < 0) { - return; - } - dk.console.attr.value = (dk.console.attr.value & 0x8f) | (col << 4); -} - -function more() -{ - var oa = dk.console.attr.value; - - curlinenum = 1; - lw('`r0`2 '+morestr); - getkey(); - dk.console.print('\r'); - dk.console.cleareol(); - dk.console.attr.value = oa; -} - -function handle_lordcodes(str) -{ - var i; - var to; - var oop; - var snip = ''; - var lwch; - - for (i=0; i<str.length; i += 1) { - if (str[i] === '`') { - sw(snip); - snip = ''; - i += 1; - if (i >= str.length) { - break; - } - switch(str[i]) { - case 'k': - case 'K': - more(); - break; - case 'w': - case 'W': - mswait(100); - break; - case 'l': - case 'L': - mswait(500); - break; - case '1': // BLUE - foreground(1); - break; - case '2': // GREEN - foreground(2); - break; - case '3': // CYAN - foreground(3); - break; - case '4': // RED - foreground(4); - break; - case '5': // MAGENTA - foreground(5); - break; - case '6': // YELLOW - foreground(6); - break; - case '7': // WHITE/GRAY - foreground(7); - break; - case '8': - foreground(8); - break; - case '9': - foreground(9); - break; - case '0': - foreground(10); - break; - case '!': - foreground(11); - break; - case '@': - foreground(12); - break; - case '#': - foreground(13); - break; - case '$': - foreground(14); - break; - case '%': - foreground(15); - break; - case '^': - case '*': - foreground(0); - break; - case 'b': - case 'B': - foreground(20); // Blinking red - break; - case 'c': - case 'C': - sclrscr(); - sln(''); - sln(''); - break; - case 'y': - case 'Y': - foreground(30); // Blinking yellow - break; - case 'r': - case 'R': - i += 1; - if (i >= str.length) { - break; - } - switch (str[i]) { - case '0': - background(0); - break; - case '1': - background(1); - break; - case '2': - background(2); - break; - case '3': - background(3); - break; - case '4': - background(4); - break; - case '5': - background(5); - break; - case '6': - background(6); - break; - case '7': - background(7); - break; - } - break; - } - } - else { - snip += str[i]; - } - } - sw(snip); -} - -function lw(str) { - str = replace_vars(str); - handle_lordcodes(str); -} - -function lln(str) -{ - lw(str); - sln(''); -} - -function repeat_chars(ch, len) -{ - var r = ''; - var i; - - for (i = 0; i < len; i++) - r += ch; - return r; -} - -function spaces(len) -{ - return repeat_chars(' ', len); -} - -function space_pad(str, len) -{ - var dl = displen(str); - var alen = Math.abs(len); - - while (dl < alen) { - if (len < 0) - str = ' ' + str; - else - str += ' '; - dl++; - } - - return str; -} - var bar_timeout = 0; var current_saybar = spaces(76); function redraw_bar(updstatus) @@ -1389,20 +97,6 @@ function status_bar() update_bar(b, false); } -function pretty_int(int, rpad) -{ - var ret = parseInt(int, 10).toString(); - var i; - if (rpad === undefined) - rpad = 0; - - for (i = ret.length - 3; i > 0; i-= 3) { - ret = ret.substr(0, i)+','+ret.substr(i); - } - ret = space_pad(ret, rpad); - return ret; -} - function tfile_append(str) { if (!tfile.open('ab')) throw new Error('Unable to open '+tfile.name); @@ -1437,68 +131,6 @@ function timeout_bar() } } -function ranked_players(prop) -{ - var i; - var ret = []; - var pl; - - for (i = 0; i < pfile.length; i++) { - pl = pfile.get(i); - if (pl.deleted === 1) - continue; - ret.push(pfile.get(i)); - } - - function sortfunc(a, b) { - function getprop(pl) { - var ret; - var op = player; - - player = pl; - ret = getvar(prop); - player = op; - } - - var ap, bp; - - if (prop !== undefined) { - ap = getprop(a); - bp = getprop(b); - if (ap !== bp) - return bp - ap; - } - if (a.p[0] !== b.p[0]) - return b.p[0] - a.p[0]; - if (a.p[8] !== b.p[8]) - return b.p[8] - a.p[8]; - if (a.p[17] !== b.p[17]) - return b.p[17] - a.p[17]; - if ((a.money + a.bank) !== (b.money + b.bank)) - return (b.money + b.bank) - (a.money + a.bank); - if (a.p[18] !== b.p[18]) - return b.p[18] - a.p[18]; - if (a.p[2] !== b.p[2]) - return b.p[2] - a.p[2]; - if (a.p[33] !== b.p[33]) - return b.p[33] - a.p[33]; - if (a.p[35] !== b.p[35]) - return b.p[35] - a.p[35]; - } - - return ret.sort(sortfunc); -} - -function get_inventory() -{ - var inv = []; - for (i = 0; i < 99; i++) { - if (player.i[i] > 0) - inv.push(i+1); - } - return inv; -} - function chooseplayer() { var i; @@ -2005,6 +637,7 @@ function run_ref(sec, fname) } clearrows(y, 23); draw_map(); + redraw_bar(true); }, 'checkmail':function(args) { mail_check(false); @@ -2327,6 +960,7 @@ function run_ref(sec, fname) }, 'drawmap':function(args) { draw_map(); + redraw_bar(true); }, 'drawpart':function(args) { var x = getvar(args[0]); @@ -2587,22 +1221,7 @@ function run_ref(sec, fname) player.put(); }, 'overheadmap':function(args) { - var off; - var x, y; - - sclrscr(); - dk.console.gotoxy(0, 0); - for (y = 0; y < 20; y++) { - dk.console.gotoxy(0, y); - for (x = 0; x < 80; x++) { - off = y * 80 + x; - if (world.hideonmap[off] || world.mapdatindex[off] < 1) - background(1); - else - background(2); - lw(' '); - } - } + overheadmap(false); }, 'pauseoff':function(args) { morechk = false; @@ -2775,6 +1394,7 @@ rescan: } } draw_map(); + redraw_bar(true); } clearrows(y, 23); }, @@ -3070,45 +1690,6 @@ function load_player() player.lasty = player.y; } -function foreground(col) -{ - if (col > 15) { - col = 0x80 | (col & 0x0f); - } - dk.console.attr.value = (dk.console.attr.value & 0x70) | col; -} - -function background(col) -{ - if (col > 7 || col < 0) { - return; - } - dk.console.attr.value = (dk.console.attr.value & 0x8f) | (col << 4); -} - -function getoffset(x, y) { - return (x * 20 + y); -} - -function getpoffset() { - return (player.x - 1)*20+(player.y - 1); -} - -function erase(x, y) { - var off = getoffset(x,y); - var mi; - var attr = dk.console.attr.value; - - if (map !== undefined) { - mi = map.mapinfo[off]; - foreground(mi.forecolour); - background(mi.backcolour); - dk.console.gotoxy(x, y); - dk.console.print(mi.ch === '' ? ' ' : mi.ch); - dk.console.attr.value = attr; - } -} - function erase_player() { if (last_draw !== undefined) { @@ -3248,6 +1829,7 @@ function mail_check(messenger) more(); if (messenger) { draw_map(); + redraw_bar(true); update(); } } @@ -3527,43 +2109,6 @@ function update(skip) { dk.console.attr.value = orig_attr; } -function draw_map() { - var x; - var y; - var off; - var mi; - var s; - - // We can't auto-load the players map here because of ORACLE2.REF in CNW - if (map === null || map === undefined) - map = load_map(player.map); - - dk.console.attr.value = 7; - // No need to clear screen since we're overwriting the whole thing. - // TODO: If dk.console had a function to clear to end of screen, that would help. - last_draw = undefined; - for (y = 0; y < 20; y++) { - for (x = 0; x < 80; x++) { - off = getoffset(x,y); - mi = map.mapinfo[off]; - foreground(mi.forecolour); - background(mi.backcolour); - dk.console.gotoxy(x, y); - if (x == 79) - dk.console.cleareol(); - dk.console.print(mi.ch === '' ? ' ' : mi.ch); - } - } - clearrows(21, dk.console.rows - 1); - redraw_bar(true); - other_players = {}; -} - -function load_map(mapnum) -{ - return mfile.get(world.mapdatindex[mapnum - 1] - 1); -} - function get_timestr() { var desc; @@ -3643,6 +2188,7 @@ function move_player(xoff, yoff) { } else { draw_map(); + redraw_bar(true); update(); } } @@ -3667,6 +2213,7 @@ function move_player(xoff, yoff) { if (newmap) { map = load_map(player.map); draw_map(); + redraw_bar(true); } else { erase_player(); @@ -3698,59 +2245,6 @@ function move_player(xoff, yoff) { } } -function box_top(width, title) -{ - var str; - - str = '`r1`0'+ascii(218) + repeat_chars(ascii(196), parseInt(((width - 2) - displen(title)) / 2, 10)) + title + '`r1`0'; - str += repeat_chars(ascii(196), (width - 1) - displen(str)); - str += ascii(191); - return str; -} - -function box_bottom(width) -{ - return '`r1`0'+ascii(192)+repeat_chars(ascii(196), (width - 2))+ascii(217); -} - -function box_middle(width, text, highlight) -{ - var str = '`r1`0'+ascii(179)+' '; - if (highlight) - str += '`r5'; - str += text; - str += '`r1`0'; - str += spaces((width - 1) - displen(str)); - str += ascii(179); - return str; -} - -function draw_box(y, title, lines, width) -{ - var x; - - if (width === undefined) { - width = displen(title) + 6; - lines.forEach(function(l) { - var len = displen(l) + 6; - if (len > width) - width = len; - }); - } - - x = Math.floor((80-width) / 2); - - dk.console.gotoxy(x, y); - lw(box_top(width, title)); - lines.forEach(function(l, i) { - dk.console.gotoxy(x, y + i + 1); - lw(box_middle(width, l)); - }); - dk.console.gotoxy(x, y + lines.length + 1); - lw(box_bottom(width)); - return {width:width, y:y, x:x}; -} - // Assume width of 36 // Assume position centered in inventory window thing function popup_menu(title, opts) @@ -4851,6 +3345,7 @@ function hail() f.close(); } draw_map(); + redraw_bar(true); update(); dk.console.gotoxy(0, 21); } @@ -5084,6 +3579,7 @@ function hail() sln(''); mail_to(op.Record); draw_map(); + redraw_bar(true); update(); break; } @@ -5162,6 +3658,7 @@ function hail() f.close(); chat(op); draw_map(); + redraw_bar(true); done = true; break; } @@ -5186,6 +3683,7 @@ function do_map() if (map === undefined || map.Record !== world.mapdatindex[player.map - 1] - 1) map = load_map(player.map); draw_map(); + redraw_bar(true); update(); ch = '' @@ -5243,11 +3741,13 @@ function do_map() getkey(); morechk = oldmore; draw_map(); + redraw_bar(true); update(); break; case 'D': run_ref('readlog', 'logstuff.ref'); draw_map(); + redraw_bar(true); update(); break; case 'F': @@ -5328,11 +3828,13 @@ function do_map() break; case 'R': draw_map(); + redraw_bar(true); update(); break; case 'S': show_player_names(); draw_map(); + redraw_bar(true); update(); break; case 'T': @@ -5351,6 +3853,7 @@ function do_map() mail_to(ch); } draw_map(); + redraw_bar(true); update(); break; case 'Y': @@ -5382,26 +3885,6 @@ function dump_player() }); } -function load_items() -{ - var i; - - for (i = 0; i < ifile.length; i++) - items.push(ifile.get(i)); -} - -function load_players() -{ - var i; - var p; - - players = []; - for (i = 0; i < pfile.length; i++) { - p = pfile.get(i); - players.push({x:p.x, y:p.y, map:p.map, onnow:p.onnow, busy:p.busy, battle:p.battle, deleted:p.deleted}); - } -} - function load_time() { var newday = false; @@ -5455,16 +3938,6 @@ function load_time() } } -function load_game() -{ - if (gfile.length > 0) - game = gfile.get(0); - else { - game = gfile.new(); - game.put(); - } -} - function pick_deleted() { var i; @@ -5507,58 +3980,13 @@ function setup_time_warnings() time_warnings.push(0); } -function build_index() -{ - var i; - var p; - var u; - - for (i = 0; i < pfile.length; i++) { - u = ufile.get(i); - if (u === null) { - u = ufile.new(); - p = pfile.Get(i); - u.x = p.x; - u.y = p.y; - u.map = p.map; - u.onnow = p.onnow; - u.busy = p.busy; - u.battle = p.battle; - u.deleted = p.deleted; - u.put(); - } - } -} - -var pfile = new RecordFile(getfname('trader.dat'), Player_Def); -var mfile = new RecordFile(getfname('map.dat'), Map_Def); -var wfile = new RecordFile(getfname('world.dat'), World_Def); -var ifile = new RecordFile(getfname('items.dat'), Item_Def); -var ufile = new RecordFile(getfname('update.tmp'), Update_Def); -if (ufile.length < pfile.length) { - build_index(); -} -var gfile = new RecordFile(getfname('game.dat'), Game_Def); -var maildir = getfname('mail'); - // TODO: Actually send this font to SyncTERM too. if (file_exists(getfname('fonts/lord2.fnt'))) { if (dk.system.mode === 'local') conio.loadfont(getfname('fonts/lord2.fnt')); } - -if (!file_isdir(maildir)) { - mkdir(maildir); - if (!file_isdir(maildir)) - throw new Error('Unable to create mail directory'); -} -maildir = backslash(maildir).replace(js.exec_dir, ''); -world = wfile.get(0); load_player(); -load_players(); -load_items(); load_time(); -load_game(); run_ref('rules', 'rules.ref'); hail_cleanup();