Feat : add login button
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { Player } from "~/netcode/interfaces";
|
||||
import type { User } from "~/netcode/interfaces";
|
||||
|
||||
export interface Props {
|
||||
player: Player;
|
||||
user: User;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
@@ -12,11 +12,11 @@ const props = defineProps<Props>();
|
||||
<div class="player-icon-container">
|
||||
<img
|
||||
class="avatar"
|
||||
v-if="props.player.user.avatar"
|
||||
:src="`https://cdn.discordapp.com/avatars/${props.player.user.userId}/${props.player.user.avatar}.webp`"
|
||||
v-if="props.user.avatar"
|
||||
:src="`https://cdn.discordapp.com/avatars/${props.user.userId}/${props.user.avatar}.webp`"
|
||||
draggable="false"
|
||||
/>
|
||||
<b class="player-name">{{ props.player.user.username }}</b>
|
||||
<b class="player-name">{{ props.user.username }}</b>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ function damage() {
|
||||
Prêt!
|
||||
</div> -->
|
||||
<div id="player_info">
|
||||
<GamePlayerIcon :player="props.player"></GamePlayerIcon>
|
||||
<GamePlayerIcon :user="props.player.user"></GamePlayerIcon>
|
||||
</div>
|
||||
<div id="player_stats">
|
||||
<!-- <template v-if="goStore.current_game?.started"> -->
|
||||
|
||||
+2
-19
@@ -9,29 +9,12 @@ export function subscribe(endpoint: string) {
|
||||
return evtSource;
|
||||
}
|
||||
|
||||
export async function getLobby() {
|
||||
export async function whoami() {
|
||||
const config = useRuntimeConfig();
|
||||
const req = await useFetch<Array<Game>>(config.public.endpoint + "/games", {
|
||||
const req = await useFetch<User>(config.public.endpoint + "/whoami", {
|
||||
credentials: "include",
|
||||
server: false,
|
||||
});
|
||||
// await req.execute();
|
||||
await req.execute();
|
||||
if (req.data.value == null) {
|
||||
throw new Error("Lobby answer is empty");
|
||||
}
|
||||
return req.data as Ref<Game[]>;
|
||||
}
|
||||
|
||||
export async function whoami() {
|
||||
const config = useRuntimeConfig();
|
||||
const req = await useFetch<User>(
|
||||
config.public.endpoint + "/whoami",
|
||||
{
|
||||
credentials: "include",
|
||||
server: false,
|
||||
}
|
||||
);
|
||||
await req.execute();
|
||||
if (req.error.value && req.error.value.statusCode == 401) {
|
||||
// await navigateTo(config.public.discordLoginEndpoint, {
|
||||
|
||||
+101
-115
@@ -28,7 +28,7 @@ const {
|
||||
server: false,
|
||||
});
|
||||
|
||||
const awaitGameReady = execute();
|
||||
await execute();
|
||||
|
||||
const containers = computed<Record<string, Container>>(() => ({
|
||||
[game.value!.fireGems._id]: game.value!.fireGems,
|
||||
@@ -226,25 +226,22 @@ const handlers = {
|
||||
},
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
awaitGameReady.then(() => {
|
||||
console.log(game.value);
|
||||
if (game.value == null) {
|
||||
navigateTo("/lobby");
|
||||
onBeforeMount(async () => {
|
||||
if (game.value == null) {
|
||||
navigateTo("/lobby");
|
||||
throw new Error("game not found");
|
||||
}
|
||||
focusedPlayer.value = selfPlayer.value ?? playerList.value![0];
|
||||
|
||||
eventSource = subscribe(`/games/${gameId}/subscribe`);
|
||||
eventSource.addEventListener("message", async (message) => {
|
||||
const current_game = game.value;
|
||||
if (!current_game) {
|
||||
throw new Error("game not found");
|
||||
}
|
||||
focusedPlayer.value = selfPlayer.value ?? playerList.value![0];
|
||||
|
||||
eventSource = subscribe(`/games/${gameId}/subscribe`);
|
||||
eventSource.addEventListener("message", async (message) => {
|
||||
const current_game = game.value;
|
||||
if (!current_game) {
|
||||
throw new Error("game not found");
|
||||
}
|
||||
const data = JSON.parse(message.data);
|
||||
queueAction(async () => {
|
||||
await handlers[data.type as keyof typeof handlers](data, current_game);
|
||||
});
|
||||
const data = JSON.parse(message.data);
|
||||
queueAction(async () => {
|
||||
await handlers[data.type as keyof typeof handlers](data, current_game);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -294,24 +291,10 @@ function showWinnerScreen() {
|
||||
isWinner.value = true;
|
||||
}
|
||||
|
||||
// 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)
|
||||
// })
|
||||
|
||||
function useTokenClick(t: Effect) {
|
||||
console.log(t);
|
||||
useToken(game.value!._id, t._id);
|
||||
@@ -332,91 +315,94 @@ onUnmounted(() => {
|
||||
:isTurn="isTurn ?? false"
|
||||
></AnimatedBackground>
|
||||
<GameOverlayOptionsDialog></GameOverlayOptionsDialog>
|
||||
<template v-if="game && focusedPlayer && playerList">
|
||||
<Transition name="slide-left" mode="out-in">
|
||||
<div id="stack_discard" :key="focusedPlayer?._id">
|
||||
<div id="stack">
|
||||
<GameCardGrouped
|
||||
:container="focusedPlayer.stack"
|
||||
:wrapped="true"
|
||||
:hidden="true"
|
||||
>
|
||||
</GameCardGrouped>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="discard"
|
||||
:class="{ invisible: discard_unwrapped }"
|
||||
@click="() => (discard_unwrapped = true)"
|
||||
>
|
||||
<GameCardGrouped
|
||||
:container="focusedPlayer.discard"
|
||||
:wrapped="true"
|
||||
@card-click="showDiscard"
|
||||
:no-effects="true"
|
||||
>
|
||||
</GameCardGrouped>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<GameMarket
|
||||
:game="game"
|
||||
:market="game.market"
|
||||
:fire_gems="game.fireGems"
|
||||
:marketStack="game.marketStack"
|
||||
>
|
||||
</GameMarket>
|
||||
<div>
|
||||
<GameToken
|
||||
:token="t"
|
||||
v-for="t in game.currentTurn.tokens"
|
||||
@useToken="useTokenClick"
|
||||
></GameToken>
|
||||
</div>
|
||||
<div id="player_list_container">
|
||||
<div id="player_list">
|
||||
<GamePlayerListElement
|
||||
v-for="p in playerList"
|
||||
:player="p"
|
||||
:game="game"
|
||||
@click="focusPlayer(p)"
|
||||
:focused="focusedPlayer == p"
|
||||
:self="selfPlayer == p"
|
||||
>
|
||||
</GamePlayerListElement>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="current_player">
|
||||
<ClientOnly>
|
||||
<template v-if="game && focusedPlayer && playerList">
|
||||
<Transition name="slide-left" mode="out-in">
|
||||
<GamePlayerSlot
|
||||
v-if="focusedPlayer"
|
||||
:player="focusedPlayer"
|
||||
:game="game"
|
||||
:key="focusedPlayer._id"
|
||||
></GamePlayerSlot>
|
||||
<div id="stack_discard" :key="focusedPlayer?._id">
|
||||
<div id="stack">
|
||||
<GameCardGrouped
|
||||
:container="focusedPlayer.stack"
|
||||
:wrapped="true"
|
||||
:hidden="true"
|
||||
>
|
||||
</GameCardGrouped>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="discard"
|
||||
:class="{ invisible: discard_unwrapped }"
|
||||
@click="() => (discard_unwrapped = true)"
|
||||
>
|
||||
<GameCardGrouped
|
||||
:container="focusedPlayer.discard"
|
||||
:wrapped="true"
|
||||
@card-click="showDiscard"
|
||||
:no-effects="true"
|
||||
>
|
||||
</GameCardGrouped>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<GameOverlayDiscard
|
||||
v-show="discard_unwrapped"
|
||||
:game="game"
|
||||
:player="focusedPlayer"
|
||||
:discard="focusedPlayer.discard"
|
||||
@close="discard_unwrapped = false"
|
||||
></GameOverlayDiscard>
|
||||
<GameOverlayResultDialog
|
||||
:isVisible="showResults"
|
||||
:won="isWinner"
|
||||
:players="playerList"
|
||||
@close="showResults = false"
|
||||
>
|
||||
</GameOverlayResultDialog>
|
||||
<GamePlayerSelf
|
||||
v-if="selfPlayer"
|
||||
:container="selfPlayer.hand"
|
||||
></GamePlayerSelf>
|
||||
</template>
|
||||
|
||||
<GameMarket
|
||||
:game="game"
|
||||
:market="game.market"
|
||||
:fire_gems="game.fireGems"
|
||||
:marketStack="game.marketStack"
|
||||
>
|
||||
</GameMarket>
|
||||
<div>
|
||||
<GameToken
|
||||
:token="t"
|
||||
v-for="t in game.currentTurn.tokens"
|
||||
@useToken="useTokenClick"
|
||||
></GameToken>
|
||||
</div>
|
||||
<div id="player_list_container">
|
||||
<div id="player_list">
|
||||
<GamePlayerListElement
|
||||
v-for="p in playerList"
|
||||
:player="p"
|
||||
:game="game"
|
||||
@click="focusPlayer(p)"
|
||||
:focused="focusedPlayer == p"
|
||||
:self="selfPlayer == p"
|
||||
>
|
||||
</GamePlayerListElement>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="current_player">
|
||||
<Transition name="slide-left" mode="out-in">
|
||||
<GamePlayerSlot
|
||||
v-if="focusedPlayer"
|
||||
:player="focusedPlayer"
|
||||
:game="game"
|
||||
:key="focusedPlayer._id"
|
||||
></GamePlayerSlot>
|
||||
</Transition>
|
||||
</div>
|
||||
<GameOverlayDiscard
|
||||
v-show="discard_unwrapped"
|
||||
:game="game"
|
||||
:player="focusedPlayer"
|
||||
:discard="focusedPlayer.discard"
|
||||
@close="discard_unwrapped = false"
|
||||
></GameOverlayDiscard>
|
||||
<GameOverlayResultDialog
|
||||
:isVisible="showResults"
|
||||
:won="isWinner"
|
||||
:players="playerList"
|
||||
@close="showResults = false"
|
||||
>
|
||||
</GameOverlayResultDialog>
|
||||
<GamePlayerSelf
|
||||
v-if="selfPlayer"
|
||||
:container="selfPlayer.hand"
|
||||
></GamePlayerSelf>
|
||||
</template>
|
||||
</ClientOnly>
|
||||
|
||||
<!-- <LoadingScreen v-if="!loaded"></LoadingScreen> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+106
-79
@@ -1,14 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
// import { playSound } from '~/helpers/audioHelpers';
|
||||
import { playSound } from "~/helpers/audioHelpers";
|
||||
import { createGame, getLobby, subscribe } from "~/netcode";
|
||||
import type { Game, Player } from "~/netcode/interfaces";
|
||||
import { createGame, subscribe } from "~/netcode";
|
||||
import type { Game, Player, User } from "~/netcode/interfaces";
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
let eventSource: EventSource;
|
||||
|
||||
let games = ref<Game[]>([]);
|
||||
const config = useRuntimeConfig();
|
||||
const req = await useFetch<Array<Game>>(config.public.endpoint + "/games", {
|
||||
credentials: "include",
|
||||
server: false,
|
||||
});
|
||||
|
||||
await req.execute();
|
||||
|
||||
let games = req.data;
|
||||
|
||||
const erika_alive = ref(true);
|
||||
const router = useRouter();
|
||||
@@ -19,22 +27,21 @@ function killErika() {
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
games.value = (await getLobby()).value;
|
||||
eventSource = subscribe("/games/subscribe");
|
||||
eventSource.addEventListener("message", (message) => {
|
||||
const data = JSON.parse(message.data);
|
||||
if (data.type == "create") {
|
||||
games.value.push(data);
|
||||
games.value?.push(data);
|
||||
} else if (data.type == "delete") {
|
||||
const index = games.value.findIndex((g) => g._id == data._id);
|
||||
if (index == -1) {
|
||||
const index = games.value?.findIndex((g) => g._id == data._id);
|
||||
if (index == -1 || !index) {
|
||||
throw new Error("Couldn't delete game");
|
||||
}
|
||||
games.value.splice(index, 1);
|
||||
games.value?.splice(index, 1);
|
||||
} else if (data.type == "joinGame") {
|
||||
games.value.find((g) => g._id == data.game)?.teams.push(data.team);
|
||||
games.value?.find((g) => g._id == data.game)?.teams.push(data.team);
|
||||
} else if (data.type == "start") {
|
||||
const targetGame = games.value.find((g) => g._id == data.game);
|
||||
const targetGame = games.value?.find((g) => g._id == data.game);
|
||||
if (targetGame) {
|
||||
targetGame.started = true;
|
||||
}
|
||||
@@ -49,58 +56,77 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="background">
|
||||
<div class="title">Entrez dans le Royaume de Héron !</div>
|
||||
|
||||
<div class="middle-row">
|
||||
<div class="create-game-zone">
|
||||
<button @click="createGame">Create Game</button>
|
||||
</div>
|
||||
|
||||
<div class="games-list-zone">
|
||||
<div v-for="g in games">
|
||||
<button
|
||||
v-if="g"
|
||||
@click="router.push({ path: `/game`, query: { id: g._id } })"
|
||||
:class="
|
||||
authStore.selfUser.userId == g.owner.userId ? 'own_game' : ''
|
||||
"
|
||||
>
|
||||
<template
|
||||
<header>
|
||||
<ClientOnly>
|
||||
<GamePlayerIcon
|
||||
v-if="authStore.logged"
|
||||
:user="(authStore.selfUser as User)"
|
||||
/>
|
||||
<button v-else @click="navigateTo('/login')">Login</button>
|
||||
</ClientOnly>
|
||||
</header>
|
||||
<main>
|
||||
<div class="title">Entrez dans le Royaume de Héron !</div>
|
||||
<ClientOnly>
|
||||
<template v-if="authStore.logged">
|
||||
<div class="create-game-zone">
|
||||
<button
|
||||
@click="createGame"
|
||||
v-if="
|
||||
g.teams.every((t) =>
|
||||
t.players.every(
|
||||
(p) => p.user.userId !== authStore.selfUser.userId
|
||||
)
|
||||
)
|
||||
games?.some((g) => g.owner.userId !== authStore.selfUser.userId)
|
||||
"
|
||||
>
|
||||
SPECTATE
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="!g.started"> JOIN BACK </template>
|
||||
<template v-else> CONTINUE </template>
|
||||
</template>
|
||||
Create Game
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<br />
|
||||
{{
|
||||
g.teams.reduce(
|
||||
(prev, curr) => prev.concat(curr.players),
|
||||
[] as Player[]
|
||||
).length
|
||||
}}
|
||||
current players:<br /><span>{{
|
||||
g.teams
|
||||
.reduce(
|
||||
<div class="games-list-zone">
|
||||
<div v-for="g in games">
|
||||
<button
|
||||
v-if="g"
|
||||
@click="router.push({ path: `/game`, query: { id: g._id } })"
|
||||
:class="
|
||||
authStore.selfUser.userId == g.owner.userId ? 'own_game' : ''
|
||||
"
|
||||
>
|
||||
<template
|
||||
v-if="
|
||||
g.teams.every((t) =>
|
||||
t.players.every(
|
||||
(p) => p.user.userId !== authStore.selfUser.userId
|
||||
)
|
||||
)
|
||||
"
|
||||
>
|
||||
SPECTATE
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="!g.started"> JOIN BACK </template>
|
||||
<template v-else> CONTINUE </template>
|
||||
</template>
|
||||
|
||||
<br />
|
||||
{{
|
||||
g.teams.reduce(
|
||||
(prev, curr) => prev.concat(curr.players),
|
||||
[] as Player[]
|
||||
)
|
||||
.map((p) => p.user.username)
|
||||
.join(",")
|
||||
}}</span>
|
||||
</button>
|
||||
).length
|
||||
}}
|
||||
current players:<br /><span>{{
|
||||
g.teams
|
||||
.reduce(
|
||||
(prev, curr) => prev.concat(curr.players),
|
||||
[] as Player[]
|
||||
)
|
||||
.map((p) => p.user.username)
|
||||
.join(",")
|
||||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</main>
|
||||
|
||||
<div class="overlay" v-if="erika_alive">
|
||||
<div class="erika-zone">
|
||||
@@ -141,9 +167,9 @@ onUnmounted(() => {
|
||||
background-color: #f0f0f0;
|
||||
background-image: url("https://www.pockettactics.com/wp-content/sites/pockettactics/2023/01/fire-emblem-engage-review-29.jpg");
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
display: grid;
|
||||
grid-template-rows: 100px 1fr;
|
||||
grid-template-columns: 1fr;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
@@ -154,39 +180,53 @@ onUnmounted(() => {
|
||||
font-size: 64px;
|
||||
color: white;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.middle-row {
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 100px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.create-game-zone {
|
||||
.create-game-zone,
|
||||
header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
flex-direction: row;
|
||||
backdrop-filter: blur(50px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.create-game-zone {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.create-game-zone button {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
border: none;
|
||||
color: white;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-size: 16px;
|
||||
margin: auto;
|
||||
width: max-content;
|
||||
cursor: pointer;
|
||||
border-radius: 12px;
|
||||
padding: 10px 24px;
|
||||
height: 50px;
|
||||
transition-duration: 0.4s;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
padding: 10px 24px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.games-list-zone {
|
||||
@@ -197,21 +237,8 @@ onUnmounted(() => {
|
||||
|
||||
.games-list-zone button {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border: none;
|
||||
color: white;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-size: 16px;
|
||||
margin: auto;
|
||||
cursor: pointer;
|
||||
border-radius: 12px;
|
||||
padding: 20px 24px;
|
||||
height: 120px;
|
||||
transition-duration: 0.4s;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
.games-list-zone button.own_game {
|
||||
|
||||
Reference in New Issue
Block a user