Merge pull request #3587 from nickofolas/improvement/infiltration-ui

INFILTRATION: Update gameplay UI
This commit is contained in:
hydroflame 2022-05-04 11:52:02 -04:00 committed by GitHub
commit 8b0ab7842d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 403 additions and 339 deletions

@ -1,15 +1,14 @@
import { Paper, Typography } from "@mui/material";
import React, { useState } from "react";
import Grid from "@mui/material/Grid";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { KEY } from "../../utils/helpers/keyCodes";
import { random } from "../utils";
import { BlinkingCursor } from "./BlinkingCursor";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { random } from "../utils";
import { interpolate } from "./Difficulty";
import { BlinkingCursor } from "./BlinkingCursor";
import Typography from "@mui/material/Typography";
import { KEY } from "../../utils/helpers/keyCodes";
import { Player } from "../../Player";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
interface Difficulty {
[key: string]: number;
@ -48,24 +47,18 @@ export function BackwardGame(props: IMinigameProps): React.ReactElement {
}
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
<Typography variant="h4">Type it{!hasAugment ? " backward" : ""}</Typography>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
<Grid item xs={6}>
<Typography style={{ transform: hasAugment ? "none" : "scaleX(-1)", marginLeft: hasAugment ? "50%" : "none" }}>
{answer}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ transform: hasAugment ? "none" : "scaleX(-1)" }}>{answer}</Typography>
<Typography>
{guess}
<BlinkingCursor />
</Typography>
</Grid>
</Grid>
</Paper>
</>
);
}

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useEffect, useState } from "react";
export function BlinkingCursor(): React.ReactElement {
const [on, setOn] = useState(true);
@ -6,5 +6,5 @@ export function BlinkingCursor(): React.ReactElement {
const i = setInterval(() => setOn((old) => !old), 1000);
return () => clearInterval(i);
});
return <>{on ? "|" : ""}</>;
return <>{on ? "|" : <>&nbsp;</>}</>;
}

@ -1,15 +1,14 @@
import { Paper, Typography } from "@mui/material";
import React, { useState } from "react";
import Grid from "@mui/material/Grid";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { KEY } from "../../utils/helpers/keyCodes";
import { random } from "../utils";
import { BlinkingCursor } from "./BlinkingCursor";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { random } from "../utils";
import { interpolate } from "./Difficulty";
import { BlinkingCursor } from "./BlinkingCursor";
import Typography from "@mui/material/Typography";
import { Player } from "../../Player";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { KEY } from "../../utils/helpers/keyCodes";
interface Difficulty {
[key: string]: number;
@ -84,16 +83,16 @@ export function BracketGame(props: IMinigameProps): React.ReactElement {
}
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Paper sx={{ display: "grid", justifyItems: "center" }}>
<Typography variant="h4">Close the brackets</Typography>
<Typography style={{ fontSize: "5em" }}>
{`${left}${right}`}
<BlinkingCursor />
</Typography>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
</Grid>
</Paper>
</>
);
}

@ -1,15 +1,14 @@
import { Paper, Typography } from "@mui/material";
import React, { useEffect, useState } from "react";
import Grid from "@mui/material/Grid";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { interpolate } from "./Difficulty";
import Typography from "@mui/material/Typography";
import { KEY } from "../../utils/helpers/keyCodes";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { KEY } from "../../utils/helpers/keyCodes";
import { downArrowSymbol, upArrowSymbol } from "../utils";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
interface Difficulty {
[key: string]: number;
@ -88,13 +87,11 @@ export function BribeGame(props: IMinigameProps): React.ReactElement {
}
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Typography variant="h4">Say something nice about the guard.</Typography>
<Paper sx={{ display: "grid", justifyItems: "center" }}>
<Typography variant="h4">Say something nice about the guard</Typography>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
<Grid item xs={6}>
<Typography variant="h5" color={upColor}>
{upArrowSymbol}
</Typography>
@ -104,8 +101,8 @@ export function BribeGame(props: IMinigameProps): React.ReactElement {
<Typography variant="h5" color={downColor}>
{downArrowSymbol}
</Typography>
</Grid>
</Grid>
</Paper>
</>
);
}
@ -154,6 +151,7 @@ const positive = [
"patient",
"dynamic",
"loyal",
"based",
];
const negative = [
@ -177,4 +175,5 @@ const negative = [
"picky",
"tactless",
"thoughtless",
"cringe",
];

@ -1,21 +1,20 @@
import { Paper, Typography } from "@mui/material";
import React, { useState } from "react";
import Grid from "@mui/material/Grid";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import {
random,
downArrowSymbol,
getArrow,
getInverseArrow,
leftArrowSymbol,
random,
rightArrowSymbol,
upArrowSymbol,
downArrowSymbol,
} from "../utils";
import { interpolate } from "./Difficulty";
import Typography from "@mui/material/Typography";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
interface Difficulty {
[key: string]: number;
@ -55,14 +54,14 @@ export function CheatCodeGame(props: IMinigameProps): React.ReactElement {
}
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Paper sx={{ display: "grid", justifyItems: "center" }}>
<Typography variant="h4">Enter the Code!</Typography>
<Typography variant="h4">{code[index]}</Typography>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
</Grid>
</Paper>
</>
);
}

