materials
Valerie 2021-07-16 20:49:29 -04:00
parent d4c008a5e1
commit dc39db5b18
23 changed files with 1215 additions and 265 deletions

View File

@ -1,30 +0,0 @@
import { registerAction } from '@actions';
import { Game } from '@game';
import { ItemState } from '@items';
import { TaskState } from '@tasks';
import { SelectItem } from '../../../src/ui/SelectItem.js';
import { FLINT_NORMAL } from '../items/CoreItems.js';
import { GATHER_FLINT, MAKE_ARROWHEAD } from '../tasks/CoreTasks.js';
// registerAction('Gather Slate', (qty) => {
// Game.current.board.addTask({
// taskId: 'core:gather-slate',
// options: {}
// })
// });
registerAction('Gather Flint', () => {
const taskState = new TaskState(GATHER_FLINT);
Game.current.board.addTask(taskState);
});
registerAction('Create Arrowhead', () => {
// const rock = new ItemState(FLINT_NORMAL, 1, null);
const item = SelectItem.show()
const task = new TaskState(MAKE_ARROWHEAD, {
baseMaterial: rock
});
Game.current.board.addTask(task);
});

View File

@ -56,7 +56,7 @@ export const SANDSTONE_PEBBLE = new Item()
.setName("Sandstone Pebble") .setName("Sandstone Pebble")
.setId('core:sandstone-pebble') .setId('core:sandstone-pebble')
export const SLATE_NORMAL = new Item() export const SLATE = new Item()
.setName("Slate") .setName("Slate")
.setId('core:slate') .setId('core:slate')

View File

@ -1,32 +1,42 @@
import { Task } from "@tasks"; import { Task } from "@tasks";
import { Game } from '@game'; import { Game } from '@game';
import { ARROWHEAD, FLINT_NORMAL, SLATE_NORMAL } from '../items/CoreItems.js'; import { ARROWHEAD, FLINT_NORMAL, SLATE, STICK } from '../items/CoreItems.js';
import { ItemState } from "@items"; import { ItemState } from "@items";
import { Popup } from "../../../src/ui/Popup.js"; import { Popup } from "../../../src/ui/Popup.js";
import { inspect } from 'util'; import { inspect } from 'util';
import { Place, ResourceNode } from "@world";
export const GATHER_FLINT = new Task('core:gather-flint') // export const GATHER_FLINT = new Task('core:gather-flint')
.setName('Gather Flint') // .setName('Gather Flint')
.setStatus('SCAVENGING') // .setStatus('SCAVENGING')
.setWork(1000) // .setWork(1000)
.setTasklistVisibility(true) // .setTasklistVisibility(true)
.setCategory("work") // .setCategory("work")
.setCompletionEvent(() => { // .setCompletionEvent(() => {
const qty = Math.floor(Math.random() * 5) + 1; // const qty = Math.floor(Math.random() * 5) + 1;
Game.current.inv.add(new ItemState(FLINT_NORMAL, 1, null)); // Game.current.inv.add(new ItemState(FLINT_NORMAL, 1, null));
}); // });
export const MAKE_ARROWHEAD = new Task<{ // export const MAKE_ARROWHEAD = new Task<{
baseMaterial: ItemState<any> // baseMaterial: ItemState<any>
}>('core:gather-slate') // }>('core:gather-slate')
.setName('Craft Arrowhead') // .setName('Craft Arrowhead')
.setStatus('CRAFTING') // .setStatus('CRAFTING')
.setWork(1000) // .setWork(1000)
.setTasklistVisibility(true) // .setTasklistVisibility(true)
.setCategory("craft") // .setCategory("craft")
.setCompletionEvent((data) => { // .setCompletionEvent((data) => {
const itemState = new ItemState(ARROWHEAD, 1, { // const itemState = new ItemState(ARROWHEAD, 1, {
baseMaterial: data.baseMaterial // baseMaterial: data.baseMaterial
}); // });
Game.current.inv.add(itemState); // Game.current.inv.add(itemState);
}); // });
export const Forest = new Place()
.setName('Forest')
.setId('core:forest')
.setFrequency(1)
.setHabitable(true)
.populateResources(() => [
new ResourceNode(new ItemState(STICK, 10_000))
])

