From 439d2ce868f0d6eda8cc7b400db5c353ed8d6ac8 Mon Sep 17 00:00:00 2001
From: Tim Schubert <tim.schubert@tu-bs.de>
Date: Fri, 29 Jan 2016 01:06:09 +0100
Subject: [PATCH] Performance improvements when rendering textures. Found an
 fixed a bug when attacking remote fields that belong to the default player.

---
 src/Bob.cpp      | 120 ++++++++++++++++++++++++++++++++++-------------
 src/Bob.hpp      |   3 --
 src/Events.cpp   |   4 +-
 src/Events.hpp   |   3 +-
 src/Gameplay.cpp |  96 ++++++++++++++++++++++++++++---------
 src/Gameplay.hpp |  27 +++++++++--
 src/Gui.cpp      |  42 ++++++++++++++---
 src/Gui.hpp      |  16 +++++--
 8 files changed, 236 insertions(+), 75 deletions(-)

diff --git a/src/Bob.cpp b/src/Bob.cpp
index 8003b6e..b576939 100644
--- a/src/Bob.cpp
+++ b/src/Bob.cpp
@@ -5,6 +5,7 @@ void Game::handle_event(SDL_Event *event)
 {
     static SDL_Point window_size;
     std::string input;
+    std::ostringstream prompt;
     switch (event->type)
     {
         case (SDL_QUIT):
@@ -44,7 +45,11 @@ void Game::handle_event(SDL_Event *event)
             {
                 this->grid->handle_event(event);
                 this->field_box->handle_event(event);
-                this->upgrade_box->handle_event(event);
+                if (this->started)
+                {
+                    this->upgrade_box->handle_event(event);
+
+                }
             }
             break;
         case SDL_KEYDOWN:
@@ -79,13 +84,10 @@ void Game::handle_event(SDL_Event *event)
                     if (this->text_input_box->get_active())
                     {
                         this->text_input_box->stop();
-                        this->test_box->set_visible(false);
                     }
                     else
                     {
                         this->text_input_box->start();
-                        this->test_box->set_visible(true);
-
                     }
                     break;
                 case SDLK_RETURN:
@@ -133,16 +135,47 @@ void Game::handle_event(SDL_Event *event)
             {
                 this->text_input_box->handle_event(event);
             }
+            break;
         default:
-            if (event->type == BOB_MARKERUPDATE
-                || event->type == BOB_NEXTROUNDEVENT
-                || event->type == BOB_FIELDUPDATEEVENT
-                || event->type == BOB_FIELDSELECTEDEVENT
+            if ((event->type == BOB_MARKERUPDATE || event->type == BOB_FIELDSELECTEDEVENT)
+                && !this->text_input_box->get_active())
+            {
+                this->grid->handle_event(event);
+                this->field_box->handle_event(event);
+                if (this->started)
+                {
+                    this->upgrade_box->handle_event(event);
+                }
+                for (Player *p : this->players)
+                {
+                    p->handle_event(event);
+                }
+            }
+            if (event->type == BOB_NEXTROUNDEVENT || event->type == BOB_FIELDUPDATEEVENT
                 || event->type == BOB_FIELDUPGRADEVENT)
             {
                 this->grid->handle_event(event);
                 this->field_box->handle_event(event);
                 this->upgrade_box->handle_event(event);
+                for (Player *p : this->players)
+                {
+                    p->handle_event(event);
+                }
+            }
+            else if (event->type == BOB_PLAYERADDED && !this->started)
+            {
+                Player *added = (Player *) event->user.data1;
+                if (event->user.code == 0)
+                {
+                    this->players.push_back(added);
+                    prompt << "Added Player: " << added->get_name();
+                }
+                else
+                {
+                    prompt << "Failed to add Player: " << added->get_name();
+                    delete added;
+                }
+                this->text_input_box->prompt(prompt.str());
             }
             break;
     }
@@ -160,51 +193,73 @@ void Game::command(std::string input)
     {
         prompt << "This is a test!";
     }
-    else if (input == "next" && this->started)
+    else if (input == "debug")
     {
-        Player *last_player = Player::current_player;
-        this->turn = this->turn + 1;
-        if (this->turn == players.size())
+        //this->debug->toggle();
+    }
+    else if (input == "next")
+    {
+        if (this->started)
         {
-            this->turn = 0;
-            trigger_event(BOB_NEXTROUNDEVENT, 0, (void *) last_player, (void *) Player::current_player);
+            Player *last_player = Player::current_player;
+            this->turn = (this->turn + 1) % players.size();
+            Player::current_player = players[turn];
+            if (this->turn == 0)
+            {
+                trigger_event(BOB_NEXTROUNDEVENT, 0, (void *) last_player, (void *) Player::current_player);
+            }
+            else
+            {
+                trigger_event(BOB_NEXTTURNEVENT, 0, (void *) last_player, (void *) Player::current_player);
+            }
+            prompt << "Next player is: " << (Player::current_player)->get_name();
         }
         else
         {
-            trigger_event(BOB_NEXTTURNEVENT, 0, (void *) last_player, (void *) Player::current_player);
+            prompt << "The game was not started yet!";
         }
-        Player::current_player = players[turn];
-        prompt << "Next player is: " << (Player::current_player)->get_name();
     }
     else if (input == "surrender")
     {
         //Player::current_player->surrender();
     }
-    else if (!this->started && input.substr(0, 10) == "add player")
+    else if (input.substr(0, 10) == "add player")
     {
-        Player *added = new Player(input.substr(11, std::string::npos));
-        if (!this->grid->place(added))
+        if (!this->started)
         {
-            prompt << "Failed to add player:" << added->get_name();
-            delete added;
+            Player *added = new Player(input.substr(11, std::string::npos));
+            this->grid->set_selecting(true, added);
+            prompt << "Select a place, please!";
+            this->text_input_box->stop();
         }
         else
         {
-            this->players.push_back(added);
-            prompt << "Added player " << added->get_name();
+            prompt << "The game has already been started. No additional player will be accepted for this game. ";
         }
     }
-    else if (input == "start" && !this->started)
+    else if (input == "start")
     {
-        this->start();
-        this->started = true;
-        prompt << "Started the game.";
+        if (this->players.size() < 2)
+        {
+            prompt << "Please add at least one player, before starting the game.";
+        }
+        else if (!this->started)
+        {
+            this->start();
+            this->started = true;
+            prompt << "Started the game.";
+        }
+        else
+        {
+            prompt << "The game has already been started!";
+        }
     }
     this->text_input_box->prompt(prompt.str());
 }
 
 void Game::start()
 {
+    this->players.erase(players.begin()); // remove default player from vector
     std::random_shuffle(players.begin(), players.end());
     this->turn = 0;
     Player::current_player = players[0];
@@ -222,14 +277,16 @@ int Game::game_loop()
         {
             this->move_timer->reset_timer();
             SDL_Point move_by = {(this->move[1] - this->move[3]) * 20, (this->move[0] - this->move[2]) * 20};
-            this->grid->move(move_by);
+            if (move[0] || move[1] || move[2] || move[3])
+            {
+                this->grid->move(move_by);
+            }
         }
         if (this->frame_timer->get_timer() > 255)
         {
             fps = frame_counter / (this->frame_timer->reset_timer() / 1000.0);
-            frame_counter = 0;
             std::cout << fps << std::endl;
-            this->test_box->load_text(std::to_string(fps));
+            frame_counter = 0;
         }
         SDL_Event event;
         while (SDL_PollEvent(&event))
@@ -250,7 +307,6 @@ void Game::render()
         this->renderer->set_draw_color({0x0, 0x0, 0x0, 0xff});
         this->renderer->clear();
         this->grid->render(this->renderer);
-        this->test_box->render(this->renderer);
         this->field_box->render(this->renderer);
         this->upgrade_box->render(this->renderer);
         this->text_input_box->render(this->renderer);
diff --git a/src/Bob.hpp b/src/Bob.hpp
index 528da88..4171f3e 100644
--- a/src/Bob.hpp
+++ b/src/Bob.hpp
@@ -44,7 +44,6 @@ public:
             FieldMeta *center = this->grid->get_field({0, 0, 0});
             this->field_box = new FieldBox(this->renderer, {0, 0, 100, 100}, fg, this->font, center);
             this->upgrade_box = new UpgradeBox(this->renderer, {0, 0, 100, 20}, fg, this->font, center);
-            this->test_box = new TextBox(this->renderer, {0, 0, 100, 20}, fg, this->font);
             this->next_turn_button = new NextTurnButtonBox(this->renderer,
                                                            {window_size.x - 100, window_size.y - 100, 1, 1}, fg,
                                                            this->font, &(this->players));
@@ -70,7 +69,6 @@ public:
         }
         delete text_input_box;
         delete this->next_turn_button;
-        delete this->test_box;
         delete this->upgrade_box;
         delete this->field_box;
         delete this->move_timer;
@@ -99,7 +97,6 @@ private:
     NextTurnButtonBox *next_turn_button;
     UpgradeBox *upgrade_box;
     FieldBox *field_box;
-    TextBox *test_box;
     TTF_Font *font;
     Window *window;
     Renderer *renderer;
diff --git a/src/Events.cpp b/src/Events.cpp
index 90de0c5..b8ba145 100644
--- a/src/Events.cpp
+++ b/src/Events.cpp
@@ -6,8 +6,8 @@ const Uint32 BOB_FIELDUPDATEEVENT = register_events(1);
 const Uint32 BOB_FIELDSELECTEDEVENT = register_events(1);
 const Uint32 BOB_FIELDUPGRADEVENT = register_events(1);
 const Uint32 BOB_NEXTTURNEVENT = register_events(1);
-const Uint32 BOB_ATTACKEVENTS = register_events(1);
-
+const Uint32 BOB_ATTACKEVENT = register_events(1);
+const Uint32 BOB_PLAYERADDED = register_events(1);
 
 bool Timer::MOUSE_LOCKED = false;
 
diff --git a/src/Events.hpp b/src/Events.hpp
index 340394d..2d68040 100644
--- a/src/Events.hpp
+++ b/src/Events.hpp
@@ -13,7 +13,8 @@ extern const Uint32 BOB_FIELDUPDATEEVENT;
 extern const Uint32 BOB_FIELDSELECTEDEVENT;
 extern const Uint32 BOB_FIELDUPGRADEVENT;
 extern const Uint32 BOB_NEXTTURNEVENT;
-extern const Uint32 BOB_ATTACKEVENTS;
+extern const Uint32 BOB_ATTACKEVENT;
+extern const Uint32 BOB_PLAYERADDED;
 #endif
 
 Uint32 register_events(Uint32 n);
diff --git a/src/Gameplay.cpp b/src/Gameplay.cpp
index fcf70e8..6e6e91c 100644
--- a/src/Gameplay.cpp
+++ b/src/Gameplay.cpp
@@ -160,6 +160,7 @@ void FieldMeta::regenerate_resources()
     if (this->upgrades[Regeneration_3])
         this->resources *= 2;
     trigger_event(BOB_FIELDUPDATEEVENT, 0, (void *) this, nullptr);
+    this->changed = true;
 }
 
 Resource HexagonGrid::get_resources_of_cluster(Cluster *cluster)
