154 lines
4.1 KiB
TypeScript
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)
|
|
}
|
|
}
|