a bunch of stuff
parent
64bcd9761f
commit
a75c18d197
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 '';
|
||||
}
|
||||
}
|
||||
26
src/Pawn.ts
26
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<unknown>;
|
||||
job: TaskState<unknown, unknown>;
|
||||
|
||||
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`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
10
src/World.ts
10
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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,16 +9,25 @@ const items = new Map<ItemID, Item<any>>();
|
|||
// ITEMS SHALL BE SINGULAR
|
||||
export class Item<Data = any> extends Serializable {
|
||||
|
||||
name = '';
|
||||
name = {
|
||||
singular: '',
|
||||
plural: ''
|
||||
}
|
||||
id: ItemID = '';
|
||||
props: Map<string, any> = 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<Data = any> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const backupTheme: Theme = {
|
|||
selected: chalk.ansi256(117).inverse
|
||||
},
|
||||
border: {
|
||||
focused: '#ffffff',
|
||||
focused: '#00ff00',
|
||||
normal: '#888888'
|
||||
},
|
||||
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 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 '';
|
||||
}
|
||||
}
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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') {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
26
src/ui/UI.ts
26
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
|
||||
};
|
||||
};
|
||||
|
||||
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) => {
|
||||
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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue