Files
front/components/PlayerSlot.vue
T
legonzaur 0669619543
release-tag / release-image (push) Successful in 51s
Chore : attempt to reduce loading times
2024-07-31 10:20:48 +02:00

495 lines
15 KiB
Vue

<script setup lang="ts">
import {
damageChampion,
discardCard,
endTurn,
joinGame,
lockCard,
lockEffect,
startGame,
useToken,
} from "~/netcode";
import {
CardEffects,
type Card,
type Effect,
type Game,
type Player,
} from "~/netcode/interfaces";
import { useTurnStore } from "~/stores/turnStore";
export interface Props {
player: Player;
game: Game;
hide_stack_and_discard?: boolean;
}
const authStore = useAuthStore();
const props = withDefaults(defineProps<Props>(), {
hide_stack_and_discard: () => false,
});
const playerList = computed(() =>
props.game.teams.reduce((acc, t) => acc.concat(t.players), [] as Player[])
);
const selfPlayer = computed(() =>
authStore.logged
? playerList.value?.find((p) => p.user.userId == authStore.selfUser.userId)
: undefined
);
const currentTeam = computed(() =>
props.game.teams.find((t) => t._id == props.game.currentTurn.currentTeam)
);
const isPlayerTurn = computed(() =>
currentTeam.value?.players.some(
(p) => p.user.userId == authStore.selfUser.userId
)
);
const isSelf = computed(
() => props.player.user.userId === authStore.selfUser.userId
);
const isSelfTurn = computed(() => isSelf && isPlayerTurn);
const cardTokens = computed(() =>
props.game.currentTurn.tokens.filter(
(t) =>
[CardEffects.PREPARE, CardEffects.STUN].includes(t.effect) ||
(CardEffects.SACRIFICE == t.effect && isSelf)
)
);
const warningText = ref("Effets restants!");
// const make_discard = (target: Player) =>
// clientStore.findUseEffect(CardEffects.MAKE_DISCARD, target);
// const sacrifice = (target: CardParser) => clientStore.findUseEffect(CardEffects.SACRIFICE, target);
// const stun = (target: CardParser) => clientStore.findUseEffect(CardEffects.STUN, target)
// 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 prepare_champion = (target: CardParser) => clientStore.findUseEffect(CardEffects.PREPARE, target)
let warning = ref(false);
// function has_actions_remaining(): boolean {
// return (goStore.self?.turn?.damage_reserve ? goStore.self?.turn?.damage_reserve > 0 : false)
// || (goStore.self?.turn?.gold_reserve ? goStore.self?.turn?.gold_reserve >= (goStore.current_game?.market.reduce((min, card) => Math.min(min, card?.cost ?? Infinity), Infinity) ?? Infinity) : false)
// || (goStore.self?.turn?.fuck_u_markers ? goStore.self?.turn?.fuck_u_markers > 0 : false)
// || !goStore.self?.turn?.effects_availables.every(e => !e.usable || e.effect_type == EffectType.SUICIDE)
// || !goStore.self?.board.every(c => (c.uuid in (goStore.self?.turn?.cards_locked ?? {})))
// || false
// }
// function can_buy_fire_gem(): boolean {
// return (goStore.self?.turn?.gold_reserve ? goStore.self?.turn?.gold_reserve >= 2 : false)
// }
function checkEndTurn() {
// TODO: Add a confirmation dialog if resources are left
// if (
// (!warning.value)
// && has_actions_remaining()) {
// // Set a warning flag to true
// // Display an alert somehow using this warning flag
// warning.value = true
// }
// else if (!warning.value && can_buy_fire_gem()) {
// warningText.value = "P'tite Fire gem?"
// warning.value = true
// }
// else {
// warningText.value = "Effets restants!"
// warning.value = false
// endTurn()
// }
endTurn(props.game._id);
}
function boardCardClick(cardUUID: string) {
if (props.game.currentTurn.cardsLocked.includes(cardUUID)) {
//Card already locked
return;
}
lockCard(props.game._id, cardUUID);
}
function effectClick(cardUUID: string, effectIndex: number) {
const card = props.player.board.cards.find((c) => c._id == cardUUID);
if (!card) {
console.error("card not found");
return;
}
if (!props.game.currentTurn.cardsLocked.includes(cardUUID)) {
return;
}
const effectUUID = card.effects[effectIndex]._id;
lockEffect(props.game._id, effectUUID);
}
// function damage_team_all(team: Team) {
// for (let i = 0; i < (goStore.self?.turn?.damage_reserve ?? 0); i++) {
// damage_team(team)
// }
// }
// function check_for_guard(player: Player) {
// return player.board.some(c => c.guard === true)
// }
function tokenClick({ card, token }: { card: Card; token: Effect }) {
useToken(props.game._id, token._id, card._id, props.player._id);
}
function damageChampionClick(card: Card) {
damageChampion(props.game._id, props.player._id, card._id);
}
function discardCardClick(card: Card) {
discardCard(props.game._id, card._id);
}
</script>
<template>
<div class="player" :class="{ turn: isPlayerTurn, self: isSelf }">
<div id="turn_buttons">
<button
id="end_turn"
class="end_turn_button turn_icon"
:class="{ hidden: !isSelfTurn }"
@click="checkEndTurn"
>
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"
:class="{
'warning-fire-gem': warningText == 'P\'tite Fire gem?',
visible: warning,
}"
>
/!\<br />{{ warningText }}
</div>
</div>
<div id="current_player_board">
<!-- <div class="other_player_buttons_container">
<button @click.stop="damage_team(props.player.team)"
v-if="isSelfTurn && isPlayerEnemy && goStore.self?.turn && props.player.team" class="damage_button"
:disabled="(goStore.self?.turn.damage_reserve ?? 0) <= 0 || check_for_guard(props.player)">
Damage
</button>
<button @click.stop="damage_team_all(props.player.team)"
v-if="isSelfTurn && isPlayerEnemy && goStore.self?.turn && props.player.team"
class="damage_button all_damage_button"
:disabled="(goStore.self?.turn.damage_reserve ?? 0) <= 0 || check_for_guard(props.player)">
(All)
</button>
<button v-if="goStore.self && isSelfTurn && isPlayerEnemy && goStore.self?.turn"
@click.stop="make_discard(props.player)" class="make_discard_button"
:disabled="!clientStore.activatedClientside.find((e: Effect) => (e.effect == CardEffects.MAKE_DISCARD) && e.usable)">
make Discard
</button>
</div> -->
<!-- <br /> -->
<CardsGrouped
:container="player.board"
:wrapped="false"
:playingTurn="props.game.currentTurn"
@cardClick="boardCardClick"
@effectClick="effectClick"
:tokens="cardTokens"
@tokenClick="tokenClick"
:championsKillable="!isSelf && isSelfTurn.value"
:discardable="
(player.fuckUMarkers > 0 || player.discardMarkers > 0) && isSelf
"
@damageChampionClick="damageChampionClick"
@discardCardClick="discardCardClick"
>
</CardsGrouped>
<br>
<!-- <div class="cards_container"> -->
<!-- HAND -->
<!-- <template v-if="isSelf">
<CardPreview :card_id="c?.card_id" v-for="c in props.player.hand" @click="c && playCard(c)">
<button
v-if="props.player.turn && c && isSelf && (props.player.turn.discard_markers + props.player.turn.fuck_u_markers) > 0"
@click.stop="discard(c)">
DISCARD
</button>
</CardPreview>
</template> -->
<!-- BOARD -->
<!-- <CardPreview :card_id="c.cardId" v-for="c in props.player.board.cards"
@click="console.log/*lockCard(c)*/"
:locked="/*props.player.turn && c.uuid in props.player.turn.cards_locked*/ false"> -->
<!-- <template v-if="c && isSelf && isPlayerTurn && props.player.turn">
// Card Locked
<template v-if="c.uuid in props.player.turn.cards_locked">
<template v-for="e in clientStore.maskedServerEffects">
<template v-if="e.card == c">
<button v-if="!clientStore.effectsHandled.has(e.effect)" @click.stop="useEffect(e)"
:disabled="!e.usable"
:class="{ 'suicide_effect': e.effect_type == EffectType.SUICIDE }">
EFFECT<br>
{{ e.effect + " " + (e.effect_type ?? '') }}
</button>
<button v-if="clientStore.effectsHandled.has(e.effect)"
@click.stop="clientStore.activateEffect(e)" :disabled="!e.usable"
:class="{ 'suicide_effect': e.effect_type == EffectType.SUICIDE }">
EFFECT<br>
{{ e.effect + " " + (e.effect_type ?? '') }}
</button>
</template>
</template>
<button
v-if="clientStore.activatedClientside.find((e: Effect) => (e.effect == CardEffects.PREPARE) && e.usable) && c.card_type == CardType.CHAMPION"
@click.stop="prepare_champion(c)">PREPARE</button>
</template>
// Card Unlocked
<template v-if="!(c.uuid in props.player.turn.cards_locked)">
<button v-if="(props.player.turn.discard_markers + props.player.turn.fuck_u_markers) > 0"
@click.stop="discard(c)">
DISCARD
</button>
<button
v-if="clientStore.activatedClientside.find((e: Effect) => (e.effect == CardEffects.SACRIFICE) && e.usable)"
@click.stop="sacrifice(c)">
SACRIFICE
</button>
<button @click.stop="lockCard(c)"
:disabled="((props.player.turn.discard_markers + props.player.turn.fuck_u_markers) > 0 && c !== props.player.turn.discard_marker_card) || props.player.turn.fuck_u_markers > 0">
LOCK
</button>
</template>
</template>
<template
v-if="c && goStore.self?.turn && isPlayerEnemy && isSelfTurn && (c.health_as_champion ?? 0) > 0">
<button class="enemy_action"
:disabled="(goStore.self?.turn.damage_reserve ?? 0) < (c.health_as_champion ?? Infinity) || (check_for_guard(props.player) && !c.guard)"
@click.stop="damage_champion(c)">
DAMAGE ({{ c.health_as_champion }})
</button>
<button class="enemy_action"
v-if="clientStore.activatedClientside.find((e: Effect) => (e.effect == CardEffects.STUN) && e.usable)"
@click.stop="stun(c)" :disabled="(check_for_guard(props.player) && !c.guard)">
STUN
</button>
</template> -->
<!-- </CardPreview> -->
<!-- </div> -->
</div>
</div>
</template>
<style scoped>
.warning {
background-color: rgba(255, 0, 0, 0.7);
color: white;
padding: 5px;
border-radius: 5px;
width: 100px;
font-size: 0.85em;
margin-left: 5px;
visibility: hidden;
}
.warning.visible {
visibility: visible;
}
.warning-fire-gem {
background-color: rgba(255, 165, 0, 0.7);
}
#turn_buttons {
grid-area: turn_buttons;
}
#end_turn {
z-index: 10;
height: 100%;
}
#end_turn.hidden {
visibility: hidden;
}
.player {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: min-content 1fr;
/* border-top: 5px solid black; */
grid-template-areas:
"player_stats"
"player"
"turn_buttons";
justify-items: center;
transition: all 1s;
}
#current_player_board {
grid-area: player;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
max-width: 1200px;
}
.damage_button {
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 8px;
padding: 5px 25px;
margin: 5px 0 0 0;
font-size: 16px;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
transition: background-color 0.3s ease;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
}
.damage_button:disabled {
background-color: rgba(255, 77, 77, 0.5);
color: rgba(255, 255, 255, 0.5);
cursor: not-allowed;
}
.damage_button:hover {
background-color: #e60000;
}
.damage_button:disabled:hover {
background-color: rgba(230, 0, 0, 0.5);
}
.damage_button:active {
transform: translateY(2px);
box-shadow: none;
}
.all_damage_button {
padding: 5px 5px;
font-size: 14px;
}
.make_discard_button {
background-color: #55b42f;
color: white;
border: none;
border-radius: 8px;
padding: 5px 15px;
margin: 5px 0 0 0;
font-size: 16px;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
transition: background-color 0.3s ease;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
}
.make_discard_button:disabled {
background-color: rgba(85, 180, 47, 0.5);
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
cursor: not-allowed;
transition: background-color 0.3s ease;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
}
.make_discard_button:hover {
background-color: #03883a;
}
.make_discard_button:disabled:hover {
background-color: rgba(3, 136, 58, 0.5);
}
.make_discard_button:active {
transform: translateY(2px);
box-shadow: none;
}
.turn_icon {
position: relative;
}
#player_info {
display: flex;
align-items: center;
min-width: 200px;
}
#player_banner.big {
padding: 0;
left: 50%;
transform: translateX(-50%);
max-width: min-content;
border: 5px solid black;
border-radius: 10px;
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, 0.6));
backdrop-filter: blur(5px) brightness(80%) grayscale(80%);
}
#player_banner img {
height: 50px;
border-radius: 25px;
}
.turn_icon img {
height: 50px;
}
.turn_icon_number {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.end_turn_button {
background-color: #4caf50;
/* Green background color */
color: white;
border: none;
border-radius: 8px;
padding: 13px 10px;
margin: 0 0 0 5px;
font-size: 16px;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
transition: background-color 0.3s ease;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
}
.end_turn_button:hover {
background-color: #45a049;
/* Darker green on hover */
}
.end_turn_button:active {
transform: translateY(2px);
/* Add a slight press effect on click */
box-shadow: none;
/* Remove shadow on click */
}
.suicide_effect {
background: linear-gradient(to bottom right, #666666, #ccc);
color: red;
}
</style>