12
index.html 100644
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>df-idle</title>
</head>
<body>
<script type="module" src="./out/index.js"></script>
</body>
</html>

View File

@ -5,6 +5,7 @@ const moduleAliases = {
"@actions": "./out/src/registries/Actions.js", "@actions": "./out/src/registries/Actions.js",
"@tasks": "./out/src/registries/Tasks.js", "@tasks": "./out/src/registries/Tasks.js",
"@items": "./out/src/registries/Items.js", "@items": "./out/src/registries/Items.js",
"@world": "./out/src/World.js",
"@ui": "./out/src/ui/UI.js", "@ui": "./out/src/ui/UI.js",
"@game": "./out/src/Game.js" "@game": "./out/src/Game.js"
}; };

View File

@ -13,6 +13,7 @@
"@types/mocha": "^8.2.2", "@types/mocha": "^8.2.2",
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/ws": "^7.4.5", "@types/ws": "^7.4.5",
"@web/dev-server": "^0.1.18",
"bonjour": "^3.5.0", "bonjour": "^3.5.0",
"chai": "^4.3.4", "chai": "^4.3.4",
"chalk": "^4.1.1", "chalk": "^4.1.1",
@ -42,6 +43,7 @@
"prod": "git fetch && git pull && yarn && tsc && yarn start", "prod": "git fetch && git pull && yarn && tsc && yarn start",
"test": "mocha", "test": "mocha",
"lint": "eslint src/**/*.ts", "lint": "eslint src/**/*.ts",
"profile": "node --inspect --no-warnings --loader ./lib/aliases.mjs --enable-source-maps out/src/index.js" "web": "web-dev-server --open index.html --node-resolve --watch",
"profile": "node --inspect-brk --no-warnings --loader ./lib/aliases.mjs --enable-source-maps out/src/index.js"
} }
} }

View File

