a bunch of stuff
parent
64bcd9761f
commit
a75c18d197
|
|
@ -30,6 +30,7 @@ export const LOG = new Item()
|
||||||
|
|
||||||
export const STICK = new Item()
|
export const STICK = new Item()
|
||||||
.setName("Stick")
|
.setName("Stick")
|
||||||
|
.plural('Sticks')
|
||||||
.setId('core:resources/stick')
|
.setId('core:resources/stick')
|
||||||
|
|
||||||
export const PLANT_FIBRES = new Item()
|
export const PLANT_FIBRES = new Item()
|
||||||
|
|
|
||||||
|
|
@ -80,5 +80,7 @@ export class Game extends Frigid implements Tickable, Renderable {
|
||||||
render() {
|
render() {
|
||||||
this.menu.render();
|
this.menu.render();
|
||||||
this.board.render();
|
this.board.render();
|
||||||
|
// TODO this logic dont make sense
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
18
src/Pawn.ts
18
src/Pawn.ts
|
|
@ -3,13 +3,13 @@ import faker from 'faker';
|
||||||
import { Task, TaskState } from './registries/Tasks.js';
|
import { Task, TaskState } from './registries/Tasks.js';
|
||||||
import Time, { Tickable } from './Time.js';
|
import Time, { Tickable } from './Time.js';
|
||||||
import { Game } from './Game.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 { Memory } from './Memory.js';
|
||||||
import { getTheme } from '@themes';
|
import { getTheme } from '@themes';
|
||||||
|
|
||||||
// TODO add stats getter to return % of all stats
|
// 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: {
|
name: {
|
||||||
first: string,
|
first: string,
|
||||||
last: string
|
last: string
|
||||||
|
|
@ -18,7 +18,7 @@ export class Pawn extends Serializable implements Tickable {
|
||||||
age: number;
|
age: number;
|
||||||
memories: Memory[];
|
memories: Memory[];
|
||||||
|
|
||||||
job: TaskState<unknown>;
|
job: TaskState<unknown, unknown>;
|
||||||
|
|
||||||
async tick() {
|
async tick() {
|
||||||
this.age ++;
|
this.age ++;
|
||||||
|
|
@ -81,11 +81,23 @@ export class Pawn extends Serializable implements Tickable {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
|
return this.render(RenderMode.ONELINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(mode: RenderMode): string {
|
||||||
|
if(mode === RenderMode.ONELINE) {
|
||||||
if(this.name) {
|
if(this.name) {
|
||||||
return this.name.first + ' ' + this.name.last;
|
return this.name.first + ' ' + this.name.last;
|
||||||
} else {
|
} else {
|
||||||
return '[Object Pawn]';
|
return '[Object Pawn]';
|
||||||
}
|
}
|
||||||
|
} else if (mode === RenderMode.DETAILS) {
|
||||||
|
return `${
|
||||||
|
this.toString()
|
||||||
|
}{|}${
|
||||||
|
this.status
|
||||||
|
}\nDETAILS\nDETAILS`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ export class TaskList extends Serializable implements Renderable {
|
||||||
} ${
|
} ${
|
||||||
getTheme().dimmed(task.worker?.toString() ?? '')
|
getTheme().dimmed(task.worker?.toString() ?? '')
|
||||||
}`).join('\n')}`);
|
}`).join('\n')}`);
|
||||||
|
return '';
|
||||||
// return this.tasks.map(task => task.toString()).join('\n');
|
// return this.tasks.map(task => task.toString()).join('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
10
src/World.ts
10
src/World.ts
|
|
@ -4,11 +4,12 @@ import { Task, TaskState } from "@tasks";
|
||||||
import { Serializable } from "frigid";
|
import { Serializable } from "frigid";
|
||||||
import { RESOURCE_COLLECTION_TASK } from "./world/ResourceCollectionTask.js";
|
import { RESOURCE_COLLECTION_TASK } from "./world/ResourceCollectionTask.js";
|
||||||
|
|
||||||
|
const explorationConstant = 0.001; // km ish
|
||||||
|
|
||||||
export class World extends Serializable {
|
export class World extends Serializable {
|
||||||
places: PlaceState[] = [];
|
places: PlaceState[] = [];
|
||||||
|
|
||||||
distanceExplored = 0; // km ish
|
distanceExplored: number; // km ish
|
||||||
explorationConstant = 0.001; // km ish
|
|
||||||
|
|
||||||
home: PlaceState = null;
|
home: PlaceState = null;
|
||||||
|
|
||||||
|
|
@ -18,7 +19,7 @@ export class World extends Serializable {
|
||||||
|
|
||||||
explore() {
|
explore() {
|
||||||
for(const [id, place] of places) {
|
for(const [id, place] of places) {
|
||||||
const threshold = (this.explorationConstant * place.frequency);
|
const threshold = (explorationConstant * place.frequency);
|
||||||
if(Math.random() <= threshold) {
|
if(Math.random() <= threshold) {
|
||||||
const angle = Math.random() * Math.PI * 2
|
const angle = Math.random() * Math.PI * 2
|
||||||
const x = Math.sin(angle) * this.distanceExplored;
|
const x = Math.sin(angle) * this.distanceExplored;
|
||||||
|
|
@ -34,10 +35,11 @@ export class World extends Serializable {
|
||||||
this.places.push(newPlaceState);
|
this.places.push(newPlaceState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.distanceExplored += this.explorationConstant;
|
this.distanceExplored += explorationConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctor() {
|
ctor() {
|
||||||
|
this.distanceExplored ??= 0;
|
||||||
this.home ??= null;
|
this.home ??= null;
|
||||||
this.places ??= [];
|
this.places ??= [];
|
||||||
if(this.home === null) {
|
if(this.home === null) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { fileURLToPath } from 'url';
|
||||||
import { Game } from '@game';
|
import { Game } from '@game';
|
||||||
import { isStarted, stop } from './ui/UI.js';
|
import { isStarted, stop } from './ui/UI.js';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
|
import ansi from 'sisteransi';
|
||||||
|
|
||||||
console.clear();
|
console.clear();
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ function gracefulShutdown() {
|
||||||
Game.current.sync();
|
Game.current.sync();
|
||||||
}
|
}
|
||||||
console.log('exitting');
|
console.log('exitting');
|
||||||
|
process.stdout.write(ansi.cursor.show);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
process.on('exit', gracefulShutdown);
|
process.on('exit', gracefulShutdown);
|
||||||
|
|
@ -50,11 +52,11 @@ for(const path of extensions) {
|
||||||
console.log('Setup Complete.');
|
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');
|
process.stdout.write('Starting DF-Idle in ' + seconds + '\r');
|
||||||
await new Promise(res => setTimeout(res, 1000));
|
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...
|
// 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
|
// maybe, i mean, an argument could be made for not that, because the game
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,25 @@ const items = new Map<ItemID, Item<any>>();
|
||||||
// ITEMS SHALL BE SINGULAR
|
// ITEMS SHALL BE SINGULAR
|
||||||
export class Item<Data = any> extends Serializable {
|
export class Item<Data = any> extends Serializable {
|
||||||
|
|
||||||
name = '';
|
name = {
|
||||||
|
singular: '',
|
||||||
|
plural: ''
|
||||||
|
}
|
||||||
id: ItemID = '';
|
id: ItemID = '';
|
||||||
props: Map<string, any> = new Map();
|
props: Map<string, any> = new Map();
|
||||||
|
|
||||||
setName(name: string) {
|
setName(name: string) {
|
||||||
this.name = name;
|
this.name.singular = name;
|
||||||
|
this.name.plural = name;
|
||||||
this.register(false);
|
this.register(false);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plural(name: string) {
|
||||||
|
this.name.plural = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
setId(id: ItemID) {
|
setId(id: ItemID) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.register(false);
|
this.register(false);
|
||||||
|
|
@ -27,7 +36,7 @@ export class Item<Data = any> extends Serializable {
|
||||||
|
|
||||||
register(force = true) {
|
register(force = true) {
|
||||||
if((!this.id || !this.name) && !force) return;
|
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);
|
items.set(this.id, this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export const backupTheme: Theme = {
|
||||||
selected: chalk.ansi256(117).inverse
|
selected: chalk.ansi256(117).inverse
|
||||||
},
|
},
|
||||||
border: {
|
border: {
|
||||||
focused: '#ffffff',
|
focused: '#00ff00',
|
||||||
normal: '#888888'
|
normal: '#888888'
|
||||||
},
|
},
|
||||||
progressBar: {
|
progressBar: {
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,8 +10,8 @@ import PawnsView from './view/PawnsView.js';
|
||||||
import InventoryView from './view/InventoryView.js';
|
import InventoryView from './view/InventoryView.js';
|
||||||
import MultiplayerView from './view/MultiplayerView.js';
|
import MultiplayerView from './view/MultiplayerView.js';
|
||||||
import { View } from './View.js';
|
import { View } from './View.js';
|
||||||
import { ActionsView } from './view/ActionsView.js';
|
|
||||||
import WorldResourcesView from './view/WorldView.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);
|
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 PawnsView(),
|
||||||
new InventoryView(),
|
new InventoryView(),
|
||||||
new MultiplayerView(),
|
new MultiplayerView(),
|
||||||
new ActionsView(),
|
|
||||||
new WorldResourcesView()
|
new WorldResourcesView()
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -54,7 +53,7 @@ export class Menu implements Renderable {
|
||||||
} else if (key.full === 'right') {
|
} else if (key.full === 'right') {
|
||||||
this.advanceView();
|
this.advanceView();
|
||||||
} else if (key.full === 'escape') {
|
} else if (key.full === 'escape') {
|
||||||
this.advanceView();
|
EscapeMenu.show();
|
||||||
|
|
||||||
// debugging hotkeys
|
// debugging hotkeys
|
||||||
} else if (key.full === '1') {
|
} else if (key.full === '1') {
|
||||||
|
|
@ -113,5 +112,6 @@ export class Menu implements Renderable {
|
||||||
this.renderView(),
|
this.renderView(),
|
||||||
].join('\n');
|
].join('\n');
|
||||||
panels.right.setContent(content);
|
panels.right.setContent(content);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ export class Popup {
|
||||||
new Popup(content)
|
new Popup(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor(content: string) {
|
protected constructor(content: string) {
|
||||||
this.box = blessed.box({
|
this.box = blessed.box({
|
||||||
top: 'center',
|
top: 'center',
|
||||||
left: 'center',
|
left: 'center',
|
||||||
|
|
|
||||||
|
|
@ -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') {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
24
src/ui/UI.ts
24
src/ui/UI.ts
|
|
@ -5,7 +5,7 @@ import { boxStyle, getTheme } from '@themes';
|
||||||
export { Popup } from './Popup.js';
|
export { Popup } from './Popup.js';
|
||||||
|
|
||||||
export interface Renderable {
|
export interface Renderable {
|
||||||
render(): void
|
render(mode?: RenderMode): string
|
||||||
}
|
}
|
||||||
|
|
||||||
let leftPanel: any;
|
let leftPanel: any;
|
||||||
|
|
@ -58,7 +58,7 @@ export function render(thing?: Renderable) {
|
||||||
export function start() {
|
export function start() {
|
||||||
assertNotStarted();
|
assertNotStarted();
|
||||||
|
|
||||||
process.stdout.write('\x1b[?1049h');
|
// process.stdout.write('\x1b[?1049h');
|
||||||
|
|
||||||
screen = blessed.screen({
|
screen = blessed.screen({
|
||||||
smartCSR: true,
|
smartCSR: true,
|
||||||
|
|
@ -99,12 +99,12 @@ export function start() {
|
||||||
process.stdout.write(ansi.cursor.hide);
|
process.stdout.write(ansi.cursor.hide);
|
||||||
|
|
||||||
// todo make a real menu
|
// todo make a real menu
|
||||||
screen.key(['C-c'], function() {
|
// screen.key(['C-c'], function() {
|
||||||
process.stdout.write(ansi.cursor.show);
|
// process.stdout.write(ansi.cursor.show);
|
||||||
setTimeout(_ => {
|
// setTimeout(_ => {
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
})
|
// })
|
||||||
});
|
// });
|
||||||
|
|
||||||
screen.key('f2', () => {
|
screen.key('f2', () => {
|
||||||
rightPanel.focus();
|
rightPanel.focus();
|
||||||
|
|
@ -120,7 +120,7 @@ export function start() {
|
||||||
|
|
||||||
export function stop() {
|
export function stop() {
|
||||||
screen.destroy();
|
screen.destroy();
|
||||||
process.stdout.write('\x1b[?1049l');
|
// process.stdout.write('\x1b[?1049l');
|
||||||
}
|
}
|
||||||
|
|
||||||
// move to some debugging shit, idk
|
// move to some debugging shit, idk
|
||||||
|
|
@ -145,3 +145,9 @@ ansiTestCard += '{/center}';
|
||||||
export {
|
export {
|
||||||
ansiTestCard
|
ansiTestCard
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum RenderMode {
|
||||||
|
ONELINE,
|
||||||
|
DETAILS,
|
||||||
|
DYNAMIC
|
||||||
|
}
|
||||||
|
|
@ -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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,7 +17,13 @@ export const RESOURCE_COLLECTION_TASK =
|
||||||
|
|
||||||
}))
|
}))
|
||||||
.setToString((data, state) => {
|
.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) => {
|
.setInitiate((data: Data) => {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue