Replace gameProp signals with store
This commit is contained in:
parent
4390269ed1
commit
252f6f6028
14 changed files with 331 additions and 339 deletions
|
@ -1,10 +1,9 @@
|
||||||
import { For } from "solid-js"
|
import { For } from "solid-js"
|
||||||
import {
|
import {
|
||||||
gameState,
|
gameProps,
|
||||||
mode,
|
|
||||||
mouseCursor,
|
mouseCursor,
|
||||||
removeShip,
|
removeShip,
|
||||||
setMode,
|
setGameProps,
|
||||||
setMouseCursor,
|
setMouseCursor,
|
||||||
setShips,
|
setShips,
|
||||||
setTarget,
|
setTarget,
|
||||||
|
@ -13,6 +12,7 @@ import {
|
||||||
import { useSession } from "~/hooks/useSession"
|
import { useSession } from "~/hooks/useSession"
|
||||||
import {
|
import {
|
||||||
borderCN,
|
borderCN,
|
||||||
|
compiledHits,
|
||||||
cornerCN,
|
cornerCN,
|
||||||
fieldIndex,
|
fieldIndex,
|
||||||
intersectingShip,
|
intersectingShip,
|
||||||
|
@ -32,19 +32,21 @@ type TilesType = {
|
||||||
}
|
}
|
||||||
|
|
||||||
function BorderTiles() {
|
function BorderTiles() {
|
||||||
const { selfIndex, activeUser, ships } = useSession()
|
const { selfIndex, ships } = useSession()
|
||||||
|
|
||||||
const settingTarget = (isGameTile: boolean, x: number, y: number) => {
|
const settingTarget = (isGameTile: boolean, x: number, y: number) => {
|
||||||
if (gameState() === "running") {
|
const sIndex = selfIndex()
|
||||||
const list = targetList(targetPreview(), mode())
|
if (sIndex === -1) return
|
||||||
|
if (gameProps.gameState === "running") {
|
||||||
|
const list = targetList(targetPreview(), gameProps.mode)
|
||||||
if (
|
if (
|
||||||
!isGameTile ||
|
!isGameTile ||
|
||||||
!list.filter(
|
!list.filter(
|
||||||
({ x, y }) => !isAlreadyHit(x, y, activeUser()?.hits() ?? []),
|
({ x, y }) => !isAlreadyHit(x, y, compiledHits(sIndex === 0 ? 1 : 0)),
|
||||||
).length
|
).length
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if (!overlapsWithAnyBorder(targetPreview(), mode()))
|
if (!overlapsWithAnyBorder(targetPreview(), gameProps.mode))
|
||||||
setTarget({
|
setTarget({
|
||||||
show: true,
|
show: true,
|
||||||
x,
|
x,
|
||||||
|
@ -52,15 +54,17 @@ function BorderTiles() {
|
||||||
orientation: targetPreview().orientation,
|
orientation: targetPreview().orientation,
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
gameState() === "starting" &&
|
gameProps.gameState === "starting" &&
|
||||||
targetPreview().show &&
|
targetPreview().show &&
|
||||||
!intersectingShip(ships(), shipProps(ships(), mode(), targetPreview()))
|
!intersectingShip(
|
||||||
.score
|
ships(),
|
||||||
|
shipProps(ships(), gameProps.mode, targetPreview()),
|
||||||
|
).score
|
||||||
) {
|
) {
|
||||||
setMouseCursor((e) => ({ ...e, shouldShow: false }))
|
setMouseCursor((e) => ({ ...e, shouldShow: false }))
|
||||||
setShips(
|
setShips(
|
||||||
[...ships(), shipProps(ships(), mode(), targetPreview())],
|
[...ships(), shipProps(ships(), gameProps.mode, targetPreview())],
|
||||||
selfIndex(),
|
sIndex,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,9 +98,11 @@ function BorderTiles() {
|
||||||
class={props.className}
|
class={props.className}
|
||||||
style={{ "--x": props.x, "--y": props.y }}
|
style={{ "--x": props.x, "--y": props.y }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (gameState() === "running") {
|
const sIndex = selfIndex()
|
||||||
|
if (sIndex === -1) return
|
||||||
|
if (gameProps.gameState === "running") {
|
||||||
settingTarget(props.isGameTile, props.x, props.y)
|
settingTarget(props.isGameTile, props.x, props.y)
|
||||||
} else if (gameState() === "starting") {
|
} else if (gameProps.gameState === "starting") {
|
||||||
const { index } = intersectingShip(ships(), {
|
const { index } = intersectingShip(ships(), {
|
||||||
...mouseCursor(),
|
...mouseCursor(),
|
||||||
size: 1,
|
size: 1,
|
||||||
|
@ -107,8 +113,8 @@ function BorderTiles() {
|
||||||
settingTarget(props.isGameTile, props.x, props.y)
|
settingTarget(props.isGameTile, props.x, props.y)
|
||||||
else {
|
else {
|
||||||
const ship = ships()[index]
|
const ship = ships()[index]
|
||||||
setMode(ship.size - 2)
|
setGameProps("mode", ship.size - 2)
|
||||||
removeShip(ship, selfIndex())
|
removeShip(ship, sIndex)
|
||||||
setMouseCursor((e) => ({ ...e, shouldShow: true }))
|
setMouseCursor((e) => ({ ...e, shouldShow: true }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,10 +125,10 @@ function BorderTiles() {
|
||||||
y: props.y,
|
y: props.y,
|
||||||
shouldShow:
|
shouldShow:
|
||||||
props.isGameTile &&
|
props.isGameTile &&
|
||||||
(gameState() === "starting"
|
(gameProps.gameState === "starting"
|
||||||
? intersectingShip(
|
? intersectingShip(
|
||||||
ships(),
|
ships(),
|
||||||
shipProps(ships(), mode(), {
|
shipProps(ships(), gameProps.mode, {
|
||||||
x: props.x,
|
x: props.x,
|
||||||
y: props.y,
|
y: props.y,
|
||||||
orientation: targetPreview().orientation,
|
orientation: targetPreview().orientation,
|
||||||
|
|
|
@ -28,18 +28,11 @@ import { For, Show, createEffect } from "solid-js"
|
||||||
import { useNavigate } from "solid-start"
|
import { useNavigate } from "solid-start"
|
||||||
import { useDrawProps } from "~/hooks/useDrawProps"
|
import { useDrawProps } from "~/hooks/useDrawProps"
|
||||||
import {
|
import {
|
||||||
allowChat,
|
gameProps,
|
||||||
allowMarkDraw,
|
|
||||||
allowSpecials,
|
|
||||||
allowSpectators,
|
|
||||||
gameState,
|
|
||||||
menu,
|
|
||||||
mode,
|
|
||||||
reset,
|
reset,
|
||||||
|
setGameProps,
|
||||||
setGameSetting,
|
setGameSetting,
|
||||||
setIsReadyFor,
|
setIsReadyFor,
|
||||||
setMenu,
|
|
||||||
setMode,
|
|
||||||
setTarget,
|
setTarget,
|
||||||
setTargetPreview,
|
setTargetPreview,
|
||||||
target,
|
target,
|
||||||
|
@ -60,36 +53,36 @@ function EventBar(props: { clear: () => void }) {
|
||||||
icon: "burger-menu",
|
icon: "burger-menu",
|
||||||
text: "Menu",
|
text: "Menu",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("menu")
|
setGameProps("menu", "menu")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gameState() === "running"
|
gameProps.gameState === "running"
|
||||||
? {
|
? {
|
||||||
icon: faSwords,
|
icon: faSwords,
|
||||||
text: "Attack",
|
text: "Attack",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("moves")
|
setGameProps("menu", "moves")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
icon: faShip,
|
icon: faShip,
|
||||||
text: "Ships",
|
text: "Ships",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("moves")
|
setGameProps("menu", "moves")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "pen",
|
icon: "pen",
|
||||||
text: "Draw",
|
text: "Draw",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("draw")
|
setGameProps("menu", "draw")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "gear",
|
icon: "gear",
|
||||||
text: "Settings",
|
text: "Settings",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("settings")
|
setGameProps("menu", "settings")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -99,48 +92,46 @@ function EventBar(props: { clear: () => void }) {
|
||||||
text: "Surrender",
|
text: "Surrender",
|
||||||
iconColor: "darkred",
|
iconColor: "darkred",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("surrender")
|
setGameProps("menu", "surrender")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
moves:
|
moves:
|
||||||
gameState() === "running"
|
gameProps.gameState === "running"
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
icon: "scope",
|
icon: "scope",
|
||||||
text: "Fire missile",
|
text: "Fire missile",
|
||||||
enabled: mode() === 0,
|
enabled: gameProps.mode === 0,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMode(0)
|
setGameProps("mode", 0)
|
||||||
setTarget((t) => ({ ...t, show: false }))
|
setTarget((t) => ({ ...t, show: false }))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "torpedo",
|
icon: "torpedo",
|
||||||
text: "Fire torpedo",
|
text: "Fire torpedo",
|
||||||
enabled: mode() === 1 || mode() === 2,
|
enabled: gameProps.mode === 1 || gameProps.mode === 2,
|
||||||
amount:
|
amount:
|
||||||
2 -
|
2 -
|
||||||
(selfUser()
|
(selfUser()?.moves.filter(
|
||||||
?.moves()
|
(e) => e.type === "htorpedo" || e.type === "vtorpedo",
|
||||||
.filter((e) => e.type === "htorpedo" || e.type === "vtorpedo")
|
).length ?? 0),
|
||||||
.length ?? 0),
|
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMode(1)
|
setGameProps("mode", 1)
|
||||||
setTarget((t) => ({ ...t, show: false }))
|
setTarget((t) => ({ ...t, show: false }))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "radar",
|
icon: "radar",
|
||||||
text: "Radar scan",
|
text: "Radar scan",
|
||||||
enabled: mode() === 3,
|
enabled: gameProps.mode === 3,
|
||||||
amount:
|
amount:
|
||||||
1 -
|
1 -
|
||||||
(selfUser()
|
(selfUser()?.moves.filter((e) => e.type === "radar").length ??
|
||||||
?.moves()
|
0),
|
||||||
.filter((e) => e.type === "radar").length ?? 0),
|
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMode(3)
|
setGameProps("mode", 3)
|
||||||
setTarget((t) => ({ ...t, show: false }))
|
setTarget((t) => ({ ...t, show: false }))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -152,7 +143,7 @@ function EventBar(props: { clear: () => void }) {
|
||||||
amount: 1 - ships().filter((e) => e.size === 2).length,
|
amount: 1 - ships().filter((e) => e.size === 2).length,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
if (1 - ships().filter((e) => e.size === 2).length === 0) return
|
if (1 - ships().filter((e) => e.size === 2).length === 0) return
|
||||||
setMode(0)
|
setGameProps("mode", 0)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -161,7 +152,7 @@ function EventBar(props: { clear: () => void }) {
|
||||||
amount: 3 - ships().filter((e) => e.size === 3).length,
|
amount: 3 - ships().filter((e) => e.size === 3).length,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
if (3 - ships().filter((e) => e.size === 3).length === 0) return
|
if (3 - ships().filter((e) => e.size === 3).length === 0) return
|
||||||
setMode(1)
|
setGameProps("mode", 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -170,7 +161,7 @@ function EventBar(props: { clear: () => void }) {
|
||||||
amount: 2 - ships().filter((e) => e.size === 4).length,
|
amount: 2 - ships().filter((e) => e.size === 4).length,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
if (2 - ships().filter((e) => e.size === 4).length === 0) return
|
if (2 - ships().filter((e) => e.size === 4).length === 0) return
|
||||||
setMode(2)
|
setGameProps("mode", 2)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -199,31 +190,31 @@ function EventBar(props: { clear: () => void }) {
|
||||||
{
|
{
|
||||||
icon: faGlasses,
|
icon: faGlasses,
|
||||||
text: "Spectators",
|
text: "Spectators",
|
||||||
disabled: !allowSpectators(),
|
disabled: !gameProps.allowSpectators,
|
||||||
callback: setGameSetting({
|
callback: setGameSetting({
|
||||||
allowSpectators: !allowSpectators(),
|
allowSpectators: !gameProps.allowSpectators,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: faSparkles,
|
icon: faSparkles,
|
||||||
text: "Specials",
|
text: "Specials",
|
||||||
disabled: !allowSpecials(),
|
disabled: !gameProps.allowSpecials,
|
||||||
callback: setGameSetting({
|
callback: setGameSetting({
|
||||||
allowSpecials: !allowSpecials(),
|
allowSpecials: !gameProps.allowSpecials,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: faComments,
|
icon: faComments,
|
||||||
text: "Chat",
|
text: "Chat",
|
||||||
disabled: !allowChat(),
|
disabled: !gameProps.allowChat,
|
||||||
callback: setGameSetting({ allowChat: !allowChat() }),
|
callback: setGameSetting({ allowChat: !gameProps.allowChat }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: faScribble,
|
icon: faScribble,
|
||||||
text: "Mark/Draw",
|
text: "Mark/Draw",
|
||||||
disabled: !allowMarkDraw(),
|
disabled: !gameProps.allowMarkDraw,
|
||||||
callback: setGameSetting({
|
callback: setGameSetting({
|
||||||
allowMarkDraw: !allowMarkDraw(),
|
allowMarkDraw: !gameProps.allowMarkDraw,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -243,7 +234,7 @@ function EventBar(props: { clear: () => void }) {
|
||||||
text: "No",
|
text: "No",
|
||||||
iconColor: "red",
|
iconColor: "red",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("main")
|
setGameProps("menu", "main")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -251,22 +242,22 @@ function EventBar(props: { clear: () => void }) {
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (
|
if (
|
||||||
menu() !== "moves" ||
|
gameProps.menu !== "moves" ||
|
||||||
gameState() !== "starting" ||
|
gameProps.gameState !== "starting" ||
|
||||||
mode() < 0 ||
|
gameProps.mode < 0 ||
|
||||||
items().moves[mode()].amount
|
items().moves[gameProps.mode].amount
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
const index = items().moves.findIndex((e) => e.amount)
|
const index = items().moves.findIndex((e) => e.amount)
|
||||||
setMode(index)
|
setGameProps("mode", index)
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
setEnable(menu() === "draw")
|
setEnable(gameProps.menu === "draw")
|
||||||
})
|
})
|
||||||
|
|
||||||
// createEffect(() => {
|
// createEffect(() => {
|
||||||
// if (gameState() !== "running") return
|
// if (gameProps.gameState !== "running") return
|
||||||
|
|
||||||
// const toastId = "otherPlayer"
|
// const toastId = "otherPlayer"
|
||||||
// if (isActiveIndex) toast.dismiss(toastId)
|
// if (isActiveIndex) toast.dismiss(toastId)
|
||||||
|
@ -293,47 +284,55 @@ function EventBar(props: { clear: () => void }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="event-bar">
|
<div class="event-bar">
|
||||||
<Show when={menu() !== "main"}>
|
<Show when={gameProps.menu !== "main"}>
|
||||||
<Item
|
<Item
|
||||||
{...{
|
{...{
|
||||||
icon: faReply,
|
icon: faReply,
|
||||||
text: "Return",
|
text: "Return",
|
||||||
iconColor: "#555",
|
iconColor: "#555",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setMenu("main")
|
setGameProps("menu", "main")
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
<For each={items()[menu()]}>
|
<For each={items()[gameProps.menu]}>
|
||||||
{(e, i) => (
|
{(e, i) => (
|
||||||
<Show when={isActiveIndex() || menu() !== "main" || i() !== 1}>
|
<Show
|
||||||
|
when={isActiveIndex() || gameProps.menu !== "main" || i() !== 1}
|
||||||
|
>
|
||||||
<Item {...e} />
|
<Item {...e} />
|
||||||
</Show>
|
</Show>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
<Show when={menu() === "moves"}>
|
<Show when={gameProps.menu === "moves"}>
|
||||||
<Item
|
<Item
|
||||||
{...{
|
{...{
|
||||||
icon: selfUser()?.isReady() ? faLock : faCheck,
|
icon: selfUser()?.isReady ? faLock : faCheck,
|
||||||
text: selfUser()?.isReady() ? "unready" : "Done",
|
text: selfUser()?.isReady ? "unready" : "Done",
|
||||||
disabled: gameState() === "starting" ? mode() >= 0 : undefined,
|
disabled:
|
||||||
enabled: gameState() === "running" && mode() >= 0 && target().show,
|
gameProps.gameState === "starting"
|
||||||
|
? gameProps.mode >= 0
|
||||||
|
: undefined,
|
||||||
|
enabled:
|
||||||
|
gameProps.gameState === "running" &&
|
||||||
|
gameProps.mode >= 0 &&
|
||||||
|
target().show,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
const i = selfIndex()
|
const i = selfIndex()
|
||||||
if (i === -1) return
|
if (i === -1) return
|
||||||
switch (gameState()) {
|
switch (gameProps.gameState) {
|
||||||
case "starting":
|
case "starting":
|
||||||
const isReady = !users[i].isReady()
|
const isReady = !users[i]?.isReady
|
||||||
setIsReadyFor({ isReady, i })
|
setIsReadyFor({ isReady, i })
|
||||||
socket.emit("isReady", isReady)
|
socket.emit("isReady", isReady)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "running":
|
case "running":
|
||||||
const moves = selfUser()?.moves()
|
const moves = selfUser()?.moves
|
||||||
const length = moves?.length
|
const length = moves?.length
|
||||||
const props = {
|
const props = {
|
||||||
type: modes[mode()].type,
|
type: modes[gameProps.mode].type,
|
||||||
x: target().x,
|
x: target().x,
|
||||||
y: target().y,
|
y: target().y,
|
||||||
orientation: target().orientation,
|
orientation: target().orientation,
|
||||||
|
|
|
@ -11,12 +11,10 @@ import { useDraw } from "~/hooks/useDraw"
|
||||||
import { useDrawProps } from "~/hooks/useDrawProps"
|
import { useDrawProps } from "~/hooks/useDrawProps"
|
||||||
import {
|
import {
|
||||||
full,
|
full,
|
||||||
gameId,
|
gameProps,
|
||||||
gameState,
|
|
||||||
mode,
|
|
||||||
mouseCursor,
|
mouseCursor,
|
||||||
reset,
|
reset,
|
||||||
setMode,
|
setGameProps,
|
||||||
setMouseCursor,
|
setMouseCursor,
|
||||||
setTargetPreview,
|
setTargetPreview,
|
||||||
target,
|
target,
|
||||||
|
@ -40,27 +38,28 @@ function Gamefield() {
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (
|
if (
|
||||||
gameState() !== "starting" ||
|
gameProps.gameState !== "starting" ||
|
||||||
!users[0].isReady() ||
|
!users[0]?.isReady ||
|
||||||
!users[1].isReady()
|
!users[1]?.isReady
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
socket.emit("ships", ships() ?? [])
|
socket.emit("ships", ships())
|
||||||
socket.emit("gameState", "running")
|
socket.emit("gameState", "running")
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (gameId() || !isConnected()) return
|
if (gameProps.gameId || !isConnected) return
|
||||||
socket.emit("update", full)
|
socket.emit("update", full)
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (mode() < 0) return
|
if (gameProps.mode < 0) return
|
||||||
const { x, y, show } = target()
|
const { x, y, show } = target()
|
||||||
const { shouldShow, ...position } = mouseCursor()
|
const { shouldShow, ...position } = mouseCursor()
|
||||||
if (
|
if (
|
||||||
!shouldShow ||
|
!shouldShow ||
|
||||||
(gameState() === "running" && overlapsWithAnyBorder(position, mode()))
|
(gameProps.gameState === "running" &&
|
||||||
|
overlapsWithAnyBorder(position, gameProps.mode))
|
||||||
)
|
)
|
||||||
setTargetPreview((t) => ({ ...t, show: false }))
|
setTargetPreview((t) => ({ ...t, show: false }))
|
||||||
else {
|
else {
|
||||||
|
@ -71,14 +70,17 @@ function Gamefield() {
|
||||||
}))
|
}))
|
||||||
const handleKeyPress = (event: KeyboardEvent) => {
|
const handleKeyPress = (event: KeyboardEvent) => {
|
||||||
if (event.key !== "r") return
|
if (event.key !== "r") return
|
||||||
if (gameState() === "starting") {
|
if (gameProps.gameState === "starting") {
|
||||||
setTargetPreview((t) => ({
|
setTargetPreview((t) => ({
|
||||||
...t,
|
...t,
|
||||||
orientation: t.orientation === "h" ? "v" : "h",
|
orientation: t.orientation === "h" ? "v" : "h",
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
if (gameState() === "running" && (mode() === 1 || mode() === 2))
|
if (
|
||||||
setMode(mode() === 1 ? 2 : 1)
|
gameProps.gameState === "running" &&
|
||||||
|
(gameProps.mode === 1 || gameProps.mode === 2)
|
||||||
|
)
|
||||||
|
setGameProps("mode", gameProps.mode === 1 ? 2 : 1)
|
||||||
}
|
}
|
||||||
document.addEventListener("keydown", handleKeyPress)
|
document.addEventListener("keydown", handleKeyPress)
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
|
@ -88,7 +90,7 @@ function Gamefield() {
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (gameState() !== "aborted") return
|
if (gameProps.gameState !== "aborted") return
|
||||||
// toast.info("Enemy gave up!")
|
// toast.info("Enemy gave up!")
|
||||||
navigator("/")
|
navigator("/")
|
||||||
reset()
|
reset()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { For, Show } from "solid-js"
|
import { For, Show } from "solid-js"
|
||||||
import { gameState } from "~/hooks/useGameProps"
|
import { gameProps } from "~/hooks/useGameProps"
|
||||||
import { useSession } from "~/hooks/useSession"
|
import { useSession } from "~/hooks/useSession"
|
||||||
import Ship from "./Ship"
|
import Ship from "./Ship"
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ function Ships() {
|
||||||
const { isActiveIndex, selfUser } = useSession()
|
const { isActiveIndex, selfUser } = useSession()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={gameState() !== "running" || !isActiveIndex()}>
|
<Show when={gameProps.gameState !== "running" || !isActiveIndex()}>
|
||||||
<For each={selfUser()?.ships()}>{(props) => <Ship {...props} />}</For>
|
<For each={selfUser()?.ships}>{(props) => <Ship {...props} />}</For>
|
||||||
</Show>
|
</Show>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { For, Match, Switch } from "solid-js"
|
import { For, Match, Switch } from "solid-js"
|
||||||
import { gameState, mode, target, targetPreview } from "~/hooks/useGameProps"
|
import { gameProps, target, targetPreview } from "~/hooks/useGameProps"
|
||||||
import { useSession } from "~/hooks/useSession"
|
import { useSession } from "~/hooks/useSession"
|
||||||
import {
|
import {
|
||||||
|
compiledHits,
|
||||||
composeTargetTiles,
|
composeTargetTiles,
|
||||||
intersectingShip,
|
intersectingShip,
|
||||||
shipProps,
|
shipProps,
|
||||||
|
@ -11,29 +12,39 @@ import HitElems from "./HitElems"
|
||||||
import Ship from "./Ship"
|
import Ship from "./Ship"
|
||||||
|
|
||||||
function Targets() {
|
function Targets() {
|
||||||
const { activeUser, ships } = useSession()
|
const { activeIndex, ships } = useSession()
|
||||||
|
|
||||||
const ship = () => shipProps(ships(), mode(), targetPreview())
|
const ship = () => shipProps(ships(), gameProps.mode, targetPreview())
|
||||||
const intersectionProps = () => intersectingShip(ships(), ship())
|
const intersectionProps = () => intersectingShip(ships(), ship())
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={gameState() === "running"}>
|
<Match when={gameProps.gameState === "running"}>
|
||||||
<For each={composeTargetTiles(target(), mode(), activeUser().hits())}>
|
<For
|
||||||
|
each={composeTargetTiles(
|
||||||
|
target(),
|
||||||
|
gameProps.mode,
|
||||||
|
compiledHits(activeIndex() === 0 ? 1 : 0),
|
||||||
|
)}
|
||||||
|
>
|
||||||
{(props) => <GamefieldPointer {...props} />}
|
{(props) => <GamefieldPointer {...props} />}
|
||||||
</For>
|
</For>
|
||||||
<For
|
<For
|
||||||
each={composeTargetTiles(
|
each={composeTargetTiles(
|
||||||
targetPreview(),
|
targetPreview(),
|
||||||
mode(),
|
gameProps.mode,
|
||||||
activeUser().hits(),
|
compiledHits(activeIndex() === 0 ? 1 : 0),
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{(props) => <GamefieldPointer {...props} preview />}
|
{(props) => <GamefieldPointer {...props} preview />}
|
||||||
</For>
|
</For>
|
||||||
</Match>
|
</Match>
|
||||||
<Match
|
<Match
|
||||||
when={gameState() === "starting" && mode() >= 0 && targetPreview().show}
|
when={
|
||||||
|
gameProps.gameState === "starting" &&
|
||||||
|
gameProps.mode >= 0 &&
|
||||||
|
targetPreview().show
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Ship
|
<Ship
|
||||||
{...ship()}
|
{...ship()}
|
||||||
|
|
|
@ -5,15 +5,7 @@ import {
|
||||||
import { JSX, Show, createEffect, createSignal, onCleanup } from "solid-js"
|
import { JSX, Show, createEffect, createSignal, onCleanup } from "solid-js"
|
||||||
import { useNavigate } from "solid-start"
|
import { useNavigate } from "solid-start"
|
||||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||||
import {
|
import { full, gameProps, leave, reset, users } from "~/hooks/useGameProps"
|
||||||
full,
|
|
||||||
gameId,
|
|
||||||
gamePin,
|
|
||||||
gameState,
|
|
||||||
leave,
|
|
||||||
reset,
|
|
||||||
users,
|
|
||||||
} from "~/hooks/useGameProps"
|
|
||||||
import { useSession } from "~/hooks/useSession"
|
import { useSession } from "~/hooks/useSession"
|
||||||
import useSocket from "~/hooks/useSocket"
|
import useSocket from "~/hooks/useSocket"
|
||||||
import { socket } from "~/lib/socket"
|
import { socket } from "~/lib/socket"
|
||||||
|
@ -45,7 +37,7 @@ function LobbyFrame(props: { openSettings: () => void }) {
|
||||||
const navigator = useNavigate()
|
const navigator = useNavigate()
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
const [launchTime, setLaunchTime] = createSignal(3)
|
const [launchTime, setLaunchTime] = createSignal(3)
|
||||||
const launching = () => users[0].isReady() && users[1].isReady()
|
const launching = () => users[0]?.isReady && users[1]?.isReady
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (!launching() || launchTime() > 0) return
|
if (!launching() || launchTime() > 0) return
|
||||||
|
@ -64,12 +56,13 @@ function LobbyFrame(props: { openSettings: () => void }) {
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (gameId() || !isConnected()) return
|
if (gameProps.gameId || !isConnected) return
|
||||||
socket.emit("update", full)
|
socket.emit("update", full)
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (gameState() === "unknown" || gameState() === "lobby") return
|
if (gameProps.gameState === "unknown" || gameProps.gameState === "lobby")
|
||||||
|
return
|
||||||
navigator("/gamefield")
|
navigator("/gamefield")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -90,10 +83,10 @@ function LobbyFrame(props: { openSettings: () => void }) {
|
||||||
>
|
>
|
||||||
{"Game-PIN: "}
|
{"Game-PIN: "}
|
||||||
<Show
|
<Show
|
||||||
when={isConnected()}
|
when={isConnected}
|
||||||
fallback={<FontAwesomeIcon icon={faSpinnerThird} spin />}
|
fallback={<FontAwesomeIcon icon={faSpinnerThird} spin />}
|
||||||
>
|
>
|
||||||
<span class="underline">{gamePin() ?? "----"}</span>
|
<span class="underline">{gameProps.gamePin ?? "----"}</span>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -103,7 +96,7 @@ function LobbyFrame(props: { openSettings: () => void }) {
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-around">
|
<div class="flex items-center justify-around">
|
||||||
<Show
|
<Show
|
||||||
when={isConnected()}
|
when={isConnected}
|
||||||
fallback={
|
fallback={
|
||||||
<p class="font-farro m-48 text-center text-6xl font-medium">
|
<p class="font-farro m-48 text-center text-6xl font-medium">
|
||||||
Warte auf Verbindung
|
Warte auf Verbindung
|
||||||
|
@ -113,7 +106,7 @@ function LobbyFrame(props: { openSettings: () => void }) {
|
||||||
<>
|
<>
|
||||||
<Player src="player_blue.png" i={0} userId={session()?.user?.id} />
|
<Player src="player_blue.png" i={0} userId={session()?.user?.id} />
|
||||||
<p class="font-farro m-4 text-6xl font-semibold">VS</p>
|
<p class="font-farro m-4 text-6xl font-semibold">VS</p>
|
||||||
{users[1].id() ? (
|
{users[1] ? (
|
||||||
<Player src="player_red.png" i={1} userId={session()?.user?.id} />
|
<Player src="player_red.png" i={1} userId={session()?.user?.id} />
|
||||||
) : (
|
) : (
|
||||||
<p class="font-farro w-96 text-center text-4xl font-medium">
|
<p class="font-farro w-96 text-center text-4xl font-medium">
|
||||||
|
|
|
@ -44,9 +44,7 @@ function HourGlass() {
|
||||||
|
|
||||||
function Player(props: { src: string; i: 0 | 1; userId?: string }) {
|
function Player(props: { src: string; i: 0 | 1; userId?: string }) {
|
||||||
const player = () => users[props.i]
|
const player = () => users[props.i]
|
||||||
const isReady = () => users[props.i].isReady()
|
const primary = () => props.userId && props.userId === player()?.id
|
||||||
const isConnected = () => users[props.i].isConnected()
|
|
||||||
const primary = () => props.userId && props.userId === users[props.i].id()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex w-96 flex-col items-center gap-4 p-4">
|
<div class="flex w-96 flex-col items-center gap-4 p-4">
|
||||||
|
@ -56,7 +54,7 @@ function Player(props: { src: string; i: 0 | 1; userId?: string }) {
|
||||||
primary() ? "font-semibold" : "font-normal",
|
primary() ? "font-semibold" : "font-normal",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{player().name() ?? "Spieler " + (props.i === 1 ? "2" : "1")}
|
{player()?.name ?? "Spieler " + (props.i === 1 ? "2" : "1")}
|
||||||
</p>
|
</p>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img
|
<img
|
||||||
|
@ -74,21 +72,27 @@ function Player(props: { src: string; i: 0 | 1; userId?: string }) {
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
type={isConnected() ? (isReady() ? "green" : "orange") : "gray"}
|
type={
|
||||||
|
player()?.isConnected
|
||||||
|
? player()?.isReady
|
||||||
|
? "green"
|
||||||
|
: "orange"
|
||||||
|
: "gray"
|
||||||
|
}
|
||||||
latching
|
latching
|
||||||
isLatched={!!isReady()}
|
isLatched={player()?.isReady}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!player()) return
|
if (!player()) return
|
||||||
socket.emit("isReady", !isReady())
|
socket.emit("isReady", !player()?.isReady)
|
||||||
setIsReadyFor({
|
setIsReadyFor({
|
||||||
i: props.i,
|
i: props.i,
|
||||||
isReady: !isReady(),
|
isReady: !player()?.isReady,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
disabled={!primary()}
|
disabled={!primary()}
|
||||||
>
|
>
|
||||||
Ready
|
Ready
|
||||||
{isReady() && isConnected() ? (
|
{player()?.isReady && player()?.isConnected ? (
|
||||||
<FontAwesomeIcon icon={faCheck} class="ml-4 w-12" />
|
<FontAwesomeIcon icon={faCheck} class="ml-4 w-12" />
|
||||||
) : primary() ? (
|
) : primary() ? (
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
|
@ -3,11 +3,10 @@ import { socket } from "~/lib/socket"
|
||||||
import { GamePropsSchema, GameState } from "~/lib/zodSchemas"
|
import { GamePropsSchema, GameState } from "~/lib/zodSchemas"
|
||||||
// import { toast } from "react-toastify"
|
// import { toast } from "react-toastify"
|
||||||
import { createSignal } from "solid-js"
|
import { createSignal } from "solid-js"
|
||||||
|
import { createStore } from "solid-js/store"
|
||||||
import { getPayloadFromProps } from "~/lib/getPayloadFromProps"
|
import { getPayloadFromProps } from "~/lib/getPayloadFromProps"
|
||||||
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
|
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
|
||||||
import {
|
import {
|
||||||
compileHits,
|
|
||||||
initialUser,
|
|
||||||
initlialMouseCursor,
|
initlialMouseCursor,
|
||||||
initlialTarget,
|
initlialTarget,
|
||||||
initlialTargetPreview,
|
initlialTargetPreview,
|
||||||
|
@ -17,81 +16,75 @@ import {
|
||||||
GameSettings,
|
GameSettings,
|
||||||
MouseCursor,
|
MouseCursor,
|
||||||
MoveDispatchProps,
|
MoveDispatchProps,
|
||||||
NewUsers,
|
|
||||||
ShipProps,
|
ShipProps,
|
||||||
Target,
|
Target,
|
||||||
TargetPreview,
|
TargetPreview,
|
||||||
|
User,
|
||||||
|
Users,
|
||||||
} from "../interfaces/frontend"
|
} from "../interfaces/frontend"
|
||||||
|
|
||||||
export const [hash, setHash] = createSignal<string | null>(null)
|
export interface GameProps {
|
||||||
export const [gamePin, setGamePin] = createSignal<string | null>(null)
|
hash: string | null
|
||||||
export const [gameId, setGameId] = createSignal<string>("")
|
gamePin: string | null
|
||||||
export const [gameState, setGameState] = createSignal<GameState>("unknown")
|
gameId: string
|
||||||
export const [allowChat, setAllowChat] = createSignal(false)
|
gameState: GameState
|
||||||
export const [allowMarkDraw, setAllowMarkDraw] = createSignal(false)
|
allowChat: boolean
|
||||||
export const [allowSpecials, setAllowSpecials] = createSignal(false)
|
allowMarkDraw: boolean
|
||||||
export const [allowSpectators, setallowSpectators] = createSignal(false)
|
allowSpecials: boolean
|
||||||
export const [menu, setMenu] = createSignal<keyof EventBarModes>("moves")
|
allowSpectators: boolean
|
||||||
export const [mode, setMode] = createSignal(0)
|
menu: keyof EventBarModes
|
||||||
|
mode: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialGameProps = {
|
||||||
|
hash: null,
|
||||||
|
gamePin: null,
|
||||||
|
gameId: "",
|
||||||
|
gameState: "unknown",
|
||||||
|
allowChat: false,
|
||||||
|
allowMarkDraw: false,
|
||||||
|
allowSpecials: false,
|
||||||
|
allowSpectators: false,
|
||||||
|
menu: "moves",
|
||||||
|
mode: 0,
|
||||||
|
} satisfies GameProps
|
||||||
|
|
||||||
|
export const [gameProps, setGameProps] =
|
||||||
|
createStore<GameProps>(initialGameProps)
|
||||||
|
|
||||||
|
const initialUsers = { 0: null, 1: null }
|
||||||
|
export const [users, setUsers] = createStore<Users>(initialUsers)
|
||||||
|
|
||||||
export const [target, setTarget] = createSignal<Target>(initlialTarget)
|
export const [target, setTarget] = createSignal<Target>(initlialTarget)
|
||||||
export const [targetPreview, setTargetPreview] = createSignal<TargetPreview>(
|
export const [targetPreview, setTargetPreview] = createSignal<TargetPreview>(
|
||||||
initlialTargetPreview,
|
initlialTargetPreview,
|
||||||
)
|
)
|
||||||
export const [mouseCursor, setMouseCursor] =
|
export const [mouseCursor, setMouseCursor] =
|
||||||
createSignal<MouseCursor>(initlialMouseCursor)
|
createSignal<MouseCursor>(initlialMouseCursor)
|
||||||
export const users = {
|
|
||||||
0: {
|
|
||||||
...initialUser(),
|
|
||||||
hits: () => compileHits(users, 0),
|
|
||||||
},
|
|
||||||
1: { ...initialUser(), hits: () => compileHits(users, 1) },
|
|
||||||
forEach(cb: (user: ReturnType<typeof initialUser>, i: 0 | 1) => void) {
|
|
||||||
cb(this[0], 0)
|
|
||||||
cb(this[1], 1)
|
|
||||||
},
|
|
||||||
map<T>(cb: (user: ReturnType<typeof initialUser>, i: 0 | 1) => T) {
|
|
||||||
return { 0: cb(this[0], 0), 1: cb(this[1], 1) }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
export type Users = typeof users
|
|
||||||
|
|
||||||
export function DispatchMove(move: MoveDispatchProps, index: 0 | 1) {
|
export function DispatchMove(move: MoveDispatchProps, index: 0 | 1) {
|
||||||
users[index].setMoves((e) => [...e, move])
|
setUsers(index, "moves", (e) => [...e, move])
|
||||||
}
|
}
|
||||||
export function setShips(ships: ShipProps[], index: number) {
|
export function setShips(ships: ShipProps[], index: 0 | 1) {
|
||||||
users.forEach(({ setShips }, i) => {
|
setUsers(index, "ships", ships)
|
||||||
if (index !== i) return
|
|
||||||
setShips(ships)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
export function removeShip({ size, variant, x, y }: ShipProps, index: number) {
|
export function removeShip({ size, variant, x, y }: ShipProps, index: 0 | 1) {
|
||||||
users.forEach((user, i) => {
|
setUsers(index, "ships", (ships) => {
|
||||||
if (index !== i) return
|
const indexToRemove = ships.findIndex(
|
||||||
const indexToRemove = user
|
(ship) =>
|
||||||
.ships()
|
ship.size === size &&
|
||||||
.findIndex(
|
ship.variant === variant &&
|
||||||
(ship) =>
|
ship.x === x &&
|
||||||
ship.size === size &&
|
ship.y === y,
|
||||||
ship.variant === variant &&
|
)
|
||||||
ship.x === x &&
|
|
||||||
ship.y === y,
|
return ships.filter((_, i) => i !== indexToRemove)
|
||||||
)
|
|
||||||
user.setShips((ships) => ships.filter((_, i) => i !== indexToRemove))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPlayer(newUsers: NewUsers): string | null {
|
export function setPlayer(newUsers: Users): string | null {
|
||||||
let hash: string | null = null
|
let hash: string | null = null
|
||||||
users.forEach((user, i) => {
|
setUsers(newUsers)
|
||||||
const newUser = newUsers[i]
|
|
||||||
if (!newUser) return defaultUser(user)
|
|
||||||
|
|
||||||
user.setId(newUser.id)
|
|
||||||
user.setName(newUser.name)
|
|
||||||
user.setChats(newUser.chats)
|
|
||||||
user.setMoves(newUser.moves)
|
|
||||||
user.setShips(newUser.ships)
|
|
||||||
})
|
|
||||||
const body = getPayloadwithChecksum(getPayloadFromProps())
|
const body = getPayloadwithChecksum(getPayloadFromProps())
|
||||||
if (!body.hash) {
|
if (!body.hash) {
|
||||||
console.log("Something is wrong... ")
|
console.log("Something is wrong... ")
|
||||||
|
@ -102,15 +95,15 @@ export function setPlayer(newUsers: NewUsers): string | null {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
hash = body.hash
|
hash = body.hash
|
||||||
setHash(hash)
|
setGameProps("hash", hash)
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
export function setSetting(newSettings: GameSettings): string | null {
|
export function setSetting(newSettings: GameSettings): string | null {
|
||||||
let hash: string | null = null
|
let hash: string | null = null
|
||||||
setAllowChat((e) => newSettings.allowChat ?? e)
|
setGameProps("allowChat", (e) => newSettings.allowChat ?? e)
|
||||||
setAllowMarkDraw((e) => newSettings.allowMarkDraw ?? e)
|
setGameProps("allowMarkDraw", (e) => newSettings.allowMarkDraw ?? e)
|
||||||
setAllowSpecials((e) => newSettings.allowSpecials ?? e)
|
setGameProps("allowSpecials", (e) => newSettings.allowSpecials ?? e)
|
||||||
setallowSpectators((e) => newSettings.allowSpectators ?? e)
|
setGameProps("allowSpectators", (e) => newSettings.allowSpectators ?? e)
|
||||||
const body = getPayloadwithChecksum(getPayloadFromProps())
|
const body = getPayloadwithChecksum(getPayloadFromProps())
|
||||||
if (!body.hash) {
|
if (!body.hash) {
|
||||||
console.log("Something is wrong... ")
|
console.log("Something is wrong... ")
|
||||||
|
@ -121,7 +114,7 @@ export function setSetting(newSettings: GameSettings): string | null {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
hash = body.hash
|
hash = body.hash
|
||||||
setHash(hash)
|
setGameProps("hash", hash)
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,36 +130,41 @@ export function setGameSetting(newSettings: GameSettings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function full(newProps: GamePropsSchema) {
|
export function full(newProps: GamePropsSchema) {
|
||||||
if (hash() === newProps.hash) {
|
if (gameProps.hash === newProps.hash) {
|
||||||
console.log("Everything up to date.")
|
console.log("Everything up to date.")
|
||||||
} else {
|
} else {
|
||||||
console.log("Update was needed.", hash(), newProps.hash)
|
console.log("Update was needed.", gameProps.hash, newProps.hash)
|
||||||
|
|
||||||
if (gameId() !== newProps.payload?.game?.id)
|
if (gameProps.gameId !== newProps.payload?.game?.id)
|
||||||
console.warn(
|
console.warn(
|
||||||
"Different gameId detected on update: ",
|
"Different gameId detected on update: ",
|
||||||
gameId(),
|
gameProps.gameId,
|
||||||
newProps.payload?.game?.id,
|
newProps.payload?.game?.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
setHash(newProps.hash)
|
setGameProps({
|
||||||
setGamePin(newProps.payload.gamePin)
|
hash: newProps.hash,
|
||||||
setGameId(newProps.payload.game?.id ?? "")
|
gamePin: newProps.payload.gamePin,
|
||||||
setGameState(newProps.payload.game?.state ?? "unknown")
|
gameId: newProps.payload.game?.id ?? "",
|
||||||
setAllowChat(newProps.payload.game?.allowChat ?? false)
|
gameState: newProps.payload.game?.state ?? "unknown",
|
||||||
setAllowMarkDraw(newProps.payload.game?.allowMarkDraw ?? false)
|
allowChat: newProps.payload.game?.allowChat ?? false,
|
||||||
setAllowSpecials(newProps.payload.game?.allowSpecials ?? false)
|
allowMarkDraw: newProps.payload.game?.allowMarkDraw ?? false,
|
||||||
setallowSpectators(newProps.payload.game?.allowSpectators ?? false)
|
allowSpecials: newProps.payload.game?.allowSpecials ?? false,
|
||||||
users.forEach((user, i) => {
|
allowSpectators: newProps.payload.game?.allowSpectators ?? false,
|
||||||
const newUser = newProps.payload.users[i]
|
|
||||||
if (!newUser) return
|
|
||||||
|
|
||||||
user.setId(newUser.id)
|
|
||||||
user.setName(newUser.name)
|
|
||||||
user.setChats(newUser.chats)
|
|
||||||
user.setMoves(newUser.moves)
|
|
||||||
user.setShips(newUser.ships)
|
|
||||||
})
|
})
|
||||||
|
const compiledUsers = [
|
||||||
|
newProps.payload.users[0],
|
||||||
|
newProps.payload.users[1],
|
||||||
|
].map((user) =>
|
||||||
|
user
|
||||||
|
? {
|
||||||
|
...user,
|
||||||
|
isReady: false,
|
||||||
|
isConnected: false,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
) as [User, User]
|
||||||
|
setUsers({ 0: compiledUsers[0], 1: compiledUsers[1] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function leave(cb: () => void) {
|
export function leave(cb: () => void) {
|
||||||
|
@ -179,12 +177,12 @@ export function leave(cb: () => void) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export function setIsReadyFor({ i, isReady }: { i: 0 | 1; isReady: boolean }) {
|
export function setIsReadyFor({ i, isReady }: { i: 0 | 1; isReady: boolean }) {
|
||||||
users[i].setIsReady(isReady)
|
setUsers(i, (e) => ({ ...e, isReady, isConnected: true }))
|
||||||
users[i].setIsConnected(true)
|
|
||||||
}
|
}
|
||||||
export function newGameState(newState: GameState) {
|
export function newGameState(newState: GameState) {
|
||||||
setGameState(newState)
|
setGameProps("gameState", newState)
|
||||||
users.forEach((e) => e.setIsReady(false))
|
setUsers(0, (e) => (e && e.isReady ? { isReady: false } : e))
|
||||||
|
setUsers(1, (e) => (e && e.isReady ? { isReady: false } : e))
|
||||||
}
|
}
|
||||||
export function setIsConnectedFor({
|
export function setIsConnectedFor({
|
||||||
i,
|
i,
|
||||||
|
@ -193,34 +191,15 @@ export function setIsConnectedFor({
|
||||||
i: 0 | 1
|
i: 0 | 1
|
||||||
isConnected: boolean
|
isConnected: boolean
|
||||||
}) {
|
}) {
|
||||||
users[i].setIsConnected(isConnected)
|
setUsers(i, "isConnected", isConnected)
|
||||||
if (isConnected) return
|
if (isConnected) return
|
||||||
users[i].setIsReady(false)
|
setUsers(i, "isReady", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reset() {
|
export function reset() {
|
||||||
setHash(null)
|
setGameProps(initialGameProps)
|
||||||
setGamePin(null)
|
|
||||||
setGameId("")
|
|
||||||
setGameState("unknown")
|
|
||||||
setallowSpectators(false)
|
|
||||||
setAllowSpecials(false)
|
|
||||||
setAllowChat(false)
|
|
||||||
setAllowMarkDraw(false)
|
|
||||||
setMenu("moves")
|
|
||||||
setMode(0)
|
|
||||||
setTarget(initlialTarget)
|
setTarget(initlialTarget)
|
||||||
setTargetPreview(initlialTargetPreview)
|
setTargetPreview(initlialTargetPreview)
|
||||||
setMouseCursor(initlialMouseCursor)
|
setMouseCursor(initlialMouseCursor)
|
||||||
users.forEach(defaultUser)
|
setUsers(initialUsers)
|
||||||
}
|
|
||||||
|
|
||||||
function defaultUser(user: ReturnType<typeof initialUser>) {
|
|
||||||
user.setIsReady(false)
|
|
||||||
user.setIsConnected(false)
|
|
||||||
user.setId("")
|
|
||||||
user.setName("")
|
|
||||||
user.setChats([])
|
|
||||||
user.setMoves([])
|
|
||||||
user.setShips([])
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,15 @@ import {
|
||||||
useContext,
|
useContext,
|
||||||
} from "solid-js"
|
} from "solid-js"
|
||||||
import { useIsRouting } from "solid-start"
|
import { useIsRouting } from "solid-start"
|
||||||
import { gameState, setMenu, setMode, users } from "./useGameProps"
|
import { gameProps, setGameProps, users } from "./useGameProps"
|
||||||
|
|
||||||
const [state, setState] = createSignal<Session | null | undefined>(undefined)
|
const [state, setState] = createSignal<Session | null | undefined>(undefined)
|
||||||
|
|
||||||
const selfIndex = () => {
|
const selfIndex = () => {
|
||||||
switch (state()?.user?.id) {
|
switch (state()?.user?.id) {
|
||||||
case users[0].id():
|
case users[0]?.id:
|
||||||
return 0
|
return 0
|
||||||
case users[1].id():
|
case users[1]?.id:
|
||||||
return 1
|
return 1
|
||||||
default:
|
default:
|
||||||
return -1
|
return -1
|
||||||
|
@ -24,9 +25,9 @@ const selfIndex = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeIndex = () => {
|
const activeIndex = () => {
|
||||||
if (gameState() !== "running") return 0
|
if (gameProps.gameState !== "running") return 0
|
||||||
const l1 = users[0].moves().length
|
const l1 = users[0]?.moves.length ?? 0
|
||||||
const l2 = users[1].moves().length
|
const l2 = users[1]?.moves.length ?? 0
|
||||||
return l1 > l2 ? 1 : 0
|
return l1 > l2 ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +49,8 @@ const selfUser = () => {
|
||||||
*/
|
*/
|
||||||
const activeUser = () => users[activeIndex() === 0 ? 1 : 0]
|
const activeUser = () => users[activeIndex() === 0 ? 1 : 0]
|
||||||
|
|
||||||
const ships = () => selfUser()?.ships() ?? []
|
const ships = () => selfUser()?.ships ?? []
|
||||||
|
|
||||||
const contextValue = {
|
const contextValue = {
|
||||||
session: state,
|
session: state,
|
||||||
selfIndex,
|
selfIndex,
|
||||||
|
@ -82,13 +84,13 @@ export function SessionProvider(props: { children: JSX.Element }) {
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (gameState() !== "running") return
|
if (gameProps.gameState !== "running") return
|
||||||
if (activeIndex() === selfIndex()) {
|
if (activeIndex() === selfIndex()) {
|
||||||
setMenu("moves")
|
setGameProps("menu", "moves")
|
||||||
setMode(0)
|
setGameProps("mode", 0)
|
||||||
} else {
|
} else {
|
||||||
setMenu("main")
|
setGameProps("menu", "main")
|
||||||
setMode(-1)
|
setGameProps("mode", -1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,15 @@ import status from "http-status"
|
||||||
import { createEffect, createSignal, onCleanup } from "solid-js"
|
import { createEffect, createSignal, onCleanup } from "solid-js"
|
||||||
import { useNavigate } from "solid-start"
|
import { useNavigate } from "solid-start"
|
||||||
import { socket } from "~/lib/socket"
|
import { socket } from "~/lib/socket"
|
||||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
import { frontendUsers } from "~/lib/utils/helpers"
|
||||||
|
import { GamePropsSchema, GameState } from "~/lib/zodSchemas"
|
||||||
import { isAuthenticated } from "~/routes/start"
|
import { isAuthenticated } from "~/routes/start"
|
||||||
import { GameSettings, PlayerEvent } from "../interfaces/frontend"
|
import { GameSettings, PlayerEvent } from "../interfaces/frontend"
|
||||||
import {
|
import {
|
||||||
DispatchMove,
|
DispatchMove,
|
||||||
full,
|
full,
|
||||||
gameId,
|
gameProps,
|
||||||
setGameState,
|
setGameProps,
|
||||||
setIsConnectedFor,
|
setIsConnectedFor,
|
||||||
setIsReadyFor,
|
setIsReadyFor,
|
||||||
setPlayer,
|
setPlayer,
|
||||||
|
@ -29,7 +30,7 @@ function useSocket() {
|
||||||
const isConnected = () => {
|
const isConnected = () => {
|
||||||
const i = selfIndex()
|
const i = selfIndex()
|
||||||
return i !== -1
|
return i !== -1
|
||||||
? users[i].isConnected() && isConnectedState()
|
? users[i]?.isConnected && isConnectedState()
|
||||||
: isConnectedState()
|
: isConnectedState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +88,8 @@ function useSocket() {
|
||||||
isConnected: true,
|
isConnected: true,
|
||||||
})
|
})
|
||||||
const index = selfIndex()
|
const index = selfIndex()
|
||||||
if (index !== -1) socket.emit("isReady", users[index].isReady())
|
if (index !== -1)
|
||||||
|
socket.emit("isReady", users[index]?.isReady ?? false)
|
||||||
message = "Player has joined the lobby."
|
message = "Player has joined the lobby."
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -100,7 +102,7 @@ function useSocket() {
|
||||||
if (type === "disconnect") return
|
if (type === "disconnect") return
|
||||||
|
|
||||||
const { hash } = event
|
const { hash } = event
|
||||||
const newHash = setPlayer(event.users)
|
const newHash = setPlayer(frontendUsers(event.users))
|
||||||
if (!newHash || newHash === hash) return
|
if (!newHash || newHash === hash) return
|
||||||
console.log("hash", hash, newHash)
|
console.log("hash", hash, newHash)
|
||||||
socket.emit("update", (body) => {
|
socket.emit("update", (body) => {
|
||||||
|
@ -109,6 +111,8 @@ function useSocket() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setGameState = (state: GameState) => setGameProps("gameState", state)
|
||||||
|
|
||||||
const gameSetting = (newSettings: GameSettings, hash: string) => {
|
const gameSetting = (newSettings: GameSettings, hash: string) => {
|
||||||
const newHash = setSetting(newSettings)
|
const newHash = setSetting(newSettings)
|
||||||
if (!newHash || newHash === hash) return
|
if (!newHash || newHash === hash) return
|
||||||
|
@ -148,7 +152,7 @@ function useSocket() {
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (!gameId()) {
|
if (!gameProps.gameId) {
|
||||||
socket.disconnect()
|
socket.disconnect()
|
||||||
fetch("/api/game/running", {
|
fetch("/api/game/running", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
|
@ -26,11 +26,11 @@ export interface ServerToClientEvents {
|
||||||
isReady: (payload: { i: 0 | 1; isReady: boolean }) => void
|
isReady: (payload: { i: 0 | 1; isReady: boolean }) => void
|
||||||
isConnected: (payload: { i: 0 | 1; isConnected: boolean }) => void
|
isConnected: (payload: { i: 0 | 1; isConnected: boolean }) => void
|
||||||
"get-canvas-state": () => void
|
"get-canvas-state": () => void
|
||||||
"canvas-state-from-server": (state: string, userIndex: number) => void
|
"canvas-state-from-server": (state: string, userIndex: 0 | 1) => void
|
||||||
"draw-line": (props: DrawLineProps, userIndex: number) => void
|
"draw-line": (props: DrawLineProps, userIndex: 0 | 1) => void
|
||||||
"canvas-clear": () => void
|
"canvas-clear": () => void
|
||||||
gameState: (newState: GameState) => void
|
gameState: (newState: GameState) => void
|
||||||
ships: (ships: ShipProps[], index: number) => void
|
ships: (ships: ShipProps[], index: 0 | 1) => void
|
||||||
dispatchMove: (props: MoveDispatchProps, i: 0 | 1) => void
|
dispatchMove: (props: MoveDispatchProps, i: 0 | 1) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ interface SocketData {
|
||||||
props: {
|
props: {
|
||||||
userId: string
|
userId: string
|
||||||
gameId: string
|
gameId: string
|
||||||
index: number
|
index: 0 | 1
|
||||||
}
|
}
|
||||||
user: Session["user"]
|
user: Session["user"]
|
||||||
gameId: string
|
gameId: string
|
||||||
|
|
|
@ -81,11 +81,15 @@ export type PlayerEvent =
|
||||||
| {
|
| {
|
||||||
type: "connect" | "leave"
|
type: "connect" | "leave"
|
||||||
i: 0 | 1
|
i: 0 | 1
|
||||||
users: NewUsers
|
users: Players
|
||||||
hash: string
|
hash: string
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "disconnect"
|
type: "disconnect"
|
||||||
i: 0 | 1
|
i: 0 | 1
|
||||||
}
|
}
|
||||||
export type NewUsers = { 0: PlayerSchema | null; 1: PlayerSchema | null }
|
export type Players = { 0: PlayerSchema; 1: PlayerSchema }
|
||||||
|
export type User =
|
||||||
|
| (PlayerSchema & { isReady: boolean; isConnected: boolean })
|
||||||
|
| null
|
||||||
|
export type Users = { 0: User; 1: User }
|
||||||
|
|
|
@ -1,32 +1,28 @@
|
||||||
import {
|
import { gameProps, users } from "~/hooks/useGameProps"
|
||||||
allowChat,
|
|
||||||
allowMarkDraw,
|
|
||||||
allowSpecials,
|
|
||||||
allowSpectators,
|
|
||||||
gameId,
|
|
||||||
gamePin,
|
|
||||||
gameState,
|
|
||||||
users,
|
|
||||||
} from "~/hooks/useGameProps"
|
|
||||||
|
|
||||||
export function getPayloadFromProps() {
|
export function getPayloadFromProps() {
|
||||||
|
const reducedUsers = [users[0], users[1]].map((user, i) =>
|
||||||
|
user
|
||||||
|
? {
|
||||||
|
index: i,
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
chats: user.chats,
|
||||||
|
moves: user.moves,
|
||||||
|
ships: user.ships,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
game: {
|
game: {
|
||||||
id: gameId(),
|
id: gameProps.gameId,
|
||||||
state: gameState(),
|
state: gameProps.gameState,
|
||||||
allowChat: allowChat(),
|
allowChat: gameProps.allowChat,
|
||||||
allowMarkDraw: allowMarkDraw(),
|
allowMarkDraw: gameProps.allowMarkDraw,
|
||||||
allowSpecials: allowSpecials(),
|
allowSpecials: gameProps.allowSpecials,
|
||||||
allowSpectators: allowSpectators(),
|
allowSpectators: gameProps.allowSpectators,
|
||||||
},
|
},
|
||||||
gamePin: gamePin(),
|
gamePin: gameProps.gamePin,
|
||||||
users: users.map((user, i) => ({
|
users: { 0: reducedUsers[0], 1: reducedUsers[1] },
|
||||||
index: i,
|
|
||||||
id: user.id(),
|
|
||||||
name: user.name(),
|
|
||||||
chats: user.chats(),
|
|
||||||
moves: user.moves(),
|
|
||||||
ships: user.ships(),
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import { createSignal } from "solid-js"
|
|
||||||
import { count } from "~/components/Gamefield/Gamefield"
|
import { count } from "~/components/Gamefield/Gamefield"
|
||||||
import { Users } from "~/hooks/useGameProps"
|
import { users } from "~/hooks/useGameProps"
|
||||||
import type {
|
import type {
|
||||||
Hit,
|
Hit,
|
||||||
IndexedPosition,
|
IndexedPosition,
|
||||||
Mode,
|
Mode,
|
||||||
|
Players,
|
||||||
PointerProps,
|
PointerProps,
|
||||||
Position,
|
Position,
|
||||||
ShipProps,
|
ShipProps,
|
||||||
Target,
|
Target,
|
||||||
TargetList,
|
TargetList,
|
||||||
TargetPreview,
|
TargetPreview,
|
||||||
|
User,
|
||||||
} from "../../interfaces/frontend"
|
} from "../../interfaces/frontend"
|
||||||
import { ChatSchema, MoveSchema, MoveType, Orientation } from "../zodSchemas"
|
import { MoveType, Orientation } from "../zodSchemas"
|
||||||
|
|
||||||
export function borderCN(count: number, x: number, y: number) {
|
export function borderCN(count: number, x: number, y: number) {
|
||||||
if (x === 0) return "left"
|
if (x === 0) return "left"
|
||||||
|
@ -131,31 +132,6 @@ export const initlialMouseCursor = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
}
|
}
|
||||||
export function initialUser() {
|
|
||||||
const [isReady, setIsReady] = createSignal(false)
|
|
||||||
const [isConnected, setIsConnected] = createSignal(false)
|
|
||||||
const [id, setId] = createSignal<string>("")
|
|
||||||
const [name, setName] = createSignal<string>("")
|
|
||||||
const [chats, setChats] = createSignal<ChatSchema[]>([])
|
|
||||||
const [moves, setMoves] = createSignal<MoveSchema[]>([])
|
|
||||||
const [ships, setShips] = createSignal<ShipProps[]>([])
|
|
||||||
return {
|
|
||||||
isReady,
|
|
||||||
setIsReady,
|
|
||||||
isConnected,
|
|
||||||
setIsConnected,
|
|
||||||
id,
|
|
||||||
setId,
|
|
||||||
name,
|
|
||||||
setName,
|
|
||||||
chats,
|
|
||||||
setChats,
|
|
||||||
moves,
|
|
||||||
setMoves,
|
|
||||||
ships,
|
|
||||||
setShips,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const shipProps = (
|
export const shipProps = (
|
||||||
ships: ShipProps[],
|
ships: ShipProps[],
|
||||||
|
@ -249,21 +225,37 @@ export function intersectingShip(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compileHits(users: Users, i: 0 | 1) {
|
export function compiledHits(i: 0 | 1) {
|
||||||
return users[i === 0 ? 1 : 0].moves().reduce((hits, move) => {
|
return (
|
||||||
const list = targetList(move, move.type)
|
users[i === 0 ? 1 : 0]?.moves.reduce((hits, move) => {
|
||||||
if (move.type === MoveType.Enum.radar) return hits
|
const list = targetList(move, move.type)
|
||||||
return [
|
return move.type === MoveType.Enum.radar
|
||||||
...hits,
|
? hits
|
||||||
...list.map(({ x, y }) => ({
|
: [
|
||||||
hit: !!intersectingShip(users[i].ships(), {
|
...hits,
|
||||||
...move,
|
...list.map(({ x, y }) => ({
|
||||||
size: 1,
|
hit: !!intersectingShip(users[i]?.ships ?? [], {
|
||||||
variant: 0,
|
...move,
|
||||||
}).fields.length,
|
size: 1,
|
||||||
x,
|
variant: 0,
|
||||||
y,
|
}).fields.length,
|
||||||
})),
|
x,
|
||||||
]
|
y,
|
||||||
}, [] as Hit[])
|
})),
|
||||||
|
]
|
||||||
|
}, [] as Hit[]) ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const frontendUsers = (users: Players) => {
|
||||||
|
const compiledUsers = [users[0], users[1]].map((user) =>
|
||||||
|
user
|
||||||
|
? {
|
||||||
|
...user,
|
||||||
|
isReady: false,
|
||||||
|
isConnected: false,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
) as [User, User]
|
||||||
|
return { 0: compiledUsers[0], 1: compiledUsers[1] }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue