Skip to content

Commit

Permalink
feat: added 40 point task
Browse files Browse the repository at this point in the history
  • Loading branch information
Дмитрий Никифоров committed Apr 23, 2022
1 parent 358704b commit a7a6436
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 50 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@
Релиз: [v0.2.0](https://github.com/Not-cottage-cheese-but-cottage-cheese/VKMiniApps/releases/tag/v0.2.0)

### 30
Реализуйте таймер. На игру даётся столько же минут, сколько игроков участвует в раунде. Таймер должен продолжать работать корректно при переходе между экранами вашего мини-приложения, будьте внимательны! Если у девайса есть фонарик, то мигайте фонариком, когда время на таймере закончится.
Релиз: [v0.3.0](https://github.com/Not-cottage-cheese-but-cottage-cheese/VKMiniApps/releases/tag/v0.3.0)
Реализуйте таймер. На игру даётся столько же минут, сколько игроков участвует в раунде. Таймер должен продолжать работать корректно при переходе между экранами вашего мини-приложения, будьте внимательны! Если у девайса есть фонарик, то мигайте фонариком, когда время на таймере закончится.
Релиз: [v0.3.0](https://github.com/Not-cottage-cheese-but-cottage-cheese/VKMiniApps/releases/tag/v0.3.0)

### 40
Добавьте в игру ввод имён всех игроков и показ того, кто из игроков — шпион. Вы наверняка заметили, что играть только с базовыми локациями скучно, — поддержите кастомизацию локаций.
Релиз: [v0.4.0](https://github.com/Not-cottage-cheese-but-cottage-cheese/VKMiniApps/releases/tag/v0.4.0)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spyfall",
"version": "0.3.0",
"version": "0.4.0",
"homepage": "./",
"scripts": {
"start": "cross-env PORT=10888 HTTPS=true react-scripts start",
Expand Down
15 changes: 14 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ import Home from "./panels/Home";
import Game from "./panels/Game";

import Locations from "./modals/Locations";
import CreateLocations from "./panels/CreateLocations";

const App = () => {
const [scheme, setScheme] = useState("bright_light");
const [activePanel, setActivePanel] = useState("home");
const [activeModal, setActiveModal] = useState("");
const [spyNames, setSpyNames] = useState("");
const [gameLocation, setGameLocation] = useState("");
const [popout, setPopout] = useState(<ScreenSpinner size="large" />);
const platform = usePlatform();
Expand Down Expand Up @@ -93,14 +95,18 @@ const App = () => {
};

const openModal = (e) => {
if (e.currentTarget.dataset.location) {
if (e.currentTarget.dataset?.location) {
setGameLocation(e.currentTarget.dataset.location);
}
if (e.currentTarget.dataset?.spynames) {
setSpyNames(e.currentTarget.dataset.spynames);
}
setActiveModal(e.currentTarget.dataset.to);
};

const modalClose = () => {
setActiveModal("");
setSpyNames("");
setGameLocation("");
};

Expand Down Expand Up @@ -137,6 +143,12 @@ const App = () => {
header="Текущая локация"
subheader={gameLocation}
/>
<ModalCard
id="whoIsSpy"
onClose={modalClose}
header="Шпионы"
subheader={spyNames}
/>
</ModalRoot>
);

Expand All @@ -149,6 +161,7 @@ const App = () => {
<SplitCol>
<View activePanel={activePanel}>
<Home id="home" go={go} />
<CreateLocations id="createLocations" go={go} />
<Game
id="game"
go={go}
Expand Down
39 changes: 0 additions & 39 deletions src/components/Countdown.js

This file was deleted.

8 changes: 7 additions & 1 deletion src/modals/Locations.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import React from "react";
import { useSelector } from "react-redux";

import { Group, Header, SimpleCell } from "@vkontakte/vkui";
import { Group, SimpleCell } from "@vkontakte/vkui";

import { LOCATIONS_ARR, LOCATIONS } from "../utils/constant";
const Locations = () => {
const locationsList = useSelector((state) => state.locations.locations);

return (
<Group>
{LOCATIONS_ARR.map((location) => (
<SimpleCell>{LOCATIONS[location]}</SimpleCell>
))}
{Object.keys(locationsList)?.map((locationId) => (
<SimpleCell>{locationsList[locationId]}</SimpleCell>
))}
</Group>
);
};
Expand Down
74 changes: 74 additions & 0 deletions src/panels/CreateLocations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { createRef } from "react";

import {
Panel,
PanelHeader,
PanelHeaderBack,
Group,
FormItem,
Input,
Button,
Div,
ButtonGroup,
Header,
SimpleCell,
IconButton,
} from "@vkontakte/vkui";

import { useSelector, useDispatch } from "react-redux";
import { setLocation, removeLocation } from "../store/features/locations";

import "./Game.css";
import {
Icon28ClearDataOutline,
Icon28RemoveCircleOutline,
} from "@vkontakte/icons";

const CreateLocations = ({ id, go }) => {
const newLocation = createRef();
const dispatch = useDispatch();
const locationsList = useSelector((state) => state.locations.locations);

const createLocation = () => {
dispatch(setLocation(newLocation.current.value));
newLocation.current.value = "";
};

return (
<Panel id={id}>
<PanelHeader left={<PanelHeaderBack onClick={go} data-to="home" />}>
Находка для шпиона
</PanelHeader>
<Group>
<Header>Мои локации</Header>
<Div>
<FormItem top="Введите название локации">
<Input type="text" getRef={newLocation} />
</FormItem>
<ButtonGroup stretched>
<Button mode="outline" stretched onClick={() => createLocation()}>
Добавить локацию
</Button>
</ButtonGroup>
</Div>
<Div>
{Object.keys(locationsList)?.map((locationId) => (
<SimpleCell
after={
<IconButton
onClick={() => dispatch(removeLocation(locationId))}
>
<Icon28RemoveCircleOutline />
</IconButton>
}
>
{locationsList[locationId]}
</SimpleCell>
))}
</Div>
</Group>
</Panel>
);
};

export default CreateLocations;
92 changes: 87 additions & 5 deletions src/panels/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,35 @@ import {
Text,
Paragraph,
ButtonGroup,
Checkbox,
} from "@vkontakte/vkui";

import { Icon56UserSquareOutline } from "@vkontakte/icons";
import { LOCATIONS, LOCATIONS_ARR } from "../utils/constant";

import { useSelector, useDispatch } from "react-redux";
import { start, end } from "../store/features/game";
import {
start,
end,
setPlayers,
changePlayerName,
setSpyesId,
} from "../store/features/game";

import "./Game.css";

const Game = ({ id, go, openModal, timerValue, startTimer }) => {
const [countOfPlayers, setCountOfPlayers] = useState(3);
const [countOfSpyes, setCountOfSpyes] = useState(1);
const [dealIsStart, setDealIsStart] = useState(false);
const [spyesFromOneOrgs, setSpyesFromOneOrgs] = useState(false);
const [currentPlayer, setCurrentPlayer] = useState(1);
const [currentLocation, setCurrentLocation] = useState("");
const [spyUsersId, setSpyUsersId] = useState([]);
const gameIsStarted = useSelector((state) => state.game.value);
const players = useSelector((state) => state.game.players);
const spyesId = useSelector((state) => state.game.spyesId);
const locationsUserList = useSelector((state) => state.locations.locations);
const dispatch = useDispatch();

const divStyle = {
Expand All @@ -46,30 +57,48 @@ const Game = ({ id, go, openModal, timerValue, startTimer }) => {
const { name, value } = e.currentTarget;
if (name === "countOfPlayers") {
setCountOfPlayers(value);
const players = {};
for (let i = 1; i <= value; i++) {
players[i] = `Игрок ${i}`;
}
dispatch(setPlayers(players));
}
if (name === "countOfSpyes") {
setCountOfSpyes(value);
}
if (name === "spyesFromOneOrgs") {
setSpyesFromOneOrgs(value);
}
};

const allLocations = () => {
let allLocations = LOCATIONS_ARR.map((id) => LOCATIONS[id]);
Object.keys(locationsUserList)?.forEach((id) =>
allLocations.push(locationsUserList[id])
);
return allLocations;
};

const dealLocations = () => {
setDealIsStart(true);
for (let i = 1; i <= countOfSpyes; i++) {
let userId = Math.floor(Math.random() * countOfPlayers + 1);
if (spyUsersId.length > 0 && spyUsersId.includes(userId)) {
if (spyUsersId.length > 0 && !spyUsersId.includes(userId)) {
userId = userId === countOfPlayers ? userId - 1 : userId + 1;
}
setSpyUsersId((arr) => [...arr, userId]);
}
const _allLocations = allLocations();
setCurrentLocation(
LOCATIONS[LOCATIONS_ARR[Math.round(Math.random() * LOCATIONS_ARR.length)]]
_allLocations[Math.round(Math.random() * _allLocations.length)]
);
};

const startGame = () => {
setDealIsStart(false);
dispatch(start());
startTimer(countOfPlayers * 60);
dispatch(setSpyesId(spyUsersId));
};

const stopGame = () => {
Expand Down Expand Up @@ -103,6 +132,11 @@ const Game = ({ id, go, openModal, timerValue, startTimer }) => {
}
};

const getSpyNames = () => {
const names = spyesId.map((id) => players[id]);
return names.join(", ");
};

return (
<Panel id={id}>
<PanelHeader left={<PanelHeaderBack onClick={go} data-to="home" />}>
Expand Down Expand Up @@ -151,11 +185,43 @@ const Game = ({ id, go, openModal, timerValue, startTimer }) => {
onChange={onChange}
/>
</FormItem>
{countOfSpyes == 2 && (
<FormItem>
<Checkbox
name="spyesFromOneOrgs"
onChange={onChange}
value={spyesFromOneOrgs}
>
Шпионы работают на одну организацию?
</Checkbox>
</FormItem>
)}
{Object.keys(players).map((playerId) => (
<FormItem top={`Введите имя игрока ${playerId}`}>
<Input
type="text"
defaultValue={`${players[playerId]}`}
onChange={(e) =>
dispatch(
changePlayerName({
id: playerId,
name: e.currentTarget.value,
})
)
}
/>
</FormItem>
))}
<FormItem>
<Button
size="l"
stretched
mode="outline"
disabled={
getSpyesStatus() === "error" ||
countOfPlayers < 3 ||
countOfPlayers > 12
}
onClick={dealLocations}
>
Начать раздачу карт!
Expand All @@ -168,7 +234,7 @@ const Game = ({ id, go, openModal, timerValue, startTimer }) => {
<Div style={divStyle}>
<Icon56UserSquareOutline />
<Paragraph style={{ margin: 10 }}>
Игрок {currentPlayer}, ознакомтесь с локацией.
{players[currentPlayer]}, ознакомтесь с локацией.
</Paragraph>
<ButtonGroup stretched>
<Button
Expand All @@ -179,7 +245,11 @@ const Game = ({ id, go, openModal, timerValue, startTimer }) => {
data-to="showLocation"
data-location={
spyUsersId.length > 0 && spyUsersId.includes(currentPlayer)
? "Вы шпион"
? spyesFromOneOrgs
? `Вы шпион вместе с ${
players[spyUsersId.find((id) => id != currentPlayer)]
}`
: "Вы шпион"
: currentLocation
}
>
Expand Down Expand Up @@ -216,6 +286,18 @@ const Game = ({ id, go, openModal, timerValue, startTimer }) => {
<Text>Кто шпион{countOfSpyes == 1 ? "" : "ы"}?</Text>
</Div>
)}
<ButtonGroup stretched>
<Button
size="l"
stretched
mode="outline"
onClick={openModal}
data-to="whoIsSpy"
data-spyNames={getSpyNames()}
>
Подсмотреть шпион{countOfSpyes == 1 ? "а" : "ов"}
</Button>
</ButtonGroup>
{timerValue == "00:00" && (
<ButtonGroup stretched>
<Button
Expand Down
Loading

0 comments on commit a7a6436

Please sign in to comment.