Feat : various fixes, sounds and multiplayer additions

This commit is contained in:
2024-07-03 23:27:10 +02:00
parent 866a537924
commit 25cf8a55e9
16 changed files with 433 additions and 272 deletions
+18 -17
View File
@@ -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>
+152 -115
View File
@@ -1,200 +1,237 @@
<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
})
wrapped: () => false,
tilted: () => 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 ".png"
})
if (settingsStore.cardStyle == CardStyles.SVG) {
return ".svg";
}
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
}
// User is Right Clicking
if ((e.buttons & 2) == 2) {
isZooming.value = true;
}
// goStore.hoveredCard = props.card_id
// 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) }">
<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>
<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">
<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>
<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"
/>
</div>
</template>
<style scoped>
.card {
--max-height: 250px;
--margin-bottom: calc(var(--max-height) * 0.05);
/* max-width: 256px; */
position: relative;
display: flex;
justify-content: center;
margin-bottom: 0px;
margin-top: var(--margin-bottom);
transition: all 0.075s cubic-bezier(1, 1.81, .59, 1.42);
isolation: isolate;
pointer-events: all;
max-height: var(--max-height);
--max-height: 250px;
--margin-bottom: calc(var(--max-height) * 0.05);
/* max-width: 256px; */
position: relative;
display: flex;
justify-content: center;
margin-bottom: 0px;
margin-top: var(--margin-bottom);
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 {
max-height: var(--max-height);
z-index: 1;
height: var(--max-height);
max-height: var(--max-height);
z-index: 1;
height: var(--max-height);
}
.card.wrapped {
height: 6px;
margin: 0;
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));
cursor: pointer;
margin-top: 0px;
margin-bottom: var(--margin-bottom);
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;
}
.card.zoom {
transform: scale(200%);
z-index: 10;
transform: scale(200%);
z-index: 10;
}
#contextMenuButtons {
position: absolute;
display: flex;
flex-direction: row;
flex-wrap: wrap;
word-break: break-word;
bottom: 0;
width: 99%;
transform: translateY(-0px);
transition: 0.1s transform cubic-bezier(1, 1.81, .59, 1.42);
position: absolute;
display: flex;
flex-direction: row;
flex-wrap: wrap;
word-break: break-word;
bottom: 0;
width: 99%;
transform: translateY(-0px);
transition: 0.1s transform cubic-bezier(1, 1.81, 0.59, 1.42);
}
.card.active:hover #contextMenuButtons {
transform: translateY(100%);
transform: translateY(100%);
}
</style>
<style>
.card.unlocked>* {
pointer-events: none;
.card.unlocked > * {
pointer-events: none;
}
#contextMenuButtons>* {
flex: 1;
border-radius: 12px;
min-height: 50px;
#contextMenuButtons > * {
flex: 1;
border-radius: 12px;
min-height: 50px;
}
@keyframes gelatine {
from,
to {
}
from,
to {}
25% {
transform: scale(1, 1.5);
}
25% {
transform: scale(1, 1.5);
}
50% {
transform: scale(1.5, 1);
}
50% {
transform: scale(1.5, 1);
}
75% {
transform: scale(1.1, 1.3);
}
75% {
transform: scale(1.1, 1.3);
}
}
.svg_resource_icon {
cursor: pointer;
animation: gelatine 0.3s normal;
transition: transform .1s cubic-bezier(0.175, 0.885, 0.32, 1.275);
cursor: pointer;
animation: gelatine 0.3s normal;
transition: transform 0.1s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.svg_resource_icon:active {
animation: none;
animation: none;
}
.svg_resource_icon:hover {
transform: scale(130%);
transform: scale(130%);
}
</style>
</style>
+18 -7
View File
@@ -55,13 +55,24 @@ function endAnimation() {
animationCallbacks.value.forEach((p) => p());
}
containerEvents.set(props.container._id, {
populateContainer,
shuffleContainer,
getCardsPosition,
startAnimation,
endAnimation,
});
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);
+6 -1
View File
@@ -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"
+23 -20
View File
@@ -1,40 +1,43 @@
<script setup lang="ts">
import type { Player } from '~/netcode/Player';
import type { Player } from "~/netcode/interfaces";
export interface Props {
player: Player;
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>
</div>
<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`"
draggable="false"
/>
<b class="player-name">{{ props.player.user.username }}</b>
</div>
</template>
<style scoped>
.player-icon-container {
display: flex;
align-items: center;
margin: 10px;
display: flex;
align-items: center;
margin: 10px;
}
.avatar {
height: 50px;
border-radius: 25px;
height: 50px;
border-radius: 25px;
}
.player-name {
font-size: 20px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin-left: 10px;
font-size: 20px;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
margin-left: 10px;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
}
</style>
</style>
+90 -79
View File
@@ -1,126 +1,137 @@
<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 {
player: Player;
focused?: Player
game: Game;
player: 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 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>
<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>
</div>
</div>
<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>
<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 :game="props.game" :player="props.player"> </PlayerStats>
<!-- </template> -->
</div>
</div>
</div>
</template>
<style scoped>
.player_list_element {
border-radius: 10px;
margin: 10px;
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, .60));
transform: translate(-2.5px, -7.5px);
backdrop-filter: blur(5px);
display: flex;
justify-content: center;
box-sizing: border-box;
transition: all .1s;
width: 300px;
cursor: pointer
border-radius: 10px;
margin: 10px;
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 0.1s;
width: 300px;
cursor: pointer;
}
.player_list_element::before {
border-radius: 10px;
background: rgb(15, 179, 255);
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: .5;
border-radius: 10px;
background: rgb(15, 179, 255);
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0.5;
}
.player_list_element.focused {
filter: unset;
transform: unset;
filter: unset;
transform: unset;
}
.player_list_element.isTurn::before {
opacity: .1;
opacity: 0.1;
}
.player_list_element.self::before {
background: rgb(33, 177, 76);
background: rgb(33, 177, 76);
}
#player_banner {
display: flex;
grid-area: player_stats;
flex-direction: row;
align-items: center;
justify-content: center;
position: sticky;
top: 0;
z-index: 1;
pointer-events: none;
display: flex;
grid-area: player_stats;
flex-direction: row;
align-items: center;
justify-content: center;
position: sticky;
top: 0;
z-index: 1;
pointer-events: none;
}
#player_banner.small {
flex-direction: row
flex-direction: row;
}
#player_banner>* {
pointer-events: all;
#player_banner > * {
pointer-events: all;
}
#player_stats {
display: flex;
grid-area: player_stats;
flex-direction: row;
align-items: center;
justify-content: center;
display: flex;
grid-area: player_stats;
flex-direction: row;
align-items: center;
justify-content: center;
}
.ready-bubble {
color: white;
padding: 0.5em;
border-radius: 1em;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
color: white;
padding: 0.5em;
border-radius: 1em;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.ready {
background-color: green;
background-color: green;
}
.not-ready {
background-color: maroon;
background-color: maroon;
}
</style>
</style>
+7 -2
View File
@@ -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"
+15 -3
View File
@@ -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>