pawns have age & birth memories
parent
4bb2b252db
commit
11965be438
10
src/Game.ts
10
src/Game.ts
|
|
@ -3,13 +3,13 @@ import { DEBUG } from 'frigid/out/Serializable.js';
|
||||||
import { Pawn } from './Pawn.js';
|
import { Pawn } from './Pawn.js';
|
||||||
import { TaskList } from './TaskList.js';
|
import { TaskList } from './TaskList.js';
|
||||||
import { Inventory } from './Inventory.js';
|
import { Inventory } from './Inventory.js';
|
||||||
import { Menu } from './Menu.js';
|
import { Menu } from './ui/Menu.js';
|
||||||
import Time, { Tickable } from './Time.js';
|
import Time, { Tickable } from './Time.js';
|
||||||
import { render, Renderable, setTitle } from './UI.js';
|
import { render, Renderable, setTitle } from './ui/UI.js';
|
||||||
import log from './log.js';
|
import log from './log.js';
|
||||||
import { ChopTreeTask } from './ChopTreeTask.js';
|
import { ChopTreeTask } from './tasks/ChopTreeTask.js';
|
||||||
import { Task } from './Task.js';
|
import { Task } from './tasks/Task.js';
|
||||||
import { ready } from './mDNS.js';
|
import { ready } from './multiplayer/mDNS.js';
|
||||||
import faker from 'faker';
|
import faker from 'faker';
|
||||||
|
|
||||||
let game = null;
|
let game = null;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Serializable } from 'frigid';
|
import { Serializable } from 'frigid';
|
||||||
import { Game } from './Game.js';
|
import { Game } from './Game.js';
|
||||||
import { Item, ItemState } from './Item.js';
|
import { Item, ItemState } from './Item.js';
|
||||||
import { Renderable } from './UI.js';
|
import { Renderable } from './ui/UI.js';
|
||||||
|
|
||||||
export class Inventory extends Serializable implements Renderable {
|
export class Inventory extends Serializable implements Renderable {
|
||||||
items: ItemState[];
|
items: ItemState[];
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Serializable } from 'frigid';
|
import { Serializable } from 'frigid';
|
||||||
import { Renderable } from './UI';
|
import { Renderable } from './ui/UI';
|
||||||
|
|
||||||
export type ItemID = string;
|
export type ItemID = string;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
export type Memory = TravelMemory | BirthMemory;
|
||||||
|
|
||||||
|
type ProtoMemory = {
|
||||||
|
type: string,
|
||||||
|
time: {
|
||||||
|
stamp: number,
|
||||||
|
locale: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TravelMemory = ProtoMemory & {
|
||||||
|
type: "travel",
|
||||||
|
location: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BirthMemory = ProtoMemory & {
|
||||||
|
type: "birth",
|
||||||
|
location: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringify(memory: Memory): string {
|
||||||
|
switch(memory.type) {
|
||||||
|
case "birth": return `I was born at ${memory.time.locale} in ${memory.location}`;
|
||||||
|
case "travel": return `I traveled to ${memory.location}.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/Pawn.ts
25
src/Pawn.ts
|
|
@ -2,11 +2,12 @@ import { Serializable } from 'frigid';
|
||||||
import faker from 'faker';
|
import faker from 'faker';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import log from './log.js';
|
import log from './log.js';
|
||||||
import { Task } from './Task.js';
|
import { Task } from './tasks/Task.js';
|
||||||
import { Tickable } from './Time.js';
|
import { Tickable } from './Time.js';
|
||||||
import { ChopTreeTask } from './ChopTreeTask.js';
|
import { ChopTreeTask } from './tasks/ChopTreeTask.js';
|
||||||
import { Game } from './Game.js';
|
import { Game } from './Game.js';
|
||||||
import { render } from './UI.js';
|
import { render } from './ui/UI.js';
|
||||||
|
import { Memory } from './Memory.js';
|
||||||
|
|
||||||
const LABORS = {
|
const LABORS = {
|
||||||
CUT_TREE: Symbol('CUT_TREE'),
|
CUT_TREE: Symbol('CUT_TREE'),
|
||||||
|
|
@ -38,7 +39,11 @@ export class Pawn extends Serializable implements Tickable {
|
||||||
|
|
||||||
age: number;
|
age: number;
|
||||||
|
|
||||||
|
memories: Memory[];
|
||||||
|
|
||||||
async tick() {
|
async tick() {
|
||||||
|
this.age ++;
|
||||||
|
|
||||||
this.energy -= energyScale;
|
this.energy -= energyScale;
|
||||||
|
|
||||||
if(this.awake === false) {
|
if(this.awake === false) {
|
||||||
|
|
@ -87,6 +92,20 @@ export class Pawn extends Serializable implements Tickable {
|
||||||
}
|
}
|
||||||
this.awake ??= true;
|
this.awake ??= true;
|
||||||
this.energy ??= 100;
|
this.energy ??= 100;
|
||||||
|
this.memories ??= [];
|
||||||
|
if(!this.age) {
|
||||||
|
this.age = 0;
|
||||||
|
this.memories.push({
|
||||||
|
type: "birth",
|
||||||
|
location: Game.current.name,
|
||||||
|
time: {
|
||||||
|
stamp: Game.current.clock.stamp,
|
||||||
|
locale: Game.current.clock.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(this.job?.completed) {
|
if(this.job?.completed) {
|
||||||
this.stopWorking();
|
this.stopWorking();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Serializable } from 'frigid';
|
import { Serializable } from 'frigid';
|
||||||
import { ChopTreeTask } from "./ChopTreeTask.js";
|
import { ChopTreeTask } from "./tasks/ChopTreeTask.js";
|
||||||
import { Game } from './Game.js';
|
import { Game } from './Game.js';
|
||||||
import { Task } from "./Task.js";
|
import { Task } from "./tasks/Task.js";
|
||||||
import { render, Renderable, tasksPanel } from './UI.js';
|
import { render, Renderable, tasksPanel } from './ui/UI.js';
|
||||||
|
|
||||||
export class TaskList extends Serializable implements Renderable {
|
export class TaskList extends Serializable implements Renderable {
|
||||||
tasks: Task[] = [];
|
tasks: Task[] = [];
|
||||||
|
|
|
||||||
34
src/Time.ts
34
src/Time.ts
|
|
@ -2,6 +2,7 @@ import chalk from "chalk";
|
||||||
import { Serializable } from "frigid";
|
import { Serializable } from "frigid";
|
||||||
import { isThisTypeNode } from "typescript";
|
import { isThisTypeNode } from "typescript";
|
||||||
import log from "./log.js";
|
import log from "./log.js";
|
||||||
|
import { Renderable } from "./ui/UI.js";
|
||||||
|
|
||||||
const daysInMonth = [
|
const daysInMonth = [
|
||||||
31, 28, 31,
|
31, 28, 31,
|
||||||
|
|
@ -17,7 +18,7 @@ const months = [
|
||||||
'Oct', 'Nov', 'Dec'
|
'Oct', 'Nov', 'Dec'
|
||||||
]
|
]
|
||||||
|
|
||||||
export default class Time extends Serializable{
|
export default class Time extends Serializable implements Renderable{
|
||||||
rate: number;
|
rate: number;
|
||||||
paused = true;
|
paused = true;
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ export default class Time extends Serializable{
|
||||||
hour: number;
|
hour: number;
|
||||||
minute: number;
|
minute: number;
|
||||||
|
|
||||||
toString() {
|
render() {
|
||||||
const sym = (this.hour >= 6 && this.hour < 20) ?
|
const sym = (this.hour >= 6 && this.hour < 20) ?
|
||||||
chalk.yellowBright('☼') :
|
chalk.yellowBright('☼') :
|
||||||
chalk.blue('☾')
|
chalk.blue('☾')
|
||||||
|
|
@ -39,6 +40,10 @@ export default class Time extends Serializable{
|
||||||
// return '☾' || '☼';
|
// return '☾' || '☼';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `${this.hour}:${this.minute} ${months[this.month]} ${this.day + 1}, ${(this.year + 1).toString().padStart(4, '0')}`
|
||||||
|
}
|
||||||
|
|
||||||
ctor() {
|
ctor() {
|
||||||
this.rate = 60;
|
this.rate = 60;
|
||||||
this.minute ??= 0;
|
this.minute ??= 0;
|
||||||
|
|
@ -48,6 +53,31 @@ export default class Time extends Serializable{
|
||||||
this.year ??= 0;
|
this.year ??= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get stamp() {
|
||||||
|
let minute = this.minute;
|
||||||
|
let hour = this.hour;
|
||||||
|
let day = this.day;
|
||||||
|
let month = this.month;
|
||||||
|
let year = this.year;
|
||||||
|
|
||||||
|
const daysInYear = daysInMonth.reduce((a, b) => a+b, 0);
|
||||||
|
|
||||||
|
day += daysInYear * year;
|
||||||
|
year = 0;
|
||||||
|
while(month > 0) {
|
||||||
|
day += daysInMonth[month];
|
||||||
|
month --;
|
||||||
|
}
|
||||||
|
|
||||||
|
hour += day * 24;
|
||||||
|
day = 0;
|
||||||
|
|
||||||
|
minute += hour * 60;
|
||||||
|
hour = 0;
|
||||||
|
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
this.paused = true;
|
this.paused = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Serializable } from "frigid";
|
||||||
|
|
||||||
|
export class World extends Serializable {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Game } from './Game.js';
|
import { Game } from './Game.js';
|
||||||
import { render } from './UI.js';
|
import { render } from './ui/UI.js';
|
||||||
|
|
||||||
const saveFile = process.argv[2];
|
const saveFile = process.argv[2];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { ItemState } from '../Item.js';
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
import { Pawn } from '../Pawn.js';
|
||||||
|
import { Game } from '../Game.js';
|
||||||
|
import { GiftMessage } from './mDNS';
|
||||||
|
|
||||||
|
|
||||||
|
export class Player {
|
||||||
|
name: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(items: (ItemState | Pawn)[]) {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
const pawnJsons: string[] = [];
|
||||||
|
for (const item of items) {
|
||||||
|
Game.current.removePawn(item as Pawn);
|
||||||
|
pawnJsons.push(item.toJson());
|
||||||
|
}
|
||||||
|
const gift: GiftMessage = {
|
||||||
|
pawns: pawnJsons,
|
||||||
|
from: Game.current.name
|
||||||
|
};
|
||||||
|
const socket = new WebSocket(`ws://${this.host}:${this.port}`);
|
||||||
|
socket.on('open', () => {
|
||||||
|
socket.send(JSON.stringify(gift));
|
||||||
|
socket.close();
|
||||||
|
res(undefined);
|
||||||
|
});
|
||||||
|
socket.on('error', () => {
|
||||||
|
rej(items);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,54 +1,22 @@
|
||||||
import bonjour from 'bonjour';
|
import bonjour from 'bonjour';
|
||||||
import log from './log.js';
|
import log from '../log.js';
|
||||||
import getPort from 'get-port';
|
import getPort from 'get-port';
|
||||||
import os from 'os'
|
import os from 'os'
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
import faker from 'faker';
|
import faker from 'faker';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { Item, ItemState } from './Item.js';
|
import { Item } from '../Item.js';
|
||||||
import WebSocket from 'ws';
|
import WebSocket from 'ws';
|
||||||
import { Popup } from './Popup.js';
|
import { Popup } from '../ui/Popup.js';
|
||||||
import { inspect } from 'util'
|
import { inspect } from 'util'
|
||||||
import { Pawn } from './Pawn.js';
|
import { Pawn } from '../Pawn.js';
|
||||||
import { Game } from './Game.js';
|
import { Game } from '../Game.js';
|
||||||
|
import { Player } from './Player.js';
|
||||||
|
|
||||||
const mdns = bonjour();
|
const mdns = bonjour();
|
||||||
const ID = uuid.v4();
|
const ID = uuid.v4();
|
||||||
let devices: Player[] = [];
|
let devices: Player[] = [];
|
||||||
|
|
||||||
export class Player {
|
|
||||||
name: string;
|
|
||||||
host: string;
|
|
||||||
port: number;
|
|
||||||
|
|
||||||
toString() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
send(items: (ItemState | Pawn)[]) {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
const pawnJsons: string[] = [];
|
|
||||||
for(const item of items) {
|
|
||||||
Game.current.removePawn(item as Pawn);
|
|
||||||
pawnJsons.push(item.toJson());
|
|
||||||
}
|
|
||||||
const gift: GiftMessage = {
|
|
||||||
pawns: pawnJsons,
|
|
||||||
from: Game.current.name
|
|
||||||
};
|
|
||||||
const socket = new WebSocket(`ws://${this.host}:${this.port}`);
|
|
||||||
socket.on('open', () => {
|
|
||||||
socket.send(JSON.stringify(gift));
|
|
||||||
socket.close();
|
|
||||||
res(undefined);
|
|
||||||
});
|
|
||||||
socket.on('error', () => {
|
|
||||||
rej(items);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const network = {
|
const network = {
|
||||||
get players() {
|
get players() {
|
||||||
return devices;
|
return devices;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { Game } from './Game.js';
|
import { Game } from '../Game.js';
|
||||||
import { Item } from './Item.js';
|
import { Item } from '../Item.js';
|
||||||
import { Pawn } from './Pawn.js';
|
import { Pawn } from '../Pawn.js';
|
||||||
import { Task } from './Task.js';
|
import { Task } from './Task.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { Serializable } from 'frigid';
|
import { Serializable } from 'frigid';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { Pawn } from './Pawn.js';
|
import { Pawn } from '../Pawn.js';
|
||||||
import { render, tasksPanel } from './UI.js';
|
import { render, tasksPanel } from '../ui/UI.js';
|
||||||
import { Game } from './Game.js';
|
import { Game } from '../Game.js';
|
||||||
import { progressbar, ProgressbarStyle } from './Progressbar.js';
|
import { progressbar, ProgressbarStyle } from '../Progressbar.js';
|
||||||
|
|
||||||
export class Task extends Serializable {
|
export class Task extends Serializable {
|
||||||
work = 0;
|
work = 0;
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import blessed from 'neo-blessed';
|
import blessed from 'neo-blessed';
|
||||||
import { Game } from './Game.js';
|
import { Game } from '../Game.js';
|
||||||
import { ItemState } from './Item.js';
|
import { ItemState } from '../Item.js';
|
||||||
import { Player } from './mDNS.js';
|
import { Player } from "../multiplayer/Player";
|
||||||
import { Pawn } from './Pawn.js';
|
import { Pawn } from '../Pawn.js';
|
||||||
import { boxStyle, screen } from './UI.js';
|
import { boxStyle, screen } from './UI.js';
|
||||||
|
|
||||||
export class GiftPopup {
|
export class GiftPopup {
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
import { Pawn } from './Pawn.js';
|
import { Pawn } from '../Pawn.js';
|
||||||
import log from './log.js';
|
import log from '../log.js';
|
||||||
import { screen, menuPanel, render, tags, Renderable } from './UI.js';
|
import { menuPanel, tags, Renderable } from './UI.js';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { Game } from './Game.js';
|
import { Game } from '../Game.js';
|
||||||
import { Task } from './Task.js';
|
import { ChopTreeTask } from '../tasks/ChopTreeTask.js';
|
||||||
import { ChopTreeTask } from './ChopTreeTask.js';
|
import { progressbar } from '../Progressbar.js';
|
||||||
import { progressbar } from './Progressbar.js';
|
|
||||||
import { inspect } from 'util';
|
|
||||||
import { Popup } from './Popup.js';
|
import { Popup } from './Popup.js';
|
||||||
import mdns from './mDNS.js';
|
import mdns from '../multiplayer/mDNS.js';
|
||||||
import { GiftPopup } from './GiftPopup.js';
|
import { GiftPopup } from './GiftPopup.js';
|
||||||
|
import { PawnDetails } from './PawnDetails.js';
|
||||||
|
|
||||||
enum SubMenu {
|
enum SubMenu {
|
||||||
NONE = 'NONE',
|
NONE = 'NONE',
|
||||||
|
|
@ -53,6 +52,8 @@ export class Menu implements Renderable {
|
||||||
Game.current.advanceSelection(-1);
|
Game.current.advanceSelection(-1);
|
||||||
} else if (key.full === 'down') {
|
} else if (key.full === 'down') {
|
||||||
Game.current.advanceSelection(1);
|
Game.current.advanceSelection(1);
|
||||||
|
} else if (key.full === 'enter') {
|
||||||
|
new PawnDetails(Game.current.selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,7 +125,7 @@ export class Menu implements Renderable {
|
||||||
|
|
||||||
renderTopBar() {
|
renderTopBar() {
|
||||||
const idlers = Game.current.pawns.filter(pawn => pawn.idle);
|
const idlers = Game.current.pawns.filter(pawn => pawn.idle);
|
||||||
return ` ${Game.current.clock.toString()}{|}Idle: ${idlers.length} `;
|
return ` ${Game.current.clock.render()}{|}Idle: ${idlers.length} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPawns() {
|
renderPawns() {
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import blessed from 'neo-blessed';
|
||||||
|
import { Game } from '../Game.js';
|
||||||
|
import { stringify } from '../Memory.js';
|
||||||
|
import { Pawn } from '../Pawn.js';
|
||||||
|
import { boxStyle, screen } from './UI.js';
|
||||||
|
|
||||||
|
export class PawnDetails {
|
||||||
|
box;
|
||||||
|
pawn: Pawn;
|
||||||
|
|
||||||
|
constructor(pawn: Pawn) {
|
||||||
|
this.pawn = pawn;
|
||||||
|
this.box = blessed.box({
|
||||||
|
top: 0,
|
||||||
|
left: 'center',
|
||||||
|
width: 'shrink',
|
||||||
|
height: 'shrink',
|
||||||
|
tags: true,
|
||||||
|
...boxStyle(),
|
||||||
|
});
|
||||||
|
this.box.on('keypress', (evt, key) => {
|
||||||
|
if(key.full === 'escape' || key.full === 'enter') {
|
||||||
|
Game.current.clock.start();
|
||||||
|
screen.remove(this.box);
|
||||||
|
} else if (key.full === 'up') {
|
||||||
|
// this.selected --;
|
||||||
|
} else if (key.full === 'down') {
|
||||||
|
// this.selected ++;
|
||||||
|
} else if (key.full === 'right') {
|
||||||
|
// this.pawns.set(Game.current.pawns[this.selected], 1);
|
||||||
|
} else if (key.full === 'left') {
|
||||||
|
// this.pawns.set(Game.current.pawns[this.selected], 0);
|
||||||
|
}
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
this.render();
|
||||||
|
screen.append(this.box);
|
||||||
|
this.box.focus();
|
||||||
|
Game.current.clock.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let i = 0;
|
||||||
|
this.box.setContent(`${
|
||||||
|
this.pawn.toString()
|
||||||
|
}{|}${
|
||||||
|
(this.pawn.sex ? "male" : "female") +
|
||||||
|
', ' + this.pawn.age
|
||||||
|
}\n${(() => {
|
||||||
|
return this.pawn.memories.map(memory => stringify(memory)).join('\n')
|
||||||
|
})()}\n\n{|}${
|
||||||
|
chalk.green('escape')
|
||||||
|
}: Cancel \n{|}${
|
||||||
|
chalk.green('enter')
|
||||||
|
}: Okay `);
|
||||||
|
screen.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import blessed from 'neo-blessed';
|
import blessed from 'neo-blessed';
|
||||||
import { Game } from './Game.js';
|
import { Game } from '../Game.js';
|
||||||
import { boxStyle, screen } from './UI.js';
|
import { boxStyle, screen } from './UI.js';
|
||||||
|
|
||||||
export class Popup {
|
export class Popup {
|
||||||
|
|
@ -96,3 +96,11 @@ screen.key(['C-c'], function(ch, key) {
|
||||||
process.stdout.write(ansi.cursor.show);
|
process.stdout.write(ansi.cursor.show);
|
||||||
return process.exit(0);
|
return process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tasksPanel.key('f2', () => {
|
||||||
|
menuPanel.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
menuPanel.key('f1', () => {
|
||||||
|
tasksPanel.focus();
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue