level-up/backend/game.ts
Moritz Ruth 88f0632194
All checks were successful
Build / build (push) Successful in 1m14s
Update dependencies, containerize, add build workflow
2025-03-03 00:35:21 +01:00

115 lines
No EOL
4.2 KiB
TypeScript

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<Events> {
private currentRoomId: string = script.roomsById.values().next()!.value!.id
private interactionQueue: Map<string, InteractionQueueItem> = new Map()
private visibleObjectIds = new Set<string>()
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()