489 lines
15 KiB
Vue
489 lines
15 KiB
Vue
<script setup lang="ts">
|
|
import goStore, {
|
|
useEffect,
|
|
playCard,
|
|
playAllCards,
|
|
discard,
|
|
lockCard,
|
|
heal,
|
|
damage_champion,
|
|
damage_team,
|
|
endTurn
|
|
|
|
} from "~/netcode";
|
|
import { CardType, type Card } from "~/netcode/Card";
|
|
import type { Player } from "~/netcode/Player";
|
|
import { CardEffects, type Effect, EffectType } from "@/netcode/Effect";
|
|
import type { Team } from "~/netcode/Team";
|
|
|
|
export interface Props {
|
|
player: Player;
|
|
hide_stack_and_discard?: boolean;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
hide_stack_and_discard: () => false,
|
|
})
|
|
|
|
const discard_unwrapped = ref(false)
|
|
const isPlayerTurn = computed(() => props.player.team === goStore.current_game?.current_turn);
|
|
const isSelf = computed(() => props.player.uuid === goStore.self?.uuid);
|
|
const isSelfTurn = computed(() => goStore.self?.team === goStore.current_game?.current_turn)
|
|
const isPlayerEnemy = computed(() => goStore.self?.team !== props.player.team)
|
|
|
|
function run_effect(
|
|
effect_type: CardEffects,
|
|
target: Player | Card
|
|
) {
|
|
if (!goStore.self?.turn) {
|
|
return
|
|
}
|
|
const effect = goStore.self?.turn.find_effect(effect_type);
|
|
if (!effect) {
|
|
return;
|
|
}
|
|
useEffect(effect, target);
|
|
}
|
|
|
|
const make_discard = (target: Player) =>
|
|
run_effect(CardEffects.MAKE_DISCARD, target);
|
|
const sacrifice = (target: Card) => run_effect(CardEffects.SACRIFICE, target);
|
|
const stun = (target: Card) => run_effect(CardEffects.STUN, target)
|
|
const restack_discarded_champion = (target: Card) => run_effect(CardEffects.RESTACK_DISCARDED_CHAMPION, target)
|
|
const restack_discarded_card = (target: Card) => run_effect(CardEffects.RESTACK_DISCARDED_CARD, target)
|
|
const prepare_champion = (target: Card) => run_effect(CardEffects.PREPARE, target)
|
|
|
|
|
|
let warning = ref(false)
|
|
|
|
function checkEndTurn() {
|
|
// TODO: Add a confirmation dialog if resources are left
|
|
console.log("Checking end turn")
|
|
if (
|
|
(!warning.value)
|
|
&& (
|
|
(goStore.self?.turn?.damage_reserve ? goStore.self?.turn?.damage_reserve > 0 : false)
|
|
|| (goStore.self?.turn?.gold_reserve ? goStore.self?.turn?.gold_reserve > 0 : false)
|
|
|| (goStore.self?.turn?.fuck_u_markers ? goStore.self?.turn?.fuck_u_markers > 0 : false)
|
|
)) {
|
|
// Set a warning flag to true
|
|
// Display an alert somehow using this warning flag
|
|
warning.value = true
|
|
}
|
|
else {
|
|
warning.value = false
|
|
endTurn()
|
|
}
|
|
}
|
|
|
|
function damage_team_all(team: Team) {
|
|
for (let i = 0; i < (goStore.self?.turn?.damage_reserve ?? 0); i++) {
|
|
damage_team(team)
|
|
}
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="`player ${isPlayerTurn ? 'turn' : ''} ${discard_unwrapped ? 'discard_unwrapped' : ''}`">
|
|
<template v-if="!hide_stack_and_discard">
|
|
<div class="stack">
|
|
|
|
<CardsGrouped :stack="props.player.stack_pile">
|
|
<!-- <button v-if="isSelf && isTurn" @click="draw">DRAW</button> -->
|
|
</CardsGrouped>
|
|
</div>
|
|
<div :id="`discard_unwrapped_bg`" :class="`${discard_unwrapped ? 'unwrapped' : ''}`"
|
|
@click="() => discard_unwrapped = false"></div>
|
|
<div :class="`discard ${discard_unwrapped ? 'unwrapped' : ''}`">
|
|
<div class="discard_container" @click="() => discard_unwrapped = true">
|
|
<CardsGrouped :stack="props.player.discard_pile" v-if="!discard_unwrapped"> </CardsGrouped>
|
|
<CardPreview :tilted="false" v-if="discard_unwrapped" :card_id="c.card_id"
|
|
v-for="c in props.player.discard_pile">
|
|
<template v-if="goStore.self?.turn && c && isSelf && isPlayerTurn">
|
|
|
|
<button v-if="goStore.self?.turn.find_effect(CardEffects.SACRIFICE)"
|
|
@click.stop="sacrifice(c)">
|
|
SACRIFICE
|
|
</button>
|
|
<button v-if="goStore.self?.turn.find_effect(CardEffects.RESTACK_DISCARDED_CHAMPION)"
|
|
@click.stop="restack_discarded_champion(c)">
|
|
RESTACK_DISCARDED_CHAMPION
|
|
</button>
|
|
<button v-if="goStore.self?.turn.find_effect(CardEffects.RESTACK_DISCARDED_CARD)"
|
|
@click.stop="restack_discarded_card(c)">
|
|
RESTACK_DISCARDED_CARD
|
|
</button>
|
|
|
|
</template>
|
|
</CardPreview>
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
<div id="player_banner">
|
|
<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 v-if="!hide_stack_and_discard">
|
|
<button id="end_turn" v-if="isSelfTurn" class="end_turn_button" @click="checkEndTurn">END TURN</button>
|
|
<div class="warning" v-if="warning">/!\<br> Effets restants!</div>
|
|
</template>
|
|
|
|
</template>
|
|
</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">
|
|
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">
|
|
(All)
|
|
</button>
|
|
<button v-if="goStore.self && isSelfTurn && isPlayerEnemy && goStore.self?.turn"
|
|
@click.stop="make_discard(props.player)"
|
|
class="make_discard_button"
|
|
:disabled="!goStore.self.turn.effects_availables.find((e: Effect) => (e.effect == CardEffects.MAKE_DISCARD) && e.usable)">
|
|
make Discard
|
|
</button>
|
|
</div>
|
|
<br />
|
|
|
|
<div class="cards_container">
|
|
<!-- HAND -->
|
|
<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>
|
|
<!-- BOARD -->
|
|
<CardPreview :card_id="c.card_id" v-for="c in props.player.board" @click="lockCard(c)"
|
|
:locked="props.player.turn && c.uuid in props.player.turn.cards_locked">
|
|
|
|
<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 props.player.turn.effects_availables">
|
|
<button v-if="e.card == c" @click.stop="useEffect(e)" :disabled="!e.usable" :class="{ 'suicide_effect': e.effect_type == EffectType.SUICIDE }" >
|
|
EFFECT<br>
|
|
{{ e.effect + " " + (e.effect_type ?? '') }}
|
|
</button>
|
|
</template>
|
|
<button
|
|
v-if="props.player.turn.find_effect(CardEffects.PREPARE) && 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="props.player.turn.find_effect(CardEffects.SACRIFICE)"
|
|
@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)"
|
|
@click.stop="damage_champion(c)">
|
|
DAMAGE ({{ c.health_as_champion }})
|
|
</button>
|
|
<button class="enemy_action" v-if="goStore.self?.turn.find_effect(CardEffects.STUN)"
|
|
@click.stop="stun(c)">
|
|
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: 85px;
|
|
font-size: 0.85em;
|
|
margin-left: 5px;
|
|
}
|
|
|
|
#end_turn {
|
|
z-index: 10;
|
|
height: 100%;
|
|
}
|
|
|
|
.stack,
|
|
.discard,
|
|
.cards_container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: center;
|
|
flex-wrap: wrap-reverse;
|
|
}
|
|
|
|
.stack {
|
|
grid-area: stack;
|
|
}
|
|
|
|
.discard {
|
|
margin-top: 50px;
|
|
grid-area: discard;
|
|
justify-content: start;
|
|
cursor: pointer;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.discard.unwrapped {
|
|
z-index: 9;
|
|
cursor: default;
|
|
position: absolute;
|
|
}
|
|
|
|
.discard_container {
|
|
display: flex;
|
|
/* background: blue; */
|
|
pointer-events: all;
|
|
}
|
|
|
|
#discard_unwrapped_bg {
|
|
display: none;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
height: 100%;
|
|
width: 100%;
|
|
z-index: 8;
|
|
background: rgba(0, 0, 0, 0.5)
|
|
}
|
|
|
|
#discard_unwrapped_bg.unwrapped {
|
|
display: block;
|
|
}
|
|
|
|
.player {
|
|
display: grid;
|
|
grid-template-columns: min-content 1fr;
|
|
grid-template-rows: min-content min-content 1fr;
|
|
/* border-top: 5px solid black; */
|
|
grid-template-areas:
|
|
"player_stats player_stats"
|
|
"stack player"
|
|
"discard player";
|
|
transition: all 1s;
|
|
}
|
|
|
|
.player.discard_unwrapped {
|
|
grid-template-areas:
|
|
"player_stats player_stats"
|
|
"stack player"
|
|
"discard discard";
|
|
}
|
|
|
|
#current_player_board {
|
|
grid-area: player;
|
|
}
|
|
|
|
.other_player_buttons_container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 0 5px;
|
|
}
|
|
|
|
.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_banner {
|
|
display: flex;
|
|
grid-area: player_stats;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: sticky;
|
|
top: 0;
|
|
padding-top: 1em;
|
|
z-index: 1;
|
|
}
|
|
|
|
#player_info {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
#player_stats {
|
|
display: flex;
|
|
grid-area: player_stats;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
#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: 5px 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 */
|
|
}
|
|
|
|
.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);
|
|
margin-bottom: 3%;
|
|
}
|
|
|
|
.ready {
|
|
background-color: green;
|
|
}
|
|
|
|
.not-ready {
|
|
background-color: maroon;
|
|
}
|
|
|
|
.suicide_effect {
|
|
background: linear-gradient(to bottom right, #666666, #ccc);
|
|
color: red;
|
|
}
|
|
</style>
|