feat(web/skillcheck): random skill check key from inputs table

This commit is contained in:
Luke
2023-02-12 19:26:09 +01:00
parent 7c2e894b67
commit f166c1675e
4 changed files with 42 additions and 17 deletions

View File

@@ -5,14 +5,17 @@ local skillcheck
---@param difficulty SkillCheckDifficulity | SkillCheckDifficulity[] ---@param difficulty SkillCheckDifficulity | SkillCheckDifficulity[]
---@return boolean? ---@return boolean?
function lib.skillCheck(difficulty) function lib.skillCheck(difficulty, inputs)
if skillcheck then return end if skillcheck then return end
skillcheck = promise:new() skillcheck = promise:new()
SetNuiFocus(true, false) SetNuiFocus(true, false)
SendNUIMessage({ SendNUIMessage({
action = 'startSkillCheck', action = 'startSkillCheck',
data = difficulty data = {
difficulty = difficulty,
inputs = inputs
}
}) })
return Citizen.Await(skillcheck) return Citizen.Await(skillcheck)

View File

@@ -2,10 +2,13 @@ import { debugData } from '../../../utils/debugData';
import { GameDifficulty } from '../../skillcheck'; import { GameDifficulty } from '../../skillcheck';
export const debugSkillCheck = () => { export const debugSkillCheck = () => {
debugData<GameDifficulty | GameDifficulty[]>([ debugData<{ difficulty: GameDifficulty | GameDifficulty[]; inputs?: string[] }>([
{ {
action: 'startSkillCheck', action: 'startSkillCheck',
data: ['easy', 'easy', 'hard'], data: {
difficulty: ['easy', 'easy', 'hard'],
inputs: ['W', 'A', 'S', 'D'],
},
}, },
]); ]);
}; };

View File

@@ -15,6 +15,7 @@ export interface SkillCheckProps {
angle: number; angle: number;
difficultyOffset: number; difficultyOffset: number;
difficulty: GameDifficulty; difficulty: GameDifficulty;
key: string;
} }
export const circleCircumference = 2 * 50 * Math.PI; export const circleCircumference = 2 * 50 * Math.PI;
@@ -65,49 +66,56 @@ const useStyles = createStyles((theme) => ({
})); }));
const SkillCheck: React.FC = () => { const SkillCheck: React.FC = () => {
const theme = useMantineTheme();
const { classes } = useStyles(); const { classes } = useStyles();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const dataRef = useRef<GameDifficulty | GameDifficulty[] | null>(null); const dataRef = useRef<{ difficulty: GameDifficulty | GameDifficulty[]; inputs?: string[] } | null>(null);
const dataIndexRef = useRef<number>(0); const dataIndexRef = useRef<number>(0);
const [skillCheck, setSkillCheck] = useState<SkillCheckProps>({ const [skillCheck, setSkillCheck] = useState<SkillCheckProps>({
angle: 0, angle: 0,
difficultyOffset: 50, difficultyOffset: 50,
difficulty: 'easy', difficulty: 'easy',
key: 'e',
}); });
useNuiEvent('startSkillCheck', (data: GameDifficulty | GameDifficulty[]) => { useNuiEvent('startSkillCheck', (data: { difficulty: GameDifficulty | GameDifficulty[]; inputs?: string[] }) => {
dataRef.current = data; dataRef.current = data;
dataIndexRef.current = 0; dataIndexRef.current = 0;
const gameData = Array.isArray(data) ? data[0] : data; const gameData = Array.isArray(data.difficulty) ? data.difficulty[0] : data.difficulty;
const offset = typeof gameData === 'object' ? gameData.areaSize : difficultyOffsets[gameData]; const offset = typeof gameData === 'object' ? gameData.areaSize : difficultyOffsets[gameData];
const randomKey = data.inputs ? data.inputs[Math.floor(Math.random() * data.inputs.length)] : 'e';
setSkillCheck({ setSkillCheck({
angle: -90 + getRandomAngle(120, 360 - offset), angle: -90 + getRandomAngle(120, 360 - offset),
difficultyOffset: offset, difficultyOffset: offset,
difficulty: gameData, difficulty: gameData,
key: randomKey,
}); });
setVisible(true); setVisible(true);
}); });
const handleComplete = (success: boolean) => { const handleComplete = (success: boolean) => {
if (!success || !Array.isArray(dataRef.current)) { if (!dataRef.current) return;
if (!success || !Array.isArray(dataRef.current.difficulty)) {
setVisible(false); setVisible(false);
return fetchNui('skillCheckOver', success); return fetchNui('skillCheckOver', success);
} }
if (dataIndexRef.current >= dataRef.current.length - 1) { if (dataIndexRef.current >= dataRef.current.difficulty.length - 1) {
setVisible(false); setVisible(false);
return fetchNui('skillCheckOver', success); return fetchNui('skillCheckOver', success);
} }
dataIndexRef.current++; dataIndexRef.current++;
const data = dataRef.current[dataIndexRef.current]; const data = dataRef.current.difficulty[dataIndexRef.current];
const key = dataRef.current.inputs
? dataRef.current.inputs[Math.floor(Math.random() * dataRef.current.inputs.length)]
: 'e';
const offset = typeof data === 'object' ? data.areaSize : difficultyOffsets[data]; const offset = typeof data === 'object' ? data.areaSize : difficultyOffsets[data];
setSkillCheck({ setSkillCheck({
angle: -90 + getRandomAngle(120, 360 - offset), angle: -90 + getRandomAngle(120, 360 - offset),
difficultyOffset: offset, difficultyOffset: offset,
difficulty: data, difficulty: data,
key,
}); });
}; };
@@ -145,7 +153,7 @@ const SkillCheck: React.FC = () => {
skillCheck={skillCheck} skillCheck={skillCheck}
/> />
</svg> </svg>
<Box className={classes.button}>E</Box> <Box className={classes.button}>{skillCheck.key.toUpperCase()}</Box>
</> </>
)} )}
</> </>

