-
LUCA WOLFART authoredLUCA WOLFART authored
MainGamePanel.cpp 16.56 KiB
#include "MainGamePanel.hpp"
#include "../uiElements/ImagePanel.hpp"
#include "../GameController.hpp"
#include <map>
MainGamePanel::MainGamePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(960, 680)) {
}
void MainGamePanel::buildGameState(game_state* gameState, player* me) {
// remove any existing UI
this->DestroyChildren();
std::vector<player*> players = gameState->get_players();
int numberOfPlayers = players.size();
// find our own player object in the list of players
int myPosition = -1;
std::vector<player*>::iterator it = std::find_if(players.begin(), players.end(), [me](const player* x) {
return x->get_id() == me->get_id();
});
if (it < players.end()) {
me = *it;
myPosition = it - players.begin();
} else {
GameController::showError("Game state error", "Could not find this player among players of server game.");
return;
}
double anglePerPlayer = MainGamePanel::twoPi / (double) numberOfPlayers;
// show all other players
for(int i = 1; i < numberOfPlayers; i++) {
// get player at i-th position after myself
player* otherPlayer = players.at((myPosition + i) % numberOfPlayers);
double playerAngle = (double) i * anglePerPlayer;
int side = (2 * i) - numberOfPlayers; // side < 0 => right, side == 0 => center, side > 0 => left
this->buildOthers(gameState, otherPlayer, playerAngle, side);
// this->buildOtherPlayerLabels(gameState, otherPlayer, playerAngle, side);
}
// show our own player
this->buildThisPlayer(gameState, me);
// show the number of rounds
this->buildRoundCounter(gameState);
// update layout
this->Layout();
}
// with open hands
void MainGamePanel::buildOthers(game_state* gameState, player* otherPlayer, double playerAngle, int side) {
// IDONTKNOWMAN
std::string err;//deugging helper...
long textAlignment = wxALIGN_CENTER;
int labelOffsetX = 0;
if (side < 0) { // right side
textAlignment = wxALIGN_LEFT;
labelOffsetX = 85;
} else if(side > 0) { // left side
textAlignment = wxALIGN_RIGHT;
labelOffsetX = -65;
}
// define the ellipse which represents the virtual player circle
double verticalRadius_hand = MainGamePanel::otherPlayerHandDistanceFromCenter;
double verticalRadius_label = MainGamePanel::otherPlayerLabelDistanceFromCenter;
double verticalRadius_bet = MainGamePanel::otherPlayerBetDistanceFromCenter;
// get this player's position on that ellipse
wxPoint handPosition = MainGamePanel::tableCenter;
wxPoint labelPosition = MainGamePanel::tableCenter;
wxPoint betPosition = MainGamePanel::tableCenter;
handPosition += this->getPointOnEllipse(verticalRadius_hand*1.2, verticalRadius_hand, playerAngle);
labelPosition += this->getPointOnEllipse(verticalRadius_label*1.2, verticalRadius_label, playerAngle);
betPosition += this->getPointOnEllipse(verticalRadius_bet*1.2, verticalRadius_bet, playerAngle);
labelPosition += wxSize(labelOffsetX, 0);
// NAME
this->buildStaticText(
otherPlayer->get_player_name(),
labelPosition + wxSize(-100, -36),
wxSize(200, 18),
textAlignment,
true
);
bool player_is_broke = otherPlayer->get_money() < gameState->_min_bet;
if(!gameState->is_started()) {
// STATUS
this->buildStaticText(
"waiting for game to start...",
labelPosition + wxSize(-100, -18),
wxSize(200, 18),
textAlignment
);
}
else if(player_is_broke){
// STATUS
this->buildStaticText(
"Status: LOST GAME",
labelPosition + wxSize(-100, -18),
wxSize(200, 18),
textAlignment
);
}
else{
// STATUS
if(otherPlayer->get_hand()->is_over_21(err)){
this->buildStaticText(
"Status: LOST ROUND",
labelPosition + wxSize(-100, -18),
wxSize(200, 18),
textAlignment
);
}
else if(gameState->get_current_player() == otherPlayer)
{
this->buildStaticText(
"Status: Playing",
labelPosition + wxSize(-100, -18),
wxSize(200, 18),
textAlignment
);
}
else
{
this->buildStaticText(
"Status: Waiting for turn",
labelPosition + wxSize(-100, -18),
wxSize(200, 18),
textAlignment
);
}
// MONEY
this->buildStaticText(
"Money in depot:" + std::to_string(otherPlayer->get_money()),
labelPosition + wxSize(-100, 0),
wxSize(200, 18),
textAlignment
);
// BET
this->buildStaticText(
"Money betted:" + std::to_string(otherPlayer->get_bet_size()),
labelPosition + wxSize(-100, 18),
wxSize(200, 18),
textAlignment
);
// ========= add player's HAND IMAGE=================================
int numberOfCards = otherPlayer->get_hand()->get_nof_cards();
std::string cardImage;
wxSize boundsOfRotatedHand = this->getBoundsOfRotatedSquare(MainGamePanel::otherPlayerHandSize, playerAngle);
wxSize weirdSize(80, 80);
double cAngle = playerAngle + MainGamePanel::twoPi/4;
int cDist = MainGamePanel::otherPlayerHandSize;
wxSize card_dist((int)(sin(cAngle)*cDist), (int)(cos(cAngle) * cDist));
handPosition -= 2*card_dist;
for(int i = 0; i<numberOfCards;++i){
card *handCard = otherPlayer->get_hand()->get_cards().at(i);
cardImage = getPngFileName(handCard->get_value(), handCard->get_suit());
new ImagePanel(this, cardImage, wxBITMAP_TYPE_ANY, handPosition, weirdSize, playerAngle);
handPosition += card_dist*0.85;
}
// add player's BET IMAGE================================= refine??
int bet=otherPlayer->get_bet_size();
if(bet<=10){
new ImagePanel(this, "assets/png-chips/blue.png", wxBITMAP_TYPE_ANY, betPosition, weirdSize, playerAngle);
}
else if(bet<=20){
new ImagePanel(this, "assets/png-chips/red.png", wxBITMAP_TYPE_ANY, betPosition, weirdSize, playerAngle);
}
else{
new ImagePanel(this, "assets/png-chips/black.png", wxBITMAP_TYPE_ANY, betPosition, weirdSize, playerAngle);
}
}
}
void MainGamePanel::buildThisPlayer(game_state* gameState, player* me) {
// Setup two nested box sizers, in order to align our player's UI to the bottom center
wxBoxSizer* outerLayout = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(outerLayout);
wxBoxSizer* innerLayout = new wxBoxSizer(wxVERTICAL);
outerLayout->Add(innerLayout, 1, wxALIGN_BOTTOM);
// Show the label with our player name
wxStaticText* playerName = buildStaticText(
me->get_player_name(),
wxDefaultPosition,
wxSize(200, 18),
wxALIGN_CENTER,
true
);
innerLayout->Add(playerName, 0, wxALIGN_CENTER);
// if the game has not yet started we say so
if(!gameState->is_started()) {
wxStaticText* playerPoints = buildStaticText(
"waiting for game to start...",
wxDefaultPosition,
wxSize(200, 18),
wxALIGN_CENTER
);
innerLayout->Add(playerPoints, 0, wxALIGN_CENTER | wxBOTTOM, 8);
// show button that allows our player to start the game
wxButton* startGameButton = new wxButton(this, wxID_ANY, "Start Game!", wxDefaultPosition, wxSize(160, 64));
startGameButton->Bind(wxEVT_BUTTON, [](wxCommandEvent& event) {
GameController::startGame();
});
innerLayout->Add(startGameButton, 0, wxALIGN_CENTER | wxBOTTOM, 8);
} else {
// This is taken care of in the betpanel
// wxStaticText *playerPoints = buildStaticText(
// "You currently have " + std::to_string(me->get_money()) + "$",
// wxDefaultPosition,
// wxSize(200, 18),
// wxALIGN_CENTER
// );
// innerLayout->Add(playerPoints, 0, wxALIGN_CENTER | wxBOTTOM, 8);
// if our player already played, we display that as status
// TODO from has_folded make has_played
if (me->has_finished_turn()) {
wxStaticText *playerStatus = buildStaticText(
"You finished your turn",
wxDefaultPosition,
wxSize(200, 32),
wxALIGN_CENTER
);
innerLayout->Add(playerStatus, 0, wxALIGN_CENTER | wxBOTTOM, 8);
}
// TODO It's our turn, display Hit and Stand button
if (gameState->get_current_player() == me) {
wxButton *hitButton = new wxButton(this, wxID_ANY, "Hit", wxDefaultPosition, wxSize(80, 32));
hitButton->Bind(wxEVT_BUTTON, [](wxCommandEvent& event) {
GameController::hit();
});
innerLayout->Add(hitButton, 0, wxALIGN_CENTER | wxBOTTOM, 8);
wxButton *standButton = new wxButton(this, wxID_ANY, "Stand", wxDefaultPosition, wxSize(80, 32));
standButton->Bind(wxEVT_BUTTON, [](wxCommandEvent& event) {
GameController::stand();
});
innerLayout->Add(standButton, 0, wxALIGN_CENTER | wxBOTTOM, 8);
// if it's not our turn, display "waiting..."
} else {
wxStaticText *playerStatus = buildStaticText(
"waiting...",
wxDefaultPosition,
wxSize(200, 32),
wxALIGN_CENTER
);
innerLayout->Add(playerStatus, 0, wxALIGN_CENTER | wxBOTTOM, 8);
}
// display our player's hand, if we have cards
int numberOfCards = me->get_hand()->get_nof_cards();
if (numberOfCards > 0) {
// create horizontal layout for the individual hand cards of our player
wxBoxSizer *handLayout = new wxBoxSizer(wxHORIZONTAL);
innerLayout->Add(handLayout, 0, wxALIGN_CENTER);
wxSize scaledCardSize = MainGamePanel::cardSize;
// Adjust card size (if the number of cards does not fit on the screen)
if (numberOfCards * (MainGamePanel::cardSize.GetWidth() + 8) >
MainGamePanel::panelSize.GetWidth()) { // 8 -> 4 pixel padding on both sides
int scaledCardWidth = (MainGamePanel::panelSize.GetWidth() / numberOfCards) - 8;
double cardAspectRatio =
(double) MainGamePanel::cardSize.GetHeight() / (double) MainGamePanel::cardSize.GetWidth();
int scaledCardHeight = (int) ((double) scaledCardWidth * cardAspectRatio);
scaledCardSize = wxSize(scaledCardWidth, scaledCardHeight);
}
// Show all cards of this player
for (int i = 0; i < me->get_hand()->get_cards().size(); i++) {
card *handCard = me->get_hand()->get_cards().at(i);
std::string cardFile = getPngFileName(handCard->get_value(), handCard->get_suit());
ImagePanel *cardButton = new ImagePanel(this, cardFile, wxBITMAP_TYPE_ANY, wxDefaultPosition, scaledCardSize);
}
}
}
}
void MainGamePanel::buildRoundCounter(game_state* gameState){
if(gameState->is_started() && gameState->get_current_player() != nullptr) {
// gameState->get_current_player()->get_player_name() is a placeholder, we need a roundnr variable
std::string roundindicator = "We are in round: " + gameState->get_current_player()->get_player_name();
//wxPoint turnIndicatorPosition = MainGamePanel::tableCenter + MainGamePanel::turnIndicatorOffset;
wxPoint roundIndicatorPosition = MainGamePanel::tableCenter + MainGamePanel::roundIndicatorOffset;
this->buildStaticText(
roundindicator,
roundIndicatorPosition,
wxSize(200, 18),
wxALIGN_CENTER,
true
);
}
}
//void buildShoe(){
// shoeFile = "assets/misc/shoe";
// wxPoint shoePosition = MainGamePanel::tableCenter + MainGamePanel::shoeOffset;
// ImagePanel *shoe = new ImagePanel(this, shoeFile, wxBITMAP_TYPE_ANY,
// shoePosition, scaledCardSize, MainGamePanel::cardSize);
//}
void MainGamePanel::buildDealer(game_state* gameState){
// Setup two nested box sizers, in order to align our player's UI to the bottom center
wxBoxSizer* outerLayout = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(outerLayout);
wxBoxSizer* innerLayout = new wxBoxSizer(wxVERTICAL);
outerLayout->Add(innerLayout, 1, wxALIGN_CENTER);
wxPoint offset(80, 0);
// TODO the call in the line below was compute_dealers_hand()
// which should return the hand the dealer will have in the end
// but get_dealers_hand returns only the current hand of the dealer
hand* hand_dealers_hand = gameState->get_dealers_hand();
std::vector<card*> dealers_cards = hand_dealers_hand->get_cards();
std::vector<wxPoint> offsets(dealers_cards.size());
for(unsigned i = 0; i < dealers_cards.size(); ++i){
offsets[i] = i * offset;
}
std::string backside = "assets/png-cards/backside.png";
std::string left_frontside = getPngFileName(dealers_cards[0]->get_value(), dealers_cards[0]->get_suit());
std::string right_frontside = getPngFileName(dealers_cards[1]->get_value(), dealers_cards[1]->get_suit());
std::vector<std::string> dealer_cards_file_names(dealers_cards.size());
std::transform(dealers_cards.begin(), dealers_cards.end(),
dealer_cards_file_names.begin(), [this](card* c) -> std::string {
return this->getPngFileName(c->get_value(), c->get_suit());
});
bool first_part = gameState-> everyone_finished();
wxBoxSizer *handLayout = new wxBoxSizer(wxHORIZONTAL);
innerLayout->Add(handLayout, 0, wxALIGN_CENTER);
if(first_part){
wxPoint leftCardPosition = MainGamePanel::tableCenter + MainGamePanel::leftDealerCardOffset;
wxPoint rightCardPosition = MainGamePanel::tableCenter + MainGamePanel::rightDealerCardOffset;
ImagePanel* rightDealerCard = new ImagePanel(this, backside, wxBITMAP_TYPE_ANY, rightCardPosition, MainGamePanel::cardSize);
ImagePanel* leftDealerCard = new ImagePanel(this, getPngFileName(dealers_cards[0]->get_value(), dealers_cards[0]->get_suit()), wxBITMAP_TYPE_ANY, leftCardPosition, MainGamePanel::cardSize);
}
else{
for(unsigned i = 0; i < dealers_cards.size(); ++i){
ImagePanel *image_panel = new ImagePanel(this, dealer_cards_file_names[i], wxBITMAP_TYPE_ANY, offsets[i], MainGamePanel::cardSize);
handLayout->Add(image_panel, 0, wxLEFT | wxRIGHT, 4);
}
}
}
wxStaticText* MainGamePanel::buildStaticText(std::string content, wxPoint position, wxSize size, long textAlignment, bool bold) {
wxStaticText* staticText = new wxStaticText(this, wxID_ANY, content, position, size, textAlignment);
if(bold) {
wxFont font = staticText->GetFont();
font.SetWeight(wxFONTWEIGHT_BOLD);
staticText->SetFont(font);
}
return staticText;
}
wxSize MainGamePanel::getBoundsOfRotatedSquare(double edgeLength, double rotationAngle) {
double newEdgeLength = this->getEdgeLengthOfRotatedSquare(edgeLength, rotationAngle);
return wxSize(newEdgeLength, newEdgeLength);
}
double MainGamePanel::getEdgeLengthOfRotatedSquare(double originalEdgeLength, double rotationAngle) {
return originalEdgeLength * (abs(sin(rotationAngle)) + abs(cos(rotationAngle)));
}
wxPoint MainGamePanel::getPointOnEllipse(double horizontalRadius, double verticalRadius, double angle) {
return wxPoint((int) (sin(angle) * horizontalRadius), (int) (cos(angle) * verticalRadius));
}
std::string MainGamePanel::getPngFileName(int value, int suit){
std::map<int, std::string> value_map {{11, "jack"}, {12, "queen"}, {1, "ace"}};
std::map<int, std::string> suit_map{
{0, "spades"}, {1, "clubs"}, {2, "diamonds"}, {3, "hearts"}};
std::string path = "assets/png-cards/";
if (value > 1 && value <= 10) {
return path + std::to_string(value) + "_of_" + suit_map[suit] + ".png";
}
else{
return path + value_map[value] + "_of_" + suit_map[suit] + ".png";
}
}