diff --git a/src/Memory.ts b/src/Memory.ts index 84b7c4c..75e6095 100644 --- a/src/Memory.ts +++ b/src/Memory.ts @@ -1,9 +1,11 @@ +import Time from "./Time"; + export type Memory = TravelMemory | BirthMemory; type ProtoMemory = { type: string, time: { - stamp: number, + age: number, locale: string } } @@ -20,7 +22,9 @@ export type BirthMemory = ProtoMemory & { export function stringify(memory: Memory): string { switch(memory.type) { - case "birth": return `I was born at ${memory.time.locale} in ${memory.location}`; + case "birth": { + return `I was born at ${memory.time.locale} in ${memory.location}`; + } case "travel": return `I traveled to ${memory.location}.`; } } \ No newline at end of file diff --git a/src/Pawn.ts b/src/Pawn.ts index 77bc970..85f6b35 100644 --- a/src/Pawn.ts +++ b/src/Pawn.ts @@ -3,7 +3,7 @@ import faker from 'faker'; import chalk from 'chalk'; import log from './log.js'; import { Task } from './tasks/Task.js'; -import { Tickable } from './Time.js'; +import Time, { Tickable } from './Time.js'; import { ChopTreeTask } from './tasks/ChopTreeTask.js'; import { Game } from './Game.js'; import { render } from './ui/UI.js'; @@ -94,13 +94,13 @@ export class Pawn extends Serializable implements Tickable { this.energy ??= 100; this.memories ??= []; if(!this.age) { - this.age = 0; + this.age = Math.floor(525600 * (16 + Math.random() * 9)); this.memories.push({ type: "birth", location: Game.current.name, time: { - stamp: Game.current.clock.stamp, - locale: Game.current.clock.toString() + age: 0, + locale: new Time(Game.current.clock.stamp - this.age).toString() } }) } diff --git a/src/Time.ts b/src/Time.ts index c68696d..3e6e664 100644 --- a/src/Time.ts +++ b/src/Time.ts @@ -30,18 +30,42 @@ export default class Time extends Serializable implements Renderable{ hour: number; minute: number; + constructor(timestamp: number = 0) { + super(); + this.minute = timestamp; + this.normalize(); + } + + asAge() { + if(this.year > 1) { + return this.year + ' years old'; + } else { + if(this.month > 2) { + return this.month + ' months old'; + } else { + if(this.day > 1) { + return this.day + ' days old'; + } else if(this.day === 1) { + return '1 day old'; + } else { + return 'newborn'; + } + } + } + } + render() { const sym = (this.hour >= 6 && this.hour < 20) ? chalk.yellowBright('☼') : chalk.blue('☾') - return `${sym} ${this.hour.toString().padStart(2, ' ')}:${this.minute.toString().padStart(2, '0')} ${months[this.month]} ${this.day + 1}, ${(this.year + 1).toString().padStart(4, '0')}` + return `${sym} ${this.hour.toString().padStart(2, ' ')}:${this.minute.toString().padStart(2, '0')} ${months[this.month]} ${this.day + 1}, ${this.normalizedYear}` // return '☾' || '☼'; } toString() { - return `${this.hour}:${this.minute} ${months[this.month]} ${this.day + 1}, ${(this.year + 1).toString().padStart(4, '0')}` + return `${this.hour}:${this.minute.toString().padStart(2, '0')} ${months[this.month]} ${this.day + 1}, ${this.normalizedYear}` } ctor() { @@ -89,22 +113,55 @@ export default class Time extends Serializable implements Renderable{ advanceTime(minutes) { this.minute ++; + this.normalize() + } + + get normalizedYear() { + if(this.year >= 0) { + return (this.year + 1).toString().padStart(4, '0') + ' CE'; + } else { + return Math.abs(this.year).toString().padStart(4, '0') + ' BCE'; + } + } + + normalize() { while(this.minute >= 60) { this.minute -= 60; this.hour ++; } + while(this.minute < 0) { + this.minute += 60; + this.hour --; + } + while(this.hour >= 24) { this.hour -= 24; this.day ++; } - while(this.day >= daysInMonth[this.month]) { - this.day -= daysInMonth[this.month]; + while(this.hour < 0) { + this.hour += 24; + this.day --; + } + + while(this.day < 0) { + this.day += daysInMonth[ + ((this.month % months.length) + months.length) % months.length + ]; + this.month --; + } + while(this.day >= daysInMonth[this.month % months.length]) { + this.day -= daysInMonth[this.month % months.length]; this.month ++; } + while(this.month >= 12) { this.month -= 12; this.year ++; } + while(this.month < 0) { + this.month += 12; + this.year --; + } } async doTick() { diff --git a/src/multiplayer/mDNS.ts b/src/multiplayer/mDNS.ts index 27e4ea8..21a6323 100644 --- a/src/multiplayer/mDNS.ts +++ b/src/multiplayer/mDNS.ts @@ -43,7 +43,15 @@ export async function ready(name, onThing?) { const {pawns: pawnJsons, from} = JSON.parse(message); const pawns = []; for(const pawnJson of pawnJsons) { - const pawn = Pawn.fromJson(pawnJson); + const pawn: Pawn = Pawn.fromJson(pawnJson); + pawn.memories.push({ + type: "travel", + time: { + age: pawn.age, + locale: Game.current.clock.toString() + }, + location: Game.current.name + }) pawns.push(pawn); } new Popup(`${(() => { diff --git a/src/ui/PawnDetails.ts b/src/ui/PawnDetails.ts index 3a56a7b..9f21e6a 100644 --- a/src/ui/PawnDetails.ts +++ b/src/ui/PawnDetails.ts @@ -3,6 +3,7 @@ import blessed from 'neo-blessed'; import { Game } from '../Game.js'; import { stringify } from '../Memory.js'; import { Pawn } from '../Pawn.js'; +import Time from '../Time.js'; import { boxStyle, screen } from './UI.js'; export class PawnDetails { @@ -45,8 +46,8 @@ export class PawnDetails { this.box.setContent(`${ this.pawn.toString() }{|}${ - (this.pawn.sex ? "male" : "female") + - ', ' + this.pawn.age + (this.pawn.sex ? "female" : "male") + + ', ' + new Time(this.pawn.age).asAge() }\n${(() => { return this.pawn.memories.map(memory => stringify(memory)).join('\n') })()}\n\n{|}${