@@ -256,15 +257,10 @@ Resource HexagonGrid::consume_resources_of_cluster(Cluster *cluster, Resource co
 
 bool Player::fight(FieldMeta *field)
 {
-    if (*this == *(field->get_owner())) // attacked field outside of the map or friendly fire
+    if (*this == *(field->get_owner())) // friendly fire
     {
         return false;
     }
-    if (field->get_owner()->get_id().is_nil()) // still to be had
-    {
-        field->set_owner(this);
-        return true;
-    }
 
     // defending player's defense against attacking player's offense
     int power_level = field->get_defense(); // it's over 9000
@@ -284,8 +280,10 @@ bool Player::fight(FieldMeta *field)
     if (power_level < 0) // attacking player has won
     {
         field->set_owner(this);
+        this->fought = true;
         return true;
     }
+    this->fought = true;
     return false;
 }
 
@@ -294,10 +292,10 @@ void FieldMeta::handle_event(const SDL_Event *event)
     if (event->type == BOB_NEXTROUNDEVENT)
     {
         this->regenerate_resources();
+        this->changed = true;
     }
 }
 
-
 void FieldMeta::load(SDL_Renderer *renderer, Layout *layout)
 {
     Point precise_location = this->field.field_to_point(layout);
@@ -416,7 +414,6 @@ void HexagonGrid::render(Renderer *renderer)
         this->load();
         this->changed = false;
     }
