00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "manager.hpp"
00021
00022 #include "action.hpp"
00023 #include "highlight_visitor.hpp"
00024 #include "mapbuilder.hpp"
00025 #include "move.hpp"
00026 #include "attack.hpp"
00027 #include "recall.hpp"
00028 #include "recruit.hpp"
00029 #include "side_actions.hpp"
00030 #include "utility.hpp"
00031
00032 #include "actions.hpp"
00033 #include "arrow.hpp"
00034 #include "chat_events.hpp"
00035 #include "foreach.hpp"
00036 #include "formula_string_utils.hpp"
00037 #include "game_preferences.hpp"
00038 #include "gettext.hpp"
00039 #include "gui/dialogs/simple_item_selector.hpp"
00040 #include "key.hpp"
00041 #include "network.hpp"
00042 #include "pathfind/pathfind.hpp"
00043 #include "play_controller.hpp"
00044 #include "resources.hpp"
00045 #include "rng.hpp"
00046 #include "team.hpp"
00047 #include "unit_display.hpp"
00048
00049 #include <boost/lexical_cast.hpp>
00050 #include <sstream>
00051
00052 namespace wb {
00053
00054 manager::manager():
00055 active_(false),
00056 inverted_behavior_(false),
00057 self_activate_once_(true),
00058 print_help_once_(true),
00059 wait_for_side_init_(true),
00060 planned_unit_map_active_(false),
00061 executing_actions_(false),
00062 executing_all_actions_(false),
00063 preparing_to_end_turn_(false),
00064 gamestate_mutated_(false),
00065 activation_state_lock_(new bool),
00066 unit_map_lock_(new bool),
00067 mapbuilder_(),
00068 highlighter_(),
00069 route_(),
00070 move_arrows_(),
00071 fake_units_(),
00072 temp_move_unit_underlying_id_(0),
00073 key_poller_(new CKey),
00074 hidden_unit_hexes_(),
00075 net_buffer_(resources::teams->size()),
00076 team_plans_hidden_(resources::teams->size(),preferences::hide_whiteboard()),
00077 units_owning_moves_()
00078 {
00079 LOG_WB << "Manager initialized.\n";
00080 }
00081
00082 manager::~manager()
00083 {
00084 LOG_WB << "Manager destroyed.\n";
00085 }
00086
00087
00088 #if 0
00089 static void print_to_chat(const std::string& title, const std::string& message)
00090 {
00091 resources::screen->add_chat_message(time(NULL), title, 0, message,
00092 events::chat_handler::MESSAGE_PRIVATE, false);
00093 }
00094 #endif
00095
00096 void manager::print_help_once()
00097 {
00098 #if 0
00099 if (!print_help_once_)
00100 return;
00101 else
00102 print_help_once_ = false;
00103
00104 print_to_chat("whiteboard", std::string("Type :wb to activate/deactivate planning mode.")
00105 + " Hold TAB to temporarily deactivate/activate it.");
00106 std::stringstream hotkeys;
00107 const hotkey::hotkey_item& hk_execute = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ACTION);
00108 if(!hk_execute.null()) {
00109
00110 hotkeys << "Execute: " << hk_execute.get_name() << ", ";
00111 }
00112 const hotkey::hotkey_item& hk_execute_all = hotkey::get_hotkey(hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS);
00113 if(!hk_execute_all.null()) {
00114
00115 hotkeys << "Execute all: " << hk_execute_all.get_name() << ", ";
00116 }
00117 const hotkey::hotkey_item& hk_delete = hotkey::get_hotkey(hotkey::HOTKEY_WB_DELETE_ACTION);
00118 if(!hk_delete.null()) {
00119
00120 hotkeys << "Delete: " << hk_delete.get_name() << ", ";
00121 }
00122 const hotkey::hotkey_item& hk_bump_up = hotkey::get_hotkey(hotkey::HOTKEY_WB_BUMP_UP_ACTION);
00123 if(!hk_bump_up.null()) {
00124
00125 hotkeys << "Move earlier: " << hk_bump_up.get_name() << ", ";
00126 }
00127 const hotkey::hotkey_item& hk_bump_down = hotkey::get_hotkey(hotkey::HOTKEY_WB_BUMP_DOWN_ACTION);
00128 if(!hk_bump_down.null()) {
00129
00130 hotkeys << "Move later: " << hk_bump_down.get_name() << ", ";
00131 }
00132 print_to_chat("HOTKEYS:", hotkeys.str() + "\n");
00133 #endif
00134 }
00135
00136 bool manager::can_modify_game_state() const
00137 {
00138 if(wait_for_side_init_
00139 || resources::teams == NULL
00140 || executing_actions_
00141 || is_observer()
00142 || resources::controller->is_linger_mode())
00143 {
00144 return false;
00145 }
00146 else
00147 {
00148 return true;
00149 }
00150 }
00151
00152 bool manager::can_activate() const
00153 {
00154
00155 if(!activation_state_lock_.unique())
00156 return false;
00157
00158 return can_modify_game_state();
00159 }
00160
00161 void manager::set_active(bool active)
00162 {
00163 if(!can_activate())
00164 {
00165 active_ = false;
00166 LOG_WB << "Whiteboard can't be activated now.\n";
00167 }
00168 else if (active != active_)
00169 {
00170 active_ = active;
00171 erase_temp_move();
00172
00173 if (active_)
00174 {
00175 if(should_clear_undo())
00176 clear_undo();
00177 validate_viewer_actions();
00178 LOG_WB << "Whiteboard activated! " << *viewer_actions() << "\n";
00179 create_temp_move();
00180 } else {
00181 LOG_WB << "Whiteboard deactivated!\n";
00182 }
00183 }
00184 }
00185
00186 void manager::set_invert_behavior(bool invert)
00187 {
00188
00189 if(!activation_state_lock_.unique())
00190 return;
00191
00192 bool block_whiteboard_activation = false;
00193 if(!can_activate())
00194 {
00195 block_whiteboard_activation = true;
00196 }
00197
00198 if (invert)
00199 {
00200 if (!inverted_behavior_)
00201 {
00202 if (active_)
00203 {
00204 DBG_WB << "Whiteboard deactivated temporarily.\n";
00205 inverted_behavior_ = true;
00206 set_active(false);
00207 }
00208 else if (!block_whiteboard_activation)
00209 {
00210 DBG_WB << "Whiteboard activated temporarily.\n";
00211 inverted_behavior_ = true;
00212 set_active(true);
00213 }
00214 }
00215 }
00216 else
00217 {
00218 if (inverted_behavior_)
00219 {
00220 if (active_)
00221 {
00222 DBG_WB << "Whiteboard set back to deactivated status.\n";
00223 inverted_behavior_ = false;
00224 set_active(false);
00225 }
00226 else if (!block_whiteboard_activation)
00227 {
00228 DBG_WB << "Whiteboard set back to activated status.\n";
00229 inverted_behavior_ = false;
00230 set_active(true);
00231 }
00232 }
00233 }
00234 }
00235
00236 bool manager::can_enable_execution_hotkeys() const
00237 {
00238 return can_enable_modifier_hotkeys() && viewer_side() == resources::controller->current_side()
00239 && viewer_actions()->turn_size(0) > 0;
00240 }
00241
00242 bool manager::can_enable_modifier_hotkeys() const
00243 {
00244 return can_modify_game_state() && !viewer_actions()->empty();
00245 }
00246
00247 bool manager::can_enable_reorder_hotkeys() const
00248 {
00249 return can_enable_modifier_hotkeys() && highlighter_ && highlighter_->get_bump_target();
00250 }
00251
00252 bool manager::allow_leader_to_move(unit const& leader) const
00253 {
00254 if(!has_actions())
00255 return true;
00256
00257
00258 { wb::future_map future;
00259 if(!has_planned_unit_map()) {
00260 WRN_WB << "Unable to build future map to determine whether leader's allowed to move.\n";
00261 }
00262 if(find_backup_leader(leader))
00263 return true;
00264 }
00265
00266 if(viewer_actions()->empty()) {
00267 return true;
00268 }
00269
00270
00271 foreach(action_const_ptr action, *viewer_actions())
00272 {
00273 recruit_const_ptr recruit = boost::dynamic_pointer_cast<class recruit const>(action);
00274 recall_const_ptr recall = boost::dynamic_pointer_cast<class recall const>(action);
00275 if(recruit || recall)
00276 {
00277 map_location const target_hex = recruit?recruit->get_recruit_hex():recall->get_recall_hex();
00278 if (can_recruit_on(*resources::game_map, leader.get_location(), target_hex))
00279 return false;
00280 }
00281 }
00282 return true;
00283 }
00284
00285 void manager::on_init_side()
00286 {
00287
00288 assert(!executing_all_actions_ && !executing_actions_);
00289
00290 update_plan_hiding();
00291 wait_for_side_init_ = false;
00292 LOG_WB << "on_init_side()\n";
00293
00294 if (self_activate_once_ && preferences::enable_whiteboard_mode_on_start())
00295 {
00296 self_activate_once_ = false;
00297 set_active(true);
00298 }
00299 }
00300
00301 void manager::on_finish_side_turn(int side)
00302 {
00303 preparing_to_end_turn_ = false;
00304 wait_for_side_init_ = true;
00305 if(side == viewer_side() && !viewer_actions()->empty()) {
00306 viewer_actions()->synced_turn_shift();
00307 }
00308 highlighter_.reset();
00309 erase_temp_move();
00310 LOG_WB << "on_finish_side_turn()\n";
00311 }
00312
00313 void manager::pre_delete_action(action_ptr)
00314 {
00315 }
00316
00317 void manager::post_delete_action(action_ptr action)
00318 {
00319
00320
00321
00322
00323 side_actions_ptr side_actions = resources::teams->at(action->team_index()).get_side_actions();
00324
00325 side_actions::iterator action_it = side_actions->find_last_action_of(action->get_unit());
00326 if (action_it != side_actions->end())
00327 {
00328 if (move_ptr move = boost::dynamic_pointer_cast<class move>(*action_it))
00329 {
00330 if (move->get_fake_unit())
00331 move->get_fake_unit()->set_standing(true);
00332 }
00333 }
00334 }
00335
00336 static void hide_all_plans()
00337 {
00338 foreach(team& t, *resources::teams)
00339 t.get_side_actions()->hide();
00340 }
00341
00342
00343 void manager::update_plan_hiding(size_t team_index)
00344 {
00345
00346 if(!resources::teams->at(team_index).is_human())
00347 hide_all_plans();
00348 else
00349 {
00350 foreach(team& t, *resources::teams)
00351 {
00352
00353 if(!t.is_network_human())
00354 team_plans_hidden_[t.side()-1] = false;
00355
00356 if(t.is_enemy(team_index+1) || team_plans_hidden_[t.side()-1])
00357 t.get_side_actions()->hide();
00358 else
00359 t.get_side_actions()->show();
00360 }
00361 }
00362 resources::teams->at(team_index).get_side_actions()->validate_actions();
00363 }
00364 void manager::update_plan_hiding()
00365 {update_plan_hiding(viewer_team());}
00366
00367 void manager::on_viewer_change(size_t team_index)
00368 {
00369 if(!wait_for_side_init_)
00370 update_plan_hiding(team_index);
00371 }
00372
00373 void manager::on_change_controller(int side, team& t)
00374 {
00375 wb::side_actions& sa = *t.get_side_actions();
00376 if(t.is_human())
00377 {
00378
00379 resources::whiteboard->queue_net_cmd(sa.team_index(),sa.make_net_cmd_clear());
00380 sa.clear();
00381
00382 update_plan_hiding();
00383 }
00384 else if(t.is_ai() || t.is_network_ai())
00385 sa.clear();
00386 else if(t.is_network())
00387 {
00388 if(side==viewer_side())
00389 hide_all_plans();
00390
00391
00392 size_t num_teams = resources::teams->size();
00393 for(size_t i=0; i<num_teams; ++i)
00394 {
00395 team& local_team = resources::teams->at(i);
00396 if(local_team.is_human() && !local_team.is_enemy(side))
00397 resources::whiteboard->queue_net_cmd(i,local_team.get_side_actions()->make_net_cmd_refresh());
00398 }
00399 }
00400 }
00401
00402 bool manager::current_side_has_actions()
00403 {
00404 if(current_side_actions()->empty()) {
00405 return false;
00406 }
00407
00408 side_actions::range_t range = current_side_actions()->iter_turn(0);
00409 return range.first != range.second;
00410 }
00411
00412 void manager::validate_viewer_actions()
00413 {
00414 assert(!executing_actions_);
00415 LOG_WB << "'gamestate_mutated_' flag dirty, validating actions.\n";
00416 gamestate_mutated_ = false;
00417 if (viewer_actions()->empty()) return;
00418 viewer_actions()->validate_actions();
00419 }
00420
00421
00422 static void draw_numbers(map_location const& hex, side_actions::numbers_t numbers)
00423 {
00424 std::vector<int>& numbers_to_draw = numbers.numbers_to_draw;
00425 std::vector<size_t>& team_numbers = numbers.team_numbers;
00426 int& main_number = numbers.main_number;
00427 std::set<size_t>& secondary_numbers = numbers.secondary_numbers;
00428
00429 const double x_offset_base = 0.0;
00430 const double y_offset_base = 0.2;
00431
00432
00433 const double x_origin = 0.8 - numbers_to_draw.size() * x_offset_base;
00434
00435 const double y_origin = 0.5 - numbers_to_draw.size() * (y_offset_base / 2);
00436 double x_offset = 0, y_offset = 0;
00437
00438 size_t size = numbers_to_draw.size();
00439 for(size_t i=0; i<size; ++i)
00440 {
00441 int number = numbers_to_draw[i];
00442
00443 std::string number_text = boost::lexical_cast<std::string>(number);
00444 size_t font_size;
00445 if (int(i) == main_number) font_size = 19;
00446 else if (secondary_numbers.find(i)!=secondary_numbers.end()) font_size = 17;
00447 else font_size = 15;
00448
00449 SDL_Color color = team::get_side_color(static_cast<int>(team_numbers[i]+1));
00450 const double x_in_hex = x_origin + x_offset;
00451 const double y_in_hex = y_origin + y_offset;
00452 resources::screen->draw_text_in_hex(hex, display::LAYER_ACTIONS_NUMBERING,
00453 number_text, font_size, color, x_in_hex, y_in_hex);
00454 x_offset += x_offset_base;
00455 y_offset += y_offset_base;
00456 }
00457 }
00458
00459
00460 namespace
00461 {
00462
00463
00464 struct move_owners_finder
00465 : private enable_visit_all<move_owners_finder>, public visitor
00466 {
00467 friend class enable_visit_all<move_owners_finder>;
00468
00469 public:
00470 move_owners_finder()
00471 : move_owners_()
00472 {
00473
00474 visit_all_actions();
00475 }
00476
00477 std::set<size_t> const& get_units_owning_moves() {
00478 return move_owners_;
00479 }
00480
00481 private:
00482 virtual void visit(move_ptr move) {
00483 move_owners_.insert(move->get_unit()->underlying_id());
00484 }
00485 virtual void visit(attack_ptr attack) {
00486
00487 if (boost::static_pointer_cast<move>(attack)->get_route().steps.size() >= 2) {
00488 move_owners_.insert(attack->get_unit()->underlying_id());
00489 }
00490 }
00491 virtual void visit(recruit_ptr){}
00492 virtual void visit(recall_ptr){}
00493 virtual void visit(suppose_dead_ptr){}
00494
00495 std::set<size_t> move_owners_;
00496 };
00497 }
00498
00499 void manager::pre_draw()
00500 {
00501 if (can_modify_game_state() && has_actions())
00502 {
00503 units_owning_moves_ = move_owners_finder().get_units_owning_moves();
00504 foreach(size_t unit_id, units_owning_moves_)
00505 {
00506 unit_map::iterator unit_iter = resources::units->find(unit_id);
00507 assert(unit_iter.valid());
00508 ghost_owner_unit(&*unit_iter);
00509 }
00510 }
00511 }
00512
00513 void manager::post_draw()
00514 {
00515 foreach(size_t unit_id, units_owning_moves_)
00516 {
00517 unit_map::iterator unit_iter = resources::units->find(unit_id);
00518 if (unit_iter.valid()) {
00519 unghost_owner_unit(&*unit_iter);
00520 }
00521 }
00522 units_owning_moves_.clear();
00523 }
00524
00525 namespace
00526 {
00527
00528 struct draw_visitor
00529 : private enable_visit_all<draw_visitor>
00530 {
00531 friend class enable_visit_all<draw_visitor>;
00532
00533 public:
00534 draw_visitor(map_location const& hex): hex_(hex) {}
00535
00536 using enable_visit_all<draw_visitor>::visit_all;
00537
00538 private:
00539
00540 bool process(size_t , team&, side_actions&, side_actions::iterator itor)
00541 { (*itor)->draw_hex(hex_); return true; }
00542
00543
00544
00545 map_location const& hex_;
00546 };
00547 }
00548
00549 void manager::draw_hex(const map_location& hex)
00550 {
00551
00552
00553
00554
00555
00556
00557 if (!wait_for_side_init_ && has_actions())
00558 {
00559
00560 draw_visitor(hex).visit_all();
00561
00562
00563 side_actions::numbers_t numbers;
00564 foreach(team& t, *resources::teams)
00565 {
00566 side_actions& sa = *t.get_side_actions();
00567 if(!sa.hidden())
00568 sa.get_numbers(hex,numbers);
00569 }
00570 draw_numbers(hex,numbers);
00571 }
00572
00573 }
00574
00575 void manager::on_mouseover_change(const map_location& hex)
00576 {
00577
00578 map_location selected_hex = resources::controller->get_mouse_handler_base().get_selected_hex();
00579 bool hex_has_unit;
00580 { wb::future_map future;
00581 hex_has_unit = resources::units->find(selected_hex) != resources::units->end();
00582 }
00583 if (!((selected_hex.valid() && hex_has_unit)
00584 || has_temp_move() || wait_for_side_init_ || executing_actions_))
00585 {
00586 if (!highlighter_)
00587 {
00588 highlighter_.reset(new highlight_visitor(*resources::units, viewer_actions()));
00589 }
00590 highlighter_->set_mouseover_hex(hex);
00591 highlighter_->highlight();
00592 }
00593 }
00594
00595 void manager::on_gamestate_change()
00596 {
00597 DBG_WB << "Manager received gamestate change notification.\n";
00598
00599
00600 assert(!planned_unit_map_active_);
00601
00602 gamestate_mutated_ = true;
00603
00604 resources::screen->clear_exclusive_draws();
00605 }
00606
00607 void manager::send_network_data()
00608 {
00609 size_t size = net_buffer_.size();
00610 for(size_t team_index=0; team_index<size; ++team_index)
00611 {
00612 config& buf_cfg = net_buffer_[team_index];
00613
00614 if(buf_cfg.empty())
00615 continue;
00616
00617 config packet;
00618 config& wb_cfg = packet.add_child("whiteboard",buf_cfg);
00619 wb_cfg["side"] = static_cast<int>(team_index+1);
00620 wb_cfg["team_name"] = resources::teams->at(team_index).team_name();
00621
00622 buf_cfg = config();
00623
00624 network::send_data(packet,0,"whiteboard");
00625
00626 size_t count = wb_cfg.child_count("net_cmd");
00627 LOG_WB << "Side " << (team_index+1) << " sent wb data (" << count << " cmds).\n";
00628 }
00629 }
00630
00631 void manager::process_network_data(config const& cfg)
00632 {
00633 if(config const& wb_cfg = cfg.child("whiteboard"))
00634 {
00635 size_t count = wb_cfg.child_count("net_cmd");
00636 LOG_WB << "Received wb data (" << count << ").\n";
00637
00638 team& team_from = resources::teams->at(wb_cfg["side"]-1);
00639 foreach(side_actions::net_cmd const& cmd, wb_cfg.child_range("net_cmd"))
00640 team_from.get_side_actions()->execute_net_cmd(cmd);
00641 }
00642 }
00643
00644 void manager::queue_net_cmd(size_t team_index, side_actions::net_cmd const& cmd)
00645 {
00646 net_buffer_[team_index].add_child("net_cmd",cmd);
00647 }
00648
00649 void manager::create_temp_move()
00650 {
00651 route_.reset();
00652
00653
00654
00655
00656
00657
00658 if(!active_
00659 || wait_for_side_init_
00660 || executing_actions_
00661 || is_observer()
00662 || resources::controller->is_linger_mode())
00663 return;
00664
00665 pathfind::marked_route const& route =
00666 resources::controller->get_mouse_handler_base().get_current_route();
00667
00668 if (route.steps.empty() || route.steps.size() < 2) return;
00669
00670 unit const* selected_unit =
00671 future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
00672 if (!selected_unit) return;
00673 if (selected_unit->side() != resources::screen->viewing_side()) return;
00674
00675
00676
00677
00678
00679
00680 temp_move_unit_underlying_id_ = selected_unit->underlying_id();
00681
00682
00683
00684
00685 route_.reset(new pathfind::marked_route(route));
00686
00687
00688 size_t turn = 0;
00689 std::vector<map_location>::iterator prev_itor = route.steps.begin();
00690 std::vector<map_location>::iterator curr_itor = prev_itor;
00691 std::vector<map_location>::iterator end_itor = route.steps.end();
00692 for(; curr_itor!=end_itor; ++curr_itor)
00693 {
00694 const map_location& hex = *curr_itor;
00695
00696
00697 pathfind::marked_route::mark_map::const_iterator w =
00698 route.marks.find(hex);
00699 if(w != route.marks.end() && w->second.turns > 0)
00700 {
00701 turn = w->second.turns-1;
00702
00703 if(turn >= move_arrows_.size())
00704 move_arrows_.resize(turn+1);
00705 if(turn >= fake_units_.size())
00706 fake_units_.resize(turn+1);
00707
00708 arrow_ptr& move_arrow = move_arrows_[turn];
00709 fake_unit_ptr& fake_unit = fake_units_[turn];
00710
00711 if(!move_arrow)
00712 {
00713
00714 move_arrow.reset(new arrow());
00715 move_arrow->set_color(team::get_side_color_index(
00716 viewer_side()));
00717 move_arrow->set_style(arrow::STYLE_HIGHLIGHTED);
00718 }
00719
00720 arrow_path_t path(prev_itor,curr_itor+1);
00721 move_arrow->set_path(path);
00722
00723 if(path.size() >= 2)
00724 {
00725 if(!fake_unit)
00726 {
00727
00728 fake_unit.reset(new game_display::fake_unit(*selected_unit));
00729 fake_unit->place_on_game_display( resources::screen);
00730 fake_unit->set_ghosted(true);
00731 }
00732
00733 unit_display::move_unit(path, *fake_unit, *resources::teams,
00734 false);
00735 fake_unit->invalidate(fake_unit->get_location());
00736 fake_unit->set_location(*curr_itor);
00737 fake_unit->set_ghosted(true);
00738 }
00739 else
00740 fake_unit.reset();
00741
00742 prev_itor = curr_itor;
00743 }
00744 }
00745
00746 int ind = fake_units_.size() - 1;
00747 fake_units_[ind]->invalidate(fake_units_[ind]->get_location());
00748
00749 move_arrows_.resize(turn+1);
00750 fake_units_.resize(turn+1);
00751 }
00752
00753 void manager::erase_temp_move()
00754 {
00755 move_arrows_.clear();
00756 foreach(fake_unit_ptr const& tmp, fake_units_) {
00757 if(tmp) {
00758 tmp->invalidate(tmp->get_location());
00759 }
00760 }
00761 fake_units_.clear();
00762 route_.reset();
00763 temp_move_unit_underlying_id_ = 0;
00764 }
00765
00766 void manager::save_temp_move()
00767 {
00768 if (has_temp_move() && !executing_actions_ && !resources::controller->is_linger_mode())
00769 {
00770 side_actions& sa = *viewer_actions();
00771 unit* u = future_visible_unit(route_->steps.front());
00772 assert(u);
00773 size_t first_turn = sa.get_turn_num_of(*u);
00774
00775 on_save_action(u);
00776
00777 assert(move_arrows_.size() == fake_units_.size());
00778 size_t size = move_arrows_.size();
00779 for(size_t i=0; i<size; ++i)
00780 {
00781 arrow_ptr move_arrow = move_arrows_[i];
00782 if(!arrow::valid_path(move_arrow->get_path()))
00783 continue;
00784
00785 size_t turn = first_turn + i;
00786 fake_unit_ptr fake_unit = fake_units_[i];
00787
00788
00789
00790 pathfind::marked_route route;
00791 route.steps = move_arrow->get_path();
00792 route.move_cost = path_cost(route.steps,*u);
00793
00794 sa.queue_move(turn,*u,route,move_arrow,fake_unit);
00795 }
00796 erase_temp_move();
00797
00798 LOG_WB << *viewer_actions() << "\n";
00799 print_help_once();
00800 }
00801 }
00802
00803 unit_map::iterator manager::get_temp_move_unit() const
00804 {
00805 return resources::units->find(temp_move_unit_underlying_id_);
00806 }
00807
00808 void manager::save_temp_attack(const map_location& attacker_loc, const map_location& defender_loc, int weapon_choice)
00809 {
00810 if (active_ && !executing_actions_ && !resources::controller->is_linger_mode())
00811 {
00812 assert(weapon_choice >= 0);
00813
00814 arrow_ptr move_arrow;
00815 fake_unit_ptr fake_unit;
00816 map_location source_hex;
00817
00818 if (route_ && !route_->steps.empty())
00819 {
00820
00821 assert(move_arrows_.size() == 1);
00822 assert(fake_units_.size() == 1);
00823 move_arrow = move_arrows_.front();
00824 fake_unit = fake_units_.front();
00825
00826 assert(route_->steps.back() == attacker_loc);
00827 source_hex = route_->steps.front();
00828
00829 fake_unit->set_disabled_ghosted(true);
00830 }
00831 else
00832 {
00833
00834 move_arrow.reset(new arrow);
00835 source_hex = attacker_loc;
00836 route_.reset(new pathfind::marked_route);
00837
00838 route_->steps.push_back(attacker_loc);
00839 }
00840
00841 unit* attacking_unit = future_visible_unit(source_hex);
00842 assert(attacking_unit);
00843
00844 on_save_action(attacking_unit);
00845
00846 side_actions& sa = *viewer_actions();
00847 sa.queue_attack(sa.get_turn_num_of(*attacking_unit),*attacking_unit,defender_loc,weapon_choice,*route_,move_arrow,fake_unit);
00848
00849 print_help_once();
00850
00851 resources::screen->invalidate(defender_loc);
00852 resources::screen->invalidate(attacker_loc);
00853 erase_temp_move();
00854 LOG_WB << *viewer_actions() << "\n";
00855 }
00856 }
00857
00858 bool manager::save_recruit(const std::string& name, int side_num, const map_location& recruit_hex)
00859 {
00860 bool created_planned_recruit = false;
00861
00862 if (active_ && !executing_actions_ && !resources::controller->is_linger_mode()) {
00863 if (side_num != resources::screen->viewing_side())
00864 {
00865 LOG_WB <<"manager::save_recruit called for a different side than viewing side.\n";
00866 created_planned_recruit = false;
00867 }
00868 else
00869 {
00870 on_save_action(NULL);
00871
00872 side_actions& sa = *viewer_actions();
00873 unit* recruiter;
00874 { wb::future_map raii;
00875 recruiter = find_recruiter(side_num-1,recruit_hex);
00876 }
00877 assert(recruiter);
00878 size_t turn = sa.get_turn_num_of(*recruiter);
00879 sa.queue_recruit(turn,name,recruit_hex);
00880 created_planned_recruit = true;
00881
00882 print_help_once();
00883 }
00884 }
00885 return created_planned_recruit;
00886 }
00887
00888 bool manager::save_recall(const unit& unit, int side_num, const map_location& recall_hex)
00889 {
00890 bool created_planned_recall = false;
00891
00892 if (active_ && !executing_actions_ && !resources::controller->is_linger_mode())
00893 {
00894 if (side_num != resources::screen->viewing_side())
00895 {
00896 LOG_WB <<"manager::save_recall called for a different side than viewing side.\n";
00897 created_planned_recall = false;
00898 }
00899 else
00900 {
00901 on_save_action(NULL);
00902
00903 side_actions& sa = *viewer_actions();
00904 size_t turn = sa.num_turns();
00905 if(turn > 0)
00906 --turn;
00907 sa.queue_recall(turn,unit,recall_hex);
00908 created_planned_recall = true;
00909
00910 print_help_once();
00911 }
00912 }
00913 return created_planned_recall;
00914 }
00915
00916 void manager::save_suppose_dead(unit& curr_unit, map_location const& loc)
00917 {
00918 if(active_ && !executing_actions_ && !resources::controller->is_linger_mode())
00919 {
00920 on_save_action(&curr_unit);
00921 side_actions& sa = *viewer_actions();
00922 sa.queue_suppose_dead(sa.get_turn_num_of(curr_unit),curr_unit,loc);
00923 }
00924 }
00925
00926 void manager::on_save_action(unit const* u) const
00927 {
00928 if(u)
00929 viewer_actions()->remove_invalid_of(u);
00930 }
00931
00932 void manager::contextual_execute()
00933 {
00934 validate_viewer_actions();
00935 if (can_enable_execution_hotkeys())
00936 {
00937 erase_temp_move();
00938
00939
00940 variable_finalizer<bool> finally(executing_actions_, false);
00941
00942 action_ptr action;
00943 side_actions::iterator it;
00944 unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
00945 if (selected_unit &&
00946 (it = viewer_actions()->find_first_action_of(selected_unit)) != viewer_actions()->end())
00947 {
00948 executing_actions_ = true;
00949 viewer_actions()->execute(it);
00950 }
00951 else if (highlighter_ && (action = highlighter_->get_execute_target()) &&
00952 (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end())
00953 {
00954 executing_actions_ = true;
00955 viewer_actions()->execute(it);
00956 }
00957 else
00958 {
00959 executing_actions_ = true;
00960 viewer_actions()->execute_next();
00961 }
00962 }
00963 }
00964
00965 bool manager::allow_end_turn()
00966 {
00967 preparing_to_end_turn_ = true;
00968 return execute_all_actions();
00969 }
00970
00971 bool manager::execute_all_actions()
00972 {
00973
00974
00975 variable_finalizer<bool> finalize_executing_actions(executing_actions_, false);
00976 variable_finalizer<bool> finalize_executing_all_actions(executing_all_actions_, false);
00977
00978 validate_viewer_actions();
00979 if(viewer_actions()->empty() || viewer_actions()->turn_size(0) == 0)
00980 {
00981
00982 return true;
00983 }
00984
00985 assert(can_enable_execution_hotkeys());
00986
00987 erase_temp_move();
00988
00989
00990 set_planned_unit_map();
00991 assert(has_planned_unit_map());
00992 set_real_unit_map();
00993
00994 executing_actions_ = true;
00995 executing_all_actions_ = true;
00996
00997 side_actions_ptr sa = viewer_actions();
00998
00999 if (resources::whiteboard->has_planned_unit_map())
01000 {
01001 ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
01002 }
01003
01004
01005
01006 while (sa->turn_begin(0) != sa->turn_end(0))
01007 {
01008 bool action_successful = sa->execute(sa->begin());
01009
01010
01011 if ( rand_rng::has_new_seed_callback())
01012 {
01013
01014 finalize_executing_all_actions.clear();
01015
01016 events::commands_disabled++;
01017 return false;
01018 }
01019
01020 if (!action_successful)
01021 {
01022 return false;
01023 }
01024 }
01025 return true;
01026 }
01027
01028 void manager::continue_execute_all()
01029 {
01030 if (executing_all_actions_ && !rand_rng::has_new_seed_callback()) {
01031 events::commands_disabled--;
01032 if (execute_all_actions()) {
01033 resources::controller->force_end_turn();
01034 }
01035 }
01036 }
01037
01038 void manager::contextual_delete()
01039 {
01040 validate_viewer_actions();
01041 if (can_enable_modifier_hotkeys())
01042 {
01043 erase_temp_move();
01044
01045 action_ptr action;
01046 side_actions::iterator it;
01047 unit const* selected_unit = future_visible_unit(resources::controller->get_mouse_handler_base().get_selected_hex(), viewer_side());
01048 if (selected_unit &&
01049 (it = viewer_actions()->find_first_action_of(selected_unit)) != viewer_actions()->end())
01050 {
01051
01052 viewer_actions()->remove_action(it);
01053
01054 }
01055 else if (highlighter_ && (action = highlighter_->get_delete_target()) &&
01056 (it = viewer_actions()->get_position_of(action)) != viewer_actions()->end())
01057 {
01058 viewer_actions()->remove_action(it);
01059 viewer_actions()->remove_invalid_of(action->get_unit());
01060 highlighter_->set_mouseover_hex(highlighter_->get_mouseover_hex());
01061 highlighter_->highlight();
01062 }
01063 else
01064 {
01065 it = (viewer_actions()->end() - 1);
01066 action = *it;
01067 viewer_actions()->remove_action(it);
01068 viewer_actions()->remove_invalid_of(action->get_unit());
01069 }
01070 }
01071 }
01072
01073 void manager::contextual_bump_up_action()
01074 {
01075 validate_viewer_actions();
01076 if(can_enable_reorder_hotkeys())
01077 {
01078 action_ptr action = highlighter_->get_bump_target();
01079 if (action)
01080 {
01081 viewer_actions()->bump_earlier(viewer_actions()->get_position_of(action));
01082 }
01083 }
01084 }
01085
01086 void manager::contextual_bump_down_action()
01087 {
01088 validate_viewer_actions();
01089 if(can_enable_reorder_hotkeys())
01090 {
01091 action_ptr action = highlighter_->get_bump_target();
01092 if (action)
01093 {
01094 viewer_actions()->bump_later(viewer_actions()->get_position_of(action));
01095 }
01096 }
01097 }
01098
01099 bool manager::has_actions() const
01100 {
01101 assert(!wait_for_side_init_);
01102 return wb::has_actions();
01103 }
01104
01105 bool manager::unit_has_actions(unit const* unit) const
01106 {
01107 assert(!wait_for_side_init_);
01108 return viewer_actions()->unit_has_actions(unit);
01109 }
01110
01111 int manager::get_spent_gold_for(int side)
01112 {
01113 if(wait_for_side_init_)
01114 return 0;
01115
01116 return resources::teams->at(side - 1).get_side_actions()->get_gold_spent();
01117 }
01118
01119 void manager::clear_undo()
01120 {
01121 apply_shroud_changes(*resources::undo_stack, viewer_side());
01122 resources::undo_stack->clear();
01123 resources::redo_stack->clear();
01124 }
01125
01126 void manager::options_dlg()
01127 {
01128 int v_side = viewer_side();
01129
01130 int selection = 0;
01131
01132 std::vector<team*> allies;
01133 std::vector<std::string> options;
01134 utils::string_map t_vars;
01135
01136 options.push_back(_("SHOW ALL allies’ plans"));
01137 options.push_back(_("HIDE ALL allies’ plans"));
01138
01139
01140 foreach(team &t, *resources::teams)
01141 {
01142
01143 if(t.is_enemy(v_side) || !t.is_network())
01144 continue;
01145
01146 allies.push_back(&t);
01147
01148 t_vars["player"] = t.current_player();
01149 size_t t_index = t.side()-1;
01150 if(team_plans_hidden_[t_index])
01151 options.push_back(vgettext("Show plans for $player", t_vars));
01152 else
01153 options.push_back(vgettext("Hide plans for $player", t_vars));
01154 }
01155
01156 gui2::tsimple_item_selector dlg("", _("Whiteboard Options"), options);
01157 dlg.show(resources::screen->video());
01158 selection = dlg.selected_index();
01159
01160 if(selection == -1)
01161 return;
01162
01163 switch(selection)
01164 {
01165 case 0:
01166 foreach(team* t, allies)
01167 team_plans_hidden_[t->side()-1]=false;
01168 break;
01169 case 1:
01170 foreach(team* t, allies)
01171 team_plans_hidden_[t->side()-1]=true;
01172 break;
01173 default:
01174 if(selection > 1)
01175 {
01176 size_t t_index = allies[selection-2]->side()-1;
01177
01178 bool hidden = team_plans_hidden_[t_index];
01179 team_plans_hidden_[t_index] = !hidden;
01180 }
01181 break;
01182 }
01183 update_plan_hiding();
01184 }
01185
01186 void manager::set_planned_unit_map()
01187 {
01188 if (!can_modify_game_state()) {
01189 LOG_WB << "Not building planned unit map: cannot modify game state now.\n";
01190 return;
01191 }
01192
01193 if(!unit_map_lock_.unique()) {
01194 LOG_WB << "Not building planned unit map: unit map locked.\n";
01195 return;
01196 }
01197 if (planned_unit_map_active_) {
01198 WRN_WB << "Not building planned unit map: already set.\n";
01199 return;
01200 }
01201
01202 validate_actions_if_needed();
01203 log_scope2("whiteboard", "Building planned unit map");
01204 mapbuilder_.reset(new mapbuilder(*resources::units));
01205 mapbuilder_->build_map();
01206
01207 planned_unit_map_active_ = true;
01208 }
01209
01210 void manager::set_real_unit_map()
01211 {
01212 if (planned_unit_map_active_)
01213 {
01214 assert(!executing_actions_);
01215 assert(!wait_for_side_init_);
01216 if(mapbuilder_)
01217 {
01218 log_scope2("whiteboard", "Restoring regular unit map.");
01219 mapbuilder_.reset();
01220 }
01221 planned_unit_map_active_ = false;
01222 }
01223 else
01224 {
01225 LOG_WB << "Not disabling planned unit map: already disabled.\n";
01226 }
01227 }
01228
01229 void manager::validate_actions_if_needed()
01230 {
01231 if (gamestate_mutated_) {
01232 validate_viewer_actions();
01233 }
01234 }
01235
01236 future_map::future_map():
01237 initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map())
01238 {
01239 if (!resources::whiteboard)
01240 return;
01241 if (!initial_planned_unit_map_)
01242 resources::whiteboard->set_planned_unit_map();
01243
01244 if (!resources::whiteboard->has_planned_unit_map()) {
01245 DBG_WB << "Scoped future unit map failed to apply.\n";
01246 }
01247 }
01248
01249 future_map::~future_map()
01250 {
01251 if (!resources::whiteboard)
01252 return;
01253 if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
01254 resources::whiteboard->set_real_unit_map();
01255 }
01256
01257 future_map_if_active::future_map_if_active():
01258 initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
01259 whiteboard_active_(resources::whiteboard && resources::whiteboard->is_active())
01260 {
01261 if (!resources::whiteboard)
01262 return;
01263 if (!whiteboard_active_)
01264 return;
01265 if (!initial_planned_unit_map_)
01266 resources::whiteboard->set_planned_unit_map();
01267
01268 if (!resources::whiteboard->has_planned_unit_map()) {
01269 DBG_WB << "Scoped future unit map failed to apply.\n";
01270 }
01271 }
01272
01273 future_map_if_active::~future_map_if_active()
01274 {
01275 if (!resources::whiteboard)
01276 return;
01277 if (!initial_planned_unit_map_ && resources::whiteboard->has_planned_unit_map())
01278 resources::whiteboard->set_real_unit_map();
01279 }
01280
01281
01282 real_map::real_map():
01283 initial_planned_unit_map_(resources::whiteboard && resources::whiteboard->has_planned_unit_map()),
01284 unit_map_lock_(resources::whiteboard ? resources::whiteboard->unit_map_lock_ : boost::shared_ptr<bool>(new bool(false)))
01285 {
01286 if (!resources::whiteboard)
01287 return;
01288 if (initial_planned_unit_map_)
01289 resources::whiteboard->set_real_unit_map();
01290 }
01291
01292 real_map::~real_map()
01293 {
01294 if (!resources::whiteboard)
01295 return;
01296 assert(!resources::whiteboard->has_planned_unit_map());
01297 if (initial_planned_unit_map_)
01298 {
01299 resources::whiteboard->set_planned_unit_map();
01300 }
01301 }
01302
01303 }