Skip to content

Commit

Permalink
feat(web): skillcheck minigame
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeWasTakenn committed Oct 18, 2022
1 parent ec18bbf commit 66c16b5
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 0 deletions.
2 changes: 2 additions & 0 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import AlertDialog from './features/dialog/AlertDialog';
import ListMenu from './features/menu/list';
import Dev from './features/dev';
import { isEnvBrowser } from './utils/misc';
import SkillCheck from './features/skillcheck';

const App: React.FC = () => {
useNuiEvent('setClipboard', (data: string) => {
Expand All @@ -31,6 +32,7 @@ const App: React.FC = () => {
<AlertDialog />
<ContextMenu />
<ListMenu />
<SkillCheck />
{isEnvBrowser() && <Dev />}
</>
);
Expand Down
93 changes: 93 additions & 0 deletions web/src/features/skillcheck/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Box, Center } from '@chakra-ui/react';
import { useEffect, useMemo, useState } from 'react';
import { useNuiEvent } from '../../hooks/useNuiEvent';
import { debugData } from '../../utils/debugData';
import Indicator from './indicator';

export interface SkillCheckProps {
visible: boolean;
angle: number;
difficultyOffset: number;
difficulty: 'easy' | 'medium' | 'hard';
}

const getRandomAngle = (min: number, max: number) => Math.floor(Math.random() * (max - min)) + min;

const difficultyOffsets = {
easy: 275,
medium: 290,
hard: 300,
};

debugData([
{
action: 'startSkillCheck',
data: 'easy',
},
]);

const SkillCheck: React.FC = () => {
const [skillCheck, setSkillCheck] = useState<SkillCheckProps>({
visible: false,
angle: 0,
difficultyOffset: 315,
difficulty: 'easy',
});

useNuiEvent('startSkillCheck', (data: 'easy' | 'medium' | 'hard') => {
setSkillCheck({
visible: true,
angle: -90 + getRandomAngle(0, 360),
difficultyOffset: difficultyOffsets[data],
difficulty: data,
});
});

return (
<Center height="100%" width="100%">
{skillCheck.visible && (
<>
<svg width={500} height={500}>
{/*Circle track*/}
<circle r={50} cx={250} cy={250} fill="transparent" stroke="#a3a8a5" strokeDasharray={360} />
{/*SkillCheck area*/}
<circle
r={50}
cx={250}
cy={250}
fill="transparent"
stroke="white"
strokeDasharray={315}
strokeDashoffset={skillCheck.difficultyOffset}
strokeWidth={5}
transform={`rotate(${skillCheck.angle}, 250, 250)`}
/>
<Indicator
angle={skillCheck.angle}
offset={skillCheck.difficultyOffset}
multiplier={skillCheck.difficulty === 'easy' ? 1 : skillCheck.difficulty === 'medium' ? 1.5 : 2}
setSkillCheck={setSkillCheck}
/>
</svg>
<Box
position="absolute"
left="50%"
top="50%"
transform="translate(-50%, -50%)"
backgroundColor="rgba(0, 0, 0, 0.4)"
w={25}
h={25}
textAlign="center"
borderRadius={5}
fontFamily="Inter"
fontSize={16}
>
E
</Box>
</>
)}
</Center>
);
};

export default SkillCheck;
63 changes: 63 additions & 0 deletions web/src/features/skillcheck/indicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useRef, useState } from 'react';
import { useNuiEvent } from '../../hooks/useNuiEvent';
import { useKeyPress } from '../../hooks/useKeyPress';
import { fetchNui } from '../../utils/fetchNui';
import { SkillCheckProps } from './index';

interface Props {
angle: number;
offset: number;
multiplier: number;
setSkillCheck: React.Dispatch<React.SetStateAction<SkillCheckProps>>;
}

const Indicator: React.FC<Props> = ({ angle, offset, multiplier, setSkillCheck }) => {
const [indicatorAngle, setIndicatorAngle] = useState(-90);
const intervalRef = useRef<NodeJS.Timer | null>(null);
const isKeyPressed = useKeyPress('e');

useEffect(() => {
console.log(1);
intervalRef.current = setInterval(() => {
setIndicatorAngle((prevState) => (prevState += multiplier));
}, 1);

return () => {
if (intervalRef.current) clearInterval(intervalRef.current);
};
}, []);

useEffect(() => {
if (intervalRef.current && indicatorAngle + 90 >= 360) {
clearInterval(intervalRef.current);
fetchNui('skillCheckOver', { success: false });
setSkillCheck((prevState) => ({ ...prevState, visible: false }));
}

if (isKeyPressed && intervalRef.current) {
clearInterval(intervalRef.current);
if (indicatorAngle < angle || indicatorAngle > angle + (315 - offset)) {
fetchNui('skillCheckOver', { success: false });
} else {
fetchNui('skillCheckOver', { success: true });
}
setSkillCheck((prevState) => ({ ...prevState, visible: false }));
}
}, [indicatorAngle, isKeyPressed]);

return (
<circle
r={50}
cx={250}
cy={250}
fill="transparent"
stroke="red"
strokeWidth={15}
strokeDasharray={315}
strokeDashoffset={312}
transform={`rotate(${indicatorAngle}, 250, 250)`}
/>
);
};

export default Indicator;

0 comments on commit 66c16b5

Please sign in to comment.