From a75c18d19737557ef4a5bb91684ab13b79792a9c Mon Sep 17 00:00:00 2001 From: Bronwen Date: Mon, 19 Jul 2021 01:53:30 -0400 Subject: [PATCH] a bunch of stuff --- content/core/items/CoreItems.ts | 1 + src/Game.ts | 2 + src/Pawn.ts | 26 ++++++++--- src/TaskList.ts | 1 + src/World.ts | 10 ++-- src/index.ts | 6 ++- src/registries/Items.ts | 15 ++++-- src/registries/Themes.ts | 2 +- src/ui/EscapeMenu.ts | 72 +++++++++++++++++++++++++++++ src/ui/Menu.ts | 6 +-- src/ui/Popup.ts | 2 +- src/ui/SelectionBox.ts | 49 ++++++++++++++++++++ src/ui/UI.ts | 26 +++++++---- src/ui/view/ActionsView.ts | 33 ------------- src/world/ResourceCollectionTask.ts | 8 +++- 15 files changed, 194 insertions(+), 65 deletions(-) create mode 100644 src/ui/EscapeMenu.ts create mode 100644 src/ui/SelectionBox.ts delete mode 100644 src/ui/view/ActionsView.ts diff --git a/content/core/items/CoreItems.ts b/content/core/items/CoreItems.ts index 92d7acf..da33f7d 100644 --- a/content/core/items/CoreItems.ts +++ b/content/core/items/CoreItems.ts @@ -30,6 +30,7 @@ export const LOG = new Item() export const STICK = new Item() .setName("Stick") + .plural('Sticks') .setId('core:resources/stick') export const PLANT_FIBRES = new Item() diff --git a/src/Game.ts b/src/Game.ts index 9b6f10f..892ca1d 100644 --- a/src/Game.ts +++ b/src/Game.ts @@ -80,5 +80,7 @@ export class Game extends Frigid implements Tickable, Renderable { render() { this.menu.render(); this.board.render(); + // TODO this logic dont make sense + return ''; } } \ No newline at end of file diff --git a/src/Pawn.ts b/src/Pawn.ts index c7f9a52..4480583 100644 --- a/src/Pawn.ts +++ b/src/Pawn.ts @@ -3,13 +3,13 @@ import faker from 'faker'; import { Task, TaskState } from './registries/Tasks.js'; import Time, { Tickable } from './Time.js'; import { Game } from './Game.js'; -import { render } from './ui/UI.js'; +import { render, Renderable, RenderMode } from './ui/UI.js'; import { Memory } from './Memory.js'; import { getTheme } from '@themes'; // TODO add stats getter to return % of all stats -export class Pawn extends Serializable implements Tickable { +export class Pawn extends Serializable implements Tickable, Renderable { name: { first: string, last: string @@ -18,7 +18,7 @@ export class Pawn extends Serializable implements Tickable { age: number; memories: Memory[]; - job: TaskState; + job: TaskState; async tick() { this.age ++; @@ -81,10 +81,22 @@ export class Pawn extends Serializable implements Tickable { } toString() { - if(this.name) { - return this.name.first + ' ' + this.name.last; - } else { - return '[Object Pawn]'; + return this.render(RenderMode.ONELINE); + } + + render(mode: RenderMode): string { + if(mode === RenderMode.ONELINE) { + if(this.name) { + return this.name.first + ' ' + this.name.last; + } else { + return '[Object Pawn]'; + } + } else if (mode === RenderMode.DETAILS) { + return `${ + this.toString() + }{|}${ + this.status + }\nDETAILS\nDETAILS` } } } diff --git a/src/TaskList.ts b/src/TaskList.ts index b85e330..69b3881 100644 --- a/src/TaskList.ts +++ b/src/TaskList.ts @@ -40,6 +40,7 @@ export class TaskList extends Serializable implements Renderable { } ${ getTheme().dimmed(task.worker?.toString() ?? '') }`).join('\n')}`); + return ''; // return this.tasks.map(task => task.toString()).join('\n'); } } \ No newline at end of file diff --git a/src/World.ts b/src/World.ts index 5aca6ef..f21538f 100644 --- a/src/World.ts +++ b/src/World.ts @@ -4,11 +4,12 @@ import { Task, TaskState } from "@tasks"; import { Serializable } from "frigid"; import { RESOURCE_COLLECTION_TASK } from "./world/ResourceCollectionTask.js"; +const explorationConstant = 0.001; // km ish + export class World extends Serializable { places: PlaceState[] = []; - distanceExplored = 0; // km ish - explorationConstant = 0.001; // km ish + distanceExplored: number; // km ish home: PlaceState = null; @@ -18,7 +19,7 @@ export class World extends Serializable { explore() { for(const [id, place] of places) { - const threshold = (this.explorationConstant * place.frequency); + const threshold = (explorationConstant * place.frequency); if(Math.random() <= threshold) { const angle = Math.random() * Math.PI * 2 const x = Math.sin(angle) * this.distanceExplored; @@ -34,10 +35,11 @@ export class World extends Serializable { this.places.push(newPlaceState); } } - this.distanceExplored += this.explorationConstant; + this.distanceExplored += explorationConstant; } ctor() { + this.distanceExplored ??= 0; this.home ??= null; this.places ??= []; if(this.home === null) { diff --git a/src/index.ts b/src/index.ts index 1a9379c..6eb821a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ import { fileURLToPath } from 'url'; import { Game } from '@game'; import { isStarted, stop } from './ui/UI.js'; import { writeFileSync } from 'fs'; +import ansi from 'sisteransi'; console.clear(); @@ -20,6 +21,7 @@ function gracefulShutdown() { Game.current.sync(); } console.log('exitting'); + process.stdout.write(ansi.cursor.show); process.exit(0); } process.on('exit', gracefulShutdown); @@ -50,11 +52,11 @@ for(const path of extensions) { console.log('Setup Complete.'); -for(let seconds = 2; seconds > 0; seconds --) { +for(let seconds = 0; seconds > 0; seconds --) { process.stdout.write('Starting DF-Idle in ' + seconds + '\r'); await new Promise(res => setTimeout(res, 1000)); } -console.log(); +console.clear(); // TODO move render logic into game, so that the ui doesnt exist until the game does... // maybe, i mean, an argument could be made for not that, because the game diff --git a/src/registries/Items.ts b/src/registries/Items.ts index b7ab2fe..badc2ff 100644 --- a/src/registries/Items.ts +++ b/src/registries/Items.ts @@ -9,16 +9,25 @@ const items = new Map>(); // ITEMS SHALL BE SINGULAR export class Item extends Serializable { - name = ''; + name = { + singular: '', + plural: '' + } id: ItemID = ''; props: Map = new Map(); setName(name: string) { - this.name = name; + this.name.singular = name; + this.name.plural = name; this.register(false); return this; } + plural(name: string) { + this.name.plural = name; + return this; + } + setId(id: ItemID) { this.id = id; this.register(false); @@ -27,7 +36,7 @@ export class Item extends Serializable { register(force = true) { if((!this.id || !this.name) && !force) return; - console.log('Added item', (this.name ?? "[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; } diff --git a/src/registries/Themes.ts b/src/registries/Themes.ts index 2b08525..0c7991f 100644 --- a/src/registries/Themes.ts +++ b/src/registries/Themes.ts @@ -54,7 +54,7 @@ export const backupTheme: Theme = { selected: chalk.ansi256(117).inverse }, border: { - focused: '#ffffff', + focused: '#00ff00', normal: '#888888' }, progressBar: { diff --git a/src/ui/EscapeMenu.ts b/src/ui/EscapeMenu.ts new file mode 100644 index 0000000..7e18ac0 --- /dev/null +++ b/src/ui/EscapeMenu.ts @@ -0,0 +1,72 @@ +import { Game } from "@game"; +import { boxStyle, getTheme } from "@themes"; +import { panels } from "@ui"; +import blessed from 'neo-blessed'; + +// TODO convert all these popup-y things to be View based +// make them be boxes that have a view +export class EscapeMenu { + + options = [ + 'RESUME', + 'QUIT' + ]; + selected = 0; + box; + + static show() { + new EscapeMenu(); + } + + protected constructor() { + this.box = blessed.box({ + top: 3, + left: 'center', + width: 30, + height: 'shrink', + content: '', + tags: true, + ...boxStyle(), + }); + this.box.on('keypress', (evt: {}, key: {full: string}) => { + if(key.full === 'up') { + this.selected --; + if(this.selected === -1) this.selected = this.options.length - 1; + } else if (key.full === 'down') { + this.selected ++; + if(this.selected === this.options.length) this.selected = 0; + } else if (key.full === 'enter') { + switch(this.selected) { + case 0: { + Game.current.clock.start(); + panels.screen.remove(this.box); + break; + } + case 1: { + Game.current.sync(); + process.exit(0); + } + } + } else if(key.full === 'escape') { + Game.current.clock.start(); + panels.screen.remove(this.box); + } + this.render(); + }); + panels.screen.append(this.box); + this.box.focus(); + Game.current.clock.pause(); + this.render(); + } + + render() { + this.box.setContent(' Paused\n\n' + this.options.map((v, i) => { + if(i === this.selected) { + return ` ${getTheme().bright(v)} `; + } else { + return ` ${getTheme().normal(v)} `; + } + }).join('\n')); + panels.screen.render(); + } +} \ No newline at end of file diff --git a/src/ui/Menu.ts b/src/ui/Menu.ts index 2324e93..76c5635 100644 --- a/src/ui/Menu.ts +++ b/src/ui/Menu.ts @@ -10,8 +10,8 @@ import PawnsView from './view/PawnsView.js'; import InventoryView from './view/InventoryView.js'; import MultiplayerView from './view/MultiplayerView.js'; import { View } from './View.js'; -import { ActionsView } from './view/ActionsView.js'; import WorldResourcesView from './view/WorldView.js'; +import { EscapeMenu } from './EscapeMenu.js'; const clamp = (min: number, max: number, value: number) => Math.min(Math.max(value, min), max); @@ -28,7 +28,6 @@ export class Menu implements Renderable { new PawnsView(), new InventoryView(), new MultiplayerView(), - new ActionsView(), new WorldResourcesView() ] @@ -54,7 +53,7 @@ export class Menu implements Renderable { } else if (key.full === 'right') { this.advanceView(); } else if (key.full === 'escape') { - this.advanceView(); + EscapeMenu.show(); // debugging hotkeys } else if (key.full === '1') { @@ -113,5 +112,6 @@ export class Menu implements Renderable { this.renderView(), ].join('\n'); panels.right.setContent(content); + return ''; } } \ No newline at end of file diff --git a/src/ui/Popup.ts b/src/ui/Popup.ts index e64534e..c865f85 100644 --- a/src/ui/Popup.ts +++ b/src/ui/Popup.ts @@ -11,7 +11,7 @@ export class Popup { new Popup(content) } - private constructor(content: string) { + protected constructor(content: string) { this.box = blessed.box({ top: 'center', left: 'center', diff --git a/src/ui/SelectionBox.ts b/src/ui/SelectionBox.ts new file mode 100644 index 0000000..618e7a6 --- /dev/null +++ b/src/ui/SelectionBox.ts @@ -0,0 +1,49 @@ +import { Renderable, RenderMode } from './UI.js'; +import { KeypressAcceptor } from './Menu.js'; +import { getTheme } from '@themes'; + +export class SelectionBox implements Renderable, KeypressAcceptor { + + selectedIdx = 0; + stuff: Renderable[] = []; + height: number; + offset: number = 0; + getData: () => Renderable[]; + + // buffer = + + constructor(height: number) { + this.height = height; + } + + setGetData(fn: () => Renderable[]) { + this.getData = fn; + } + + render() { + return this.stuff.map((renderable, idx) => { + if(idx === this.selectedIdx) { + return ` ${getTheme().bright(` ❯ ${renderable.render(RenderMode.DETAILS)}`)} `; + } else { + return ` ${getTheme().normal(` ${renderable.render(RenderMode.DETAILS)}`)} `; + } + }).join('\n') + } + + up() { + this.selectedIdx --; + // if(this.selectedIdx === -1) { + + // } + } + + down() { + this.selectedIdx ++; + } + + keypress(key: { full: string; }) { + if(key.full === 'up') { + + } + }; +} diff --git a/src/ui/UI.ts b/src/ui/UI.ts index d248fd2..2c6bdb2 100644 --- a/src/ui/UI.ts +++ b/src/ui/UI.ts @@ -5,7 +5,7 @@ import { boxStyle, getTheme } from '@themes'; export { Popup } from './Popup.js'; export interface Renderable { - render(): void + render(mode?: RenderMode): string } let leftPanel: any; @@ -58,7 +58,7 @@ export function render(thing?: Renderable) { export function start() { assertNotStarted(); - process.stdout.write('\x1b[?1049h'); + // process.stdout.write('\x1b[?1049h'); screen = blessed.screen({ smartCSR: true, @@ -99,12 +99,12 @@ export function start() { process.stdout.write(ansi.cursor.hide); // todo make a real menu - screen.key(['C-c'], function() { - process.stdout.write(ansi.cursor.show); - setTimeout(_ => { - process.exit(0); - }) - }); + // screen.key(['C-c'], function() { + // process.stdout.write(ansi.cursor.show); + // setTimeout(_ => { + // process.exit(0); + // }) + // }); screen.key('f2', () => { rightPanel.focus(); @@ -120,7 +120,7 @@ export function start() { export function stop() { screen.destroy(); - process.stdout.write('\x1b[?1049l'); + // process.stdout.write('\x1b[?1049l'); } // move to some debugging shit, idk @@ -144,4 +144,10 @@ ansiTestCard += '{/center}'; export { ansiTestCard -}; \ No newline at end of file +}; + +export enum RenderMode { + ONELINE, + DETAILS, + DYNAMIC +} \ No newline at end of file diff --git a/src/ui/view/ActionsView.ts b/src/ui/view/ActionsView.ts deleted file mode 100644 index fb0c868..0000000 --- a/src/ui/view/ActionsView.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { getTheme } from "@themes"; -import { Game } from "../../Game.js"; -import { Renderable } from "../UI.js"; -import { View } from "../View.js"; -import { actions } from "@actions"; - -export class ActionsView extends View { - actionIdx: number = 0; - - constructor() { - super(); - this.name = 'Actions'; - } - - keypress(key: {full: string}) { - if(key.full === 'up') { - this.actionIdx --; - } else if (key.full === 'down') { - this.actionIdx ++; - } else if (key.full === 'enter') { - actions[this.actionIdx].invoke(1); - } - } - render() { - return actions.map((action, idx) => `${(() => { - if(this.actionIdx === idx) { - return getTheme().bright(' ❯ ' + action.name); - } else { - return getTheme().normal(' ' + action.name); - } - })()}`).join('\n'); - } -} \ No newline at end of file diff --git a/src/world/ResourceCollectionTask.ts b/src/world/ResourceCollectionTask.ts index 469245f..f5a7cd3 100644 --- a/src/world/ResourceCollectionTask.ts +++ b/src/world/ResourceCollectionTask.ts @@ -17,7 +17,13 @@ export const RESOURCE_COLLECTION_TASK = })) .setToString((data, state) => { - return 'Collect ' + data.node.resources.item.name + ' from ' + data.node.place.place.name; + return 'Collect ' + + data.qty + + ' ' + + (data.qty === 1 ? data.node.resources.item.name.singular : + data.node.resources.item.name.plural) + + ' from ' + + data.node.place.place.name; }) .setInitiate((data: Data) => { return {