Compare commits
17 Commits
v0.2
...
46ebb88ef2
| Author | SHA1 | Date | |
|---|---|---|---|
| 46ebb88ef2 | |||
| de14978b01 | |||
| d5ac79559e | |||
| 5ea47ddd25 | |||
| 1a95765877 | |||
| 6bff555cbc | |||
| f4b58fb67e | |||
| 0271b56542 | |||
| 5d73e751d7 | |||
| 314b7a8488 | |||
| 7151be0b1a | |||
| d124205a71 | |||
| 87920548e5 | |||
| 57620c70a2 | |||
| 3dac18c821 | |||
| 3538403f40 | |||
| ec40495328 |
@@ -25,7 +25,6 @@ If you want to know more details about the generation and classification of poly
|
||||
- ULTRA : scores as much as possible in only 2 minutes!
|
||||
- MASTER : clear 200 lines at levels higher than maximum gravity!
|
||||
- ZEN : practice indefinitely in this mode with no gravity!
|
||||
- ??? : still to do
|
||||
|
||||
## Manual build
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ _Repeat for every avaible actions._
|
||||
|
||||
The settings file has the following format:
|
||||
|
||||
- The versions of the file format, stored with 1 byte
|
||||
- The previous maximum pieces size selected, stored with 1 byte
|
||||
- The number of the chosen keybinds (from 0 to 4), stored with 1 byte
|
||||
- The DAS of the player, stored with 1 byte
|
||||
- The ARR of the player, stored with 1 byte
|
||||
@@ -47,5 +49,11 @@ The settings file has the following format:
|
||||
- The last selected width of the board, stored with 1 byte
|
||||
- The last selected height of the board, stored with 1 byte
|
||||
- The uniformity mode (0 for default distribution, 1 for uniformous distribution, 2 for custom distribution), stored with 1 byte
|
||||
- If custom distribution is set, store the proportion of each size (15x1 byte total)
|
||||
- Every selected pieces, using 1 byte for the type of selection (once again converted from an Enum) and 1 byte for the actual value
|
||||
- For each size, store the custom proportion (from 0 to 20) (15x1 byte total)
|
||||
- Every selected pieces
|
||||
- For every groupe of piece (ALL, CONVEX, HOLELESS, OTHER), use 1 byte for the type (once again converted from an Enum) and 1 byte for the size
|
||||
- For every single piece, use 1 byte for (the size + encoding that it is a single piece),
|
||||
and 3 bytes to store the number of the piece (allows number up to 16M, size 15 has 6M pieces).
|
||||
|
||||
The current file format version is 11.
|
||||
If the file starts with a number lower than that, it will be regenerated upon launching the game.
|
||||
|
||||
@@ -106,3 +106,17 @@ Grade is an alternate system to line clears.
|
||||
|
||||
The only exception occurs when the total ends in '99', a line must be cleared to progress.
|
||||
When this line is cleared, the point of the piece is also counted towards the total.
|
||||
|
||||
## Pieces distribution
|
||||
|
||||
A bag is an object which contains a set of pieces.
|
||||
The principle of a bag generator is to put every available pieces into a bag and take them out one by one until the bag is empty, to then start with a new full bag.
|
||||
It's a way to have equal distribution of pieces while still allowing for a random order of pieces.
|
||||
|
||||
The game has 3 modes of pieces distribution:
|
||||
|
||||
1. Default. The simplest of them, all selected pieces are put in a single bag.
|
||||
2. Uniformous. The pieces are now separated by size and put in different bags. Each size will now appear as often as any other.
|
||||
3. Custom. The pieces are once again separated by size, but now the player specifies how likely each size is to appear.
|
||||
|
||||
Both system 2 and 3 uses a system analogous to a bag to determine which size of piece to take next.
|
||||
|
||||
@@ -7,26 +7,54 @@
|
||||
#include <utility>
|
||||
#include <cstdlib>
|
||||
|
||||
static const double SMALLEST_CONSIDERED_PROPORTION = 0.01; // the smallest a proportion can get before it is considered equal to 0
|
||||
|
||||
|
||||
Bag::Bag(const std::shared_ptr<PiecesList>& piecesList) :
|
||||
piecesList(piecesList) {
|
||||
|
||||
this->currentBag = this->piecesList->getSelectedPieces();
|
||||
this->nextBag.clear();
|
||||
|
||||
this->highestSize = this->piecesList->getHighestLoadedSize();
|
||||
this->selectedPieces = this->piecesList->getSelectedPieces();
|
||||
this->distributionMode = this->piecesList->getDistributionMode();
|
||||
this->propotionsPerSize = this->piecesList->getProportionsPerSize();
|
||||
|
||||
this->currentBags.clear();
|
||||
this->nextBags.clear();
|
||||
this->sizesBag.clear();
|
||||
this->sizesProgression.clear();
|
||||
|
||||
if (this->distributionMode == DEFAULT) {
|
||||
this->currentBags.push_back(this->selectedPieces);
|
||||
this->nextBags.push_back({});
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i <= this->highestSize; i++) {
|
||||
this->currentBags.push_back(PieceBag());
|
||||
this->nextBags.push_back(PieceBag());
|
||||
this->sizesProgression.push_back(0);
|
||||
}
|
||||
|
||||
for (const auto& piece : this->selectedPieces) {
|
||||
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().size();
|
||||
this->currentBags.at(pieceSize).push_back(piece);
|
||||
}
|
||||
}
|
||||
|
||||
this->prepareNext();
|
||||
}
|
||||
|
||||
void Bag::jumpToNextBag() {
|
||||
if (this->currentBag.size() < this->nextBag.size()) {
|
||||
std::swap(this->currentBag, this->nextBag);
|
||||
for (int i = 0; i < this->currentBags.size(); i++) {
|
||||
if (this->currentBags.at(i).size() < this->nextBags.at(i).size()) {
|
||||
std::swap(this->currentBags.at(i), this->nextBags.at(i));
|
||||
}
|
||||
|
||||
for (const auto& piece : this->nextBags.at(i)) {
|
||||
this->currentBags.at(i).push_back(piece);
|
||||
}
|
||||
this->nextBags.at(i).clear();
|
||||
}
|
||||
|
||||
for (const std::pair<int, int>& pieceIndex : this->nextBag) {
|
||||
this->currentBag.push_back(pieceIndex);
|
||||
}
|
||||
this->nextBag.clear();
|
||||
|
||||
this->prepareNext();
|
||||
}
|
||||
|
||||
@@ -43,13 +71,40 @@ Piece Bag::getNext() {
|
||||
}
|
||||
|
||||
void Bag::prepareNext() {
|
||||
if (this->currentBag.empty()) {
|
||||
std::swap(this->currentBag, this->nextBag);
|
||||
if (this->distributionMode == DEFAULT) {
|
||||
this->getNextPieceFromBag(0);
|
||||
}
|
||||
else {
|
||||
if (this->sizesBag.empty()) {
|
||||
for (int i = 0; i <= this->highestSize; i++) {
|
||||
if (this->propotionsPerSize.at(i) >= SMALLEST_CONSIDERED_PROPORTION
|
||||
&& !(this->currentBags.at(i).empty() && this->nextBags.at(i).empty())) {
|
||||
while (this->sizesProgression.at(i) < 1) {
|
||||
this->sizesBag.push_back(i);
|
||||
this->sizesProgression.at(i) += this->propotionsPerSize.at(i);
|
||||
}
|
||||
|
||||
this->sizesProgression.at(i) -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nextSizeIndex = std::rand() % this->sizesBag.size();
|
||||
int nextSize = this->sizesBag.at(nextSizeIndex);
|
||||
this->sizesBag.erase(this->sizesBag.begin() + nextSizeIndex);
|
||||
|
||||
this->getNextPieceFromBag(nextSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::getNextPieceFromBag(int bagIndex) {
|
||||
if (this->currentBags.at(bagIndex).empty()) {
|
||||
std::swap(this->currentBags.at(bagIndex), this->nextBags.at(bagIndex));
|
||||
}
|
||||
|
||||
int indexIndex = std::rand() % this->currentBag.size();
|
||||
this->next = this->currentBag.at(indexIndex);
|
||||
int indexIndex = std::rand() % this->currentBags.at(bagIndex).size();
|
||||
this->next = this->currentBags.at(bagIndex).at(indexIndex);
|
||||
|
||||
this->nextBag.push_back(this->next);
|
||||
this->currentBag.erase(this->currentBag.begin() + indexIndex);
|
||||
this->nextBags.at(bagIndex).push_back(this->next);
|
||||
this->currentBags.at(bagIndex).erase(this->currentBags.at(bagIndex).begin() + indexIndex);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
#include "../Pieces/Piece.h"
|
||||
#include "PiecesList.h"
|
||||
#include "DistributionMode.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
using PieceBag = std::vector<std::pair<int, int>>;
|
||||
|
||||
|
||||
/**
|
||||
* A litteral bag of pieces, in which you take each of its piece randomly one by one then start again with a new bag
|
||||
@@ -14,10 +17,15 @@
|
||||
class Bag {
|
||||
private:
|
||||
std::shared_ptr<PiecesList> piecesList; // the list of loaded pieces
|
||||
int highestSize; // the highest size of piece in the bag
|
||||
std::vector<std::pair<int, int>> selectedPieces; // the list of pieces that can be given to the player
|
||||
DistributionMode distributionMode; // the distribution mode
|
||||
std::vector<double> propotionsPerSize; // the proportion of pieces for each size
|
||||
std::pair<int, int> next; // the next piece to give
|
||||
std::vector<std::pair<int, int>> currentBag; // the list of pieces that are still to be taken out before starting a new bag
|
||||
std::vector<std::pair<int, int>> nextBag; // the list of pieces that have been taken out of the current bag and have been placed in the next
|
||||
std::vector<PieceBag> currentBags; // for each size, the list of pieces that are still to be taken out before starting a new bag
|
||||
std::vector<PieceBag> nextBags; // for each size, the list of pieces that have been taken out of the current bag and have been placed in the next
|
||||
std::vector<int> sizesBag; // the list each of bags that are still to have a piece taken out of them
|
||||
std::vector<double> sizesProgression; // how close each size is to meet its quota of pieces
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -26,7 +34,7 @@ class Bag {
|
||||
Bag(const std::shared_ptr<PiecesList>& piecesList);
|
||||
|
||||
/**
|
||||
* Ignores the remaining pieces in the current bag and startd fresh from a new bag
|
||||
* Ignores the remaining pieces in the current bag and start fresh from a new bag
|
||||
*/
|
||||
void jumpToNextBag();
|
||||
|
||||
@@ -44,7 +52,12 @@ class Bag {
|
||||
|
||||
private:
|
||||
/**
|
||||
* Prepare the next picked piece in advance
|
||||
* Prepares the next picked piece in advance
|
||||
*/
|
||||
void prepareNext();
|
||||
|
||||
/**
|
||||
* Gets the next picked piece from the specified bag
|
||||
*/
|
||||
void getNextPieceFromBag(int bagIndex);
|
||||
};
|
||||
|
||||
27
src/Core/DistributionMode.h
Normal file
27
src/Core/DistributionMode.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
/**
|
||||
* The modes of pieces distribution managed by the app
|
||||
*/
|
||||
enum DistributionMode {
|
||||
DEFAULT,
|
||||
UNIFORM,
|
||||
CUSTOM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return A string containing the name of the given distribution mode
|
||||
*/
|
||||
inline std::string getPiecesDistributionName(DistributionMode distributionMode) {
|
||||
static const std::string DISTRIBUTION_NAMES[] = {
|
||||
"DEFAULT",
|
||||
"UNIFORM",
|
||||
"CUSTOM"
|
||||
};
|
||||
|
||||
return DISTRIBUTION_NAMES[distributionMode];
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
GameBoard::GameBoard(int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& piecesList, int nextQueueLength) :
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
GameParameters::GameParameters(Gamemode gamemode, const Player& controls) :
|
||||
gamemode(gamemode),
|
||||
controls(controls) {
|
||||
|
||||
|
||||
this->reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "../Pieces/Piece.h"
|
||||
#include "../Pieces/PiecesFiles.h"
|
||||
#include "DistributionMode.h"
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
@@ -11,6 +12,10 @@ PiecesList::PiecesList() {
|
||||
this->highestLoadedSize = 0;
|
||||
this->selectedPieces.clear();
|
||||
|
||||
this->distributionMode = DEFAULT;
|
||||
this->proportionsPerSize.clear();
|
||||
this->customProportionsPerSize.clear();
|
||||
|
||||
// we need to have something at index 0 even if there is no pieces of size 0
|
||||
this->loadedPieces.clear();
|
||||
this->convexPieces.clear();
|
||||
@@ -24,6 +29,7 @@ PiecesList::PiecesList() {
|
||||
|
||||
bool PiecesList::loadPieces(int size) {
|
||||
if (size < 1) return false;
|
||||
if (size <= this->highestLoadedSize) return true;
|
||||
|
||||
PiecesFiles piecesFiles;
|
||||
for (int i = this->highestLoadedSize + 1; i <= size; i++) {
|
||||
@@ -87,6 +93,14 @@ void PiecesList::unselectAll() {
|
||||
this->selectedPieces.clear();
|
||||
}
|
||||
|
||||
bool PiecesList::setDistributionMode(DistributionMode distributionMode) {
|
||||
if (distributionMode == DEFAULT || distributionMode == UNIFORM || distributionMode == CUSTOM) {
|
||||
this->distributionMode = distributionMode;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int PiecesList::getHighestLoadedSize() const {
|
||||
return this->highestLoadedSize;
|
||||
}
|
||||
@@ -101,13 +115,42 @@ std::vector<std::pair<int, int>> PiecesList::getSelectedPieces() const {
|
||||
return this->selectedPieces;
|
||||
}
|
||||
|
||||
DistributionMode PiecesList::getDistributionMode() const {
|
||||
return this->distributionMode;
|
||||
}
|
||||
|
||||
bool PiecesList::changeCustomDistribution(int size, double distribution) {
|
||||
if (size < 1 || size > this->highestLoadedSize || distribution > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->customProportionsPerSize.at(size) = distribution;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<double> PiecesList::getProportionsPerSize() const {
|
||||
if (this->distributionMode == CUSTOM) {
|
||||
return this->customProportionsPerSize;
|
||||
}
|
||||
else {
|
||||
return this->proportionsPerSize;
|
||||
}
|
||||
}
|
||||
|
||||
Piece PiecesList::getPiece(const std::pair<int, int>& pieceIndex) const {
|
||||
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
|
||||
}
|
||||
|
||||
const Piece& PiecesList::lookAtPiece(const std::pair<int, int>& pieceIndex) const {
|
||||
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
|
||||
}
|
||||
|
||||
void PiecesList::pushBackEmptyVectors() {
|
||||
this->loadedPieces.push_back(std::vector<Piece>());
|
||||
this->convexPieces.push_back(std::vector<int>());
|
||||
this->holelessPieces.push_back(std::vector<int>());
|
||||
this->otherPieces.push_back(std::vector<int>());
|
||||
|
||||
this->proportionsPerSize.push_back(1);
|
||||
this->customProportionsPerSize.push_back(1);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Pieces/Piece.h"
|
||||
#include "DistributionMode.h"
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
@@ -18,6 +19,9 @@ class PiecesList {
|
||||
std::vector<std::vector<int>> holelessPieces; // the list of holeless loaded pieces by size
|
||||
std::vector<std::vector<int>> otherPieces; // the list of other loaded pieces by size
|
||||
std::vector<std::pair<int, int>> selectedPieces; // the list of all currently selected pieces
|
||||
DistributionMode distributionMode; // the current pieces distribution mode
|
||||
std::vector<double> proportionsPerSize; // the proportion of piece for each sizes
|
||||
std::vector<double> customProportionsPerSize; // the proportion of piece for each sizes when the distribution mode is set to custom
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -66,6 +70,19 @@ class PiecesList {
|
||||
*/
|
||||
void unselectAll();
|
||||
|
||||
/**
|
||||
* Changes the current pieces distribution mode
|
||||
* @return If the mode is supported
|
||||
*/
|
||||
bool setDistributionMode(DistributionMode distributionMode);
|
||||
|
||||
/**
|
||||
* Changes the distribution of the specified size for when the distribution mode is set to custom,
|
||||
* the specified distribution must lower or equal to 1
|
||||
* @return If the new distribution was applied
|
||||
*/
|
||||
bool changeCustomDistribution(int size, double distribution);
|
||||
|
||||
/**
|
||||
* @return The highest loaded size of pieces
|
||||
*/
|
||||
@@ -81,10 +98,25 @@ class PiecesList {
|
||||
*/
|
||||
std::vector<std::pair<int, int>> getSelectedPieces() const;
|
||||
|
||||
/**
|
||||
* @return The current distribution mode
|
||||
*/
|
||||
DistributionMode getDistributionMode() const;
|
||||
|
||||
/**
|
||||
* @return The proportion of pieces for each loaded size
|
||||
*/
|
||||
std::vector<double> getProportionsPerSize() const;
|
||||
|
||||
/**
|
||||
* @return A copy of the piece corresponding to the specified index
|
||||
*/
|
||||
Piece getPiece(const std::pair<int, int>& pieceIndex) const;
|
||||
|
||||
/**
|
||||
* @return The piece corresponding to the specified index
|
||||
*/
|
||||
const Piece& lookAtPiece(const std::pair<int, int>& pieceIndex) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
||||
@@ -80,4 +80,11 @@ class AppMenu {
|
||||
text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos}));
|
||||
this->renderWindow->draw(text);
|
||||
}
|
||||
|
||||
sf::Color getColorOfBlock(Block block, int luminosityShift) const {
|
||||
Color rgbColor = BLOCKS_COLOR[block];
|
||||
return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.green + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.blue + luminosityShift, 0, 255));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
@@ -58,8 +57,6 @@ void GameBoardAppMenu::drawFrame() const {
|
||||
|
||||
this->placeTitle(text, {}, "BOARD SETTINGS", 5.f, {});
|
||||
|
||||
sf::Vector2u windowSize = this->renderWindow->getSize();
|
||||
|
||||
this->placeText(text, this->playerCursor, "< BOARD WIDTH: " + std::to_string(menu.getBoardWidth()) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "< BOARD HEIGHT: " + std::to_string(menu.getBoardHeight()) + " >", 5.f, 25.f, sf::Vector2u{0, 1});
|
||||
|
||||
|
||||
85
src/GraphicalUI/AppMenus/GameDistributionAppMenu.cpp
Normal file
85
src/GraphicalUI/AppMenus/GameDistributionAppMenu.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "GameDistributionAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
GameDistributionAppMenu::GameDistributionAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({1}) {
|
||||
|
||||
for (int i = 1; i <= this->settings->getMaximumPiecesSize(); i++) {
|
||||
this->playerCursor.addRow(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GameDistributionAppMenu::computeFrame() {
|
||||
this->updateMetaBinds();
|
||||
this->playerCursor.updatePosition();
|
||||
|
||||
PiecesList& piecesList = this->settings->getMenu().getPiecesList();
|
||||
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
piecesList.setDistributionMode(DistributionMode((int) piecesList.getDistributionMode() - 1));
|
||||
}
|
||||
if (this->playerCursor.movedRight()) {
|
||||
piecesList.setDistributionMode(DistributionMode((int) piecesList.getDistributionMode() + 1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (piecesList.getDistributionMode() != CUSTOM) {
|
||||
this->playerCursor.goToPosition({0, 0});
|
||||
}
|
||||
else {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
this->settings->decreaseDistribution(this->playerCursor.getPosition().y);
|
||||
}
|
||||
if (this->playerCursor.movedRight()) {
|
||||
this->settings->increaseDistribution(this->playerCursor.getPosition().y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->escReleased) {
|
||||
this->settings->confirmDistribution();
|
||||
this->menuStack->pop();
|
||||
}
|
||||
}
|
||||
|
||||
void GameDistributionAppMenu::drawFrame() const {
|
||||
this->renderWindow->clear(sf::Color(200, 200, 200));
|
||||
|
||||
const Menu& menu = this->settings->getMenu();
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||
text.setFillColor(sf::Color(0, 0, 0));
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
|
||||
this->placeTitle(text, {}, "DISTRIBUTION SETTINGS", 5.f, {});
|
||||
|
||||
const DistributionMode distributionMode = this->settings->getMenu().readPiecesList().getDistributionMode();
|
||||
const std::vector<int>& distributions = this->settings->getDistributions();
|
||||
|
||||
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 1, 0, this->settings->getMaximumPiecesSize() - 3);
|
||||
if (firstElem == 0) {
|
||||
this->placeText(text, this->playerCursor, "< DISTRIBUTION MODE: " + getPiecesDistributionName(distributionMode) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
}
|
||||
else {
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem) + " PROBABILITY: " + std::to_string(distributions.at(firstElem)) + " >", 5.f, 15.f, sf::Vector2u{(unsigned int) firstElem, 0});
|
||||
}
|
||||
|
||||
if (distributionMode != CUSTOM) {
|
||||
text.setFillColor(sf::Color(100, 100, 100));
|
||||
}
|
||||
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem + 1) + " PROBABILITY: " + std::to_string(distributions.at(firstElem + 1)) + " >", 5.f, 25.f, sf::Vector2u{0, (unsigned int) firstElem + 1});
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem + 2) + " PROBABILITY: " + std::to_string(distributions.at(firstElem + 2)) + " >", 5.f, 35.f, sf::Vector2u{0, (unsigned int) firstElem + 2});
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem + 3) + " PROBABILITY: " + std::to_string(distributions.at(firstElem + 3)) + " >", 5.f, 45.f, sf::Vector2u{0, (unsigned int) firstElem + 3});
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
21
src/GraphicalUI/AppMenus/GameDistributionAppMenu.h
Normal file
21
src/GraphicalUI/AppMenus/GameDistributionAppMenu.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
class GameDistributionAppMenu : public AppMenu {
|
||||
private:
|
||||
PlayerCursor playerCursor;
|
||||
|
||||
public:
|
||||
GameDistributionAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
|
||||
|
||||
void computeFrame() override;
|
||||
|
||||
void drawFrame() const override;
|
||||
};
|
||||
234
src/GraphicalUI/AppMenus/GamePiecesAppMenu.cpp
Normal file
234
src/GraphicalUI/AppMenus/GamePiecesAppMenu.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
#include "GamePiecesAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "GameDistributionAppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
GamePiecesAppMenu::GamePiecesAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({1, (unsigned int) this->settings->getSelectedPieces().size() + 1u}) {
|
||||
|
||||
for (int i = 1; i <= this->settings->getMaximumPiecesSize(); i++) {
|
||||
this->playerCursor.addRow(i + 1, this->settings->getMenu().readPiecesList().getNumberOfPieces(i) + 4);
|
||||
}
|
||||
|
||||
if (this->settings->getMaximumPiecesSize() < GENERATED_PIECES_SIZE) {
|
||||
this->playerCursor.addRow(this->settings->getMaximumPiecesSize() + 2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::computeFrame() {
|
||||
this->updateMetaBinds();
|
||||
this->playerCursor.updatePosition();
|
||||
|
||||
if (this->playerCursor.movedDown() && this->playerCursor.getPosition().y == 2) {
|
||||
this->playerCursor.goToPosition({0, 2});
|
||||
}
|
||||
|
||||
if (this->enterReleased) {
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
this->menuStack->push(std::make_shared<GameDistributionAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
}
|
||||
|
||||
if (this->playerCursor.getPosition().y == (this->settings->getMaximumPiecesSize() + 2)) {
|
||||
int newMaxSize = this->settings->getMaximumPiecesSize() + 1;
|
||||
this->settings->loadPieces(newMaxSize);
|
||||
|
||||
this->playerCursor.removeRow(newMaxSize + 1);
|
||||
this->playerCursor.addRow(newMaxSize + 1, this->settings->getMenu().readPiecesList().getNumberOfPieces(newMaxSize) + 4);
|
||||
this->playerCursor.goToPosition({0u, newMaxSize + 1u});
|
||||
|
||||
if (newMaxSize < GENERATED_PIECES_SIZE) {
|
||||
this->playerCursor.addRow(newMaxSize + 2, 1);
|
||||
}
|
||||
}
|
||||
else if (this->playerCursor.getPosition().y > 1) {
|
||||
if (this->playerCursor.getPosition().x >= 4) {
|
||||
this->settings->selectPieces(createSinglePieceType(this->playerCursor.getPosition().y - 1), this->playerCursor.getPosition().x - 4);
|
||||
}
|
||||
else {
|
||||
switch (this->playerCursor.getPosition().x) {
|
||||
case 0 : {this->settings->selectPieces(ALL_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
case 1 : {this->settings->selectPieces(CONVEX_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
case 2 : {this->settings->selectPieces(HOLELESS_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
case 3 : {this->settings->selectPieces(OTHER_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
}
|
||||
}
|
||||
this->playerCursor.addPosition(0, 1);
|
||||
}
|
||||
}
|
||||
if (this->escReleased) {
|
||||
if (this->playerCursor.getPosition().y == 1) {
|
||||
if (this->playerCursor.getPosition().x > 0) {
|
||||
this->settings->unselectPieces(this->playerCursor.getPosition().x - 1);
|
||||
this->playerCursor.removePosition(this->playerCursor.getPosition().x - 1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->settings->confirmSelectedPieces();
|
||||
this->menuStack->pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawFrame() const {
|
||||
this->renderWindow->clear(sf::Color(200, 200, 200));
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||
text.setFillColor(sf::Color(0, 0, 0));
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
|
||||
this->placeTitle(text, {}, "PIECES SELECT", 5.f, {});
|
||||
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
this->placeText(text, this->playerCursor, "PIECES DISTRIBUTION", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->drawSelectedPiecesRow(25.f);
|
||||
this->drawRow(1, 35.f, true);
|
||||
this->drawRow(2, 45.f, true);
|
||||
}
|
||||
else {
|
||||
this->drawSelectedPiecesRow(15.f);
|
||||
|
||||
bool drawFromFirstElem = (this->playerCursor.getPosition().y == 1);
|
||||
bool addExtraLine = (this->settings->getMaximumPiecesSize() < GENERATED_PIECES_SIZE);
|
||||
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 2, 1, this->settings->getMaximumPiecesSize() - 2 + (addExtraLine ? 1 : 0));
|
||||
this->drawRow(firstElem, 25.f, drawFromFirstElem);
|
||||
this->drawRow(firstElem + 1, 35.f, drawFromFirstElem);
|
||||
this->drawRow(firstElem + 2, 45.f, drawFromFirstElem);
|
||||
}
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
|
||||
sf::RectangleShape rect({(float) this->renderWindow->getSize().x, 8.f * this->settings->getWindowSizeMultiplier()});
|
||||
rect.setPosition({0.f, (yPos - 4.f) * this->settings->getWindowSizeMultiplier()});
|
||||
rect.setFillColor({240, 240, 240});
|
||||
this->renderWindow->draw(rect);
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier());
|
||||
text.setFillColor({0, 0, 0});
|
||||
|
||||
int elem = (this->playerCursor.getPosition().y == 1) ? std::max(((int) this->playerCursor.getPosition().x) - 4, 0) : 0;
|
||||
float xProgress = 1.f;
|
||||
|
||||
bool first = true;
|
||||
while (true) {
|
||||
if ((this->playerCursor.getPosition().y == 1) && (elem == this->playerCursor.getPosition().x)) {
|
||||
this->placeText(text, {}, "|", xProgress, yPos, {});
|
||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||
}
|
||||
|
||||
if (elem >= this->settings->getSelectedPieces().size()) return;
|
||||
|
||||
const auto& [pieceType, value] = this->settings->getSelectedPieces().at(elem);
|
||||
|
||||
int pieceSize = getSizeOfPieces(pieceType);
|
||||
if (pieceSize > 0) {
|
||||
if (!(pieceSize > this->settings->getMaximumPiecesSize())) {
|
||||
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({pieceSize, value});
|
||||
int cellSize = (8 * this->settings->getWindowSizeMultiplier()) / (piece.getLength());
|
||||
sf::FloatRect piecePosition(sf::Vector2f(xProgress, yPos - 4.f) * (float) this->settings->getWindowSizeMultiplier(), sf::Vector2f(8 , 8) * (float) this->settings->getWindowSizeMultiplier());
|
||||
this->drawPiece(piece, cellSize, piecePosition, false);
|
||||
xProgress += (1.f + 8.f);
|
||||
}
|
||||
else {
|
||||
this->placeText(text, {}, "ERROR_UNSUPPORTED", xProgress, yPos, {});
|
||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(value > this->settings->getMaximumPiecesSize())) {
|
||||
this->placeText(text, {}, ((first) ? "" : " ") + getPiecesTypeName(pieceType) + "_" + std::to_string(value), xProgress, yPos, {});
|
||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||
}
|
||||
else {
|
||||
this->placeText(text, {}, "ERROR_UNSUPPORTED", xProgress, yPos, {});
|
||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||
}
|
||||
}
|
||||
|
||||
elem++;
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const {
|
||||
if (piecesSize > this->settings->getMaximumPiecesSize()) {
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||
text.setOutlineThickness(this->settings->getWindowSizeMultiplier() / 2);
|
||||
if (this->playerCursor.getPosition().y == (piecesSize + 1)) {
|
||||
text.setOutlineColor({255, 255, 255});
|
||||
}
|
||||
else {
|
||||
text.setOutlineColor({0, 0, 0});
|
||||
}
|
||||
|
||||
std::string sizeString = "LOAD SIZE " + std::to_string(piecesSize) + "? ";
|
||||
if (piecesSize <= 10) {
|
||||
text.setFillColor({0, 255, 0});
|
||||
this->placeText(text, {}, sizeString + "(LOW LOAD TIME)", 1.f, yPos, {});
|
||||
}
|
||||
else if (piecesSize <= 13) {
|
||||
text.setFillColor({255, 255, 0});
|
||||
this->placeText(text, {}, sizeString + "(MEDIUM LOAD TIME)", 1.f, yPos, {});
|
||||
}
|
||||
else {
|
||||
text.setFillColor({255, 0, 0});
|
||||
this->placeText(text, {}, sizeString + "(LONG LOAD TIME)", 1.f, yPos, {});
|
||||
}
|
||||
}
|
||||
else {
|
||||
int numberOfPieces = this->settings->getMenu().readPiecesList().getNumberOfPieces(piecesSize);
|
||||
int firstElem = (drawFromFirstElem) ? -4 : std::max(((int) this->playerCursor.getPosition().x) - 7, -4);
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier());
|
||||
text.setFillColor({0, 0, 0});
|
||||
text.setOutlineColor({255, 255, 255});
|
||||
|
||||
this->placeText(text, {}, "SIZE " + std::to_string(piecesSize), 1.f, yPos, {});
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (i + firstElem >= numberOfPieces) return;
|
||||
|
||||
if ((i + firstElem) < 0) {
|
||||
switch (i + firstElem) {
|
||||
case -4 : {this->placeText(text, this->playerCursor, "ALL", 10.f + (i * 10.f), yPos, sf::Vector2u{0, piecesSize + 1u}); break;}
|
||||
case -3 : {this->placeText(text, this->playerCursor, "CONVEX", 10.f + (i * 10.f), yPos, sf::Vector2u{1, piecesSize + 1u}); break;}
|
||||
case -2 : {this->placeText(text, this->playerCursor, "HOLELESS", 10.f + (i * 10.f), yPos, sf::Vector2u{2, piecesSize + 1u}); break;}
|
||||
case -1 : {this->placeText(text, this->playerCursor, "OTHER", 10.f + (i * 10.f), yPos, sf::Vector2u{3, piecesSize + 1u}); break;}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({piecesSize, firstElem + i});
|
||||
int cellSize = (8 * this->settings->getWindowSizeMultiplier()) / (piece.getLength());
|
||||
sf::FloatRect piecePosition(sf::Vector2f(10.f + (i * 10.f), yPos - 4.f) * (float) this->settings->getWindowSizeMultiplier(), sf::Vector2f(8 , 8) * (float) this->settings->getWindowSizeMultiplier());
|
||||
this->drawPiece(piece, cellSize, piecePosition, this->playerCursor.getPosition() == sf::Vector2u{i + firstElem + 4u, piecesSize + 1u});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawPiece(const Piece& piece, int cellSize, const sf::FloatRect& piecePosition, bool selected) const {
|
||||
sf::RectangleShape rect(piecePosition.size);
|
||||
rect.setPosition(piecePosition.position);
|
||||
rect.setFillColor({180, 180, 180});
|
||||
if (selected) {
|
||||
rect.setOutlineColor({0, 0, 0});
|
||||
rect.setOutlineThickness(this->settings->getWindowSizeMultiplier() / 2);
|
||||
}
|
||||
this->renderWindow->draw(rect);
|
||||
|
||||
sf::RectangleShape cell(sf::Vector2f(cellSize, cellSize));
|
||||
cell.setFillColor(this->getColorOfBlock(piece.getBlockType(), 0));
|
||||
|
||||
for (const Position& cellPosition : piece.getPositions()) {
|
||||
cell.setPosition(sf::Vector2f(piecePosition.position.x + (cellPosition.x * cellSize),
|
||||
piecePosition.position.y + ((piece.getLength() - cellPosition.y - 1) * cellSize) ));
|
||||
this->renderWindow->draw(cell);
|
||||
}
|
||||
}
|
||||
29
src/GraphicalUI/AppMenus/GamePiecesAppMenu.h
Normal file
29
src/GraphicalUI/AppMenus/GamePiecesAppMenu.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
class GamePiecesAppMenu : public AppMenu {
|
||||
private:
|
||||
PlayerCursor playerCursor;
|
||||
|
||||
public:
|
||||
GamePiecesAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
|
||||
|
||||
void computeFrame() override;
|
||||
|
||||
void drawFrame() const override;
|
||||
|
||||
private:
|
||||
void drawSelectedPiecesRow(float yPos) const;
|
||||
|
||||
void drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const;
|
||||
|
||||
void drawPiece(const Piece& piece, int cellSize, const sf::FloatRect& pos, bool selected) const;
|
||||
};
|
||||
@@ -9,14 +9,15 @@
|
||||
#include <string>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
static const int TIME_BEFORE_STARTING = 60;
|
||||
|
||||
|
||||
GamePlayingAppMenu::GamePlayingAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
game(this->settings->getMenu().startGame(this->settings->getGamemode())) {
|
||||
|
||||
this->startTimer = TIME_BEFORE_STARTING;
|
||||
this->startTimer = this->settings->getStartTimerLength() * FRAMES_PER_SECOND;
|
||||
if (this->startTimer == 0) {
|
||||
this->game.start();
|
||||
}
|
||||
this->paused = false;
|
||||
this->pausePressed = false;
|
||||
this->retryPressed = false;
|
||||
@@ -39,7 +40,7 @@ GamePlayingAppMenu::GamePlayingAppMenu(std::shared_ptr<MenuStack> menuStack, std
|
||||
|
||||
this->nextCellSizeZoom = this->nextQueuePosition[0].size.y;
|
||||
for (const auto& piece : this->settings->getMenu().getPiecesList().getSelectedPieces()) {
|
||||
float nextPieceCellSizeZoom = ((int) this->nextQueuePosition[0].size.y) / this->settings->getMenu().getPiecesList().getPiece(piece).getLength();
|
||||
float nextPieceCellSizeZoom = ((int) this->nextQueuePosition[0].size.y) / this->settings->getMenu().getPiecesList().lookAtPiece(piece).getLength();
|
||||
this->nextCellSizeZoom = std::min(this->nextCellSizeZoom, nextPieceCellSizeZoom);
|
||||
}
|
||||
|
||||
@@ -77,7 +78,10 @@ void GamePlayingAppMenu::computeFrame() {
|
||||
else {
|
||||
if (this->retryPressed) {
|
||||
this->game.reset();
|
||||
this->startTimer = TIME_BEFORE_STARTING;
|
||||
this->startTimer = this->settings->getStartTimerLength() * FRAMES_PER_SECOND;
|
||||
if (this->startTimer == 0) {
|
||||
this->game.start();
|
||||
}
|
||||
}
|
||||
this->retryPressed = false;
|
||||
}
|
||||
@@ -247,6 +251,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
// game state
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
text.setOutlineThickness(windowSizeMultiplier / 2.f);
|
||||
text.setCharacterSize(windowSizeMultiplier * 4);
|
||||
|
||||
if (this->game.hasWon()) {
|
||||
this->placeTitle(text, {}, "WIN", 25.f, {});
|
||||
@@ -258,20 +263,12 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
this->placeTitle(text, {}, "PAUSE", 25.f, {});
|
||||
}
|
||||
else if (this->startTimer > 0) {
|
||||
text.setCharacterSize(windowSizeMultiplier * 4);
|
||||
this->placeTitle(text, {}, std::to_string(((this->startTimer - 1) / (TIME_BEFORE_STARTING / 4))), 25.f, {});
|
||||
this->placeTitle(text, {}, std::to_string(((this->startTimer - 1) / ((this->settings->getStartTimerLength() * FRAMES_PER_SECOND) / 4))), 25.f, {});
|
||||
}
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
sf::Color GamePlayingAppMenu::getColorOfBlock(Block block, int luminosityShift) const {
|
||||
Color rgbColor = BLOCKS_COLOR[block];
|
||||
return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.green + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.blue + luminosityShift, 0, 255));
|
||||
}
|
||||
|
||||
sf::Vector2f GamePlayingAppMenu::getBoardBlockPosition(int x, int y) const {
|
||||
return sf::Vector2f(this->boardPosition.position.x + (x * this->cellSizeZoom),
|
||||
this->boardPosition.position.y + ((this->game.getBoard().getBaseHeight() + 9 - y) * this->cellSizeZoom));
|
||||
|
||||
@@ -28,7 +28,5 @@ class GamePlayingAppMenu : public AppMenu {
|
||||
|
||||
void drawFrame() const override;
|
||||
|
||||
sf::Color getColorOfBlock(Block block, int luminosityShift) const;
|
||||
|
||||
sf::Vector2f getBoardBlockPosition(int x, int y) const;
|
||||
};
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#include "GameSettingsAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "GamePiecesAppMenu.h"
|
||||
#include "GameBoardAppMenu.h"
|
||||
#include "GamePlayingAppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
GameSettingsAppMenu::GameSettingsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({2, 3, 3}) {
|
||||
playerCursor({2, 3, 2}) {
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ void GameSettingsAppMenu::computeFrame() {
|
||||
switch (this->playerCursor.getPosition().x) {
|
||||
case 0 : {this->settings->setGamemode(MASTER); break;}
|
||||
case 1 : {this->settings->setGamemode(ZEN); break;}
|
||||
case 2 : break; //TODO
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -43,7 +42,7 @@ void GameSettingsAppMenu::computeFrame() {
|
||||
if (this->enterReleased) {
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
if (this->playerCursor.getPosition().x == 0) {
|
||||
//TODO
|
||||
this->menuStack->push(std::make_shared<GamePiecesAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
}
|
||||
if (this->playerCursor.getPosition().x == 1) {
|
||||
this->menuStack->push(std::make_shared<GameBoardAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
@@ -67,15 +66,17 @@ void GameSettingsAppMenu::drawFrame() const {
|
||||
|
||||
this->placeTitle(text, {}, "GAME SETTINGS", 5.f, {});
|
||||
|
||||
this->placeText(text, this->playerCursor, "PIECES SELECT (TODO)", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "PIECES SELECT", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "BOARD SELECT", 40.f, 15.f, sf::Vector2u{1, 0});
|
||||
|
||||
this->placeText(text, this->playerCursor, "SPRINT", 5.f, 25.f, sf::Vector2u{0, 1});
|
||||
this->placeText(text, this->playerCursor, "MARATHON", 25.f, 25.f, sf::Vector2u{1, 1});
|
||||
this->placeText(text, this->playerCursor, "ULTRA", 50.f, 25.f, sf::Vector2u{2, 1});
|
||||
this->placeText(text, this->playerCursor, "MASTER", 5.f, 35.f, sf::Vector2u{0, 2});
|
||||
this->placeText(text, this->playerCursor, "ZEN", 25.f, 35.f, sf::Vector2u{1, 2});
|
||||
this->placeText(text, this->playerCursor, "??? (TODO)", 50.f, 35.f, sf::Vector2u{2, 2});
|
||||
text.setOutlineThickness(0);
|
||||
this->placeTitle(text, {}, "GAMEMODE SELECT", 25.f, {});
|
||||
|
||||
this->placeText(text, this->playerCursor, "SPRINT", 5.f, 35.f, sf::Vector2u{0, 1});
|
||||
this->placeText(text, this->playerCursor, "MARATHON", 25.f, 35.f, sf::Vector2u{1, 1});
|
||||
this->placeText(text, this->playerCursor, "ULTRA", 50.f, 35.f, sf::Vector2u{2, 1});
|
||||
this->placeText(text, this->playerCursor, "MASTER", 5.f, 45.f, sf::Vector2u{0, 2});
|
||||
this->placeText(text, this->playerCursor, "ZEN", 25.f, 45.f, sf::Vector2u{1, 2});
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
@@ -15,7 +14,7 @@
|
||||
|
||||
SettingsKeybindsAppMenu::SettingsKeybindsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({12, 1}) {
|
||||
playerCursor({1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) {
|
||||
|
||||
this->selectedAnAction = false;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
@@ -37,10 +36,10 @@ void SettingsMainAppMenu::computeFrame() {
|
||||
}
|
||||
case 3 : {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
this->settings->lowerMasterVolume();
|
||||
this->settings->shortenStartTimer();
|
||||
}
|
||||
if (this->playerCursor.movedRight()) {
|
||||
this->settings->raiseMasterVolume();
|
||||
this->settings->lengthenStartTimer();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -73,7 +72,7 @@ void SettingsMainAppMenu::drawFrame() const {
|
||||
this->placeText(text, this->playerCursor, "CHANGE KEYBINDS", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "CHANGE CONTROLS", 5.f, 25.f, sf::Vector2u{0, 1});
|
||||
this->placeText(text, this->playerCursor, "< WINDOW SIZE: " + std::to_string(windowSize.x) + "x" + std::to_string(windowSize.y) + " >", 5.f, 35.f, sf::Vector2u{0, 2});
|
||||
this->placeText(text, this->playerCursor, "< VOLUME: " + std::to_string(this->settings->getMasterVolume()) + "% >", 5.f, 45.f, sf::Vector2u{0, 3});
|
||||
this->placeText(text, this->playerCursor, "< START TIMER: " + std::to_string(this->settings->getStartTimerLength()) + "s >", 5.f, 45.f, sf::Vector2u{0, 3});
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
75
src/GraphicalUI/AppMenus/StartUpAppMenu.cpp
Normal file
75
src/GraphicalUI/AppMenus/StartUpAppMenu.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "StartUpAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "MainAppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
StartUpAppMenu::StartUpAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({GENERATED_PIECES_SIZE + 1}) {
|
||||
|
||||
this->playerCursor.goToPosition({(unsigned int) std::clamp(this->settings->getMaximumPiecesSize(), MINIMUM_PIECES_SIZE, GENERATED_PIECES_SIZE), 0u});
|
||||
}
|
||||
|
||||
void StartUpAppMenu::computeFrame() {
|
||||
this->updateMetaBinds();
|
||||
this->playerCursor.updatePosition();
|
||||
|
||||
if (this->playerCursor.getPosition().x < MINIMUM_PIECES_SIZE) {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
this->playerCursor.goToPosition({GENERATED_PIECES_SIZE, 0});
|
||||
}
|
||||
else {
|
||||
this->playerCursor.goToPosition({MINIMUM_PIECES_SIZE, 0});
|
||||
}
|
||||
}
|
||||
|
||||
if (this->enterReleased) {
|
||||
this->settings->loadSettingsFromFile(true, {this->playerCursor.getPosition().x});
|
||||
this->menuStack->pop();
|
||||
|
||||
if (this->settings->hasLoadedPieces()) {
|
||||
this->menuStack->push(std::make_shared<MainAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
}
|
||||
else {
|
||||
std::cout << "ERROR: COULD NOT LOAD PIECES" << std::endl;
|
||||
std::cout << "ARGUMENT WAS: " << this->playerCursor.getPosition().x << std::endl;
|
||||
}
|
||||
}
|
||||
else if (this->escReleased) {
|
||||
this->menuStack->pop();
|
||||
}
|
||||
}
|
||||
|
||||
void StartUpAppMenu::drawFrame() const {
|
||||
this->renderWindow->clear(sf::Color(200, 200, 200));
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||
text.setFillColor(sf::Color(0, 0, 0));
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
|
||||
this->placeTitle(text, {}, "SELECT THE LOADED PIECES MAXIMUM SIZE", 10.f, {});
|
||||
this->placeTitle(text, this->playerCursor, "< " + std::to_string(this->playerCursor.getPosition().x) + " >", 25.f, this->playerCursor.getPosition());
|
||||
|
||||
text.setOutlineColor({0, 0, 0});
|
||||
if (this->playerCursor.getPosition().x <= 10) {
|
||||
text.setFillColor({0, 255, 0});
|
||||
this->placeTitle(text, {}, "LOW LOAD TIME", 40.f, {});
|
||||
}
|
||||
else if (this->playerCursor.getPosition().x <= 13) {
|
||||
text.setFillColor({255, 255, 0});
|
||||
this->placeTitle(text, {}, "MEDIUM LOAD TIME", 40.f, {});
|
||||
}
|
||||
else {
|
||||
text.setFillColor({255, 0, 0});
|
||||
this->placeTitle(text, {}, "LONG LOAD TIME", 40.f, {});
|
||||
}
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
21
src/GraphicalUI/AppMenus/StartUpAppMenu.h
Normal file
21
src/GraphicalUI/AppMenus/StartUpAppMenu.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
class StartUpAppMenu : public AppMenu {
|
||||
private:
|
||||
PlayerCursor playerCursor;
|
||||
|
||||
public:
|
||||
StartUpAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
|
||||
|
||||
void computeFrame() override;
|
||||
|
||||
void drawFrame() const override;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "GraphApp.h"
|
||||
|
||||
#include "AppMenus/AppMenu.h"
|
||||
#include "AppMenus/MainAppMenu.h"
|
||||
#include "AppMenus/StartUpAppMenu.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <stack>
|
||||
@@ -12,14 +12,14 @@ static const double TIME_BETWEEN_FRAMES = (1000.f / FRAMES_PER_SECOND);
|
||||
|
||||
|
||||
GraphApp::GraphApp() {
|
||||
this->settings = std::make_shared<Settings>();
|
||||
this->settings = std::make_shared<Settings>(false);
|
||||
this->menuStack = std::make_shared<MenuStack>();
|
||||
this->renderWindow = std::make_shared<sf::RenderWindow>();
|
||||
}
|
||||
|
||||
void GraphApp::run() {
|
||||
this->settings->changeVideoMode(*this->renderWindow);
|
||||
this->menuStack->push(std::make_shared<MainAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
this->menuStack->push(std::make_shared<StartUpAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
|
||||
bool quit = false;
|
||||
double timeAtNextFrame = 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
using sfKey = sf::Keyboard::Key;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
enum PiecesType {
|
||||
CONVEX_PIECES,
|
||||
@@ -19,3 +21,15 @@ inline int getSizeOfPieces(PiecesType type) {
|
||||
inline PiecesType createSinglePieceType(int size) {
|
||||
return PiecesType(SINGLE_PIECE + size - 1);
|
||||
}
|
||||
|
||||
inline std::string getPiecesTypeName(PiecesType piecesType) {
|
||||
static const std::string PIECES_TYPE_NAME[] = {
|
||||
"CONVEX",
|
||||
"HOLELESS",
|
||||
"OTHER",
|
||||
"ALL",
|
||||
"SINGLE"
|
||||
};
|
||||
|
||||
return PIECES_TYPE_NAME[piecesType];
|
||||
}
|
||||
|
||||
@@ -66,6 +66,48 @@ void PlayerCursor::goToPosition(const sf::Vector2u& newPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerCursor::addPosition(unsigned int x, unsigned int y) {
|
||||
if (y >= this->rows.size()) return false;
|
||||
if (x > this->rows.at(y)) return false;
|
||||
|
||||
this->rows.at(y)++;
|
||||
if ((y == this->position.y) && (x <= this->position.x)) {
|
||||
this->position.x++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerCursor::removePosition(unsigned int x, unsigned int y) {
|
||||
if (y >= this->rows.size()) return false;
|
||||
if (x >= this->rows.at(y)) return false;
|
||||
|
||||
this->rows.at(y)--;
|
||||
if ((y == this->position.y) && (x < this->position.x)) {
|
||||
this->position.x--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerCursor::addRow(unsigned int position, unsigned int width) {
|
||||
if (position > this->rows.size()) return false;
|
||||
|
||||
this->rows.insert(this->rows.begin() + position, width);
|
||||
if (position <= this->position.y) {
|
||||
this->position.y++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerCursor::removeRow(unsigned int position) {
|
||||
if (position >= this->rows.size()) return false;
|
||||
|
||||
this->rows.erase(this->rows.begin() + position);
|
||||
if (position < this->position.y) {
|
||||
this->position.y--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const sf::Vector2u& PlayerCursor::getPosition() const {
|
||||
return this->position;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,14 @@ class PlayerCursor {
|
||||
|
||||
void goToPosition(const sf::Vector2u& newPosition);
|
||||
|
||||
bool addPosition(unsigned int x, unsigned int y);
|
||||
|
||||
bool removePosition(unsigned int x, unsigned int y);
|
||||
|
||||
bool addRow(unsigned int position, unsigned int width);
|
||||
|
||||
bool removeRow(unsigned int position);
|
||||
|
||||
const sf::Vector2u& getPosition() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
#include "../Core/Menu.h"
|
||||
#include "Keybinds.h"
|
||||
#include "PiecesType.h"
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <SFML/Graphics.hpp>
|
||||
@@ -10,25 +13,64 @@
|
||||
static const sf::Vector2u BASE_WINDOW_SIZE = {80, 50};
|
||||
static const int WINDOW_SIZE_MULTIPLIERS[] = {4, 6, 10, 14, 20, 30, 40};
|
||||
static const int WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1;
|
||||
static const int START_TIMER_MAX = 4;
|
||||
static const int DISTRIBUTION_MAX = 20;
|
||||
|
||||
|
||||
Settings::Settings() {
|
||||
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||
this->menu.getPiecesList().loadPieces(i);
|
||||
}
|
||||
|
||||
Settings::Settings(bool loadPieces) {
|
||||
this->keybinds.clear();
|
||||
this->keybinds.reserve(NUMBER_OF_KEYBINDS);
|
||||
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
||||
this->keybinds.emplace_back(i);
|
||||
}
|
||||
|
||||
this->loadSettingsFromFile();
|
||||
this->loadSettingsFromFile(loadPieces, {});
|
||||
}
|
||||
|
||||
void Settings::loadSettingsFromFile() {
|
||||
void Settings::loadPieces(int maximumPiecesSizeRequest) {
|
||||
if (maximumPiecesSizeRequest < MINIMUM_PIECES_SIZE) {
|
||||
maximumPiecesSizeRequest = MINIMUM_PIECES_SIZE;
|
||||
}
|
||||
else if (maximumPiecesSizeRequest > GENERATED_PIECES_SIZE || maximumPiecesSizeRequest > MAXIMUM_PIECES_SIZE) {
|
||||
maximumPiecesSizeRequest = GENERATED_PIECES_SIZE;
|
||||
}
|
||||
|
||||
bool succeeded = true;
|
||||
int i = 1;
|
||||
while (succeeded && (i <= maximumPiecesSizeRequest)) {
|
||||
succeeded = this->menu.getPiecesList().loadPieces(i);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (succeeded) {
|
||||
this->maximumPiecesSize = maximumPiecesSizeRequest;
|
||||
}
|
||||
this->loadedPieces = succeeded;
|
||||
}
|
||||
|
||||
void Settings::loadSettingsFromFile(bool loadPieces, std::optional<int> maximumPiecesSizeRequest) {
|
||||
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
|
||||
char byte;
|
||||
|
||||
// file format version
|
||||
settingsFile.get(byte);
|
||||
|
||||
// maximum pieces size
|
||||
settingsFile.get(byte);
|
||||
this->maximumPiecesSize = byte;
|
||||
|
||||
if (loadPieces) {
|
||||
if (maximumPiecesSizeRequest.has_value()) {
|
||||
this->loadPieces(maximumPiecesSizeRequest.value());
|
||||
}
|
||||
else {
|
||||
this->loadPieces(byte);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->loadedPieces = false;
|
||||
}
|
||||
|
||||
// keybind layout
|
||||
settingsFile.get(byte);
|
||||
this->chosenKeybinds = byte;
|
||||
@@ -49,9 +91,9 @@ void Settings::loadSettingsFromFile() {
|
||||
settingsFile.get(byte);
|
||||
this->windowSizeMode = byte;
|
||||
|
||||
// master volume
|
||||
// start timer length
|
||||
settingsFile.get(byte);
|
||||
this->masterVolume = byte;
|
||||
this->startTimerLength = byte;
|
||||
|
||||
// gamemode
|
||||
settingsFile.get(byte);
|
||||
@@ -65,35 +107,68 @@ void Settings::loadSettingsFromFile() {
|
||||
settingsFile.get(byte);
|
||||
this->menu.setBoardHeight(byte);
|
||||
|
||||
// piece distribution
|
||||
settingsFile.get(byte);
|
||||
//TODO
|
||||
if (byte == 2) {
|
||||
if (this->loadedPieces) {
|
||||
// piece distribution
|
||||
settingsFile.get(byte);
|
||||
this->menu.getPiecesList().setDistributionMode(DistributionMode(byte));
|
||||
|
||||
this->distributions.clear();
|
||||
this->distributions.push_back(0);
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
settingsFile.get(byte);
|
||||
//TODO
|
||||
this->distributions.push_back(byte);
|
||||
}
|
||||
}
|
||||
this->confirmDistribution();
|
||||
|
||||
// selected pieces
|
||||
char pieceType;
|
||||
char pieceValue;
|
||||
this->selectedPieces.clear();
|
||||
while (settingsFile.get(pieceType)) {
|
||||
if (settingsFile.eof()) break;
|
||||
|
||||
settingsFile.get(pieceValue);
|
||||
this->selectedPieces.push_back({PiecesType(pieceType), pieceValue});
|
||||
// selected pieces
|
||||
char pieceType;
|
||||
char pieceSize;
|
||||
char lowByte;
|
||||
char midByte;
|
||||
char highByte;
|
||||
|
||||
this->selectedPieces.clear();
|
||||
while (settingsFile.get(pieceType)) {
|
||||
if (settingsFile.eof()) break;
|
||||
|
||||
if (getSizeOfPieces(PiecesType(pieceType)) == 0) {
|
||||
settingsFile.get(pieceSize);
|
||||
|
||||
this->selectedPieces.emplace_back(PiecesType(pieceType), pieceSize);
|
||||
}
|
||||
else {
|
||||
settingsFile.get(lowByte);
|
||||
settingsFile.get(midByte);
|
||||
settingsFile.get(highByte);
|
||||
|
||||
int pieceNumber = ((unsigned char) lowByte) + ((unsigned char) midByte << 8) + ((unsigned char) highByte << 16);
|
||||
this->selectedPieces.emplace_back(PiecesType(pieceType), pieceNumber);
|
||||
}
|
||||
}
|
||||
this->confirmSelectedPieces();
|
||||
}
|
||||
else {
|
||||
this->distributions.clear();
|
||||
this->selectedPieces.clear();
|
||||
}
|
||||
this->confirmSelectedPieces();
|
||||
}
|
||||
|
||||
void Settings::saveSettingsToFile() const {
|
||||
if (!this->loadedPieces) return;
|
||||
|
||||
this->keybinds.at(CUSTOMIZABLE_KEYBINDS).saveKeybindsToFile();
|
||||
|
||||
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
|
||||
char byte;
|
||||
|
||||
// file format version
|
||||
byte = CURRENT_FILE_FORMAT_VERSION;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// maximum pieces size
|
||||
byte = this->maximumPiecesSize;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// keybind layout
|
||||
byte = this->chosenKeybinds;
|
||||
settingsFile.write(&byte, 1);
|
||||
@@ -114,8 +189,8 @@ void Settings::saveSettingsToFile() const {
|
||||
byte = this->windowSizeMode;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// master volume
|
||||
byte = this->masterVolume;
|
||||
// start timer length
|
||||
byte = this->startTimerLength;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// gamemode
|
||||
@@ -131,15 +206,30 @@ void Settings::saveSettingsToFile() const {
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// piece distribution
|
||||
//TODO
|
||||
byte = this->menu.readPiecesList().getDistributionMode();
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
byte = this->distributions.at(i);
|
||||
settingsFile.write(&byte, 1);
|
||||
}
|
||||
|
||||
// selected pieces
|
||||
for (const auto& [type, value] : this->selectedPieces) {
|
||||
byte = type;
|
||||
settingsFile.write(&byte, 1);
|
||||
byte = value;
|
||||
settingsFile.write(&byte, 1);
|
||||
if (getSizeOfPieces(type) == 0) {
|
||||
byte = value;
|
||||
settingsFile.write(&byte, 1);
|
||||
}
|
||||
else {
|
||||
int number = value;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
byte = (number % 256);
|
||||
settingsFile.write(&byte, 1);
|
||||
number = (number >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,17 +278,17 @@ void Settings::changeVideoMode(sf::RenderWindow& window) const {
|
||||
window.setPosition(sf::Vector2i((desktopSize.x / 2) - (windowSize.x / 2), (desktopSize.y / 2) - (windowSize.y / 2)));
|
||||
}
|
||||
|
||||
bool Settings::raiseMasterVolume() {
|
||||
if (this->masterVolume < 100) {
|
||||
this->masterVolume = std::min(this->masterVolume + 5, 100);
|
||||
bool Settings::lengthenStartTimer() {
|
||||
if (this->startTimerLength < START_TIMER_MAX) {
|
||||
this->startTimerLength++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Settings::lowerMasterVolume() {
|
||||
if (this->masterVolume > 0) {
|
||||
this->masterVolume = std::max(this->masterVolume - 5, 0);
|
||||
bool Settings::shortenStartTimer() {
|
||||
if (this->startTimerLength > 0) {
|
||||
this->startTimerLength--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -209,35 +299,80 @@ void Settings::setGamemode(Gamemode gamemode) {
|
||||
}
|
||||
|
||||
void Settings::selectPieces(PiecesType type, int value) {
|
||||
if (!this->loadedPieces) return;
|
||||
|
||||
this->selectedPieces.emplace_back(type, value);
|
||||
}
|
||||
|
||||
void Settings::unselectPieces(int index) {
|
||||
if (!this->loadedPieces) return;
|
||||
if (index >= this->selectedPieces.size()) return;
|
||||
|
||||
this->selectedPieces.erase(this->selectedPieces.begin() + index);
|
||||
}
|
||||
|
||||
void Settings::confirmSelectedPieces() {
|
||||
if (!this->loadedPieces) return;
|
||||
|
||||
this->menu.getPiecesList().unselectAll();
|
||||
|
||||
bool selectedNone = true;
|
||||
for (const auto& [type, value] : this->selectedPieces) {
|
||||
int size = getSizeOfPieces(type);
|
||||
|
||||
if (size == 0) {
|
||||
switch (type) {
|
||||
case CONVEX_PIECES : {this->menu.getPiecesList().selectConvexPieces(value); break;}
|
||||
case HOLELESS_PIECES : {this->menu.getPiecesList().selectHolelessPieces(value); break;}
|
||||
case OTHER_PIECES : {this->menu.getPiecesList().selectOtherPieces(value); break;}
|
||||
case ALL_PIECES : {this->menu.getPiecesList().selectAllPieces(value); break;}
|
||||
if (!(value > this->maximumPiecesSize)) {
|
||||
switch (type) {
|
||||
case CONVEX_PIECES : {this->menu.getPiecesList().selectConvexPieces(value); break;}
|
||||
case HOLELESS_PIECES : {this->menu.getPiecesList().selectHolelessPieces(value); break;}
|
||||
case OTHER_PIECES : {this->menu.getPiecesList().selectOtherPieces(value); break;}
|
||||
case ALL_PIECES : {this->menu.getPiecesList().selectAllPieces(value); break;}
|
||||
}
|
||||
selectedNone = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (size > MAXIMUM_PIECES_SIZE) return;
|
||||
|
||||
this->menu.getPiecesList().selectPiece(size, value);
|
||||
if (!(getSizeOfPieces(type) > this->maximumPiecesSize)) {
|
||||
this->menu.getPiecesList().selectPiece(size, value);
|
||||
selectedNone = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedNone) {
|
||||
this->selectedPieces.push_back(DEFAULT_SELECTION);
|
||||
this->confirmSelectedPieces();
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::increaseDistribution(int size) {
|
||||
if (!this->loadedPieces) return false;
|
||||
if (size < 1 || size > this->maximumPiecesSize) return false;
|
||||
|
||||
if (this->distributions.at(size) < DISTRIBUTION_MAX) {
|
||||
this->distributions.at(size)++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Settings::decreaseDistribution(int size) {
|
||||
if (!this->loadedPieces) return false;
|
||||
if (size < 1 || size > this->maximumPiecesSize) return false;
|
||||
|
||||
if (this->distributions.at(size) > 0) {
|
||||
this->distributions.at(size)--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Settings::confirmDistribution() {
|
||||
if (!this->loadedPieces) return;
|
||||
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
this->menu.getPiecesList().changeCustomDistribution(i, (double) 1 / (this->distributions.at(i) + 0.001));
|
||||
}
|
||||
}
|
||||
|
||||
Menu& Settings::getMenu() {
|
||||
@@ -248,6 +383,14 @@ Keybinds& Settings::getKeybinds() {
|
||||
return this->keybinds.at(this->chosenKeybinds);
|
||||
}
|
||||
|
||||
int Settings::getMaximumPiecesSize() const {
|
||||
return this->maximumPiecesSize;
|
||||
}
|
||||
|
||||
bool Settings::hasLoadedPieces() const {
|
||||
return this->loadedPieces;
|
||||
}
|
||||
|
||||
int Settings::getKeybindsLayout() const {
|
||||
return this->chosenKeybinds;
|
||||
}
|
||||
@@ -260,10 +403,14 @@ int Settings::getWindowSizeMultiplier() const {
|
||||
return WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode];
|
||||
}
|
||||
|
||||
int Settings::getMasterVolume() const {
|
||||
return this->masterVolume;
|
||||
int Settings::getStartTimerLength() const {
|
||||
return this->startTimerLength;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<PiecesType, int>>& Settings::getSelectedPieces() const {
|
||||
return this->selectedPieces;
|
||||
}
|
||||
|
||||
const std::vector<int>& Settings::getDistributions() const {
|
||||
return this->distributions;
|
||||
}
|
||||
|
||||
@@ -4,34 +4,47 @@
|
||||
#include "Keybinds.h"
|
||||
#include "PiecesType.h"
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
static const int CURRENT_FILE_FORMAT_VERSION = 11;
|
||||
|
||||
static const int MAXIMUM_BOARD_WIDTH = 40;
|
||||
static const int MAXIMUM_BOARD_HEIGHT = 40;
|
||||
|
||||
//#define __JMINOS_RELEASE__
|
||||
#ifdef __JMINOS_RELEASE__
|
||||
static const int MINIMUM_PIECES_SIZE = 4;
|
||||
static const int MAXIMUM_PIECES_SIZE = 15;
|
||||
|
||||
#define __JMINOS_RELEASE__
|
||||
#ifdef __JMINOS_RELEASE__
|
||||
static const int GENERATED_PIECES_SIZE = 15;
|
||||
#else
|
||||
static const int MAXIMUM_PIECES_SIZE = 10;
|
||||
static const int GENERATED_PIECES_SIZE = 10;
|
||||
#endif
|
||||
|
||||
static const std::pair<PiecesType, int> DEFAULT_SELECTION = {ALL_PIECES, MINIMUM_PIECES_SIZE};
|
||||
|
||||
|
||||
class Settings {
|
||||
private:
|
||||
Menu menu;
|
||||
int maximumPiecesSize;
|
||||
bool loadedPieces;
|
||||
std::vector<Keybinds> keybinds;
|
||||
int chosenKeybinds;
|
||||
int windowSizeMode;
|
||||
int masterVolume;
|
||||
int startTimerLength;
|
||||
Gamemode gamemode;
|
||||
std::vector<std::pair<PiecesType, int>> selectedPieces;
|
||||
std::vector<int> distributions;
|
||||
|
||||
public:
|
||||
Settings();
|
||||
Settings(bool loadPieces);
|
||||
|
||||
void loadSettingsFromFile();
|
||||
void loadPieces(int maximumPiecesSizeRequest);
|
||||
|
||||
void loadSettingsFromFile(bool loadPieces, std::optional<int> maximumPiecesSizeRequest);
|
||||
|
||||
void saveSettingsToFile() const;
|
||||
|
||||
@@ -47,9 +60,9 @@ class Settings {
|
||||
|
||||
void changeVideoMode(sf::RenderWindow& window) const;
|
||||
|
||||
bool raiseMasterVolume();
|
||||
bool lengthenStartTimer();
|
||||
|
||||
bool lowerMasterVolume();
|
||||
bool shortenStartTimer();
|
||||
|
||||
void setGamemode(Gamemode gamemode);
|
||||
|
||||
@@ -59,17 +72,29 @@ class Settings {
|
||||
|
||||
void confirmSelectedPieces();
|
||||
|
||||
bool increaseDistribution(int size);
|
||||
|
||||
bool decreaseDistribution(int size);
|
||||
|
||||
void confirmDistribution();
|
||||
|
||||
Menu& getMenu();
|
||||
|
||||
Keybinds& getKeybinds();
|
||||
|
||||
int getMaximumPiecesSize() const;
|
||||
|
||||
bool hasLoadedPieces() const;
|
||||
|
||||
int getKeybindsLayout() const;
|
||||
|
||||
Gamemode getGamemode() const;
|
||||
|
||||
int getWindowSizeMultiplier() const;
|
||||
|
||||
int getMasterVolume() const;
|
||||
int getStartTimerLength() const;
|
||||
|
||||
const std::vector<std::pair<PiecesType, int>>& getSelectedPieces() const;
|
||||
|
||||
const std::vector<int>& getDistributions() const;
|
||||
};
|
||||
|
||||
@@ -13,16 +13,31 @@ int main() {
|
||||
std::srand(std::time(NULL));
|
||||
|
||||
PiecesFiles pf;
|
||||
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||
for (int i = 1; i <= GENERATED_PIECES_SIZE; i++) {
|
||||
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
||||
std::cout << "pieces files for size " << i << " not found, generating..." << std::endl;
|
||||
pf.savePieces(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("data/config/settings.bin")) {
|
||||
std::cout << "settings file not found, generating..." << std::endl;
|
||||
resetSettingsFile();
|
||||
}
|
||||
else {
|
||||
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
|
||||
char byte;
|
||||
|
||||
settingsFile.get(byte);
|
||||
if ((unsigned char) byte < CURRENT_FILE_FORMAT_VERSION) {
|
||||
std::cout << "files format changed, regenerating..." << std::endl;
|
||||
resetSettingsFile();
|
||||
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
||||
resetKeybindFile(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
||||
if (!std::filesystem::exists("data/config/keybinds/layout" + std::to_string(i) + ".bin")) {
|
||||
std::cout << "keybind file n°" << (i + 1) << "/" << NUMBER_OF_KEYBINDS << " not found, generating..." << std::endl;
|
||||
@@ -43,6 +58,14 @@ void resetSettingsFile() {
|
||||
|
||||
Menu menu;
|
||||
|
||||
// file format version
|
||||
byte = CURRENT_FILE_FORMAT_VERSION;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// maximum pieces size
|
||||
byte = MINIMUM_PIECES_SIZE;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// keybind layout
|
||||
byte = 0;
|
||||
settingsFile.write(&byte, 1);
|
||||
@@ -63,8 +86,8 @@ void resetSettingsFile() {
|
||||
byte = 2;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// master volume
|
||||
byte = 50;
|
||||
// start timer length
|
||||
byte = 2;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// gamemode
|
||||
@@ -80,8 +103,12 @@ void resetSettingsFile() {
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// piece distribution
|
||||
byte = 0;
|
||||
byte = DEFAULT;
|
||||
settingsFile.write(&byte, 1);
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
byte = 1;
|
||||
settingsFile.write(&byte, 1);
|
||||
}
|
||||
|
||||
// selected pieces
|
||||
byte = ALL_PIECES;
|
||||
|
||||
@@ -91,7 +91,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
|
||||
char positionByte;
|
||||
for (int i = 0; i < polyominoSize; i++) {
|
||||
piecesFile.get(positionByte);
|
||||
int x = (positionByte & xMask) >> 4;
|
||||
int x = ((unsigned char) positionByte & xMask) >> 4;
|
||||
int y = positionByte & yMask;
|
||||
piecePositions.insert(Position{x, y});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user