This commit is contained in:
parent
dd5e018477
commit
3498bbb8ad
9 changed files with 45 additions and 4 deletions
|
@ -21,6 +21,8 @@ export class Game {
|
|||
private currentScene: CurrentScene
|
||||
public eventBus = new EventEmitter<Events>({ captureRejections: false })
|
||||
|
||||
private isVirtualCurtainOpen = false
|
||||
|
||||
constructor() {
|
||||
this.switchScene("pre-start")
|
||||
|
||||
|
@ -33,6 +35,7 @@ export class Game {
|
|||
const events: PlayerBroadcast[] = []
|
||||
events.push({ type: "scene-changed", sceneId: this.currentScene.id })
|
||||
events.push(...this.currentScene.state.getConnectionEvents().map((event: SceneEvent) => ({ type: "scene-event", event })))
|
||||
events.push({ type: "virtual-curtain-changed", isOpen: this.isVirtualCurtainOpen })
|
||||
|
||||
return events
|
||||
}
|
||||
|
@ -62,6 +65,12 @@ export class Game {
|
|||
return null
|
||||
}
|
||||
}
|
||||
|
||||
setVirtualCurtainOpen(isOpen: boolean) {
|
||||
if (this.isVirtualCurtainOpen === isOpen) return
|
||||
this.isVirtualCurtainOpen = isOpen
|
||||
this.eventBus.emit("player-broadcast", { type: "virtual-curtain-changed", isOpen: this.isVirtualCurtainOpen })
|
||||
}
|
||||
}
|
||||
|
||||
export const game = new Game()
|
|
@ -18,6 +18,14 @@ export const crewRouter = t.router({
|
|||
game.switchScene(input.sceneId)
|
||||
}),
|
||||
|
||||
setVirtualCurtainOpen: crewProcedure
|
||||
.input(z.object({
|
||||
isOpen: z.boolean()
|
||||
}))
|
||||
.mutation(async ({ input }) => {
|
||||
game.setVirtualCurtainOpen(input.isOpen)
|
||||
}),
|
||||
|
||||
interactionScene: t.router({
|
||||
setObjectVisibility: crewProcedure
|
||||
.input(z.object({
|
||||
|
|
|
@ -22,6 +22,8 @@ export const useGame = defineStore("gameState", () => {
|
|||
controller: markRaw(sceneTypesById.text.createController(script.scenesById.get("pre-start") as TextSceneDefinition))
|
||||
})
|
||||
|
||||
const isVirtualCurtainOpen = ref(false)
|
||||
|
||||
const isConnected = ref(false)
|
||||
const isCrew = window.localStorage.getItem("crew-token") !== null
|
||||
|
||||
|
@ -47,6 +49,10 @@ export const useGame = defineStore("gameState", () => {
|
|||
case "scene-event":
|
||||
currentScene.value.controller.handleEvent(broadcast.event)
|
||||
break
|
||||
|
||||
case "virtual-curtain-changed":
|
||||
isVirtualCurtainOpen.value = broadcast.isOpen
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +73,10 @@ export const useGame = defineStore("gameState", () => {
|
|||
isCrew,
|
||||
isConnected,
|
||||
currentScene,
|
||||
switchScene
|
||||
isVirtualCurtainOpen,
|
||||
switchScene,
|
||||
async setVirtualCurtainOpen(isOpen: boolean) {
|
||||
await trpcClient.crew.setVirtualCurtainOpen.mutate({ isOpen })
|
||||
}
|
||||
}
|
||||
})
|
|
@ -17,13 +17,14 @@
|
|||
/>
|
||||
</div>
|
||||
<transition-group tag="div" name="list" class="grid gap-3 grid-cols-2 flex-grow auto-rows-min p-4 pt-0 relative">
|
||||
<ObjectCard
|
||||
<PlayerObjectCard
|
||||
v-for="objectId in controller.visibleObjectIds.values()"
|
||||
:key="objectId"
|
||||
:objectId="objectId"
|
||||
:object="definition.objectsById.get(objectId)!"
|
||||
:is-over-dropzone="allFloatingObjectIds.has(objectId)"
|
||||
:marked-for="getMarkedFor(objectId)"
|
||||
:completion-step="controller.objectCompletionById.get(objectId) ?? 0"
|
||||
@drag-start="onObjectDragStart"
|
||||
@drag-end="onObjectDragEnd"
|
||||
/>
|
||||
|
@ -36,7 +37,7 @@
|
|||
</style>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ObjectCard from "./ObjectCard.vue"
|
||||
import PlayerObjectCard from "./PlayerObjectCard.vue"
|
||||
import { useGame } from "../../game"
|
||||
import { computed, reactive, ref } from "vue"
|
||||
import ObjectCardDropZone from "./ObjectCardDropZone.vue"
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
<div class="text-gray-200">
|
||||
{{ object.label }}
|
||||
</div>
|
||||
<div v-if="object.completion !== undefined" class="h-4px rounded-full w-80% bg-gray-700 overflow-hidden">
|
||||
<div class="h-full bg-green-500 transition-all transition-duration-1s" :style="{ width: `${completionStep / object.completion.steps * 100}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -48,6 +51,7 @@
|
|||
object: SceneObjectDefinition
|
||||
isOverDropzone: boolean
|
||||
markedFor: null | "use" | "combine" | "combine-first"
|
||||
completionStep: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
|
@ -26,6 +26,7 @@ export const InteractionSceneType: SceneType<InteractionSceneDefinition, Interac
|
|||
|
||||
return {
|
||||
visibleObjectIds,
|
||||
objectCompletionById,
|
||||
interactionQueue,
|
||||
sortedInteractionQueue: computed(() => [...interactionQueue.values()].sort((a, b) => a.votes - b.votes)),
|
||||
sortedInteractionQueueWithDefined: computed(() => {
|
||||
|
@ -147,6 +148,7 @@ export interface InteractionQueueItem {
|
|||
export interface InteractionSceneController extends SceneController {
|
||||
visibleObjectIds: Reactive<Set<string>>
|
||||
interactionQueue: Reactive<Map<string, InteractionQueueItem>>
|
||||
objectCompletionById: Reactive<Map<string, number>>
|
||||
sortedInteractionQueue: Readonly<Ref<Array<InteractionQueueItem>>>
|
||||
sortedInteractionQueueWithDefined: Readonly<Ref<Array<InteractionQueueItem>>>
|
||||
suggestedInteraction: Ref<SuggestedInteraction | null>
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<button class="bg-green-800 px-2 text-sm rounded-full" @click="game.setVirtualCurtainOpen(!game.isVirtualCurtainOpen)">Vorhang ist {{ game.isVirtualCurtainOpen ? "auf" : "zu" }}</button>
|
||||
</div>
|
||||
</section>
|
||||
<component :is="game.currentScene.type.crewView" :controller="game.currentScene.controller" :definition="game.currentScene.definition"/>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<component :is="game.currentScene.type.playerView" :controller="game.currentScene.controller" :definition="game.currentScene.definition"/>
|
||||
<div class="flex flex-col justify-center items-center text-lg inset-0 absolute bg-dark-900 transition" :class="game.isVirtualCurtainOpen && 'opacity-0 pointer-events-none'">
|
||||
<span class="text-center">mega_cooler_vorhang.jpg</span>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center items-center text-lg inset-0 absolute bg-dark-900 transition" :class="game.isConnected && 'opacity-0 pointer-events-none'">
|
||||
<span class="text-center">Verbindung wird hergestellt…</span>
|
||||
</div>
|
||||
|
|
|
@ -3,4 +3,5 @@ import type { SceneEvent } from "../backend/scene-types"
|
|||
export type PlayerBroadcast =
|
||||
| { type: "keep-alive" }
|
||||
| { type: "scene-changed"; sceneId: string }
|
||||
| { type: "scene-event"; event: SceneEvent }
|
||||
| { type: "scene-event"; event: SceneEvent }
|
||||
| { type: "virtual-curtain-changed", isOpen: boolean }
|
Loading…
Add table
Reference in a new issue