diff --git a/src/Gameplay.cpp b/src/Gameplay.cpp index 34b67a8..2540164 100644 --- a/src/Gameplay.cpp +++ b/src/Gameplay.cpp @@ -9,11 +9,6 @@ Player *FieldMeta::get_owner() return this->owner; } -void FieldMeta::set_owner(Player *player) -{ - this->owner = player; -} - Field FieldMeta::get_field() { return this->field; } void FieldMeta::render(SDL_Renderer *renderer, Layout *layout) @@ -31,7 +26,9 @@ void FieldMeta::render(SDL_Renderer *renderer, Layout *layout) vx[i] = (Sint16) polygon[i].x; vy[i] = (Sint16) polygon[i].y; } - filledPolygonRGBA(renderer, vx, vy, 6, color.r, color.g, color.b, 0x22); + if ((*this->owner) == Player::default_player) + color = {0x77, 0x77, 0x77, 0x77}; + filledPolygonRGBA(renderer, vx, vy, 6, color.r, color.g, color.b, 0x33); SDL_Color inverse; inverse.r = (Uint8) (0xff - color.r); inverse.g = (Uint8) (0xff - color.g); @@ -95,20 +92,23 @@ Resource FieldMeta::get_resources() return this->resources; } -Resource FieldMeta::get_resources_of_cluster() +Resource FieldMeta::get_resources_of_cluster(Cluster cluster) { Resource res = {0, 0, 0}; - std::unordered_set *cluster = new std::unordered_set(); - this->get_cluster(cluster); - for (FieldMeta *elem : *cluster) + for (FieldMeta *elem : cluster) { Resource r_plus = elem->get_resources(); res += r_plus; } - delete cluster; return res; } +Resource FieldMeta::get_resources_of_cluster() +{ + Cluster cluster = this->get_cluster(); + return this->get_resources_of_cluster(cluster); +} + Uint32 FieldMeta::get_upgrades() { return this->upgrades; } bool FieldMeta::upgrade(Upgrade upgrade) @@ -132,22 +132,22 @@ bool FieldMeta::upgrade(Upgrade upgrade) std::cout << "Unknown update: " << upgrade; break; } - if (cluster_resources > costs) + Resource remaining_costs = this->consume_resources_of_cluster(costs); + Resource neutral = {0, 0, 0}; + if (remaining_costs == neutral) { - this->resources -= costs; this->upgrades |= upgrade; + return true; } return false; } -std::unordered_set *FieldMeta::get_cluster(std::unordered_set *visited) +Cluster FieldMeta::get_cluster(Cluster visited) { - assert(visited != nullptr); - - if (visited->find(this) != visited->end()) // already been here before + if (visited.find(this) != visited.end()) // already been here before return visited; - visited->insert(this); + visited.insert(this); for (Uint8 i = 0; i < 6; i++) { @@ -160,3 +160,80 @@ std::unordered_set *FieldMeta::get_cluster(std::unordered_setget_cluster(); + Resource cluster_resources = this->get_resources_of_cluster(cluster); + for (FieldMeta *meta : cluster) + { + // mind the "special" definition of -=, only byte of what you can chew or leave nothing behind + Resource tmp = costs; + costs -= meta->resources; + meta->resources -= tmp; + } + return costs; // > {0, 0, 0} means there were not enough resources +} + +void FieldMeta::set_owner(Player *player) +{ + this->owner = player; +} + +FieldMeta *FieldMeta::get_meta(Field field) +{ + auto pair = fields.find(field); + if (pair != fields.end()) + { + return pair->second; + } + return nullptr; // no meta-information (there is no field on the map at this location) +} + +bool Player::fight(Field field) +{ + FieldMeta *meta = FieldMeta::get_meta(field); + if (meta == nullptr || *this == *(meta->get_owner())) // attacked field outside of the map or friendly fire + { + return false; + } + if (*(meta->get_owner()) == this->default_player) // still to be had + { + meta->set_owner(this); + return true; + } + + // defending player's defense against attacking player's offense + int power_level = meta->get_defense(); // it's over 9000 + Field center = meta->get_field(); + for (Uint8 i = 0; i < 6; i++) + { + Field neighbor = hex_neighbor(i, center); + FieldMeta *neighbor_meta = FieldMeta::get_meta(neighbor); + if (neighbor_meta == nullptr) // there is no neighbor in this direction + { + continue; + } + if (*(neighbor_meta->get_owner()) == *this) // comparison by UUID + power_level -= neighbor_meta->get_offense(); + else if (*(neighbor_meta->get_owner()) == *(meta->get_owner())) + power_level += neighbor_meta->get_defense(); + // else ignore, field / player not part of the fight (e.g. default player) + } + if (power_level < 0) // attacking player has won + { + meta->set_owner(this); + return true; + } + return false; +} + +int FieldMeta::get_offense() +{ + return this->offense; +} + +int FieldMeta::get_defense() +{ + return this->defense; +} diff --git a/src/Gameplay.hpp b/src/Gameplay.hpp index 49bc46c..b547827 100644 --- a/src/Gameplay.hpp +++ b/src/Gameplay.hpp @@ -9,6 +9,8 @@ #include #include "Grid.hpp" + +#ifndef Upgrade typedef enum { UPGRADE_FIRST_UPGRADE = 0, @@ -17,6 +19,7 @@ typedef enum UPGRADE_REGENERATION_3, UPGRADE_REPRODUCTION } Upgrade; +#endif #ifndef Tagged @@ -96,6 +99,8 @@ public: return descriptor.str(); } + bool fight(Field field); + static Player default_player; }; @@ -125,9 +130,21 @@ struct Resource Resource &operator-=(const Resource &rhs) { - this->circle -= rhs.circle; - this->triangle -= rhs.triangle; - this->square -= rhs.square; + if (this->circle < rhs.circle) + this->circle = 0; + else + this->circle -= rhs.circle; + + if (this->triangle < rhs.triangle) + this->triangle = 0; + else + this->triangle -= rhs.triangle; + + if (this->square < rhs.square) + this->square = 0; + else + this->square -= rhs.square; + return *this; } @@ -180,10 +197,18 @@ struct Resource inline bool operator<=(const Resource &rhs) const { return !(*this > rhs); } inline bool operator>=(const Resource &rhs) const { return !(*this < rhs); } + + bool operator==(const Resource &rhs) const + { + return (this->circle == rhs.circle && this->triangle == rhs.triangle && this->square == rhs.square); + } + + inline bool operator!=(const Resource &rhs) const { return !(*this == rhs); } }; #endif + #ifndef FieldMeta class FieldMeta @@ -201,21 +226,34 @@ public: this->resources_base.square = distro(rng); std::pair pair(field, this); this->fields.insert(pair); + this->offense = 1; + this->defense = 1; } + int get_offense(); + + int get_defense(); + + static FieldMeta *get_meta(Field field); + Field get_field(); Player *get_owner(); void set_owner(Player *player); + //void set_owner(Player *player); + void render(SDL_Renderer *renderer, Layout *layout); Resource get_resources(); Resource get_resources_of_cluster(); - std::unordered_set *get_cluster(std::unordered_set *visited); + Resource get_resources_of_cluster(std::unordered_set cluster); + + std::unordered_set get_cluster( + std::unordered_set visited = std::unordered_set()); Uint32 get_upgrades(); @@ -223,6 +261,8 @@ public: bool upgrade(Upgrade upgrade); + Resource consume_resources_of_cluster(Resource costs); + private: const Field field; static std::unordered_map fields; @@ -230,6 +270,13 @@ private: Uint32 upgrades; Resource resources_base; // without upgrades applied, used as basis of regeneration Resource resources; // actual current resources + int offense; + int defense; }; -#endif \ No newline at end of file +#endif + +#ifndef Cluster +typedef std::unordered_set Cluster; +#endif + diff --git a/src/Main.cpp b/src/Main.cpp index 0e14d5b..3ccc42f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -58,7 +58,7 @@ void Game::toggle_fullscreen() this->full_screen = true; SDL_SetWindowSize(this->window, dm.w, dm.h); SDL_SetWindowFullscreen(this->window, SDL_WINDOW_FULLSCREEN); - this->grid->update_box(dm.w, dm.h); + this->grid->update_box(dm.w - SIDEBOX_WIDTH, dm.h); } else { @@ -135,7 +135,7 @@ int Game::game_loop() if (move_timer->get_timer() > 10) { move_timer->reset_timer(); - SDL_Point move_by = {(this->move[1] - this->move[3]) * 10, (this->move[0] - this->move[2]) * 10}; + SDL_Point move_by = {(this->move[1] - this->move[3]) * 20, (this->move[0] - this->move[2]) * 20}; this->grid->move(move_by); } if (frame_timer->get_timer() > 1000.0) @@ -155,7 +155,7 @@ int Game::game_loop() { quit = true; } - if (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEWHEEL) + if (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEWHEEL || event.type == SDL_MOUSEBUTTONDOWN) { grid->handle_event(&event); } @@ -205,8 +205,8 @@ int main(int, char **) SDL_Quit(); return -1; } - Layout *layout = new Layout(pointy_orientation, GRID_SIZE, {5 * SCREEN_WIDTH / 12, 5 * SCREEN_HEIGTH / 12}, - {0, 0, 5 * SCREEN_WIDTH / 6, 5 * SCREEN_HEIGTH / 6}); + Layout *layout = new Layout(pointy_orientation, 20, {SCREEN_WIDTH / 2, SCREEN_HEIGTH / 2}, + {0, 0, SCREEN_WIDTH - SIDEBOX_WIDTH, SCREEN_HEIGTH}); Game *game = new Game(window, renderer, layout); int exit_status = game->game_loop(); delete game; diff --git a/src/Main.hpp b/src/Main.hpp index bd3f696..7ce1fb5 100644 --- a/src/Main.hpp +++ b/src/Main.hpp @@ -10,7 +10,8 @@ const Sint16 GRID_SIZE = 4; const int SCREEN_WIDTH = 800; const int SCREEN_HEIGTH = 600; -char TITLE[] = "Bob - Battles of Bacteria"; +const int SIDEBOX_WIDTH = 200; +const char TITLE[] = "Bob - Battles of Bacteria"; #endif #if SDL_BYTEORDER == SDL_BIG_ENDIAN @@ -49,7 +50,7 @@ private: SDL_Renderer *renderer; HexagonGrid *grid; // only deal with meta information - std::unordered_set fields_meta; + Cluster fields_meta; Layout *layout; bool move[4]; bool full_screen;