Feat : various fixes, sounds and multiplayer additions
This commit is contained in:
@@ -15,17 +15,15 @@ const canvas = ref<HTMLCanvasElement | null>(null);
|
||||
const canvas_resize_temp = ref<HTMLCanvasElement | null>(null);
|
||||
|
||||
export interface Props {
|
||||
colorStart?: [number, number, number];
|
||||
colorEnd?: [number, number, number];
|
||||
isTurn?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
colorStart: () => [0, 0.3, 0],
|
||||
colorEnd: () => [0, 1, 0],
|
||||
isTurn: () => false,
|
||||
});
|
||||
|
||||
const _colorStart = reactive(props.colorStart);
|
||||
const _colorEnd = reactive(props.colorEnd);
|
||||
const _colorStart = reactive([0, 0.3, 0]);
|
||||
const _colorEnd = reactive([0, 1, 0]);
|
||||
|
||||
function initShader() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
@@ -119,15 +117,19 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
// watch(() => [props.game.currentTurn], () => {
|
||||
// if (props.game.teams.find() != goStore.self?.team) {
|
||||
// gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: .2, 2: .3 })
|
||||
// gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 1 })
|
||||
// } else {
|
||||
// gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: .3, 2: 0 })
|
||||
// gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 0 })
|
||||
// }
|
||||
// }, { immediate: true })
|
||||
watch(
|
||||
() => [props.isTurn],
|
||||
() => {
|
||||
if (props.isTurn) {
|
||||
gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: 0.3, 2: 0 });
|
||||
gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 0 });
|
||||
} else {
|
||||
gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: 0.2, 2: 0.3 });
|
||||
gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 1 });
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch([_colorEnd, _colorStart], () => {
|
||||
recolorShader();
|
||||
@@ -153,8 +155,7 @@ onUnmounted(() => {
|
||||
:class="{ pixelated: settingsStore.shaderPixelated }"
|
||||
width="480"
|
||||
height="270"
|
||||
>test</canvas
|
||||
>
|
||||
></canvas>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
+89
-52
@@ -1,93 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
export interface Props {
|
||||
uuid?: string
|
||||
card_id?: number
|
||||
locked?: boolean
|
||||
wrapped?: boolean
|
||||
tilted?: boolean
|
||||
uuid?: string;
|
||||
card_id?: number;
|
||||
locked?: boolean;
|
||||
wrapped?: boolean;
|
||||
tilted?: boolean;
|
||||
}
|
||||
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
wrapped: () => false,
|
||||
tilted: () => true,
|
||||
locked: () => true
|
||||
})
|
||||
locked: () => true,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["click"])
|
||||
const emit = defineEmits(["click"]);
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const childCount = ref<number>(0)
|
||||
const childCount = ref<number>(0);
|
||||
|
||||
const card = ref<HTMLElement>()
|
||||
const card = ref<HTMLElement>();
|
||||
|
||||
const extension = computed(() => {
|
||||
if (settingsStore.cardStyle == CardStyles.SVG) {
|
||||
return ".svg"
|
||||
return ".svg";
|
||||
}
|
||||
return ".png"
|
||||
})
|
||||
return ".png";
|
||||
});
|
||||
function cardClick() {
|
||||
if (!props.card_id) return
|
||||
emit("click")
|
||||
if (!props.card_id) return;
|
||||
emit("click");
|
||||
}
|
||||
|
||||
const isZooming = ref<boolean>(false)
|
||||
const isZooming = ref<boolean>(false);
|
||||
|
||||
function mouseenter(e: MouseEvent) {
|
||||
// User is Right Clicking
|
||||
if ((e.buttons & 2) == 2) {
|
||||
isZooming.value = true
|
||||
isZooming.value = true;
|
||||
}
|
||||
|
||||
// goStore.hoveredCard = props.card_id
|
||||
}
|
||||
function mouseleave(e: MouseEvent) {
|
||||
isZooming.value = false
|
||||
isZooming.value = false;
|
||||
}
|
||||
|
||||
function rightClickDown(e: MouseEvent) {
|
||||
isZooming.value = true
|
||||
isZooming.value = true;
|
||||
}
|
||||
|
||||
function rightClickUp(e: MouseEvent) {
|
||||
isZooming.value = false
|
||||
isZooming.value = false;
|
||||
}
|
||||
|
||||
function activateEffect(e: CustomEvent) {
|
||||
console.log(e.detail, props.uuid)
|
||||
console.log(e.detail, props.uuid);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
card.value?.style.setProperty("--random-seed", -Math.random() * 10 + 's')
|
||||
})
|
||||
card.value?.style.setProperty("--random-seed", -Math.random() * 10 + "s");
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="card" class="card" :class="{ active: childCount > 0, wrapped, unlocked: !props.locked, zoom: isZooming }"
|
||||
@contextmenu.prevent="false" @click.left="cardClick" @mousedown.right="rightClickDown"
|
||||
@mouseup.right="rightClickUp" @mouseenter="mouseenter" @mouseleave="mouseleave">
|
||||
<div id="contextMenuButtons" :ref="(el) => { childCount = ((el as Element)?.childElementCount ?? 0) }">
|
||||
<div
|
||||
ref="card"
|
||||
class="card"
|
||||
:class="{
|
||||
active: childCount > 0,
|
||||
wrapped,
|
||||
unlocked: !props.locked,
|
||||
zoom: isZooming,
|
||||
}"
|
||||
@contextmenu.prevent="false"
|
||||
@click.left="cardClick"
|
||||
@mousedown.right="rightClickDown"
|
||||
@mouseup.right="rightClickUp"
|
||||
@mouseenter="mouseenter"
|
||||
@mouseleave="mouseleave"
|
||||
>
|
||||
<div
|
||||
id="contextMenuButtons"
|
||||
:ref="(el) => { childCount = ((el as Element)?.childElementCount ?? 0) }"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<template v-if="props.card_id">
|
||||
<svg width="180" height="250" v-if="settingsStore.cardStyle == CardStyles.SVG" viewBox="0 0 298 417">
|
||||
<use :xlink:href="`/cards/${settingsStore.cardStyle}/` + props.card_id.toString().padStart(3, '0') + extension + '#card' + props.card_id"
|
||||
@activate_effect="activateEffect($event)">
|
||||
</use>
|
||||
<svg
|
||||
width="180"
|
||||
height="250"
|
||||
v-if="settingsStore.cardStyle == CardStyles.SVG"
|
||||
viewBox="0 0 298 417"
|
||||
>
|
||||
<use
|
||||
:xlink:href="
|
||||
`/cards/${settingsStore.cardStyle}/` +
|
||||
props.card_id.toString().padStart(3, '0') +
|
||||
extension +
|
||||
'#card' +
|
||||
props.card_id
|
||||
"
|
||||
@activate_effect="activateEffect($event)"
|
||||
></use>
|
||||
</svg>
|
||||
<img :class="`card_image`" v-else
|
||||
:src="`/cards/${settingsStore.cardStyle}/` + props.card_id.toString().padStart(3, '0') + extension"
|
||||
draggable="false">
|
||||
<img
|
||||
:class="`card_image`"
|
||||
v-else
|
||||
:src="
|
||||
`/cards/${settingsStore.cardStyle}/` +
|
||||
props.card_id.toString().padStart(3, '0') +
|
||||
extension
|
||||
"
|
||||
draggable="false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<img :class="`card_image`" v-else :src="'/cards/background.png'" draggable="false">
|
||||
|
||||
<img
|
||||
:class="`card_image`"
|
||||
v-else
|
||||
:src="'/cards/background.png'"
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -100,14 +135,14 @@ onMounted(() => {
|
||||
justify-content: center;
|
||||
margin-bottom: 0px;
|
||||
margin-top: var(--margin-bottom);
|
||||
transition: all 0.075s cubic-bezier(1, 1.81, .59, 1.42);
|
||||
transition: all 0.075s cubic-bezier(1, 1.81, 0.59, 1.42);
|
||||
isolation: isolate;
|
||||
pointer-events: all;
|
||||
max-height: var(--max-height);
|
||||
}
|
||||
|
||||
.card.active {
|
||||
cursor: pointer
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card_image {
|
||||
@@ -117,19 +152,22 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.card.wrapped {
|
||||
height: 6px;
|
||||
height: 1px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card.wrapped .card_image {
|
||||
filter: drop-shadow(.5px .5px .5px gray) drop-shadow(-.5px -.5px .5px gray);
|
||||
filter: drop-shadow(0.5px 0.5px 0.5px gray)
|
||||
drop-shadow(-0.5px -0.5px 0.5px gray);
|
||||
}
|
||||
|
||||
.card.unlocked {
|
||||
margin-top: 0px;
|
||||
margin-bottom: var(--margin-bottom);
|
||||
transform: translateY(calc(var(--margin-bottom)*-.25));
|
||||
filter: drop-shadow(calc(var(--margin-bottom)*.3) var(--margin-bottom) 1px rgba(0, 0, 0, .60));
|
||||
transform: translateY(calc(var(--margin-bottom) * -0.25));
|
||||
filter: drop-shadow(
|
||||
calc(var(--margin-bottom) * 0.3) var(--margin-bottom) 1px rgba(0, 0, 0, 0.6)
|
||||
);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -147,12 +185,11 @@ onMounted(() => {
|
||||
bottom: 0;
|
||||
width: 99%;
|
||||
transform: translateY(-0px);
|
||||
transition: 0.1s transform cubic-bezier(1, 1.81, .59, 1.42);
|
||||
transition: 0.1s transform cubic-bezier(1, 1.81, 0.59, 1.42);
|
||||
}
|
||||
|
||||
.card.active:hover #contextMenuButtons {
|
||||
transform: translateY(100%);
|
||||
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@@ -167,9 +204,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
@keyframes gelatine {
|
||||
|
||||
from,
|
||||
to {}
|
||||
to {
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: scale(1, 1.5);
|
||||
@@ -187,7 +224,7 @@ onMounted(() => {
|
||||
.svg_resource_icon {
|
||||
cursor: pointer;
|
||||
animation: gelatine 0.3s normal;
|
||||
transition: transform .1s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
transition: transform 0.1s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
|
||||
.svg_resource_icon:active {
|
||||
|
||||
@@ -55,13 +55,24 @@ function endAnimation() {
|
||||
animationCallbacks.value.forEach((p) => p());
|
||||
}
|
||||
|
||||
containerEvents.set(props.container._id, {
|
||||
watch(
|
||||
props.container,
|
||||
(newValue, oldValue) => {
|
||||
if (oldValue) {
|
||||
containerEvents.delete(oldValue._id);
|
||||
}
|
||||
if (newValue) {
|
||||
containerEvents.set(newValue._id, {
|
||||
populateContainer,
|
||||
shuffleContainer,
|
||||
getCardsPosition,
|
||||
startAnimation,
|
||||
endAnimation,
|
||||
});
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
async function onEnter(_el: any, done: () => void) {
|
||||
animationCallbacks.value.push(done);
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Container } from "~/netcode/interfaces";
|
||||
|
||||
export interface Props {
|
||||
market: Container;
|
||||
marketStack: Container;
|
||||
fire_gems: Container;
|
||||
}
|
||||
|
||||
@@ -28,7 +29,11 @@ function fireGemCardClick(e: string) {
|
||||
|
||||
<template>
|
||||
<div id="market">
|
||||
<CardPreview :tilted="false" :card_id="undefined"></CardPreview>
|
||||
<CardsGrouped
|
||||
:container="marketStack"
|
||||
:wrapped="true"
|
||||
:hidden="true"
|
||||
></CardsGrouped>
|
||||
<div class="separator"></div>
|
||||
<CardsGrouped
|
||||
:container="market"
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import type { Player } from '~/netcode/Player';
|
||||
|
||||
import type { Player } from "~/netcode/interfaces";
|
||||
|
||||
export interface Props {
|
||||
player: Player;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const props = defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="player-icon-container">
|
||||
<img class="avatar" v-if="props.player.image" :src="props.player.image" draggable="false">
|
||||
<b class="player-name">{{ props.player.username }}</b>
|
||||
<img
|
||||
class="avatar"
|
||||
v-if="props.player.user.avatar"
|
||||
:src="`https://cdn.discordapp.com/avatars/${props.player.user.userId}/${props.player.user.avatar}.webp`"
|
||||
draggable="false"
|
||||
/>
|
||||
<b class="player-name">{{ props.player.user.username }}</b>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -31,7 +34,7 @@ const props = defineProps<Props>()
|
||||
|
||||
.player-name {
|
||||
font-size: 20px;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
margin-left: 10px;
|
||||
|
||||
color: white;
|
||||
|
||||
@@ -1,43 +1,54 @@
|
||||
<script setup lang="ts">
|
||||
import goStore from '@/netcode';
|
||||
import type { Player } from "~/netcode/Player";
|
||||
import type { Game, Player } from "~/netcode/interfaces";
|
||||
|
||||
const emit = defineEmits(['click'])
|
||||
|
||||
|
||||
const view = ref<"main" | "discard">("main")
|
||||
|
||||
function show(data: "main" | "discard") {
|
||||
view.value = data
|
||||
}
|
||||
const emit = defineEmits(["click"]);
|
||||
|
||||
export interface Props {
|
||||
game: Game;
|
||||
player: Player;
|
||||
focused?: Player
|
||||
focused?: boolean;
|
||||
isTurn?: boolean;
|
||||
self?: boolean;
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
isTurn: () => false,
|
||||
self: () => false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="player_list_element" @click="$emit('click')"
|
||||
:class="{ self: props.player == goStore.self, focused: props.focused == props.player, isTurn: props.player.team == goStore.current_game?.current_turn }">
|
||||
<div
|
||||
class="player_list_element"
|
||||
@click="$emit('click')"
|
||||
:class="{
|
||||
self,
|
||||
focused,
|
||||
isTurn,
|
||||
}"
|
||||
>
|
||||
<div id="player_banner" class="small">
|
||||
<div class="ready-bubble not-ready" v-if="!props.player.ready && !goStore.current_game?.started">Pas encore
|
||||
prêt...
|
||||
<!-- <div
|
||||
class="ready-bubble not-ready"
|
||||
v-if="!props.player.ready && !goStore.current_game?.started"
|
||||
>
|
||||
Pas encore prêt...
|
||||
</div>
|
||||
<div class="ready-bubble ready" v-if="props.player.ready && !goStore.current_game?.started">Prêt!</div>
|
||||
<div
|
||||
class="ready-bubble ready"
|
||||
v-if="props.player.ready && !goStore.current_game?.started"
|
||||
>
|
||||
Prêt!
|
||||
</div> -->
|
||||
<div id="player_info">
|
||||
<PlayerIcon :player="props.player"></PlayerIcon>
|
||||
</div>
|
||||
<div id="player_stats">
|
||||
<template v-if="goStore.current_game?.started">
|
||||
<PlayerStats :player="props.player">
|
||||
</PlayerStats>
|
||||
</template>
|
||||
<!-- <template v-if="goStore.current_game?.started"> -->
|
||||
<PlayerStats :game="props.game" :player="props.player"> </PlayerStats>
|
||||
<!-- </template> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,15 +56,15 @@ const props = defineProps<Props>()
|
||||
.player_list_element {
|
||||
border-radius: 10px;
|
||||
margin: 10px;
|
||||
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, .60));
|
||||
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, 0.6));
|
||||
transform: translate(-2.5px, -7.5px);
|
||||
backdrop-filter: blur(5px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
transition: all .1s;
|
||||
transition: all 0.1s;
|
||||
width: 300px;
|
||||
cursor: pointer
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.player_list_element::before {
|
||||
@@ -65,7 +76,7 @@ const props = defineProps<Props>()
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.player_list_element.focused {
|
||||
@@ -74,7 +85,7 @@ const props = defineProps<Props>()
|
||||
}
|
||||
|
||||
.player_list_element.isTurn::before {
|
||||
opacity: .1;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.player_list_element.self::before {
|
||||
@@ -94,7 +105,7 @@ const props = defineProps<Props>()
|
||||
}
|
||||
|
||||
#player_banner.small {
|
||||
flex-direction: row
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#player_banner > * {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { endTurn, lockCard } from "~/netcode";
|
||||
import { endTurn, joinGame, lockCard, startGame } from "~/netcode";
|
||||
import type { Game, Player } from "~/netcode/interfaces";
|
||||
import { useTurnStore } from "~/stores/turnStore";
|
||||
|
||||
@@ -105,7 +105,6 @@ function boardCardClick(cardUUID: string) {
|
||||
|
||||
<template>
|
||||
<div class="player" :class="{ turn: isPlayerTurn, self: isSelf }">
|
||||
<div id="player_banner" class="big">test</div>
|
||||
<div id="turn_buttons">
|
||||
<button
|
||||
id="end_turn"
|
||||
@@ -115,6 +114,12 @@ function boardCardClick(cardUUID: string) {
|
||||
>
|
||||
END TURN
|
||||
</button>
|
||||
<button class="end_turn_button turn_icon" @click="startGame(game._id)">
|
||||
Start game
|
||||
</button>
|
||||
<button class="end_turn_button turn_icon" @click="joinGame(game._id)">
|
||||
Join game
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="warning"
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import type { Player } from "~/netcode/interfaces";
|
||||
import { playSound } from "~/helpers/audioHelpers";
|
||||
import type { Game, Player } from "~/netcode/interfaces";
|
||||
|
||||
export interface Props {
|
||||
game: Game;
|
||||
player: Player;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const team = computed(() =>
|
||||
props.game.teams.find((t) =>
|
||||
t.players.map((p) => p._id).includes(props.player._id)
|
||||
)
|
||||
);
|
||||
|
||||
const isTurn = computed(
|
||||
() => team.value && team.value?._id == props.game.currentTurn.currentTeam
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="turn_icon">
|
||||
<img src="/img/champion-shield.png" class="icon_img" draggable="false" />
|
||||
<span class="turn_icon_number">
|
||||
{{ player.team?.health }}
|
||||
{{ team?.health }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- <div class="turn_icon" v-if="showTurnData">
|
||||
@@ -30,7 +42,7 @@ const props = defineProps<Props>();
|
||||
<div class="turn_icon">
|
||||
<img src="/img/fuck.svg" class="icon_img" draggable="false" />
|
||||
<span class="turn_icon_number">{{
|
||||
(player.turn?.discard_markers ?? 0) + (player.turn?.fuck_u_markers ?? 0)
|
||||
(isTurn && (player.discardMarkers ?? 0) + (player.fuckUMarkers ?? 0)) || 0
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+21
-3
@@ -48,7 +48,25 @@ export async function whoami() {
|
||||
|
||||
export async function createGame() {
|
||||
const config = useRuntimeConfig();
|
||||
await $fetch<User>(new URL("/games", config.public.endpoint).href, {
|
||||
const res = await $fetch<Game>(new URL("/games", config.public.endpoint).href, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
console.log(res)
|
||||
navigateTo("/game/" + res._id)
|
||||
}
|
||||
|
||||
export async function startGame(game: string) {
|
||||
const config = useRuntimeConfig();
|
||||
const res = await $fetch<Game>(new URL(`games/${game}/start`, config.public.endpoint).href, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
}
|
||||
|
||||
export async function joinGame(game: string) {
|
||||
const config = useRuntimeConfig();
|
||||
const res = await $fetch<Game>(new URL(`games/${game}/join`, config.public.endpoint).href, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
@@ -56,7 +74,7 @@ export async function createGame() {
|
||||
|
||||
export async function endTurn(game: string) {
|
||||
const config = useRuntimeConfig();
|
||||
await $fetch<User>(
|
||||
await $fetch(
|
||||
new URL(`games/${game}/endTurn`, config.public.endpoint).href,
|
||||
{
|
||||
method: "POST",
|
||||
@@ -67,7 +85,7 @@ export async function endTurn(game: string) {
|
||||
|
||||
export async function lockCard(game: string, cardId: string) {
|
||||
const config = useRuntimeConfig();
|
||||
await $fetch<User>(
|
||||
await $fetch(
|
||||
new URL(`games/${game}/turn/lockCard/${cardId}`, config.public.endpoint).href,
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
@@ -16,10 +16,13 @@ export interface Game extends GameObject {
|
||||
marketStack: Container;
|
||||
teams: Team[];
|
||||
currentTurn: PlayingTurn;
|
||||
started: boolean
|
||||
owner: User
|
||||
}
|
||||
|
||||
export interface Team extends GameObject {
|
||||
players: Player[];
|
||||
health: number;
|
||||
}
|
||||
|
||||
export interface Player extends GameObject {
|
||||
@@ -28,10 +31,14 @@ export interface Player extends GameObject {
|
||||
hand: Container;
|
||||
stack: Container;
|
||||
user: User;
|
||||
discardMarkers: number
|
||||
fuckUMarkers: number
|
||||
}
|
||||
|
||||
export interface User extends GameObject {
|
||||
userId: string;
|
||||
avatar: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface Container extends GameObject {
|
||||
|
||||
+56
-16
@@ -3,9 +3,11 @@ import LoadingScreen from "~/components/LoadingScreen.vue";
|
||||
import { subscribe } from "~/netcode";
|
||||
import { containerEvents, delay } from "~/netcode/events";
|
||||
import { type Container, type Game, type Player } from "~/netcode/interfaces";
|
||||
import { playSound } from "~/helpers/audioHelpers";
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const settingsStore = useSettingsStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
const route = useRoute();
|
||||
const gameId = route.params.id;
|
||||
@@ -76,9 +78,10 @@ eventSource.addEventListener("message", async (message) => {
|
||||
queueAction(async () => {
|
||||
await containerEvents.get(data.container)?.startAnimation();
|
||||
});
|
||||
const fromContainer = containers.value[data.container.id as string];
|
||||
const fromContainer = containers.value[data.container._id as string];
|
||||
queueAction(async () => {
|
||||
for (const card of data.container.cards) {
|
||||
playSound("/sounds/distribute.mp3");
|
||||
fromContainer.cards.push(card);
|
||||
await delay(settingsStore.animationSpeed);
|
||||
}
|
||||
@@ -88,6 +91,8 @@ eventSource.addEventListener("message", async (message) => {
|
||||
});
|
||||
} else if (data.type == "shuffleContainer") {
|
||||
queueAction(async () => {
|
||||
playSound("/sounds/shuffle.mp3");
|
||||
// TODO : IMPORTANT : find a better way than containerEvents
|
||||
await containerEvents.get(data.container)?.shuffleContainer();
|
||||
});
|
||||
} else if (data.type == "distributeCards") {
|
||||
@@ -108,6 +113,7 @@ eventSource.addEventListener("message", async (message) => {
|
||||
});
|
||||
|
||||
queueAction(async () => {
|
||||
playSound("/sounds/distribute.mp3");
|
||||
toContainer.cards.push(card);
|
||||
await delay(settingsStore.animationSpeed);
|
||||
});
|
||||
@@ -119,16 +125,27 @@ eventSource.addEventListener("message", async (message) => {
|
||||
});
|
||||
} else if (data.type == "endTurn") {
|
||||
queueAction(async () => {
|
||||
current_game.currentTurn.cardsLocked = [];
|
||||
current_game.currentTurn.effectsUsed = [];
|
||||
current_game.currentTurn.damage = 0;
|
||||
current_game.currentTurn.gold = 0;
|
||||
current_game.currentTurn = data.currentTurn;
|
||||
await delay(settingsStore.animationSpeed);
|
||||
const playingPlayer = current_game.teams.find(
|
||||
(t) => t._id == current_game.currentTurn.currentTeam
|
||||
)?.players[0];
|
||||
console.log(playingPlayer);
|
||||
if (playingPlayer) {
|
||||
focusPlayer(playingPlayer);
|
||||
await delay(settingsStore.animationSpeed);
|
||||
}
|
||||
});
|
||||
} else if (data.type == "lockCard") {
|
||||
queueAction(async () => {
|
||||
playSound("/sounds/lock.mp3");
|
||||
current_game.currentTurn.cardsLocked.push(data.card);
|
||||
});
|
||||
} else if (data.type == "joinGame") {
|
||||
queueAction(async () => {
|
||||
playSound("/sounds/teleport.mp3");
|
||||
current_game.teams.push(data.team);
|
||||
});
|
||||
} else if (data.type == "useEffect") {
|
||||
queueAction(async () => {
|
||||
current_game.currentTurn.effectsUsed.push(data.effect);
|
||||
@@ -141,8 +158,6 @@ eventSource.addEventListener("message", async (message) => {
|
||||
}
|
||||
});
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
const playerList = computed(() =>
|
||||
game.value!.teams.reduce((acc, t) => acc.concat(t.players), [] as Player[])
|
||||
);
|
||||
@@ -151,6 +166,13 @@ const selfPlayer = computed(() =>
|
||||
? playerList.value?.find((p) => p.user.userId == authStore.selfUser.userId)
|
||||
: undefined
|
||||
);
|
||||
const isTurn = computed(
|
||||
() =>
|
||||
selfPlayer.value &&
|
||||
game.value &&
|
||||
game.value.teams.find((t) => t.players.includes(selfPlayer.value!))?._id ==
|
||||
game.value.currentTurn.currentTeam
|
||||
);
|
||||
|
||||
// TODO : current turn sound
|
||||
|
||||
@@ -161,6 +183,8 @@ const selfPlayer = computed(() =>
|
||||
const showResults = ref(false);
|
||||
const isWinner = ref(false);
|
||||
const loaded = ref(false);
|
||||
const discard_unwrapped = ref(false);
|
||||
const focusedPlayer = ref<Player>(selfPlayer.value ?? playerList.value[0]);
|
||||
|
||||
function showLoserScreen() {
|
||||
// playSound('/sounds/ding.mp3')
|
||||
@@ -174,9 +198,6 @@ function showWinnerScreen() {
|
||||
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)
|
||||
@@ -202,7 +223,10 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<div @contextmenu.prevent="false" id="game_board" v-if="game">
|
||||
<AnimatedBackground @ready="loaded = true"></AnimatedBackground>
|
||||
<AnimatedBackground
|
||||
@ready="loaded = true"
|
||||
:isTurn="isTurn ?? false"
|
||||
></AnimatedBackground>
|
||||
<div id="stack_discard">
|
||||
<div id="stack">
|
||||
<CardsGrouped
|
||||
@@ -223,14 +247,25 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MarketCards :market="game.market" :fire_gems="game.fireGems"></MarketCards>
|
||||
<MarketCards
|
||||
:market="game.market"
|
||||
:fire_gems="game.fireGems"
|
||||
:marketStack="game.marketStack"
|
||||
></MarketCards>
|
||||
|
||||
<!-- <div id="player_list_container">
|
||||
<div id="player_list_container">
|
||||
<div id="player_list">
|
||||
<PlayerListElement v-for="p in playerList" :player="p" @click="focusPlayer(p)" :focused="focusedPlayer">
|
||||
<PlayerListElement
|
||||
v-for="p in playerList"
|
||||
:player="p"
|
||||
:game="game"
|
||||
@click="focusPlayer(p)"
|
||||
:focused="focusedPlayer == p"
|
||||
:self="selfPlayer == p"
|
||||
>
|
||||
</PlayerListElement>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div id="current_player">
|
||||
<PlayerSlot
|
||||
@@ -273,7 +308,12 @@ onUnmounted(() => {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#player_list,
|
||||
#player_list {
|
||||
display: flex;
|
||||
flex-direction: inherit;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#current_player {
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
|
||||
+8
-6
@@ -20,10 +20,13 @@ eventSource.addEventListener("message", (message) => {
|
||||
throw new Error("Couldn't delete game");
|
||||
}
|
||||
games.value.splice(index, 1);
|
||||
} else if (data.type == "update") {
|
||||
throw new Error("not implemented");
|
||||
} else if (data.type == "joinGame") {
|
||||
games.value.find((g) => g._id == data.game)?.teams.push(data.team);
|
||||
} else if (data.type == "start") {
|
||||
throw new Error("not implemented");
|
||||
const targetGame = games.value.find((g) => g._id == data.game);
|
||||
if (targetGame) {
|
||||
targetGame.started = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,9 +61,8 @@ onUnmounted(() => {
|
||||
authStore.selfUser.userId == g.owner.userId ? 'own_game' : ''
|
||||
"
|
||||
>
|
||||
<template v-if="g.started && g.ended"> GAME OVER </template>
|
||||
<template
|
||||
v-else-if="
|
||||
v-if="
|
||||
g.teams.every((t) =>
|
||||
t.players.every(
|
||||
(p) => p.user.userId !== authStore.selfUser.userId
|
||||
@@ -101,7 +103,7 @@ onUnmounted(() => {
|
||||
<img
|
||||
@click="router.push('/rules')"
|
||||
class="overlay-image"
|
||||
src="https://static.wikia.nocookie.net/umineko/img/9/9d/PC_Erika.Casual.Sprite_36.png"
|
||||
src="https://static.wikia.nocookie.net/umineko/images/9/9d/PC_Erika.Casual.Sprite_36.png"
|
||||
alt="pétasse"
|
||||
/>
|
||||
<div class="overlay-button">
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user