Implemented merging/levels

This commit is contained in:
thepaperpilot 2023-02-18 18:09:06 -06:00
parent 17ffc977fb
commit b0e0f8aeac
5 changed files with 175 additions and 37 deletions

View file

@ -10,6 +10,10 @@
<link rel="alternate icon" type="image/png" sizes="48x48" href="/favicon.ico">
<meta name="theme-color" content="#2E3440">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Mynerve&display=swap" rel="stylesheet">
<title>Profectus</title>
<meta name="description" content="A project made in Profectus"/>

View file

@ -1,9 +1,26 @@
<template>
<Tooltip
:display="character ? characters[character.type].nickname : ''"
:display="character && selected == null ? characters[character.type].nickname : ''"
:direction="Direction.Up"
>
<div class="character" :class="{ selected, empty: character == null }">
<div
class="character"
:class="{ selected: isSelected, empty: character == null && selected == null }"
>
<span class="move-indicator" v-if="character == null && selected != null">
<span class="material-icons">straight</span></span
>
<span
class="move-indicator"
v-if="
character != null &&
selected != null &&
!isSelected &&
character.type === selected.type &&
character.exp < 6
"
><span class="material-icons">merge</span></span
>
<span class="character-display" v-if="character != null">
<img :src="characters[character.type].display" />
</span>
@ -15,6 +32,18 @@
<span class="material-icons"> extension </span>
{{ character?.presence }}
</span>
<span class="level-display" v-if="character != null">
<span class="level">{{ level }}</span>
<span class="segments">
<span
v-for="i in segments"
:key="i"
class="segment"
:class="{ filled: filledSegments >= i }"
>
</span>
</span>
</span>
</div>
</Tooltip>
</template>
@ -22,16 +51,39 @@
<script setup lang="ts">
import Tooltip from "features/tooltips/Tooltip.vue";
import { Direction } from "util/common";
import { computed, watch } from "vue";
import { characters } from "./projEntry";
defineProps<{
character?: {
type: string;
relevancy: number;
presence: number;
} | null;
selected?: boolean;
const props = defineProps<{
character?: Character | null;
isSelected?: boolean;
selected?: Character | null;
}>();
const level = computed(() => {
const exp = props.character?.exp ?? 0;
if (exp < 3) {
return 1;
}
if (exp < 6) {
return 2;
}
return 3;
});
const segments = computed(() => {
const exp = props.character?.exp ?? 0;
if (exp < 3) {
return 2;
}
return 3;
});
const filledSegments = computed(() => {
const exp = props.character?.exp ?? 0;
if (exp < 3) {
return exp - 1;
}
return exp - 3;
});
</script>
<style scoped>
@ -81,6 +133,7 @@ defineProps<{
left: 0;
right: 0;
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='%2388C0D0' stroke-width='8' stroke-dasharray='10%25%2c90%25' stroke-dashoffset='5' stroke-linecap='square'/%3e%3c/svg%3e");
transform: scale(1.5);
}
.relevancy-display {
@ -116,4 +169,71 @@ defineProps<{
font-size: 200%;
z-index: -1;
}
.level-display {
position: absolute;
bottom: -10%;
right: -20%;
color: var(--accent2);
font-size: xx-large;
text-shadow: -1px 1px 0 var(--outline), 1px 1px 0 var(--outline), 1px -1px 0 var(--outline),
-1px -1px 0 var(--outline);
}
.level {
background: var(--locked);
border-radius: 4px;
border-top-left-radius: 50%;
border-bottom-left-radius: 0;
border: solid 2px var(--raised-background);
padding-left: 4px;
padding-right: 4px;
}
.level,
.level::before {
font-family: "Mynerve", cursive;
}
.level::before {
content: "lv";
font-size: large;
}
.segments {
position: absolute;
right: calc(100% - 2px);
width: 100%;
height: 25%;
bottom: -2px;
background: var(--locked);
border-radius: 20px 0 0 0;
border: solid 2px var(--raised-background);
display: flex;
overflow: hidden;
}
.segment {
width: 100%;
height: 100%;
}
.segment:not(:last-child) {
border-right: solid 3px var(--raised-background);
}
.segment.filled {
background-color: var(--accent2);
}
.move-indicator {
position: absolute;
transform: translateX(-50%) rotate(180deg);
top: -75%;
left: 50%;
font-size: xxx-large;
}
.move-indicator .material-icons {
font-size: xxx-large;
}
</style>

View file

@ -78,7 +78,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
const turn = ref<number>(0);
const gold = ref<number>(0);
const team = ref<(Character | null)[]>([null, null, null]);
const shop = ref<(string | null)[]>([]);
const shop = ref<(Character | null)[]>([]);
const selectedCharacter = ref<number | null>(null);
const selectedShopItem = ref<number | null>(null);
@ -123,37 +123,34 @@ export const main = createLayer("main", function (this: BaseLayer) {
<h2>{nickname.value}</h2>
<Spacer height="10vh" />
<Row>
{new Array(3).fill(0).map((_, i) => (
<CharacterSlot
character={team.value[0]}
selected={selectedCharacter.value === 0}
onClick={clickCharacter(0)}
/>
<CharacterSlot
character={team.value[1]}
selected={selectedCharacter.value === 1}
onClick={clickCharacter(1)}
/>
<CharacterSlot
character={team.value[2]}
selected={selectedCharacter.value === 2}
onClick={clickCharacter(2)}
character={team.value[i]}
isSelected={selectedCharacter.value === i}
selected={
selectedCharacter.value == null
? selectedShopItem.value == null ||
(team.value[i] != null &&
shop.value[selectedShopItem.value]?.type !==
team.value[i]?.type)
? null
: shop.value[selectedShopItem.value]
: team.value[selectedCharacter.value]
}
onClick={clickCharacter(i)}
/>
))}
</Row>
<Spacer height="10vh" />
<Row>
{shop.value.map((item, i) => (
<CharacterSlot
character={
item == null
? undefined
: {
type: item,
relevancy: characters[item].initialRelevancy,
presence: characters[item].initialPresence
}
}
selected={selectedShopItem.value === i}
character={item == null ? undefined : item}
isSelected={selectedShopItem.value === i}
onClick={(e: MouseEvent) => {
if (item == null) {
return;
}
selectedShopItem.value = selectedShopItem.value === i ? null : i;
selectedCharacter.value = null;
e.stopPropagation();

View file

@ -102,10 +102,20 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
socket.on("newTurn", shop => {
main.gold.value = 10;
main.turn.value++;
main.shop.value = shop;
main.shop.value = shop.map(item => ({
type: item,
relevancy: characters[item].initialRelevancy,
presence: characters[item].initialPresence,
exp: 1
}));
});
socket.on("reroll", shop => {
main.shop.value = shop;
main.shop.value = shop.map(item => ({
type: item,
relevancy: characters[item].initialRelevancy,
presence: characters[item].initialPresence,
exp: 1
}));
});
socket.on("buy", (shopIndex, teamIndex, char) => {
main.team.value[teamIndex] = char;
@ -117,6 +127,10 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
main.team.value[index] = main.team.value[otherIndex];
main.team.value[otherIndex] = temp;
});
socket.on("merge", (index, otherIndex, char) => {
main.team.value[index] = null;
main.team.value[otherIndex] = char;
});
}
declare module "game/settings" {

3
src/data/types.d.ts vendored
View file

@ -7,6 +7,7 @@ interface CharacterInfo {
interface Character {
type: string;
exp: number;
relevancy: number;
presence: number;
}
@ -19,9 +20,11 @@ interface ServerToClientEvents {
reroll: (shop: string[]) => void;
buy: (shopIndex: number, teamIndex: number, char: Character) => void;
move: (index: number, otherIndex: number) => void;
merge: (shopIndex: number, teamIndex: number, char: Character) => void;
}
interface ClientToServerEvents {
buy: (shopIndex: number, teamIndex: number) => void;
move: (index: number, otherIndex: number) => void;
merge: (index: number, otherIndex: number) => void;
}