11 Commits

Author SHA1 Message Date
f4b58fb67e omg omg 2025-03-30 22:43:41 +02:00
0271b56542 better piece scrolling 2025-03-30 20:16:14 +02:00
5d73e751d7 début de qqch 2025-03-30 13:07:17 +02:00
314b7a8488 added distribution menu 2025-03-29 21:57:27 +01:00
7151be0b1a better cursor 2025-03-29 19:28:04 +01:00
d124205a71 ok fix ig 2025-03-29 18:52:06 +01:00
87920548e5 Merge branch 'main' of https://git.ale-pri.com/TetrisNerd/jminos 2025-03-29 18:50:54 +01:00
57620c70a2 added distribution modes 2025-03-29 18:48:37 +01:00
3dac18c821 fix linux build 2025-03-29 18:14:14 +01:00
3538403f40 finalized gamemode select menu 2025-03-29 12:31:54 +01:00
ec40495328 change volume to start timer 2025-03-29 11:49:19 +01:00
30 changed files with 701 additions and 89 deletions

View File

@@ -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! - ULTRA : scores as much as possible in only 2 minutes!
- MASTER : clear 200 lines at levels higher than maximum gravity! - MASTER : clear 200 lines at levels higher than maximum gravity!
- ZEN : practice indefinitely in this mode with no gravity! - ZEN : practice indefinitely in this mode with no gravity!
- ??? : still to do
## Manual build ## Manual build

View File

@@ -47,5 +47,5 @@ The settings file has the following format:
- The last selected width of the board, stored with 1 byte - The last selected width of the board, stored with 1 byte
- The last selected height 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 - 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) - For each size, store the custom proportion (from 0 to 10) (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 - Every selected pieces, using 1 byte for the type of selection (once again converted from an Enum) and 1 byte for the actual value

View File

@@ -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. 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. 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.

View File

@@ -7,25 +7,53 @@
#include <utility> #include <utility>
#include <cstdlib> #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) : Bag::Bag(const std::shared_ptr<PiecesList>& piecesList) :
piecesList(piecesList) { piecesList(piecesList) {
this->currentBag = this->piecesList->getSelectedPieces(); this->highestSize = this->piecesList->getHighestLoadedSize();
this->nextBag.clear(); 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(); this->prepareNext();
} }
void Bag::jumpToNextBag() { void Bag::jumpToNextBag() {
if (this->currentBag.size() < this->nextBag.size()) { for (int i = 0; i < this->currentBags.size(); i++) {
std::swap(this->currentBag, this->nextBag); if (this->currentBags.at(i).size() < this->nextBags.at(i).size()) {
std::swap(this->currentBags.at(i), this->nextBags.at(i));
} }
for (const std::pair<int, int>& pieceIndex : this->nextBag) { for (const auto& piece : this->nextBags.at(i)) {
this->currentBag.push_back(pieceIndex); this->currentBags.at(i).push_back(piece);
}
this->nextBags.at(i).clear();
} }
this->nextBag.clear();
this->prepareNext(); this->prepareNext();
} }
@@ -43,13 +71,40 @@ Piece Bag::getNext() {
} }
void Bag::prepareNext() { void Bag::prepareNext() {
if (this->currentBag.empty()) { if (this->distributionMode == DEFAULT) {
std::swap(this->currentBag, this->nextBag); 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);
} }
int indexIndex = std::rand() % this->currentBag.size(); this->sizesProgression.at(i) -= 1;
this->next = this->currentBag.at(indexIndex); }
}
this->nextBag.push_back(this->next); }
this->currentBag.erase(this->currentBag.begin() + indexIndex);
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->currentBags.at(bagIndex).size();
this->next = this->currentBags.at(bagIndex).at(indexIndex);
this->nextBags.at(bagIndex).push_back(this->next);
this->currentBags.at(bagIndex).erase(this->currentBags.at(bagIndex).begin() + indexIndex);
} }

View File

