From 6811d6bcb70b784808799909837d5c5665336af7 Mon Sep 17 00:00:00 2001
From: marie3003 <marie.viktoria.becker@gmail.com>
Date: Sun, 15 Dec 2024 12:45:36 +0100
Subject: [PATCH] game can now also be left when game has not started yet

---
 src/client/GameController.cpp             |  7 ++++++-
 src/client/GameController.h               |  1 +
 src/client/panels/MainGamePanelWizard.cpp | 14 ++++++++++---
 src/common/game_state/game_state.cpp      |  1 +
 src/common/game_state/player/player.cpp   | 25 +++++++++++++++++++++--
 src/common/game_state/player/player.h     | 16 +++++++++++++++
 6 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/src/client/GameController.cpp b/src/client/GameController.cpp
index 40522af..d040d52 100644
--- a/src/client/GameController.cpp
+++ b/src/client/GameController.cpp
@@ -171,6 +171,7 @@ void GameController::startGame() {
 }
 
 void GameController::leaveGame() {
+    _me->set_has_left_game(true);
     leave_game_request request = leave_game_request(GameController::_currentGameState->get_id(), GameController::_me->get_id(), _me->get_player_name());
     ClientNetworkManager::sendRequest(request);
 }
@@ -284,7 +285,6 @@ void GameController::showTrickOverMessage(const player* winner)
     dialog->ShowModal();
 }
 
-
 void GameController::showGameOverMessage() {
     std::string title = "Game Over!";
     std::string message = "Final score:\n";
@@ -327,3 +327,8 @@ void GameController::showGameOverMessage() {
         GameController::_gameWindow->Close();
     }
 }
+
+void GameController::closeGameWindow()
+{
+    GameController::_gameWindow->Close();
+}
diff --git a/src/client/GameController.h b/src/client/GameController.h
index 90310f6..4494b48 100644
--- a/src/client/GameController.h
+++ b/src/client/GameController.h
@@ -29,6 +29,7 @@ public:
     static void showNewRoundMessage(game_state* oldGameState, game_state* newGameState);
     static void showTrickOverMessage(const player* winner);
     static void showGameOverMessage();
+    static void closeGameWindow();
 
 private:
     static GameWindow* _gameWindow;
diff --git a/src/client/panels/MainGamePanelWizard.cpp b/src/client/panels/MainGamePanelWizard.cpp
index 03c6006..f9b2eac 100644
--- a/src/client/panels/MainGamePanelWizard.cpp
+++ b/src/client/panels/MainGamePanelWizard.cpp
@@ -98,10 +98,18 @@ void MainGamePanelWizard::buildGameState(game_state* gameState, player* me)
     std::vector<player*>::iterator it = std::find_if(players.begin(), players.end(), [me](const player* x) {
        return x->get_id() == me->get_id();
     });
+    std::cout << me->has_left_game() << std::endl;
     if (it < players.end()) {
         me = *it;
         myPosition = it - players.begin();
-    } else {
+    }
+    else if (me->has_left_game() == true)
+    {
+        //GameController::showError("Left Game", "You have left the game.");
+        GameController::closeGameWindow();
+        return;
+    }
+    else {
         GameController::showError("Game state error", "Could not find this player among players of server game.");
         return;
     }
@@ -176,7 +184,7 @@ void MainGamePanelWizard::buildScoreLeaveButtons(wxGridBagSizer *sizer, game_sta
     {
         wxButton *scoreBoardButton = new wxButton(panel, wxID_ANY, "ScoreBoard");
         scoreBoardButton->SetMinSize(wxSize(110, 43)); //90 , 35
-        sizer_vert->Add(scoreBoardButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3);
+        sizer_vert->Add(scoreBoardButton, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 3);
 
         scoreBoardButton->SetFont(magicalFont);
         scoreBoardButton->SetForegroundColour(wxColour(225, 225, 225)); // Set button text color
@@ -189,7 +197,7 @@ void MainGamePanelWizard::buildScoreLeaveButtons(wxGridBagSizer *sizer, game_sta
     }
         wxButton *leaveGameButton = new wxButton(panel, wxID_ANY, "Leave Game");
         leaveGameButton->SetMinSize(wxSize(110, 43));
-        sizer_vert->Add(leaveGameButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3);
+        sizer_vert->Add(leaveGameButton, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 3);
 
         leaveGameButton->SetFont(magicalFont);
         leaveGameButton->SetBackgroundColour(wxColour(50,0,51));  // Set background color to blue
diff --git a/src/common/game_state/game_state.cpp b/src/common/game_state/game_state.cpp
index 845f157..e2295a1 100644
--- a/src/common/game_state/game_state.cpp
+++ b/src/common/game_state/game_state.cpp
@@ -451,6 +451,7 @@ bool game_state::remove_player(player *player_ptr, std::string &err)
                 // reduce current_player_idx if the player who left had a lower index
                 _current_player_idx->set_value(_current_player_idx->get_value() - 1);
             }
+            player_ptr->set_has_left_game(true);
             _players.erase(_players.begin() + idx);
             return true;
         } else {
diff --git a/src/common/game_state/player/player.cpp b/src/common/game_state/player/player.cpp
index 2efef60..c33546f 100644
--- a/src/common/game_state/player/player.cpp
+++ b/src/common/game_state/player/player.cpp
@@ -8,20 +8,22 @@ player::player(const std::string& name) : unique_serializable() {
     this->_nof_predicted = new serializable_value<int>(-1);
     this->_nof_tricks = new serializable_value<int>(0);
     this->_scores = std::vector<serializable_value<int>*>(0);
+    this->_has_left_game = new serializable_value<bool>(false);
     this->_hand = new hand();
-
 }
 
 // deserialization constructor
 player::player(const std::string& id, serializable_value<std::string>* name,
                serializable_value<int>* nof_tricks,
                serializable_value<int>* nof_predicted,
-               const std::vector<serializable_value<int>*>& scores, hand *hand) :
+               const std::vector<serializable_value<int>*>& scores,
+               serializable_value<bool>* player_has_left_game, hand *hand) :
         unique_serializable(id),
         _player_name(name),
         _nof_tricks(nof_tricks),
         _nof_predicted(nof_predicted),
         _scores(scores),
