2011-06-23 21:28:49 +00:00
|
|
|
#include "gamedata.h"
|
|
|
|
#include "mathutils.h"
|
2011-06-24 15:03:40 +00:00
|
|
|
#include "debug.h"
|
|
|
|
#include <list>
|
|
|
|
#include <algorithm>
|
2011-06-24 15:37:56 +00:00
|
|
|
#include <cassert>
|
2011-06-24 15:03:40 +00:00
|
|
|
|
|
|
|
using std::list;
|
2011-06-23 21:28:49 +00:00
|
|
|
|
|
|
|
int GameData::PLAYER1_COLOUR = 0x4a483f;
|
|
|
|
int GameData::PLAYER2_COLOUR = 0x090c7a;
|
|
|
|
|
2011-07-01 18:10:45 +00:00
|
|
|
int GameData::BASE_BUILD_RADIUS = 75;
|
|
|
|
int GameData::NODE_RADIUS = 10;
|
2011-06-29 02:27:33 +00:00
|
|
|
|
2011-07-02 00:00:19 +00:00
|
|
|
|
2011-07-02 02:04:58 +00:00
|
|
|
GameVertex::GameVertex(int x, int y, int z, int r, int colour, int score,
|
|
|
|
VertexType type, Player* player)
|
|
|
|
: Vertex(x, y, z, r, colour, score)
|
|
|
|
{
|
|
|
|
this->type = type;
|
|
|
|
this->player = player;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-23 21:28:49 +00:00
|
|
|
GameData::GameData()
|
|
|
|
: Graph(true)
|
|
|
|
{
|
|
|
|
current = NULL;
|
2011-07-01 18:10:45 +00:00
|
|
|
mode = MODE_BUILD;
|
2011-07-02 00:00:19 +00:00
|
|
|
player1 = Player("player 1", PLAYER1_COLOUR);
|
|
|
|
player2 = Player("player 2", PLAYER2_COLOUR);
|
2011-07-01 18:10:45 +00:00
|
|
|
turn = &player1;
|
2011-07-03 19:16:00 +00:00
|
|
|
build_type = VERTEX_PRODUCER; // first vertex is always a producer
|
2011-06-23 21:28:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GameData::~GameData() { }
|
|
|
|
|
2011-07-01 18:10:45 +00:00
|
|
|
|
|
|
|
Vertex* GameData::get_current_vertex(bool only_mine) const
|
|
|
|
{
|
|
|
|
if (only_mine)
|
|
|
|
{
|
2011-07-02 00:00:19 +00:00
|
|
|
if (current != NULL &&
|
2011-07-02 03:24:41 +00:00
|
|
|
dynamic_cast<GameVertex*>(current)->player == turn) return current;
|
2011-07-01 18:10:45 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-02 00:00:19 +00:00
|
|
|
void GameData::clear_current_vertex()
|
|
|
|
{
|
|
|
|
mode = MODE_SELECT;
|
|
|
|
current = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-23 21:28:49 +00:00
|
|
|
void GameData::toggle_turn()
|
|
|
|
{
|
2011-07-01 22:23:01 +00:00
|
|
|
if (!turn->has_played()) turn->set_played();
|
2011-06-24 18:59:18 +00:00
|
|
|
|
|
|
|
if (!endgame())
|
|
|
|
{
|
2011-07-01 18:10:45 +00:00
|
|
|
if (turn == &player1) turn = &player2;
|
|
|
|
else if (turn == &player2) turn = &player1;
|
|
|
|
|
2011-07-03 19:16:00 +00:00
|
|
|
if (!turn->has_played())
|
|
|
|
{
|
|
|
|
mode = MODE_BUILD;
|
|
|
|
build_type = VERTEX_PRODUCER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mode = MODE_SELECT;
|
|
|
|
build_type = VERTEX_NONE;
|
|
|
|
}
|
2011-06-24 18:59:18 +00:00
|
|
|
}
|
2011-07-01 22:23:01 +00:00
|
|
|
|
|
|
|
current = NULL;
|
2011-06-23 21:28:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-01 18:10:45 +00:00
|
|
|
void GameData::handle_click(int x, int y)
|
2011-06-23 21:28:49 +00:00
|
|
|
{
|
2011-07-01 18:10:45 +00:00
|
|
|
int r = 10;
|
2011-06-23 21:28:49 +00:00
|
|
|
|
2011-06-24 18:59:18 +00:00
|
|
|
int colour;
|
2011-07-01 18:10:45 +00:00
|
|
|
colour = turn->get_colour();
|
2011-06-24 18:59:18 +00:00
|
|
|
|
2011-07-03 14:38:56 +00:00
|
|
|
Vertex* v = vertex_at(x, y, 0);
|
|
|
|
|
|
|
|
// fixme - energy expenditure should happen in each of these cases except
|
|
|
|
// MODE_SELECT
|
|
|
|
switch (mode)
|
2011-06-24 16:02:53 +00:00
|
|
|
{
|
2011-07-03 14:38:56 +00:00
|
|
|
case MODE_SELECT:
|
2011-07-01 22:23:01 +00:00
|
|
|
// select_vertex handles making sure a point exists at (x,y)
|
|
|
|
select_vertex(x, y);
|
2011-07-03 14:38:56 +00:00
|
|
|
break;
|
|
|
|
case MODE_BUILD:
|
2011-07-01 22:23:01 +00:00
|
|
|
add_vertex(x, y, 0, r, colour);
|
2011-07-03 14:38:56 +00:00
|
|
|
break;
|
|
|
|
case MODE_ATTACK:
|
2011-07-02 03:24:41 +00:00
|
|
|
if (v == NULL || dynamic_cast<GameVertex*>(v)->player == turn) return;
|
2011-07-01 18:10:45 +00:00
|
|
|
if (v->colour != colour) attack_vertex(v);
|
2011-07-03 14:38:56 +00:00
|
|
|
break;
|
|
|
|
case MODE_MOVE:
|
|
|
|
if (current == NULL) return;
|
|
|
|
if (MathUtils::distance(current->x, current->y, current->z, x, y, 0)
|
|
|
|
<= get_range())
|
|
|
|
{
|
|
|
|
current->x = x;
|
|
|
|
current->y = y;
|
|
|
|
toggle_turn();
|
|
|
|
}
|
|
|
|
break;
|
2011-06-24 18:59:18 +00:00
|
|
|
}
|
2011-06-23 21:28:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-02 03:24:41 +00:00
|
|
|
bool GameData::select_vertex(int x, int y)
|
2011-06-23 21:28:49 +00:00
|
|
|
{
|
2011-07-01 18:10:45 +00:00
|
|
|
Vertex * v = vertex_at(x, y, 0);
|
2011-07-01 18:39:45 +00:00
|
|
|
if (v == NULL) return false;
|
2011-06-23 21:28:49 +00:00
|
|
|
|
2011-07-01 18:10:45 +00:00
|
|
|
current = v;
|
2011-07-01 18:39:45 +00:00
|
|
|
return true;
|
2011-06-23 21:28:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-01 16:24:52 +00:00
|
|
|
bool GameData::add_vertex(int x, int y, int z, int r, int colour)
|
2011-06-23 21:28:49 +00:00
|
|
|
{
|
2011-07-03 19:16:00 +00:00
|
|
|
if (build_type == VERTEX_NONE) return false;
|
|
|
|
|
|
|
|
GameVertex* v = new GameVertex(x, y, z, r, colour, 10, build_type, turn);
|
2011-07-02 02:04:58 +00:00
|
|
|
|
2011-06-23 21:28:49 +00:00
|
|
|
if (current == NULL)
|
|
|
|
{
|
2011-06-24 18:59:18 +00:00
|
|
|
// this is the special case for adding the first vertex for each player
|
2011-07-01 18:10:45 +00:00
|
|
|
if (!turn->has_played())
|
2011-06-23 21:28:49 +00:00
|
|
|
{
|
2011-07-02 02:04:58 +00:00
|
|
|
if (Graph::add_vertex(v))
|
2011-07-01 22:04:15 +00:00
|
|
|
{
|
2011-06-24 15:03:40 +00:00
|
|
|
#ifdef DEBUG
|
2011-07-01 22:04:15 +00:00
|
|
|
fprintf(stderr, "debug: GameData::add_vertex(): strength=%2.f\n", calculate_strength(*(vertices.rbegin())));
|
2011-06-24 15:03:40 +00:00
|
|
|
#endif
|
2011-07-01 22:04:15 +00:00
|
|
|
toggle_turn();
|
|
|
|
return true;
|
|
|
|
}
|
2011-06-23 21:28:49 +00:00
|
|
|
}
|
2011-07-01 22:23:01 +00:00
|
|
|
|
|
|
|
// really, we shouldn't be able to get here. return false just in case
|
2011-07-02 02:04:58 +00:00
|
|
|
delete v;
|
2011-06-23 21:28:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-07-01 22:23:01 +00:00
|
|
|
// same here - just a logic check
|
2011-07-02 03:24:41 +00:00
|
|
|
if (dynamic_cast<GameVertex*>(current)->player != turn)
|
2011-07-02 02:04:58 +00:00
|
|
|
{
|
|
|
|
delete v;
|
|
|
|
return false;
|
|
|
|
}
|
2011-07-01 18:10:45 +00:00
|
|
|
|
2011-07-01 22:23:01 +00:00
|
|
|
// This is the range check...
|
2011-07-02 02:04:58 +00:00
|
|
|
if (MathUtils::distance(current->x, current->y, 0, v->x, v->y, 0) >
|
|
|
|
get_range())
|
|
|
|
{
|
|
|
|
delete v;
|
2011-07-01 22:23:01 +00:00
|
|
|
return false;
|
2011-07-02 02:04:58 +00:00
|
|
|
}
|
2011-07-01 22:23:01 +00:00
|
|
|
|
2011-07-02 02:04:58 +00:00
|
|
|
if (Graph::add_vertex(v, current))
|
2011-06-23 21:28:49 +00:00
|
|
|
{
|
2011-06-24 15:03:40 +00:00
|
|
|
#ifdef DEBUG
|
2011-06-24 19:06:52 +00:00
|
|
|
fprintf(stderr, "debug: GameData::add_vertex(): strength=%.2f\n",
|
2011-06-24 15:03:40 +00:00
|
|
|
calculate_strength(*(vertices.rbegin())));
|
|
|
|
#endif
|
|
|
|
|
2011-06-23 21:28:49 +00:00
|
|
|
toggle_turn();
|
|
|
|
return true;
|
|
|
|
}
|
2011-07-02 02:04:58 +00:00
|
|
|
|
|
|
|
delete v;
|
2011-06-23 21:28:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-06-24 15:03:40 +00:00
|
|
|
|
|
|
|
|
2011-07-02 00:00:19 +00:00
|
|
|
float GameData::calculate_armor(Vertex* node)
|
|
|
|
{
|
|
|
|
float str = calculate_strength(node);
|
2011-07-03 19:48:06 +00:00
|
|
|
float armor;
|
|
|
|
|
|
|
|
switch(dynamic_cast<GameVertex*>(node)->type)
|
|
|
|
{
|
|
|
|
case VERTEX_ATTACKER:
|
|
|
|
armor = str / 10;
|
|
|
|
break;
|
|
|
|
case VERTEX_DEFENDER:
|
|
|
|
armor = str / 5;
|
|
|
|
break;
|
|
|
|
case VERTEX_PRODUCER:
|
|
|
|
armor = str / 40;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-07-03 19:16:00 +00:00
|
|
|
if (armor < 1) armor = 1;
|
|
|
|
return armor;
|
2011-07-02 00:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-03 19:48:06 +00:00
|
|
|
float GameData::calculate_attack(Vertex* node)
|
|
|
|
{
|
|
|
|
float attack = calculate_strength(node);
|
|
|
|
|
|
|
|
switch (dynamic_cast<GameVertex*>(node)->type)
|
|
|
|
{
|
|
|
|
case VERTEX_ATTACKER:
|
|
|
|
attack *= 1.5;
|
|
|
|
break;
|
|
|
|
case VERTEX_DEFENDER:
|
|
|
|
attack /= 0.75;
|
|
|
|
break;
|
|
|
|
case VERTEX_PRODUCER:
|
|
|
|
attack = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-24 15:32:50 +00:00
|
|
|
float GameData::calculate_strength(Vertex* node)
|
2011-06-24 15:03:40 +00:00
|
|
|
{
|
2011-06-24 15:32:50 +00:00
|
|
|
list<Vertex*> visited;
|
2011-06-24 15:03:40 +00:00
|
|
|
|
|
|
|
// Special case - a one-node tree just returns its own score!
|
2011-07-01 15:48:49 +00:00
|
|
|
if (node->neighbors.empty()) return (float)node->score;
|
2011-06-24 15:03:40 +00:00
|
|
|
|
2011-06-24 15:32:50 +00:00
|
|
|
return calculate_strength_r(node, 0, visited);
|
|
|
|
}
|
|
|
|
|
2011-06-24 15:03:40 +00:00
|
|
|
|
2011-06-24 15:32:50 +00:00
|
|
|
// Oh the recursive recursion!
|
|
|
|
float GameData::calculate_strength_r(Vertex* node, unsigned int depth, list<Vertex*>& visited)
|
|
|
|
{
|
2011-06-24 15:03:40 +00:00
|
|
|
// Find which vertices we need to visit from here
|
2011-06-27 22:10:24 +00:00
|
|
|
list<Vertex*> neighbors = node->neighbors;
|
2011-06-24 15:03:40 +00:00
|
|
|
list<Vertex*> to_visit;
|
|
|
|
|
2011-06-24 15:37:56 +00:00
|
|
|
visited.push_back(node);
|
|
|
|
|
2011-06-24 16:18:52 +00:00
|
|
|
for (list<Vertex*>::iterator cursor = neighbors.begin();
|
|
|
|
cursor != neighbors.end(); cursor++)
|
2011-06-24 15:03:40 +00:00
|
|
|
{
|
2011-06-24 16:18:52 +00:00
|
|
|
Vertex* v = *cursor;
|
2011-06-24 15:03:40 +00:00
|
|
|
// if this is true, we haven't visited the vertex on the other end of
|
|
|
|
// this edge yet
|
2011-06-24 16:18:52 +00:00
|
|
|
if (find(visited.begin(), visited.end(), v) == visited.end())
|
2011-06-24 15:03:40 +00:00
|
|
|
{
|
2011-06-24 16:18:52 +00:00
|
|
|
to_visit.push_back(v);
|
2011-06-24 15:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the base case - this node has no unvisited neighbors
|
2011-06-24 15:32:50 +00:00
|
|
|
if (to_visit.empty())
|
|
|
|
{
|
2011-06-24 15:37:56 +00:00
|
|
|
assert(depth > 0);
|
2011-06-24 15:32:50 +00:00
|
|
|
return (float)(node->score) / depth;
|
|
|
|
}
|
2011-06-24 15:03:40 +00:00
|
|
|
|
|
|
|
// Else, iterate through to_visit and visit them all, summing their
|
|
|
|
// effective strengths adjusted for depth.
|
|
|
|
// Since our trees are acyclic, this can't loop.
|
2011-06-24 15:06:26 +00:00
|
|
|
float modscore = (float)node->score;
|
2011-06-24 15:03:40 +00:00
|
|
|
if (depth > 0) modscore /= depth;
|
|
|
|
|
|
|
|
for (list<Vertex*>::iterator cursor = to_visit.begin();
|
|
|
|
cursor != to_visit.end(); cursor++)
|
|
|
|
{
|
|
|
|
Vertex* v = *cursor;
|
2011-06-24 15:32:50 +00:00
|
|
|
modscore += calculate_strength_r(v, depth+1, visited);
|
2011-06-24 15:03:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return modscore;
|
|
|
|
}
|
2011-06-24 16:02:53 +00:00
|
|
|
|
|
|
|
|
2011-07-01 22:23:01 +00:00
|
|
|
// This class contains logic checks to keep the mode aligned with
|
|
|
|
// what is reasonable. Special cases inside the GameData class should just
|
|
|
|
// do mode = MODE_<whatever>
|
|
|
|
void GameData::set_mode(Mode m)
|
2011-07-01 18:10:45 +00:00
|
|
|
{
|
2011-07-01 22:23:01 +00:00
|
|
|
// Stay in MODE_SELECT (or maybe MODE_BUILD) when current is null
|
|
|
|
if (current == NULL) return;
|
2011-07-02 00:00:19 +00:00
|
|
|
|
2011-07-03 14:12:47 +00:00
|
|
|
// If we're leaving MODE_BUILD, we should set the build_type back to none
|
|
|
|
if (mode == MODE_ATTACK && m != mode) build_type = VERTEX_NONE;
|
|
|
|
|
2011-07-01 22:23:01 +00:00
|
|
|
// The other modes all require current to match the player
|
2011-07-02 03:24:41 +00:00
|
|
|
if (dynamic_cast<GameVertex*>(current)->player == turn) mode = m;
|
2011-07-01 18:10:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-24 16:18:52 +00:00
|
|
|
int GameData::get_range(Vertex* node)
|
2011-06-24 16:02:53 +00:00
|
|
|
{
|
2011-06-24 16:18:52 +00:00
|
|
|
if (node == NULL) node = current;
|
|
|
|
|
|
|
|
if (node == NULL) return 0;
|
2011-07-01 18:10:45 +00:00
|
|
|
else if (mode == MODE_MOVE) return turn->get_energy();
|
|
|
|
else if (mode == MODE_BUILD) return BASE_BUILD_RADIUS;
|
2011-06-24 16:18:52 +00:00
|
|
|
else if (mode == MODE_ATTACK)
|
|
|
|
{
|
2011-07-01 18:10:45 +00:00
|
|
|
int range = BASE_BUILD_RADIUS;
|
2011-06-27 22:10:24 +00:00
|
|
|
list<Vertex*> neighbors = node->neighbors;
|
2011-06-24 18:59:18 +00:00
|
|
|
|
|
|
|
for(list<Vertex*>::iterator cursor = neighbors.begin();
|
|
|
|
cursor != neighbors.end(); cursor++)
|
|
|
|
{
|
|
|
|
Vertex* v = *cursor;
|
2011-07-01 16:24:52 +00:00
|
|
|
range -= (100 - MathUtils::distance(v->x, v->y, v->z,
|
|
|
|
node->x, node->y, node->z))
|
|
|
|
/ 2;
|
2011-06-24 18:59:18 +00:00
|
|
|
}
|
2011-06-24 19:06:52 +00:00
|
|
|
if (range < 0) range = 0;
|
|
|
|
return range;
|
2011-06-24 16:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GameData::attack_vertex(Vertex* target)
|
|
|
|
{
|
2011-07-03 19:48:06 +00:00
|
|
|
float atk = calculate_attack(current);
|
2011-07-03 19:16:00 +00:00
|
|
|
float armor = calculate_armor(target);
|
2011-07-02 00:00:19 +00:00
|
|
|
int damage = (int)(atk / armor);
|
2011-06-24 18:59:18 +00:00
|
|
|
target->score -= damage;
|
|
|
|
if (target->score <= 0) remove_vertex(target);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2011-07-03 19:16:00 +00:00
|
|
|
fprintf(stderr, "debug: GameData::attack_vertex(): atk=%.2f, armor=%.2f, damage=%d\n", atk, armor, damage);
|
2011-06-24 18:59:18 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
toggle_turn();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool GameData::endgame()
|
|
|
|
{
|
2011-07-01 18:10:45 +00:00
|
|
|
if (!(player1.has_played() && player2.has_played())) return false;
|
2011-06-24 18:59:18 +00:00
|
|
|
|
2011-07-01 18:10:45 +00:00
|
|
|
if (get_colour(player1.get_colour()).empty())
|
2011-06-24 18:59:18 +00:00
|
|
|
{
|
2011-06-29 02:14:55 +00:00
|
|
|
debug("Gamedata::endgame(): player 2 wins\n");
|
2011-06-24 18:59:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-07-01 18:10:45 +00:00
|
|
|
if (get_colour(player2.get_colour()).empty())
|
2011-06-24 18:59:18 +00:00
|
|
|
{
|
2011-06-29 02:14:55 +00:00
|
|
|
debug("Gamedata::endgame(): player 1 wins\n");
|
2011-06-24 18:59:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2011-06-24 16:02:53 +00:00
|
|
|
}
|