pawns have age & birth memories

master
Valerie 2021-06-16 15:26:42 -04:00
parent 4bb2b252db
commit 11965be438
18 changed files with 231 additions and 76 deletions

View File

@ -3,13 +3,13 @@ import { DEBUG } from 'frigid/out/Serializable.js';
import { Pawn } from './Pawn.js';
import { TaskList } from './TaskList.js';
import { Inventory } from './Inventory.js';
import { Menu } from './Menu.js';
import { Menu } from './ui/Menu.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 { ChopTreeTask } from './ChopTreeTask.js';
import { Task } from './Task.js';
import { ready } from './mDNS.js';
import { ChopTreeTask } from './tasks/ChopTreeTask.js';
import { Task } from './tasks/Task.js';
import { ready } from './multiplayer/mDNS.js';
import faker from 'faker';
let game = null;

View File

@ -1,7 +1,7 @@
import { Serializable } from 'frigid';
import { Game } from './Game.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 {
items: ItemState[];

View File

@ -1,5 +1,5 @@
import { Serializable } from 'frigid';
import { Renderable } from './UI';
import { Renderable } from './ui/UI';
export type ItemID = string;

26
src/Memory.ts 100644
View File

@ -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}.`;
}
}

View File

@ -2,11 +2,12 @@ import { Serializable } from 'frigid';
import faker from 'faker';
import chalk from 'chalk';
import log from './log.js';
import { Task } from './Task.js';
import { Task } from './tasks/Task.js';
import { Tickable } from './Time.js';
import { ChopTreeTask } from './ChopTreeTask.js';
import { ChopTreeTask } from './tasks/ChopTreeTask.js';
import { Game } from './Game.js';
import { render } from './UI.js';
import { render } from './ui/UI.js';
import { Memory } from './Memory.js';
const LABORS = {
CUT_TREE: Symbol('CUT_TREE'),
@ -38,7 +39,11 @@ export class Pawn extends Serializable implements Tickable {
age: number;
memories: Memory[];
async tick() {
this.age ++;
this.energy -= energyScale;
if(this.awake === false) {
@ -87,6 +92,20 @@ export class Pawn extends Serializable implements Tickable {
}
this.awake ??= true;
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) {
this.stopWorking();
}

View File

@ -1,8 +1,8 @@
import { Serializable } from 'frigid';
import { ChopTreeTask } from "./ChopTreeTask.js";
import { ChopTreeTask } from "./tasks/ChopTreeTask.js";
import { Game } from './Game.js';
import { Task } from "./Task.js";
import { render, Renderable, tasksPanel } from './UI.js';
import { Task } from "./tasks/Task.js";
import { render, Renderable, tasksPanel } from './ui/UI.js';
export class TaskList extends Serializable implements Renderable {
tasks: Task[] = [];

View File

@ -2,6 +2,7 @@ import chalk from "chalk";
import { Serializable } from "frigid";
import { isThisTypeNode } from "typescript";
import log from "./log.js";
import { Renderable } from "./ui/UI.js";
const daysInMonth = [
31, 28, 31,
@ -17,7 +18,7 @@ const months = [
'Oct', 'Nov', 'Dec'
]
export default class Time extends Serializable{
export default class Time extends Serializable implements Renderable{
rate: number;
paused = true;
@ -29,7 +30,7 @@ export default class Time extends Serializable{
hour: number;
minute: number;
toString() {
render() {
const sym = (this.hour >= 6 && this.hour < 20) ?
chalk.yellowBright('☼') :
chalk.blue('☾')
@ -39,6 +40,10 @@ export default class Time extends Serializable{
// return '☾' || '☼';
}
toString() {
return `${this.hour}:${this.minute} ${months[this.month]} ${this.day + 1}, ${(this.year + 1).toString().padStart(4, '0')}`
}
ctor() {
this.rate = 60;
this.minute ??= 0;
@ -48,6 +53,31 @@ export default class Time extends Serializable{
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() {
this.paused = true;
}

5
src/World.ts 100644
View File

@ -0,0 +1,5 @@
import { Serializable } from "frigid";
export class World extends Serializable {
}

View File

@ -1,5 +1,5 @@
import { Game } from './Game.js';
import { render } from './UI.js';
import { render } from './ui/UI.js';
const saveFile = process.argv[2];

View File

@ -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);
});
});
}
}

View File

@ -1,54 +1,22 @@
import bonjour from 'bonjour';
import log from './log.js';
import log from '../log.js';
import getPort from 'get-port';
import os from 'os'
import * as uuid from 'uuid';
import faker from 'faker';
import chalk from 'chalk';
import { Item, ItemState } from './Item.js';
import { Item } from '../Item.js';
import WebSocket from 'ws';
import { Popup } from './Popup.js';
import { Popup } from '../ui/Popup.js';
import { inspect } from 'util'
import { Pawn } from './Pawn.js';
import { Game } from './Game.js';
import { Pawn } from '../Pawn.js';
import { Game } from '../Game.js';
import { Player } from './Player.js';
const mdns = bonjour();
const ID = uuid.v4();
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 = {
get players() {
return devices;

View File

@ -1,7 +1,7 @@
import chalk from 'chalk';
import { Game } from './Game.js';
import { Item } from './Item.js';
import { Pawn } from './Pawn.js';
import { Game } from '../Game.js';
import { Item } from '../Item.js';
import { Pawn } from '../Pawn.js';
import { Task } from './Task.js';

View File

@ -1,10 +1,10 @@
import { Serializable } from 'frigid';
import EventEmitter from 'events';
import chalk from 'chalk';
import { Pawn } from './Pawn.js';
import { render, tasksPanel } from './UI.js';
import { Game } from './Game.js';
import { progressbar, ProgressbarStyle } from './Progressbar.js';
import { Pawn } from '../Pawn.js';
import { render, tasksPanel } from '../ui/UI.js';
import { Game } from '../Game.js';
import { progressbar, ProgressbarStyle } from '../Progressbar.js';
export class Task extends Serializable {
work = 0;

View File

@ -1,9 +1,9 @@
import chalk from 'chalk';
import blessed from 'neo-blessed';
import { Game } from './Game.js';
import { ItemState } from './Item.js';
import { Player } from './mDNS.js';
import { Pawn } from './Pawn.js';
import { Game } from '../Game.js';
import { ItemState } from '../Item.js';
import { Player } from "../multiplayer/Player";
import { Pawn } from '../Pawn.js';
import { boxStyle, screen } from './UI.js';
export class GiftPopup {

View File

@ -1,15 +1,14 @@
import { Pawn } from './Pawn.js';
import log from './log.js';
import { screen, menuPanel, render, tags, Renderable } from './UI.js';
import { Pawn } from '../Pawn.js';
import log from '../log.js';
import { menuPanel, tags, Renderable } from './UI.js';
import chalk from 'chalk';
import { Game } from './Game.js';
import { Task } from './Task.js';
import { ChopTreeTask } from './ChopTreeTask.js';
import { progressbar } from './Progressbar.js';
import { inspect } from 'util';
import { Game } from '../Game.js';
import { ChopTreeTask } from '../tasks/ChopTreeTask.js';
import { progressbar } from '../Progressbar.js';
import { Popup } from './Popup.js';
import mdns from './mDNS.js';
import mdns from '../multiplayer/mDNS.js';
import { GiftPopup } from './GiftPopup.js';
import { PawnDetails } from './PawnDetails.js';
enum SubMenu {
NONE = 'NONE',
@ -53,6 +52,8 @@ export class Menu implements Renderable {
Game.current.advanceSelection(-1);
} else if (key.full === 'down') {
Game.current.advanceSelection(1);
} else if (key.full === 'enter') {
new PawnDetails(Game.current.selected);
}
}
@ -124,7 +125,7 @@ export class Menu implements Renderable {
renderTopBar() {
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() {

View File

@ -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();
}
}

View File

@ -1,6 +1,6 @@
import chalk from 'chalk';
import blessed from 'neo-blessed';
import { Game } from './Game.js';
import { Game } from '../Game.js';
import { boxStyle, screen } from './UI.js';
export class Popup {

View File

@ -95,4 +95,12 @@ process.stdout.write(ansi.cursor.hide);
screen.key(['C-c'], function(ch, key) {
process.stdout.write(ansi.cursor.show);
return process.exit(0);
});
tasksPanel.key('f2', () => {
menuPanel.focus();
});
menuPanel.key('f1', () => {
tasksPanel.focus();
});