tome-web/client/game/GameClient.tsx

154 lines
4.1 KiB
TypeScript

import React from 'react'
import assertNever from '~/common/assertNever.ts'
import Loading from '../components/Loading.tsx'
import {
AsyncHandle,
FighterArea,
GameState,
GameAction,
GameCommandAPI,
} from './types.ts'
import useServerSocket from './useServerSocket.ts'
import Game from './Game.tsx'
function reducer(state: GameState, action: GameAction): GameState {
switch (action.type) {
case 'update-state': {
return {...action.state, team: state.team}
}
case 'set-player': {
return {...state, team: action.team}
}
default: return state
}
}
const initialState: GameState = {
board: {
sentinal: Array(4).fill(undefined) as FighterArea,
scourge: Array(4).fill(undefined) as FighterArea,
},
player: {
name: '',
id: 0,
hand: [],
life: 0,
ready: false,
},
deck: [],
team: 1,
enemyLife: 0,
enemyDeckSize: 0,
enemyHandSize: 0,
currentTurn: 1,
canDraw: false,
hasDrawn: false,
gameStatus: 0,
}
export default function GameClient(): JSX.Element {
const [state, dispatch] = React.useReducer(reducer, initialState)
const handleGameUpdate = React.useCallback((data: Record<string, unknown>) => {
console.log(data)
}, [])
const socketHandle = useServerSocket(handleGameUpdate)
const gameHandle = React.useMemo<AsyncHandle<GameCommandAPI>>(
() => {
if (socketHandle.status !== 'connected') return socketHandle
return {
status: 'connected',
handle: {
readyPlayer: () => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 's',
cmd: 'b',
})
},
startTurn: () => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 's',
cmd: 's',
})
},
endTurn: () => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 's',
cmd: 'e',
})
},
getView: () => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 's',
cmd: 'g',
})
},
startDraw: () => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 'a',
cmd: 's',
})
},
commitDraw: (cardIndex: number) => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 'a',
cmd: `d ${cardIndex}`,
})
},
playCard: (handIndex: number, positionIndex: number) => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 'a',
cmd: `p ${handIndex} ${positionIndex}`,
})
},
moveCard: (positionFrom: number, positionTo: number) => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 'a',
cmd: `m ${positionFrom} ${positionTo}`,
})
},
attackCard: (positionFrom: number, positionTo: number) => {
if (socketHandle.status !== 'connected') return
socketHandle.handle.sendGameCommand({
type: 'a',
cmd: `a ${positionFrom} ${positionTo}`,
})
},
},
}
},
[socketHandle, state],
)
React.useEffect(() => {
if (gameHandle.status !== 'connected') return
gameHandle.handle.readyPlayer()
if (state?.team === 1) gameHandle.handle.startTurn()
}, [gameHandle, state?.team])
switch (gameHandle.status) {
case 'connected': {
if (!state) return <Loading />
return <Game {...state} {...gameHandle.handle} />
}
case 'not-connected':
case 'connecting': {
return <Loading />
}
default: return assertNever(gameHandle)
}
}