-    //this->load();
     renderer->copy(this->texture, &(this->layout->box), &(this->layout->box));
 }
 
@@ -463,8 +460,8 @@ void HexagonGrid::handle_event(SDL_Event *event)
                 p.x = (int) marker_pos.x;
                 p.y = (int) marker_pos.y;
                 this->move(mouse - p);
-                this->changed = true;
             }
+            this->update_marker();
             break;
         case SDL_MOUSEBUTTONDOWN:
             switch (event->button.button)
@@ -474,25 +471,42 @@ void HexagonGrid::handle_event(SDL_Event *event)
                     break;
                 case SDL_BUTTON_RIGHT:
                     trigger_event(BOB_FIELDSELECTEDEVENT, 0, (void *) this->marker, nullptr);
+                    this->changed = true;
                     break;
                 case SDL_BUTTON_LEFT:
-                    owner = this->marker->get_owner();
-                    if (*owner == *(Player::current_player))
+                    if (this->selecting)
                     {
-                        if (this->first_attack != nullptr)
+                        if (this->place(this->selecting_player, this->marker))
                         {
-                            this->first_attack->set_fighting(false);
+                            trigger_event(BOB_PLAYERADDED, 0, (void *) this->selecting_player, nullptr);
                         }
-                        this->first_attack = this->marker;
-                        this->first_attack->set_fighting(true);
+                        else
+                        {
+                            trigger_event(BOB_PLAYERADDED, 1, (void *) this->selecting_player, nullptr);
+                        }
+                        this->selecting = false;
                     }
