diff --git a/xtrn/lord2/lord2.js b/xtrn/lord2/lord2.js index 480546e78773c99866eee30835379d3e4172fa20..5b3888f9927a8841f300eba3354089bc99b68ab1 100644 --- a/xtrn/lord2/lord2.js +++ b/xtrn/lord2/lord2.js @@ -4,6 +4,8 @@ // TODO: Multiplayer interactions // TODO: Save player after changes in case process crashes // TODO: run NOTIME in HELP.REF on idle timeout +// TODO: When I stole the Gryphon Moon, it didn't go into my inventory! +// TODO: Listing does not have K (Koshi Quest) or D (Dragontooth Quest) js.yield_interval = 0; js.load_path_list.unshift(js.exec_dir+"dorkit/"); @@ -864,8 +866,10 @@ function superclean(str) function lord_to_ansi(str) { - var ret = ''; + var ret = '\x1b[0m'; var i; + var bg = ''; + var bright = false; for (i=0; i<str.length; i += 1) { if (str[i] === '`') { @@ -875,80 +879,162 @@ function lord_to_ansi(str) ret += '\x1b[2J\x1b[H\r\n\r\n'; break; case '1': - ret += '\x1b[0;34m'; + if (bright) + ret += '\x1b[0;34'+bg+'m'; + else + ret += '\x1b[34m'; + bright = false; + break; + case '^': + // TODO: This may not do 41... + if (bright) + ret += '\x1b[0;30'+bg+'m'; + else + ret += '\x1b[30m'; + bright = false; break; case '*': // TODO: This may not do 41... - ret += '\x1b[0;30;41m'; + if (bright) { + ret += '\x1b[0;30;41m'; + } + else + ret += '\x1b[30;41m'; + bg = ';41'; + bright = false; break; case '2': - ret += '\x1b[0;32m'; + if (bright) + ret += '\x1b[0;32'+bg+'m'; + else + ret += '\x1b[32m'; + bright = false; break; case '3': - ret += '\x1b[0;36m'; + if (bright) + ret += '\x1b[0;36'+bg+'m'; + else + ret += '\x1b[36m'; + bright = false; break; case '4': - ret += '\x1b[0;31m'; + if (bright) + ret += '\x1b[0;31'+bg+'m'; + else + ret += '\x1b[31m'; + bright = false; break; case '5': - ret += '\x1b[0;35m'; + if (bright) + ret += '\x1b[0;35'+bg+'m'; + else + ret += '\x1b[35m'; + bright = false; break; case '6': - ret += '\x1b[0;33m'; + if (bright) + ret += '\x1b[0;33;'+bg+'m'; + else + ret += '\x1b[33m'; + bright = false; break; case '7': - ret += '\x1b[0;37m'; + if (bright) + ret += '\x1b[0;37'+bg+'m'; + else + ret += '\x1b[37m'; + bright = false; break; case '8': - ret += '\x1b[1;30m'; + if (bright) + ret += '\x1b[30m'; + else + ret += '\x1b[1;30m'; + bright = true; break; case '9': - ret += '\x1b[1;34m'; + if (bright) + ret += '\x1b[34m'; + else + ret += '\x1b[1;34m'; + bright = true; break; case '0': - ret += '\x1b[1;32m'; + if (bright) + ret += '\x1b[32m'; + else + ret += '\x1b[1;32m'; + bright = true; break; case '!': - ret += '\x1b[1;36m'; + if (bright) + ret += '\x1b[36m'; + else + ret += '\x1b[1;36m'; + bright = true; break; case '@': - ret += '\x1b[1;31m'; + if (bright) + ret += '\x1b[31m'; + else + ret += '\x1b[1;31m'; + bright = true; break; case '#': - ret += '\x1b[1;35m'; + if (bright) + ret += '\x1b[35m'; + else + ret += '\x1b[1;35m'; + bright = true; break; case '$': - ret += '\x1b[1;33m'; + if (bright) + ret += '\x1b[33m'; + else + ret += '\x1b[1;33m'; + bright = true; break; case '%': - ret += '\x1b[1;37m'; + if (bright) + ret += '\x1b[37m'; + else + ret += '\x1b[1;37m'; + bright = true; break; case 'r': i += 1; switch(str[i]) { - case 0: + case '0': ret += '\x1b[40m'; + bg = ''; break; - case 1: + case '1': ret += '\x1b[44m'; + bg = ';44'; break; - case 2: + case '2': ret += '\x1b[42m'; + bg = ';42' break; - case 3: + case '3': ret += '\x1b[43m'; + bg = ';43'; break; - case 4: + case '4': ret += '\x1b[41m'; + bg = ';41'; break; - case 5: + case '5': ret += '\x1b[45m'; + bg = ';45'; break; - case 6: + case '6': ret += '\x1b[47m'; + bg = ';47'; break; - case 7: + case '7': ret += '\x1b[46m'; + bg = ';46'; break; } break; @@ -1214,9 +1300,13 @@ function spaces(len) function space_pad(str, len) { var dl = displen(str); + var alen = Math.abs(len); - while (dl < len) { - str += ' '; + while (dl < alen) { + if (len < 0) + str = ' ' + str; + else + str += ' '; dl++; } @@ -1346,14 +1436,17 @@ function status_bar() update_bar(b, false); } -function pretty_int(int) +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; } @@ -1491,6 +1584,7 @@ function run_ref(sec, fname) var cl; var args; var ret; + var refret; fname = fname.toLowerCase(); sec = sec.toLowerCase(); @@ -1664,6 +1758,7 @@ function run_ref(sec, fname) player.name = getvar('`s10'); }, 'moveback':function(args) { + // TODO: After giving the guard north of Stoneport or whatever an apple from the left, you "stick" erase(player.x - 1, player.y - 1); player.x = player.lastx; player.y = player.lasty; @@ -1748,12 +1843,24 @@ function run_ref(sec, fname) 'do':function(args) { var tmp; - if (args.length < 1 || args.length > 0 && args[0].toLowerCase() === 'do') { + if (args.length < 1 || args.length == 1 && args[0].toLowerCase() === 'do') { if (line + 1 >= files[fname].lines.length) throw new Error('do at end of file'); // Trailing do is not fatal... see jump.ref:21 in cnw //if (files[fname].lines[line + 1].search(/^\s*@begin/i) === -1) // throw new Error('trailing do at '+fname+':'+line); + tmp = line; + while (files[fname].lines[++tmp].search(/^\s*;/) != -1) { + if (tmp >= files[fname].lines.length) + break; + } + if (tmp < files[fname].lines.length) { + if (files[fname].lines[tmp].search(/^\s*@begin(?:\s*|;.*)$/i) != -1) + line = tmp; + } + return; + } + if (args.length == 2 && args[1].toLowerCase() === 'begin') { line++; return; } @@ -1778,6 +1885,9 @@ function run_ref(sec, fname) tmp = pfile.get(clamp_integer(getvar(args[3]), '8')); setvar(args[0], tmp.deleted); } + else if (args[2].toLowerCase() === 'random') { + setvar(args[0], random(clamp_integer(getvar(args[3]), 's32')) + clamp_integer(getvar(args[4]), 's32')); + } else setvar(args[0], getsvar(args[2], args[0])); return; @@ -1881,18 +1991,20 @@ function run_ref(sec, fname) case '=': case 'equals': case 'is': - if (args[2].toLowerCase() === 'length') { - tmp = remove_colour(expand_ticks(replace_vars(getvar(args[3])))).length; + tmp2 = 2; + if (args[tmp2].toLowerCase() === 'length') { + tmp = remove_colour(expand_ticks(replace_vars(getvar(args[++tmp2])))).length; } - else if (args[2].toLowerCase() === 'reallength') { - tmp = getvar(args[3]).length; + else if (args[tmp2].toLowerCase() === 'reallength') { + tmp = getvar(args[++tmp2]).length; } else - tmp = getsvar(args[2], args[0]); + tmp = getsvar(args[tmp2], args[0]); + tmp2++; if (getvar(args[0]).toString() === tmp.toString()) - handlers.do(args.slice(4)); - else if (args[4].toLowerCase() === 'begin') - handlers.begin(args.slice(5)); + handlers.do(args.slice(tmp2 + 1)); + else if (args[tmp2].toLowerCase() === 'begin') + handlers.begin(args.slice(tmp2 + 1)); break; case 'exist': case 'exists': @@ -1930,7 +2042,7 @@ function run_ref(sec, fname) } }, 'routine':function(args) { - var s = replace_vars(args[0]); + var s = replace_vars(args[0]).toLowerCase(); if (args.length === 1) { run_ref(s, fname); return; @@ -1939,7 +2051,7 @@ function run_ref(sec, fname) run_ref(s, args[2]); return; } - throw new Error('Unable to parse routine at '+fname+':'+line); + throw new Error('Unable to parse routine "'+s+'" at '+fname+':'+line); }, 'run':function(args) { var f = fname; @@ -2647,7 +2759,7 @@ rescan: if (!f.open('ab')) return; rp.forEach(function(pl, i) { - f.write((pl.sexmale === 1 ? '`0M' : '`#F')+' `2'+space_pad(pl.name, 21)+'`2'+format('%14d', pl.p[0])+'`%'+format('%5d', pl.p[8])+' '+space_pad((pl.dead === 1 ? '`4Dead' : '`%Alive'), 6)+(pl.p[6] >= 0 ? '`0' : '`4') + format('%7d',pl.p[6])+'`% '+pl.p[18]+'\r\n'); + f.write((pl.sexmale === 1 ? ' ' : '`#F')+' `2'+space_pad(pl.name, 21)+'`2'+pretty_int(pl.p[0], -14)+'`%'+pretty_int(pl.p[8], -5)+' '+space_pad((pl.dead === 1 ? '`4Dead' : '`%Alive'), 6)+(pl.p[6] >= 0 ? '`0' : '`4') + pretty_int(pl.p[6], -7)+'`% '+(pl.p[17] > 0 ? pretty_int(pl.p[17]) : '')+((pl.t[16] & (1<<7)) ? ' `r1`%K`r0' : '')+((pl.t[17] & (1<<7)) ? ' `r4`^D`r0' : '') + '\r\n'); }); f.close(); }, @@ -2784,14 +2896,16 @@ rescan: while (1) { line++; if (line >= files[fname].lines.length) - return; + return refret; cl = files[fname].lines[line].replace(/^\s*/,''); if (cl.search(/^@#/) !== -1) - return; + return refret; if (cl.search(/^\s*@closescript/i) !== -1) - return; - if (cl.search(/^\s*@itemexit/i) !== -1) - return 'ITEMEXIT'; + return refret; + if (cl.search(/^\s*@itemexit/i) !== -1) { + refret = 'ITEMEXIT'; + continue; + } if (cl.search(/^;/) !== -1) continue; if (cl.search(/^@/) === -1) { @@ -2804,6 +2918,8 @@ rescan: } // A bare @ is used to terminate things sometimes... args = cl.substr(1).split(/\s+/); + while (args !== undefined && args.length > 1 && args[args.length - 1] === '') + args.pop(); ret = handle(args); } } @@ -3428,33 +3544,22 @@ function draw_box(y, title, lines, width) function popup_menu(title, opts) { var str; - var x = 21; var y = 12 + ((9 - opts.length)/2); var cur = 0; var ch; var sattr = dk.console.attr.value; var otxt = []; + var oinit = []; + var box; + var first = '`r5`0'; - str = box_top(38, title); - dk.console.gotoxy(x, y); - lw(str); - opts.forEach(function(o, i) { - str = box_middle(38, o.txt, i === cur); - dk.console.gotoxy(x, y+1+i); - lw(str); - }); - dk.console.gotoxy(x+3, y+1+cur); - - str = box_bottom(38); - dk.console.gotoxy(x, y+opts.length+1); - lw(str); - - dk.console.gotoxy(x+3, y+1+cur); opts.forEach(function(o) { otxt.push(o.txt); + oinit.push(first + o.txt); + first = ''; }); - - ch = vbar(otxt, {drawall:false, x:x + 3, y:y + 1, highlight:'`r5`0', norm:'`r1`0'}); + box = draw_box(y, title, oinit); + ch = vbar(otxt, {drawall:false, x:box.x + 3, y:box.y + 1, highlight:'`r5`0', norm:'`r1`0'}); return opts[ch.cur].ret; } @@ -3587,7 +3692,11 @@ newpage: } if (ret === undefined || ret !== 'ITEMEXIT') continue rescan; - // Fallthrough + if (ret == 'ITEMEXIT') { + dk.console.attr.value = attr; + return ret; + } + // Fallthrough(?) case 'Q': dk.console.attr.value = attr; return; @@ -3692,6 +3801,10 @@ function offline_battle() var enm = enemy; var supr; + // TODO Something weird happens when you do multiple training fights... + // A small map is shown you can move one square on during the battle. + // (Seen after swamp) + // Seen with swamp dago in SKY WORLD... which was DEAD when I moved at all enemy = undefined; switch(enm.sex) { case 1: @@ -4568,8 +4681,8 @@ function do_map() run_ref('talk', 'help.ref'); break; case 'V': - view_inventory(); - run_ref('closestats', 'gametxt.ref'); + if (view_inventory() !== 'ITEMEXIT') + run_ref('closestats', 'gametxt.ref'); break; case 'W': sclrscr();