2021-06-15 19:15:49 -04:00
|
|
|
import chalk from "chalk";
|
2021-06-14 22:03:55 -04:00
|
|
|
import { Serializable } from "frigid";
|
2021-06-22 19:25:41 -04:00
|
|
|
import { getTheme } from "./registries/Themes.js";
|
2021-06-16 15:26:42 -04:00
|
|
|
import { Renderable } from "./ui/UI.js";
|
2021-06-14 22:03:55 -04:00
|
|
|
|
2021-06-19 12:40:01 -04:00
|
|
|
type AbbreviatedMonthName = string;
|
|
|
|
|
|
2021-06-14 22:03:55 -04:00
|
|
|
const daysInMonth = [
|
2021-06-19 12:40:01 -04:00
|
|
|
31, 28, 31,
|
|
|
|
|
30, 31, 30,
|
|
|
|
|
31, 31, 30,
|
|
|
|
|
31, 30, 31
|
2021-06-14 22:03:55 -04:00
|
|
|
];
|
|
|
|
|
|
2021-06-19 12:40:01 -04:00
|
|
|
const months: AbbreviatedMonthName[] = [
|
|
|
|
|
'Jan', 'Feb', 'Mar',
|
|
|
|
|
'Apr', 'May', 'Jun',
|
|
|
|
|
'Jul', 'Aug', 'Sep',
|
|
|
|
|
'Oct', 'Nov', 'Dec'
|
2021-06-14 22:03:55 -04:00
|
|
|
]
|
|
|
|
|
|
2021-06-18 02:02:50 -04:00
|
|
|
export default class Time extends Serializable implements Renderable {
|
2021-06-19 12:40:01 -04:00
|
|
|
rate: number;
|
|
|
|
|
paused = true;
|
|
|
|
|
|
|
|
|
|
thing: Tickable;
|
|
|
|
|
|
|
|
|
|
year: number;
|
|
|
|
|
month: number;
|
|
|
|
|
day: number;
|
|
|
|
|
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) ?
|
2021-06-19 18:23:44 -04:00
|
|
|
chalk.ansi256(226).bgAnsi256(27)(' ☼ ') :
|
2021-06-19 12:40:01 -04:00
|
|
|
chalk.ansi256(254).bgAnsi256(17)(' ☾ ')
|
|
|
|
|
|
|
|
|
|
return `${sym} ${
|
|
|
|
|
getTheme().normal(`${
|
2021-06-22 19:25:41 -04:00
|
|
|
this.toString()
|
2021-06-19 12:40:01 -04:00
|
|
|
}`)
|
|
|
|
|
}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toString() {
|
2021-06-22 19:25:41 -04:00
|
|
|
return `${this.hour}:${Math.floor(this.minute).toString().padStart(2, '0')} ${months[this.month]} ${this.day + 1}, ${this.normalizedYear}`
|
2021-06-19 12:40:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctor() {
|
|
|
|
|
this.rate = 60;
|
|
|
|
|
this.minute ??= 0;
|
|
|
|
|
this.hour ??= 0;
|
|
|
|
|
this.day ??= 0;
|
|
|
|
|
this.month ??= 0;
|
|
|
|
|
this.year ??= 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 19:25:41 -04:00
|
|
|
get second() {
|
|
|
|
|
return Math.floor((this.minute % 1) * 60)
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:40:01 -04:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start() {
|
|
|
|
|
this.paused = false;
|
|
|
|
|
setTimeout(this.doTick.bind(this), 0);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 19:25:41 -04:00
|
|
|
advanceTime(seconds) {
|
|
|
|
|
this.minute += seconds / 60;
|
2021-06-19 12:40:01 -04:00
|
|
|
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';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 19:25:41 -04:00
|
|
|
|
|
|
|
|
|
2021-06-19 12:40:01 -04:00
|
|
|
normalize() {
|
2021-06-22 19:25:41 -04:00
|
|
|
// while(t)
|
2021-06-19 12:40:01 -04:00
|
|
|
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.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() {
|
|
|
|
|
this.advanceTime(1);
|
|
|
|
|
const timeout = 1000 / this.rate;
|
|
|
|
|
const start = new Date().getTime();
|
|
|
|
|
if(this.thing) {
|
|
|
|
|
await this.thing.tick();
|
|
|
|
|
}
|
|
|
|
|
const elapsed = new Date().getTime() - start;
|
|
|
|
|
const wait = Math.max(timeout - elapsed, 0);
|
|
|
|
|
if(this.paused) return;
|
|
|
|
|
setTimeout(this.doTick.bind(this), wait)
|
|
|
|
|
}
|
2021-06-14 22:03:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export interface Tickable {
|
2021-06-19 12:40:01 -04:00
|
|
|
tick: () => Promise<void>
|
2021-06-14 22:03:55 -04:00
|
|
|
}
|