-                    else if (this->first_attack != nullptr)
+                    else
                     {
-                        attacking = this->first_attack->get_owner();
-                        attacking->fight(this->marker);
-                        this->first_attack->set_fighting(false);
-                        this->first_attack = nullptr;
+                        owner = this->marker->get_owner();
+                        if (*owner == *(Player::current_player))
+                        {
+                            if (this->first_attack != nullptr)
+                            {
+                                this->first_attack->set_fighting(false);
+                            }
+                            this->first_attack = this->marker;
+                            this->first_attack->set_fighting(true);
+                        }
+                        else if (this->first_attack != nullptr)
+                        {
+                            attacking = this->first_attack->get_owner();
+                            attacking->fight(this->marker);
+                            this->first_attack->set_fighting(false);
+                            this->first_attack = nullptr;
+                        }
                     }
+                    changed = true;
                     break;
                 default:
                     break;
@@ -586,6 +600,7 @@ void HexagonGrid::update_dimensions(SDL_Point dimensions)
     this->layout->origin = {dimensions.x / 2, dimensions.y / 2};
     this->layout->box.w = dimensions.x;
     this->layout->box.h = dimensions.y;
+    this->changed = true;
 }
 
 Point HexagonGrid::field_to_point(FieldMeta *field)
@@ -599,7 +614,44 @@ bool inside_target(const SDL_Rect *target, const SDL_Point *position)
            target->y + target->h > position->y;
 }
 