+        _has_left_game(player_has_left_game),
         _hand(hand)
 { }
 
@@ -32,11 +34,13 @@ player::~player() {
         delete _player_name;
         delete _nof_predicted;
         delete _nof_tricks;
+        delete _has_left_game;
 
         _hand = nullptr;
         _player_name = nullptr;
         _nof_predicted = nullptr;
         _nof_tricks = nullptr;
+        _has_left_game = nullptr;
     }
 }
 
@@ -50,6 +54,7 @@ player::player(const std::string& id, const std::string& name) :
     this->_hand = new hand();
     this->_nof_predicted = new serializable_value<int>(-1);
     this->_nof_tricks = new serializable_value<int>(0);
+    this->_has_left_game = new serializable_value<bool>(false);
 }
 
 // server accessors
@@ -87,6 +92,16 @@ void player::set_nof_tricks(const int nof_tricks) const
     _nof_tricks->set_value(nof_tricks);
 }
 
+bool player::has_left_game() const
+{
+    return _has_left_game->get_value();
+}
+
+void player::set_has_left_game(bool has_left_game)
+{
+    _has_left_game->set_value(has_left_game);
+}
+
 
 // getter and setter for number of predicted tricks
 int player::get_nof_predicted() const noexcept
@@ -175,6 +190,10 @@ void player::write_into_json(rapidjson::Value& json, rapidjson::Document::Alloca
 
     json.AddMember("scores", vector_utils::serialize_vector(_scores, allocator), allocator);
 
+    rapidjson::Value has_left_game_val(rapidjson::kObjectType);
+    _has_left_game->write_into_json(has_left_game_val, allocator);
+    json.AddMember("has_left_game", has_left_game_val, allocator);
+
     rapidjson::Value hand_val(rapidjson::kObjectType);
     _hand->write_into_json(hand_val, allocator);
     json.AddMember("hand", hand_val, allocator);
@@ -186,6 +205,7 @@ player* player::from_json(const rapidjson::Value &json) {
         && json.HasMember("nof_tricks")
         && json.HasMember("player_name")
         && json.HasMember("scores")
+        && json.HasMember("has_left_game")
         && json.HasMember("hand"))
     {
         std::vector<serializable_value<int>*> deserialized_scores;
@@ -198,6 +218,7 @@ player* player::from_json(const rapidjson::Value &json) {
                 serializable_value<int>::from_json(json["nof_tricks"].GetObject()),
                 serializable_value<int>::from_json(json["nof_predicted"].GetObject()),
                 deserialized_scores,
+                serializable_value<bool>::from_json(json["has_left_game"].GetObject()),
                 hand::from_json(json["hand"].GetObject()));
     } else {
         throw WizardException("Failed to deserialize player from json. Required json entries were missing.");
diff --git a/src/common/game_state/player/player.h b/src/common/game_state/player/player.h
index 1eb41bd..3a1f159 100644
--- a/src/common/game_state/player/player.h
+++ b/src/common/game_state/player/player.h
@@ -22,6 +22,7 @@ private:
     serializable_value<int>* _nof_tricks;           ///< The number of tricks won in the current round.
     serializable_value<int>* _nof_predicted;        ///< The number of predicted tricks in the current round.
     std::vector<serializable_value<int>*> _scores;  ///< The scores of the player (total game score, current and past ones).
+    serializable_value<bool>* _has_left_game;       ///< Boolean whether player has left the game.
     hand* _hand;                                    ///< The player's hand holding the player's cards.
 
 #ifdef WIZARD_SERVER
@@ -35,6 +36,7 @@ private:
      * @param nof_tricks The number of tricks won by the player in the current round.
      * @param nof_predicted The number of tricks predicted to be won by the player in the current round.
      * @param scores The player's scores.
+     * @param has_left_game Boolean whether player has left the game.
      * @param hand The player's hand.
      */
     player(const std::string& id,
@@ -42,6 +44,7 @@ private:
            serializable_value<int>* nof_tricks,
            serializable_value<int>* nof_predicted,
            const std::vector<serializable_value<int>*>& scores,
+           serializable_value<bool>* has_left_game,
            hand* hand);
 
 public:
@@ -106,6 +109,18 @@ public:
      */
     void set_nof_tricks(int nof_tricks) const;
 
+    /**
+     * @brief State whether player has left the game.
+     * @return Boolean stating whether player has left the game.
+     */
+    [[nodiscard]] bool has_left_game() const;
+
+    /**
+     * @brief Sets the players game to left when he leaves the game
+     * @param has_left_game Boolean whether player has left game
+     */
+    void set_has_left_game(bool has_left_game);
+
     /**
      * @brief Gets the number of tricks predicted to be won by the player in the current round.
      * @return The number of tricks predicted to be won by the player in the current round.
@@ -127,6 +142,7 @@ public:
      */
     [[nodiscard]] unsigned int get_nof_cards() const noexcept;
 
+
     /**
      * @brief Gets the player's hand.
      * @return The player's hand.
-- 
GitLab