mirror of
https://github.com/thepaperpilot/Super-Auto-Coots.git
synced 2024-11-22 08:31:34 +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,
|
||||
dragging,
|
||||
isDragging,
|
||||
draggingOver
|
||||
draggingOver,
|
||||
shake
|
||||
}"
|
||||
draggable="true"
|
||||
:ondragstart="() => (dragging = true)"
|
||||
|
@ -105,6 +106,7 @@ defineProps<{
|
|||
isShop?: boolean;
|
||||
isDragging?: boolean;
|
||||
selected?: Character | null;
|
||||
shake?: boolean;
|
||||
}>();
|
||||
|
||||
const dragging = ref(false);
|
||||
|
@ -139,6 +141,10 @@ watch(dragging, dragging => {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.character.shake {
|
||||
animation: shake 0.5s infinite;
|
||||
}
|
||||
|
||||
.character * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -232,8 +238,9 @@ watch(dragging, dragging => {
|
|||
|
||||
.level-display {
|
||||
position: absolute;
|
||||
bottom: -15%;
|
||||
bottom: -5%;
|
||||
right: -5%;
|
||||
z-index: 1;
|
||||
transform: translate(50%, 50%);
|
||||
}
|
||||
|
||||
|
@ -270,4 +277,40 @@ watch(dragging, dragging => {
|
|||
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>
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
}
|
||||
|
||||
.resource-box {
|
||||
margin-right: 20px !important;
|
||||
font-size: large;
|
||||
display: flex;
|
||||
border: solid 2px var(--bought);
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
|
@ -24,6 +23,10 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.resource-box:not(:last-child) {
|
||||
margin-right: 20px !important;
|
||||
}
|
||||
|
||||
.resource-box .material-icons {
|
||||
margin-right: 6px;
|
||||
font-size: 1em;
|
||||
|
@ -56,3 +59,144 @@
|
|||
display: flex;
|
||||
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 { createLayer } from "game/layers";
|
||||
import type { Player } from "game/player";
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, ref, Transition, TransitionGroup } from "vue";
|
||||
import CharacterSlot from "./CharacterSlot.vue";
|
||||
import "./socket";
|
||||
import "./common.css";
|
||||
|
@ -20,6 +20,7 @@ import vespa from "../../public/Vespa Coots.png";
|
|||
import heart from "../../public/Heart.png";
|
||||
import startStream from "../../public/start stream.png";
|
||||
import { createReset } from "features/reset";
|
||||
import settings from "game/settings";
|
||||
|
||||
export const characters: Record<string, CharacterInfo> = {
|
||||
coots: {
|
||||
|
@ -85,6 +86,49 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
const selectedCharacter = ref<number | null>(null);
|
||||
const selectedShopItem = ref<number | null>(null);
|
||||
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(() => ({
|
||||
onReset() {
|
||||
|
@ -97,128 +141,331 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
selectedCharacter.value = null;
|
||||
selectedShopItem.value = null;
|
||||
findingMatch.value = false;
|
||||
battle.value = null;
|
||||
outcome.value = "";
|
||||
showingOutcome.value = false;
|
||||
playClicked.value = false;
|
||||
queue.value = [];
|
||||
}
|
||||
}));
|
||||
|
||||
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 {
|
||||
name: "Game",
|
||||
minimizable: false,
|
||||
display: jsx(() => (
|
||||
<div
|
||||
class="game-container"
|
||||
style={findingMatch.value ? "pointer-events: none" : ""}
|
||||
onClick={() => {
|
||||
selectedCharacter.value = null;
|
||||
selectedShopItem.value = null;
|
||||
}}
|
||||
>
|
||||
<Row style="position: absolute; top: 10px; left: -5px">
|
||||
<div class="resource-box">
|
||||
<span class="material-icons">credit_card</span>
|
||||
{gold.value}
|
||||
display: jsx(() => {
|
||||
if (battle.value != null) {
|
||||
return (
|
||||
<div class={{ ["battle-container"]: true, fast: settings.fast }}>
|
||||
<div class="battle-controls">
|
||||
<button
|
||||
class="button"
|
||||
onClick={() => {
|
||||
playClicked.value = true;
|
||||
prepareMove();
|
||||
}}
|
||||
>
|
||||
<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 class="resource-box">
|
||||
<img src={heart} />
|
||||
{lives.value}
|
||||
</div>
|
||||
<div class="resource-box">
|
||||
<span class="material-icons">emoji_events</span>
|
||||
{wins.value}/5
|
||||
</div>
|
||||
</Row>
|
||||
<h2 style="font-size: 3vmin">{nickname.value}</h2>
|
||||
<Row style="margin-top: 10vh">
|
||||
{new Array(3).fill(0).map((_, i) => (
|
||||
<CharacterSlot
|
||||
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) ||
|
||||
gold.value < 3
|
||||
? null
|
||||
: shop.value[selectedShopItem.value]
|
||||
: team.value[selectedCharacter.value]
|
||||
}
|
||||
isDragging={isDragging.value}
|
||||
onClick={clickCharacter(i)}
|
||||
onDragstart={() => {
|
||||
isDragging.value = true;
|
||||
selectedCharacter.value = i;
|
||||
selectedShopItem.value = null;
|
||||
}}
|
||||
onDragend={() => {
|
||||
isDragging.value = false;
|
||||
selectedCharacter.value = null;
|
||||
selectedShopItem.value = null;
|
||||
}}
|
||||
onDrop={() => clickCharacter(i)()}
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
<Row style="margin-top: 10vh">
|
||||
<div
|
||||
class="reroll"
|
||||
style={gold.value > 0 ? "" : "color: var(--locked); cursor: not-allowed"}
|
||||
onClick={() => {
|
||||
if (gold.value > 0) {
|
||||
emit("reroll");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span class="material-icons" style="font-size: 8vmin">
|
||||
casino
|
||||
</span>
|
||||
<span style="font-size: 2vmin">Roll</span>
|
||||
</div>
|
||||
{shop.value.map((item, i) => (
|
||||
<CharacterSlot
|
||||
character={item == null ? undefined : item}
|
||||
isSelected={selectedShopItem.value === i}
|
||||
isShop={true}
|
||||
isDragging={isDragging.value}
|
||||
onClick={(e: MouseEvent) => {
|
||||
if (item == null) {
|
||||
return;
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class="game-container"
|
||||
style={findingMatch.value ? "pointer-events: none" : ""}
|
||||
onClick={() => {
|
||||
selectedCharacter.value = null;
|
||||
selectedShopItem.value = null;
|
||||
}}
|
||||
>
|
||||
<Row style="position: absolute; top: 10px; left: -5px">
|
||||
<div class="resource-box">
|
||||
<span class="material-icons">credit_card</span>
|
||||
{gold.value}
|
||||
</div>
|
||||
<div class="resource-box">
|
||||
<img src={heart} />
|
||||
{lives.value}
|
||||
</div>
|
||||
<div class="resource-box">
|
||||
<span class="material-icons">emoji_events</span>
|
||||
{wins.value}/5
|
||||
</div>
|
||||
</Row>
|
||||
<h2 style="font-size: 3vmin">{nickname.value}</h2>
|
||||
<Row style="margin-top: 10vh">
|
||||
{new Array(3).fill(0).map((_, i) => (
|
||||
<CharacterSlot
|
||||
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) ||
|
||||
gold.value < 3
|
||||
? null
|
||||
: shop.value[selectedShopItem.value]
|
||||
: team.value[selectedCharacter.value]
|
||||
}
|
||||
isDragging={isDragging.value}
|
||||
onClick={clickCharacter(i)}
|
||||
onDragstart={() => {
|
||||
isDragging.value = true;
|
||||
selectedCharacter.value = i;
|
||||
selectedShopItem.value = null;
|
||||
}}
|
||||
onDragend={() => {
|
||||
isDragging.value = false;
|
||||
selectedCharacter.value = null;
|
||||
selectedShopItem.value = null;
|
||||
}}
|
||||
onDrop={() => clickCharacter(i)()}
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
<Row style="margin-top: 10vh">
|
||||
<div
|
||||
class="reroll"
|
||||
style={
|
||||
gold.value > 0 ? "" : "color: var(--locked); cursor: not-allowed"
|
||||
}
|
||||
onClick={() => {
|
||||
if (gold.value > 0) {
|
||||
emit("reroll");
|
||||
}
|
||||
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;
|
||||
>
|
||||
<span class="material-icons" style="font-size: 8vmin">
|
||||
casino
|
||||
</span>
|
||||
<span style="font-size: 2vmin">Roll</span>
|
||||
</div>
|
||||
{shop.value.map((item, i) => (
|
||||
<CharacterSlot
|
||||
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>
|
||||
<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>
|
||||
)),
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
lives,
|
||||
wins,
|
||||
turn,
|
||||
|
@ -228,7 +475,12 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
selectedCharacter,
|
||||
selectedShopItem,
|
||||
findingMatch,
|
||||
reset
|
||||
showingOutcome,
|
||||
outcome,
|
||||
reset,
|
||||
battle,
|
||||
playClicked,
|
||||
prepareMove
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
|
|||
socket.on("newTurn", shop => {
|
||||
main.gold.value = 10;
|
||||
main.turn.value++;
|
||||
main.battle.value = null;
|
||||
main.shop.value = shop.map(item => ({
|
||||
type: item,
|
||||
relevancy: characters[item].initialRelevancy,
|
||||
|
@ -135,15 +136,22 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
|
|||
main.team.value[index] = null;
|
||||
main.team.value[otherIndex] = char;
|
||||
});
|
||||
socket.on("stream", (enemyTeam, enemyNickname, outcome) => {
|
||||
if (outcome === "Victory") {
|
||||
main.wins.value++;
|
||||
} else if (outcome === "Defeat") {
|
||||
main.lives.value--;
|
||||
}
|
||||
socket.on("stream", (enemy, outcome) => {
|
||||
main.findingMatch.value = false;
|
||||
// TODO display combat
|
||||
emit("newTurn");
|
||||
main.battle.value = {
|
||||
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;
|
||||
move: (index: number, otherIndex: number) => 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 {
|
||||
|
|
|
@ -20,6 +20,8 @@ export interface Settings {
|
|||
unthrottled: boolean;
|
||||
/** Whether to align modifiers to the unit. */
|
||||
alignUnits: boolean;
|
||||
autoplay: boolean;
|
||||
fast: boolean;
|
||||
}
|
||||
|
||||
const state = reactive<Partial<Settings>>({
|
||||
|
@ -28,7 +30,9 @@ const state = reactive<Partial<Settings>>({
|
|||
showTPS: true,
|
||||
theme: Themes.Nordic,
|
||||
unthrottled: false,
|
||||
alignUnits: false
|
||||
alignUnits: false,
|
||||
autoplay: false,
|
||||
fast: false
|
||||
});
|
||||
|
||||
watch(
|
||||
|
@ -61,7 +65,9 @@ export const hardResetSettings = (window.hardResetSettings = () => {
|
|||
saves: [],
|
||||
showTPS: true,
|
||||
theme: Themes.Nordic,
|
||||
alignUnits: false
|
||||
alignUnits: false,
|
||||
autoplay: false,
|
||||
fast: false
|
||||
};
|
||||
globalBus.emit("loadSettings", settings);
|
||||
Object.assign(state, settings);
|
||||
|
|
Loading…
Reference in a new issue