-bool HexagonGrid::place(Player *player)
+bool HexagonGrid::place(Player *player, FieldMeta *center)
 {
-    return true;
+    std::vector<FieldMeta *> selected;
+    selected.push_back(center);
+    for (Uint8 i = 0; i < 6; i++)
+    {
+        FieldMeta *neighbor = center->get_neighbor(i);
+        if (neighbor->get_owner()->get_id() == boost::uuids::nil_uuid())
+        {
+            selected.push_back(neighbor);
+        }
+        else
+        {
+            return false;
+        }
+    }
+    static const Resource lower = {0, 0, 0};
+    Resource resources = {0, 0, 0};
+    for (auto r : selected)
+    {
+        resources += r->get_resources();
+    }
+    if (resources > lower)
+    {
+        for (auto i : selected)
+        {
+            i->set_owner(player);
+            i->set_offense(1);
+        }
+        return true;
+    }
+    return false;
+}
+
+void Player::handle_event(SDL_Event *event)
+{
+    if (event->type == BOB_NEXTROUNDEVENT)
+    {
+        this->fought = false;
+    }
 }
\ No newline at end of file
diff --git a/src/Gameplay.hpp b/src/Gameplay.hpp
index bb3ccc4..4d1d4f7 100644
--- a/src/Gameplay.hpp
+++ b/src/Gameplay.hpp
@@ -511,7 +511,7 @@ public:
     Player()
             : name("Default Player"), uuid(boost::uuids::nil_uuid()) { }
     Player(std::string name_)
-            : name(name_), uuid(boost::uuids::basic_random_generator<boost::mt19937>()())
+            : name(name_), uuid(boost::uuids::basic_random_generator<boost::mt19937>()()), fought(false)
     {
         // use the last 24 bits of the tag for the color
         boost::uuids::uuid id = this->uuid;
@@ -543,12 +543,15 @@ public:
         return !(*this == rhs);
     }
 
+    void handle_event(SDL_Event *event);
+
     static Player *current_player;
 
 private:
     boost::uuids::uuid uuid;
     SDL_Color color;
     std::string name;
+    bool fought;
 };
 
 class Grid;
@@ -559,7 +562,7 @@ class FieldMeta
 {
 public:
     FieldMeta(HexagonGrid *grid_, Field field_, Player *owner_)
-            : grid(grid_), field(field_), owner(owner_)
+            : grid(grid_), field(field_), owner(owner_), changed(true)
     {
         this->fighting = false;
         this->upgrades = 0;
@@ -569,8 +572,8 @@ public:
         this->resources_base.circle = distro(rng);
         this->resources_base.triangle = distro(rng);
         this->resources_base.square = distro(rng);
-        this->offense = 1;
-        this->defense = 1;
+        this->offense = 0;
+        this->defense = 0;
         this->regenerate_resources();
     }
 
@@ -580,6 +583,10 @@ public:
 
     int get_defense() { return this->defense; }
 
+    void set_offense(int off) { this->offense = off; }
+
+    void set_defense(int def) { this->defense = def; }
+
     Field get_field() { return this->field; }
 
     Player *get_owner() { return this->owner; }
@@ -608,6 +615,7 @@ public:
 
 private:
     bool fighting;
+    bool changed;
     const Field field;
     HexagonGrid *grid;
     Player *owner;
@@ -646,6 +654,7 @@ public:
             }
         }
         this->marker = new FieldMeta(this, new_field, this->default_player);
+        this->load();
     }
 
     ~HexagonGrid()
@@ -686,10 +695,18 @@ public:
 
     void handle_event(SDL_Event *event);
 
-    bool place(Player *player);
+    bool place(Player *player, FieldMeta *center);
+
+    void set_selecting(bool state, Player *player)
+    {
+        this->selecting = state;
+        this->selecting_player = player;
+    }
 
 private:
     bool changed;
+    bool selecting;
+    Player *selecting_player;
     FieldMeta *first_attack;
     Renderer *renderer;
     SDL_Texture *texture;
diff --git a/src/Gui.cpp b/src/Gui.cpp
index 8ef4fbe..dd8efe1 100644
--- a/src/Gui.cpp
+++ b/src/Gui.cpp
@@ -19,18 +19,22 @@ TTF_Font *load_font_from_file(std::string path_to_file, int size)
     return font;
 }
 