@@ -2,11 +2,14 @@
#include "../Pieces/Piece.h" #include "../Pieces/Piece.h"
#include "PiecesList.h" #include "PiecesList.h"
#include "DistributionMode.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <utility> #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 * 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 { class Bag {
private: private:
std::shared_ptr<PiecesList> piecesList; // the list of loaded pieces 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 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::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<PieceBag> currentBags; // for each size, 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> 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: public:
/** /**
@@ -26,7 +34,7 @@ class Bag {
Bag(const std::shared_ptr<PiecesList>& piecesList); 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(); void jumpToNextBag();
@@ -44,7 +52,12 @@ class Bag {
private: private:
/** /**
* Prepare the next picked piece in advance * Prepares the next picked piece in advance
*/ */
void prepareNext(); void prepareNext();
/**
* Gets the next picked piece from the specified bag
*/
void getNextPieceFromBag(int bagIndex);
}; };

View 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];
}

View File

@@ -2,6 +2,7 @@
#include "../Pieces/Piece.h" #include "../Pieces/Piece.h"
#include "../Pieces/PiecesFiles.h" #include "../Pieces/PiecesFiles.h"
#include "DistributionMode.h"
#include <vector> #include <vector>
#include <utility> #include <utility>
@@ -11,6 +12,10 @@ PiecesList::PiecesList() {
this->highestLoadedSize = 0; this->highestLoadedSize = 0;
this->selectedPieces.clear(); 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 // we need to have something at index 0 even if there is no pieces of size 0
this->loadedPieces.clear(); this->loadedPieces.clear();
this->convexPieces.clear(); this->convexPieces.clear();
@@ -87,6 +92,14 @@ void PiecesList::unselectAll() {
this->selectedPieces.clear(); 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 { int PiecesList::getHighestLoadedSize() const {
return this->highestLoadedSize; return this->highestLoadedSize;
} }
@@ -101,13 +114,42 @@ std::vector<std::pair<int, int>> PiecesList::getSelectedPieces() const {
return this->selectedPieces; 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 { Piece PiecesList::getPiece(const std::pair<int, int>& pieceIndex) const {
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second); 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() { void PiecesList::pushBackEmptyVectors() {
this->loadedPieces.push_back(std::vector<Piece>()); this->loadedPieces.push_back(std::vector<Piece>());
this->convexPieces.push_back(std::vector<int>()); this->convexPieces.push_back(std::vector<int>());
this->holelessPieces.push_back(std::vector<int>()); this->holelessPieces.push_back(std::vector<int>());
this->otherPieces.push_back(std::vector<int>()); this->otherPieces.push_back(std::vector<int>());
this->proportionsPerSize.push_back(1);
this->customProportionsPerSize.push_back(1);
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "../Pieces/Piece.h" #include "../Pieces/Piece.h"
#include "DistributionMode.h"
#include <vector> #include <vector>
#include <utility> #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>> 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::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 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: public:
/** /**
@@ -66,6 +70,19 @@ class PiecesList {
*/ */
void unselectAll(); 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 * @return The highest loaded size of pieces
*/ */
@@ -81,11 +98,26 @@ class PiecesList {
*/ */
std::vector<std::pair<int, int>> getSelectedPieces() const; 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 * @return A copy of the piece corresponding to the specified index
*/ */
Piece getPiece(const std::pair<int, int>& pieceIndex) const; 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: private:
/** /**
* Adds empty vectors at the end of every pieces list * Adds empty vectors at the end of every pieces list

View File

@@ -80,4 +80,11 @@ class AppMenu {
text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos})); text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos}));
this->renderWindow->draw(text); 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));
}
}; };

View File

@@ -5,7 +5,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
@@ -58,8 +57,6 @@ void GameBoardAppMenu::drawFrame() const {
this->placeTitle(text, {}, "BOARD SETTINGS", 5.f, {}); 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 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}); this->placeText(text, this->playerCursor, "< BOARD HEIGHT: " + std::to_string(menu.getBoardHeight()) + " >", 5.f, 25.f, sf::Vector2u{0, 1});

View 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 <= MAXIMUM_PIECES_SIZE; 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, MAXIMUM_PIECES_SIZE - 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();
}

View 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;
};

View File

@@ -0,0 +1,182 @@
#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 <= MAXIMUM_PIECES_SIZE; i++) {
this->playerCursor.addRow(i + 1, this->settings->getMenu().readPiecesList().getNumberOfPieces(i) + 4);
}
}
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 > 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 {
if (this->settings->getSelectedPieces().size() == 0) {
this->settings->selectPieces(ALL_PIECES, 4);
}
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);
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 2, 1, MAXIMUM_PIECES_SIZE - 2);
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) {
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, {}, ((first) ? "" : " ") + getPiecesTypeName(pieceType) + "_" + std::to_string(value), xProgress, yPos, {});
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
}
elem++;
}
}
void GamePiecesAppMenu::drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const {
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);
}
}

View 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;
};

View File

@@ -9,14 +9,15 @@
#include <string> #include <string>
#include <SFML/Graphics.hpp> #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) : GamePlayingAppMenu::GamePlayingAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, renderWindow), AppMenu(menuStack, settings, renderWindow),
game(this->settings->getMenu().startGame(this->settings->getGamemode())) { 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->paused = false;
this->pausePressed = false; this->pausePressed = false;
this->retryPressed = false; this->retryPressed = false;
@@ -39,7 +40,7 @@ GamePlayingAppMenu::GamePlayingAppMenu(std::shared_ptr<MenuStack> menuStack, std
this->nextCellSizeZoom = this->nextQueuePosition[0].size.y; this->nextCellSizeZoom = this->nextQueuePosition[0].size.y;
for (const auto& piece : this->settings->getMenu().getPiecesList().getSelectedPieces()) { 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); this->nextCellSizeZoom = std::min(this->nextCellSizeZoom, nextPieceCellSizeZoom);
} }
@@ -77,7 +78,10 @@ void GamePlayingAppMenu::computeFrame() {
else { else {
if (this->retryPressed) { if (this->retryPressed) {
this->game.reset(); 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; this->retryPressed = false;
} }
@@ -116,6 +120,8 @@ void GamePlayingAppMenu::drawFrame() const {
} }
} }
// end coutdown
if (drawActivePiece) { if (drawActivePiece) {
// ghost piece // ghost piece
sf::Color ghostColor = this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), 100); sf::Color ghostColor = this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), 100);
@@ -247,6 +253,7 @@ void GamePlayingAppMenu::drawFrame() const {
// game state // game state
text.setOutlineColor(sf::Color(255, 255, 255)); text.setOutlineColor(sf::Color(255, 255, 255));
text.setOutlineThickness(windowSizeMultiplier / 2.f); text.setOutlineThickness(windowSizeMultiplier / 2.f);
text.setCharacterSize(windowSizeMultiplier * 4);
if (this->game.hasWon()) { if (this->game.hasWon()) {
this->placeTitle(text, {}, "WIN", 25.f, {}); this->placeTitle(text, {}, "WIN", 25.f, {});
@@ -258,20 +265,12 @@ void GamePlayingAppMenu::drawFrame() const {
this->placeTitle(text, {}, "PAUSE", 25.f, {}); this->placeTitle(text, {}, "PAUSE", 25.f, {});
} }
else if (this->startTimer > 0) { else if (this->startTimer > 0) {
text.setCharacterSize(windowSizeMultiplier * 4); this->placeTitle(text, {}, std::to_string(((this->startTimer - 1) / ((this->settings->getStartTimerLength() * FRAMES_PER_SECOND) / 4))), 25.f, {});
this->placeTitle(text, {}, std::to_string(((this->startTimer - 1) / (TIME_BEFORE_STARTING / 4))), 25.f, {});
} }
this->renderWindow->display(); 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 { sf::Vector2f GamePlayingAppMenu::getBoardBlockPosition(int x, int y) const {
return sf::Vector2f(this->boardPosition.position.x + (x * this->cellSizeZoom), return sf::Vector2f(this->boardPosition.position.x + (x * this->cellSizeZoom),
this->boardPosition.position.y + ((this->game.getBoard().getBaseHeight() + 9 - y) * this->cellSizeZoom)); this->boardPosition.position.y + ((this->game.getBoard().getBaseHeight() + 9 - y) * this->cellSizeZoom));

View File

@@ -28,7 +28,5 @@ class GamePlayingAppMenu : public AppMenu {
void drawFrame() const override; void drawFrame() const override;
sf::Color getColorOfBlock(Block block, int luminosityShift) const;
sf::Vector2f getBoardBlockPosition(int x, int y) const; sf::Vector2f getBoardBlockPosition(int x, int y) const;
}; };

View File

@@ -1,19 +1,19 @@
#include "GameSettingsAppMenu.h" #include "GameSettingsAppMenu.h"
#include "AppMenu.h" #include "AppMenu.h"
#include "GamePiecesAppMenu.h"
#include "GameBoardAppMenu.h" #include "GameBoardAppMenu.h"
#include "GamePlayingAppMenu.h" #include "GamePlayingAppMenu.h"
#include "../PlayerCursor.h" #include "../PlayerCursor.h"
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
GameSettingsAppMenu::GameSettingsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : GameSettingsAppMenu::GameSettingsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, 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) { switch (this->playerCursor.getPosition().x) {
case 0 : {this->settings->setGamemode(MASTER); break;} case 0 : {this->settings->setGamemode(MASTER); break;}
case 1 : {this->settings->setGamemode(ZEN); break;} case 1 : {this->settings->setGamemode(ZEN); break;}
case 2 : break; //TODO
} }
break; break;
} }
@@ -43,7 +42,7 @@ void GameSettingsAppMenu::computeFrame() {
if (this->enterReleased) { if (this->enterReleased) {
if (this->playerCursor.getPosition().y == 0) { if (this->playerCursor.getPosition().y == 0) {
if (this->playerCursor.getPosition().x == 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) { if (this->playerCursor.getPosition().x == 1) {
this->menuStack->push(std::make_shared<GameBoardAppMenu>(this->menuStack, this->settings, this->renderWindow)); 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->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, "BOARD SELECT", 40.f, 15.f, sf::Vector2u{1, 0});
this->placeText(text, this->playerCursor, "SPRINT", 5.f, 25.f, sf::Vector2u{0, 1}); text.setOutlineThickness(0);
this->placeText(text, this->playerCursor, "MARATHON", 25.f, 25.f, sf::Vector2u{1, 1}); this->placeTitle(text, {}, "GAMEMODE SELECT", 25.f, {});
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, "SPRINT", 5.f, 35.f, sf::Vector2u{0, 1});
this->placeText(text, this->playerCursor, "ZEN", 25.f, 35.f, sf::Vector2u{1, 2}); this->placeText(text, this->playerCursor, "MARATHON", 25.f, 35.f, sf::Vector2u{1, 1});
this->placeText(text, this->playerCursor, "??? (TODO)", 50.f, 35.f, sf::Vector2u{2, 2}); 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(); this->renderWindow->display();
} }

View File

@@ -5,7 +5,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>

View File

@@ -8,7 +8,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>

View File

@@ -5,7 +5,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>

View File

@@ -5,7 +5,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <string> #include <string>
#include <regex> #include <regex>
#include <filesystem> #include <filesystem>
@@ -15,7 +14,7 @@
SettingsKeybindsAppMenu::SettingsKeybindsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : SettingsKeybindsAppMenu::SettingsKeybindsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, renderWindow), AppMenu(menuStack, settings, renderWindow),
playerCursor({12, 1}) { playerCursor({1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) {
this->selectedAnAction = false; this->selectedAnAction = false;

View File

@@ -7,7 +7,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <vector>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
@@ -37,10 +36,10 @@ void SettingsMainAppMenu::computeFrame() {
} }
case 3 : { case 3 : {
if (this->playerCursor.movedLeft()) { if (this->playerCursor.movedLeft()) {
this->settings->lowerMasterVolume(); this->settings->shortenStartTimer();
} }
if (this->playerCursor.movedRight()) { if (this->playerCursor.movedRight()) {
this->settings->raiseMasterVolume(); this->settings->lengthenStartTimer();
} }
break; 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 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, "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, "< 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(); this->renderWindow->display();
} }

View File

@@ -4,7 +4,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <optional> #include <algorithm>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
using sfKey = sf::Keyboard::Key; using sfKey = sf::Keyboard::Key;

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <string>
enum PiecesType { enum PiecesType {
CONVEX_PIECES, CONVEX_PIECES,
@@ -19,3 +21,15 @@ inline int getSizeOfPieces(PiecesType type) {
inline PiecesType createSinglePieceType(int size) { inline PiecesType createSinglePieceType(int size) {
return PiecesType(SINGLE_PIECE + size - 1); 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];
}

View File

@@ -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 { const sf::Vector2u& PlayerCursor::getPosition() const {
return this->position; return this->position;
} }

View File

@@ -28,6 +28,14 @@ class PlayerCursor {
void goToPosition(const sf::Vector2u& newPosition); 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; const sf::Vector2u& getPosition() const;
private: private:

View File

@@ -10,6 +10,8 @@
static const sf::Vector2u BASE_WINDOW_SIZE = {80, 50}; 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_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 WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1;
static const int START_TIMER_MAX = 4;
static const int DISTRIBUTION_MAX = 10;
Settings::Settings() { Settings::Settings() {
@@ -49,9 +51,9 @@ void Settings::loadSettingsFromFile() {
settingsFile.get(byte); settingsFile.get(byte);
this->windowSizeMode = byte; this->windowSizeMode = byte;
// master volume // start timer length
settingsFile.get(byte); settingsFile.get(byte);
this->masterVolume = byte; this->startTimerLength = byte;
// gamemode // gamemode
settingsFile.get(byte); settingsFile.get(byte);
@@ -67,13 +69,15 @@ void Settings::loadSettingsFromFile() {
// piece distribution // piece distribution
settingsFile.get(byte); settingsFile.get(byte);
//TODO this->menu.getPiecesList().setDistributionMode(DistributionMode(byte));
if (byte == 2) {
this->distributions.clear();
this->distributions.push_back(0);
for (int i = 1; i <= 15; i++) { for (int i = 1; i <= 15; i++) {
settingsFile.get(byte); settingsFile.get(byte);
//TODO this->distributions.push_back(byte);
}
} }
this->confirmDistribution();
// selected pieces // selected pieces
char pieceType; char pieceType;
@@ -114,8 +118,8 @@ void Settings::saveSettingsToFile() const {
byte = this->windowSizeMode; byte = this->windowSizeMode;
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
// master volume // start timer length
byte = this->masterVolume; byte = this->startTimerLength;
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
// gamemode // gamemode
@@ -131,9 +135,14 @@ void Settings::saveSettingsToFile() const {
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
// piece distribution // piece distribution
//TODO byte = this->menu.readPiecesList().getDistributionMode();
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
for (int i = 1; i <= 15; i++) {
byte = this->distributions.at(i);
settingsFile.write(&byte, 1);
}
// selected pieces // selected pieces
for (const auto& [type, value] : this->selectedPieces) { for (const auto& [type, value] : this->selectedPieces) {
byte = type; byte = type;
@@ -188,17 +197,17 @@ void Settings::changeVideoMode(sf::RenderWindow& window) const {
window.setPosition(sf::Vector2i((desktopSize.x / 2) - (windowSize.x / 2), (desktopSize.y / 2) - (windowSize.y / 2))); window.setPosition(sf::Vector2i((desktopSize.x / 2) - (windowSize.x / 2), (desktopSize.y / 2) - (windowSize.y / 2)));
} }
bool Settings::raiseMasterVolume() { bool Settings::lengthenStartTimer() {
if (this->masterVolume < 100) { if (this->startTimerLength < START_TIMER_MAX) {
this->masterVolume = std::min(this->masterVolume + 5, 100); this->startTimerLength++;
return true; return true;
} }
return false; return false;
} }
bool Settings::lowerMasterVolume() { bool Settings::shortenStartTimer() {
if (this->masterVolume > 0) { if (this->startTimerLength > 0) {
this->masterVolume = std::max(this->masterVolume - 5, 0); this->startTimerLength--;
return true; return true;
} }
return false; return false;
@@ -240,6 +249,32 @@ void Settings::confirmSelectedPieces() {
} }
} }
bool Settings::increaseDistribution(int size) {
if (size < 1 || size > MAXIMUM_PIECES_SIZE) return false;
if (this->distributions.at(size) < DISTRIBUTION_MAX) {
this->distributions.at(size)++;
return true;
}
return false;
}
bool Settings::decreaseDistribution(int size) {
if (size < 1 || size > MAXIMUM_PIECES_SIZE) return false;
if (this->distributions.at(size) > 0) {
this->distributions.at(size)--;
return true;
}
return false;
}
void Settings::confirmDistribution() {
for (int i = 1; i <= 15; i++) {
this->menu.getPiecesList().changeCustomDistribution(i, (double) 1 / (this->distributions.at(i) + 0.001));
}
}
Menu& Settings::getMenu() { Menu& Settings::getMenu() {
return this->menu; return this->menu;
} }
@@ -260,10 +295,14 @@ int Settings::getWindowSizeMultiplier() const {
return WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode]; return WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode];
} }
int Settings::getMasterVolume() const { int Settings::getStartTimerLength() const {
return this->masterVolume; return this->startTimerLength;
} }
const std::vector<std::pair<PiecesType, int>>& Settings::getSelectedPieces() const { const std::vector<std::pair<PiecesType, int>>& Settings::getSelectedPieces() const {
return this->selectedPieces; return this->selectedPieces;
} }
const std::vector<int>& Settings::getDistributions() const {
return this->distributions;
}

View File

@@ -24,9 +24,10 @@ class Settings {
std::vector<Keybinds> keybinds; std::vector<Keybinds> keybinds;
int chosenKeybinds; int chosenKeybinds;
int windowSizeMode; int windowSizeMode;
int masterVolume; int startTimerLength;
Gamemode gamemode; Gamemode gamemode;
std::vector<std::pair<PiecesType, int>> selectedPieces; std::vector<std::pair<PiecesType, int>> selectedPieces;
std::vector<int> distributions;
public: public:
Settings(); Settings();
@@ -47,9 +48,9 @@ class Settings {
void changeVideoMode(sf::RenderWindow& window) const; void changeVideoMode(sf::RenderWindow& window) const;
bool raiseMasterVolume(); bool lengthenStartTimer();
bool lowerMasterVolume(); bool shortenStartTimer();
void setGamemode(Gamemode gamemode); void setGamemode(Gamemode gamemode);
@@ -59,6 +60,12 @@ class Settings {
void confirmSelectedPieces(); void confirmSelectedPieces();
bool increaseDistribution(int size);
bool decreaseDistribution(int size);
void confirmDistribution();
Menu& getMenu(); Menu& getMenu();
Keybinds& getKeybinds(); Keybinds& getKeybinds();
@@ -69,7 +76,9 @@ class Settings {
int getWindowSizeMultiplier() const; int getWindowSizeMultiplier() const;
int getMasterVolume() const; int getStartTimerLength() const;
const std::vector<std::pair<PiecesType, int>>& getSelectedPieces() const; const std::vector<std::pair<PiecesType, int>>& getSelectedPieces() const;
const std::vector<int>& getDistributions() const;
}; };

View File

@@ -63,8 +63,8 @@ void resetSettingsFile() {
byte = 2; byte = 2;
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
// master volume // start timer length
byte = 50; byte = 2;
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
// gamemode // gamemode
@@ -80,8 +80,12 @@ void resetSettingsFile() {
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
// piece distribution // piece distribution
byte = 0; byte = DEFAULT;
settingsFile.write(&byte, 1); settingsFile.write(&byte, 1);
for (int i = 1; i <= 15; i++) {
byte = 1;
settingsFile.write(&byte, 1);
}
// selected pieces // selected pieces
byte = ALL_PIECES; byte = ALL_PIECES;

View File

@@ -91,7 +91,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
char positionByte; char positionByte;
for (int i = 0; i < polyominoSize; i++) { for (int i = 0; i < polyominoSize; i++) {
piecesFile.get(positionByte); piecesFile.get(positionByte);
int x = (positionByte & xMask) >> 4; int x = ((unsigned char) positionByte & xMask) >> 4;
int y = positionByte & yMask; int y = positionByte & yMask;
piecePositions.insert(Position{x, y}); piecePositions.insert(Position{x, y});
} }