Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 15380x 15380x 15380x 15380x 15380x 15380x 15380x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 72x 18x 18x 18x 18x 18x 18x 18x 18x 72x 72x 72x 72x 18x 18x 72x | // game_display.js — NetHack-specific display wrapper around Terminal.
// Adds game state properties (topMessage, toplines, toplin) and
// message window handling. Delegates all terminal operations to
// the wrapped Terminal instance.
//
// Usage:
// const terminal = new Terminal('game-container');
// const display = new GameDisplay(terminal);
// // display.setCell, display.readKey etc. all delegate to terminal
// // display.topMessage, display.putstr_message are NetHack-specific
import { Terminal, CLR_GRAY } from './terminal.js';
const TOPLINE_EMPTY = 0;
const TOPLINE_NEED_MORE = 1;
export class GameDisplay {
constructor(terminalOrContainerId) {
// Accept either a Terminal instance or a container ID (backward compat)
if (terminalOrContainerId instanceof Terminal) {
this.terminal = terminalOrContainerId;
} else {
this.terminal = new Terminal(
terminalOrContainerId != null ? terminalOrContainerId : null,
{ rows: 24, cols: 80 }
);
}
// NetHack-specific message state
this.topMessage = null;
this.toplines = '';
this.messages = [];
this.toplin = TOPLINE_EMPTY;
this.messageWinFlags = 0;
}
// --- Delegate all Terminal properties and methods ---
get rows() { return this.terminal.rows; }
get cols() { return this.terminal.cols; }
get grid() { return this.terminal.grid; }
get cursorCol() { return this.terminal.cursorCol; }
set cursorCol(v) { this.terminal.cursorCol = v; }
get cursorRow() { return this.terminal.cursorRow; }
set cursorRow(v) { this.terminal.cursorRow = v; }
get cursorVisible() { return this.terminal.cursorVisible; }
set cursorVisible(v) { this.terminal.cursorVisible = v; }
get spans() { return this.terminal.spans; }
get container() { return this.terminal.container; }
get flags() { return this.terminal.flags; }
set flags(v) { this.terminal.flags = v; }
// Display methods
setCell(col, row, ch, color, attr) { return this.terminal.setCell(col, row, ch, color, attr); }
putstr(col, row, str, color, attr) { return this.terminal.putstr(col, row, str, color, attr); }
setCursor(col, row) { return this.terminal.setCursor(col, row); }
clearScreen() { return this.terminal.clearScreen(); }
clearRow(row) { return this.terminal.clearRow(row); }
scrollUp() { return this.terminal.scrollUp(); }
moveCursor(x, y) { return this.terminal.moveCursor(x, y); }
putChar(x, y, ch, attr) { return this.terminal.putChar(x, y, ch, attr); }
getChar(x, y) { return this.terminal.getChar(x, y); }
putString(str) { return this.terminal.putString(str); }
putCharAtCursor(ch) { return this.terminal.putCharAtCursor(ch); }
clearToEol() { return this.terminal.clearToEol(); }
cursSet(visibility) { return this.terminal.cursSet(visibility); }
flush() { return this.terminal.flush?.(); }
getPreElement() { return this.terminal.getPreElement(); }
getCanvas() { return this.terminal.getCanvas?.(); }
colorToCss(color) { return this.terminal.colorToCss(color); }
captureForShell() { return this.terminal.captureForShell(); }
// Input methods — delegate to terminal with NetHack-specific defaults
pushKey(code) { return this.terminal.pushKey(code); }
clearInputQueue() { return this.terminal.clearInputQueue(); }
get isWaitingForInput() { return this.terminal.isWaitingForInput; }
get inputQueueLength() { return this.terminal.inputQueueLength; }
get waitEpoch() { return this.terminal.waitEpoch; }
/**
* Read a key with NetHack-specific options bundled.
* Apps set keyMapper, onInterrupt, onEmptyQueue on GameDisplay;
* these are passed through to terminal.readKey on every call.
*/
readKey(extraOptions) {
return this.terminal.readKey({
keyMapper: this.keyMapper,
onInterrupt: this.onInterrupt,
onEmptyQueue: this.onEmptyQueue,
...extraOptions,
});
}
/** NetHack key mapper — converts browser keys to game codes. */
keyMapper = null;
/** Ctrl-C handler. */
onInterrupt = null;
/** Called when input queue is empty (headless replay). */
onEmptyQueue = null;
// --- NetHack-specific methods ---
putstr_message(msg) {
this.clearRow(0);
this.putstr(0, 0, msg, CLR_GRAY);
this.topMessage = msg.trimEnd();
this.toplines = this.topMessage;
this.toplin = this.topMessage ? TOPLINE_NEED_MORE : TOPLINE_EMPTY;
this.messages.push(this.topMessage);
if (this.messages.length > 20) this.messages.shift();
}
renderStatus(_player) {
// TODO: full status line rendering from player stats
}
moveCursorTo(col, row = 0) {
this.setCursor(col, row);
}
}
|