mirror of
https://github.com/thepaperpilot/Super-Auto-Coots.git
synced 2025-04-01 13:30:58 +00:00
Implement battles
This commit is contained in:
parent
eb08ec9976
commit
75e2e3e2ae
6 changed files with 588 additions and 126 deletions
|
@ -14,7 +14,8 @@
|
||||||
empty: character == null && selected == null,
|
empty: character == null && selected == null,
|
||||||
dragging,
|
dragging,
|
||||||
isDragging,
|
isDragging,
|
||||||
draggingOver
|
draggingOver,
|
||||||
|
shake
|
||||||
}"
|
}"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
:ondragstart="() => (dragging = true)"
|
:ondragstart="() => (dragging = true)"
|
||||||
|
@ -105,6 +106,7 @@ defineProps<{
|
||||||
isShop?: boolean;
|
isShop?: boolean;
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
selected?: Character | null;
|
selected?: Character | null;
|
||||||
|
shake?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dragging = ref(false);
|
const dragging = ref(false);
|
||||||
|
@ -139,6 +141,10 @@ watch(dragging, dragging => {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.character.shake {
|
||||||
|
animation: shake 0.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
.character * {
|
.character * {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
@ -232,8 +238,9 @@ watch(dragging, dragging => {
|
||||||
|
|
||||||
.level-display {
|
.level-display {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -15%;
|
bottom: -5%;
|
||||||
right: -5%;
|
right: -5%;
|
||||||
|
z-index: 1;
|
||||||
transform: translate(50%, 50%);
|
transform: translate(50%, 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,4 +277,40 @@ watch(dragging, dragging => {
|
||||||
transform: translateX(-50%) rotate(180deg) translateY(0%);
|
transform: translateX(-50%) rotate(180deg) translateY(0%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0% {
|
||||||
|
transform: translate(1px, 1px) rotate(0deg);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: translate(-1px, -2px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: translate(-3px, 0px) rotate(1deg);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: translate(3px, 2px) rotate(0deg);
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: translate(1px, -1px) rotate(1deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate(-1px, 2px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: translate(-3px, 1px) rotate(0deg);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: translate(3px, 1px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: translate(-1px, -1px) rotate(1deg);
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
transform: translate(1px, 2px) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(1px, -2px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-box {
|
.resource-box {
|
||||||
margin-right: 20px !important;
|
display: flex;
|
||||||
font-size: large;
|
|
||||||
border: solid 2px var(--bought);
|
border: solid 2px var(--bought);
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
@ -24,6 +23,10 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-box:not(:last-child) {
|
||||||
|
margin-right: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.resource-box .material-icons {
|
.resource-box .material-icons {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
@ -56,3 +59,144 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.battle-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.battle-container:not(.fast) * {
|
||||||
|
transition-duration: 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teams-container {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0 4vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stream-container {
|
||||||
|
aspect-ratio: 16/9;
|
||||||
|
width: calc(100% - 4px);
|
||||||
|
margin: 0 auto;
|
||||||
|
border: solid 2px var(--accent1);
|
||||||
|
position: relative;
|
||||||
|
background: var(--background);
|
||||||
|
filter: drop-shadow(2px 4px 6px black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stream-details {
|
||||||
|
position: absolute;
|
||||||
|
top: 1vmin;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stream-details .stats {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 1vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-counter {
|
||||||
|
font-size: 2vmin;
|
||||||
|
position: absolute;
|
||||||
|
top: 1vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamers-container {
|
||||||
|
width: 90%;
|
||||||
|
height: 18vmin;
|
||||||
|
position: absolute;
|
||||||
|
left: 5%;
|
||||||
|
bottom: 5%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-container {
|
||||||
|
height: 18vmin;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamers-container .row,
|
||||||
|
.members-container .row {
|
||||||
|
flex-flow: row
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamers-container .character {
|
||||||
|
margin: 4vmin 1vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.battle-controls {
|
||||||
|
margin-bottom: 2vmin;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.battle-controls .button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 2vmin;
|
||||||
|
margin: 1vmin;
|
||||||
|
border: solid 2px var(--link);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.battle-controls .button.active {
|
||||||
|
background: var(--link);
|
||||||
|
color: var(--feature-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outcome {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
padding: 2vmin 4vmin;
|
||||||
|
background: var(--tooltip-background);
|
||||||
|
border-radius: 4vmin;
|
||||||
|
font-size: 6vmin;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outcome span {
|
||||||
|
margin: 1vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.character-transition-enter-from {
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
.character-transition-leave-to {
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
.character-trensition-active {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (orientation: portrait) {
|
||||||
|
.teams-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-container {
|
||||||
|
margin: 4vmin 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stream-container {
|
||||||
|
width: unset;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { jsx } from "features/feature";
|
||||||
import type { BaseLayer, GenericLayer } from "game/layers";
|
import type { BaseLayer, GenericLayer } from "game/layers";
|
||||||
import { createLayer } from "game/layers";
|
import { createLayer } from "game/layers";
|
||||||
import type { Player } from "game/player";
|
import type { Player } from "game/player";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref, Transition, TransitionGroup } from "vue";
|
||||||
import CharacterSlot from "./CharacterSlot.vue";
|
import CharacterSlot from "./CharacterSlot.vue";
|
||||||
import "./socket";
|
import "./socket";
|
||||||
import "./common.css";
|
import "./common.css";
|
||||||
|
@ -20,6 +20,7 @@ import vespa from "../../public/Vespa Coots.png";
|
||||||
import heart from "../../public/Heart.png";
|
import heart from "../../public/Heart.png";
|
||||||
import startStream from "../../public/start stream.png";
|
import startStream from "../../public/start stream.png";
|
||||||
import { createReset } from "features/reset";
|
import { createReset } from "features/reset";
|
||||||
|
import settings from "game/settings";
|
||||||
|
|
||||||
export const characters: Record<string, CharacterInfo> = {
|
export const characters: Record<string, CharacterInfo> = {
|
||||||
coots: {
|
coots: {
|
||||||
|
@ -85,6 +86,49 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
const selectedCharacter = ref<number | null>(null);
|
const selectedCharacter = ref<number | null>(null);
|
||||||
const selectedShopItem = ref<number | null>(null);
|
const selectedShopItem = ref<number | null>(null);
|
||||||
const findingMatch = ref<boolean>(false);
|
const findingMatch = ref<boolean>(false);
|
||||||
|
const outcome = ref<BattleOutcome | "">("");
|
||||||
|
const showingOutcome = ref<boolean>(false);
|
||||||
|
const previewing = ref<boolean>(false);
|
||||||
|
const playClicked = ref<boolean>(false);
|
||||||
|
const queue = ref<
|
||||||
|
{
|
||||||
|
action: "join";
|
||||||
|
}[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const battle = ref<{
|
||||||
|
team: Character[];
|
||||||
|
streamers: Character[];
|
||||||
|
enemyTeam: Character[];
|
||||||
|
enemyStreamers: Character[];
|
||||||
|
enemyNickname: string;
|
||||||
|
enemyLives: number;
|
||||||
|
enemyWins: number;
|
||||||
|
enemyTurn: number;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
|
const views = computed(() => {
|
||||||
|
if (battle.value == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
battle.value.streamers.reduce(
|
||||||
|
(acc, curr) => acc + Math.max(0, curr.presence) * Math.max(0, curr.relevancy),
|
||||||
|
0
|
||||||
|
) * 100
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const enemyViews = computed(() => {
|
||||||
|
if (battle.value == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
battle.value.enemyStreamers.reduce(
|
||||||
|
(acc, curr) => acc + Math.max(0, curr.presence) * Math.max(0, curr.relevancy),
|
||||||
|
0
|
||||||
|
) * 100
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const reset = createReset(() => ({
|
const reset = createReset(() => ({
|
||||||
onReset() {
|
onReset() {
|
||||||
|
@ -97,128 +141,331 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
selectedCharacter.value = null;
|
selectedCharacter.value = null;
|
||||||
selectedShopItem.value = null;
|
selectedShopItem.value = null;
|
||||||
findingMatch.value = false;
|
findingMatch.value = false;
|
||||||
|
battle.value = null;
|
||||||
|
outcome.value = "";
|
||||||
|
showingOutcome.value = false;
|
||||||
|
playClicked.value = false;
|
||||||
|
queue.value = [];
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const isDragging = ref(false);
|
const isDragging = ref(false);
|
||||||
|
|
||||||
|
function prepareMove() {
|
||||||
|
if (battle.value == null) {
|
||||||
|
throw "Preparing move while not in battle";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
queue.value.length === 0 &&
|
||||||
|
battle.value.team.length === 0 &&
|
||||||
|
battle.value.enemyTeam.length === 0
|
||||||
|
) {
|
||||||
|
if (outcome.value === "Victory") {
|
||||||
|
wins.value++;
|
||||||
|
} else if (outcome.value === "Defeat") {
|
||||||
|
lives.value--;
|
||||||
|
}
|
||||||
|
showingOutcome.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (queue.value.length === 0) {
|
||||||
|
queue.value.push({
|
||||||
|
action: "join"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (settings.autoplay === false && playClicked.value === false) {
|
||||||
|
previewing.value = true;
|
||||||
|
} else {
|
||||||
|
previewing.value = false;
|
||||||
|
const action = queue.value.shift()!;
|
||||||
|
switch (action.action) {
|
||||||
|
case "join":
|
||||||
|
if ((battle.value.team.length ?? 0) > 0) {
|
||||||
|
battle.value.streamers.push(battle.value.team.pop()!);
|
||||||
|
}
|
||||||
|
if ((battle.value.enemyTeam.length ?? 0) > 0) {
|
||||||
|
battle.value.enemyStreamers.push(battle.value.enemyTeam.pop()!);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
playClicked.value = false;
|
||||||
|
setTimeout(prepareMove, settings.fast ? 750 : 1250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "Game",
|
name: "Game",
|
||||||
minimizable: false,
|
minimizable: false,
|
||||||
display: jsx(() => (
|
display: jsx(() => {
|
||||||
<div
|
if (battle.value != null) {
|
||||||
class="game-container"
|
return (
|
||||||
style={findingMatch.value ? "pointer-events: none" : ""}
|
<div class={{ ["battle-container"]: true, fast: settings.fast }}>
|
||||||
onClick={() => {
|
<div class="battle-controls">
|
||||||
selectedCharacter.value = null;
|
<button
|
||||||
selectedShopItem.value = null;
|
class="button"
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
playClicked.value = true;
|
||||||
<Row style="position: absolute; top: 10px; left: -5px">
|
prepareMove();
|
||||||
<div class="resource-box">
|
}}
|
||||||
<span class="material-icons">credit_card</span>
|
>
|
||||||
{gold.value}
|
<span class="material-icons">play_arrow</span>
|
||||||
|
<span>Play</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class={{ button: true, active: settings.autoplay }}
|
||||||
|
onClick={() => {
|
||||||
|
settings.autoplay = !settings.autoplay;
|
||||||
|
if (previewing.value) {
|
||||||
|
prepareMove();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="material-icons">all_inclusive</span>
|
||||||
|
<span>Autoplay</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class={{ button: true, active: settings.fast }}
|
||||||
|
onClick={() => (settings.fast = !settings.fast)}
|
||||||
|
>
|
||||||
|
<span class="material-icons">fast_forward</span>
|
||||||
|
<span>Fast</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="teams-container"
|
||||||
|
style={showingOutcome.value ? "pointer-events: none;" : ""}
|
||||||
|
>
|
||||||
|
<div class="team-container">
|
||||||
|
<div class="stream-container">
|
||||||
|
<div class="stream-details" style="left: 1vmin">
|
||||||
|
<span style="margin-left: 0">{nickname.value} (YOU)</span>
|
||||||
|
<div class="stats" style="margin-left: 0">
|
||||||
|
<div class="resource-box">
|
||||||
|
<img src={heart} />
|
||||||
|
<span>{lives.value}</span>
|
||||||
|
</div>
|
||||||
|
<div class="resource-box">
|
||||||
|
<span class="material-icons">emoji_events</span>
|
||||||
|
<span>{wins.value}/5</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="view-counter" style="right: 1vmin">
|
||||||
|
{views.value} Views
|
||||||
|
</div>
|
||||||
|
<Row class="streamers-container">
|
||||||
|
<TransitionGroup name="character-transition">
|
||||||
|
{battle.value.streamers
|
||||||
|
.slice()
|
||||||
|
.reverse()
|
||||||
|
.map((streamer, i) => (
|
||||||
|
<CharacterSlot
|
||||||
|
key={battle.value!.streamers.length - i}
|
||||||
|
character={streamer}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TransitionGroup>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
<Row class="members-container" style="margin-left: 0">
|
||||||
|
<TransitionGroup name="character-transition">
|
||||||
|
{battle.value.team.map((member, i) => (
|
||||||
|
<CharacterSlot
|
||||||
|
character={member}
|
||||||
|
key={i}
|
||||||
|
shake={
|
||||||
|
previewing.value &&
|
||||||
|
queue.value[0]?.action === "join" &&
|
||||||
|
member ===
|
||||||
|
battle.value?.team[
|
||||||
|
(battle.value?.team.length ?? 0) - 1
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TransitionGroup>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
<div class="team-container">
|
||||||
|
<div class="stream-container">
|
||||||
|
<div class="stream-details" style="right: 1vmin">
|
||||||
|
<span style="margin-right: 0">
|
||||||
|
{battle.value.enemyNickname}
|
||||||
|
</span>
|
||||||
|
<div class="stats" style="margin-right: 0">
|
||||||
|
<div class="resource-box">
|
||||||
|
<img src={heart} />
|
||||||
|
<span>{battle.value.enemyLives}</span>
|
||||||
|
</div>
|
||||||
|
<div class="resource-box">
|
||||||
|
<span class="material-icons">emoji_events</span>
|
||||||
|
<span>{battle.value.enemyWins}/5</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="view-counter" style="left: 1vmin">
|
||||||
|
{enemyViews.value} Views
|
||||||
|
</div>
|
||||||
|
<Row class="streamers-container">
|
||||||
|
<TransitionGroup name="character-transition">
|
||||||
|
{battle.value.enemyStreamers.map((streamer, i) => (
|
||||||
|
<CharacterSlot key={i} character={streamer} />
|
||||||
|
))}
|
||||||
|
</TransitionGroup>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
<Row class="members-container" style="margin-right: 0">
|
||||||
|
<TransitionGroup name="character-transition">
|
||||||
|
{battle.value.enemyTeam
|
||||||
|
.slice()
|
||||||
|
.reverse()
|
||||||
|
.map((member, i) => (
|
||||||
|
<CharacterSlot
|
||||||
|
character={member}
|
||||||
|
key={battle.value!.enemyStreamers.length + i}
|
||||||
|
shake={
|
||||||
|
previewing.value &&
|
||||||
|
queue.value[0]?.action === "join" &&
|
||||||
|
member ===
|
||||||
|
battle.value?.enemyTeam[
|
||||||
|
(battle.value?.enemyTeam.length ??
|
||||||
|
0) - 1
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TransitionGroup>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{showingOutcome.value ? (
|
||||||
|
<div class="outcome" onClick={() => emit("newTurn")}>
|
||||||
|
<span>{outcome.value}</span>
|
||||||
|
<span style="font-size: 2vmin">Next Turn</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div class="resource-box">
|
);
|
||||||
<img src={heart} />
|
}
|
||||||
{lives.value}
|
|
||||||
</div>
|
return (
|
||||||
<div class="resource-box">
|
<div
|
||||||
<span class="material-icons">emoji_events</span>
|
class="game-container"
|
||||||
{wins.value}/5
|
style={findingMatch.value ? "pointer-events: none" : ""}
|
||||||
</div>
|
onClick={() => {
|
||||||
</Row>
|
selectedCharacter.value = null;
|
||||||
<h2 style="font-size: 3vmin">{nickname.value}</h2>
|
selectedShopItem.value = null;
|
||||||
<Row style="margin-top: 10vh">
|
}}
|
||||||
{new Array(3).fill(0).map((_, i) => (
|
>
|
||||||
<CharacterSlot
|
<Row style="position: absolute; top: 10px; left: -5px">
|
||||||
character={team.value[i]}
|
<div class="resource-box">
|
||||||
isSelected={selectedCharacter.value === i}
|
<span class="material-icons">credit_card</span>
|
||||||
selected={
|
{gold.value}
|
||||||
selectedCharacter.value == null
|
</div>
|
||||||
? selectedShopItem.value == null ||
|
<div class="resource-box">
|
||||||
(team.value[i] != null &&
|
<img src={heart} />
|
||||||
shop.value[selectedShopItem.value]?.type !==
|
{lives.value}
|
||||||
team.value[i]?.type) ||
|
</div>
|
||||||
gold.value < 3
|
<div class="resource-box">
|
||||||
? null
|
<span class="material-icons">emoji_events</span>
|
||||||
: shop.value[selectedShopItem.value]
|
{wins.value}/5
|
||||||
: team.value[selectedCharacter.value]
|
</div>
|
||||||
}
|
</Row>
|
||||||
isDragging={isDragging.value}
|
<h2 style="font-size: 3vmin">{nickname.value}</h2>
|
||||||
onClick={clickCharacter(i)}
|
<Row style="margin-top: 10vh">
|
||||||
onDragstart={() => {
|
{new Array(3).fill(0).map((_, i) => (
|
||||||
isDragging.value = true;
|
<CharacterSlot
|
||||||
selectedCharacter.value = i;
|
character={team.value[i]}
|
||||||
selectedShopItem.value = null;
|
isSelected={selectedCharacter.value === i}
|
||||||
}}
|
selected={
|
||||||
onDragend={() => {
|
selectedCharacter.value == null
|
||||||
isDragging.value = false;
|
? selectedShopItem.value == null ||
|
||||||
selectedCharacter.value = null;
|
(team.value[i] != null &&
|
||||||
selectedShopItem.value = null;
|
shop.value[selectedShopItem.value]?.type !==
|
||||||
}}
|
team.value[i]?.type) ||
|
||||||
onDrop={() => clickCharacter(i)()}
|
gold.value < 3
|
||||||
/>
|
? null
|
||||||
))}
|
: shop.value[selectedShopItem.value]
|
||||||
</Row>
|
: team.value[selectedCharacter.value]
|
||||||
<Row style="margin-top: 10vh">
|
}
|
||||||
<div
|
isDragging={isDragging.value}
|
||||||
class="reroll"
|
onClick={clickCharacter(i)}
|
||||||
style={gold.value > 0 ? "" : "color: var(--locked); cursor: not-allowed"}
|
onDragstart={() => {
|
||||||
onClick={() => {
|
isDragging.value = true;
|
||||||
if (gold.value > 0) {
|
selectedCharacter.value = i;
|
||||||
emit("reroll");
|
selectedShopItem.value = null;
|
||||||
}
|
}}
|
||||||
}}
|
onDragend={() => {
|
||||||
>
|
isDragging.value = false;
|
||||||
<span class="material-icons" style="font-size: 8vmin">
|
selectedCharacter.value = null;
|
||||||
casino
|
selectedShopItem.value = null;
|
||||||
</span>
|
}}
|
||||||
<span style="font-size: 2vmin">Roll</span>
|
onDrop={() => clickCharacter(i)()}
|
||||||
</div>
|
/>
|
||||||
{shop.value.map((item, i) => (
|
))}
|
||||||
<CharacterSlot
|
</Row>
|
||||||
character={item == null ? undefined : item}
|
<Row style="margin-top: 10vh">
|
||||||
isSelected={selectedShopItem.value === i}
|
<div
|
||||||
isShop={true}
|
class="reroll"
|
||||||
isDragging={isDragging.value}
|
style={
|
||||||
onClick={(e: MouseEvent) => {
|
gold.value > 0 ? "" : "color: var(--locked); cursor: not-allowed"
|
||||||
if (item == null) {
|
}
|
||||||
return;
|
onClick={() => {
|
||||||
|
if (gold.value > 0) {
|
||||||
|
emit("reroll");
|
||||||
}
|
}
|
||||||
selectedShopItem.value = selectedShopItem.value === i ? null : i;
|
|
||||||
selectedCharacter.value = null;
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
}}
|
||||||
onDragstart={() => {
|
>
|
||||||
isDragging.value = true;
|
<span class="material-icons" style="font-size: 8vmin">
|
||||||
selectedCharacter.value = null;
|
casino
|
||||||
selectedShopItem.value = i;
|
</span>
|
||||||
}}
|
<span style="font-size: 2vmin">Roll</span>
|
||||||
onDragend={() => {
|
</div>
|
||||||
isDragging.value = false;
|
{shop.value.map((item, i) => (
|
||||||
selectedCharacter.value = null;
|
<CharacterSlot
|
||||||
selectedShopItem.value = null;
|
character={item == null ? undefined : item}
|
||||||
|
isSelected={selectedShopItem.value === i}
|
||||||
|
isShop={true}
|
||||||
|
isDragging={isDragging.value}
|
||||||
|
onClick={(e: MouseEvent) => {
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedShopItem.value =
|
||||||
|
selectedShopItem.value === i ? null : i;
|
||||||
|
selectedCharacter.value = null;
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
onDragstart={() => {
|
||||||
|
isDragging.value = true;
|
||||||
|
selectedCharacter.value = null;
|
||||||
|
selectedShopItem.value = i;
|
||||||
|
}}
|
||||||
|
onDragend={() => {
|
||||||
|
isDragging.value = false;
|
||||||
|
selectedCharacter.value = null;
|
||||||
|
selectedShopItem.value = null;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
<Spacer height="4vh" />
|
||||||
|
{findingMatch.value ? (
|
||||||
|
<div class="waiting">Finding opposing team...</div>
|
||||||
|
) : (
|
||||||
|
<img
|
||||||
|
class="startStream"
|
||||||
|
draggable="false"
|
||||||
|
onClick={() => {
|
||||||
|
emit("stream");
|
||||||
|
findingMatch.value = true;
|
||||||
}}
|
}}
|
||||||
|
src={startStream}
|
||||||
/>
|
/>
|
||||||
))}
|
)}
|
||||||
</Row>
|
</div>
|
||||||
<Spacer height="4vh" />
|
);
|
||||||
{findingMatch.value ? (
|
}),
|
||||||
<div class="waiting">Finding opposing team...</div>
|
|
||||||
) : (
|
|
||||||
<img
|
|
||||||
class="startStream"
|
|
||||||
draggable="false"
|
|
||||||
onClick={() => {
|
|
||||||
emit("stream");
|
|
||||||
findingMatch.value = true;
|
|
||||||
}}
|
|
||||||
src={startStream}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)),
|
|
||||||
lives,
|
lives,
|
||||||
wins,
|
wins,
|
||||||
turn,
|
turn,
|
||||||
|
@ -228,7 +475,12 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
selectedCharacter,
|
selectedCharacter,
|
||||||
selectedShopItem,
|
selectedShopItem,
|
||||||
findingMatch,
|
findingMatch,
|
||||||
reset
|
showingOutcome,
|
||||||
|
outcome,
|
||||||
|
reset,
|
||||||
|
battle,
|
||||||
|
playClicked,
|
||||||
|
prepareMove
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
|
||||||
socket.on("newTurn", shop => {
|
socket.on("newTurn", shop => {
|
||||||
main.gold.value = 10;
|
main.gold.value = 10;
|
||||||
main.turn.value++;
|
main.turn.value++;
|
||||||
|
main.battle.value = null;
|
||||||
main.shop.value = shop.map(item => ({
|
main.shop.value = shop.map(item => ({
|
||||||
type: item,
|
type: item,
|
||||||
relevancy: characters[item].initialRelevancy,
|
relevancy: characters[item].initialRelevancy,
|
||||||
|
@ -135,15 +136,22 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
|
||||||
main.team.value[index] = null;
|
main.team.value[index] = null;
|
||||||
main.team.value[otherIndex] = char;
|
main.team.value[otherIndex] = char;
|
||||||
});
|
});
|
||||||
socket.on("stream", (enemyTeam, enemyNickname, outcome) => {
|
socket.on("stream", (enemy, outcome) => {
|
||||||
if (outcome === "Victory") {
|
|
||||||
main.wins.value++;
|
|
||||||
} else if (outcome === "Defeat") {
|
|
||||||
main.lives.value--;
|
|
||||||
}
|
|
||||||
main.findingMatch.value = false;
|
main.findingMatch.value = false;
|
||||||
// TODO display combat
|
main.battle.value = {
|
||||||
emit("newTurn");
|
team: JSON.parse(JSON.stringify(main.team.value.filter(m => m != null))),
|
||||||
|
streamers: [],
|
||||||
|
enemyTeam: enemy.team.filter(m => m != null) as Character[],
|
||||||
|
enemyStreamers: [],
|
||||||
|
enemyNickname: enemy.nickname,
|
||||||
|
enemyLives: enemy.lives,
|
||||||
|
enemyWins: enemy.wins,
|
||||||
|
enemyTurn: enemy.turn
|
||||||
|
};
|
||||||
|
main.outcome.value = outcome;
|
||||||
|
main.showingOutcome.value = false;
|
||||||
|
main.playClicked.value = false;
|
||||||
|
setTimeout(main.prepareMove, 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/data/types.d.ts
vendored
11
src/data/types.d.ts
vendored
|
@ -23,7 +23,16 @@ interface ServerToClientEvents {
|
||||||
buy: (shopIndex: number, teamIndex: number, char: Character) => void;
|
buy: (shopIndex: number, teamIndex: number, char: Character) => void;
|
||||||
move: (index: number, otherIndex: number) => void;
|
move: (index: number, otherIndex: number) => void;
|
||||||
merge: (shopIndex: number, teamIndex: number, char: Character) => void;
|
merge: (shopIndex: number, teamIndex: number, char: Character) => void;
|
||||||
stream: (enemyTeam: (Character | null)[], nickname: string, outcome: BattleOutcome) => void;
|
stream: (
|
||||||
|
enemy: {
|
||||||
|
team: (Character | null)[];
|
||||||
|
nickname: string;
|
||||||
|
lives: number;
|
||||||
|
wins: number;
|
||||||
|
turn: number;
|
||||||
|
},
|
||||||
|
outcome: BattleOutcome
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ClientToServerEvents {
|
interface ClientToServerEvents {
|
||||||
|
|
|
@ -20,6 +20,8 @@ export interface Settings {
|
||||||
unthrottled: boolean;
|
unthrottled: boolean;
|
||||||
/** Whether to align modifiers to the unit. */
|
/** Whether to align modifiers to the unit. */
|
||||||
alignUnits: boolean;
|
alignUnits: boolean;
|
||||||
|
autoplay: boolean;
|
||||||
|
fast: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = reactive<Partial<Settings>>({
|
const state = reactive<Partial<Settings>>({
|
||||||
|
@ -28,7 +30,9 @@ const state = reactive<Partial<Settings>>({
|
||||||
showTPS: true,
|
showTPS: true,
|
||||||
theme: Themes.Nordic,
|
theme: Themes.Nordic,
|
||||||
unthrottled: false,
|
unthrottled: false,
|
||||||
alignUnits: false
|
alignUnits: false,
|
||||||
|
autoplay: false,
|
||||||
|
fast: false
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -61,7 +65,9 @@ export const hardResetSettings = (window.hardResetSettings = () => {
|
||||||
saves: [],
|
saves: [],
|
||||||
showTPS: true,
|
showTPS: true,
|
||||||
theme: Themes.Nordic,
|
theme: Themes.Nordic,
|
||||||
alignUnits: false
|
alignUnits: false,
|
||||||
|
autoplay: false,
|
||||||
|
fast: false
|
||||||
};
|
};
|
||||||
globalBus.emit("loadSettings", settings);
|
globalBus.emit("loadSettings", settings);
|
||||||
Object.assign(state, settings);
|
Object.assign(state, settings);
|
||||||
|
|
Loading…
Add table
Reference in a new issue