void recall::apply_temp_modifier(unit_map& unit_map) { assert(valid()); temp_unit_->set_location(recall_hex_); DBG_WB << "Inserting future recall " << temp_unit_->name() << " [" << temp_unit_->id() << "] at position " << temp_unit_->get_location() << ".\n"; //temporarily remove unit from recall list UnitPtr it = resources::teams->at(team_index()).recall_list().extract_if_matches_id(temp_unit_->id()); assert(it); //Add cost to money spent on recruits. int cost = resources::teams->at(team_index()).recall_cost(); if (it->recall_cost() > -1) { cost = it->recall_cost(); } // Temporarily insert unit into unit_map //unit map takes ownership of temp_unit unit_map.insert(temp_unit_); resources::teams->at(team_index()).get_side_actions()->change_gold_spent_by(cost); // Update gold in top bar resources::screen->invalidate_game_status(); }
void recall::apply_temp_modifier(unit_map& unit_map) { assert(valid_); temp_unit_->set_location(recall_hex_); DBG_WB << "Inserting future recall " << temp_unit_->name() << " [" << temp_unit_->id() << "] at position " << temp_unit_->get_location() << ".\n"; //temporarily remove unit from recall list std::vector<unit>& recalls = resources::teams->at(team_index()).recall_list(); std::vector<unit>::iterator it = std::find_if(recalls.begin(), recalls.end(), unit_comparator_predicate(*temp_unit_)); assert(it != recalls.end()); recalls.erase(it); // Temporarily insert unit into unit_map unit_map.insert(temp_unit_); //unit map takes ownership of temp_unit temp_unit_ = NULL; //Add cost to money spent on recruits. temp_cost_ = resources::teams->at(team_index()).recall_cost(); resources::teams->at(team_index()).get_side_actions()->change_gold_spent_by(temp_cost_); // Update gold in top bar resources::screen->invalidate_game_status(); }
void recruit::execute(bool& success, bool& complete) { assert(valid()); temporary_unit_hider const raii(*fake_unit_); const int side_num = team_index() + 1; //Give back the spent gold so we don't get "not enough gold" message resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(-cost_); bool const result = resources::controller->get_menu_handler().do_recruit(unit_name_, side_num, recruit_hex_); //If it failed, take back the gold if (!result) { resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(cost_); } success = complete = result; }
void recall::remove_temp_modifier(unit_map& unit_map) { temp_unit_ = unit_map.extract(recall_hex_); assert(temp_unit_); //Put unit back into recall list resources::teams->at(team_index()).recall_list().push_back(*temp_unit_); /* * Remove cost from money spent on recruits. */ resources::teams->at(team_index()).get_side_actions()->change_gold_spent_by(-temp_cost_); temp_cost_ = 0; resources::screen->invalidate_game_status(); }
void recall::execute(bool& success, bool& complete) { team & current_team = resources::teams->at(team_index()); assert(valid()); assert(temp_unit_.get()); temporary_unit_hider const raii(*fake_unit_); //Give back the spent gold so we don't get "not enough gold" message int cost = current_team.recall_cost(); if (temp_unit_->recall_cost() > -1) { cost=temp_unit_->recall_cost(); } current_team.get_side_actions()->change_gold_spent_by(-cost); bool const result = synced_context::run_in_synced_context("recall", replay_helper::get_recall(temp_unit_->id(), recall_hex_, map_location::null_location()), true, true, true, synced_context::ignore_error_function); if (!result) { current_team.get_side_actions()->change_gold_spent_by(cost); } success = complete = result; }
void recall::draw_hex(map_location const& hex) { if (hex == recall_hex_) { const double x_offset = 0.5; const double y_offset = 0.7; //position 0,0 in the hex is the upper left corner std::stringstream number_text; unit &it = *get_unit(); int cost = statistics::un_recall_unit_cost(it); if (cost < 0) { number_text << utils::unicode_minus << resources::teams->at(team_index()).recall_cost(); } else { number_text << utils::unicode_minus << cost; } size_t font_size = 16; SDL_Color color; color.r = 255; color.g = 0; color.b = 0; //red resources::screen->draw_text_in_hex(hex, display::LAYER_ACTIONS_NUMBERING, number_text.str(), font_size, color, x_offset, y_offset); } }
void recall::remove_temp_modifier(unit_map& unit_map) { temp_unit_ = unit_map.extract(recall_hex_); assert(temp_unit_.get()); //Put unit back into recall list resources::teams->at(team_index()).recall_list().add(temp_unit_); }
bool recruit::execute() { assert(valid_); fake_unit_->set_hidden(true); int side_num = team_index() + 1; resources::controller->get_menu_handler().do_recruit(unit_name_, side_num, recruit_hex_); return true; }
unit* recruit::create_corresponding_unit() { unit_type const* type = unit_types.find(unit_name_); assert(type); int side_num = team_index() + 1; //real_unit = false needed to avoid generating random traits and causing OOS bool real_unit = false; return new unit(type, side_num, real_unit); }
bool recall::execute() { assert(valid_); assert(temp_unit_); fake_unit_->set_hidden(true); resources::controller->get_menu_handler().do_recall(*temp_unit_, team_index() + 1, recall_hex_); delete temp_unit_; temp_unit_ = NULL; return true; }
void move::init() { // If a unit is invalid, return immediately to avoid crashes such as trying to plan a move for a planned recruit. // As per Bug #18637, this should be fixed so that planning moves on planned recruits work properly. // The alternative is to disable movement on planned recruits altogether, // possibly in select_or_action() where the fake unit is selected in the first place. if (get_unit() == NULL) return; assert(get_unit()); unit_id_ = get_unit()->id(); //This action defines the future position of the unit, make its fake unit more visible //than previous actions' fake units if (fake_unit_) { fake_unit_->anim_comp().set_ghosted(true); } side_actions_ptr side_actions = resources::teams->at(team_index()).get_side_actions(); side_actions::iterator action = side_actions->find_last_action_of(*(get_unit())); if (action != side_actions->end()) { if (move_ptr move = boost::dynamic_pointer_cast<class move>(*action)) { if (move->fake_unit_) move->fake_unit_->anim_comp().set_disabled_ghosted(true); } } this->calculate_move_cost(); // Initialize arrow_brightness_ and arrow_texture_ using arrow_->style_ arrow::STYLE arrow_style = arrow_->get_style(); if(arrow_style == arrow::STYLE_STANDARD) { arrow_brightness_ = ARROW_BRIGHTNESS_STANDARD; arrow_texture_ = ARROW_TEXTURE_VALID; } else if(arrow_style == arrow::STYLE_HIGHLIGHTED) { arrow_brightness_ = ARROW_BRIGHTNESS_HIGHLIGHTED; arrow_texture_ = ARROW_TEXTURE_VALID; } else if(arrow_style == arrow::STYLE_FOCUS) { arrow_brightness_ = ARROW_BRIGHTNESS_FOCUS; arrow_texture_ = ARROW_TEXTURE_VALID; } else if(arrow_style == arrow::STYLE_FOCUS_INVALID) { arrow_brightness_ = ARROW_BRIGHTNESS_STANDARD; arrow_texture_ = ARROW_TEXTURE_INVALID; } }
unit_ptr recruit::create_corresponding_unit() { unit_type const* type = unit_types.find(unit_name_); assert(type); int side_num = team_index() + 1; //real_unit = false needed to avoid generating random traits and causing OOS bool real_unit = false; unit_ptr result(new unit(*type, side_num, real_unit)); result->set_movement(0, true); result->set_attacks(0); return result; //ownership gets transferred to returned unique_ptr copy }
action::error recall::check_validity() const { //Check that destination hex is still free if(resources::units->find(recall_hex_) != resources::units->end()) { return LOCATION_OCCUPIED; } //Check that unit to recall is still in side's recall list if( !(*resources::teams)[team_index()].recall_list().find_if_matches_id(temp_unit_->id()) ) { return UNIT_UNAVAILABLE; } //Check that there is still enough gold to recall this unit if((*resources::teams)[team_index()].recall_cost() > (*resources::teams)[team_index()].gold()) { return NOT_ENOUGH_GOLD; } //Check that there is a leader available to recall this unit if(!find_recruiter(team_index(),get_recall_hex())) { return NO_LEADER; } return OK; }
action::error recruit::check_validity() const { //Check that destination hex is still free if(resources::units->find(recruit_hex_) != resources::units->end()) { return LOCATION_OCCUPIED; } //Check that unit to recruit is still in side's recruit list const std::set<std::string>& recruits = (*resources::teams)[team_index()].recruits(); if(recruits.find(unit_name_) == recruits.end()) { return UNIT_UNAVAILABLE; } //Check that there is still enough gold to recruit this unit if(temp_unit_->cost() > (*resources::teams)[team_index()].gold()) { return NOT_ENOUGH_GOLD; } //Check that there is a leader available to recruit this unit if(!find_recruiter(team_index(),get_recruit_hex())) { return NO_LEADER; } return OK; }
bool move::calculate_new_route(const map_location& source_hex, const map_location& dest_hex) { pathfind::plain_route new_plain_route; pathfind::shortest_path_calculator path_calc(*get_unit(), resources::teams->at(team_index()), *resources::teams, *resources::game_map); new_plain_route = pathfind::a_star_search(source_hex, dest_hex, 10000, &path_calc, resources::game_map->w(), resources::game_map->h()); if (new_plain_route.move_cost >= path_calc.getNoPathValue()) return false; route_.reset(new pathfind::marked_route(pathfind::mark_route(new_plain_route))); calculate_move_cost(); return true; }
void recall::draw_hex(map_location const& hex) { if (hex == recall_hex_) { const double x_offset = 0.5; const double y_offset = 0.7; //position 0,0 in the hex is the upper left corner std::stringstream number_text; number_text << "-" << resources::teams->at(team_index()).recall_cost(); size_t font_size = 16; SDL_Color color; color.r = 255; color.g = 0; color.b = 0; //red resources::screen->draw_text_in_hex(hex, display::LAYER_ACTIONS_NUMBERING, number_text.str(), font_size, color, x_offset, y_offset); } }
void recall::execute(bool& success, bool& complete) { team & current_team = resources::teams->at(team_index()); assert(valid()); assert(temp_unit_.get()); temporary_unit_hider const raii(*fake_unit_); //Give back the spent gold so we don't get "not enough gold" message int cost = current_team.recall_cost(); current_team.get_side_actions()->change_gold_spent_by(-cost); bool const result = actions::recall_unit(temp_unit_->id(), current_team, recall_hex_, map_location::null_location); if (!result) { current_team.get_side_actions()->change_gold_spent_by(cost); } success = complete = result; }
void move::init() { assert(get_unit()); unit_id_ = get_unit()->id(); //This action defines the future position of the unit, make its fake unit more visible //than previous actions' fake units if (fake_unit_) { fake_unit_->set_ghosted(true); } side_actions_ptr side_actions = resources::teams->at(team_index()).get_side_actions(); side_actions::iterator action = side_actions->find_last_action_of(*(get_unit())); if (action != side_actions->end()) { if (move_ptr move = boost::dynamic_pointer_cast<class move>(*action)) { if (move->fake_unit_) move->fake_unit_->set_disabled_ghosted(true); } } this->calculate_move_cost(); // Initialize arrow_brightness_ and arrow_texture_ using arrow_->style_ arrow::STYLE arrow_style = arrow_->get_style(); if(arrow_style == arrow::STYLE_STANDARD) { arrow_brightness_ = ARROW_BRIGHTNESS_STANDARD; arrow_texture_ = ARROW_TEXTURE_VALID; } else if(arrow_style == arrow::STYLE_HIGHLIGHTED) { arrow_brightness_ = ARROW_BRIGHTNESS_HIGHLIGHTED; arrow_texture_ = ARROW_TEXTURE_VALID; } else if(arrow_style == arrow::STYLE_FOCUS) { arrow_brightness_ = ARROW_BRIGHTNESS_FOCUS; arrow_texture_ = ARROW_TEXTURE_VALID; } else if(arrow_style == arrow::STYLE_FOCUS_INVALID) { arrow_brightness_ = ARROW_BRIGHTNESS_STANDARD; arrow_texture_ = ARROW_TEXTURE_INVALID; } }
void recruit::apply_temp_modifier(unit_map& unit_map) { assert(valid()); temp_unit_->set_location(recruit_hex_); DBG_WB << "Inserting future recruit [" << temp_unit_->id() << "] at position " << temp_unit_->get_location() << ".\n"; // Add cost to money spent on recruits. resources::gameboard->teams().at(team_index()).get_side_actions()->change_gold_spent_by(cost_); // Temporarily insert unit into unit_map // unit map takes ownership of temp_unit unit_map.insert(temp_unit_); // Update gold in the top bar game_display::get_singleton()->invalidate_game_status(); }
void recruit::apply_temp_modifier(unit_map& unit_map) { assert(valid_); temp_unit_->set_location(recruit_hex_); DBG_WB << "Inserting future recruit [" << temp_unit_->id() << "] at position " << temp_unit_->get_location() << ".\n"; temp_cost_ = temp_unit_->type()->cost(); // Add cost to money spent on recruits. resources::teams->at(team_index()).get_side_actions()->change_gold_spent_by(temp_cost_); // Temporarily insert unit into unit_map unit_map.insert(temp_unit_); // unit map takes ownership of temp_unit temp_unit_ = NULL; // Update gold in the top bar resources::screen->invalidate_game_status(); }
recall::recall(config const& cfg, bool hidden) : action(cfg,hidden) , temp_unit_() , recall_hex_(cfg.child("recall_hex_")["x"],cfg.child("recall_hex_")["y"]) , fake_unit_() { // Construct and validate temp_unit_ size_t underlying_id = cfg["temp_unit_"]; BOOST_FOREACH(const UnitConstPtr & recall_unit, resources::teams->at(team_index()).recall_list()) { if(recall_unit->underlying_id()==underlying_id) { temp_unit_.reset(new class unit(*recall_unit)); //TODO: is it necessary to make a copy? break; } } if(!temp_unit_.get()) { throw action::ctor_err("recall: Invalid underlying_id"); } fake_unit_.reset(UnitPtr(new class unit(*temp_unit_))); //makes copy of temp_unit_ this->init(); }
recall::recall(config const& cfg, bool hidden) : action(cfg,hidden) , temp_unit_() , recall_hex_(cfg.child("recall_hex_")["x"],cfg.child("recall_hex_")["y"]) , fake_unit_() { // Construct and validate temp_unit_ size_t underlying_id = cfg["temp_unit_"]; BOOST_FOREACH(unit const& recall_unit, resources::teams->at(team_index()).recall_list()) { if(recall_unit.underlying_id()==underlying_id) { temp_unit_.reset(new unit(recall_unit)); break; } } if(!temp_unit_.get()) { throw action::ctor_err("recall: Invalid underlying_id"); } fake_unit_.reset(new game_display::fake_unit(*temp_unit_)); //makes copy of temp_unit_ this->init(); }
void move::execute(bool& success, bool& complete) { if (!valid_) { success = false; //Setting complete to true signifies to side_actions to delete the planned action. complete = true; return; } if (get_source_hex() == get_dest_hex()) { //zero-hex move, used by attack subclass success = complete = true; return; } LOG_WB << "Executing: " << shared_from_this() << "\n"; set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED); hide_fake_unit(); events::mouse_handler& mouse_handler = resources::controller->get_mouse_handler_base(); std::set<map_location> adj_enemies = mouse_handler.get_adj_enemies(get_dest_hex(), side_number()); map_location final_location; bool steps_finished; bool enemy_sighted; { team const& owner_team = resources::teams->at(team_index()); try { steps_finished = mouse_handler.move_unit_along_route(*route_, &final_location, owner_team.auto_shroud_updates(), &enemy_sighted); } catch (end_turn_exception&) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); throw; // we rely on the caller to delete this action } // final_location now contains the final unit location // if that isn't needed, pass NULL rather than &final_location // Also, enemy_sighted now tells whether a unit was sighted during the move } if(mouse_handler.get_adj_enemies(final_location,side_number()) != adj_enemies) enemy_sighted = true; //< "ambushed" on last hex unit_map::const_iterator unit_it; if (final_location == route_->steps.front()) { LOG_WB << "Move execution resulted in zero movement.\n"; success = false; complete = true; } else if (final_location.valid() && (unit_it = resources::units->find(final_location)) != resources::units->end() && unit_it->id() == unit_id_) { if (steps_finished && route_->steps.back() == final_location) //reached destination { complete = true; //check if new enemies are now visible if(enemy_sighted) { LOG_WB << "Move completed, but interrupted on final hex. Halting.\n"; //reset to a single-hex path, just in case *this is a wb::attack arrow_.reset(); route_->steps = std::vector<map_location>(1,route_->steps.back()); success = false; } else // Everything went smoothly success = true; } else // Move was interrupted, probably by enemy unit sighted { success = false; LOG_WB << "Move finished at (" << final_location << ") instead of at (" << get_dest_hex() << "), analyzing\n"; std::vector<map_location>::iterator start_new_path; bool found = false; for (start_new_path = route_->steps.begin(); ((start_new_path != route_->steps.end()) && !found); ++start_new_path) { if (*start_new_path == final_location) { found = true; } } if (found) { --start_new_path; //since the for loop incremented the iterator once after we found the right one. std::vector<map_location> new_path(start_new_path, route_->steps.end()); LOG_WB << "Setting new path for this move from (" << new_path.front() << ") to (" << new_path.back() << ").\n"; //FIXME: probably better to use the new calculate_new_route instead of doing this route_->steps = new_path; arrow_->set_path(new_path); complete = false; } else //Unit ended up in location outside path, likely due to a WML event { WRN_WB << "Unit ended up in location outside path during move execution.\n"; complete = true; } } } else //Unit disappeared from the map, likely due to a WML event { WRN_WB << "Unit disappeared from map during move execution.\n"; success = false; complete = true; } if(!complete) { set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD); show_fake_unit(); } }