View File

@@ -1,7 +1,6 @@
import { useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useKeyPress } from '../../hooks/useKeyPress'; import { useKeyPress } from '../../hooks/useKeyPress';
import { SkillCheckProps } from './index'; import { SkillCheckProps } from './index';
// import { useInterval } from '@chakra-ui/react';
import { useInterval } from '@mantine/hooks'; import { useInterval } from '@mantine/hooks';
import { circleCircumference } from './index'; import { circleCircumference } from './index';
@@ -16,7 +15,7 @@ interface Props {
const Indicator: React.FC<Props> = ({ angle, offset, multiplier, handleComplete, skillCheck, className }) => { const Indicator: React.FC<Props> = ({ angle, offset, multiplier, handleComplete, skillCheck, className }) => {
const [indicatorAngle, setIndicatorAngle] = useState(-90); const [indicatorAngle, setIndicatorAngle] = useState(-90);
const isKeyPressed = useKeyPress('e'); const [keyPressed, setKeyPressed] = useState(false);
const interval = useInterval( const interval = useInterval(
() => () =>
setIndicatorAngle((prevState) => { setIndicatorAngle((prevState) => {
@@ -25,8 +24,17 @@ const Indicator: React.FC<Props> = ({ angle, offset, multiplier, handleComplete,
1 1
); );
const keyHandler = useCallback(
(e: KeyboardEvent) => {
if (e.key.toLowerCase() !== skillCheck.key.toLowerCase()) return;
setKeyPressed(true);
},
[skillCheck]
);
useEffect(() => { useEffect(() => {
setIndicatorAngle(-90); setIndicatorAngle(-90);
window.addEventListener('keydown', keyHandler);
interval.start(); interval.start();
}, [skillCheck]); }, [skillCheck]);
@@ -38,13 +46,16 @@ const Indicator: React.FC<Props> = ({ angle, offset, multiplier, handleComplete,
}, [indicatorAngle]); }, [indicatorAngle]);
useEffect(() => { useEffect(() => {
if (!isKeyPressed) return; if (!keyPressed) return;
interval.stop(); interval.stop();
setKeyPressed(false);
window.removeEventListener('keydown', keyHandler);
if (indicatorAngle < angle || indicatorAngle > angle + offset) handleComplete(false); if (indicatorAngle < angle || indicatorAngle > angle + offset) handleComplete(false);
else handleComplete(true); else handleComplete(true);
}, [isKeyPressed]); }, [keyPressed]);
return ( return (
<circle <circle