Skip to content

Commit

Permalink
Display GameOverview in spectate mode
Browse files Browse the repository at this point in the history
  • Loading branch information
magnetenstad committed Jan 30, 2024
1 parent e53f0fb commit e1e2a7c
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 94 deletions.
115 changes: 115 additions & 0 deletions src/components/GameOverview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<template>
<div class="row spaced">
<h3>
{{ getGameDisplayName(game) }}
</h3>
<h3>
{{ gameState?.getTopRightText() }}
</h3>
</div>

<div v-if="game && !allPlayersFinished" class="col">
<div
class="col shadow"
style="
background-color: rgb(43, 43, 43);
border-radius: 0.5em;
padding: 1em 0;
margin-bottom: 1.5em;
overflow: hidden;
gap: 1.5em;
"
>
<div class="row" style="overflow: auto; padding: 0 1em">
<button
v-for="userId in gameState?.playersLeft ?? []"
:class="{ selected: gameState?.player == userId }"
:key="userId"
:id="userId"
style="min-width: 135px"
@click="clickUser(userId)"
>
{{ usersStore.getUser(userId)?.name ?? 'Unknown' }}
<br />
{{ gameState?.getUserDisplayText(userId) }}
</button>
</div>
<div class="row" style="margin: 0 1em">
<button
v-for="(segment, i) in displayVisit.visit"
:class="{
outlined:
(!displayVisit.isPrev && i == displayVisit.visit.indexOf(null)) ||
(displayVisit.isPrev && i == 0),
}"
:disabled="displayVisit.isPrev || segment == null"
>
{{ gameController.getSegmentText(segment) }}
</button>
</div>
</div>

<component
v-if="showInput"
:is="getInputComponent(game.type)"
@hit="emit('hit', $event)"
@miss="emit('miss')"
@undo="emit('undo')"
></component>
</div>
</template>

<script lang="ts" setup>
import { getGameDisplayName, getInputComponent } from '@/games/games'
import { useModalStore } from '@/stores/modal'
import { useUsersStore } from '@/stores/users'
import {
Game,
GameController,
GameState,
Segment,
getLegOfUser,
} from '@/types/game'
import { computed } from 'vue'
import InGameSummary from './InGameSummary.vue'

const props = defineProps<{
game: Game
gameState: GameState
gameController: GameController<GameState>
showInput: boolean
}>()

const emit = defineEmits<{
hit: [segment: Segment]
miss: []
undo: []
}>()

const usersStore = useUsersStore()

const allPlayersFinished = computed(
() => (props.game?.legs.length ?? 0) == (props.gameState?.rank.length ?? 0)
)

const displayVisit = computed(() => {
if (!props.game || !props.gameState?.player)
return { visit: [null, null, null], isPrev: false }
const leg = getLegOfUser(props.game, props.gameState?.player)
const visit = leg?.visits.at(-1)
if ((!visit || visit?.indexOf(null) == -1) && props.gameState?.prevPlayer) {
const leg = getLegOfUser(props.game, props.gameState?.prevPlayer)
const visit = leg?.visits.at(-1)
return { visit: visit ?? [null, null, null], isPrev: true }
}
return { visit: visit ?? [null, null, null], isPrev: false }
})

const clickUser = (userId: string) => {
if (!props.game) return
const leg = getLegOfUser(props.game, userId)
const user = usersStore.getUser(userId)
if (!leg || !user) return
useModalStore().push(InGameSummary, { leg, user }, {})
}
</script>
2 changes: 1 addition & 1 deletion src/stores/online.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const useOnlineStore = defineStore('online', {
.channel(`game-${this.spectating}`)
.on('broadcast', { event: 'game' }, (game) => {
// @ts-ignore
this.spectatingGame = game as Game
this.spectatingGame = game.payload as Game
})
.subscribe()
},
Expand Down
97 changes: 11 additions & 86 deletions src/views/GameView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,63 +16,16 @@
Quit
</button>

<div class="row spaced">
<h3>
{{ getGameDisplayName(gameStore.game) }}
</h3>
<h3>
{{ gameStore.gameState?.getTopRightText() }}
</h3>
</div>

<div v-if="gameStore.game && !allPlayersFinished" class="col">
<div
class="col shadow"
style="
background-color: rgb(43, 43, 43);
border-radius: 0.5em;
padding: 1em 0;
margin-bottom: 1.5em;
overflow: hidden;
gap: 1.5em;
"
>
<div class="row" style="overflow: auto; padding: 0 1em">
<button
v-for="userId in gameStore.gameState?.playersLeft ?? []"
:class="{ selected: gameStore.gameState?.player == userId }"
:key="userId"
:id="userId"
style="min-width: 135px"
@click="clickUser(userId)"
>
{{ usersStore.getUser(userId)?.name ?? 'Unknown' }}
<br />
{{ gameStore.gameState?.getUserDisplayText(userId) }}
</button>
</div>
<div class="row" style="margin: 0 1em">
<button
v-for="(segment, i) in displayVisit.visit"
:class="{
outlined:
(!displayVisit.isPrev && i == displayVisit.visit.indexOf(null)) ||
(displayVisit.isPrev && i == 0),
}"
:disabled="displayVisit.isPrev || segment == null"
>
{{ gameStore.getController().getSegmentText(segment) }}
</button>
</div>
</div>