@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import Grid from "@mui/material/Grid";
import { Paper, Typography } from "@mui/material";
import React, { useEffect, useState } from "react";
import Typography from "@mui/material/Typography";
interface IProps {
onFinish: () => void;
}
@ -13,17 +12,13 @@ export function Countdown(props: IProps): React.ReactElement {
props.onFinish();
return;
}
setTimeout(() => setX(x - 1), 200);
setTimeout(() => setX(x - 1), 300);
});
return (
<>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="h4">Get Ready!</Typography>
<Typography variant="h4">{x}</Typography>
</Grid>
</Grid>
</>
<Paper sx={{ p: 1, textAlign: "center" }}>
<Typography variant="h4">Get Ready!</Typography>
<Typography variant="h4">{x}</Typography>
</Paper>
);
}

@ -1,15 +1,14 @@
import { Paper, Typography, Box } from "@mui/material";
import React, { useState } from "react";
import Grid from "@mui/material/Grid";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { interpolate } from "./Difficulty";
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
import Typography from "@mui/material/Typography";
import { KEY } from "../../utils/helpers/keyCodes";
import { Settings } from "../../Settings/Settings";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { KEY } from "../../utils/helpers/keyCodes";
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
interface Difficulty {
[key: string]: number;
@ -19,6 +18,12 @@ interface Difficulty {
symbols: number;
}
interface GridItem {
content: string;
color: string;
selected?: boolean;
}
const difficulties: {
Trivial: Difficulty;
Normal: Difficulty;
@ -76,18 +81,33 @@ export function Cyberpunk2077Game(props: IMinigameProps): React.ReactElement {
}
}
const flatGrid: GridItem[] = [];
grid.map((line, y) =>
line.map((cell, x) => {
const isCorrectAnswer = cell === answers[currentAnswerIndex];
const optionColor = hasAugment && !isCorrectAnswer ? Settings.theme.disabled : Settings.theme.primary;
if (x === pos[0] && y === pos[1]) {
flatGrid.push({ color: optionColor, content: cell, selected: true });
return;
}
flatGrid.push({ color: optionColor, content: cell });
}),
);
const fontSize = "2em";
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
<Typography variant="h4">Match the symbols!</Typography>
<Typography variant="h5" color={Settings.theme.primary}>
Targets:{" "}
{answers.map((a, i) => {
if (i == currentAnswerIndex)
return (
<span key={`${i}`} style={{ fontSize: "1em", color: "blue" }}>
<span key={`${i}`} style={{ fontSize: "1em", color: Settings.theme.infolight }}>
{a}&nbsp;
</span>
);
@ -99,34 +119,30 @@ export function Cyberpunk2077Game(props: IMinigameProps): React.ReactElement {
})}
</Typography>
<br />
{grid.map((line, y) => (
<div key={y}>
<Typography>
{line.map((cell, x) => {
const isCorrectAnswer = cell === answers[currentAnswerIndex];
if (x == pos[0] && y == pos[1]) {
return (
<span key={`${x}${y}`} style={{ fontSize: fontSize, color: "blue" }}>
{cell}&nbsp;
</span>
);
}
const optionColor = hasAugment && !isCorrectAnswer ? Settings.theme.disabled : Settings.theme.primary;
return (
<span key={`${x}${y}`} style={{ fontSize: fontSize, color: optionColor }}>
{cell}&nbsp;
</span>
);
})}
<Box
sx={{
display: "grid",
gridTemplateColumns: `repeat(${Math.round(difficulty.width)}, 1fr)`,
gap: 1,
}}
>
{flatGrid.map((item) => (
<Typography
sx={{
fontSize: fontSize,
color: item.color,
border: item.selected ? `2px solid ${Settings.theme.infolight}` : "unset",
lineHeight: "unset",
p: item.selected ? "2px" : "4px",
}}
>
{item.content}
</Typography>
<br />
</div>
))}
))}
</Box>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
</Grid>
</Paper>
</>
);
}

