diff --git a/package.json b/package.json index faa6fd5..97cfaa8 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "bonjour": "^3.5.0", "chalk": "^4.1.1", "faker": "^5.5.3", - "frigid": "^1.3.6", + "frigid": "^1.3.8", "get-port": "^5.1.1", "logger": "^0.0.1", "neo-blessed": "^0.2.0", diff --git a/src/GiftPopup.ts b/src/GiftPopup.ts new file mode 100644 index 0000000..70b21b1 --- /dev/null +++ b/src/GiftPopup.ts @@ -0,0 +1,84 @@ +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 { boxStyle, screen } from './UI.js'; + +export class GiftPopup { + box; + + selected = 0; + player: Player; + + pawns = new Map(); + + constructor(player: Player) { + this.player = player; + this.box = blessed.box({ + top: 0, + left: 'center', + width: 'shrink', + height: 'shrink', + tags: true, + ...boxStyle(), + }); + this.box.on('keypress', (evt, key) => { + if(key.full === 'enter') { + this.send(); + } 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(); + for(const pawn of Game.current.pawns) this.pawns.set(pawn, 0); + screen.append(this.box); + this.box.focus(); + Game.current.clock.pause(); + } + + send() { + const stuffToSend: (Pawn | ItemState)[] = []; + for(const [pawn, qty] of this.pawns) { + if(qty === 0) continue; + stuffToSend.push(pawn); + pawn.stopWorking(); + // Game.current.removePawn + } + this.player.send(stuffToSend).then(_ => { + + }).catch(_ => { + + }); + } + + render() { + let i = 0; + this.box.setContent(`${(() => { + let pawns = []; + for (const [pawn, qty] of this.pawns.entries()) { + const style = i === this.selected ? chalk.underline : _ => _; + if(qty > 0) { + pawns.push(style(`{|}${pawn.toString()} `)) + } else { + pawns.push(style(` ${pawn.toString()}{|}`)) + } + // pawns[pawns.length - 1] = chalk.underline(pawns[pawns.length - 1]) + i ++; + } + return pawns.join('\n') + })()}\n\n{|}${chalk.green('escape')}: Cancel \n{|}${chalk.green('enter')}: Okay `); + screen.render(); + } +} \ No newline at end of file diff --git a/src/Menu.ts b/src/Menu.ts index 3bb591b..0dcb0b0 100644 --- a/src/Menu.ts +++ b/src/Menu.ts @@ -9,6 +9,7 @@ import { progressbar } from './Progressbar.js'; import { inspect } from 'util'; import { Popup } from './Popup.js'; import mdns from './mDNS.js'; +import { GiftPopup } from './GiftPopup.js'; enum SubMenu { NONE = 'NONE', @@ -57,7 +58,8 @@ export class Menu implements Renderable { if(this.view === View.MULTIPLAYER) { if (key.full === 'enter') { - mdns.players[this.multiplayerSelected].sendItem(null); + new GiftPopup(mdns.players[this.multiplayerSelected]); + // mdns.players[this.multiplayerSelected].sendItem(null); } else if (key.full === 'up') { this.multiplayerSelected --; } else if (key.full === 'down') { @@ -168,8 +170,8 @@ export class Menu implements Renderable { renderMultiplayer() { if(mdns.players.length === 0) return `{center}${tags.bright}${tags.black.fg}No friends online{/center}`; return mdns.players.map((player, i) => { - if(i === this.multiplayerSelected) return '> ' + player.toString(); - else return player.toString(); + if(i === this.multiplayerSelected) return ' ❯ ' + player.toString(); + else return ' ' + chalk.bold.black(player.toString()); }).join('\n'); } diff --git a/src/mDNS.ts b/src/mDNS.ts index 986a0c1..8f62d7d 100644 --- a/src/mDNS.ts +++ b/src/mDNS.ts @@ -9,33 +9,41 @@ import { Item, ItemState } from './Item.js'; import WebSocket from 'ws'; import { Popup } from './Popup.js'; import { inspect } from 'util' +import { Pawn } from './Pawn.js'; +import { Game } from './Game.js'; const mdns = bonjour(); const ID = uuid.v4(); let devices: Player[] = []; -class Player { +export class Player { name: string; host: string; port: number; toString() { - return ` ${this.name} ${chalk.bold.black(`${this.host}:${this.port}`)}`; + return this.name; } - sendItem(item: ItemState) { + send(items: (ItemState | Pawn)[]) { return new Promise((res, rej) => { - const log = new ItemState(Item.LOG, 1, {}); - const json = log.toJson(); + 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}`); - // new Popup(`opening ws://${this.host}:${this.port}`); socket.on('open', () => { - socket.send(json); + socket.send(JSON.stringify(gift)); socket.close(); res(undefined); }); socket.on('error', () => { - rej(log); + rej(items); }); }); } @@ -47,6 +55,11 @@ const network = { } } +export type GiftMessage = { + pawns: string[], + from: string +} + export default network; export async function ready(name, onThing?) { @@ -59,7 +72,18 @@ export async function ready(name, onThing?) { const wss = new WebSocket.Server({ port }); wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { - new Popup(inspect(message)); + const {pawns: pawnJsons, from} = JSON.parse(message); + const pawns = []; + for(const pawnJson of pawnJsons) { + const pawn = Pawn.fromJson(pawnJson); + pawns.push(pawn); + } + new Popup(`${(() => { + if(pawns.length === 0) return `A care package has arrived from ${from}.`; + if(pawns.length === 1) return `A traveler from ${from} named ${pawns[0].toString()} has arrived.`; + if(pawns.length > 1) return `A caravan of ${pawns.length} people from ${from} has arrived.` + })()}`); + for(const pawn of pawns) Game.current.pawns.push(pawn); }); }); } diff --git a/yarn.lock b/yarn.lock index 5fb6ab5..b6e9099 100644 --- a/yarn.lock +++ b/yarn.lock @@ -113,9 +113,10 @@ faker@^5.5.3: version "5.5.3" resolved "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz" -frigid@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/frigid/-/frigid-1.3.6.tgz#45cc8a9ae855263c1a7255c5ccc500ba17097634" +frigid@^1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/frigid/-/frigid-1.3.8.tgz#a16919821e5426344bc98d301099f7631d2bae8a" + integrity sha512-i3HgB/5hQsALyumWoRlBvEpAXfTmM3Xw+Ica6E9mTASUVYtqZQ8mzUX8/3zscTUM4bCKhSa7MSvXl9L7pt5ICg== function-bind@^1.1.1: version "1.1.1"