import EventEmitter from "eventemitter3" import type { GameEvent } from "../shared/gameEvents" import type { Interaction, InteractionQueueItem } from "../shared/script/types" import { script } from "../shared/script" import { findMatchingCombination, getInteractionQueueItemId } from "../shared/util" interface Events { "game-event": [GameEvent] } export class Game extends EventEmitter { private currentRoomId: string = script.roomsById.values().next()!.value!.id private interactionQueue: Map = new Map() private visibleObjectIds = new Set() constructor() { super() this.switchRoom(this.currentRoomId) } getInitialStateEvents(): GameEvent[] { const events: GameEvent[] = [] events.push({ type: "room-changed", roomId: this.currentRoomId }) this.interactionQueue.forEach(item => events.push({ type: "interaction-queued", item })) script.roomsById.get(this.currentRoomId)!.initialObjects.forEach(o => { if (!this.visibleObjectIds.has(o.id)) events.push({ type: "object-visibility-changed", id: o.id, isVisible: false }) }) script.roomsById.get(this.currentRoomId)!.hiddenObjects.forEach(o => { if (this.visibleObjectIds.has(o.id)) events.push({ type: "object-visibility-changed", id: o.id, isVisible: true }) }) return events } addInteractionVote(interaction: Interaction) { const id = getInteractionQueueItemId(interaction) const existingItem = this.interactionQueue.get(id) if (existingItem === undefined) { const item = { id, votes: 1, interaction } this.interactionQueue.set(item.id, item) this.emit("game-event", { type: "interaction-queued", item }) } else { existingItem.votes += 1 this.emit("game-event", { type: "interaction-votes-changed", id: existingItem.id, votes: existingItem.votes }) } } removeInteractionVote(id: string) { const item = this.interactionQueue.get(id) if (item !== undefined) { item.votes -= 1 this.emit("game-event", { type: "interaction-votes-changed", id: item.id, votes: item.votes }) if (item.votes <= 0) this.interactionQueue.delete(id) } } switchRoom(roomId: string) { this.currentRoomId = roomId this.interactionQueue.clear() this.visibleObjectIds.clear() script.roomsById.get(this.currentRoomId)!.initialObjects.forEach(o => this.visibleObjectIds.add(o.id)) this.emit("game-event", { type: "room-changed", roomId }) } activateInteractionQueueItem(id: string) { const item = this.interactionQueue.get(id) if (item === undefined) return this.interactionQueue.delete(id) this.emit("game-event", { type: "interaction-votes-changed", id, votes: 0 }) switch (item.interaction.type) { case "use": this.setObjectVisibility(item.interaction.objectId, false) break case "combine": const matchingCombination = findMatchingCombination(script.roomsById.get(this.currentRoomId)!.combinations, item.interaction.objectIds) if (matchingCombination !== undefined) { matchingCombination.inputs.forEach(input => { if (input.isConsumed) this.setObjectVisibility(input.objectId, false) }) matchingCombination.outputIds.forEach(outputId => { this.setObjectVisibility(outputId, true) }) } break } } removeInteractionQueueItem(id: string) { if (!this.interactionQueue.has(id)) return this.emit("game-event", { type: "interaction-votes-changed", id, votes: 0 }) this.interactionQueue.delete(id) } setObjectVisibility(id: string, isVisible: boolean) { if (isVisible) this.visibleObjectIds.add(id) else this.visibleObjectIds.delete(id) this.emit("game-event", { type: "object-visibility-changed", id, isVisible }) } } export const game = new Game()