Feat : add fast animations option, move netcode handlers inside dict
release-tag / release-image (push) Successful in 29s

This commit is contained in:
2024-07-31 11:11:19 +02:00
parent c1bbf7dce4
commit 2e8046f81c
5 changed files with 239 additions and 308 deletions
+29 -55
View File
@@ -218,26 +218,16 @@ onUnmounted(() => {
</script>
<template>
<div
ref="card"
class="card"
:class="{
dragging: dragStatus.dragging,
active: childCount > 0,
wrapped,
unlocked: !props.locked,
zoom: isZooming,
no_effects: noEffects || !props.locked,
discardable,
}"
@contextmenu.prevent="false"
@mousedown.right="rightClickDown"
@mouseup.right="rightClickUp"
@mousedown.left="leftClickDown"
@mouseup.left="leftClickUp"
@mouseenter="mouseenter"
@mouseleave="mouseleave"
>
<div ref="card" class="card" :class="{
dragging: dragStatus.dragging,
active: childCount > 0,
wrapped,
unlocked: !props.locked,
zoom: isZooming,
no_effects: noEffects || !props.locked,
discardable,
}" @contextmenu.prevent="false" @mousedown.right="rightClickDown" @mouseup.right="rightClickUp"
@mousedown.left="leftClickDown" @mouseup.left="leftClickUp" @mouseenter="mouseenter" @mouseleave="mouseleave">
<template v-if="props.card_id">
<!-- <svg
width="180"
@@ -256,43 +246,29 @@ onUnmounted(() => {
@activate_effect="activateEffect($event)"
></use>
</svg> -->
<CardComponent
v-if="settingsStore.cardStyle == CardStyles.SVG && props.card"
:card="props.card"
:used_effects_indexes="used_effects_indexes"
@effectClick="emit('effectClick', $event)"
></CardComponent>
<img
:class="`card_image`"
v-else
:src="
`/cards/${settingsStore.cardStyle}/` +
props.card_id.toString().padStart(3, '0') +
extension
"
draggable="false"
/>
<div id="overlay"><slot></slot></div>
<CardComponent v-if="settingsStore.cardStyle == CardStyles.SVG && props.card" :card="props.card"
:used_effects_indexes="used_effects_indexes" @effectClick="emit('effectClick', $event)"></CardComponent>
<img :class="`card_image`" v-else :src="`/cards/${settingsStore.cardStyle}/` +
props.card_id.toString().padStart(3, '0') +
extension
" draggable="false" />
<div id="overlay">
<slot></slot>
</div>
</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>
.card.dragging {
transform: translateX(v-bind("translateX + 'px'"))
translateY(v-bind("translateY + 'px'"));
transform: translateX(v-bind("translateX + 'px'")) translateY(v-bind("translateY + 'px'"));
cursor: grabbing;
z-index: 999;
}
.card.dragging > svg {
.card.dragging>svg {
transform: scale(110%);
}
@@ -312,8 +288,7 @@ onUnmounted(() => {
}
.card.wrapped .card_image {
filter: drop-shadow(0.5px 0.5px 0.5px gray)
drop-shadow(-0.5px -0.5px 0.5px gray);
filter: drop-shadow(0.5px 0.5px 0.5px gray) drop-shadow(-0.5px -0.5px 0.5px gray);
}
.card.zoom {
@@ -338,20 +313,20 @@ onUnmounted(() => {
}
</style>
<style>
.card.no_effects svg > * {
.card.no_effects svg>* {
pointer-events: none;
}
#contextMenuButtons > * {
#contextMenuButtons>* {
flex: 1;
border-radius: 12px;
min-height: 50px;
}
@keyframes gelatine {
from,
to {
}
to {}
25% {
transform: scale(1, 1.5);
@@ -379,6 +354,7 @@ onUnmounted(() => {
.svg_resource_icon:hover {
transform: scale(130%);
}
.used {
opacity: 0.2;
filter: grayscale(0.6);
@@ -420,9 +396,7 @@ onUnmounted(() => {
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)
);
filter: drop-shadow(calc(var(--margin-bottom) * 0.3) var(--margin-bottom) 1px rgba(0, 0, 0, 0.6));
cursor: pointer;
}
+6 -21
View File
@@ -61,29 +61,14 @@ function tokenClick({ card, token }: { card: Card; token: Effect }) {
<template>
<div class="market">
<CardsGrouped
:container="marketStack"
:wrapped="true"
:hidden="true"
></CardsGrouped>
<div class="separator"></div>
<CardsGrouped
:container="market"
@cardClick="marketCardClick"
:noEffects="true"
:tokens="marketTokens"
@tokenClick="tokenClick"
>
<CardsGrouped :container="market" @cardClick="marketCardClick" :noEffects="true" :tokens="marketTokens"
@tokenClick="tokenClick">
</CardsGrouped>
<div class="separator"></div>
<CardsGrouped
:container="fire_gems"
:wrapped="true"
@cardClick="fireGemCardClick"
:noEffects="true"
:tokens="gemsTokens"
@tokenClick="tokenClick"
></CardsGrouped>
<CardsGrouped :container="fire_gems" :wrapped="true" @cardClick="fireGemCardClick" :noEffects="true"
:tokens="gemsTokens" @tokenClick="tokenClick"></CardsGrouped>
<div class="separator"></div>
<CardsGrouped :container="marketStack" :wrapped="true" :hidden="true"></CardsGrouped>
</div>
</template>
+29 -33
View File
@@ -38,17 +38,17 @@ const close = () => {
<span>Animation Speed</span>
</div>
<div class="dialog-body">
<input
type="range"
min="0"
max="250"
step="25"
v-model="settingsStore.animationSpeed"
/>
<input type="range" min="0" max="250" step="25" v-model="settingsStore.animationSpeed" />
</div>
<div class="dialog-footer">
<span>{{ settingsStore.animationSpeed }}ms</span>
</div>
<div class="dialog-header">
<span>Fast mode</span>
</div>
<div class="dialog-body">
<input type="checkbox" v-model="settingsStore.fastAnimations" />
</div>
<div class="dialog-header">
<h3>Graphics</h3>
</div>
@@ -56,44 +56,31 @@ const close = () => {
<span>Shader Quality</span>
</div>
<div class="dialog-body">
<input
type="range"
min="1"
max="10"
v-model="settingsStore.shaderQuality"
:disabled="settingsStore.shaderFramerate == 0"
/>
<input type="range" min="1" max="10" v-model="settingsStore.shaderQuality"
:disabled="settingsStore.shaderFramerate == 0" />
</div>
<div class="dialog-footer">
<span
>{{
Math.floor(
(_window.innerWidth *
_devicePixelRatio *
settingsStore.shaderQuality) /
10
)
}}x{{
<span>{{
Math.floor(
(_window.innerWidth *
_devicePixelRatio *
settingsStore.shaderQuality) /
10
)
}}x{{
Math.floor(
(_window.innerHeight *
_devicePixelRatio *
settingsStore.shaderQuality) /
10
10
)
}}</span
>
}}</span>
</div>
<div class="dialog-header">
<span>Shader Framerate</span>
</div>
<div class="dialog-body">
<input
type="range"
min="0"
max="65"
step="5"
v-model="settingsStore.shaderFramerate"
/>
<input type="range" min="0" max="65" step="5" v-model="settingsStore.shaderFramerate" />
</div>
<div class="dialog-footer">
<span v-if="settingsStore.shaderFramerate == 65">vsync</span>
@@ -105,6 +92,15 @@ const close = () => {
<div class="dialog-body">
<input type="checkbox" v-model="settingsStore.shaderPixelated" />
</div>
<div class="dialog-header">
<h3>Other</h3>
</div>
<div class="dialog-header">
<span>Enable dragging (experimental)</span>
</div>
<div class="dialog-body">
<input type="checkbox" v-model="settingsStore.enableDragging" />
</div>
</div>
</div>
</template>
+174 -199
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import LoadingScreen from "~/components/LoadingScreen.vue";
import { subscribe, useToken } from "~/netcode";
import { endTurn, subscribe, useToken } from "~/netcode";
import { delay } from "~/netcode/events";
import {
type Container,
@@ -68,6 +68,176 @@ async function execAction(callback: () => Promise<any>) {
}
}
const handlers = {
start: async () => {
throw new Error("not implemented")
},
populateContainer: async (data: any) => {
const fromContainer = containers.value[data.container._id as string];
playSound("/sounds/distribute.mp3");
for (const card of data.container.cards) {
fromContainer.cards.push(card);
// if (!settingsStore.fastAnimations) {
// await delay(settingsStore.animationSpeed);
// }
}
},
shuffleContainer: async (data: any) => {
playSound("/sounds/shuffle.mp3");
const container = containers.value[data.container as string];
container.shuffling = true;
await delay(settingsStore.animationSpeed * 2);
container.shuffling = false;
await delay(settingsStore.animationSpeed * 2);
},
distributeCards: async (data: any) => {
const fromContainer = containers.value[data.from as string];
const toContainer = containers.value[data.to as string];
if (settingsStore.fastAnimations) {
playSound("/sounds/distribute.mp3");
}
for (const card of data.cards) {
const index = fromContainer.cards.findIndex(
(c) => !c || c._id == card._id
);
fromContainer.cards.splice(index, 1);
if (!settingsStore.fastAnimations) {
await delay(settingsStore.animationSpeed);
playSound("/sounds/distribute.mp3");
}
toContainer.cards.push(card);
if (!settingsStore.fastAnimations) {
await delay(settingsStore.animationSpeed);
}
}
await delay(settingsStore.animationSpeed * 2);
},
endTurn: async (data: any, game: Game) => {
game.currentTurn = data.currentTurn;
await delay(settingsStore.animationSpeed);
const playingPlayer = game.teams.find(
(t) => t._id == game.currentTurn.currentTeam
)?.players[0];
if (playingPlayer) {
focusPlayer(playingPlayer);
await delay(settingsStore.animationSpeed);
}
},
lockCard: async (data: any, game: Game) => {
playSound("/sounds/lock.mp3");
game.currentTurn.cardsLocked.push(data.card);
await delay(settingsStore.animationSpeed);
},
destroyCard: async (data: any) => {
const fromContainer = containers.value[data.from as string];
const index = fromContainer.cards.findIndex(
(c) => !c || c._id == data.card
);
fromContainer.cards.splice(index, 1);
playSound("/sounds/destroy.mp3");
await delay(settingsStore.animationSpeed);
},
joinGame: async (data: any, game: Game) => {
playSound("/sounds/teleport.mp3");
game.teams.push(data.team);
},
lockEffect: async (data: any, game: Game) => {
game.currentTurn.lockedEffects.push(data.effect);
await delay(settingsStore.animationSpeed);
},
unlockEffect: async (data: any, game: Game) => {
const effectIndex = game.currentTurn.lockedEffects.indexOf(
data.effect
);
game.currentTurn.lockedEffects.splice(effectIndex, 1);
await delay(settingsStore.animationSpeed);
},
"currentTurn.updateGold": async (data: any, game: Game) => {
console.log(`adding gold amount : ` + data.operation);
game.currentTurn.gold = data.gold;
},
"currentTurn.updateDamage": async (data: any, game: Game) => {
console.log(`adding damage amount : ` + data.operation);
game.currentTurn.damage = data.damage;
},
"currentTurn.addToken": async (data: any, game: Game) => {
game.currentTurn.tokens.push(data.token);
await delay(settingsStore.animationSpeed);
},
"currentTurn.useToken": async (data: any, game: Game) => {
const index = game.currentTurn.tokens.findIndex(
(t) => t._id == data.tokenId
);
game.currentTurn.tokens.splice(index, 1);
if (!settingsStore.fastAnimations) {
await delay(settingsStore.animationSpeed);
}
},
"team.updateHealth": async (data: any, game: Game) => {
const team = game.teams.find((t) => t._id == data.team);
if (!team) {
throw new Error("Team not found");
}
console.log(`adding health amount : ` + data.operation);
team.health = data.health;
},
"player.addFuckUMarker": async (data: any, game: Game) => {
console.log(`adding fuckUMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot add fuckU Markers : player not found");
}
targetPlayer.fuckUMarkers = data.fuckUMarkers;
},
"player.removeFuckUMarker": async (data: any, game: Game) => {
console.log(`adding fuckUMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot remove fuckU Markers : player not found");
}
targetPlayer.fuckUMarkers = data.fuckUMarkers;
},
"player.addDiscardMarker": async (data: any, game: Game) => {
console.log(`adding discardMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot add discard Markers : player not found");
}
targetPlayer.discardMarkers = data.discardMarkers;
},
"player.removeDiscardMarker": async (data: any, game: Game) => {
console.log(`adding fuckUMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot remove discard Markers : player not found");
}
targetPlayer.discardMarkers = data.discardMarkers;
},
killTeam: async (data: any, game: Game) => {
const index = game.teams.findIndex((t) => t._id == data.teamId);
if (!index) {
console.error("team index not found. Desyncs might happen");
await refresh();
return;
}
game.teams.splice(index, 1);
},
consumeEffect: async (data: any) => {
console.warn("consumeEffect not implemented")
},
endGame: async () => {
alert("game ended")
}
}
onMounted(async () => {
awaitGameReady.then(() => {
console.log(game.value)
@@ -84,204 +254,9 @@ onMounted(async () => {
throw new Error("game not found");
}
const data = JSON.parse(message.data);
console.log(data);
if (data.type == "start") {
throw new Error("not implemented");
} else if (data.type == "populateContainer") {
queueAction(async () => {
// await containerEvents.get(data.container)?.startAnimation();
});
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);
}
});
queueAction(async () => {
// await containerEvents.get(data.container)?.endAnimation();
});
} else if (data.type == "shuffleContainer") {
queueAction(async () => {
playSound("/sounds/shuffle.mp3");
const container = containers.value[data.container as string];
container.shuffling = true;
await delay(settingsStore.animationSpeed * 2);
container.shuffling = false;
await delay(settingsStore.animationSpeed * 2);
});
} else if (data.type == "distributeCards") {
// containerEvents.get(data.from)?.getCardsPosition(data.cards)
queueAction(async () => {
// containerEvents.get(data.from)?.startAnimation();
// containerEvents.get(data.to)?.startAnimation();
});
const fromContainer = containers.value[data.from as string];
const toContainer = containers.value[data.to as string];
for (const card of data.cards) {
queueAction(async () => {
const index = fromContainer.cards.findIndex(
(c) => !c || c._id == card._id
);
fromContainer.cards.splice(index, 1);
await delay(settingsStore.animationSpeed);
});
queueAction(async () => {
playSound("/sounds/distribute.mp3");
toContainer.cards.push(card);
await delay(settingsStore.animationSpeed);
});
}
queueAction(async () => {
// containerEvents.get(data.from)?.endAnimation();
// containerEvents.get(data.to)?.endAnimation();
await delay(settingsStore.animationSpeed * 2);
});
} else if (data.type == "endTurn") {
queueAction(async () => {
current_game.currentTurn = data.currentTurn;
await delay(settingsStore.animationSpeed);
const playingPlayer = current_game.teams.find(
(t) => t._id == current_game.currentTurn.currentTeam
)?.players[0];
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);
await delay(settingsStore.animationSpeed);
});
} else if (data.type == "destroyCard") {
const fromContainer = containers.value[data.from as string];
queueAction(async () => {
const index = fromContainer.cards.findIndex(
(c) => !c || c._id == data.card
);
fromContainer.cards.splice(index, 1);
await delay(settingsStore.animationSpeed);
});
queueAction(async () => {
playSound("/sounds/destroy.mp3");
await delay(settingsStore.animationSpeed);
});
} else if (data.type == "joinGame") {
queueAction(async () => {
playSound("/sounds/teleport.mp3");
current_game.teams.push(data.team);
});
} else if (data.type == "lockEffect") {
queueAction(async () => {
current_game.currentTurn.lockedEffects.push(data.effect);
await delay(settingsStore.animationSpeed);
});
} else if (data.type == "unlockEffect") {
queueAction(async () => {
const effectIndex = current_game.currentTurn.lockedEffects.indexOf(
data.effect
);
current_game.currentTurn.lockedEffects.splice(effectIndex, 1);
await delay(settingsStore.animationSpeed);
});
} else if (data.type == "currentTurn.updateGold") {
queueAction(async () => {
console.log(`adding gold amount : ` + data.operation);
current_game.currentTurn.gold = data.gold;
});
} else if (data.type == "currentTurn.updateDamage") {
queueAction(async () => {
console.log(`adding damage amount : ` + data.operation);
current_game.currentTurn.damage = data.damage;
});
} else if (data.type == "currentTurn.addToken") {
queueAction(async () => {
current_game.currentTurn.tokens.push(data.token);
await delay(settingsStore.animationSpeed);
});
} else if (data.type == "currentTurn.useToken") {
queueAction(async () => {
const index = current_game.currentTurn.tokens.findIndex(
(t) => t._id == data.tokenId
);
current_game.currentTurn.tokens.splice(index, 1);
await delay(settingsStore.animationSpeed);
});
} else if (data.type == "team.updateHealth") {
queueAction(async () => {
const team = game.value?.teams.find((t) => t._id == data.team);
if (!team) {
throw new Error("Team not found");
}
console.log(`adding health amount : ` + data.operation);
team.health = data.health;
});
} else if (data.type == "player.addFuckUMarker") {
queueAction(async () => {
console.log(`adding fuckUMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot add fuckU Markers : player not found");
}
targetPlayer.fuckUMarkers = data.fuckUMarkers;
});
} else if (data.type == "player.removeFuckUMarker") {
queueAction(async () => {
console.log(`adding fuckUMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot remove fuckU Markers : player not found");
}
targetPlayer.fuckUMarkers = data.fuckUMarkers;
});
} else if (data.type == "player.addDiscardMarker") {
queueAction(async () => {
console.log(`adding discardMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot add discard Markers : player not found");
}
targetPlayer.discardMarkers = data.discardMarkers;
});
} else if (data.type == "player.removeDiscardMarker") {
queueAction(async () => {
console.log(`adding fuckUMarkers : ` + data.operation);
const targetPlayer = playerList.value?.find(
(p) => p._id == data.playerId
);
if (!targetPlayer) {
throw new Error("Cannot remove discard Markers : player not found");
}
targetPlayer.discardMarkers = data.discardMarkers;
});
} else if (data.type == "killTeam") {
queueAction(async () => {
const index = game.value?.teams.findIndex((t) => t._id == data.teamId);
if (!index) {
console.error("team index not found. Desyncs might happen");
await refresh();
return;
}
game.value?.teams.splice(index, 1);
});
} else if (data.type == "endGame") {
queueAction(async () => {
alert("game Ended");
});
}
queueAction(async () => {
await handlers[data.type as keyof typeof handlers](data, current_game)
})
});
})
+1
View File
@@ -10,6 +10,7 @@ export const useSettingsStore = defineStore("settingstore", {
state: () => ({
cardStyle: CardStyles.SVG,
animationSpeed: 100,
fastAnimations: false,
shaderQuality: 3,
shaderFramerate: 10,
shaderPixelated: true,