shotgun/site/src/components/Game.vue
2024-02-03 22:29:17 -06:00

107 lines
3.7 KiB
Vue

<template>
<v-container>
<v-row class="d-flex justify-center">
<v-sheet :elevation="2" width="800">
<v-progress-linear :model-value="timeLeft" :max="initTimeLeft" :color="moveColor"></v-progress-linear>
<v-row class="d-flex justify-center">
<v-col cols="auto">
<GameStatus :game="props.game" />
</v-col>
</v-row>
<v-row>
<v-col cols="6">
<!-- dealer -->
<Player :stats="props.game.players[0]" :dealer="true" :disabled="!props.dealer || !myTurn" @item="(evt: number) => useItem(evt)" />
</v-col>
<v-divider vertical />
<v-col cols="6">
<!-- challenger -->
<Player :stats="props.game.players[1]" :dealer="false" :disabled="props.dealer || !myTurn" @item="(evt: number) => useItem(evt)" />
</v-col>
</v-row>
<v-row v-if="gameOver" class="py-4">
<v-col cols="3"></v-col>
<v-col cols="6">
<v-btn block disabled>THE GAME IS OVER</v-btn>
</v-col>
</v-row>
<v-row v-else-if="myTurn" class="py-4">
<v-col cols="1"></v-col>
<v-col cols="5">
<v-btn block @click="attack(true)">SHOOT {{ dealerTarget }}</v-btn>
</v-col>
<v-col cols="5">
<v-btn block @click="attack(false)">SHOOT {{ challTarget }}</v-btn>
</v-col>
</v-row>
<v-row v-else class="py-4">
<v-col cols="3"></v-col>
<v-col cols="6">
<v-btn block disabled>THE {{ currentTurn }} IS CONSIDERING</v-btn>
</v-col>
</v-row>
</v-sheet>
</v-row>
<v-row class="d-flex justify-center mt-8">
<v-btn @click="leave">Leave</v-btn>
</v-row>
</v-container>
</template>
<script setup lang="ts">
import type { Game, Action } from '@/lib/game';
import { computed, ref, watch } from 'vue';
import { useTimestamp } from '@vueuse/core';
export interface Props {
/**
* Game state to display.
*/
game: Game;
/**
* Whether this client is connected as the dealer.
*/
dealer: boolean;
}
export interface Emits {
(e: 'action', v: Action): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
const gameOver = computed(() => props.game.winner != null);
const myTurn = computed(() => !gameOver.value && props.dealer === props.game.dealer);
const currentTurn = computed(() => props.game.dealer ? 'DEALER' : 'CHALLENGER');
const dealerTarget = computed(() => props.dealer ? 'YOURSELF' : 'THE DEALER');
const challTarget = computed(() => props.dealer ? 'THE CHALLENGER' : 'YOURSELF');
const initTimeLeft = ref(15000);
const timeLeft = ref(15000);
const timestamp = useTimestamp({
callback: (t) => {
timeLeft.value = props.game.deadline - t;
},
interval: 60,
});
watch(props.game, (now) => {
initTimeLeft.value = now.deadline - timestamp.value;
});
const moveColor = computed(() => timeLeft.value > 3000 ? 'primary' : 'red');
function attack(left: boolean) {
const action = left === props.dealer ? 'self' : 'across';
emit('action', { action });
}
function useItem(evt: number) {
const action = evt.toString() as "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7";
emit('action', { action });
}
function leave() {
emit('action', { action: 'quit' });
}
</script>