<component
:is="getInputComponent(gameStore.game.type)"
@hit="gameStore.getController().recordHit($event)"
@miss="gameStore.getController().recordMiss()"
@undo="gameStore.undoScore()"
></component>
</div>
<GameOverview
v-if="gameStore.game && gameStore.gameState"
:show-input="true"
:game="gameStore.game"
:game-state="gameStore.gameState"
:game-controller="gameStore.getController()"
@hit="gameStore.getController().recordHit($event)"
@miss="gameStore.getController().recordMiss()"
@undo="gameStore.undoScore()"
></GameOverview>

<div v-if="gameStore.game && somePlayersFinished">
<button v-if="allPlayersFinished" @click="gameStore.undoScore()">
Expand All @@ -99,11 +52,10 @@
</template>

<script lang="ts" setup>
import InGameSummary from '@/components/InGameSummary.vue'
import GameOverview from '@/components/GameOverview.vue'
import Prompt from '@/components/Prompt.vue'
import Youtube from '@/components/Youtube.vue'
import { speak } from '@/functions/speak'
import { getGameDisplayName, getInputComponent } from '@/games/games'
import { router } from '@/router'
import { useAuthStore } from '@/stores/auth'
import { useEloStore } from '@/stores/elo'
Expand All @@ -113,12 +65,9 @@ import { useModalStore } from '@/stores/modal'
import { useOnlineStore } from '@/stores/online'
import { useOptionsStore } from '@/stores/options'
import { roundToNDecimals } from '@/stores/stats'
import { useUsersStore } from '@/stores/users'
import { getLegOfUser } from '@/types/game'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'

const gameStore = useGameStore()
const usersStore = useUsersStore()
const loadingStore = useLoadingStore()
const onlineStore = useOnlineStore()
const authStore = useAuthStore()
Expand All @@ -135,22 +84,6 @@ const somePlayersFinished = computed(
() => (gameStore.gameState?.rank.length ?? 0) > 0
)

const displayVisit = computed(() => {
if (!gameStore.game || !gameStore.gameState?.player)
return { visit: [null, null, null], isPrev: false }
const leg = getLegOfUser(gameStore.game, gameStore.gameState?.player)
const visit = leg?.visits.at(-1)
if (
(!visit || visit?.indexOf(null) == -1) &&
gameStore.gameState?.prevPlayer
) {
const leg = getLegOfUser(gameStore.game, gameStore.gameState?.prevPlayer)
const visit = leg?.visits.at(-1)
return { visit: visit ?? [null, null, null], isPrev: true }
}
return { visit: visit ?? [null, null, null], isPrev: false }
})

onMounted(async () => {
if (!gameStore.game) {
quit()
Expand Down Expand Up @@ -220,14 +153,6 @@ const saveGame = async () => {
})
}

const clickUser = (userId: string) => {
if (!gameStore.game) return
const leg = getLegOfUser(gameStore.game, userId)
const user = usersStore.getUser(userId)
if (!leg || !user) return
useModalStore().push(InGameSummary, { leg, user }, {})
}

watch(
() => gameStore.gameState?.player,
(userId) => {
Expand Down
27 changes: 20 additions & 7 deletions src/views/SpectateView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@
Back
</button>

<template v-if="onlineStore.getSpectating">
<h2>Spectating {{ name }}</h2>

<p v-if="onlineStore.getSpectating.inGame">{{ name }} is in game.</p>
<p v-else>{{ name }} is not in game.</p>

{{ onlineStore.spectatingGame }}
<h2>Spectating {{ name }}</h2>

<template v-if="onlineStore.spectatingGame && gameController && gameState">
<GameOverview
:show-input="false"
:game="onlineStore.spectatingGame"
:game-state="gameState"
:game-controller="gameController"
></GameOverview>
</template>
<p v-else>{{ name }} is not in game.</p>
</template>

<script lang="ts" setup>
import GameOverview from '@/components/GameOverview.vue'
import { getGameController } from '@/games/games'
import { router } from '@/router'
import { useOnlineStore } from '@/stores/online'
import { useUsersStore } from '@/stores/users'
Expand All @@ -25,6 +30,14 @@ const name = computed(
() => useUsersStore().getUser(onlineStore.getSpectating?.userId)?.name
)
const gameController = computed(() =>
onlineStore.spectatingGame
? getGameController(onlineStore.spectatingGame)
: null
)
const gameState = computed(() => gameController.value?.getGameState())
watch(
() => onlineStore.getSpectating,
(spectating) => {
Expand Down

0 comments on commit e1e2a7c

Please sign in to comment.