-bool TextBox::load_text(std::string text)
+void TextBox::load()
 {
     this->renderer->set_draw_color({0, 0, 0, 0xff});
-    const char *displayed_text = text.c_str();
+    if (this->text.size() < 1)
+    {
+        this->text += " ";
+    }
+    const char *displayed_text = this->text.c_str();
     SDL_Surface *text_surface = TTF_RenderUTF8_Blended_Wrapped(this->font, displayed_text, this->color,
                                                                this->dimensions.w);
-    this->dimensions.h = text_surface->h;
     if (text_surface == nullptr)
     {
         SDL_FreeSurface(text_surface);
         throw SDL_TTFException();
     }
+    this->dimensions.h = text_surface->h;
     SDL_Surface *surface = SDL_CreateRGBSurface(0, this->dimensions.w, text_surface->h, 32, rmask, gmask, bmask,
                                                 amask);
     if (surface == nullptr || SDL_LockSurface(surface) < 0 ||
@@ -57,7 +61,6 @@ bool TextBox::load_text(std::string text)
         throw SDL_TextureException();
     }
     SDL_SetRenderTarget(this->renderer->get_renderer(), nullptr); // reset the render target
-    return (this->texture != nullptr);
 }
 
 void Container::handle_event(SDL_Event *event)
@@ -73,7 +76,7 @@ void FieldBox::handle_event(const SDL_Event *event)
         FieldMeta *field_update = reinterpret_cast<FieldMeta *>(event->user.data1);
         if (field_update == this->field)
         {
-            this->update();
+            changed = true;
         }
     }
     else if (event->type == BOB_MARKERUPDATE)
@@ -85,6 +88,7 @@ void FieldBox::handle_event(const SDL_Event *event)
         SDL_GetMouseState(&mouse.x, &mouse.y);
         this->update_position(mouse);
         this->visible = true;
+        changed = true;
     }
 }
 
@@ -100,6 +104,7 @@ void FieldBox::update()
     << "▲ " << (int) cluster_resources.triangle << " (" << (int) field_resources.triangle << ")" << "\n"
     << "■ " << (int) cluster_resources.square << " (" << (int) field_resources.square << ")" << "\n";
     this->load_text(output.str());
+    changed = true;
 }
 
 void UpgradeButtonBox::set_active(bool state)
@@ -115,6 +120,7 @@ void UpgradeButtonBox::set_active(bool state)
         this->color = {0, 0, 0, 0xff};
         this->load_text(UPGRADE_NAMES.at(this->upgrade));
     }
+    changed = true;
 }
 
 void UpgradeBox::update_upgrade_boxes()
@@ -124,6 +130,7 @@ void UpgradeBox::update_upgrade_boxes()
     {
         this->upgrades[i]->set_active(active_upgrades[i]);
     }
+    changed = true;
 }
 
 void UpgradeBox::handle_event(const SDL_Event *event)
@@ -133,6 +140,7 @@ void UpgradeBox::handle_event(const SDL_Event *event)
         if (event->type == BOB_FIELDUPDATEEVENT)
         {
             this->update_upgrade_boxes();
+            changed = true;
         }
         else if (event->type == SDL_MOUSEBUTTONDOWN)
         {
@@ -147,6 +155,7 @@ void UpgradeBox::handle_event(const SDL_Event *event)
             {
                 this->marked_upgrade->handle_event(event);
             }
+            changed = true;
         }
         else if (event->type == SDL_MOUSEMOTION && this->visible)
         {
@@ -171,6 +180,7 @@ void UpgradeBox::handle_event(const SDL_Event *event)
                     this->upgrade_info->load_text(output.str());
                 }
             }
+            changed = true;
         }
     }
     else // NOT visible
@@ -187,6 +197,7 @@ void UpgradeBox::handle_event(const SDL_Event *event)
                 this->field = selected;
                 this->update_upgrade_boxes();
                 this->set_visible(true);
+                changed = true;
             }
         }
     }
