Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 45 additions & 9 deletions components/Object/Card/ObjectCardDeck.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const props = defineProps<{
// Stores
const boardStore = useBoardStore()
const levelStore = useLevelStore()
const cardStore = useCardStore()

// Handle dragging card decks
const hoveringOverBottomCard = ref(false)
Expand Down Expand Up @@ -57,16 +58,51 @@ const { getVisualComponentName } = useCardVisual()
:model-value="boardCard.currentHealth"
:max="boardCard.card.health"
/>
<div
:class="CardClasses"
@mouseenter="hoveringOverBottomCard = true"
@mouseleave="hoveringOverBottomCard = false"
<UPopover
mode="hover"
:open-delay="400"
arrow
>
<Component
:is="getVisualComponentName(boardCard.card)"
:board-card="boardCard"
/>
</div>
<div
:class="CardClasses"
@mouseenter="hoveringOverBottomCard = true"
@mouseleave="hoveringOverBottomCard = false"
>
<Component
:is="getVisualComponentName(boardCard.card)"
:board-card="boardCard"
/>
</div>

<template #content>
<div
class="w-[300px] !p-4"
>
<h2
class="!text-lg !font-bold"
v-text="boardCard.card.label"
/>
<p v-text="boardCard.card.description" />

<template v-if="boardCard.card.interactions?.length">
<br><hr><br>

<p class="!text-sm">
Can interact with:
</p>

<div class="!mt-1 !text-gray-200 !space-x-2">
<Icon
v-for="interaction in boardCard.card.interactions"
:key="interaction.card"
size="2em"
:name="cardStore.getCardByIdentifier(interaction.card)?.icon"
/>
</div>
</template>
</div>
</template>
</UPopover>

<ObjectCardDeckStacked
v-if="boardCard.stackedCard"
Expand Down
60 changes: 48 additions & 12 deletions components/Object/Card/ObjectCardDeckStacked.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const props = defineProps<{
// Usage of stores
const boardStore = useBoardStore()
const levelStore = useLevelStore()
const cardStore = useCardStore()

// Handle dragging card decks
const movedOnce = ref(false)
Expand Down Expand Up @@ -60,20 +61,55 @@ const classes = computed(() => {
</script>

<template>
<div
ref="card"
:style="style"
:class="classes"
<UPopover
mode="hover"
:open-delay="400"
arrow
>
<div
class="w-full h-full"
:class="{ 'absolute': movedOnce, 'scale-90': isDragging }"
:style="offset"
ref="card"
:style="style"
:class="classes"
>
<Component
:is="getVisualComponentName(boardCard.card)"
:board-card="boardCard"
/>
<div
class="w-full h-full"
:class="{ 'absolute': movedOnce, 'scale-90': isDragging }"
:style="offset"
>
<Component
:is="getVisualComponentName(boardCard.card)"
:board-card="boardCard"
/>
</div>
</div>
</div>

<template #content>
<div
class="w-[300px] !p-4"
>
<h2
class="!text-lg !font-bold"
v-text="boardCard.card.label"
/>
<p v-text="boardCard.card.description" />

<template v-if="boardCard.card.interactions?.length">
<br><hr><br>

<p class="!text-sm">
Can interact with:
</p>

<div class="!mt-1 !text-gray-200 !space-x-2">
<Icon
v-for="interaction in boardCard.card.interactions"
:key="interaction.card"
size="2em"
:name="cardStore.getCardByIdentifier(interaction.card)?.icon"
/>
</div>
</template>
</div>
</template>
</UPopover>
</template>
66 changes: 51 additions & 15 deletions components/Object/Card/ObjectCardSingle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const props = defineProps<{
// Use stores & composables
const boardStore = useBoardStore()
const levelStore = useLevelStore()
const cardStore = useCardStore()
const { activeCard } = storeToRefs(boardStore) // This is the card, the user is currently hovering above

const { hasInteractionWith, interact } = useInteraction(props.boardCard)
Expand Down Expand Up @@ -96,20 +97,55 @@ watch(playState, (state) => {
</script>

<template>
<div
ref="card"
:style="style"
:class="classes"
<UPopover
mode="hover"
:open-delay="400"
arrow
>
<UProgress
v-if="boardCard.timerProgress !== undefined"
:model-value="100 - (boardCard.timerProgress ?? 0)"
class="absolute -top-4"
color="neutral"
/>
<Component
:is="getVisualComponentName(boardCard.card)"
:board-card="boardCard"
/>
</div>
<div
ref="card"
:style="style"
:class="classes"
>
<UProgress
v-if="boardCard.timerProgress !== undefined"
:model-value="100 - (boardCard.timerProgress ?? 0)"
class="absolute -top-4"
color="neutral"
/>
<Component
:is="getVisualComponentName(boardCard.card)"
:board-card="boardCard"
/>
</div>

<template #content>
<div
class="w-[300px] !p-4"
>
<h2
class="!text-lg !font-bold"
v-text="boardCard.card.label"
/>
<p v-text="boardCard.card.description" />

<template v-if="boardCard.card.interactions?.length">
<br><hr><br>

<p class="!text-sm">
Can interact with:
</p>

<div class="!mt-1 !text-gray-200 !space-x-2">
<Icon
v-for="interaction in boardCard.card.interactions"
:key="interaction.card"
size="2em"
:name="cardStore.getCardByIdentifier(interaction.card)?.icon"
/>
</div>
</template>
</div>
</template>
</UPopover>
</template>
7 changes: 7 additions & 0 deletions composables/actions/win.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { CardsCollectionItem } from '@nuxt/content'
import type { BoardCard } from '~/types/Board'
import type { Action } from '~/types/Action'

export const win: Action = (_action: CardsCollectionItem['interactions'][0]['actions'][0], _baseCard: BoardCard, _interactingCard: BoardCard) => {
navigateTo('/win', { external: true })
}
2 changes: 2 additions & 0 deletions composables/useAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { travel } from './actions/travel'
import { destroyAll } from './actions/destroyAll'
import { destroyRandom } from './actions/destroyRandom'
import { random } from './actions/random'
import { win } from './actions/win'
import type { BoardCard } from '~/types/Board'
import type { Action } from '~/types/Action'
import { reveal } from '~/composables/actions/reveal'
Expand All @@ -33,6 +34,7 @@ const allActions: { [key: string]: Action } = {
destroyRandom,
random,
reveal,
win,
}

export const useAction = () => {
Expand Down
9 changes: 9 additions & 0 deletions composables/useCardTimer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const useCardTimer = () => {

card.timerTimeoutId = setTimeout(() => {
assert(card.card.timer?.actions !== undefined, `Card '${card.card.label}' with timer needs actions`)
if (card.isDead) return

runActions(card.card.timer.actions, card, card)
}, (card.card.timer.time ?? 0) * 1000)
Expand All @@ -25,7 +26,15 @@ export const useCardTimer = () => {
}, 10)
}

const reset = (card: BoardCard) => {
if (card.timerTimeoutId) clearTimeout(card.timerTimeoutId)
if (card.timerIntervalId) clearInterval(card.timerIntervalId)

card.timerStartAt = card.timerFinishAt = card.timerProgress = card.timerTimeoutId = card.timerIntervalId = undefined
}

return {
init,
reset,
}
}
11 changes: 10 additions & 1 deletion composables/useInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const useInteraction = (draggingCard: BoardCard) => {
const boardStore = useBoardStore()
const { runActions } = useAction()
const { startCooldown } = useCardCooldown()
const { reset } = useCardTimer()

const getAvailableInteractions = (boardCard: BoardCard): string[] => {
return (boardCard.card.interactions ?? []).map(interaction => interaction.card)
Expand Down Expand Up @@ -43,6 +44,10 @@ export const useInteraction = (draggingCard: BoardCard) => {
}

boardCard.currentInteraction = interaction
if (boardCard.card.timer?.resetWhenCardIsStacked) {
reset(boardCard)
}

if ((interaction.time ?? 0) <= 0) {
runInteractionActions(boardCard)
return
Expand Down Expand Up @@ -73,7 +78,7 @@ export const useInteraction = (draggingCard: BoardCard) => {

runActions(boardCard.currentInteraction.actions, boardCard, draggingCard)

if (boardCard.currentInteraction.consumeContainer && boardCard.amount !== null) {
if (boardCard.currentInteraction?.consumeContainer && boardCard.amount !== null) {
boardCard.amount = clamp(boardCard.amount - 1, 0, boardCard.card.containerMax ?? 0)
}

Expand All @@ -84,13 +89,17 @@ export const useInteraction = (draggingCard: BoardCard) => {
if (boardCard.currentHealth !== null && boardCard.currentHealth <= 0) {
runActions(boardCard.card.onDeath ?? [], boardCard, draggingCard)
boardStore.removeCard(boardCard)
boardCard.isDead = true
reset(boardCard)
someoneDied = true
}

// If the interacting card has health and is now down to 0 health, remove it
if (draggingCard.currentHealth !== null && draggingCard.currentHealth <= 0) {
runActions(draggingCard.card.onDeath ?? [], boardCard, draggingCard)
boardStore.removeCard(draggingCard)
draggingCard.isDead = true
reset(draggingCard)
someoneDied = true
}

Expand Down
2 changes: 2 additions & 0 deletions content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineContentConfig({
identifier: z.string(),
extend: z.string().optional(),
label: z.string(),
description: z.string(),
icon: z.string().default('material-symbols:man-rounded'),
iconColor: z.string().optional().default('#000000'),
health: z.number().gte(0).lte(20).optional(),
Expand All @@ -54,6 +55,7 @@ export default defineContentConfig({
onSpawn: actionsType,
timer: z.object({
time: z.number().positive().default(0),
resetWhenCardIsStacked: z.boolean().default(false),
actions: actionsType,
}).optional(),
}),
Expand Down
1 change: 1 addition & 0 deletions content/cards/asteroid.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "asteroid",
"label": "Asteroid",
"description": "A small asteroid. Destroys a random card on impact and can be mined to get metal",
"icon": "tabler:meteor",
"health": 10,
"type": "enemy",
Expand Down
1 change: 1 addition & 0 deletions content/cards/asteroidField.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"identifier": "asteroid-field",
"description": "Can be mined to get a bunch of metal. Disappears after some time",
"label": "Asteroid Field",
"icon": "mdi:focus-field",
"type": "event",
Expand Down
1 change: 1 addition & 0 deletions content/cards/baby.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "baby",
"label": "Baby",
"description": "Small human. Will grow to be a large human.",
"icon": "hugeicons:baby-02",
"health": 2,
"type": "person",
Expand Down
1 change: 1 addition & 0 deletions content/cards/brainrot.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "brainrot",
"label": "Brainrot",
"description": "What the sigma? Bruh, this will uneducate anyone! No cap.",
"icon": "mdi:brain",
"type": "limitedUsage",
"buyable": true,
Expand Down
1 change: 1 addition & 0 deletions content/cards/distressSignal.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "distress-signal",
"label": "Distress Signal",
"description": "Someone needs our help! Or is it a trap?",
"icon": "oui:security-signal-detected",
"type": "event",
"interactions": [
Expand Down
1 change: 1 addition & 0 deletions content/cards/duck.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "duck",
"label": "Duck",
"description": "Quack.",
"icon": "icon-park-outline:duck",
"type": "person",
"buyable": true,
Expand Down
1 change: 1 addition & 0 deletions content/cards/fire-extinguisher.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "fire-extinguisher",
"label": "Fire Extinguisher",
"description": "This can safely extinguish fires. It's a bit expensive though.",
"icon": "material-symbols:fire-extinguisher-outline",
"type": "limitedUsage",
"health": 3,
Expand Down
1 change: 1 addition & 0 deletions content/cards/fire.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"identifier": "fire",
"label": "Fire",
"description": "It's a fire! Don't throw fuel at it!",
"icon": "noto-v1:fire",
"health": 10,
"type": "enemy",
Expand Down
Loading