@ -8,6 +8,7 @@ import Time, { Tickable } from './Time.js';
import { render, Renderable, setTitle, start } from './ui/UI.js'; import { render, Renderable, setTitle, start } from './ui/UI.js';
import { ready } from './multiplayer/mDNS.js'; import { ready } from './multiplayer/mDNS.js';
import faker from 'faker'; import faker from 'faker';
import { World } from '@world';
let game: Game = null; let game: Game = null;
@ -19,6 +20,7 @@ export class Game extends Frigid implements Tickable, Renderable {
menu: Menu; menu: Menu;
clock: Time; clock: Time;
name: string; name: string;
world: World;
[DEBUG] = true; [DEBUG] = true;
@ -57,6 +59,7 @@ export class Game extends Frigid implements Tickable, Renderable {
start(); start();
this.name ??= faker.address.city(); this.name ??= faker.address.city();
setTitle(this.name); setTitle(this.name);
this.world ??= new World();
this.pawns ??= []; this.pawns ??= [];
this.selected ??= this.pawns[0] || null; this.selected ??= this.pawns[0] || null;
this.menu = new Menu(); this.menu = new Menu();
@ -71,7 +74,7 @@ export class Game extends Frigid implements Tickable, Renderable {
} }
static serializationDependencies() { static serializationDependencies() {
return [ Pawn, Inventory, TaskList, Time ]; return [ Pawn, Inventory, TaskList, Time, World ];
} }
render() { render() {

View File

@ -1,19 +1,12 @@
import { Serializable } from 'frigid'; import { Serializable } from 'frigid';
import faker from 'faker'; import faker from 'faker';
import { 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 } from './ui/UI.js';
import { Memory } from './Memory.js'; import { Memory } from './Memory.js';
import { getTheme } from '@themes'; import { getTheme } from '@themes';
// const STATUS = {
// IDLE: Symbol('IDLE')
// }
const energyScale = 0.1;
const MAX_ENERGY = 100;
// 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 {
@ -21,54 +14,18 @@ export class Pawn extends Serializable implements Tickable {
first: string, first: string,
last: string last: string
}; };
job: TaskState<any>;
awake: boolean;
sex: number; sex: number;
energy: number;
fun: number;
age: number; age: number;
memories: Memory[]; memories: Memory[];
job: TaskState<unknown>;
async tick() { async tick() {
this.age ++; this.age ++;
this.energy -= energyScale;
if(this.awake === false) {
this.energy += energyScale * 4;
if(this.energy >= MAX_ENERGY) {
this.awake = true;
}
} else {
if(this.job) {
this.job.doWork(1, this);
this.energy -= energyScale;
if(this.job?.completed) {
this.stopWorking();
}
} else {
const inactive = Game.current.board.tasks.filter(task => {
return task.worker === null;
});
if(inactive.length > 0) {
const task = inactive[0];
// const task = inactive[Math.floor(Math.random() * inactive.length)];
this.assignJob(task);
}
}
if(this.energy <= 0) {
this.stopWorking();
this.awake = false;
}
}
} }
get idle() { get idle() {
return !this.job && this.awake; return !this.job;
} }
ctor() { ctor() {
@ -80,8 +37,6 @@ export class Pawn extends Serializable implements Tickable {
this.sex = Math.round(Math.random()); this.sex = Math.round(Math.random());
this.name.first = faker.name.firstName(this.sex); this.name.first = faker.name.firstName(this.sex);
} }
this.awake ??= true;
this.energy ??= MAX_ENERGY;
this.memories ??= []; this.memories ??= [];
if(!this.age) { if(!this.age) {
this.age = Math.floor(525600 * (16 + Math.random() * 9)); this.age = Math.floor(525600 * (16 + Math.random() * 9));
@ -96,30 +51,29 @@ export class Pawn extends Serializable implements Tickable {
} }
if(this.job?.completed) { // if(this.job?.completed) {
this.stopWorking(); // this.stopWorking();
// }
} }
taskCompleted() {
this.job = null
} }
stopWorking() { stopWorking() {
if(this.job) { if(this.job) {
this.job.stopJob(); // this.job.unclaim(this);
this.job = null; this.job = null;
} }
} }
assignJob(task: TaskState<any>) {
this.job?.stopJob()
this.job = task;
this.job.claim(this);
}
get status() { get status() {
if(this.job) { return 'SEMETHING';
return this.job.task.status; // if(this.job) {
} else { // return this.job.task.status;
return this.awake ? getTheme().status.idle('IDLE') : getTheme().status.self('RESTING') // } else {
} // return this.awake ? getTheme().status.idle('IDLE') : getTheme().status.self('RESTING')
// }
} }
static serializationDependencies() { static serializationDependencies() {
@ -134,3 +88,5 @@ export class Pawn extends Serializable implements Tickable {
} }
} }
} }
// const task =

View File

