Files
front/pages/game/[id].vue
T
2024-06-27 19:40:29 +02:00

280 lines
7.3 KiB
Vue

<script setup lang="ts">
import LoadingScreen from '~/components/LoadingScreen.vue';
import { subscribe } from '~/netcode';
import { containerEvents } from '~/netcode/events';
import { type Container, type Game, type Player } from '~/netcode/interfaces';
const config = useRuntimeConfig()
const route = useRoute()
const gameId = route.params.id
const { data: game, pending, error, refresh } = await useFetch<Game>(
new URL(`/games/${gameId}`, config.public.endpoint).href,
{
credentials: "include",
},
)
if (game.value == null) {
navigateTo("/lobby");
throw new Error("game not found")
}
const containers = computed<Record<string, Container>>(() => ({
[game.value!.fireGems._id]: game.value!.fireGems,
[game.value!.market._id]: game.value!.market,
[game.value!.marketStack._id]: game.value!.marketStack,
...Object.fromEntries(
game.value!.teams.reduce(
(acc, t) => acc.concat(t.players), [] as Player[]
).map(
p => [
[p.board._id, p.board],
[p.discard._id, p.discard],
[p.hand._id, p.hand],
[p.stack._id, p.stack]
]
).flat(1)
)
}))
const eventSource = subscribe(`/games/${gameId}/subscribe`)
eventSource.addEventListener("message", (message) => {
const data = JSON.parse(message.data)
console.log(data)
if (data.type == 'start') {
throw new Error("not implemented")
} else if (data.type == "populateContainer") {
throw new Error("not implemented")
} else if (data.type == "shuffleContainer") {
containerEvents.get(data.container._id)?.shuffleContainer()
} else if (data.type == "distributeCards") {
containerEvents.get(data.from._id)?.hideCards(data.cards)
containerEvents.get(data.from._id)?.getCardsPosition(data.cards)
const fromContainer = containers.value[data.from as string]
const toContainer = containers.value[data.to as string]
for (const card of data.cards) {
const index = fromContainer.cards.findIndex(c => c._id == card._id)
fromContainer.cards.splice(index, 1)
}
for (const card of data.cards) {
toContainer.cards.push(card)
}
} else if (data.type == "endTurn") {
throw new Error("not implemented")
}
});
const authStore = useAuthStore()
const playerList = computed(() => game.value!.teams.reduce((acc, t) => acc.concat(t.players), [] as Player[]))
const selfPlayer = computed(() => authStore.logged ? playerList.value?.find(p => p.user.userId == authStore.selfUser.userId) : undefined)
// TODO : current turn sound
// TODO : winner screen
// TODO : join sound
const showResults = ref(false)
const isWinner = ref(false)
const loaded = ref(false)
function showLoserScreen() {
// playSound('/sounds/ding.mp3')
showResults.value = true
isWinner.value = false
}
function showWinnerScreen() {
// playSound('/sounds/ding.mp3')
showResults.value = true
isWinner.value = true
}
const discard_unwrapped = ref(false)
const focusedPlayer = ref<Player>(selfPlayer.value ?? playerList.value[0])
// const clientStore = useClientSideStore()
// const restack_discarded_champion = (target: Card) => clientStore.findUseEffect(CardEffects.RESTACK_DISCARDED_CHAMPION, target)
// const restack_discarded_card = (target: Card) => clientStore.findUseEffect(CardEffects.RESTACK_DISCARDED_CARD, target)
// const sacrifice = (target: Card) => clientStore.findUseEffect(CardEffects.SACRIFICE, target);
function focusPlayer(p: Player) {
focusedPlayer.value = p
}
// watch<Team>(() => goStore.current_game!.current_turn, (new_team, old_team) => {
// if (focusedPlayer.value.team != old_team) { return }
// const first_player = goStore.current_game?.players.find(p => p.team == goStore.current_game?.current_turn)
// if (!first_player) {
// return
// }
// focusPlayer(first_player)
// })
onUnmounted(() => {
eventSource.close()
})
</script>
<template>
<div @contextmenu.prevent="false" id="game_board" v-if="game">
<AnimatedBackground @ready="loaded = true"></AnimatedBackground>
<div id="stack_discard">
<div id="stack">
<CardsGrouped :container="focusedPlayer.stack">
</CardsGrouped>
</div>
<div id="discard" :class="{ invisible: discard_unwrapped }" @click="() => discard_unwrapped = true">
<CardsGrouped :container="focusedPlayer.discard">
</CardsGrouped>
</div>
</div>
<!-- <MarketCards :container="game.market"></MarketCards> -->
<div id="player_list_container">
<div id="player_list">
<!-- <PlayerListElement v-for="p in playerList" :player="p" @click="focusPlayer(p)" :focused="focusedPlayer">
</PlayerListElement> -->
</div>
</div>
<div id="current_player">
<PlayerSlot v-if="focusedPlayer" :player="focusedPlayer" :game="game!"></PlayerSlot>
</div>
<ResultDialog :isVisible="showResults" :won="isWinner" :players="playerList" @close="showResults = false">
</ResultDialog>
<!-- <GlobalOverlay></GlobalOverlay>
<SelfView></SelfView> -->
<LoadingScreen v-if="!loaded"></LoadingScreen>
</div>
</template>
<style scoped>
#game_status {
position: fixed;
z-index: 10;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(255, 255, 255, .75);
}
#game_board {
display: grid;
grid-template-columns: 1fr min-content 1fr;
grid-template-rows: min-content min-content 1fr;
grid-template-areas:
"stack_discard market empty"
"player_list player_list player_list"
"current_player current_player current_player";
height: 100%;
}
#player_list,
#current_player {
overflow: auto;
position: relative;
isolation: isolate;
/* background: url('/images/bg-darkgrass.png'); */
}
#current_player {
grid-area: current_player;
}
#stack_discard {
grid-area: stack_discard;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
#stack,
#discard {
display: flex;
flex-direction: row;
}
#discard {
cursor: pointer;
}
.discard_overlay {
z-index: 9;
display: flex;
/* background: blue; */
pointer-events: none;
gap: 2px;
flex-wrap: wrap-reverse;
align-content: flex-end;
cursor: default;
position: absolute;
padding-bottom: inherit;
padding-left: 40px;
height: calc(100% - 64px);
padding-top: 64px;
width: calc(100% -40px);
margin-left: 0;
}
#discard_unwrapped_bg {
display: none;
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
z-index: 8;
background: rgba(0, 0, 0, 0.5);
pointer-events: all;
padding: inherit;
}
#discard_unwrapped_bg.unwrapped {
display: block;
}
#market {
grid-area: market;
display: flex;
flex-direction: row;
justify-content: center;
}
#player_list_container {
grid-area: player_list;
display: flex;
flex-direction: row;
justify-content: center;
/* background-image: url("/images/bg-darkgrass.png"); */
}
#player_list {
/* border: 5px solid #000; */
display: flex;
}
</style>
<style>
#player_list .card {
--max-height: 90px;
}
</style>