@ -1,19 +1,17 @@
import { use } from "../../ui/Context";
import { Button, Container, Paper, Typography } from "@mui/material";
import React, { useState } from "react";
import Grid from "@mui/material/Grid";
import Button from "@mui/material/Button";
import { Countdown } from "./Countdown";
import { BracketGame } from "./BracketGame";
import { SlashGame } from "./SlashGame";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { use } from "../../ui/Context";
import { BackwardGame } from "./BackwardGame";
import { BracketGame } from "./BracketGame";
import { BribeGame } from "./BribeGame";
import { CheatCodeGame } from "./CheatCodeGame";
import { Countdown } from "./Countdown";
import { Cyberpunk2077Game } from "./Cyberpunk2077Game";
import { MinesweeperGame } from "./MinesweeperGame";
import { WireCuttingGame } from "./WireCuttingGame";
import { SlashGame } from "./SlashGame";
import { Victory } from "./Victory";
import Typography from "@mui/material/Typography";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { WireCuttingGame } from "./WireCuttingGame";
interface IProps {
StartingDifficulty: number;
@ -139,22 +137,20 @@ export function Game(props: IProps): React.ReactElement {
}
return (
<>
<Grid container spacing={3}>
<Grid item xs={3}>
<Button onClick={cancel}>Cancel</Button>
</Grid>
<Grid item xs={3}>
<Typography>
Level: {level}&nbsp;/&nbsp;{props.MaxLevel}
</Typography>
<Progress />
</Grid>
<Container>
<Paper sx={{ p: 1, mb: 1, display: "grid", justifyItems: "center", gap: 1 }}>
{stage !== Stage.Sell && (
<Button sx={{ width: "100%" }} onClick={cancel}>
Cancel Infiltration
</Button>
)}
<Typography variant="h5">
Level {level} / {props.MaxLevel}
</Typography>
<Progress />
</Paper>
<Grid item xs={12}>
{stageComponent}
</Grid>
</Grid>
</>
{stageComponent}
</Container>
);
}