@@ -204,6 +215,7 @@ void UpgradeButtonBox::handle_event(const SDL_Event *event)
             if (*(Player::current_player) == *(field->get_owner()))
             {
                 field->upgrade(this->upgrade);
+                changed = true;
             }
         }
     }
@@ -216,9 +228,11 @@ void UpgradeBox::render(Renderer *ext_renderer)
     {
         box->render(ext_renderer);
     }
-    SDL_Rect dim = this->upgrades[0]->get_dimensions();
+    this->changed = false;
+    /*SDL_Rect dim = this->upgrades[0]->get_dimensions();
     this->dimensions.w = dim.w;
     this->dimensions.h = dim.h * (int) this->upgrades.size();
+     */
 }
 
 void Container::render(Renderer *renderer)
@@ -231,10 +245,15 @@ void Container::render(Renderer *renderer)
 
 void Box::render(Renderer *ext_renderer)
 {
+    if (changed)
+    {
+        this->load();
+    }
     if (this->visible && this->texture != nullptr)
     {
         ext_renderer->copy(this->texture, nullptr, &(this->dimensions));
     }
+    this->changed = false;
 }
 
 void Container::set_visible(bool visible)
@@ -309,6 +328,7 @@ void NextTurnButtonBox::handle_event(const SDL_Event *event)
             std::ostringstream text;
             text << "NEXT TURN" << "\n\n" << Player::current_player->get_name();
             this->load_text(text.str());
+            this->changed = true;
         }
     }
 }
@@ -375,6 +395,7 @@ void TextInputBox::handle_event(const SDL_Event *event)
         if (text.empty())
             text += " ";
         this->load_text(text);
+        this->changed = true;
     }
 }
 
@@ -389,14 +410,21 @@ void TextInputBox::prompt(std::string message)
         output.str("");
         this->prompt(message);
     }
+    this->input.str("");
+    this->changed = true;
 }
 
 void TextInputBox::render(Renderer *ext_renderer)
 {
+    if (this->changed)
+    {
+        this->load();
+    }
     if (this->texture != nullptr && this->visible)
     {
         ext_renderer->copy(this->texture, nullptr, &(this->dimensions));
     }
+    this->changed = false;
 }
 
 void TextInputBox::update_dimensions(SDL_Rect rect)
@@ -404,7 +432,7 @@ void TextInputBox::update_dimensions(SDL_Rect rect)
     this->dimensions.x = rect.x;
     this->dimensions.y = rect.y;
     this->dimensions.w = rect.w;
-    this->load_text(output.str());
+    this->changed = true;
 }
 
 bool TextInputBox::get_active()
diff --git a/src/Gui.hpp b/src/Gui.hpp
index 6832d68..6a47ed4 100644
--- a/src/Gui.hpp
+++ b/src/Gui.hpp
@@ -34,6 +34,8 @@ public:
 
     virtual void render(Renderer *renderer);
 
+    virtual void load() { this->changed = false; }
+
     virtual void set_visible(bool visibility) { this->visible = visibility; }
 
     SDL_Rect get_dimensions() { return this->dimensions; }
@@ -45,6 +47,7 @@ protected:
     SDL_Rect dimensions;
     SDL_Color color;
     bool visible;
+    bool changed;
 };
 
 class TextBox : public Box
@@ -53,17 +56,23 @@ public:
     TextBox(Renderer *renderer, SDL_Rect dimensions, SDL_Color color, TTF_Font *font_)
             : Box(renderer, dimensions, color), font(font_), lines(1)
     {
-        this->font_height = TTF_FontHeight(font);
+        this->load();
     }
 
-    bool load_text(std::string text);
+    void load();
+
+    void load_text(std::string text)
+    {
+        this->text = text;
+        changed = true;
+    }
 
     virtual void handle_event(const SDL_Event *event) { }
 
 protected:
     TTF_Font *font;
     Uint16 lines;
-    int font_height;
+    std::string text;
 };
 
 class TextInputBox : TextBox
@@ -74,6 +83,7 @@ public:
     {
         this->visible = false;
         this->output << Player::current_player->get_name() << "# ";
+        this->load();
         this->load_text(output.str());
     }