diff --git a/src/Game.ts b/src/Game.ts index 73e578d..1cc197c 100644 --- a/src/Game.ts +++ b/src/Game.ts @@ -61,8 +61,11 @@ export class Game extends Frigid implements Tickable { this.inventory ??= new Inventory(); this.inventory.validate(); this.clock ??= new Time(); - this.clock.thing = this; - this.clock.start(); + this.clock.start(this); + this.pawns = []; + if(this.pawns.length === 0) { + for(let i = 0; i < 3; i ++) this.pawns.push(new Pawn()); + } ready(this.name); } diff --git a/src/ProcessManager.ts b/src/ProcessManager.ts index 6bb92a0..813914c 100644 --- a/src/ProcessManager.ts +++ b/src/ProcessManager.ts @@ -1,3 +1,4 @@ +import chalk from 'chalk'; import EventEmitter from 'events'; import ipc from 'node-ipc'; import { @@ -9,27 +10,31 @@ import { } from './Constants.js'; let connected = false; +const oldConsoleLog = console.log; + +const patchLog = () => console.log = console.log.bind(console, chalk.cyan('[CLIENT]')); +const restoreLog = () => console.log = oldConsoleLog; + +// const log = (...args: any[]) => console.log(chalk.cyan('[CLIENT]'), ...args); class ProcessManagerClass extends EventEmitter { quit() { - if (connected) { - console.log('client sending quit event') - ipc.of[name].emit(IPC_QUIT_EVENT); - process.exit(0); - } else { - process.exit(0); - } + this.emit('shutdown'); + process.exit(0); } restart() { + this.emit('shutdown'); if (connected) { - console.log('client emitting ipc restart') ipc.of[name].emit(IPC_RESTART_EVENT); - process.exit(0); - } else { - console.log('eh?! not connected to tower... closing') - process.exit(0); } + setTimeout(() => { + process.exit(0); + }) + } + + get connected() { + return connected; } } @@ -40,11 +45,23 @@ ipc.config.appspace = IPC_CLIENT_APPSAPCE; ipc.config.silent = true; ipc.connectTo(name, () => { - ipc.of[name].on('connect', () => connected = true); - ipc.of[name].on('disconnect', () => connected = false); + ipc.of[name].on('connect', () => { + connected = true; + patchLog(); + }); + ipc.of[name].on('disconnect', () => { + connected = false + restoreLog(); + }); ipc.of[name].on(IPC_REQUEST_RESTART, () => { + console.log('received restart request'); + // ProcessManager.restart(); ProcessManager.emit('reload'); }) }); -///////////// \ No newline at end of file +process.on('SIGKILL', () => ProcessManager.quit()); +process.on('SIGTERM', () => ProcessManager.quit()); +process.on('SIGINT', () => ProcessManager.quit()); + +/// \ No newline at end of file diff --git a/src/Time.ts b/src/Time.ts index 952c0ed..46bb358 100644 --- a/src/Time.ts +++ b/src/Time.ts @@ -18,8 +18,9 @@ const months: AbbreviatedMonthName[] = [ 'Oct', 'Nov', 'Dec' ] +// TODO split ticker util and calendar util... export default class Time extends Serializable { - rate: number; + targetTPS: number; paused = true; thing: Tickable; @@ -30,6 +31,12 @@ export default class Time extends Serializable { hour: number; minute: number; + ticksInSecond: number; + lastTPSCheckpoint: number; + tps: number; + + _boundTick: Function; + constructor(timestamp: number = 0) { super(); this.minute = timestamp; @@ -67,16 +74,34 @@ export default class Time extends Serializable { } toString() { - return `${this.hour}:${Math.floor(this.minute).toString().padStart(2, '0')} ${months[this.month]} ${this.day + 1}, ${this.normalizedYear}` + return `${ + this.hour + }:${ + Math.floor(this.minute).toString().padStart(2, '0') + } ${ + months[this.month] + } ${ + this.day + 1 + }, ${ + this.normalizedYear + } [${ + this.tps + } / ${ + this.targetTPS + }]`; } ctor() { - this.rate = 60; + this.targetTPS = 2000; this.minute ??= 0; this.hour ??= 0; this.day ??= 0; this.month ??= 0; this.year ??= 0; + this.tps ??= 0; + this.lastTPSCheckpoint = ms4(); + this.ticksInSecond = 0; + this._boundTick = this.doTick.bind(this); } get second() { @@ -112,7 +137,13 @@ export default class Time extends Serializable { this.paused = true; } - start() { + resume() { + this.paused = false; + setTimeout(this.doTick.bind(this), 0); + } + + start(tickable: Tickable) { + this.thing = tickable; this.paused = false; setTimeout(this.doTick.bind(this), 0); } @@ -130,8 +161,6 @@ export default class Time extends Serializable { } } - - normalize() { // while(t) while(this.minute >= 60) { @@ -173,20 +202,46 @@ export default class Time extends Serializable { } async doTick() { + this.advanceTime(1); - const timeout = 1000 / this.rate; - const start = new Date().getTime(); + const timeout = 1000 / this.targetTPS; + // const start = ms4() + const start = ms4(); if(this.thing) { await this.thing.tick(); } - const elapsed = new Date().getTime() - start; - const wait = Math.max(timeout - elapsed, 0); + const end = ms4() + const elapsed = end - start; + const wait = timeout - elapsed; + const normalizedWait = Math.floor(Math.max(wait, 0)); + + // process.stdout.write(`tick took ${elapsed} waiting ${normalizedWait}\n`); + + if(wait < 0) { + const ticksOver = (-wait / timeout) + 1; + console.log(chalk.yellow('Can\'t keep up! Tick took ' + ticksOver.toFixed(2) + ' ticks (' + (timeout - wait).toFixed(4) + 'ms)')); + } + + + this.ticksInSecond ++; + + if(end > this.lastTPSCheckpoint + 1000) { + this.lastTPSCheckpoint = end; + this.tps = this.ticksInSecond; + this.ticksInSecond = 0; + } + if(this.paused) return; - setTimeout(this.doTick.bind(this), wait) + setTimeout(this._boundTick, normalizedWait) + } } - export interface Tickable { tick: () => Promise +} + +function ms4() { + const a = process.hrtime() + return a[0]*10e2 + a[1]/1000000; } \ No newline at end of file diff --git a/src/Util.ts b/src/Util.ts index 93f3ade..429b166 100644 --- a/src/Util.ts +++ b/src/Util.ts @@ -3,6 +3,8 @@ import { parse, resolve } from 'path'; import walkSync from 'walk-sync'; import { fileURLToPath } from 'url'; import { APPLICATION_NAME } from './Constants.js'; +import chalk from 'chalk'; + export function osrsNumber(x: number): string { if(x < 10_000) return '' + x; @@ -11,7 +13,7 @@ export function osrsNumber(x: number): string { } export async function loadExtensions() { - console.log(APPLICATION_NAME + ': Loading extensions'); + console.log('Loading extensions'); const extensionsPath = resolve(parse(fileURLToPath(import.meta.url)).dir, '../content'); const extensions = walkSync(extensionsPath) @@ -28,6 +30,4 @@ export async function loadExtensions() { } console.log('Setup Complete.'); -} - -// export function \ No newline at end of file +} \ No newline at end of file diff --git a/src/hot-index.ts b/src/hot-index.ts index db31e45..f5e1ee9 100644 --- a/src/hot-index.ts +++ b/src/hot-index.ts @@ -6,83 +6,85 @@ import { IPC_REQUEST_RESTART } from './Constants.js'; import { spawn, ChildProcess } from 'child_process'; -import watch from 'watch'; import chokidar from 'chokidar'; import chalk from 'chalk'; +ipc.config.silent = true; -// ipc.config.silent = true; -const exec = 'qode' + (process.platform === "win32" ? '.cmd' : ''); +// should be obtained from process spawn args, but whatever! +const exec = 'qode' + + (process.platform === "win32" ? '.cmd' : ''); const args = [ 'bin/app.bundle.cjs' -] +]; -ipc.serve(IPC_PATH, () => { - ipc.server.on(IPC_QUIT_EVENT, async () => { - await killProcess(); - ipc.server.stop(); - process.exit(0); - }); - ipc.server.on(IPC_RESTART_EVENT, restart) -}); - -console.log('started ipc tower server!') -ipc.server.start(); +const log = console.log.bind(console, chalk.green('[TOWER]')); +// varying state data +let connected = 0; let proc: ChildProcess = null; +let restartTimer: NodeJS.Timeout = null; + +function ensureAlive() { + if(proc) { + return; + } -function startProcess() { proc = spawn(exec, args, { stdio: 'inherit' }); - console.log(`[${proc.pid}] ${chalk.grey(`${exec} ${args.join(' ')}`)}`); - proc.on('exit', () => { - console.log('process died'); + proc.once('exit', () => { proc = null; - }) + }); + log(`[${ + proc.pid + }] ${ + chalk.grey(`${ + exec + } ${ + args.join(' ') + }`) + }`); } -async function killProcess() { - if(proc) { - console.log('killing process...'); - const killedPromise = new Promise((res) => { - proc.on('exit', (code, sig) => { - res(code || sig); - }) - }) - proc.kill(); - console.log('process died with code', await killedPromise); - proc = null; - console.log() +async function ensureDead() { + if(!proc) { + return; } + const killedPromise = + new Promise(res => proc.once('exit', res)); + proc.kill(9); + await killedPromise; + proc = null; } async function restart() { - console.log('received restart event'); - await killProcess(); - console.log('') - startProcess(); + await ensureDead(); + ensureAlive(); } -startProcess(); - -let restartTimer: NodeJS.Timeout = null; - function fileChange() { - // appendFileSync('log.log', evt + ' ' + path + '\n'); - // console.log(cluster.isMaster, evt, path); if(restartTimer) clearTimeout(restartTimer) restartTimer = setTimeout(() => { - console.log('changes detected'); - if(proc) { - ipc.server.broadcast(IPC_REQUEST_RESTART); - } else { - startProcess(); - } + ensureAlive(); + ipc.server.broadcast(IPC_REQUEST_RESTART); restartTimer = null; }, 100); } -chokidar.watch('./out').on('all', fileChange); -// watch.watchTree('./bin', fileChange); +// start the server, connect events +ipc.serve(IPC_PATH, () => { + ipc.server.on(IPC_QUIT_EVENT, ensureDead); + ipc.server.on(IPC_RESTART_EVENT, restart); + ipc.server.on('connect', () => connected ++); + ipc.server.on('disconnect', () => connected --); +}); +ipc.server.start(); +// open the process +ensureAlive(); + +//begin watching for files, ignore changes on boot. +chokidar.watch('./out', { + ignoreInitial: true +}).on('all', fileChange); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index aac14d0..808175c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,25 +16,25 @@ import ansi from 'sisteransi'; import './../content/content.js'; import { loadExtensions } from './Util.js'; import { APPLICATION_NAME } from './Constants.js'; +import chalk from 'chalk'; +import { ProcessManager } from './ProcessManager.js'; // console.clear(); -function gracefulShutdown() { - if (isStarted()) { - stop(); - } - console.log('shutting down gracefully...'); - if (Game.current) { - console.log('saving world...'); - Game.current.sync(); - } - console.log('exitting'); - process.stdout.write(ansi.cursor.show); +ProcessManager.on('shutdown', gracefulShutdown); - process.exit(0); +function gracefulShutdown() { + // if (isStarted()) { + // stop(); + // } + if (Game.current) { + console.log(chalk.cyan('Saving world...')); + Game.current.sync(); + console.log(chalk.cyan('World Saved!')); + } } -process.on('exit', gracefulShutdown); +// process.on('exit', gracefulShutdown); const saveFile = process.argv[2] || 'data/world01.json'; @@ -42,10 +42,11 @@ ensureDirSync(parse(saveFile).dir); // loadExtensions(); -for (let seconds = 0; seconds > 0; seconds --) { - process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + seconds + '\r'); -} -process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + 0 + '\n'); +// TODO replace with splash screen +// for (let seconds = 0; seconds > 0; seconds --) { +// process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + seconds + '\r'); +// } +// process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + 0 + '\n'); // console.clear(); // TODO move render logic into game, so that the ui doesnt exist until the game does... diff --git a/src/multiplayer/mDNS.ts b/src/multiplayer/mDNS.ts index bec9192..8302559 100644 --- a/src/multiplayer/mDNS.ts +++ b/src/multiplayer/mDNS.ts @@ -5,7 +5,7 @@ import * as uuid from 'uuid'; import faker from 'faker'; import chalk from 'chalk'; import { Item } from '../registries/Items.js'; -import WebSocket from 'ws'; +import WebSocket, { EventEmitter } from 'ws'; import { Popup } from '@ui'; import { inspect } from 'util' import { Pawn } from '../Pawn.js'; @@ -18,11 +18,11 @@ const mdns = bonjour(); const ID = uuid.v4(); let devices: Player[] = []; -const network = { +const network = new (class Network extends EventEmitter { get players() { return devices; } -} +})(); export type GiftMessage = { pawns: string[], @@ -61,11 +61,13 @@ export async function ready(name: string) { mdns.find({ type: MDNS_TYPE }, (service) => { + network.emit('change'); const p = new Player(); p.name = service.name; p.host = service.host; p.port = service.port; devices.push(p); }).on("down", (service) => { + network.emit('change'); // TODO remove player from MP }) \ No newline at end of file diff --git a/src/qt/GameView.ts b/src/qt/GameView.ts index 07a8efc..7a15f9a 100644 --- a/src/qt/GameView.ts +++ b/src/qt/GameView.ts @@ -1,18 +1,19 @@ import { Game } from '@game'; +import { ItemState } from '@items'; import { QLabel, QTabWidget, QWidget, QIcon, - FlexLayout, QGridLayout, FocusPolicy, - WidgetEventTypes, AlignmentFlag, - QListView, - QListWidget, - QListWidgetItem + QBoxLayout, + Direction, + QScrollArea, } from '@nodegui/nodegui'; +import network from '../multiplayer/mDNS.js'; +import { Player } from '../multiplayer/Player.js'; import { Pawn } from '../Pawn.js'; import { View } from './View.js'; @@ -33,9 +34,6 @@ export class GameView extends View { this.title.setText(this.game.name); - this.left.setInlineStyle('border: 1px solid white;') - this.right.setInlineStyle('border: 1px solid white;') - this.layout.addWidget(this.title, 0, 0); this.layout.addWidget(this.timeLabel, 0, 1); this.layout.addWidget(this.left, 1, 0); @@ -46,7 +44,8 @@ export class GameView extends View { this.layout.setColumnStretch(1, 2); this.right.addTab(new PawnPageWidget(), new QIcon(), 'Pawns'); - this.right.addTab(new InventoryWidget(), new QIcon(), 'Inventory') + this.right.addTab(new InventoryPageWidget(), new QIcon(), 'Inventory'); + this.right.addTab(new MultiplayerPageWidget(), new QIcon(), 'Multiplayer'); } constructor(game: Game) { @@ -55,52 +54,154 @@ export class GameView extends View { } } -class PawnWidget extends QWidget { - constructor(pawn: Pawn) { +class GridItem extends QWidget { + + rootLayout: QGridLayout; + + get layout(): QGridLayout { + return this.rootLayout; + } + + constructor() { super(); - let layout: QGridLayout; - this.setLayout(layout = new QGridLayout()); - // this.setInlineStyle(` - // margin-bottom: 4px; - // `); - const nameLabel = new QLabel(); - nameLabel.setText(pawn.name.first + ' ' + pawn.name.last); - nameLabel.setAlignment(AlignmentFlag.AlignLeft | AlignmentFlag.AlignTop); - - const activityLabel = new QLabel(); - activityLabel.setText(pawn.status); - activityLabel.setAlignment(AlignmentFlag.AlignRight | AlignmentFlag.AlignTop); - - this.layout.addWidget(nameLabel, 0, 0, 1, 1); - this.layout.addWidget(activityLabel, 0, 1, 1, 1); - layout.setColumnStretch(0, 1); - layout.setColumnStretch(1, 1); - layout.setRowStretch(0, 1); - // this.setFocusPolicy(FocusPolicy.ClickFocus); + this.rootLayout = new QGridLayout() + this.setLayout(this.rootLayout); + this.setInlineStyle(` + width: \'100%\'; + background: coral; + margin: 0px; + padding: 0px; + `); + + this.setFocusPolicy(FocusPolicy.ClickFocus); } } -class PawnPageWidget extends QListWidget { - +function addSplitText(layout: QGridLayout, left: string, right: string, row: number) { + layout.setSpacing(0); + + const nameLabel = new QLabel(); + nameLabel.setText(left); + nameLabel.setAlignment(AlignmentFlag.AlignLeft | AlignmentFlag.AlignTop); + const activityLabel = new QLabel(); + activityLabel.setText(right); + activityLabel.setAlignment(AlignmentFlag.AlignRight | AlignmentFlag.AlignTop); + + layout.addWidget(nameLabel, row, 0, 1, 1); + layout.addWidget(activityLabel, row, 1, 1, 1); + layout.setRowStretch(row, 1); + + // in theory this is redundant, calling this + // function on the same layout multiple times... + layout.setColumnStretch(0, 1); + layout.setColumnStretch(1, 1); +} + +class PawnWidget extends GridItem { + constructor(pawn: Pawn) { + super(); + + addSplitText( + this.layout, + pawn.name.first + ' ' + pawn.name.last, + pawn.status, + 0 + ); + } +} + +class ItemWidget extends GridItem { + constructor(itemState: ItemState) { + super(); + + addSplitText( + this.layout, + itemState.name, + '' + (itemState.qty), + 0 + ); + } +} + +abstract class ScrollPanel extends QScrollArea { + centralWidget: QWidget; + vLayout: QBoxLayout; + constructor() { super(); - // this.setLayout(new FlexLayout()); - this.setInlineStyle('background: purple;'); - // this.layout.addWidget(new PawnWidget(Game.current.pawns[0])); + this.setInlineStyle(` + background: rgba(0, 0, 0, 0); + border: none; + `) + this.centralWidget = new QWidget(); + this.centralWidget.setInlineStyle(` + background: rgba(0, 0, 0, 0); + `) + // this.setVerticalScrollBarPolicy(ScrollBarPolicy.ScrollBarAlwaysOn); + this.setWidgetResizable(true); + this.setWidget(this.centralWidget); + this.vLayout = new QBoxLayout(Direction.TopToBottom); + this.centralWidget.setLayout(this.vLayout); + this.fill(); + + this.vLayout.addStretch(1); + + // for(let i = 0; i < 100; i ++) { + // const button = new QPushButton(); + // button.setText('' + i); + // this.vLayout.addWidget(button); + // } + } + + refill() { + for(const a of this.nodeChildren) { + console.log(a); + } + this.fill(); + } + + addWidget(widget: QWidget) { + this.vLayout.addWidget(widget); + } + + abstract fill(): void; +} + +class PawnPageWidget extends ScrollPanel { + fill() { for(const pawn of Game.current.pawns) { - // const label = new QLabel(); - // label.setText(pawn.name.first); - // this.layout.addWidget(label); - // this.layout.addWidget(new PawnWidget(pawn)); - const item = new QListWidgetItem(); - this.addItem(item); - this.setItemWidget(item, new PawnWidget(pawn)); + this.addWidget(new PawnWidget(pawn)); } } } +// class PawnPageWidget extends QListWidget { +// constructor() { +// super(); +// for (const pawn of Game.current.pawns) { +// const pawnWidget = new PawnWidget(pawn); +// const item = new QListWidgetItem(); +// this.addItem(item); +// this.setItemWidget(item, pawnWidget); +// } +// } +// } + +// class PawnPageWidget extends QWidget { + +// constructor() { +// super(); +// this.setLayout(new QBoxLayout(Direction.TopToBottom)); +// // this.setLayout(new FlexLayout()); + +// for(const pawn of Game.current.pawns) { +// this.layout.addWidget(new PawnWidget(pawn)); +// } +// } +// } + class TimeWidget extends QLabel { constructor() { @@ -112,6 +213,38 @@ class TimeWidget extends QLabel { } } -class InventoryWidget extends QWidget { + +class InventoryPageWidget extends ScrollPanel { + fill() { + for(const itemState of Game.current.inv.items) { + this.addWidget(new ItemWidget(itemState)) + } + } +} + +class MultiplayerPlayerWidget extends GridItem { + constructor(player: Player) { + super(); + addSplitText( + this.layout, + player.name, + player.host + ':' + player.port, + 0 + ) + } +} + +class MultiplayerPageWidget extends ScrollPanel { + constructor() { + super(); + network.on('change', () => { + this.refill(); + }) + } + fill(): void { + for(const player of network.players) { + this.addWidget(new MultiplayerPlayerWidget(player)) + } + } } \ No newline at end of file diff --git a/src/qt/index.ts b/src/qt/index.ts index 745f438..a3ca1a0 100644 --- a/src/qt/index.ts +++ b/src/qt/index.ts @@ -20,10 +20,14 @@ win.setWindowTitle(APPLICATION_NAME); win.show(); (global as any).win = win; win.addEventListener(WidgetEventTypes.Paint, _ => _); -win.addEventListener('customContextMenuRequested', console.log) -win.addEventListener('objectNameChanged', console.log) -win.addEventListener('windowIconChanged', console.log) -win.addEventListener('windowTitleChanged', console.log) +win.addEventListener('customContextMenuRequested', console.log); +win.addEventListener('objectNameChanged', console.log); +win.addEventListener('windowIconChanged', console.log); +win.addEventListener('windowTitleChanged', console.log); +win.addEventListener( + WidgetEventTypes.Close, + () => ProcessManager.quit() +); setView(new LoadingView()); @@ -54,7 +58,6 @@ export function isStarted() { ProcessManager.on('reload', () => { RequestReloadPopup.show(); - // }); @@ -62,6 +65,6 @@ ProcessManager.on('reload', () => { function f() { win.repaint(); win.update(); - setTimeout(f, 100); + setTimeout(f, 0); } f(); \ No newline at end of file diff --git a/src/registries/Items.ts b/src/registries/Items.ts index 6abea87..f967f1f 100644 --- a/src/registries/Items.ts +++ b/src/registries/Items.ts @@ -36,7 +36,7 @@ export class Item { register(force = true) { if((!this.id || !this.name) && !force) return; - console.log('Added item', (this.name.singular ?? "[No Name]").padStart(20, ' '), `| (${this.id})`) + // console.log('Added item', (this.name.singular ?? "[No Name]").padStart(20, ' '), `| (${this.id})`) items.set(this.id, this); return this; } @@ -63,6 +63,10 @@ export class ItemState extends Serializable { return new ItemState(this.item, qty, this.data); } + get name() { + return this.qty === 1 ? this.item.name.singular : this.item.name.plural; + } + get item() { if(!items.has(this.itemId)) throw new Error('unknown item: ' + this.itemId); diff --git a/src/registries/Themes.ts b/src/registries/Themes.ts index 0c7991f..f4253ec 100644 --- a/src/registries/Themes.ts +++ b/src/registries/Themes.ts @@ -80,7 +80,7 @@ let currentTheme = backupTheme; const themes: Map = new Map(); export function registerTheme(name: ThemeName, theme: Partial) { - console.log('Registered theme', name); + // console.log('Registered theme', name); themes.set(name, merge(backupTheme, theme)); } diff --git a/src/term-ui/EscapeMenu.ts b/src/term-ui/EscapeMenu.ts index 3768507..c86119f 100644 --- a/src/term-ui/EscapeMenu.ts +++ b/src/term-ui/EscapeMenu.ts @@ -40,7 +40,7 @@ export class EscapeMenu { } else if (key.full === 'enter') { switch(this.selected) { case 0: { - Game.current.clock.start(); + Game.current.clock.resume(); panels.screen.remove(this.box); break; } @@ -54,7 +54,7 @@ export class EscapeMenu { } } } else if(key.full === 'escape') { - Game.current.clock.start(); + Game.current.clock.resume(); panels.screen.remove(this.box); } this.render(); diff --git a/src/term-ui/GiftPopup.ts b/src/term-ui/GiftPopup.ts index f8cf5d6..4c8a280 100644 --- a/src/term-ui/GiftPopup.ts +++ b/src/term-ui/GiftPopup.ts @@ -29,7 +29,7 @@ export class GiftPopup { if(key.full === 'enter') { this.send(); } if(key.full === 'escape' || key.full === 'enter') { - Game.current.clock.start(); + Game.current.clock.resume(); panels.screen.remove(this.box); } else if (key.full === 'up') { this.selected --; diff --git a/src/term-ui/PawnDetails.ts b/src/term-ui/PawnDetails.ts index 971db0a..3913850 100644 --- a/src/term-ui/PawnDetails.ts +++ b/src/term-ui/PawnDetails.ts @@ -23,7 +23,7 @@ export class PawnDetails { }); this.box.on('keypress', (evt: {}, key: {full: string}) => { if(key.full === 'escape' || key.full === 'enter') { - Game.current.clock.start(); + Game.current.clock.resume(); panels.screen.remove(this.box); } else if (key.full === 'up') { // this.selected --; diff --git a/src/term-ui/Popup.ts b/src/term-ui/Popup.ts index c865f85..8bd5e4f 100644 --- a/src/term-ui/Popup.ts +++ b/src/term-ui/Popup.ts @@ -23,7 +23,7 @@ export class Popup { }); this.box.on('keypress', (evt: {}, key: {full: string}) => { if(key.full === 'escape' || key.full === 'enter') { - Game.current.clock.start(); + Game.current.clock.resume(); panels.screen.remove(this.box); } }); diff --git a/src/term-ui/SelectItem.ts b/src/term-ui/SelectItem.ts index 3edfeca..dd5e4d0 100644 --- a/src/term-ui/SelectItem.ts +++ b/src/term-ui/SelectItem.ts @@ -33,7 +33,7 @@ export class SelectItem { } private close() { - Game.current.clock.start(); + Game.current.clock.resume(); panels.screen.remove(this.box); } diff --git a/src/term-ui/UI.ts b/src/term-ui/UI.ts index a93c14c..075f9e0 100644 --- a/src/term-ui/UI.ts +++ b/src/term-ui/UI.ts @@ -122,6 +122,7 @@ export function start() { export function stop() { screen.destroy(); // process.stdout.write('\x1b[?1049l'); + process.stdout.write(ansi.cursor.show); } // move to some debugging shit, idk