@ -1,10 +1,9 @@
import LinearProgress from "@mui/material/LinearProgress";
import React, { useState, useEffect } from "react";
import withStyles from "@mui/styles/withStyles";
import { LinearProgress, Paper } from "@mui/material";
import { Theme } from "@mui/material/styles";
import Grid from "@mui/material/Grid";
import { use } from "../../ui/Context";
import withStyles from "@mui/styles/withStyles";
import React, { useEffect, useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { use } from "../../ui/Context";
const TimerProgress = withStyles((theme: Theme) => ({
root: {
@ -19,6 +18,7 @@ const TimerProgress = withStyles((theme: Theme) => ({
interface IProps {
millis: number;
onExpire: () => void;
noPaper?: boolean;
}
export function GameTimer(props: IProps): React.ReactElement {
@ -42,9 +42,11 @@ export function GameTimer(props: IProps): React.ReactElement {
// https://stackoverflow.com/questions/55593367/disable-material-uis-linearprogress-animation
// TODO(hydroflame): there's like a bug where it triggers the end before the
// bar physically reaches the end
return (
<Grid item xs={12}>
return props.noPaper ? (
<TimerProgress variant="determinate" value={v} color="primary" />
) : (
<Paper sx={{ p: 1, mb: 1 }}>
<TimerProgress variant="determinate" value={v} color="primary" />
</Grid>
</Paper>
);
}

@ -1,9 +1,9 @@
import React, { useState } from "react";
import { Intro } from "./Intro";
import { Game } from "./Game";
import { Location } from "../../Locations/Location";
import { use } from "../../ui/Context";
import { calculateDifficulty, calculateReward } from "../formulas/game";
import { Game } from "./Game";
import { Intro } from "./Intro";
interface IProps {
location: Location;
}
@ -22,24 +22,24 @@ export function InfiltrationRoot(props: IProps): React.ReactElement {
router.toCity();
}
if (!start) {
return (
<Intro
Location={props.location}
Difficulty={difficulty}
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
start={() => setStart(true)}
cancel={cancel}
/>
);
}
return (
<Game
StartingDifficulty={startingSecurityLevel}
Difficulty={difficulty}
Reward={reward}
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
/>
<div style={{ display: "flex", alignItems: "center", height: "calc(100vh - 16px)" }}>
{start ? (
<Game
StartingDifficulty={startingSecurityLevel}
Difficulty={difficulty}
Reward={reward}
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
/>
) : (
<Intro
Location={props.location}
Difficulty={difficulty}
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
start={() => setStart(true)}
cancel={cancel}
/>
)}
</div>
);
}

@ -1,8 +1,8 @@
import { Report } from "@mui/icons-material";
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
import React from "react";
import { Location } from "../../Locations/Location";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { Settings } from "../../Settings/Settings";
import { numeralWrapper } from "../../ui/numeralFormat";
interface IProps {
@ -41,9 +41,9 @@ function coloredArrow(difficulty: number): JSX.Element {
} else {
return (
<>
{arrowPart("white", difficulty * 13)}
{arrowPart("orange", (difficulty - 1) * 13)}
{arrowPart("red", (difficulty - 2) * 13)}
{arrowPart(Settings.theme.primary, difficulty * 13)}
{arrowPart(Settings.theme.warning, (difficulty - 1) * 13)}
{arrowPart(Settings.theme.error, (difficulty - 2) * 13)}
</>
);
}
@ -51,65 +51,84 @@ function coloredArrow(difficulty: number): JSX.Element {
export function Intro(props: IProps): React.ReactElement {
return (
<>
<Grid container spacing={3}>
<Grid item xs={10}>
<Typography variant="h4">Infiltrating {props.Location.name}</Typography>
</Grid>
<Grid item xs={10}>
<Typography variant="h5" color="primary">
Maximum level: {props.MaxLevel}
</Typography>
</Grid>
<Grid item xs={10}>
<Typography variant="h5" color="primary">
Difficulty: {numeralWrapper.format(props.Difficulty * 33.3333, "0")} / 100
</Typography>
</Grid>
<Container sx={{ alignItems: "center" }}>
<Paper sx={{ p: 1, mb: 1, display: "grid", justifyItems: "center" }}>
<Typography variant="h4">
Infiltrating <b>{props.Location.name}</b>
</Typography>
<Typography variant="h6">
<b>Maximum Level: </b>
{props.MaxLevel}
</Typography>
<Typography
variant="h6"
sx={{
color:
props.Difficulty > 2
? Settings.theme.error
: props.Difficulty > 1
? Settings.theme.warning
: Settings.theme.primary,
display: "flex",
alignItems: "center",
}}
>
<b>Difficulty:&nbsp;</b>
{numeralWrapper.format(props.Difficulty * 33.3333, "0")} / 100
{props.Difficulty > 1.5 && (
<Tooltip
title={
<Typography color="error">
This location is too heavily guarded for your current stats. It is recommended that you try training,
or finding an easier location.
</Typography>
}
>
<Report sx={{ ml: 1 }} />
</Tooltip>
)}
</Typography>
{props.Difficulty > 1.5 && (
<Grid item xs={10}>
<Typography variant="h5" color="primary">
Warning: This location is too heavily guarded for your current stats, try training or finding an easier
location.
</Typography>
</Grid>
)}
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>[{coloredArrow(props.Difficulty)}]</Typography>
<Typography
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
>{`▲ ▲ ▲ ▲`}</Typography>
<Typography
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
>{` Trivial Normal Hard Impossible`}</Typography>
</Paper>
<Grid item xs={10}>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>[{coloredArrow(props.Difficulty)}]</Typography>
<Typography
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
>{` ^ ^ ^ ^`}</Typography>
<Typography
sx={{ lineHeight: "1em", whiteSpace: "pre" }}
>{` Trivial Normal Hard Impossible`}</Typography>
</Grid>
<Grid item xs={10}>
<Paper sx={{ p: 1, display: "grid", justifyItems: "center" }}>
<Typography sx={{ width: "75%", textAlign: "center" }}>
<b>Infiltration</b> is a series of short minigames that get progressively harder. You take damage for failing
them. Reaching the maximum level rewards you with intel that you can trade for money or reputation.
<br />
<br />
<b>Gameplay:</b>
</Typography>
<ul>
<Typography>
Infiltration is a series of short minigames that get progressively harder. You take damage for failing them.
Reaching the maximum level rewards you with intel you can trade for money or reputation.
<li>
The minigames you play are randomly selected.
<br />
It might take you a few tries to get used to them.
</li>
<li>No game requires use of the mouse.</li>
<li>
<b>Spacebar</b> is the default action/confirm button.
</li>
<li>
The <b>arrow keys</b> and <b>WASD</b> can be used interchangeably.
</li>
<li>Sometimes the rest of the keyboard is used.</li>
</Typography>
<br />
<Typography>
The minigames you play are randomly selected. It might take you few tries to get used to them.
</Typography>
<br />
<Typography>No game require use of the mouse.</Typography>
<br />
<Typography>Spacebar is the default action/confirm button.</Typography>
<br />
<Typography>Everything that uses arrow can also use WASD</Typography>
<br />
<Typography>Sometimes the rest of the keyboard is used.</Typography>
</Grid>
<Grid item xs={3}>
</ul>
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", width: "100%" }}>
<Button onClick={props.start}>Start</Button>
</Grid>
<Grid item xs={3}>
<Button onClick={props.cancel}>Cancel</Button>
</Grid>
</Grid>
</>
</Box>
</Paper>
</Container>
);
}

@ -1,14 +1,16 @@
import React, { useState, useEffect } from "react";
import Grid from "@mui/material/Grid";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { interpolate } from "./Difficulty";
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
import Typography from "@mui/material/Typography";
import { KEY } from "../../utils/helpers/keyCodes";
import { Close, Flag, Report } from "@mui/icons-material";
import { Box, Paper, Typography } from "@mui/material";
import { uniqueId } from "lodash";
import React, { useEffect, useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { KEY } from "../../utils/helpers/keyCodes";
import { downArrowSymbol, getArrow, leftArrowSymbol, rightArrowSymbol, upArrowSymbol } from "../utils";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
interface Difficulty {
[key: string]: number;
@ -81,32 +83,77 @@ export function MinesweeperGame(props: IMinigameProps): React.ReactElement {
return () => clearInterval(id);
}, []);
const flatGrid: { flagged?: boolean; current?: boolean; marked?: boolean }[] = [];
minefield.map((line, y) =>
line.map((cell, x) => {
if (memoryPhase) {
flatGrid.push({ flagged: Boolean(minefield[y][x]) });
return;
} else if (x === pos[0] && y === pos[1]) {
flatGrid.push({ current: true });
} else if (answer[y][x]) {
flatGrid.push({ marked: true });
} else if (hasAugment && minefield[y][x]) {
flatGrid.push({ flagged: true });
} else {
flatGrid.push({});
}
}),
);
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
<Typography variant="h4">{memoryPhase ? "Remember all the mines!" : "Mark all the mines!"}</Typography>
{minefield.map((line, y) => (
<div key={y}>
<Typography>
{line.map((cell, x) => {
if (memoryPhase) {
if (minefield[y][x]) return <span key={x}>[?]&nbsp;</span>;
return <span key={x}>[&nbsp;]&nbsp;</span>;
} else {
if (x == pos[0] && y == pos[1]) return <span key={x}>[X]&nbsp;</span>;
if (answer[y][x]) return <span key={x}>[.]&nbsp;</span>;
if (hasAugment && minefield[y][x]) return <span key={x}>[?]&nbsp;</span>;
return <span key={x}>[&nbsp;]&nbsp;</span>;
}
})}
</Typography>
<br />
</div>
))}
<Box
sx={{
display: "grid",
gridTemplateColumns: `repeat(${Math.round(difficulty.width)}, 1fr)`,
gridTemplateRows: `repeat(${Math.round(difficulty.height)}, 1fr)`,
gap: 1,
}}
>
{flatGrid.map((item) => {
let color: string;
let icon: React.ReactElement;
if (item.marked) {
color = Settings.theme.warning;
icon = <Flag />;
} else if (item.current) {
color = Settings.theme.infolight;
icon = <Close />;
} else if (item.flagged) {
color = Settings.theme.error;
icon = <Report />;
} else {
color = Settings.theme.primary;
icon = <></>;
}
return (
<Typography
key={`${item}${uniqueId()}`}
sx={{
color: color,
border: `2px solid ${item.current ? Settings.theme.infolight : Settings.theme.primary}`,
height: "32px",
width: "32px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{icon}
</Typography>
);
})}
</Box>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
</Grid>
</Paper>
</>
);
}

@ -1,13 +1,12 @@
import React, { useState, useEffect } from "react";
import Grid from "@mui/material/Grid";
import { Box, Paper, Typography } from "@mui/material";
import React, { useEffect, useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { KEY } from "../../utils/helpers/keyCodes";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { interpolate } from "./Difficulty";
import Typography from "@mui/material/Typography";
import { KEY } from "../../utils/helpers/keyCodes";
import { Player } from "../../Player";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
interface Difficulty {
[key: string]: number;
@ -59,23 +58,25 @@ export function SlashGame(props: IMinigameProps): React.ReactElement {
}, []);
return (
<Grid container spacing={3}>
<>
<GameTimer millis={5000} onExpire={props.onFailure} />
<Grid item xs={12}>
<Paper sx={{ display: "grid", justifyItems: "center" }}>
<Typography variant="h4">Slash when his guard is down!</Typography>
{hasAugment ? (
<>
<Typography variant="h4">Guard will drop in...</Typography>
<GameTimer millis={timeUntilAttacking} onExpire={props.onFailure} />
</>
<Box sx={{ my: 1 }}>
<Typography variant="h5">Guard will drop in...</Typography>
<GameTimer millis={timeUntilAttacking} onExpire={() => null} noPaper />
</Box>
) : (
<></>
)}
{phase === 0 && <Typography variant="h4">Guarding ...</Typography>}
{phase === 1 && <Typography variant="h4">Preparing?</Typography>}
{phase === 2 && <Typography variant="h4">ATTACKING!</Typography>}
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
</Grid>
</Paper>
</>
);
}

@ -1,21 +1,17 @@
import { Factions } from "../../Faction/Factions";
import { Box, Button, MenuItem, Paper, Select, SelectChangeEvent, Typography } from "@mui/material";
import React, { useState } from "react";
import Grid from "@mui/material/Grid";
import { FactionNames } from "../../Faction/data/FactionNames";
import { inviteToFaction } from "../../Faction/FactionHelpers";
import { Factions } from "../../Faction/Factions";
import { use } from "../../ui/Context";
import { Money } from "../../ui/React/Money";
import { Reputation } from "../../ui/React/Reputation";
import { use } from "../../ui/Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { FactionNames } from "../../Faction/data/FactionNames";
import { formatNumber } from "../../utils/StringHelperFunctions";
import {
calculateInfiltratorsRepReward,
calculateSellInformationCashReward,
calculateTradeInformationRepReward,
} from "../formulas/victory";
import { inviteToFaction } from "../../Faction/FactionHelpers";
interface IProps {
StartingDifficulty: number;
@ -66,24 +62,22 @@ export function Victory(props: IProps): React.ReactElement {
}
return (
<>
<Grid container spacing={3}>
<Grid item xs={10}>
<Typography variant="h4">Infiltration successful!</Typography>
</Grid>
<Grid item xs={10}>
<Typography variant="h5" color="primary">
You{" "}
{isMemberOfInfiltrators ? (
<>
have gained {formatNumber(infiltrationRepGain, 2)} rep for {FactionNames.ShadowsOfAnarchy} and{" "}
</>
) : (
<></>
)}
can trade the confidential information you found for money or reputation.
</Typography>
<Select value={faction} onChange={changeDropdown}>
<Paper sx={{ p: 1, textAlign: "center", display: "flex", alignItems: "center", flexDirection: "column" }}>
<Typography variant="h4">Infiltration successful!</Typography>
<Typography variant="h5" color="primary" width="75%">
You{" "}
{isMemberOfInfiltrators ? (
<>
have gained {formatNumber(infiltrationRepGain, 2)} rep for {FactionNames.ShadowsOfAnarchy} and{" "}
</>
) : (
<></>
)}
can trade the confidential information you found for money or reputation.
</Typography>
<Box sx={{ width: "fit-content" }}>
<Box sx={{ width: "100%" }}>
<Select value={faction} onChange={changeDropdown} sx={{ mr: 1 }}>
<MenuItem key={"none"} value={"none"}>
{"none"}
</MenuItem>
@ -98,17 +92,15 @@ export function Victory(props: IProps): React.ReactElement {
<Button onClick={trade}>
Trade for <Reputation reputation={repGain} /> reputation
</Button>
</Grid>
<Grid item xs={3}>
<Button onClick={sell}>
Sell for&nbsp;
<Money money={moneyGain} />
</Button>
</Grid>
<Grid item xs={3}>
<Button onClick={quitInfiltration}>Quit</Button>
</Grid>
</Grid>
</>
</Box>
<Button onClick={sell} sx={{ width: "100%" }}>
Sell for&nbsp;
<Money money={moneyGain} />
</Button>
</Box>
<Button onClick={quitInfiltration} sx={{ width: "100%", mt: 1 }}>
Quit
</Button>
</Paper>
);
}

@ -1,15 +1,14 @@
import { Box, Paper, Typography } from "@mui/material";
import React, { useEffect, useState } from "react";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
import { GameTimer } from "./GameTimer";
import { random } from "../utils";
import { interpolate } from "./Difficulty";
import { KEY } from "../../utils/helpers/keyCodes";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { KEY } from "../../utils/helpers/keyCodes";
import { random } from "../utils";
import { interpolate } from "./Difficulty";
import { GameTimer } from "./GameTimer";
import { IMinigameProps } from "./IMinigameProps";
import { KeyHandler } from "./KeyHandler";
interface Difficulty {
[key: string]: number;
@ -102,46 +101,53 @@ export function WireCuttingGame(props: IMinigameProps): React.ReactElement {
}
return (
<Grid container spacing={3}>
<>
<GameTimer millis={timer} onExpire={props.onFailure} />
<Grid item xs={12}>
<Typography variant="h4">Cut the wires with the following properties! (keyboard 1 to 9)</Typography>
<Paper sx={{ display: "grid", justifyItems: "center", pb: 1 }}>
<Typography variant="h4" sx={{ width: "75%", textAlign: "center" }}>
Cut the wires with the following properties! (keyboard 1 to 9)
</Typography>
{questions.map((question, i) => (
<Typography key={i}>{question.toString()}</Typography>
))}
<Typography>
<Box
sx={{
display: "grid",
gridTemplateColumns: `repeat(${wires.length}, 1fr)`,
columnGap: 3,
justifyItems: "center",
}}
>
{new Array(wires.length).fill(0).map((_, i) => {
const isCorrectWire = checkWire(i + 1);
const color = hasAugment && !isCorrectWire ? Settings.theme.disabled : Settings.theme.primary;
return (
<span key={i} style={{ color: color }}>
&nbsp;{i + 1}&nbsp;&nbsp;&nbsp;&nbsp;
</span>
<Typography key={i} style={{ color: color }}>
{i + 1}
</Typography>
);
})}
</Typography>
{new Array(8).fill(0).map((_, i) => (
<div key={i}>
<Typography>
{new Array(8).fill(0).map((_, i) => (
<React.Fragment key={i}>
{wires.map((wire, j) => {
if ((i === 3 || i === 4) && cutWires[j]) {
return <span key={j}>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>;
return <Typography key={j}></Typography>;
}
const isCorrectWire = checkWire(j + 1);
const wireColor =
hasAugment && !isCorrectWire ? Settings.theme.disabled : wire.colors[i % wire.colors.length];
return (
<span key={j} style={{ color: wireColor }}>
|{wire.tpe}|&nbsp;&nbsp;&nbsp;
</span>
<Typography key={j} style={{ color: wireColor }}>
|{wire.tpe}|
</Typography>
);
})}
</Typography>
</div>
))}
</React.Fragment>
))}
</Box>
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
</Grid>
</Grid>
</Paper>
</>
);
}