255 lines
6.4 KiB
Vue
255 lines
6.4 KiB
Vue
<script setup lang="ts">
|
|
import { delay } from "~/netcode/events";
|
|
import {
|
|
CardEffects,
|
|
CardType,
|
|
type Card,
|
|
type Container,
|
|
type Effect,
|
|
type PlayingTurn,
|
|
} from "~/netcode/interfaces";
|
|
|
|
export interface Props {
|
|
container: Container;
|
|
playingTurn?: PlayingTurn;
|
|
wrapped?: boolean;
|
|
hidden?: boolean;
|
|
noEffects?: boolean;
|
|
tokens?: Effect[];
|
|
championsKillable?: boolean;
|
|
discardable?: boolean;
|
|
locked?: boolean;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
wrapped: () => false,
|
|
hidden: () => false,
|
|
noEffects: () => false,
|
|
tokens: () => [],
|
|
championsKillable: () => false,
|
|
discardable: () => false,
|
|
});
|
|
|
|
const emit = defineEmits([
|
|
"cardClick",
|
|
"effectClick",
|
|
"tokenClick",
|
|
"damageChampionClick",
|
|
"discardCardClick",
|
|
]);
|
|
|
|
const settingsStore = useSettingsStore();
|
|
|
|
const cards = computed(() => {
|
|
if (props.hidden) {
|
|
return props.container.cards.map((_v, i) => ({
|
|
cardId: undefined,
|
|
})) as unknown as Card[];
|
|
}
|
|
return props.container.cards;
|
|
});
|
|
|
|
const animationSpeed = computed(() => settingsStore.animationSpeed + "ms");
|
|
const shuffleAnimationSpeed = computed(
|
|
() => settingsStore.animationSpeed * 2 + "ms"
|
|
);
|
|
|
|
function populateContainer() { }
|
|
|
|
// const rotate = ref(false);
|
|
// async function shuffleContainer() {
|
|
// rotate.value = true;
|
|
// await delay(settingsStore.animationSpeed * 2);
|
|
// rotate.value = false;
|
|
// await delay(settingsStore.animationSpeed * 2);
|
|
// }
|
|
|
|
function getCardsPosition(cards: string) { }
|
|
|
|
const animationCallbacks = ref<Array<() => void>>([]);
|
|
|
|
function startAnimation() {
|
|
animationCallbacks.value.forEach((p) => p());
|
|
animationCallbacks.value = [];
|
|
}
|
|
|
|
function endAnimation() {
|
|
animationCallbacks.value.forEach((p) => p());
|
|
}
|
|
|
|
// 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);
|
|
// }
|
|
|
|
// async function onLeave(_el: any, done: () => void) {
|
|
// animationCallbacks.value.push(done);
|
|
// }
|
|
|
|
onUnmounted(() => {
|
|
// containerEvents.delete(props.container._id);
|
|
});
|
|
|
|
const interval = ref<ReturnType<typeof setInterval>>();
|
|
// function startMove() {
|
|
// interval.value = setInterval(() => {
|
|
// props.container.cards.sort((a, b) => Math.random() - 0.5);
|
|
// }, 1000);
|
|
// }
|
|
// function stopMove() {
|
|
// clearInterval(interval.value);
|
|
// }
|
|
|
|
function tokenClick(token: Effect, card: Card) {
|
|
emit("tokenClick", { token, card });
|
|
}
|
|
|
|
function damageChampionClick(card: Card) {
|
|
emit("damageChampionClick", card);
|
|
}
|
|
|
|
function discardCardClick(card: Card) {
|
|
emit("discardCardClick", card);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="cards_container" :class="{ wrapped, rotate: container.shuffling }">
|
|
<TransitionGroup name="list">
|
|
<GameCard @click="$emit('cardClick', c._id)" @effectClick="$emit('effectClick', c._id, $event)"
|
|
v-for="(c, i) in cards" :cardId="c?.cardId" :uuid="c._id" :wrapped="wrapped" :key="c?._id || i" :locked="locked ||
|
|
!playingTurn ||
|
|
playingTurn?.cardsLocked.includes(c._id.toString())
|
|
" :used_effects_indexes="c?.effects?.reduce((prev, e, i) => {
|
|
if (playingTurn?.lockedEffects.includes(e._id)) {
|
|
prev.push(i)
|
|
}
|
|
return prev
|
|
}, [] as number[])" :noEffects="noEffects" :discardable="discardable">
|
|
<template v-for="t in tokens">
|
|
<GameToken :token="t" @useToken="tokenClick(t, c)" v-if="
|
|
((t.effect == CardEffects.SACRIFICE &&
|
|
playingTurn &&
|
|
!playingTurn?.cardsLocked.includes(c._id.toString())) ||
|
|
(t.effect == CardEffects.PREPARE &&
|
|
c.cardType == CardType.CHAMPION) ||
|
|
(t.effect == CardEffects.STACK_NEXT_ACTION_BOUGHT &&
|
|
c.cardType == CardType.ACTION) ||
|
|
(t.effect == CardEffects.STUN &&
|
|
c.cardType == CardType.CHAMPION &&
|
|
championsKillable) ||
|
|
t.effect == CardEffects.PLAY_NEXT_CARD_BOUGHT ||
|
|
t.effect == CardEffects.STACK_NEXT_CARD_BOUGHT ||
|
|
t.effect == CardEffects.RESTACK_DISCARDED_CARD ||
|
|
(t.effect == CardEffects.RESTACK_DISCARDED_ACTION &&
|
|
c.cardType == CardType.ACTION) ||
|
|
(t.effect == CardEffects.RESTACK_DISCARDED_CHAMPION &&
|
|
c.cardType == CardType.CHAMPION)) && ((wrapped && i == (cards.length - 1)) || !wrapped)
|
|
"></GameToken>
|
|
</template>
|
|
<button v-if="championsKillable && c.cardType == CardType.CHAMPION" @click.stop="damageChampionClick(c)"
|
|
@mousedown.left.stop="">
|
|
Damage
|
|
</button>
|
|
<button v-if="
|
|
discardable && !playingTurn?.cardsLocked.includes(c._id.toString())
|
|
" @mousedown.left.stop="" @click.stop="discardCardClick(c)">
|
|
Discard
|
|
</button>
|
|
</GameCard>
|
|
</TransitionGroup>
|
|
<!-- <img :class="`card_image`" :src="'/cards/background.png'" draggable="false"> -->
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.list-move,
|
|
.list-enter-active,
|
|
.list-leave-active {
|
|
transition: all v-bind("animationSpeed") ease;
|
|
}
|
|
|
|
/* .list-leave-to, */
|
|
.list-enter-from {
|
|
opacity: 0;
|
|
/* transform: translateX(30px); */
|
|
}
|
|
|
|
.list-leave-active {
|
|
position: absolute;
|
|
height: unset;
|
|
}
|
|
|
|
.rotate {
|
|
rotate: 360deg;
|
|
}
|
|
|
|
.cards_container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
gap: 30px;
|
|
min-width: 200px;
|
|
flex-wrap: wrap;
|
|
transition: rotate v-bind("shuffleAnimationSpeed") ease;
|
|
}
|
|
|
|
.cards_container.wrapped {
|
|
flex-direction: column-reverse;
|
|
justify-content: center;
|
|
gap: 0;
|
|
}
|
|
|
|
.cards_container.wrapped:before {
|
|
height: calc(250px - 10px);
|
|
display: block;
|
|
content: "";
|
|
width: 0;
|
|
}
|
|
|
|
.empty {
|
|
max-height: 10px;
|
|
}
|
|
|
|
.empty>.card_image {
|
|
filter: brightness(0.5);
|
|
max-height: 250px;
|
|
}
|
|
</style>
|
|
|
|
<style>
|
|
use * use[data-effect-id="0"] {
|
|
opacity: 0;
|
|
}
|
|
|
|
.cards_container .card #background rect:first-child {
|
|
stroke-width: 0;
|
|
}
|
|
|
|
.cards_container .card.wrapped #background rect:first-child {
|
|
stroke-width: 1px;
|
|
}
|
|
|
|
.cards_container .card.card.wrapped:nth-child(5n) #background rect:first-child {
|
|
stroke-width: 2px;
|
|
}
|
|
</style>
|