Refactoring, Exception handling and Events.

This commit is contained in:
Tim Schubert 2016-01-23 03:27:32 +01:00
parent b159f83c63
commit a3df4a3189
14 changed files with 1377 additions and 916 deletions

View file

@ -1,23 +1,12 @@
#include "Gameplay.hpp"
Player Player::default_player = Player("Default");
std::unordered_map<Field, FieldMeta *> FieldMeta::fields = std::unordered_map<Field, FieldMeta *>();
Player *FieldMeta::get_owner()
{
return this->owner;
}
Field FieldMeta::get_field() { return this->field; }
void FieldMeta::render(SDL_Renderer *renderer, Layout *layout)
{
Point precise_location = field_to_point(this->field, layout);
Point precise_location = this->field.field_to_point(layout);
SDL_Point location;
location.x = (int) precise_location.x;
location.y = (int) precise_location.y;
std::vector<Point> polygon = field_to_polygon(this->field, layout);
std::vector<Point> polygon = this->field.field_to_polygon(layout);
SDL_Color color = this->owner->get_color();
Sint16 vx[6];
Sint16 vy[6];
@ -26,7 +15,7 @@ void FieldMeta::render(SDL_Renderer *renderer, Layout *layout)
vx[i] = (Sint16) polygon[i].x;
vy[i] = (Sint16) polygon[i].y;
}
if ((*this->owner) == Player::default_player)
if (this->owner == this->grid->get_default_player())
color = {0x77, 0x77, 0x77, 0x77};
filledPolygonRGBA(renderer, vx, vy, 6, color.r, color.g, color.b, 0x33);
SDL_Color inverse;
@ -70,32 +59,21 @@ void FieldMeta::render(SDL_Renderer *renderer, Layout *layout)
}
}
void FieldMeta::regenerate_resources()
{
resources = resources_base;
switch (this->upgrades)
{
case (UPGRADE_REGENERATION_1):
resources *= 2;
case (UPGRADE_REGENERATION_2):
resources *= 2;
case (UPGRADE_REGENERATION_3):
resources *= 2;
default:
break;
}
this->resources = resources_base;
if (this->upgrades[Regeneration_1])
this->resources *= 2;
if (this->upgrades[Regeneration_2])
this->resources *= 2;
if (this->upgrades[Regeneration_3])
this->resources *= 2;
}
Resource FieldMeta::get_resources()
{
return this->resources;
}
Resource FieldMeta::get_resources_of_cluster(Cluster cluster)
Resource Grid::get_resources_of_cluster(const Cluster *cluster)
{
Resource res = {0, 0, 0};
for (FieldMeta *elem : cluster)
for (FieldMeta *elem : *cluster)
{
Resource r_plus = elem->get_resources();
res += r_plus;
@ -103,137 +81,252 @@ Resource FieldMeta::get_resources_of_cluster(Cluster 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)
{
// check available resources for cluster and consume resources
Resource cluster_resources = this->get_resources_of_cluster();
Resource costs;
switch (upgrade)
Cluster *cluster = this->grid->get_cluster(this);
Resource cluster_resources = this->grid->get_resources_of_cluster(this->grid->get_cluster(this, cluster));
Resource remaining_costs;
try
{
case UPGRADE_REGENERATION_1:
costs = {(1 << 1), (1 << 1), (1 << 1)};
break;
case UPGRADE_REGENERATION_2:
costs = {(1 << 2), (1 << 2), (1 << 2)};
break;
case UPGRADE_REGENERATION_3:
costs = {(1 << 3), (1 << 3), (1 << 3)};
break;
default:
std::cout << "Unknown update: " << upgrade;
break;
Resource costs = UPGRADE_COSTS.at(upgrade);
remaining_costs = this->grid->consume_resources_of_cluster(cluster, costs);
}
Resource remaining_costs = this->consume_resources_of_cluster(costs);
Resource neutral = {0, 0, 0};
catch (const std::out_of_range &oor)
{
std::cerr << "Out of Range exception: " << oor.what() << std::endl;
remaining_costs = {1, 1, 1};
}
static const Resource neutral = {0, 0, 0};
if (remaining_costs == neutral)
{
this->upgrades |= upgrade;
return true;
this->upgrades[upgrade] = true;
}
return false;
return this->upgrades[upgrade];
}
Cluster FieldMeta::get_cluster(Cluster visited)
FieldMeta *FieldMeta::get_neighbor(Uint8 direction)
{
if (visited.find(this) != visited.end()) // already been here before
return this->grid->get_neighbor(this, direction);
}
FieldMeta *HexagonGrid::get_neighbor(FieldMeta *meta, Uint8 direction)
{
Field neighbor_field = meta->get_field().get_neighbor(direction);
try
{
return this->fields.at(neighbor_field);
}
catch (const std::out_of_range &oor)
{
std::cerr << "Tried to look up non-existing field: " << neighbor_field << std::endl;
}
return nullptr;
}
Cluster *HexagonGrid::get_cluster(FieldMeta *field, Cluster *visited)
{
if (visited == nullptr)
visited = new Cluster();
if (visited->find(field) != visited->end()) // already been here before
return visited;
visited.insert(this);
else
visited->insert(field);
for (Uint8 i = 0; i < 6; i++)
{
auto neighbor_pair = FieldMeta::fields.find(hex_neighbor(i, this->get_field()));
FieldMeta *neighbor = neighbor_pair->second;
if (neighbor->get_owner() != this->get_owner()) // ignore meta if field not owned by specified owner
FieldMeta *neighbor = this->get_neighbor(field, i);
if (neighbor->get_owner() != field->get_owner()) // ignore meta if field not owned by specified owner
return visited;
else
return neighbor->get_cluster(visited);
this->get_cluster(neighbor, visited);
}
return visited;
}
Resource FieldMeta::consume_resources_of_cluster(Resource costs)
Resource Grid::consume_resources_of_cluster(Cluster *cluster, Resource costs)
{
Cluster cluster = this->get_cluster();
Resource cluster_resources = this->get_resources_of_cluster(cluster);
for (FieldMeta *meta : 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;
costs -= meta->get_resources();
meta->consume_resources(tmp);
}
delete cluster;
return costs; // > {0, 0, 0} means there were not enough resources
}
void FieldMeta::set_owner(Player *player)
bool Player::fight(FieldMeta *field)
{
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
if (*this == *(field->get_owner())) // attacked field outside of the map or friendly fire
{
return false;
}
if (*(meta->get_owner()) == this->default_player) // still to be had
if (field->get_owner() == field->get_grid()->get_default_player()) // still to be had
{
meta->set_owner(this);
field->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();
int power_level = field->get_defense(); // it's over 9000
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
FieldMeta *neighbor = field->get_neighbor(i);
if (neighbor == 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();
if (*(neighbor->get_owner()) == *this) // comparison by UUID
power_level -= neighbor->get_offense();
else if (*(neighbor->get_owner()) == *(field->get_owner()))
power_level += neighbor->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);
field->set_owner(this);
return true;
}
return false;
}
int FieldMeta::get_offense()
void FieldMeta::handle_event(const SDL_Event *event)
{
return this->offense;
this->regenerate_resources();
}
int FieldMeta::get_defense()
bool HexagonGrid::render(SDL_Renderer *renderer)
{
return this->defense;
Field some_field = {0, 0, 0};
std::vector<Point> polygon = some_field.field_to_polygon_normalized(this->layout);
assert(polygon.size() > 5);
Sint16 x[6];
Sint16 y[6];
for (std::pair<Field, FieldMeta *> const &elem : this->fields)
{
Field field = elem.first;
Point center = field.field_to_point(this->layout);
for (uint8_t i = 0; i < 6; i++)
{
x[i] = (Sint16) (center.x + polygon[i].x);
y[i] = (Sint16) (center.y + polygon[i].y);
}
const SDL_Color color = {0xff, 0xff, 0xff, 0xff};
polygonRGBA(renderer, x, y, 6, color.r, color.g, color.b, color.a);
if (elem.first == this->marker->get_field())
{
filledPolygonRGBA(renderer, x, y, 6, 0x77, 0x77, 0x77, 0x77);
}
elem.second->render(renderer, this->layout);
}
return true;
}
void Grid::handle_event(SDL_Event *event)
{
if (event->type == SDL_MOUSEWHEEL)
{
SDL_Point mouse = {0, 0};
SDL_GetMouseState(&mouse.x, &mouse.y);
int scroll = this->layout->size / 10 * event->wheel.y;
double old_size = this->layout->size;
SDL_Point old_origin = this->layout->origin;
if (old_size + scroll < 10)
{
this->layout->size = 10;
}
else if (old_size + scroll > 100)
{
this->layout->size = 100;
}
else
{
this->layout->size += scroll;
}
this->move(((1.0 - (double) this->layout->size / old_size) * (mouse - old_origin)));
}
if (event->type == SDL_MOUSEMOTION)
{
if (this->panning)
{
SDL_Point mouse = {0, 0};
SDL_GetMouseState(&mouse.x, &mouse.y);
Point marker_pos = this->marker->get_field().field_to_point(this->layout);
SDL_Point p;
p.x = (int) marker_pos.x;
p.y = (int) marker_pos.y;
this->move(mouse - p);
}
this->update_marker();
}
if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_MIDDLE)
{
this->panning = !(this->panning);
}
}
void Grid::move(SDL_Point m)
{
this->layout->origin = this->layout->origin + m;
// check if some part is inside layout->box
if (!on_rectangle(&layout->box))
this->layout->origin = this->layout->origin - m;
this->update_marker();
}
void Grid::update_marker()
{
SDL_Point m = {0, 0};
SDL_GetMouseState(&(m.x), &(m.y));
Point p = {0.0, 0.0};
p.x = m.x;
p.y = m.y;
FieldMeta *n_marker = this->point_to_field(p);
if (n_marker != nullptr)
this->marker = n_marker;
}
FieldMeta *Grid::point_to_field(const Point p)
{
Field field = p.point_to_field(this->layout);
FieldMeta *meta = nullptr;
try
{
meta = this->fields.at(field);
}
catch (const std::out_of_range &oor)
{
//std::cerr << "Tried to access non-existant field " << field << ": " << oor.what() << std::endl;
}
return meta;
}
bool Grid::on_rectangle(SDL_Rect *rect)
{
// check if center inside rect for ANY field
for (const auto &pair : this->fields)
{
Point precise_p = pair.first.field_to_point(layout);
SDL_Point p;
p.x = (int) precise_p.x;
p.y = (int) precise_p.y;
if (p.x > rect->x && p.y > rect->y && p.x < (rect->x + rect->w) && p.y < (rect->y + rect->h))
{
return true;
}
}
return false;
}
void Grid::update_box(SDL_Point dimensions)
{
this->layout->box.w = dimensions.x;
this->layout->box.h = dimensions.y;
}
std::ostream &operator<<(std::ostream &os, const Field &rhs)
{
os << "(" << rhs.x << "," << rhs.y << ",";
return os;
}