#include "game.h" #include "mathutils.h" #include "drawutils.h" #include "debug.h" #include "itos.h" #include Game::Game(stack* state_stack, SDL_Surface* display) : GameState(state_stack, display) { background = NULL; font = NULL; attacker_icon = NULL; defender_icon = NULL; producer_icon = NULL; } Game::~Game() { if (background != NULL) SDL_FreeSurface(background); if (font != NULL) TTF_CloseFont(font); for (list::iterator cursor = buttons.begin(); cursor != buttons.end(); cursor++) { delete *cursor; } } bool Game::init() { background = DrawUtils::load("background.bmp"); font = TTF_OpenFont("res/LiberationSans-Regular.ttf", 12); attacker_icon = DrawUtils::load("attacker_icon.bmp"); defender_icon = DrawUtils::load("defender_icon.bmp"); producer_icon = DrawUtils::load("producer_icon.bmp"); if (background == NULL || font == NULL || attacker_icon == NULL || defender_icon == NULL || producer_icon == NULL) { debug("Game::init(): error: Couldn't load some resource(s)"); return false; } DrawUtils::transpare(attacker_icon); DrawUtils::transpare(defender_icon); DrawUtils::transpare(producer_icon); int row1 = display->h - 95; int row2 = display->h - 50; int col1 = 155; int col2 = 260; int col3 = 365; int col4 = 470; int col5 = 575; int col6 = 680; buttons.push_back(new MenuButton("Move", font, col1, row1, BUTTON_MOVE)); buttons.push_back(new MenuButton("Build", font, col1, row2, BUTTON_BUILD)); buttons.push_back(new MenuButton("Attack", font, col2, row1, BUTTON_ATTACK)); buttons.push_back(new MenuButton("Attacker", font, col3, row1, BUTTON_BUILD_ATTACKER)); buttons.push_back(new MenuButton("Defender", font, col3, row2, BUTTON_BUILD_DEFENDER)); buttons.push_back(new MenuButton("Producer", font, col4, row1, BUTTON_BUILD_PRODUCER)); buttons.push_back(new MenuButton("End Turn", font, col6, row2, BUTTON_END_TURN)); return GameState::init(); } void Game::render() { int range = data.get_range(); int range_colour = 0x888888; switch(data.get_mode()) { case MODE_BUILD: range_colour = 0x0000ff; break; case MODE_MOVE: range_colour = 0x00ff00; break; case MODE_ATTACK: range_colour = 0xff0000; break; } // Background image first DrawUtils::draw(display, background, 0, 0); // Now paint on the targeting circle if (data.get_current_vertex(true) != NULL) { GameVertex* v = data.get_current_vertex(); DrawUtils::draw_circle_filled(display, v->x, v->y, range, range_colour); } // First draw the edges, so that they don't obscure any data list vertices = data.get_vertices(); for (list::iterator cursor = vertices.begin(); cursor != vertices.end(); cursor++) { Vertex* v = *cursor; for (list::iterator subcursor = v->neighbors.begin(); subcursor != v->neighbors.end(); subcursor++) { Vertex* v1 = *subcursor; DrawUtils::draw_line(display, v->x, v->y, v1->x, v1->y, 2, v->colour); } } // highlight the selected vertex and write info about it if (data.get_current_vertex() != NULL) { GameVertex* v = data.get_current_vertex(); DrawUtils::draw_circle(display, v->x, v->y, v->r + 5, 0x000000); draw_stats(v); } // Draw each node for (list::iterator cursor = vertices.begin(); cursor != vertices.end(); cursor++) { GameVertex* v = dynamic_cast(*cursor); draw_node(v); } // draw the rest of the bottom menu // horizontal line across the whole thing DrawUtils::draw_line(display, 0, display->h - 100, display->w, display->h - 100, 2, 0x000000); // vertical line to separate info pane from button pane DrawUtils::draw_line(display, 150, display->h - 100, 150, display->h, 2, 0x000000); { for (list::iterator cursor = buttons.begin(); cursor != buttons.end(); cursor++) { MenuButton* button = *cursor; if (!(button->get_action() & BUTTON_END_TURN) && (data.get_current_vertex() == NULL || data.get_current_vertex()->player != data.get_turn())) continue; if ((button->get_action() & (BUTTON_BUILD_ATTACKER | BUTTON_BUILD_DEFENDER | BUTTON_BUILD_PRODUCER)) && data.get_mode() != MODE_BUILD) continue; draw_button(button); } } draw_player_info(); SDL_Flip(display); } void Game::draw_button(MenuButton* button) { int colour = 0x000000; ButtonAction action = button->get_action(); Mode mode = data.get_mode(); VertexType build_type = data.get_build_type(); // fixme - there's really got to be a better way... if ((action == BUTTON_BUILD && mode == MODE_BUILD) || (action == BUTTON_ATTACK && mode == MODE_ATTACK) || (action == BUTTON_MOVE && mode == MODE_MOVE) || (action == BUTTON_BUILD_ATTACKER && build_type == VERTEX_ATTACKER) || (action == BUTTON_BUILD_DEFENDER && build_type == VERTEX_DEFENDER) || (action == BUTTON_BUILD_PRODUCER && build_type == VERTEX_PRODUCER) ) colour = 0x0000ff; else if (button->is_at(cursor_x, cursor_y)) colour = 0xff0000; button->draw(display, colour); } void Game::draw_node(GameVertex* v) { DrawUtils::draw_circle_filled(display, v->x, v->y, v->r, v->colour); DrawUtils::draw_text(display, itos(v->score), v->x, v->y, font, 0x00ff00, true, true); switch (v->type) { case VERTEX_ATTACKER: DrawUtils::draw(display, attacker_icon, v->x + 5, v-> y + 5); break; case VERTEX_DEFENDER: DrawUtils::draw(display, defender_icon, v->x + 5, v-> y + 5); break; case VERTEX_PRODUCER: DrawUtils::draw(display, producer_icon, v->x + 5, v-> y + 5); break; } } void Game::draw_player_info() { Player* player = data.get_turn(); DrawUtils::draw_text(display, player->get_name(), 680, display->h - 95, font); string temp = "Energy: "; temp += itos(player->get_energy()); DrawUtils::draw_text(display, temp, 680, display->h - 80, font); } void Game::handle_button_press(ButtonAction action) { switch (action) { case BUTTON_BUILD: data.set_mode(MODE_BUILD); break; case BUTTON_ATTACK: data.set_mode(MODE_ATTACK); break; case BUTTON_MOVE: data.set_mode(MODE_MOVE); break; case BUTTON_BUILD_ATTACKER: data.set_build_type(VERTEX_ATTACKER); break; case BUTTON_BUILD_DEFENDER: data.set_build_type(VERTEX_DEFENDER); break; case BUTTON_BUILD_PRODUCER: data.set_build_type(VERTEX_PRODUCER); break; case BUTTON_END_TURN: data.toggle_turn(); break; } } void Game::draw_stats(GameVertex* v) { int line_num = 0; int line_height = 14; int x = 10; int y = display->h - 95; int adj_y = y; DrawUtils::draw_text(display, "player:", x, adj_y, font); DrawUtils::draw_text(display, v->player->get_name(), x + 50, adj_y, font); line_num++; adj_y = y + line_num * line_height; DrawUtils::draw_text(display, "type:", x, adj_y, font); string type; switch(v->type) { case VERTEX_ATTACKER: type = "attacker"; break; case VERTEX_DEFENDER: type = "defender"; break; case VERTEX_PRODUCER: type = "producer"; break; } DrawUtils::draw_text(display, type, x + 50, adj_y, font); line_num++; adj_y = y + line_num * line_height; DrawUtils::draw_text(display, "atk:", x, adj_y, font); DrawUtils::draw_text(display, itos(v->calculate_attack()), x + 50, adj_y, font); line_num++; adj_y = y + line_num * line_height; DrawUtils::draw_text(display, "armor:", x, adj_y, font); DrawUtils::draw_text(display, itos(v->calculate_armor()), x + 50, adj_y, font); line_num++; adj_y = y + line_num * line_height; DrawUtils::draw_text(display, "hp:", x, adj_y, font); DrawUtils::draw_text(display, itos(v->score), x + 50, adj_y, font); if (v->type == VERTEX_PRODUCER) { line_num++; adj_y = y + line_num * line_height; DrawUtils::draw_text(display, "energy:", x, adj_y, font); DrawUtils::draw_text(display, "25", x + 50, adj_y, font); } } void Game::on_lbutton_down(int x, int y) { for (list::iterator cursor = buttons.begin(); cursor != buttons.end(); cursor++) { MenuButton* button = *cursor; if (button->is_at(x, y)) handle_button_press(button->get_action()); } if (y > display->h - 110) return; if (!data.endgame()) data.handle_click(x, y); } void Game::on_rbutton_down(int mX, int mY) { data.clear_current_vertex(); } void Game::on_key_down(SDLKey sym, SDLMod mod, Uint16 unicode) { if (sym == SDLK_q && mod & KMOD_CTRL) throw StateExit(); else if (sym == SDLK_a) data.set_mode(MODE_ATTACK); else if (sym == SDLK_m) data.set_mode(MODE_MOVE); else if (sym == SDLK_b) data.set_mode(MODE_BUILD); else if (sym == SDLK_s || sym == SDLK_ESCAPE) data.set_mode(MODE_SELECT); else if (sym == SDLK_e) data.toggle_turn(); #ifdef DEBUG if (sym == SDLK_d && mod & (KMOD_ALT | KMOD_CTRL)) print_debug_info(); #endif } void Game::on_mouse_move(int mX, int mY, int relX, int relY, bool left, bool right, bool middle) { cursor_x = mX; cursor_y = mY; } #ifdef DEBUG void Game::print_debug_info() { fprintf(stderr, "Mode: %d\n", data.get_mode()); fprintf(stderr, "Turn: %s\n", data.get_turn()->get_name().c_str()); } #endif