@ -1,11 +1,10 @@
import { getTheme } from '@themes';
import { Serializable } from 'frigid'; import { Serializable } from 'frigid';
import { Task, TaskState } from './registries/Tasks.js'; import { Task, TaskState } from './registries/Tasks.js';
import { render, Renderable, panels } from './ui/UI.js'; import { render, Renderable, panels } from './ui/UI.js';
const taskTypes = {};
export class TaskList extends Serializable implements Renderable { export class TaskList extends Serializable implements Renderable {
tasks: TaskState<any>[] = []; tasks: TaskState<unknown, unknown>[] = [];
clear() { clear() {
for(const task of this.tasks) { for(const task of this.tasks) {
@ -13,27 +12,34 @@ export class TaskList extends Serializable implements Renderable {
} }
} }
static serializationDependencies() { static serializationDependencies(): any[] {
return [TaskState] return [];
} }
addTask(task: TaskState<any>) { // TODO assign task dependant on pawn skills
getUnclaimedTask(): TaskState<unknown, unknown> | null {
// const availableTasks = this.tasks.filter(task => !task.claimed);
// if(availableTasks.length > 0) {
// return availableTasks[0]
// } else return null;
return null;
}
addTask(task: TaskState<unknown, unknown>) {
this.tasks = [...this.tasks, task]; this.tasks = [...this.tasks, task];
} }
removeTask(task: TaskState<any>) { removeTask(task: TaskState<unknown, unknown>) {
this.tasks = this.tasks.filter(v => v !== task); this.tasks = this.tasks.filter(v => v !== task);
} }
render() { render() {
// const width = tasksPanel.width; // const width = tasksPanel.width;
panels.left.setContent(`${this.tasks.map(task => { panels.left.setContent(`${this.tasks.map(task => `${
return task.toString(); getTheme().normal(task.toString())
}).join('\n')}`); } ${
getTheme().dimmed(task.worker?.toString() ?? '')
}`).join('\n')}`);
// return this.tasks.map(task => task.toString()).join('\n'); // return this.tasks.map(task => task.toString()).join('\n');
} }
} }
// export function registerTask(name, clazz) {
// taskTypes[name] = clazz;
// }

View File

@ -1,5 +1,143 @@
import { Game } from "@game";
import { ItemFilter, ItemState } from "@items";
import { Task, TaskState } from "@tasks";
import { Serializable } from "frigid"; import { Serializable } from "frigid";
import { RESOURCE_COLLECTION_TASK } from "./world/ResourceCollectionTask.js";
export class World extends Serializable { export class World extends Serializable {
places: PlaceState[] = [];
distanceExplored = 0; // km ish
explorationConstant = 0.001; // km ish
home: PlaceState = null;
static serializationDependencies() {
return [PlaceState];
}
explore() {
for(const [id, place] of places) {
const threshold = (this.explorationConstant * place.frequency);
if(Math.random() <= threshold) {
const angle = Math.random() * Math.PI * 2
const x = Math.sin(angle) * this.distanceExplored;
const y = Math.cos(angle) * this.distanceExplored;
const newPlaceState = new PlaceState(
place,
Math.round(x * 1000),
Math.round(y * 1000)
);
if(this.home === null) {
this.home = newPlaceState;
}
this.places.push(newPlaceState);
}
}
this.distanceExplored += this.explorationConstant;
}
ctor() {
this.home ??= null;
this.places ??= [];
if(this.home === null) {
let hasHabitablePlacesLoaded = false;
for(const [id, place] of places) {
if(place.habitable) hasHabitablePlacesLoaded = true;
break;
}
if(hasHabitablePlacesLoaded) {
while(this.home === null) {
this.explore();
}
} else {
throw new Error('No habitable places loaded\n'
+ 'unable to create home!')
}
}
}
}
const places: Map<string, Place> = new Map();
export class PlaceState extends Serializable {
resources: ResourceNode[];
placeId: string;
x: number;
y: number;
constructor(place: Place, x: number, y: number) {
super();
this.placeId = place.id;
this.resources = this.place.populate();
for(const node of this.resources) node.setPlace(this);
this.x = x;
this.y = y;
}
get place() {
return places.get(this.placeId);
}
static serializationDependencies() {
return [ResourceNode];
}
}
export class Place {
name: string;
id: string;
frequency: number;
habitable: boolean;
populate: () => ResourceNode[];
setName(name: string) {
this.name = name;
return this;
}
setId(id: string) {
this.id = id;
places.set(this.id, this);
return this;
}
populateResources(fn: () => ResourceNode[]) {
this.populate = fn;
return this;
}
setFrequency(frequency: number) {
this.frequency = frequency;
return this;
}
setHabitable(habitable: boolean) {
this.habitable = habitable;
return this;
}
}
export class ResourceNode extends Serializable {
resources: ItemState<unknown>;
place: PlaceState;
constructor(resources: ItemState<unknown>) {
// collectionRequirements: ItemFilter[] = []
super();
this.resources = resources;
}
setPlace(place: PlaceState) {
this.place = place;
}
request(qty: number) {
Game.current.board.addTask(
new TaskState(RESOURCE_COLLECTION_TASK, {
qty,
node: this
})
);
}
} }

View File

@ -8,6 +8,7 @@ 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';
console.clear();
function gracefulShutdown() { function gracefulShutdown() {
if(isStarted()) { if(isStarted()) {
@ -34,19 +35,27 @@ console.log('df-idle: Loading extensions');
const extensionsPath = resolve(parse(fileURLToPath(import.meta.url)).dir, '../content'); const extensionsPath = resolve(parse(fileURLToPath(import.meta.url)).dir, '../content');
const extensions = walkSync(extensionsPath) const extensions = walkSync(extensionsPath)
.map(path => resolve(extensionsPath, path)) .map(path => [path, resolve(extensionsPath, path)])
.filter(path => lstatSync(path).isFile()) .filter(path => lstatSync(path[1]).isFile())
.filter(path => parse(path).ext === '.js'); .filter(path => parse(path[1]).ext === '.js');
// .map(path => import(path));
console.log('found', extensions.length, 'extensions'); console.log('found', extensions.length, 'extensions');
for(const path of extensions) { for(const path of extensions) {
console.log('=== [', path, '] ==='); console.log('=== [', path[0], '] ===');
await import(path); await import(path[1]);
console.log(); console.log();
} }
console.log('Setup Complete.');
for(let seconds = 2; seconds > 0; seconds --) {
process.stdout.write('Starting DF-Idle in ' + seconds + '\r');
await new Promise(res => setTimeout(res, 1000));
}
console.log();
// 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
// isnt necessarily the entire thing, its just one instance of a save file. // isnt necessarily the entire thing, its just one instance of a save file.

View File

@ -1,20 +0,0 @@
import { getTheme } from "@themes";
import { Renderable } from "../ui/UI.js";
export const actions: Action[] = [];
export function registerAction(name: string, invoke: () => void) {
console.log('Registered action', name);
actions.push(new Action(name, invoke))
}
export class Action {
name: string;
qty: number;
invoke: (qty: number) => void;
constructor(name: string, done: (qty: number) => void) {
this.name = name;
this.invoke = done;
}
}

View File

@ -7,7 +7,7 @@ export type ItemID = string;
const items = new Map<ItemID, Item<any>>(); const items = new Map<ItemID, Item<any>>();
// ITEMS SHALL BE SINGULAR // ITEMS SHALL BE SINGULAR
export class Item<Data> extends Serializable { export class Item<Data = any> extends Serializable {
name = ''; name = '';
id: ItemID = ''; id: ItemID = '';
@ -60,7 +60,7 @@ export class ItemState<Data> extends Serializable implements Renderable {
return items.get(this.itemId); return items.get(this.itemId);
} }
constructor(item: Item<Data>, amount: number, data: Data) { constructor(item: Item<Data>, amount: number, data: Data = null) {
super(); super();
this.qty = amount; this.qty = amount;
this.itemId = item.id; this.itemId = item.id;

View File

@ -6,119 +6,94 @@ import { Game } from '../Game.js';
import { panels } from '../ui/UI.js'; import { panels } from '../ui/UI.js';
import { progressbar, ProgressbarStyle } from '../Progressbar.js'; import { progressbar, ProgressbarStyle } from '../Progressbar.js';
export const tasks: Map<string, Task<any>> = new Map(); const tasks: Map<string, Task<unknown, unknown>> = new Map();
export type TaskCategory = "self" | "work" | "craft" | "idle"; type WorkFunction<Data, State> = (taskState: TaskState<Data, State>, dtime: number) => void;
type InitFunction<Data, State> = (data: Data) => State;
export class Task<Data> { export class Task<Data, State> {
id: string; id: string;
work: number; fn: WorkFunction<Data, State>;
name: string | ((data: Data) => string); init: InitFunction<Data, State>;
status: string; name: string;
tasklistVisibility: boolean; toString: (data: Data, state: State) => string;
category: TaskCategory;
completionEvent: (data: Data) => void;
setTasklistVisibility(b: boolean) { constructor(id: string) {
this.tasklistVisibility = b; this.id = id;
tasks.set(id, this);
}
setInitiate(init: InitFunction<Data, State>) {
this.init = init;
return this; return this;
} }
setName(name: string | ((data: Data) => string)) { setFunction(fn: WorkFunction<Data, State>) {
this.fn = fn;
return this;
}
setName(name: string) {
this.name = name; this.name = name;
return this; return this;
} }
setStatus(s: string) { setToString(fn: (data: Data, state: State) => string) {
this.status = s; this.toString = fn;
return this; return this;
} }
setCategory(c: TaskCategory) {
this.category = c;
return this;
} }
setWork(n: number) { export class TaskState<Data, State> extends Serializable {
this.work = n;
return this;
}
setCompletionEvent(fn: (data: Data) => void) {
this.completionEvent = fn;
return this;
}
constructor(id: string) {
this.id = id;
this.tasklistVisibility = true;
this.category = "work";
tasks.set(this.id, this);
}
}
export class TaskState<T> extends Serializable {
taskId: string; taskId: string;
progress: number; workFn: WorkFunction<Data, State>;
x: number;
y: number;
data: Data;
completed: boolean = false;
worker: Pawn; worker: Pawn;
data: T; state: State;
ctor() { constructor(task: Task<Data, State>, data: Data) {
// retest completion when loaded, JUST IN CASE
this.testCompletion();
}
constructor(task: Task<T>, data: T = {} as T) {
super(); super();
this.taskId = task.id;
this.progress = 0;
this.worker = null;
// preset the data to nothing JIC
this.data = data; this.data = data;
this.taskId = task.id;
this.workFn = this.task.fn.bind(this);
} }
stopJob() { setLocation(x: number, y: number) {
this.worker = null; this.x = x;
this.y = y;
} }
doWork(work = 1, pawn: Pawn) { get task(): Task<Data, State> {
this.worker = pawn; // casting because the id this is associated with
this.progress += work; // should have the datatype of the task it was
this.testCompletion(); // created with, but it stored as unknown
return tasks.get(this.taskId) as Task<Data, State>;
} }
testCompletion() { get name() {
if (this.taskId && this.completed) { return this.task.name;
this.task.completionEvent(this.data);
Game.current.board.removeTask(this);
}
} }
free() { work(dtime: number) {
this.worker = null; this.workFn(this, dtime);
} }
claim(pawn: Pawn) { claim(pawn: Pawn) {
this.worker = pawn; this.worker = pawn;
} }
get completion() { unclaim() {
return Math.min(1, this.progress / this.task.work); this.worker = null;
}
get task() {
return tasks.get(this.taskId);
}
get completed() {
return this.completion >= 1;
} }
toString() { toString() {
// HACK magic number 2 here, is the border return this.task.toString(this.data, this.state)
// of the panel
const width = panels.left.width - 2;
const left = ' ' + this.task.name + ' ' + (this.worker?.toString() || chalk.bold.black('Queued'));
const bar = width - 2;
return `${left}\n ${progressbar(this.completion, bar, ProgressbarStyle.progress)}\n`;
} }
} }
// export interface TaskProvider {
// hasTask(): boolean;
// getTask(): TaskState<unknown, unknown>;
// }

View File

@ -11,7 +11,7 @@ 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 { ActionsView } from './view/ActionsView.js';
import { tasks } from '@tasks'; import WorldResourcesView from './view/WorldView.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,8 @@ export class Menu implements Renderable {
new PawnsView(), new PawnsView(),
new InventoryView(), new InventoryView(),
new MultiplayerView(), new MultiplayerView(),
new ActionsView() new ActionsView(),
new WorldResourcesView()
] ]
get view() { get view() {
@ -59,8 +60,6 @@ export class Menu implements Renderable {
} else if (key.full === '1') { } else if (key.full === '1') {
Popup.show(inspect(stats)); Popup.show(inspect(stats));
} else if (key.full === '2') { } else if (key.full === '2') {
Popup.show(inspect(tasks));
} else if (key.full === '3') {
Popup.show(inspect(stats)); Popup.show(inspect(stats));
} else if (key.full === 'z') { } else if (key.full === 'z') {
Game.current.pawns.push(new Pawn()); Game.current.pawns.push(new Pawn());

View File

@ -2,7 +2,7 @@ import { Renderable } from './UI.js';
import { KeypressAcceptor } from './Menu.js'; import { KeypressAcceptor } from './Menu.js';
export abstract class View implements Renderable, KeypressAcceptor { export abstract class View implements Renderable, KeypressAcceptor {
abstract render(): void; abstract render(): string;
abstract keypress(key: { full: string; }): void; abstract keypress(key: { full: string; }): void;
name: string; name: string;

View File

@ -30,7 +30,7 @@ export default class PawnsView extends View {
let str = ''; let str = '';
if(selected) { if(selected) {
str += ` ${getTheme().bright(` ${pawn.toString()}`)}{|}${pawn.status} \n`; str += ` ${getTheme().bright(` ${pawn.toString()}`)}{|}${pawn.status} \n`;
str += ` ${getTheme().normal('Energy')}{|}${progressbar(pawn.energy / 100, (panels.right.width - 4) / 2)} \n`; // str += ` ${getTheme().normal('Energy')}{|}${progressbar(pawn.energy / 100, (panels.right.width - 4) / 2)} \n`;
} else { } else {
str += ` ${getTheme().normal(pawn.toString())}{|}${pawn.status} `; str += ` ${getTheme().normal(pawn.toString())}{|}${pawn.status} `;
} }

View File

@ -0,0 +1,27 @@
import { Game } from "@game";
import { View } from "../View.js";
export default class WorldResourcesView extends View {
constructor() {
super();
this.name = 'World'
}
render(): string {
return `Explored: ${
Game.current.world.distanceExplored.toFixed(3)
} km\n${
Game.current.world.places?.map(place => ` ${
place.placeId
} (${place.x}, ${place.y})\n${
place.resources.map(resourceNode => ` ${
resourceNode.resources.render()
}`)
}`)
}`
}
keypress(key: { full: string; }): void {
if(key.full === 'enter') {
Game.current.world.home.resources[0].request(10);
}
}
}

View File

View File

@ -0,0 +1,26 @@
import { Task } from "@tasks"
import { ResourceNode } from "@world";
type Data = {
qty: number,
node: ResourceNode
};
type State = {
workCounter: number
}
export const RESOURCE_COLLECTION_TASK =
new Task<Data, State>('core:resource-collection-task')
.setName('Collect Resources')
.setFunction(((taskState, dTime) => {
}))
.setToString((data, state) => {
return 'Collect ' + data.node.resources.item.name + ' from ' + data.node.place.place.name;
})
.setInitiate((data: Data) => {
return {
workCounter: 0
}
});

View File

@ -12,6 +12,7 @@
"@actions": ["./src/registries/Actions"], "@actions": ["./src/registries/Actions"],
"@tasks": ["./src/registries/Tasks"], "@tasks": ["./src/registries/Tasks"],
"@items": ["./src/registries/Items"], "@items": ["./src/registries/Items"],
"@world": ["./src/World"],
"@ui": ["./src/ui/UI"], "@ui": ["./src/ui/UI"],
"@game": ["./src/Game"] "@game": ["./src/Game"]
}, },

861
yarn.lock

File diff suppressed because it is too large Load Diff