00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "global.hpp"
00024
00025 #include "builder.hpp"
00026 #include "ai/manager.hpp"
00027 #include "dialogs.hpp"
00028 #include "formatter.hpp"
00029 #include "filechooser.hpp"
00030 #include "foreach.hpp"
00031 #include "game_end_exceptions.hpp"
00032 #include "game_events.hpp"
00033 #include "game_preferences.hpp"
00034 #include "gettext.hpp"
00035 #include "gui/dialogs/chat_log.hpp"
00036 #include "gui/dialogs/edit_label.hpp"
00037 #include "gui/dialogs/message.hpp"
00038 #include "gui/dialogs/transient_message.hpp"
00039 #include "gui/dialogs/wml_message.hpp"
00040 #include "gui/dialogs/gamestate_inspector.hpp"
00041 #include "gui/dialogs/mp_change_control.hpp"
00042 #include "gui/dialogs/data_manage.hpp"
00043 #include "gui/dialogs/simple_item_selector.hpp"
00044 #include "gui/dialogs/unit_create.hpp"
00045 #include "gui/widgets/settings.hpp"
00046 #include "gui/widgets/window.hpp"
00047 #include "help.hpp"
00048 #include "log.hpp"
00049 #include "map.hpp"
00050 #include "map_label.hpp"
00051 #include "marked-up_text.hpp"
00052 #include "menu_events.hpp"
00053 #include "mouse_events.hpp"
00054 #include "play_controller.hpp"
00055 #include "preferences_display.hpp"
00056 #include "replay.hpp"
00057 #include "resources.hpp"
00058 #include "savegame.hpp"
00059 #include "sound.hpp"
00060 #include "statistics_dialog.hpp"
00061 #include "unit_display.hpp"
00062 #include "wml_separators.hpp"
00063 #include "formula_string_utils.hpp"
00064 #include "scripting/lua.hpp"
00065 #include "whiteboard/manager.hpp"
00066 #include "widgets/combo.hpp"
00067
00068 static lg::log_domain log_engine("engine");
00069 #define ERR_NG LOG_STREAM(err, log_engine)
00070 #define LOG_NG LOG_STREAM(info, log_engine)
00071
00072 namespace events{
00073
00074 class delete_recall_unit : public gui::dialog_button_action
00075 {
00076 public:
00077 delete_recall_unit(game_display& disp, gui::filter_textbox& filter, const std::vector<const unit*>& units) : disp_(disp), filter_(filter), units_(units) {}
00078 private:
00079 gui::dialog_button_action::RESULT button_pressed(int menu_selection);
00080
00081 game_display& disp_;
00082 gui::filter_textbox& filter_;
00083 const std::vector<const unit*>& units_;
00084 };
00085
00086 gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_selection)
00087 {
00088 const std::vector<std::pair<int, int> >& param = std::vector<std::pair<int, int> >();
00089 param.back();
00090 const size_t index = size_t(filter_.get_index(menu_selection));
00091 if(index < units_.size()) {
00092 const unit &u = *(units_[index]);
00093
00094
00095
00096 std::stringstream message;
00097 if (u.loyal()) {
00098 message << _("This unit is loyal and requires no upkeep.") << ' ' << (u.gender() == unit_race::MALE ? _("Do you really want to dismiss him?")
00099 : _("Do you really want to dismiss her?"));
00100 } else if(u.level() > 1) {
00101 message << _("This unit is an experienced one, having advanced levels.") << ' ' << (u.gender() == unit_race::MALE ? _("Do you really want to dismiss him?")
00102 : _("Do you really want to dismiss her?"));
00103
00104 } else if(u.experience() > u.max_experience()/2) {
00105 message << _("This unit is close to advancing a level.") << ' ' << (u.gender() == unit_race::MALE ? _("Do you really want to dismiss him?")
00106 : _("Do you really want to dismiss her?"));
00107 }
00108
00109 if(!message.str().empty()) {
00110 const int res = gui2::show_message(disp_.video(), _("Dismiss Unit"), message.str(), gui2::tmessage::yes_no_buttons);
00111 if(res == gui2::twindow::CANCEL) {
00112 return gui::CONTINUE_DIALOG;
00113 }
00114 }
00115
00116 filter_.delete_item(index);
00117
00118 resources::undo_stack->push_back(undo_action(u, map_location(), map_location(), undo_action::DISMISS));
00119
00120
00121 std::vector<unit>& recall_list = (*resources::teams)[u.side() -1].recall_list();
00122 assert(!recall_list.empty());
00123 std::vector<unit>::iterator dismissed_unit =
00124 find_if_matches_id(recall_list, u.id());
00125 assert(dismissed_unit != recall_list.end());
00126 recall_list.erase(dismissed_unit);
00127 recorder.add_disband(dismissed_unit->id());
00128
00129
00130 resources::redo_stack->clear();
00131 return gui::DELETE_ITEM;
00132 } else {
00133 return gui::CONTINUE_DIALOG;
00134 }
00135 }
00136
00137 menu_handler::menu_handler(game_display* gui, unit_map& units, std::vector<team>& teams,
00138 const config& level, const gamemap& map,
00139 const config& game_config, const tod_manager& tod_mng, game_state& gamestate) :
00140 gui_(gui),
00141 units_(units),
00142 teams_(teams),
00143 level_(level),
00144 map_(map),
00145 game_config_(game_config),
00146 tod_manager_(tod_mng),
00147 gamestate_(gamestate),
00148 textbox_info_(),
00149 last_search_(),
00150 last_search_hit_(),
00151 last_recruit_()
00152 {
00153 }
00154
00155 menu_handler::~menu_handler()
00156 {
00157 }
00158
00159 gui::floating_textbox& menu_handler::get_textbox(){
00160 return textbox_info_;
00161 }
00162
00163 std::string menu_handler::get_title_suffix(int side_num)
00164 {
00165 int controlled_recruiters = 0;
00166 for(size_t i = 0; i < teams_.size(); ++i) {
00167 if(teams_[i].is_human() && !teams_[i].recruits().empty()
00168 && units_.find_leader(i + 1) != units_.end()) {
00169 ++controlled_recruiters;
00170 }
00171 }
00172 std::stringstream msg;
00173 if(controlled_recruiters >= 2) {
00174 unit_map::const_iterator leader = units_.find_leader(side_num);
00175 if (leader != units_.end() && !leader->name().empty()) {
00176 msg << " (" << leader->name(); msg << ")";
00177 }
00178 }
00179 return msg.str();
00180 }
00181
00182 void menu_handler::objectives(int side_num)
00183 {
00184 config cfg;
00185 cfg["side"] = str_cast(side_num);
00186 game_events::handle_event_command("show_objectives",
00187 game_events::queued_event("_from_interface", map_location(),
00188 map_location(), config()), vconfig(cfg));
00189 team ¤t_team = teams_[side_num - 1];
00190 dialogs::show_objectives(level_, current_team.objectives());
00191 current_team.reset_objectives_changed();
00192 }
00193
00194 void menu_handler::show_statistics(int side_num)
00195 {
00196 team ¤t_team = teams_[side_num - 1];
00197
00198 const std::string &player = current_team.current_player();
00199
00200 std::stringstream title_str;
00201 title_str << _("Statistics") << " (" << player << ")";
00202 statistics_dialog stats_dialog(*gui_, title_str.str(),
00203 side_num, current_team.save_id(), player);
00204 stats_dialog.show();
00205 }
00206
00207 void menu_handler::unit_list()
00208 {
00209 const std::string heading = std::string(1,HEADING_PREFIX) +
00210 _("Type") + COLUMN_SEPARATOR +
00211 _("Name") + COLUMN_SEPARATOR +
00212 _("Moves") + COLUMN_SEPARATOR +
00213 _("Status") + COLUMN_SEPARATOR +
00214 _("HP") + COLUMN_SEPARATOR +
00215 _("Level^Lvl.") + COLUMN_SEPARATOR +
00216 _("XP") + COLUMN_SEPARATOR +
00217 _("unit list^Traits");
00218
00219 gui::menu::basic_sorter sorter;
00220 sorter.set_alpha_sort(0).set_alpha_sort(1).set_numeric_sort(2);
00221 sorter.set_alpha_sort(3).set_numeric_sort(4).set_level_sort(5, 6);
00222 sorter.set_xp_sort(6).set_alpha_sort(7);
00223
00224 std::vector<std::string> items;
00225 items.push_back(heading);
00226
00227 std::vector<map_location> locations_list;
00228 std::vector<unit> units_list;
00229
00230 int selected = 0;
00231
00232 for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
00233 if (i->side() != gui_->viewing_side())
00234 continue;
00235
00236 std::stringstream row;
00237
00238 if (gui_->selected_hex() == i->get_location()) {
00239 row << DEFAULT_ITEM;
00240 selected = units_list.size();
00241 }
00242
00243
00244
00245 if (i->can_recruit() ) {
00246 row << "<205,173,0>";
00247 }
00248 row << i->type_name() << COLUMN_SEPARATOR;
00249 if (i->can_recruit() ) {
00250 row << "<205,173,0>";
00251 }
00252 row << i->name() << COLUMN_SEPARATOR;
00253
00254
00255 if (i->movement_left() == 0) {
00256 row << font::RED_TEXT;
00257 } else if (i->movement_left() < i->total_movement() ) {
00258 row << "<255,255,0>";
00259 } else {
00260 row << font::GREEN_TEXT;
00261 }
00262 row << i->movement_left() << '/' << i->total_movement() << COLUMN_SEPARATOR;
00263
00264
00265 if(i->get_state(unit::STATE_PETRIFIED))
00266 row << IMAGE_PREFIX << "misc/petrified.png" << IMG_TEXT_SEPARATOR;
00267 if(i->get_state(unit::STATE_POISONED))
00268 row << IMAGE_PREFIX << "misc/poisoned.png" << IMG_TEXT_SEPARATOR;
00269 if(i->get_state(unit::STATE_SLOWED))
00270 row << IMAGE_PREFIX << "misc/slowed.png" << IMG_TEXT_SEPARATOR;
00271 if(i->invisible(i->get_location(),false))
00272 row << IMAGE_PREFIX << "misc/invisible.png";
00273 row << COLUMN_SEPARATOR;
00274
00275
00276
00277 row << font::color2markup(i->hp_color());
00278 row << i->hitpoints() << '/' << i->max_hitpoints() << COLUMN_SEPARATOR;
00279
00280
00281 int level = i->level();
00282 if(level < 1) {
00283 row << "<150,150,150>";
00284 } else if(level == 1) {
00285 row << font::NORMAL_TEXT;
00286 } else if(level == 2) {
00287 row << font::BOLD_TEXT;
00288 } else if(level > 2 ) {
00289 row << font::BOLD_TEXT << "<255,255,255>";
00290 }
00291 row << level << COLUMN_SEPARATOR;
00292
00293
00294 row << font::color2markup(i->xp_color());
00295 row << i->experience() << "/";
00296 if (i->can_advance()) {
00297 row << i->max_experience();
00298 } else {
00299 row << "-";
00300 }
00301 row << COLUMN_SEPARATOR;
00302
00303
00304 row << utils::join(i->trait_names(), ", ");
00305 items.push_back(row.str());
00306
00307 locations_list.push_back(i->get_location());
00308 units_list.push_back(*i);
00309 }
00310
00311 {
00312 dialogs::units_list_preview_pane unit_preview(units_list);
00313 unit_preview.set_selection(selected);
00314
00315 gui::dialog umenu(*gui_, _("Unit List"), "", gui::NULL_DIALOG);
00316 umenu.set_menu(items, &sorter);
00317 umenu.add_pane(&unit_preview);
00318
00319 umenu.get_menu().sort_by(0);
00320
00321 umenu.add_button(new gui::standard_dialog_button(gui_->video(), _("Scroll To"), 0, false),
00322 gui::dialog::BUTTON_STANDARD);
00323 umenu.add_button(new gui::standard_dialog_button(gui_->video(), _("Close"), 1, true),
00324 gui::dialog::BUTTON_STANDARD);
00325 umenu.set_basic_behavior(gui::OK_CANCEL);
00326 selected = umenu.show();
00327 }
00328
00329 if(selected >= 0 && selected < int(locations_list.size())) {
00330 const map_location& loc = locations_list[selected];
00331 gui_->scroll_to_tile(loc,game_display::WARP);
00332 gui_->select_hex(loc);
00333 }
00334 }
00335
00336 namespace {
00337 class leader_scroll_dialog : public gui::dialog {
00338 public:
00339 leader_scroll_dialog(display &disp, const std::string &title,
00340 std::vector<bool> &leader_bools, int selected,
00341 gui::DIALOG_RESULT extra_result) :
00342 dialog(disp, title, "", gui::NULL_DIALOG),
00343 scroll_btn_(new gui::standard_dialog_button(disp.video(), _("Scroll To"), 0, false)),
00344 leader_bools_(leader_bools),
00345 extra_result_(extra_result)
00346 {
00347 scroll_btn_->enable(leader_bools[selected]);
00348 add_button(scroll_btn_, gui::dialog::BUTTON_STANDARD);
00349 add_button(new gui::standard_dialog_button(disp.video(),
00350 _("Close"), 1, true), gui::dialog::BUTTON_STANDARD);
00351 }
00352 void action(gui::dialog_process_info &info) {
00353 const bool leader_bool = leader_bools_[get_menu().selection()];
00354 scroll_btn_->enable(leader_bool);
00355 if(leader_bool && (info.double_clicked || (!info.key_down
00356 && (info.key[SDLK_RETURN] || info.key[SDLK_KP_ENTER])))) {
00357 set_result(get_menu().selection());
00358 } else if(!info.key_down && info.key[SDLK_ESCAPE]) {
00359 set_result(gui::CLOSE_DIALOG);
00360 } else if(!info.key_down && info.key[SDLK_SPACE]) {
00361 set_result(extra_result_);
00362 } else if(result() == gui::CONTINUE_DIALOG) {
00363 dialog::action(info);
00364 }
00365 }
00366 private:
00367 gui::standard_dialog_button *scroll_btn_;
00368 std::vector<bool> &leader_bools_;
00369 gui::DIALOG_RESULT extra_result_;
00370 };
00371 }
00372 void menu_handler::status_table(int selected)
00373 {
00374 std::stringstream heading;
00375 heading << HEADING_PREFIX << _("Leader") << COLUMN_SEPARATOR << ' ' << COLUMN_SEPARATOR
00376 << _("Team") << COLUMN_SEPARATOR
00377 << _("Gold") << COLUMN_SEPARATOR
00378 << _("Villages") << COLUMN_SEPARATOR
00379 << _("status^Units") << COLUMN_SEPARATOR
00380 << _("Upkeep") << COLUMN_SEPARATOR
00381 << _("Income");
00382
00383 gui::menu::basic_sorter sorter;
00384 sorter.set_redirect_sort(0,1).set_alpha_sort(1).set_alpha_sort(2).set_numeric_sort(3)
00385 .set_numeric_sort(4).set_numeric_sort(5).set_numeric_sort(6).set_numeric_sort(7);
00386
00387 std::vector<std::string> items;
00388 std::vector<bool> leader_bools;
00389 items.push_back(heading.str());
00390
00391 const team& viewing_team = teams_[gui_->viewing_team()];
00392
00393 unsigned total_villages = 0;
00394
00395 bool status_table_empty = true;
00396
00397
00398
00399
00400
00401
00402 for(size_t n = 0; n != teams_.size(); ++n) {
00403 if(teams_[n].hidden()) {
00404 continue;
00405 }
00406 status_table_empty=false;
00407
00408 const bool known = viewing_team.knows_about_team(n, network::nconnections() > 0);
00409 const bool enemy = viewing_team.is_enemy(n+1);
00410
00411 std::stringstream str;
00412
00413 const team_data data = calculate_team_data(teams_[n],n+1);
00414
00415 unit_map::const_iterator leader = units_.find_leader(n + 1);
00416 std::string leader_name;
00417
00418
00419 if(leader != units_.end()) {
00420 const bool fogged = viewing_team.fogged(leader->get_location());
00421
00422
00423 if (!fogged || known || game_config::debug) {
00424 str << IMAGE_PREFIX << leader->absolute_image();
00425 leader_bools.push_back(true);
00426 leader_name = leader->name();
00427 } else {
00428 str << IMAGE_PREFIX << std::string("units/unknown-unit.png");
00429 leader_bools.push_back(false);
00430 leader_name = "Unknown";
00431 }
00432 if (gamestate_.classification().campaign_type == "multiplayer")
00433 leader_name = teams_[n].current_player();
00434
00435 #ifndef LOW_MEM
00436 str << leader->image_mods();
00437 #endif
00438 } else {
00439 leader_bools.push_back(false);
00440 }
00441 str << COLUMN_SEPARATOR << team::get_side_highlight(n)
00442 << leader_name << COLUMN_SEPARATOR
00443 << (data.teamname.empty() ? teams_[n].team_name() : data.teamname)
00444 << COLUMN_SEPARATOR;
00445
00446 if(!known && !game_config::debug) {
00447
00448
00449 items.push_back(str.str());
00450 continue;
00451 }
00452
00453 if(game_config::debug) {
00454 str << utils::half_signed_value(data.gold) << COLUMN_SEPARATOR;
00455 } else if(enemy && viewing_team.uses_fog()) {
00456 str << ' ' << COLUMN_SEPARATOR;
00457 } else {
00458 str << utils::half_signed_value(data.gold) << COLUMN_SEPARATOR;
00459 }
00460 str << data.villages;
00461 if(!(viewing_team.uses_fog() || viewing_team.uses_shroud())) {
00462 str << "/" << map_.villages().size();
00463 }
00464 str << COLUMN_SEPARATOR
00465 << data.units << COLUMN_SEPARATOR << data.upkeep << COLUMN_SEPARATOR
00466 << (data.net_income < 0 ? font::BAD_TEXT : font::NULL_MARKUP) << utils::signed_value(data.net_income);
00467 total_villages += data.villages;
00468 items.push_back(str.str());
00469 }
00470 if (total_villages > map_.villages().size()) {
00471 ERR_NG << "Logic error: map has " << map_.villages().size() << " villages but status table shows " << total_villages << " owned in total\n";
00472 }
00473
00474 if (status_table_empty)
00475 {
00476
00477 std::stringstream str;
00478 str << " ";
00479 for (int i=0;i<7;++i)
00480 str << COLUMN_SEPARATOR << " ";
00481 leader_bools.push_back(false);
00482 items.push_back(str.str());
00483 }
00484 int result = 0;
00485 {
00486 leader_scroll_dialog slist(*gui_, _("Current Status"), leader_bools, selected, gui::DIALOG_FORWARD);
00487 slist.add_button(new gui::dialog_button(gui_->video(), _("More >"),
00488 gui::button::TYPE_PRESS, gui::DIALOG_FORWARD),
00489 gui::dialog::BUTTON_EXTRA_LEFT);
00490 slist.set_menu(items, &sorter);
00491 slist.get_menu().move_selection(selected);
00492 result = slist.show();
00493 selected = slist.get_menu().selection();
00494 }
00495
00496 if (result >= 0)
00497 gui_->scroll_to_leader(units_, selected+1);
00498 else if (result == gui::DIALOG_FORWARD)
00499 scenario_settings_table(selected);
00500 }
00501
00502 void menu_handler::scenario_settings_table(int selected)
00503 {
00504 std::stringstream heading;
00505 heading << HEADING_PREFIX << _("scenario settings^Leader") << COLUMN_SEPARATOR
00506 << COLUMN_SEPARATOR
00507 << _("scenario settings^Side") << COLUMN_SEPARATOR
00508 << _("scenario settings^Start\nGold") << COLUMN_SEPARATOR
00509 << _("scenario settings^Base\nIncome") << COLUMN_SEPARATOR
00510 << _("scenario settings^Gold Per\nVillage") << COLUMN_SEPARATOR
00511 << _("scenario settings^Support Per\nVillage") << COLUMN_SEPARATOR
00512 << _("scenario settings^Fog") << COLUMN_SEPARATOR
00513 << _("scenario settings^Shroud");
00514
00515 gui::menu::basic_sorter sorter;
00516 sorter.set_redirect_sort(0,1).set_alpha_sort(1).set_numeric_sort(2)
00517 .set_numeric_sort(3).set_numeric_sort(4).set_numeric_sort(5)
00518 .set_numeric_sort(6).set_alpha_sort(7).set_alpha_sort(8);
00519
00520 std::vector<std::string> items;
00521 std::vector<bool> leader_bools;
00522 items.push_back(heading.str());
00523
00524 const team& viewing_team = teams_[gui_->viewing_team()];
00525 bool settings_table_empty = true;
00526 bool fogged;
00527
00528 for(size_t n = 0; n != teams_.size(); ++n) {
00529 if(teams_[n].hidden()) {
00530 continue;
00531 }
00532 settings_table_empty = false;
00533
00534 std::stringstream str;
00535 unit_map::const_iterator leader = units_.find_leader(n + 1);
00536
00537 if(leader != units_.end()) {
00538
00539
00540 fogged=viewing_team.fogged(leader->get_location());
00541 if (!fogged || viewing_team.knows_about_team(n, network::nconnections() > 0) || game_config::debug) {
00542 str << IMAGE_PREFIX << leader->absolute_image();
00543 leader_bools.push_back(true);
00544 } else {
00545 str << IMAGE_PREFIX << std::string("units/unknown-unit.png");
00546 leader_bools.push_back(false);
00547 }
00548 #ifndef LOW_MEM
00549 str << "~RC(" << leader->team_color() << '>'
00550 << team::get_side_color_index(n+1) << ")";
00551 #endif
00552 } else {
00553 leader_bools.push_back(false);
00554 }
00555
00556 str << COLUMN_SEPARATOR << team::get_side_highlight(n)
00557 << teams_[n].current_player() << COLUMN_SEPARATOR
00558 << n + 1 << COLUMN_SEPARATOR
00559 << teams_[n].start_gold() << COLUMN_SEPARATOR
00560 << teams_[n].base_income() << COLUMN_SEPARATOR
00561 << teams_[n].village_gold() << COLUMN_SEPARATOR
00562 << teams_[n].village_support() << COLUMN_SEPARATOR
00563 << (teams_[n].uses_fog() ? _("yes") : _("no")) << COLUMN_SEPARATOR
00564 << (teams_[n].uses_shroud() ? _("yes") : _("no")) << COLUMN_SEPARATOR;
00565
00566 items.push_back(str.str());
00567 }
00568
00569 if (settings_table_empty)
00570 {
00571
00572 std::stringstream str;
00573 for (int i=0;i<8;++i)
00574 str << " " << COLUMN_SEPARATOR;
00575 leader_bools.push_back(false);
00576 items.push_back(str.str());
00577 }
00578 int result = 0;
00579 {
00580 leader_scroll_dialog slist(*gui_, _("Scenario Settings"), leader_bools, selected, gui::DIALOG_BACK);
00581 slist.set_menu(items, &sorter);
00582 slist.get_menu().move_selection(selected);
00583 slist.add_button(new gui::dialog_button(gui_->video(), _(" < Back"),
00584 gui::button::TYPE_PRESS, gui::DIALOG_BACK),
00585 gui::dialog::BUTTON_EXTRA_LEFT);
00586 result = slist.show();
00587 selected = slist.get_menu().selection();
00588 }
00589
00590 if (result >= 0)
00591 gui_->scroll_to_leader(units_, selected+1);
00592 else if (result == gui::DIALOG_BACK)
00593 status_table(selected);
00594 }
00595
00596 void menu_handler::save_map()
00597 {
00598 std::string input_name = get_dir(get_dir(get_user_data_dir() + "/editor") + "/maps/");
00599 int res = 0;
00600 int overwrite = 1;
00601 do {
00602 res = dialogs::show_file_chooser_dialog_save(*gui_, input_name, _("Save the Map As"));
00603 if (res == 0) {
00604
00605 if (file_exists(input_name)) {
00606 const int res = gui2::show_message((*gui_).video(), "", _("The map already exists. Do you want to overwrite it?"), gui2::tmessage::yes_no_buttons);
00607 overwrite = res == gui2::twindow::CANCEL ? 1 : 0;
00608 }
00609 else
00610 overwrite = 0;
00611 }
00612 } while (res == 0 && overwrite != 0);
00613
00614
00615 if (res == 0) {
00616 try {
00617 config file;
00618 config& map = file.add_child("map");
00619 map_.write(map);
00620 std::stringstream str;
00621 str << file;
00622 write_file(input_name, str.str());
00623 gui2::show_transient_message(gui_->video(), "", _("Map saved."));
00624 } catch (io_exception& e) {
00625 utils::string_map symbols;
00626 symbols["msg"] = e.what();
00627 const std::string msg = vgettext("Could not save the map: $msg",symbols);
00628 gui2::show_transient_message(gui_->video(), "", msg);
00629 }
00630 }
00631 }
00632
00633 void menu_handler::preferences()
00634 {
00635 preferences::show_preferences_dialog(*gui_, game_config_);
00636
00637 gui_->redraw_everything();
00638 }
00639
00640 void menu_handler::show_chat_log()
00641 {
00642 config c;
00643 c["name"] = "prototype of chat log";
00644 gui2::tchat_log chat_log_dialog(vconfig(c),&recorder);
00645 chat_log_dialog.show(resources::screen->video());
00646
00647
00648
00649 }
00650
00651 void menu_handler::show_help()
00652 {
00653 help::show_help(*gui_);
00654 }
00655
00656 void menu_handler::speak()
00657 {
00658 textbox_info_.show(gui::TEXTBOX_MESSAGE,_("Message:"),
00659 has_friends() ? is_observer() ? _("Send to observers only") : _("Send to allies only")
00660 : "", preferences::message_private(), *gui_);
00661 }
00662
00663 void menu_handler::whisper()
00664 {
00665 preferences::set_message_private(true);
00666 speak();
00667 }
00668
00669 void menu_handler::shout()
00670 {
00671 preferences::set_message_private(false);
00672 speak();
00673 }
00674
00675 bool menu_handler::has_friends() const
00676 {
00677 if(is_observer()) {
00678 return !gui_->observers().empty();
00679 }
00680
00681 for(size_t n = 0; n != teams_.size(); ++n) {
00682 if(n != gui_->viewing_team() && teams_[gui_->viewing_team()].team_name() == teams_[n].team_name() && teams_[n].is_network()) {
00683 return true;
00684 }
00685 }
00686
00687 return false;
00688 }
00689
00690 void menu_handler::recruit(int side_num, const map_location &last_hex)
00691 {
00692 team ¤t_team = teams_[side_num - 1];
00693
00694 std::vector<const unit_type*> sample_units;
00695
00696 gui_->draw();
00697 std::vector<std::string> item_keys;
00698 std::vector<std::string> items;
00699
00700 std::set<std::string> recruits = get_recruits_for_location(side_num, last_hex);
00701
00702 for(std::set<std::string>::const_iterator it = recruits.begin(); it != recruits.end(); ++it) {
00703 const unit_type *type = unit_types.find(*it);
00704 if (!type) {
00705 ERR_NG << "could not find unit '" << *it << "'\n";
00706 return;
00707 }
00708
00709 item_keys.push_back(*it);
00710
00711 char prefix;
00712 { wb::future_map future;
00713 int wb_gold = resources::whiteboard->get_spent_gold_for(side_num);
00714
00715 prefix = (type->cost() > current_team.gold() - wb_gold
00716 ? font::BAD_TEXT : font::NULL_MARKUP);
00717 }
00718
00719 std::stringstream description;
00720 description << font::IMAGE << type->image();
00721 #ifndef LOW_MEM
00722 description << "~RC(" << type->flag_rgb() << '>'
00723 << team::get_side_color_index(side_num) << ')';
00724 #endif
00725 description << COLUMN_SEPARATOR << font::LARGE_TEXT << prefix << type->type_name() << "\n"
00726 << prefix << type->cost() << " " << sngettext("unit^Gold", "Gold", type->cost());
00727
00728 items.push_back(description.str());
00729 sample_units.push_back(type);
00730 }
00731
00732 if(sample_units.empty()) {
00733 gui2::show_transient_message(gui_->video(),"",_("You have no units available to recruit."));
00734 return;
00735 }
00736
00737 int recruit_res = 0;
00738
00739 {
00740 dialogs::unit_types_preview_pane unit_preview(
00741 sample_units, NULL, side_num);
00742 std::vector<gui::preview_pane*> preview_panes;
00743 preview_panes.push_back(&unit_preview);
00744
00745 gui::menu::basic_sorter sorter;
00746 sorter.set_alpha_sort(1);
00747
00748 gui::dialog rmenu(*gui_, _("Recruit") + get_title_suffix(side_num),
00749 _("Select unit:") + std::string("\n"),
00750 gui::OK_CANCEL,
00751 gui::dialog::default_style);
00752 rmenu.add_button(new help::help_button(*gui_,"recruit_and_recall"),
00753 gui::dialog::BUTTON_HELP);
00754 rmenu.set_menu(items, &sorter);
00755 rmenu.get_menu().sort_by(1);
00756 rmenu.set_panes(preview_panes);
00757 recruit_res = rmenu.show();
00758 }
00759
00760 if(recruit_res != -1) {
00761 do_recruit(item_keys[recruit_res], side_num, last_hex);
00762 }
00763 }
00764
00765
00766 void menu_handler::repeat_recruit(int side_num, const map_location &last_hex)
00767 {
00768 if(last_recruit_.empty() == false)
00769 do_recruit(last_recruit_, side_num, last_hex);
00770 }
00771
00772 bool menu_handler::do_recruit(const std::string &name, int side_num,
00773 const map_location &last_hex)
00774 {
00775 team ¤t_team = teams_[side_num - 1];
00776
00777
00778 int recruit_num = 0;
00779 std::set<std::string> recruits = get_recruits_for_location(side_num, last_hex);
00780
00781 for(std::set<std::string>::const_iterator r = recruits.begin(); ; ++r) {
00782 if (r == recruits.end()) {
00783 return false;
00784 }
00785
00786 if (name == *r) {
00787 break;
00788 }
00789 ++recruit_num;
00790 }
00791
00792 const unit_type *u_type = unit_types.find(name);
00793 assert(u_type);
00794
00795 if (u_type->cost() > current_team.gold() - resources::whiteboard->get_spent_gold_for(side_num)) {
00796 gui2::show_transient_message(gui_->video(), "",
00797 _("You don’t have enough gold to recruit that unit"));
00798 return false;
00799 }
00800
00801 last_recruit_ = name;
00802 const events::command_disabler disable_commands;
00803
00804 map_location loc = last_hex;
00805 map_location recruited_from = map_location::null_location;
00806 std::string msg;
00807 { wb::future_map_if_active future;
00808 msg = find_recruit_location(side_num, loc, recruited_from, u_type->id());
00809 }
00810 if (!msg.empty()) {
00811 gui2::show_transient_message(gui_->video(), "", msg);
00812 return false;
00813 }
00814
00815 if (!resources::whiteboard->save_recruit(name, side_num, loc)) {
00816
00817 recorder.add_recruit(recruit_num, loc, recruited_from);
00818 const unit new_unit(u_type, side_num, true);
00819 place_recruit(new_unit, loc, recruited_from, false, true);
00820 current_team.spend_gold(u_type->cost());
00821 statistics::recruit_unit(new_unit);
00822
00823
00824 current_team.set_action_bonus_count(1 + current_team.action_bonus_count());
00825
00826 resources::redo_stack->clear();
00827 assert(new_unit.type());
00828
00829
00830
00831 const bool shroud_cleared = clear_shroud(side_num);
00832 if (shroud_cleared || new_unit.type()->genders().size() > 1
00833 || new_unit.type()->has_random_traits()) {
00834 clear_undo_stack(side_num);
00835 } else {
00836 resources::undo_stack->push_back(undo_action(new_unit, loc, recruited_from, undo_action::RECRUIT));
00837 }
00838
00839 gui_->redraw_minimap();
00840 gui_->invalidate_game_status();
00841 gui_->invalidate(loc);
00842 recorder.add_checksum_check(loc);
00843 return true;
00844 }
00845 return false;
00846 }
00847
00848 void menu_handler::recall(int side_num, const map_location &last_hex)
00849 {
00850 if (level_["disallow_recall"].to_bool()) {
00851 gui2::show_transient_message(gui_->video(),"",_("You are separated from your soldiers and may not recall them"));
00852 return;
00853 }
00854
00855 team ¤t_team = teams_[side_num - 1];
00856 if(!current_team.persistent()) {
00857 ERR_NG << "cannot recall a unit for side " << side_num
00858 << ", which has no recall list!\n";
00859 return;
00860 }
00861
00862 std::vector<const unit*> recall_list_team;
00863 { wb::future_map future;
00864 recall_list_team = get_recalls_for_location(side_num, last_hex);
00865 }
00866
00867 gui_->draw();
00868
00869
00870 DBG_WB <<"menu_handler::recall: Contents of wb-modified recall list:\n";
00871 foreach(const unit* unit, recall_list_team)
00872 {
00873 DBG_WB << unit->name() << " [" << unit->id() <<"]\n";
00874 }
00875
00876 if(current_team.recall_list().empty()) {
00877 gui2::show_transient_message(gui_->video(), "",
00878 _("There are no troops available to recall\n(You must have"
00879 " veteran survivors from a previous scenario)"));
00880 return;
00881 }
00882 if(recall_list_team.empty()) {
00883 gui2::show_transient_message(gui_->video(), "",
00884 _("You currently can't recall at the highlighted location"));
00885 return;
00886 }
00887
00888 std::vector<std::string> options, options_to_filter;
00889
00890 std::ostringstream heading;
00891 heading << HEADING_PREFIX << COLUMN_SEPARATOR << _("Type")
00892 << COLUMN_SEPARATOR << _("Name")
00893 << COLUMN_SEPARATOR << _("Level^Lvl.")
00894 << COLUMN_SEPARATOR << _("XP");
00895 heading << COLUMN_SEPARATOR << _("Traits");
00896
00897 gui::menu::basic_sorter sorter;
00898 sorter.set_alpha_sort(1).set_alpha_sort(2);
00899 sorter.set_level_sort(3,4).set_xp_sort(4).set_alpha_sort(5);
00900
00901 options.push_back(heading.str());
00902 options_to_filter.push_back(options.back());
00903
00904 foreach (const unit* u, recall_list_team)
00905 {
00906 std::stringstream option, option_to_filter;
00907 std::string name = u->name();
00908 if (name.empty()) name = "-";
00909
00910 option << IMAGE_PREFIX << u->absolute_image();
00911 #ifndef LOW_MEM
00912 option << "~RC(" << u->team_color() << '>'
00913 << team::get_side_color_index(side_num) << ')';
00914 #endif
00915 option << COLUMN_SEPARATOR
00916 << u->type_name() << COLUMN_SEPARATOR
00917 << name << COLUMN_SEPARATOR;
00918
00919
00920 const int level = u->level();
00921 if(level < 1) {
00922 option << "<150,150,150>";
00923 } else if(level == 1) {
00924 option << font::NORMAL_TEXT;
00925 } else if(level == 2) {
00926 option << font::BOLD_TEXT;
00927 } else if(level > 2 ) {
00928 option << font::BOLD_TEXT << "<255,255,255>";
00929 }
00930 option << level << COLUMN_SEPARATOR;
00931
00932 option << font::color2markup(u->xp_color()) << u->experience() << "/";
00933 if (u->can_advance())
00934 option << u->max_experience();
00935 else
00936 option << "-";
00937
00938 option_to_filter << u->type_name() << " " << name << " " << u->level();
00939
00940 option << COLUMN_SEPARATOR;
00941 foreach (const t_string& trait, u->trait_names()) {
00942 option << trait << '\n';
00943 option_to_filter << " " << trait;
00944 }
00945
00946 options.push_back(option.str());
00947 options_to_filter.push_back(option_to_filter.str());
00948 }
00949
00950 int res = 0;
00951
00952 {
00953 gui::dialog rmenu(*gui_, _("Recall") + get_title_suffix(side_num),
00954 _("Select unit:") + std::string("\n"),
00955 gui::OK_CANCEL, gui::dialog::default_style);
00956 rmenu.set_menu(options, &sorter);
00957
00958 gui::filter_textbox* filter = new gui::filter_textbox(gui_->video(),
00959 _("Filter: "), options, options_to_filter, 1, rmenu, 200);
00960 rmenu.set_textbox(filter);
00961
00962 delete_recall_unit recall_deleter(*gui_, *filter, recall_list_team);
00963 gui::dialog_button_info delete_button(&recall_deleter,_("Dismiss Unit"));
00964 rmenu.add_button(delete_button);
00965
00966 rmenu.add_button(new help::help_button(*gui_,"recruit_and_recall"),
00967 gui::dialog::BUTTON_HELP);
00968
00969 dialogs::units_list_preview_pane unit_preview(recall_list_team, filter);
00970 rmenu.add_pane(&unit_preview);
00971
00972
00973 static int sort_by = 3;
00974 static bool sort_reversed = false;
00975
00976 if(sort_by >= 0) {
00977 rmenu.get_menu().sort_by(sort_by);
00978
00979 if(sort_reversed) {
00980 rmenu.get_menu().sort_by(sort_by);
00981 }
00982 }
00983
00984 res = rmenu.show();
00985 res = filter->get_index(res);
00986
00987 sort_by = rmenu.get_menu().get_sort_by();
00988 sort_reversed = rmenu.get_menu().get_sort_reversed();
00989
00990 if (res < 0) return;
00991
00992 }
00993
00994 int wb_gold = resources::whiteboard->get_spent_gold_for(side_num);
00995 if (current_team.gold() - wb_gold < current_team.recall_cost()) {
00996 utils::string_map i18n_symbols;
00997 i18n_symbols["cost"] = lexical_cast<std::string>(current_team.recall_cost());
00998 std::string msg = vngettext(
00999 "You must have at least 1 gold piece to recall a unit",
01000 "You must have at least $cost gold pieces to recall a unit",
01001 current_team.recall_cost(), i18n_symbols);
01002 gui2::show_transient_message(gui_->video(), "", msg);
01003 return;
01004 }
01005
01006 LOG_NG << "recall index: " << res << "\n";
01007 const events::command_disabler disable_commands;
01008
01009 map_location recall_location = last_hex;
01010 map_location recall_from = map_location::null_location;
01011 std::string err;
01012 { wb::future_map_if_active future;
01013 err = find_recall_location(side_num, recall_location, recall_from, *(recall_list_team[res]));
01014 }
01015 if(!err.empty()) {
01016 gui2::show_transient_message(gui_->video(), "", err);
01017 return;
01018 }
01019 unit* recalled_unit;
01020 recalled_unit = new unit(*(recall_list_team[res]));
01021
01022 if (!resources::whiteboard->save_recall(*recalled_unit, side_num, recall_location)) {
01023 do_recall(*recalled_unit, side_num, recall_location, recall_from);
01024 }
01025 }
01026
01027 bool menu_handler::do_recall(const unit& un, int side_num, const map_location& recall_location, const map_location& recall_from)
01028 {
01029 team ¤t_team = teams_[side_num - 1];
01030 std::vector<unit>& recall_list_team = current_team.recall_list();
01031
01032 std::vector<unit>::iterator it = find_if_matches_id(recall_list_team, un.id());
01033 if (it == recall_list_team.end())
01034 {
01035 ERR_NG << "menu_handler::do_recall(): Unit doesn't exist in recall list.\n";
01036 return false;
01037 }
01038
01039 recall_list_team.erase(it);
01040 recorder.add_recall(un.id(), recall_location, recall_from);
01041 place_recruit(un, recall_location, recall_from, true, true);
01042 statistics::recall_unit(un);
01043 current_team.spend_gold(current_team.recall_cost());
01044
01045 bool shroud_cleared = clear_shroud(side_num);
01046 if (shroud_cleared) {
01047 clear_undo_stack(side_num);
01048 } else {
01049 resources::undo_stack->push_back(undo_action(un, recall_location, recall_from, undo_action::RECALL));
01050 }
01051
01052 resources::redo_stack->clear();
01053 gui_->redraw_minimap();
01054 gui_->invalidate_game_status();
01055 gui_->invalidate(recall_location);
01056 recorder.add_checksum_check(recall_location);
01057 return true;
01058 }
01059
01060 void menu_handler::undo(int side_num)
01061 {
01062 if(resources::undo_stack->empty())
01063 return;
01064
01065 const events::command_disabler disable_commands;
01066 team ¤t_team = teams_[side_num - 1];
01067
01068
01069
01070 undo_action action = resources::undo_stack->back();
01071 resources::undo_stack->pop_back();
01072
01073 if (action.is_dismiss()) {
01074
01075
01076 if(!current_team.persistent()) {
01077 ERR_NG << "trying to undo a dismissal for side " << side_num
01078 << ", which has no recall list!\n";
01079 return;
01080 }
01081 current_team.recall_list().push_back(action.affected_unit);
01082 resources::whiteboard->on_gamestate_change();
01083 } else if(action.is_recall()) {
01084
01085 if(!current_team.persistent()) {
01086 ERR_NG << "trying to undo a recall for side " << side_num
01087 << ", which has no recall list!\n";
01088 return;
01089 }
01090
01091 if(units_.count(action.recall_loc) == 0) {
01092 return;
01093 }
01094
01095 const unit &un = *units_.find(action.recall_loc);
01096 statistics::un_recall_unit(un);
01097 current_team.spend_gold(-current_team.recall_cost());
01098
01099 current_team.recall_list().push_back(un);
01100
01101
01102 gui_->invalidate(action.recall_loc);
01103 units_.erase(action.recall_loc);
01104 resources::whiteboard->on_gamestate_change();
01105 } else if(action.is_recruit()) {
01106
01107 if(units_.count(action.recall_loc) == 0) {
01108 return;
01109 }
01110
01111 const unit &un = *units_.find(action.recall_loc);
01112 statistics::un_recruit_unit(un);
01113 assert(un.type());
01114 current_team.spend_gold(-un.type()->cost());
01115
01116
01117 if(action.countdown_time_bonus)
01118 {
01119 current_team.set_action_bonus_count(current_team.action_bonus_count() - 1);
01120 }
01121
01122
01123
01124 gui_->invalidate(action.recall_loc);
01125 units_.erase(action.recall_loc);
01126 resources::whiteboard->on_gamestate_change();
01127 } else {
01128
01129 const int starting_moves = action.starting_moves;
01130 std::vector<map_location> route = action.route;
01131 std::reverse(route.begin(),route.end());
01132 unit_map::iterator u = units_.find(route.front());
01133 const unit_map::iterator u_end = units_.find(route.back());
01134 if(u == units_.end() || u_end != units_.end()) {
01135
01136 ERR_NG << "Illegal 'undo' found. Possible abuse of [allow_undo]?\n";
01137 return;
01138 }
01139
01140 if(map_.is_village(route.front())) {
01141 get_village(route.front(), action.original_village_owner + 1);
01142
01143 if(action.countdown_time_bonus)
01144 {
01145 current_team.set_action_bonus_count(current_team.action_bonus_count() - 1);
01146 }
01147 }
01148
01149 action.starting_moves = u->movement_left();
01150
01151 undo_action action_copy(action);
01152
01153 unit_display::move_unit(route, *u, teams_, true, action_copy.starting_dir);
01154
01155 units_.move(u->get_location(), route.back());
01156 unit::clear_status_caches();
01157
01158 u = units_.find(route.back());
01159 u->set_goto(map_location());
01160 u->set_movement(starting_moves);
01161 u->set_standing();
01162
01163 gui_->invalidate_unit_after_move(route.front(), route.back());
01164 resources::whiteboard->on_gamestate_change();
01165 }
01166 recorder.undo();
01167 resources::redo_stack->push_back(action);
01168
01169 gui_->invalidate_unit();
01170 gui_->invalidate_game_status();
01171 gui_->redraw_minimap();
01172 gui_->draw();
01173 }
01174
01175 void menu_handler::redo(int side_num)
01176 {
01177 if(resources::redo_stack->empty())
01178 return;
01179
01180 const events::command_disabler disable_commands;
01181 team ¤t_team = teams_[side_num - 1];
01182
01183
01184
01185 undo_action action = resources::redo_stack->back();
01186 resources::redo_stack->pop_back();
01187
01188 if (action.is_dismiss()) {
01189 if(!current_team.persistent()) {
01190 ERR_NG << "trying to redo a dismiss for side " << side_num
01191 << ", which has no recall list!\n";
01192 return;
01193 }
01194
01195 recorder.add_disband(action.affected_unit.id());
01196 std::vector<unit>::iterator unit_it =
01197 find_if_matches_id(current_team.recall_list(), action.affected_unit.id());
01198 current_team.recall_list().erase(unit_it);
01199 resources::whiteboard->on_gamestate_change();
01200 } else if(action.is_recall()) {
01201 if(!current_team.persistent()) {
01202 ERR_NG << "trying to redo a recall for side " << side_num
01203 << ", which has no recall list!\n";
01204 return;
01205 }
01206
01207
01208 recorder.add_recall(action.affected_unit.id(), action.recall_loc, action.recall_from);
01209 map_location loc = action.recall_loc;
01210 map_location from = map_location::null_location;
01211 const events::command_disabler disable_commands;
01212 const std::string &msg = find_recall_location(side_num, loc, from, action.affected_unit);
01213 if(msg.empty()) {
01214 unit un = action.affected_unit;
01215
01216 std::vector<unit>::iterator unit_it =
01217 find_if_matches_id(current_team.recall_list(), action.affected_unit.id());
01218 assert(unit_it != current_team.recall_list().end());
01219 current_team.recall_list().erase(unit_it);
01220
01221 place_recruit(un, loc, from, true, true);
01222 statistics::recall_unit(un);
01223 current_team.spend_gold(current_team.recall_cost());
01224 gui_->invalidate(loc);
01225 recorder.add_checksum_check(loc);
01226 } else {
01227 recorder.undo();
01228 gui::dialog(*gui_,"",msg,gui::OK_ONLY).show();
01229 return;
01230 }
01231 resources::whiteboard->on_gamestate_change();
01232 } else if(action.is_recruit()) {
01233
01234 map_location loc = action.recall_loc;
01235 map_location from = action.recall_from;
01236 const std::string name = action.affected_unit.type_id();
01237
01238
01239 int recruit_num = 0;
01240 const std::set<std::string>& recruits = current_team.recruits();
01241 for(std::set<std::string>::const_iterator r = recruits.begin(); ; ++r) {
01242 if (r == recruits.end()) {
01243 ERR_NG << "trying to redo a recruit for side " << side_num
01244 << ", which does not recruit type \"" << name << "\"\n";
01245 assert(false);
01246 return;
01247 }
01248 if (name == *r) {
01249 break;
01250 }
01251 ++recruit_num;
01252 }
01253 last_recruit_ = name;
01254 recorder.add_recruit(recruit_num,loc,from);
01255 const events::command_disabler disable_commands;
01256 const std::string &msg = find_recruit_location(side_num, loc, from, action.affected_unit.type_id());
01257 if(msg.empty()) {
01258 const unit new_unit = action.affected_unit;
01259
01260 place_recruit(new_unit, loc, from, false, true);
01261 current_team.spend_gold(new_unit.type()->cost());
01262 statistics::recruit_unit(new_unit);
01263 gui_->invalidate(loc);
01264
01265
01266 current_team.set_action_bonus_count(1 + current_team.action_bonus_count());
01267
01268 recorder.add_checksum_check(loc);
01269 } else {
01270 recorder.undo();
01271 gui::dialog(*gui_,"",msg,gui::OK_ONLY).show();
01272 return;
01273 }
01274 resources::whiteboard->on_gamestate_change();
01275 } else {
01276
01277 const int starting_moves = action.starting_moves;
01278 std::vector<map_location> route = action.route;
01279 unit_map::iterator u = units_.find(route.front());
01280 if(u == units_.end()) {
01281 ERR_NG << "Illegal movement 'redo'.\n";
01282 assert(false);
01283 return;
01284 }
01285
01286 action.starting_moves = u->movement_left();
01287
01288 undo_action action_copy(action);
01289
01290 unit_display::move_unit(route, *u, teams_);
01291
01292 units_.move(u->get_location(), route.back());
01293 u = units_.find(route.back());
01294
01295 unit::clear_status_caches();
01296 u->set_goto(action_copy.affected_unit.get_goto());
01297 u->set_movement(starting_moves);
01298 u->set_standing();
01299
01300 if(map_.is_village(route.back())) {
01301 get_village(route.back(), u->side());
01302
01303 if(action_copy.countdown_time_bonus)
01304 {
01305 current_team.set_action_bonus_count(1 + current_team.action_bonus_count());
01306 }
01307 }
01308
01309 gui_->invalidate_unit_after_move(route.front(), route.back());
01310 resources::whiteboard->on_gamestate_change();
01311
01312 recorder.add_movement(action_copy.route);
01313 }
01314 resources::undo_stack->push_back(action);
01315
01316 gui_->invalidate_unit();
01317 gui_->invalidate_game_status();
01318 gui_->redraw_minimap();
01319 gui_->draw();
01320 }
01321
01322 bool menu_handler::clear_shroud(int side_num)
01323 {
01324 bool cleared = teams_[side_num - 1].auto_shroud_updates() &&
01325 ::clear_shroud(side_num);
01326 return cleared;
01327 }
01328
01329 void menu_handler::clear_undo_stack(int side_num)
01330 {
01331 if (!teams_[side_num - 1].auto_shroud_updates())
01332 apply_shroud_changes(*resources::undo_stack, side_num);
01333 resources::undo_stack->clear();
01334 }
01335
01336
01337 void menu_handler::show_enemy_moves(bool ignore_units, int side_num)
01338 {
01339 wb::future_map future;
01340
01341 gui_->unhighlight_reach();
01342
01343
01344 for(unit_map::iterator u = units_.begin(); u != units_.end(); ++u) {
01345 bool invisible = u->invisible(u->get_location());
01346
01347 if (teams_[side_num - 1].is_enemy(u->side()) &&
01348 !gui_->fogged(u->get_location()) && !u->incapacitated() && !invisible)
01349 {
01350 const unit_movement_resetter move_reset(*u);
01351 const pathfind::paths& path = pathfind::paths(map_,units_,
01352 *u, teams_, false, true,
01353 teams_[gui_->viewing_team()], 0, false, ignore_units);
01354
01355 gui_->highlight_another_reach(path);
01356 }
01357 }
01358 }
01359
01360 void menu_handler::toggle_shroud_updates(int side_num)
01361 {
01362 team ¤t_team = teams_[side_num - 1];
01363 bool auto_shroud = current_team.auto_shroud_updates();
01364
01365 if (!auto_shroud) update_shroud_now(side_num);
01366 current_team.set_auto_shroud_updates(!auto_shroud);
01367 }
01368
01369 void menu_handler::update_shroud_now(int side_num)
01370 {
01371 clear_undo_stack(side_num);
01372 }
01373
01374 bool menu_handler::end_turn(int side_num)
01375 {
01376 if(!resources::state_of_game->allow_end_turn()) {
01377 gui2::show_message((*gui_).video(), "", _("You cannot end your turn yet!"), gui2::tmessage::ok_button);
01378 return false;
01379 }
01380
01381 bool unmoved_units = false, partmoved_units = false, some_units_have_moved = false;
01382 int units_alive = 0;
01383 for(unit_map::const_iterator un = units_.begin(); un != units_.end(); ++un) {
01384 if (un->side() == side_num) {
01385 units_alive++;
01386
01387
01388 if (unit_can_move(*un) && !resources::whiteboard->unit_has_actions(&*un)) {
01389 if (!un->has_moved()) {
01390 unmoved_units = true;
01391 }
01392
01393 partmoved_units = true;
01394 }
01395 if (un->has_moved()) {
01396 some_units_have_moved = true;
01397 }
01398 }
01399 }
01400
01401
01402 if (preferences::confirm_no_moves() && units_alive && !some_units_have_moved
01403 && !resources::whiteboard->current_side_has_actions()) {
01404 const int res = gui2::show_message((*gui_).video(), "", _("You have not started your turn yet. Do you really want to end your turn?"), gui2::tmessage::yes_no_buttons);
01405 if(res == gui2::twindow::CANCEL) {
01406 return false;
01407 }
01408 }
01409
01410
01411 if(preferences::yellow_confirm() && partmoved_units) {
01412 const int res = gui2::show_message((*gui_).video(), "", _("Some units have movement left. Do you really want to end your turn?"), gui2::tmessage::yes_no_buttons);
01413 if(res == gui2::twindow::CANCEL) {
01414 return false;
01415 }
01416 } else if (preferences::green_confirm() && unmoved_units) {
01417 const int res = gui2::show_message((*gui_).video(), "", _("Some units have movement left. Do you really want to end your turn?"), gui2::tmessage::yes_no_buttons);
01418 if(res == gui2::twindow::CANCEL) {
01419 return false;
01420 }
01421 }
01422
01423
01424
01425 if (!resources::whiteboard->allow_end_turn()) {
01426 return false;
01427 }
01428
01429 return true;
01430 }
01431
01432 void menu_handler::goto_leader(int side_num)
01433 {
01434 unit_map::const_iterator i = units_.find_leader(side_num);
01435 if(i != units_.end()) {
01436 clear_shroud(side_num);
01437 gui_->scroll_to_tile(i->get_location(), game_display::WARP);
01438 }
01439 }
01440
01441 void menu_handler::unit_description()
01442 {
01443 const unit_map::const_iterator un = current_unit();
01444 if(un != units_.end()) {
01445 dialogs::show_unit_description(*un);
01446 }
01447 }
01448
01449 void menu_handler::rename_unit()
01450 {
01451 const unit_map::iterator un = current_unit();
01452 if (un == units_.end() || gui_->viewing_side() != un->side())
01453 return;
01454 if (un->unrenamable())
01455 return;
01456
01457 std::string name = un->name();
01458 const int res = gui::show_dialog(*gui_,NULL,_("Rename Unit"),"", gui::OK_CANCEL,NULL,NULL,"",&name);
01459 if(res == 0) {
01460 recorder.add_rename(name, un->get_location());
01461 un->rename(name);
01462 gui_->invalidate_unit();
01463 }
01464 }
01465
01466 unit_map::iterator menu_handler::current_unit()
01467 {
01468 const mouse_handler& mousehandler = resources::controller->get_mouse_handler_base();
01469
01470 unit_map::iterator res = find_visible_unit(mousehandler.get_last_hex(),
01471 teams_[gui_->viewing_team()]);
01472 if(res != units_.end()) {
01473 return res;
01474 } else {
01475 return find_visible_unit(mousehandler.get_selected_hex(),
01476 teams_[gui_->viewing_team()]);
01477 }
01478 }
01479
01480 void menu_handler::create_unit_2(mouse_handler& mousehandler)
01481 {
01482 assert(gui_ != NULL);
01483
01484
01485
01486
01487 gui2::tunit_create create_dlg;
01488 create_dlg.show(gui_->video());
01489
01490 if(create_dlg.no_choice()) {
01491 return;
01492 }
01493
01494 const std::string& ut_id = create_dlg.choice();
01495 const unit_type *utp = unit_types.find(ut_id);
01496 if (!utp) {
01497 ERR_NG << "create unit dialog returned inexistent or unusable unit_type id '" << ut_id << "'\n";
01498 return;
01499 }
01500
01501 const unit_type &ut = *utp;
01502
01503 unit_race::GENDER gender = create_dlg.gender();
01504
01505
01506
01507 if(ut.genders().end() == std::find(ut.genders().begin(), ut.genders().end(), gender)) {
01508 gender = ut.genders().front();
01509 }
01510
01511 unit chosen(&ut, 1, true, gender);
01512 chosen.new_turn();
01513
01514 const map_location& loc = mousehandler.get_last_hex();
01515 units_.replace(loc, chosen);
01516
01517 if(map_.is_village(loc)) {
01518 get_village(loc, chosen.side());
01519 }
01520
01521 gui_->invalidate(loc);
01522 gui_->invalidate_unit();
01523 }
01524
01525 void menu_handler::create_unit(mouse_handler& mousehandler)
01526 {
01527
01528 if(gui2::new_widgets) {
01529 create_unit_2(mousehandler);
01530 return;
01531 }
01532
01533 std::vector<std::string> options;
01534 static int last_selection = -1;
01535 static bool random_gender = false;
01536 std::vector<const unit_type*> unit_choices;
01537 const std::string heading = std::string(1,HEADING_PREFIX) +
01538 _("Race") + COLUMN_SEPARATOR +
01539 _("Type");
01540 options.push_back(heading);
01541
01542 foreach (const unit_type_data::unit_type_map::value_type &i, unit_types.types())
01543 {
01544 std::stringstream row;
01545
01546 unit_types.find(i.first, unit_type::HELP_INDEX);
01547
01548 std::string race;
01549 if (const unit_race *r = unit_types.find_race(i.second.race())) {
01550 race = r->plural_name();
01551 }
01552 row << race << COLUMN_SEPARATOR;
01553 row << i.second.type_name() << COLUMN_SEPARATOR;
01554
01555 options.push_back(row.str());
01556 unit_choices.push_back(&i.second);
01557 }
01558
01559 int choice = 0;
01560 bool random_gender_choice = random_gender;
01561 {
01562 gui::dialog umenu(*gui_, _("Create Unit (Debug!)"), "", gui::OK_CANCEL);
01563
01564 umenu.add_option(
01565 (formatter()<<_("Gender: ")<<_("gender^Random")).str(),
01566 random_gender_choice,
01567 gui::dialog::BUTTON_EXTRA
01568 );
01569
01570 gui::menu::basic_sorter sorter;
01571 sorter.set_alpha_sort(0).set_alpha_sort(1);
01572 umenu.set_menu(options, &sorter);
01573
01574 gui::filter_textbox* filter = new gui::filter_textbox(gui_->video(),
01575 _("Filter: "), options, options, 1, umenu, 200);
01576 umenu.set_textbox(filter);
01577
01578
01579 umenu.get_menu().sort_by(1);
01580 umenu.get_menu().sort_by(0);
01581 if (last_selection >= 0)
01582 umenu.get_menu().move_selection(last_selection);
01583 else
01584 umenu.get_menu().reset_selection();
01585
01586 dialogs::unit_types_preview_pane unit_preview(unit_choices, filter, 1, dialogs::unit_types_preview_pane::SHOW_ALL);
01587 umenu.add_pane(&unit_preview);
01588 unit_preview.set_selection(umenu.get_menu().selection());
01589
01590 choice = umenu.show();
01591 choice = filter->get_index(choice);
01592 random_gender_choice = umenu.option_checked(0);
01593 }
01594
01595 if (size_t(choice) < unit_choices.size()) {
01596 last_selection = choice;
01597 random_gender = random_gender_choice;
01598
01599 const unit_type* type = unit_choices[choice];
01600 const unit_race::GENDER gender = random_gender ? unit_race::NUM_GENDERS :
01601 type->genders().empty() ? unit_race::MALE : type->genders().front();
01602
01603 unit chosen(type, 1, true, gender);
01604 chosen.new_turn();
01605
01606 const map_location loc = mousehandler.get_last_hex();
01607 units_.replace(loc, chosen);
01608 unit_display::unit_recruited(loc);
01609
01610 if(map_.is_village(loc)) {
01611 get_village(loc, chosen.side());
01612 }
01613
01614 gui_->invalidate(loc);
01615 gui_->invalidate_unit();
01616 }
01617 }
01618
01619 void menu_handler::change_side(mouse_handler& mousehandler)
01620 {
01621 const map_location& loc = mousehandler.get_last_hex();
01622 const unit_map::iterator i = units_.find(loc);
01623 if(i == units_.end()) {
01624 if(!map_.is_village(loc))
01625 return;
01626
01627
01628 int team = village_owner(loc, teams_) + 1;
01629
01630
01631 if(team > team::nteams()) {
01632 team = 0;
01633 }
01634 get_village(loc, team + 1);
01635 } else {
01636 int side = i->side();
01637 ++side;
01638 if(side > team::nteams()) {
01639 side = 1;
01640 }
01641 i->set_side(side);
01642
01643 if(map_.is_village(loc)) {
01644 get_village(loc, side);
01645 }
01646 }
01647 }
01648
01649 void menu_handler::label_terrain(mouse_handler& mousehandler, bool team_only)
01650 {
01651 const map_location& loc = mousehandler.get_last_hex();
01652 if (map_.on_board(loc) == false) {
01653 return;
01654 }
01655
01656 const terrain_label* old_label = gui_->labels().get_label(loc);
01657 std::string label = old_label ? old_label->text() : "";
01658
01659 if(gui2::tedit_label::execute(label, team_only, gui_->video())) {
01660 std::string team_name;
01661 SDL_Color color = font::LABEL_COLOR;
01662
01663 if (team_only) {
01664 team_name = gui_->labels().team_name();
01665 } else {
01666 color = int_to_color(team::get_side_rgb(gui_->viewing_side()));
01667 }
01668 const std::string& old_team_name = old_label ? old_label->team_name() : "";
01669
01670 if (team_only == (old_team_name == "")) {
01671 const terrain_label* old = gui_->labels().set_label(loc, "", old_team_name, color);
01672 if (old) recorder.add_label(old);
01673 }
01674 const terrain_label* res = gui_->labels().set_label(loc, label, team_name, color);
01675 if (res)
01676 recorder.add_label(res);
01677 }
01678 }
01679
01680 void menu_handler::clear_labels()
01681 {
01682 if (gui_->team_valid()
01683 && !is_observer())
01684 {
01685 gui_->labels().clear(gui_->current_team_name(), false);
01686 recorder.clear_labels(gui_->current_team_name(), false);
01687 }
01688 }
01689
01690 void menu_handler::continue_move(mouse_handler &mousehandler, int side_num)
01691 {
01692 unit_map::iterator i = current_unit();
01693 if (i == units_.end() || !i->move_interrupted()) {
01694 i = units_.find(mousehandler.get_selected_hex());
01695 if (i == units_.end() || !i->move_interrupted()) return;
01696 }
01697 move_unit_to_loc(i, i->get_interrupted_move(), true,
01698 side_num, mousehandler);
01699 }
01700
01701 void menu_handler::move_unit_to_loc(const unit_map::iterator &ui,
01702 const map_location& target, bool continue_move, int side_num,
01703 mouse_handler &mousehandler)
01704 {
01705 assert(ui != units_.end());
01706
01707 pathfind::marked_route route = mousehandler.get_route(&*ui, target, teams_[side_num - 1]);
01708
01709 if(route.steps.empty())
01710 return;
01711
01712 assert(route.steps.front() == ui->get_location());
01713
01714 gui_->set_route(&route);
01715 move_unit(NULL, route.steps, &recorder, resources::undo_stack, true, NULL, continue_move);
01716 gui_->invalidate_game_status();
01717 }
01718
01719 void menu_handler::execute_gotos(mouse_handler &mousehandler, int side)
01720 {
01721
01722
01723
01724
01725 bool wait_blocker_move = true;
01726 std::set<map_location> fully_moved;
01727
01728 bool change = false;
01729 bool blocked_unit = false;
01730 do {
01731 change = false;
01732 blocked_unit = false;
01733 for(unit_map::iterator ui = units_.begin(); ui != units_.end(); ++ui) {
01734 if (ui->side() != side || ui->movement_left() == 0)
01735 continue;
01736
01737 const map_location ¤t_loc = ui->get_location();
01738 const map_location &goto_loc = ui->get_goto();
01739
01740 if(goto_loc == current_loc){
01741 ui->set_goto(map_location());
01742 continue;
01743 }
01744
01745 if(!map_.on_board(goto_loc))
01746 continue;
01747
01748
01749 if(fully_moved.count(current_loc))
01750 continue;
01751
01752 pathfind::marked_route route = mousehandler.get_route(&*ui, goto_loc, teams_[side - 1]);
01753
01754 if(route.steps.size() <= 1) {
01755 fully_moved.insert(current_loc);
01756 continue;
01757 }
01758
01759
01760 map_location next_stop = goto_loc;
01761 pathfind::marked_route::mark_map::const_iterator w = route.marks.begin();
01762 for(; w != route.marks.end(); ++w) {
01763 if (w->second.turns == 1) {
01764 next_stop = w->first;
01765 break;
01766 }
01767 }
01768
01769 if(next_stop == current_loc) {
01770 fully_moved.insert(current_loc);
01771 continue;
01772 }
01773
01774
01775
01776 if(units_.count(next_stop)) {
01777 blocked_unit = true;
01778 if (wait_blocker_move)
01779 continue;
01780 }
01781
01782 gui_->set_route(&route);
01783 int moves = ::move_unit(NULL, route.steps, &recorder, resources::undo_stack, true, NULL, false);
01784 change = moves > 0;
01785
01786 if (change) {
01787
01788 wait_blocker_move = true;
01789 }
01790 }
01791
01792 if(!change && wait_blocker_move) {
01793
01794 wait_blocker_move = false;
01795 change = true;
01796 }
01797 } while(change && blocked_unit);
01798
01799
01800 gui_->set_route(NULL);
01801 gui_->invalidate_game_status();
01802 }
01803
01804
01805 void menu_handler::toggle_ellipses()
01806 {
01807 preferences::set_ellipses(!preferences::ellipses());
01808 gui_->invalidate_all();
01809 }
01810
01811 void menu_handler::toggle_grid()
01812 {
01813 preferences::set_grid(!preferences::grid());
01814 gui_->invalidate_all();
01815 }
01816
01817 void menu_handler::unit_hold_position(mouse_handler &mousehandler, int side_num)
01818 {
01819 const unit_map::iterator un = units_.find(mousehandler.get_selected_hex());
01820 if (un != units_.end() && un->side() == side_num && un->movement_left() >= 0)
01821 {
01822 un->set_hold_position(!un->hold_position());
01823 gui_->invalidate(mousehandler.get_selected_hex());
01824
01825 mousehandler.set_current_paths(pathfind::paths());
01826 gui_->draw();
01827
01828 if (un->hold_position()) {
01829 un->set_user_end_turn(true);
01830 mousehandler.cycle_units(false);
01831 }
01832 }
01833 }
01834
01835 void menu_handler::end_unit_turn(mouse_handler &mousehandler, int side_num)
01836 {
01837 const unit_map::iterator un = units_.find(mousehandler.get_selected_hex());
01838 if (un != units_.end() && un->side() == side_num && un->movement_left() >= 0)
01839 {
01840 un->set_user_end_turn(!un->user_end_turn());
01841 if (un->hold_position() && !un->user_end_turn()) {
01842 un->set_hold_position(false);
01843 }
01844 gui_->invalidate(mousehandler.get_selected_hex());
01845
01846 mousehandler.set_current_paths(pathfind::paths());
01847 gui_->draw();
01848
01849 if (un->user_end_turn()) {
01850 mousehandler.cycle_units(false);
01851 }
01852 }
01853 }
01854
01855 void menu_handler::search()
01856 {
01857 std::ostringstream msg;
01858 msg << _("Search");
01859 if(last_search_hit_.valid()) {
01860 msg << " [" << last_search_ << "]";
01861 }
01862 msg << ':';
01863 textbox_info_.show(gui::TEXTBOX_SEARCH,msg.str(), "", false, *gui_);
01864 }
01865
01866 void menu_handler::do_speak(){
01867
01868
01869 chat_handler::do_speak(textbox_info_.box()->text(),textbox_info_.check() != NULL ? textbox_info_.check()->checked() : false);
01870 }
01871
01872
01873 void menu_handler::add_chat_message(const time_t& time,
01874 const std::string& speaker, int side, const std::string& message,
01875 events::chat_handler::MESSAGE_TYPE type)
01876 {
01877 gui_->add_chat_message(time, speaker, side, message, type, false);
01878 }
01879
01880
01881
01882
01883
01884
01885 class cmd_arg_parser
01886 {
01887 public:
01888 cmd_arg_parser() :
01889 str_(""),
01890 args(1, 0),
01891 args_end(false)
01892 {
01893 }
01894
01895 explicit cmd_arg_parser(const std::string& str) :
01896 str_(str),
01897 args(1, 0),
01898 args_end(false)
01899 {
01900 }
01901
01902 void parse(const std::string& str)
01903 {
01904 str_ = str;
01905 args.clear();
01906 args.push_back(0);
01907 args_end = false;
01908 }
01909
01910 const std::string& get_str() const
01911 {
01912 return str_;
01913 }
01914 std::string get_arg(unsigned n) const
01915 {
01916 advance_to_arg(n);
01917 if (n < args.size()) {
01918 return std::string(str_, args[n], str_.find(' ', args[n]) - args[n]);
01919 } else {
01920 return "";
01921 }
01922 }
01923 std::string get_data(unsigned n) const
01924 {
01925 advance_to_arg(n);
01926 if (n < args.size()) {
01927 std::string data(str_, args[n]);
01928 return utils::strip(data);
01929 } else {
01930 return "";
01931 }
01932 }
01933 std::string get_cmd() const
01934 {
01935 return get_arg(0);
01936 }
01937 private:
01938 cmd_arg_parser& operator=(const cmd_arg_parser&);
01939 cmd_arg_parser(const cmd_arg_parser&);
01940 void advance_to_arg(unsigned n) const
01941 {
01942 while (n < args.size() && !args_end) {
01943 size_t first_space = str_.find_first_of(' ', args.back());
01944 size_t next_arg_begin = str_.find_first_not_of(' ', first_space);
01945 if (next_arg_begin != std::string::npos) {
01946 args.push_back(next_arg_begin);
01947 } else {
01948 args_end = true;
01949 }
01950 }
01951 }
01952 std::string str_;
01953 mutable std::vector<size_t> args;
01954 mutable bool args_end;
01955 };
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969 template <class Worker>
01970 class map_command_handler
01971 {
01972 public:
01973 typedef void (Worker::*command_handler)();
01974 struct command
01975 {
01976 command_handler handler;
01977 std::string help;
01978 std::string usage;
01979 std::string flags;
01980 explicit command(command_handler h, const std::string help="",
01981 const std::string& usage="", const std::string flags="")
01982 : handler(h), help(help), usage(usage), flags(flags)
01983 {
01984 }
01985 bool has_flag(const char f) const
01986 {
01987 return flags.find(f) != flags.npos;
01988 }
01989 command& add_flag(const char f)
01990 {
01991 flags += f;
01992 return *this;
01993 }
01994 };
01995 typedef std::map<std::string, command> command_map;
01996 typedef std::map<std::string, std::string> command_alias_map;
01997
01998 map_command_handler() : cap_("")
01999 {
02000 }
02001
02002 virtual ~map_command_handler() {}
02003
02004 bool empty() const
02005 {
02006 return command_map_.empty();
02007 }
02008
02009 void dispatch(std::string cmd)
02010 {
02011 if (empty()) {
02012 init_map_default();
02013 init_map();
02014 }
02015
02016
02017 for (int i=0; i < 100; ++i) {
02018 parse_cmd(cmd);
02019 std::string actual_cmd = get_actual_cmd(get_cmd());
02020 if (actual_cmd == get_cmd())
02021 break;
02022 std::string data = get_data(1);
02023
02024 cmd = actual_cmd + (data.empty() ? "" : " ") + data;
02025 }
02026
02027 if (get_cmd().empty()) {
02028 return;
02029 }
02030
02031 if (const command* c = get_command(get_cmd())) {
02032 if (is_enabled(*c)) {
02033 (static_cast<Worker*>(this)->*(c->handler))();
02034 } else {
02035 print(get_cmd(), _("This command is currently unavailable."));
02036 }
02037 } else if (help_on_unknown_) {
02038 utils::string_map symbols;
02039 symbols["command"] = get_cmd();
02040 symbols["help_command"] = cmd_prefix_ + "help";
02041 print("help", VGETTEXT("Unknown command '$command', try $help_command "
02042 "for a list of available commands.", symbols));
02043 }
02044 }
02045
02046 std::vector<std::string> get_commands_list() const
02047 {
02048 std::vector<std::string> res;
02049 foreach(typename command_map::value_type i, command_map_) {
02050 res.push_back(i.first);
02051 }
02052 return res;
02053 }
02054
02055 protected:
02056 void init_map_default()
02057 {
02058 register_command("help", &map_command_handler<Worker>::help,
02059 _("Available commands list and command-specific help. "
02060 "Use \"help all\" to include currently unavailable commands."),
02061 _("do not translate the 'all'^[all|<command>]"));
02062 }
02063
02064 virtual void init_map() = 0;
02065
02066 virtual void print(const std::string& title, const std::string& message) = 0;
02067
02068
02069 virtual std::string get_flags_description() const
02070 {
02071 return "";
02072 }
02073
02074 virtual std::string get_command_flags_description(const command& ) const
02075 {
02076 return "";
02077 }
02078
02079
02080 virtual bool is_enabled(const command& ) const
02081 {
02082 return true;
02083 }
02084 virtual void parse_cmd(const std::string& cmd_string)
02085 {
02086 cap_.parse(cmd_string);
02087 }
02088
02089 virtual std::string get_arg(unsigned argn) const
02090 {
02091 return cap_.get_arg(argn);
02092 }
02093
02094 virtual std::string get_data(unsigned argn = 1) const
02095 {
02096 return cap_.get_data(argn);
02097 }
02098 virtual std::string get_cmd() const
02099 {
02100 return cap_.get_cmd();
02101 }
02102
02103 void command_failed(const std::string& message)
02104 {
02105 print(get_cmd(), _("Error:") + std::string(" ") + message);
02106 }
02107 void command_failed_need_arg(int argn)
02108 {
02109 utils::string_map symbols;
02110 symbols["arg_id"] = lexical_cast<std::string>(argn);
02111 command_failed(VGETTEXT("Missing argument $arg_id", symbols));
02112 }
02113 void print_usage()
02114 {
02115 help_command(get_cmd());
02116 }
02117
02118 std::string get_actual_cmd(const std::string& cmd) const
02119 {
02120 command_alias_map::const_iterator i = command_alias_map_.find(cmd);
02121 return i != command_alias_map_.end() ? i->second : cmd;
02122 }
02123 const command* get_command(const std::string& cmd) const
02124 {
02125 typename command_map::const_iterator i = command_map_.find(cmd);
02126 return i != command_map_.end() ? &i->second : 0;
02127 }
02128 command* get_command(const std::string& cmd)
02129 {
02130 typename command_map::iterator i = command_map_.find(cmd);
02131 return i != command_map_.end() ? &i->second : 0;
02132 }
02133 void help()
02134 {
02135
02136 if (help_command(get_arg(1))) {
02137 return;
02138 }
02139 std::stringstream ss;
02140 bool show_unavail = show_unavailable_ || get_arg(1) == "all";
02141 BOOST_FOREACH(typename command_map::value_type i, command_map_) {
02142 if (show_unavail || is_enabled(i.second)) {
02143 ss << i.first;
02144
02145
02146
02147
02148
02149 if (!i.second.flags.empty()) {
02150 ss << " (" << i.second.flags << ") ";
02151 }
02152 ss << "; ";
02153 }
02154 }
02155 utils::string_map symbols;
02156 symbols["flags_description"] = get_flags_description();
02157 symbols["list_of_commands"] = ss.str();
02158 symbols["help_command"] = cmd_prefix_ + "help";
02159 print(_("help"), VGETTEXT("Available commands $flags_description:\n$list_of_commands", symbols));
02160 print(_("help"), VGETTEXT("Type $help_command <command> for more info.", symbols));
02161 }
02162
02163 bool help_command(const std::string& acmd)
02164 {
02165 std::string cmd = get_actual_cmd(acmd);
02166 const command* c = get_command(cmd);
02167 if (c) {
02168 std::stringstream ss;
02169 ss << cmd_prefix_ << cmd;
02170 if (c->help.empty() && c->usage.empty()) {
02171 ss << _(" No help available.");
02172 } else {
02173 ss << " - " << c->help;
02174 }
02175 if (!c->usage.empty()) {
02176 ss << " " << _("Usage:") << " " << cmd_prefix_ << cmd << " " << c->usage;
02177 }
02178 ss << get_command_flags_description(*c);
02179 const std::vector<std::string> l = get_aliases(cmd);
02180 if (!l.empty()) {
02181 ss << " (" << _("aliases:") << " " << utils::join(l," ") << ")";
02182 }
02183 print(_("help"), ss.str());
02184 }
02185 return c != 0;
02186 }
02187 cmd_arg_parser cap_;
02188 protected:
02189
02190 static void set_help_on_unknown(bool value)
02191 {
02192 help_on_unknown_ = value;
02193 }
02194
02195 static void set_cmd_prefix(std::string value)
02196 {
02197 cmd_prefix_ = value;
02198 }
02199 virtual void register_command(const std::string& cmd,
02200 command_handler h, const std::string& help="",
02201 const std::string& usage="", const std::string& flags="")
02202 {
02203 command c = command(h, help, usage, flags);
02204 std::pair<typename command_map::iterator, bool> r;
02205 r = command_map_.insert(typename command_map::value_type(cmd, c));
02206 if (!r.second) {
02207 r.first->second = c;
02208 }
02209 }
02210 virtual void assert_existence(const std::string& cmd) {
02211 assert(command_map_.count(cmd));
02212 }
02213 virtual void register_alias(const std::string& to_cmd,
02214 const std::string& cmd)
02215 {
02216
02217
02218
02219 command_alias_map_[cmd] = to_cmd;
02220 }
02221
02222 static const std::vector<std::string> get_aliases(const std::string& cmd)
02223 {
02224 std::vector<std::string> aliases;
02225 typedef command_alias_map::value_type p;
02226 BOOST_FOREACH(p i, command_alias_map_) {
02227 if (i.second == cmd) {
02228 aliases.push_back(i.first);
02229 }
02230 }
02231 return aliases;
02232 }
02233 private:
02234 static command_map command_map_;
02235 static command_alias_map command_alias_map_;
02236 static bool help_on_unknown_;
02237 static bool show_unavailable_;
02238 static std::string cmd_prefix_;
02239 };
02240
02241
02242 template <class Worker>
02243 typename map_command_handler<Worker>::command_map map_command_handler<Worker>::command_map_;
02244
02245 template <class Worker>
02246 typename map_command_handler<Worker>::command_alias_map map_command_handler<Worker>::command_alias_map_;
02247
02248 template <class Worker>
02249 bool map_command_handler<Worker>::help_on_unknown_ = true;
02250
02251 template <class Worker>
02252 bool map_command_handler<Worker>::show_unavailable_ = false;
02253
02254 template <class Worker>
02255 std::string map_command_handler<Worker>::cmd_prefix_;
02256
02257
02258 class chat_command_handler : public map_command_handler<chat_command_handler>
02259 {
02260 public:
02261 typedef map_command_handler<chat_command_handler> map;
02262 chat_command_handler(chat_handler& chathandler, bool allies_only)
02263 : map(), chat_handler_(chathandler), allies_only_(allies_only)
02264 {
02265 }
02266
02267 protected:
02268 void do_emote();
02269 void do_network_send();
02270 void do_network_send_req_arg();
02271 void do_room_query();
02272 void do_room_query_noarg();
02273 void do_gen_room_query();
02274 void do_whisper();
02275 void do_chanmsg();
02276 void do_log();
02277 void do_ignore();
02278 void do_friend();
02279 void do_remove();
02280 void do_display();
02281 void do_version();
02282
02283
02284 void do_register();
02285
02286
02287 void do_drop();
02288
02289
02290 void do_set();
02291
02292
02293 void do_info();
02294
02295
02296
02297
02298
02299 void do_details();
02300
02301 std::string get_flags_description() const {
02302 return _("(A) — admin command");
02303 }
02304
02305 std::string get_command_flags_description(
02306 const map_command_handler<chat_command_handler>::command& c) const
02307 {
02308 if (c.has_flag('A')) {
02309 return std::string(" ") + _("(admin only)");
02310 } else {
02311 return "";
02312 }
02313 }
02314
02315 bool is_enabled(
02316 const map_command_handler<chat_command_handler>::command& c) const
02317 {
02318 return !(c.has_flag('A') && !preferences::is_authenticated());
02319 }
02320
02321 void print(const std::string& title, const std::string& message)
02322 {
02323 chat_handler_.add_chat_message(time(NULL), title, 0, message);
02324 }
02325 void init_map()
02326 {
02327 set_cmd_prefix("/");
02328 register_command("query", &chat_command_handler::do_network_send,
02329 _("Send a query to the server. Without arguments the server"
02330 " should tell you the available commands."));
02331 register_alias("query", "q");
02332 register_command("ban", &chat_command_handler::do_network_send_req_arg,
02333 _("Ban and kick a player or observer. If he is not in the"
02334 " game but on the server he will only be banned."), _("<nickname>"));
02335 register_command("unban", &chat_command_handler::do_network_send_req_arg,
02336 _("Unban a user. He does not have to be in the game but on"
02337 " the server."), _("<nickname>"));
02338 register_command("kick", &chat_command_handler::do_network_send_req_arg,
02339 _("Kick a player or observer."), _("<nickname>"));
02340 register_command("mute", &chat_command_handler::do_network_send,
02341 _("Mute an observer. Without an argument displays the mute status."), _("<nickname>"));
02342 register_command("unmute", &chat_command_handler::do_network_send,
02343 _("Unmute an observer. Without an argument unmutes everyone."), _("<nickname>"));
02344 register_command("muteall", &chat_command_handler::do_network_send,
02345 _("Mute/Unmute all observers. (toggles)"), "");
02346 register_command("ping", &chat_command_handler::do_network_send,
02347 "");
02348 register_command("green", &chat_command_handler::do_network_send_req_arg,
02349 "", "", "A");
02350 register_command("red", &chat_command_handler::do_network_send_req_arg,
02351 "", "", "A");
02352 register_command("yellow", &chat_command_handler::do_network_send_req_arg,
02353 "", "", "A");
02354 register_command("report", &chat_command_handler::do_network_send_req_arg,
02355 _("Report abuse, rule violations, etc. to the server moderators. "
02356 "Make sure to mention relevant nicknames, etc."), "");
02357 register_alias("report", "adminmsg");
02358 register_command("emote", &chat_command_handler::do_emote,
02359 _("Send an emotion or personal action in chat."), _("<message>"));
02360 register_alias("emote", "me");
02361 register_command("whisper", &chat_command_handler::do_whisper,
02362 _("Sends a private message. "
02363 "You cannot send private messages to players in a running game you observe or play in."),
02364 _("<nickname> <message>"));
02365 register_alias("whisper", "msg");
02366 register_alias("whisper", "m");
02367 register_command("log", &chat_command_handler::do_log,
02368 _("Change the log level of a log domain."), _("<level> <domain>"));
02369 register_command("ignore", &chat_command_handler::do_ignore,
02370 _("Add a nickname to your ignores list."), _("<nickname>"));
02371 register_command("friend", &chat_command_handler::do_friend,
02372 _("Add a nickname to your friends list."), _("<nickname>"));
02373 register_command("remove", &chat_command_handler::do_remove,
02374 _("Remove a nickname from your ignores or friends list."), _("<nickname>"));
02375 register_command("list", &chat_command_handler::do_display,
02376 _("Show your ignores and friends list."));
02377 register_alias("list", "display");
02378 register_command("version", &chat_command_handler::do_version,
02379 _("Display version information."));
02380 register_command("register", &chat_command_handler::do_register,
02381 _("Register your nickname"), _("<password> <email (optional)>"));
02382 register_command("drop", &chat_command_handler::do_drop,
02383 _("Drop your nickname."));
02384 register_command("set", &chat_command_handler::do_set,
02385 _("Update details for your nickname. For possible details see '/details'."),
02386 _("<detail> <value>"));
02387 register_command("info", &chat_command_handler::do_info,
02388 _("Request information about a nickname."), _("<nickname>"));
02389 register_command("details", &chat_command_handler::do_details,
02390 _("Request a list of details you can set for your registered nickname."));
02391 register_command("join", &chat_command_handler::do_network_send_req_arg,
02392 _("Join a room."), _("<room>"));
02393 register_alias("join", "j");
02394 register_command("part", &chat_command_handler::do_network_send_req_arg,
02395 _("Part a room."), _("<room>"));
02396 register_command("names", &chat_command_handler::do_room_query,
02397 _("List room members."), _("<room>"));
02398 register_command("rooms", &chat_command_handler::do_room_query_noarg,
02399 _("List available rooms."));
02400 register_command("room", &chat_command_handler::do_chanmsg,
02401 _("Room message."), _("<room> <msg>"));
02402 register_command("room_query", &chat_command_handler::do_gen_room_query,
02403 _("Room query."), _("<room> <type> [value]"));
02404 register_alias("room_query", "rq");
02405 }
02406 private:
02407 chat_handler& chat_handler_;
02408 bool allies_only_;
02409 };
02410
02411
02412
02413 class console_handler : public map_command_handler<console_handler>, private chat_command_handler
02414 {
02415 public:
02416
02417 typedef map_command_handler<console_handler> chmap;
02418 console_handler(menu_handler& menu_handler)
02419 : chmap(), chat_command_handler(menu_handler, true), menu_handler_(menu_handler), team_num_(resources::controller->current_side())
02420 {}
02421 using chmap::dispatch;
02422 using chmap::get_commands_list;
02423
02424 protected:
02425
02426
02427 virtual void register_command(const std::string& cmd,
02428 chat_command_handler::command_handler h, const std::string& help="",
02429 const std::string& usage="", const std::string& flags="")
02430 {
02431 chmap::register_command(cmd, h, help, usage, flags + "N");
02432 }
02433 virtual void assert_existence(const std::string& cmd) {
02434 chmap::assert_existence(cmd);
02435 }
02436 virtual void register_alias(const std::string& to_cmd,
02437 const std::string& cmd)
02438 {
02439 chmap::register_alias(to_cmd, cmd);
02440 }
02441 virtual std::string get_arg(unsigned i) const
02442 {
02443 return chmap::get_arg(i);
02444 }
02445 virtual std::string get_cmd() const
02446 {
02447 return chmap::get_cmd();
02448 }
02449 virtual std::string get_data(unsigned n = 1) const
02450 {
02451 return chmap::get_data(n);
02452 }
02453
02454
02455 using chmap::register_command;
02456 using chmap::register_alias;
02457 using chmap::help;
02458 using chmap::is_enabled;
02459 using chmap::command_failed;
02460 using chmap::command_failed_need_arg;
02461
02462 void do_refresh();
02463 void do_droid();
02464 void do_theme();
02465 void do_control();
02466 void do_clear();
02467 void do_sunset();
02468 void do_foreground();
02469 void do_layers();
02470 void do_fps();
02471 void do_benchmark();
02472 void do_save();
02473 void do_save_quit();
02474 void do_quit();
02475 void do_ignore_replay_errors();
02476 void do_nosaves();
02477 void do_next_level();
02478 void do_choose_level();
02479 void do_turn();
02480 void do_turn_limit();
02481 void do_debug();
02482 void do_nodebug();
02483 void do_lua();
02484 void do_unsafe_lua();
02485 void do_custom();
02486 void do_set_alias();
02487 void do_set_var();
02488 void do_show_var();
02489 void do_inspect();
02490 void do_control_dialog();
02491 void do_manage();
02492 void do_unit();
02493
02494
02495 void do_discover();
02496 void do_undiscover();
02497 void do_create();
02498 void do_fog();
02499 void do_shroud();
02500 void do_gold();
02501 void do_event();
02502 void do_toggle_draw_coordinates();
02503 void do_toggle_draw_terrain_codes();
02504 void do_toggle_whiteboard();
02505 void do_whiteboard_options();
02506
02507 std::string get_flags_description() const {
02508 return _("(D) — debug only, (N) — network only, (A) — admin only");
02509 }
02510 using chat_command_handler::get_command_flags_description;
02511 std::string get_command_flags_description(const chmap::command& c) const
02512 {
02513 std::string space(" ");
02514 return std::string(c.has_flag('D') ? space + _("(debug command)") : "")
02515 + std::string(c.has_flag('N') ? space + _("(network only)") : "")
02516 + std::string(c.has_flag('A') ? space + _("(admin only)") : "");
02517 }
02518 using map::is_enabled;
02519 bool is_enabled(const chmap::command& c) const
02520 {
02521 return !((c.has_flag('D') && !game_config::debug)
02522 || (c.has_flag('N') && network::nconnections() == 0)
02523 || (c.has_flag('A') && !preferences::is_authenticated()));
02524 }
02525 void print(const std::string& title, const std::string& message)
02526 {
02527 menu_handler_.add_chat_message(time(NULL), title, 0, message);
02528 }
02529 void init_map()
02530 {
02531 chat_command_handler::init_map();
02532 chmap::get_command("log")->flags = "";
02533 chmap::get_command("version")->flags = "";
02534 chmap::get_command("ignore")->flags = "";
02535 chmap::get_command("friend")->flags = "";
02536 chmap::get_command("list")->flags = "";
02537 chmap::get_command("remove")->flags = "";
02538 chmap::set_cmd_prefix(":");
02539 register_command("refresh", &console_handler::do_refresh,
02540 _("Refresh gui."));
02541 register_command("droid", &console_handler::do_droid,
02542 _("Switch a side to/from AI control."), _("do not translate the on/off^[<side> [on/off]]"));
02543 register_command("theme", &console_handler::do_theme);
02544 register_command("control", &console_handler::do_control,
02545 _("Assign control of a side to a different player or observer."), _("<side> <nickname>"), "N");
02546 register_command("clear", &console_handler::do_clear,
02547 _("Clear chat history."));
02548 register_command("sunset", &console_handler::do_sunset,
02549 _("Visualize the screen refresh procedure."), "", "D");
02550 register_command("foreground", &console_handler::do_foreground,
02551 _("Debug foreground terrain."), "", "D");
02552 register_command("layers", &console_handler::do_layers,
02553 _("Debug layers from terrain under the mouse."), "", "D");
02554 register_command("fps", &console_handler::do_fps, _("Show fps."));
02555 register_command("benchmark", &console_handler::do_benchmark);
02556 register_command("save", &console_handler::do_save, _("Save game."));
02557 register_alias("save", "w");
02558 register_command("quit", &console_handler::do_quit, _("Quit game."));
02559
02560 register_alias("quit", "q!");
02561 register_command("save_quit", &console_handler::do_save_quit,
02562 _("Save and quit."));
02563 register_alias("save_quit", "wq");
02564 register_command("ignore_replay_errors", &console_handler::do_ignore_replay_errors,
02565 _("Ignore replay errors."));
02566 register_command("nosaves", &console_handler::do_nosaves,
02567 _("Disable autosaves."));
02568 register_command("next_level", &console_handler::do_next_level,
02569 _("Advance to the next scenario, or scenario identified by 'id'"), _("<id>"), "D");
02570 register_alias("next_level", "n");
02571 register_command("choose_level", &console_handler::do_choose_level,
02572 _("Choose next scenario"), "", "D");
02573 register_alias("choose_level", "cl");
02574 register_command("turn", &console_handler::do_turn,
02575 _("Change turn number (and time of day), or increase by one if no number is specified."), _("[turn]"), "D");
02576 register_command("turn_limit", &console_handler::do_turn_limit,
02577 _("Change turn limit, or turn the turn limit off if no number is specified or it’s −1."), _("[limit]"), "D");
02578 register_command("debug", &console_handler::do_debug,
02579 _("Turn debug mode on."));
02580 register_command("nodebug", &console_handler::do_nodebug,
02581 _("Turn debug mode off."), "", "D");
02582 register_command("lua", &console_handler::do_lua,
02583 _("Execute a Lua statement."), _("<command>[;<command>...]"), "D");
02584 register_command("unsafe_lua", &console_handler::do_unsafe_lua,
02585 _("Grant higher privileges to Lua scripts."), "", "D");
02586 register_command("custom", &console_handler::do_custom,
02587 _("Set the command used by the custom command hotkey"), _("<command>[;<command>...]"));
02588 register_command("give_control"
02589 , &console_handler::do_control_dialog
02590 , _("Invoke a dialog allowing changing control of MP sides.")
02591 , ""
02592 , "N");
02593 register_command("inspect", &console_handler::do_inspect,
02594 _("Launch the gamestate inspector"), "", "D");
02595 register_command("manage", &console_handler::do_manage,
02596 _("Manage persistence data"), "", "D");
02597 register_command("alias", &console_handler::do_set_alias,
02598 _("Set or show alias to a command"), _("<name>[=<command>]"));
02599 register_command("set_var", &console_handler::do_set_var,
02600 _("Set a scenario variable."), _("<var>=<value>"), "D");
02601 register_command("show_var", &console_handler::do_show_var,
02602 _("Show a scenario variable."), _("<var>"), "D");
02603 register_command("unit", &console_handler::do_unit,
02604 _("Modify a unit variable. (Only top level keys are supported.)"), "", "D");
02605
02606
02607
02608
02609
02610 register_command("discover", &console_handler::do_discover,
02611 _("Discover all units in help."), "");
02612 register_command("undiscover", &console_handler::do_undiscover,
02613 _("'Undiscover' all units in help."), "");
02614 register_command("create", &console_handler::do_create,
02615 _("Create a unit."), "", "D");
02616 register_command("fog", &console_handler::do_fog,
02617 _("Toggle fog for the current player."), "", "D");
02618 register_command("shroud", &console_handler::do_shroud,
02619 _("Toggle shroud for the current player."), "", "D");
02620 register_command("gold", &console_handler::do_gold,
02621 _("Give gold to the current player."), "", "D");
02622 register_command("throw", &console_handler::do_event,
02623 _("Fire a game event."), "", "D");
02624 register_alias("throw", "fire");
02625 register_command("show_coordinates", &console_handler::do_toggle_draw_coordinates,
02626 _("Toggle overlaying of x,y coordinates on hexes."));
02627 register_alias("show_coordinates", "sc");
02628 register_command("show_terrain_codes", &console_handler::do_toggle_draw_terrain_codes,
02629 _("Toggle overlaying of terrain codes on hexes."));
02630 register_alias("show_terrain_codes", "tc");
02631 register_command("whiteboard", &console_handler::do_toggle_whiteboard,
02632 _("Toggle planning mode."));
02633 register_alias("whiteboard", "wb");
02634 register_command("whiteboard_options", &console_handler::do_whiteboard_options,
02635 _("Access whiteboard options dialog."));
02636 register_alias("whiteboard_options", "wbo");
02637
02638 if (const config &alias_list = preferences::get_alias())
02639 {
02640 foreach (const config::attribute &a, alias_list.attribute_range()) {
02641 register_alias(a.second, a.first);
02642 }
02643 }
02644 }
02645 private:
02646 menu_handler& menu_handler_;
02647 const unsigned int team_num_;
02648 };
02649
02650 chat_handler::chat_handler()
02651 {
02652 }
02653
02654 chat_handler::~chat_handler()
02655 {
02656 }
02657
02658
02659
02660
02661
02662
02663 void chat_handler::change_logging(const std::string& data) {
02664 const std::string::const_iterator j =
02665 std::find(data.begin(), data.end(), ' ');
02666 if (j == data.end()) return;
02667 const std::string level(data.begin(),j);
02668 const std::string domain(j+1,data.end());
02669 int severity;
02670 if (level == "error") severity = 0;
02671 else if (level == "warning") severity = 1;
02672 else if (level == "info") severity = 2;
02673 else if (level == "debug") severity = 3;
02674 else {
02675 utils::string_map symbols;
02676 symbols["level"] = level;
02677 const std::string& msg =
02678 vgettext("Unknown debug level: '$level'.", symbols);
02679 ERR_NG << msg << "\n";
02680 add_chat_message(time(NULL), _("error"), 0, msg);
02681 return;
02682 }
02683 if (!lg::set_log_domain_severity(domain, severity)) {
02684 utils::string_map symbols;
02685 symbols["domain"] = domain;
02686 const std::string& msg =
02687 vgettext("Unknown debug domain: '$domain'.", symbols);
02688 ERR_NG << msg << "\n";
02689 add_chat_message(time(NULL), _("error"), 0, msg);
02690 return;
02691 } else {
02692 utils::string_map symbols;
02693 symbols["level"] = level;
02694 symbols["domain"] = domain;
02695 const std::string& msg =
02696 vgettext("Switched domain: '$domain' to level: '$level'.", symbols);
02697 LOG_NG << msg << "\n";
02698 add_chat_message(time(NULL), "log", 0, msg);
02699 }
02700 }
02701
02702 void chat_handler::send_command(const std::string& cmd, const std::string& args ) {
02703 config data;
02704 if (cmd == "muteall") {
02705 data.add_child(cmd);
02706 } else if (cmd == "query") {
02707 data.add_child(cmd)["type"] = args;
02708 } else if (cmd == "ban" || cmd == "unban" || cmd == "kick"
02709 || cmd == "mute" || cmd == "unmute") {
02710 data.add_child(cmd)["username"] = args;
02711 } else if (cmd == "ping") {
02712 data[cmd] = lexical_cast<std::string>(time(NULL));
02713 } else if (cmd == "green") {
02714 data.add_child("query")["type"] = "lobbymsg @" + args;
02715 } else if (cmd == "red") {
02716 data.add_child("query")["type"] = "lobbymsg #" + args;
02717 } else if (cmd == "yellow") {
02718 data.add_child("query")["type"] = "lobbymsg <255,255,0>" + args;
02719 } else if (cmd == "report") {
02720 data.add_child("query")["type"] = "report " + args;
02721 } else if (cmd == "join") {
02722 data.add_child("room_join")["room"] = args;
02723 } else if (cmd == "part") {
02724 data.add_child("room_part")["room"] = args;
02725 }
02726 network::send_data(data, 0);
02727 }
02728
02729 void chat_handler::do_speak(const std::string& message, bool allies_only)
02730 {
02731 if(message == "" || message == "/") {
02732 return;
02733 }
02734 bool is_command = (message[0] == '/');
02735 bool quoted_command = (is_command && message[1] == ' ');
02736
02737 if(!is_command) {
02738 send_chat_message(message, allies_only);
02739 return;
02740 } else if (quoted_command) {
02741 send_chat_message(std::string(message.begin() + 2, message.end()), allies_only);
02742 return;
02743 }
02744 std::string cmd(message.begin() + 1, message.end());
02745 chat_command_handler cch(*this, allies_only);
02746 cch.dispatch(cmd);
02747 }
02748
02749 void chat_handler::user_relation_changed(const std::string& )
02750 {
02751 }
02752
02753 void chat_handler::send_whisper(const std::string& receiver, const std::string& message)
02754 {
02755 config cwhisper, data;
02756 cwhisper["receiver"] = receiver;
02757 cwhisper["message"] = message;
02758 cwhisper["sender"] = preferences::login();
02759 data.add_child("whisper", cwhisper);
02760 network::send_data(data, 0);
02761 }
02762
02763 void chat_handler::add_whisper_sent(const std::string& receiver, const std::string& message)
02764 {
02765 utils::string_map symbols;
02766 symbols["receiver"] = receiver;
02767 add_chat_message(time(NULL), VGETTEXT("whisper to $receiver", symbols), 0, message);
02768 }
02769
02770 void chat_handler::add_whisper_received(const std::string& sender, const std::string& message)
02771 {
02772 utils::string_map symbols;
02773 symbols["sender"] = sender;
02774 add_chat_message(time(NULL), VGETTEXT("whisper: $sender", symbols), 0, message);
02775 }
02776
02777 void chat_handler::send_chat_room_message(const std::string& room,
02778 const std::string& message)
02779 {
02780 config cmsg, data;
02781 cmsg["room"] = room;
02782 cmsg["message"] = message;
02783 cmsg["sender"] = preferences::login();
02784 data.add_child("message", cmsg);
02785 network::send_data(data, 0);
02786 }
02787
02788 void chat_handler::add_chat_room_message_sent(const std::string &room, const std::string &message)
02789 {
02790 add_chat_room_message_received(room, preferences::login(), message);
02791 }
02792
02793 void chat_handler::add_chat_room_message_received(const std::string &room,
02794 const std::string &speaker, const std::string &message)
02795 {
02796 add_chat_message(time(NULL), room + ": " + speaker, 0, message, events::chat_handler::MESSAGE_PRIVATE);
02797 }
02798
02799
02800 void chat_command_handler::do_emote()
02801 {
02802 chat_handler_.send_chat_message("/me " + get_data(), allies_only_);
02803 }
02804
02805 void chat_command_handler::do_network_send()
02806 {
02807 chat_handler_.send_command(get_cmd(), get_data());
02808 }
02809
02810 void chat_command_handler::do_network_send_req_arg()
02811 {
02812 if (get_data(1).empty()) return command_failed_need_arg(1);
02813 do_network_send();
02814 }
02815
02816 void chat_command_handler::do_room_query_noarg()
02817 {
02818 config data;
02819 config& q = data.add_child("room_query");
02820 q.add_child(get_cmd());
02821 network::send_data(data, 0);
02822 }
02823
02824 void chat_command_handler::do_room_query()
02825 {
02826 if (get_data(1).empty()) return command_failed_need_arg(1);
02827 config data;
02828 config& q = data.add_child("room_query");
02829 q["room"] = get_arg(1);
02830 q.add_child(get_cmd());
02831 network::send_data(data, 0);
02832 }
02833
02834 void chat_command_handler::do_gen_room_query()
02835 {
02836 if (get_data(1).empty()) return command_failed_need_arg(1);
02837 config data;
02838 config& q = data.add_child("room_query");
02839 q["room"] = get_arg(1);
02840 config& c = q.add_child(get_arg(2));
02841 c["value"] = get_data(3);
02842 network::send_data(data, 0);
02843 }
02844
02845 void chat_command_handler::do_whisper()
02846 {
02847 if (get_data(1).empty()) return command_failed_need_arg(1);
02848 if (get_data(2).empty()) return command_failed_need_arg(2);
02849 chat_handler_.send_whisper(get_arg(1), get_data(2));
02850 chat_handler_.add_whisper_sent(get_arg(1), get_data(2));
02851 }
02852
02853 void chat_command_handler::do_chanmsg()
02854 {
02855 if (get_data(1).empty()) return command_failed_need_arg(1);
02856 if (get_data(2).empty()) return command_failed_need_arg(2);
02857 chat_handler_.send_chat_room_message(get_arg(1), get_data(2));
02858 chat_handler_.add_chat_room_message_sent(get_arg(1), get_data(2));
02859 }
02860
02861 void chat_command_handler::do_log()
02862 {
02863 chat_handler_.change_logging(get_data());
02864 }
02865
02866 void chat_command_handler::do_ignore()
02867 {
02868 if (get_arg(1).empty()) {
02869 const std::set<std::string>& tmp = preferences::get_ignores();
02870 print(_("ignores list"), tmp.empty() ? _("(empty)") : utils::join(tmp));
02871 } else {
02872 for(int i = 1; !get_arg(i).empty(); i++){
02873 utils::string_map symbols;
02874 symbols["nick"] = get_arg(i);
02875 if (preferences::add_ignore(get_arg(i))) {
02876 print(_("ignores list"), VGETTEXT("Added to ignore list: $nick", symbols));
02877 chat_handler_.user_relation_changed(get_arg(i));
02878 } else {
02879 command_failed(VGETTEXT("Invalid username: $nick", symbols));
02880 }
02881 }
02882 }
02883 }
02884
02885 void chat_command_handler::do_friend()
02886 {
02887 if (get_arg(1).empty()) {
02888 const std::set<std::string>& tmp = preferences::get_friends();
02889 print(_("friends list"), tmp.empty() ? _("(empty)") : utils::join(tmp));
02890 } else {
02891 for(int i = 1;!get_arg(i).empty();i++){
02892 utils::string_map symbols;
02893 symbols["nick"] = get_arg(i);
02894 if (preferences::add_friend(get_arg(i))) {
02895 chat_handler_.user_relation_changed(get_arg(i));
02896 print(_("friends list"), VGETTEXT("Added to friends list: $nick", symbols));
02897 } else {
02898 command_failed(VGETTEXT("Invalid username: $nick", symbols));
02899 }
02900 }
02901 }
02902 }
02903
02904 void chat_command_handler::do_remove()
02905 {
02906 for(int i = 1;!get_arg(i).empty();i++){
02907 preferences::remove_friend(get_arg(i));
02908 preferences::remove_ignore(get_arg(i));
02909 chat_handler_.user_relation_changed(get_arg(i));
02910 utils::string_map symbols;
02911 symbols["nick"] = get_arg(i);
02912 print(_("friends and ignores list"), VGETTEXT("Removed from list: $nick", symbols));
02913 }
02914 }
02915
02916 void chat_command_handler::do_display()
02917 {
02918 const std::set<std::string> & friends = preferences::get_friends();
02919 const std::set<std::string> & ignores = preferences::get_ignores();
02920
02921 if (!friends.empty()) {
02922 print(_("friends list"), utils::join(friends));
02923 }
02924
02925 if (!ignores.empty()) {
02926 print(_("ignores list"), utils::join(ignores));
02927 }
02928
02929 if (friends.empty() && ignores.empty()) {
02930 print(_("friends and ignores list"), _("There are no players on your friends or ignore list."));
02931 }
02932 }
02933
02934 void chat_command_handler::do_version() {
02935 print(_("version"), game_config::revision);
02936 }
02937
02938 void chat_command_handler::do_register() {
02939 config data;
02940 config& nickserv = data.add_child("nickserv");
02941
02942 if (get_data(1).empty()) return command_failed_need_arg(1);
02943
02944 config ® = nickserv.add_child("register");
02945 reg["password"] = get_arg(1);
02946 if(!get_data(2).empty()) {
02947 reg["mail"] = get_arg(2);
02948 }
02949 std::string msg;
02950 if (get_data(2).empty()) {
02951 msg = _("registering with password *** and no email address");
02952 } else {
02953 utils::string_map symbols;
02954 symbols["email"] = get_data(2);
02955 msg = VGETTEXT("registering with password *** and "
02956 "email address $email", symbols);
02957 }
02958 print(_("nick registration"), msg);
02959
02960 network::send_data(data, 0);
02961 }
02962
02963 void chat_command_handler::do_drop() {
02964 config data;
02965 config& nickserv = data.add_child("nickserv");
02966
02967 nickserv.add_child("drop");
02968
02969 print(_("nick registration"), _("dropping your username"));
02970
02971 network::send_data(data, 0);
02972 }
02973
02974 void chat_command_handler::do_set() {
02975 config data;
02976 config& nickserv = data.add_child("nickserv");
02977
02978 if (get_data(1).empty()) return command_failed_need_arg(1);
02979 if (get_data(2).empty()) return command_failed_need_arg(2);
02980
02981 config &set = nickserv.add_child("set");
02982 set["detail"] = get_arg(1);
02983 set["value"] = get_data(2);
02984 utils::string_map symbols;
02985 symbols["var"] = get_arg(1);
02986 symbols["value"] = get_arg(2);
02987 print(_("nick registration"), VGETTEXT("setting $var to $value", symbols));
02988
02989 network::send_data(data, 0);
02990 }
02991
02992 void chat_command_handler::do_info() {
02993 if (get_data(1).empty()) return command_failed_need_arg(1);
02994
02995 config data;
02996 config& nickserv = data.add_child("nickserv");
02997
02998 nickserv.add_child("info")["name"] = get_data(1);
02999 utils::string_map symbols;
03000 symbols["nick"] = get_arg(1);
03001 print(_("nick registration"), VGETTEXT("requesting information for user $nick", symbols));
03002
03003 network::send_data(data, 0);
03004 }
03005
03006 void chat_command_handler::do_details() {
03007
03008 config data;
03009 config& nickserv = data.add_child("nickserv");
03010 nickserv.add_child("details");
03011
03012 network::send_data(data, 0);
03013 }
03014
03015 void menu_handler::send_chat_message(const std::string& message, bool allies_only)
03016 {
03017 config cfg;
03018 cfg["id"] = preferences::login();
03019 cfg["message"] = message;
03020
03021 const int side = is_observer() ? 0 : gui_->viewing_side();
03022 if(!is_observer()) {
03023 cfg["side"] = side;
03024 }
03025
03026 bool private_message = has_friends() && allies_only;
03027
03028 if(private_message) {
03029 if (is_observer()) {
03030 cfg["team_name"] = game_config::observer_team_name;
03031 } else {
03032 cfg["team_name"] = teams_[gui_->viewing_team()].team_name();
03033 }
03034 }
03035
03036 recorder.speak(cfg);
03037 add_chat_message(time(NULL), cfg["id"], side, message,
03038 private_message ? events::chat_handler::MESSAGE_PRIVATE : events::chat_handler::MESSAGE_PUBLIC);
03039
03040 }
03041
03042
03043 void menu_handler::do_search(const std::string& new_search)
03044 {
03045 if(new_search.empty() == false && new_search != last_search_)
03046 last_search_ = new_search;
03047
03048 if(last_search_.empty()) return;
03049
03050 bool found = false;
03051 map_location loc = last_search_hit_;
03052
03053 std::vector<std::string> args = utils::split(last_search_, ',');
03054 if(args.size() == 2) {
03055 int x, y;
03056 x = lexical_cast_default<int>(args[0], 0)-1;
03057 y = lexical_cast_default<int>(args[1], 0)-1;
03058 if(x >= 0 && x < map_.w() && y >= 0 && y < map_.h()) {
03059 loc = map_location(x,y);
03060 found = true;
03061 }
03062 }
03063
03064 if(loc.valid() == false)
03065 loc = map_location(map_.w()-1,map_.h()-1);
03066 map_location start = loc;
03067 while (!found) {
03068
03069 loc.x = (loc.x + 1) % map_.w();
03070 if(loc.x == 0)
03071 loc.y = (loc.y + 1) % map_.h();
03072
03073
03074 if (!gui_->shrouded(loc)) {
03075 const terrain_label* label = gui_->labels().get_label(loc);
03076 if(label) {
03077 std::string label_text = label->text().str();
03078 if(std::search(label_text.begin(), label_text.end(),
03079 last_search_.begin(), last_search_.end(),
03080 chars_equal_insensitive) != label_text.end()) {
03081 found = true;
03082 }
03083 }
03084 }
03085
03086 if (!gui_->fogged(loc)) {
03087 unit_map::const_iterator ui = units_.find(loc);
03088 if(ui != units_.end()) {
03089 const std::string name = ui->name();
03090 if(std::search(name.begin(), name.end(),
03091 last_search_.begin(), last_search_.end(),
03092 chars_equal_insensitive) != name.end()) {
03093 if (!teams_[gui_->viewing_team()].is_enemy(ui->side()) ||
03094 !ui->invisible(ui->get_location())) {
03095 found = true;
03096 }
03097 }
03098 }
03099 }
03100
03101 if(loc == start)
03102 break;
03103 }
03104
03105 if(found) {
03106 last_search_hit_ = loc;
03107 gui_->scroll_to_tile(loc,game_display::ONSCREEN,false);
03108 gui_->highlight_hex(loc);
03109 } else {
03110 last_search_hit_ = map_location();
03111
03112 utils::string_map symbols;
03113 symbols["search"] = last_search_;
03114 const std::string msg = vgettext("Couldn't find label or unit "
03115 "containing the string '$search'.", symbols);
03116 gui::dialog(*gui_,"",msg).show();
03117 }
03118 }
03119
03120 void menu_handler::do_command(const std::string& str)
03121 {
03122 console_handler ch(*this);
03123 ch.dispatch(str);
03124 }
03125
03126 std::vector<std::string> menu_handler::get_commands_list()
03127 {
03128 console_handler ch(*this);
03129 return ch.get_commands_list();
03130 }
03131
03132 void console_handler::do_refresh() {
03133 image::flush_cache();
03134 menu_handler_.gui_->redraw_everything();
03135 }
03136
03137 void console_handler::do_droid() {
03138
03139 const std::string side_s = get_arg(1);
03140 const std::string action = get_arg(2);
03141
03142 const unsigned int side = side_s.empty() ?
03143 team_num_ : lexical_cast_default<unsigned int>(side_s);
03144
03145 if (side < 1 || side > menu_handler_.teams_.size()) {
03146 utils::string_map symbols;
03147 symbols["side"] = side_s;
03148 command_failed(vgettext("Can't droid invalid side: '$side'.", symbols));
03149 return;
03150 } else if (menu_handler_.teams_[side - 1].is_network()) {
03151 utils::string_map symbols;
03152 symbols["side"] = lexical_cast<std::string>(side);
03153 command_failed(vgettext("Can't droid networked side: '$side'.", symbols));
03154 return;
03155 } else if (menu_handler_.teams_[side - 1].is_human() && action != " off") {
03156
03157 menu_handler_.teams_[side - 1].make_human_ai();
03158 menu_handler_.change_controller(lexical_cast<std::string>(side),"human_ai");
03159 if(team_num_ == side) {
03160
03161
03162 throw end_turn_exception(side);
03163 }
03164 } else if (menu_handler_.teams_[side - 1].is_ai() && action != " on") {
03165 menu_handler_.teams_[side - 1].make_human();
03166 menu_handler_.change_controller(lexical_cast<std::string>(side),"human");
03167 }
03168 menu_handler_.textbox_info_.close(*menu_handler_.gui_);
03169 }
03170
03171 void console_handler::do_theme() {
03172 preferences::show_theme_dialog(*menu_handler_.gui_);
03173 }
03174 void console_handler::do_control() {
03175
03176 if (network::nconnections() == 0) return;
03177 const std::string side = get_arg(1);
03178 const std::string player = get_arg(2);
03179 if(player.empty())
03180 {
03181 command_failed_need_arg(2);
03182 return;
03183 }
03184
03185 unsigned int side_num;
03186 try {
03187 side_num = lexical_cast<unsigned int>(side);
03188 } catch(bad_lexical_cast&) {
03189 utils::string_map symbols;
03190 symbols["side"] = side;
03191 command_failed(vgettext("Can't change control of invalid side: '$side'.", symbols));
03192 return;
03193 }
03194 if (side_num < 1 || side_num > menu_handler_.teams_.size()) {
03195 utils::string_map symbols;
03196 symbols["side"] = side;
03197 command_failed(vgettext("Can't change control of out-of-bounds side: '$side'.", symbols));
03198 return;
03199 }
03200 menu_handler_.request_control_change(side_num,player);
03201 menu_handler_.textbox_info_.close(*(menu_handler_.gui_));
03202 }
03203 void console_handler::do_clear() {
03204 menu_handler_.gui_->clear_chat_messages();
03205 }
03206 void console_handler::do_sunset() {
03207 int delay = lexical_cast_default<int>(get_data());
03208 menu_handler_.gui_->sunset(delay);
03209 gui2::twindow::set_sunset(delay);
03210 }
03211 void console_handler::do_foreground() {
03212 menu_handler_.gui_->toggle_debug_foreground();
03213 }
03214
03215 void console_handler::do_layers() {
03216 const mouse_handler& mousehandler = resources::controller->get_mouse_handler_base();
03217 const map_location &loc = mousehandler.get_last_hex();
03218
03219 std::vector<std::string> layers;
03220
03221 std::string heading = std::string(1,HEADING_PREFIX) +
03222 "^#" + COLUMN_SEPARATOR +
03223 "Image" + COLUMN_SEPARATOR +
03224 "Name" + COLUMN_SEPARATOR +
03225 "Loc" + COLUMN_SEPARATOR +
03226 "Layer" + COLUMN_SEPARATOR +
03227 "Base.x" + COLUMN_SEPARATOR +
03228 "Base.y" + COLUMN_SEPARATOR +
03229 "Center"
03230
03231 ;
03232 layers.push_back(heading);
03233
03234 display& disp = *(menu_handler_.gui_);
03235 terrain_builder& builder = disp.get_builder();
03236 terrain_builder::tile* tile = builder.get_tile(loc);
03237
03238 const std::string& tod_id = disp.get_time_of_day(loc).id;
03239 terrain_builder::tile::logs tile_logs;
03240 tile->rebuild_cache(tod_id, &tile_logs);
03241
03242 int order = 1;
03243 foreach(const terrain_builder::tile::log_details det, tile_logs) {
03244 const terrain_builder::tile::rule_image_rand& ri = *det.first;
03245 const terrain_builder::rule_image_variant& variant = *det.second;
03246
03247
03248 const image::locator& img = variant.images.front().get_first_frame();
03249 const std::string& name = img.get_filename();
03250
03251
03252 const map_location& loc_cut = img.get_loc();
03253
03254 std::ostringstream str;
03255
03256 int tz = image::tile_size;
03257 SDL_Rect r = create_rect(0,0,tz,tz);
03258
03259 surface surf = image::get_image(img.get_filename());
03260
03261
03262 if(loc_cut.valid()) {
03263
03264 r = create_rect(
03265 ((tz*3) / 4) * loc_cut.x
03266 , tz * loc_cut.y + (tz / 2) * (loc_cut.x % 2)
03267 , tz, tz);
03268
03269 if(img.get_center_x() >= 0 && img.get_center_y()>= 0){
03270 r.x += surf->w/2 - img.get_center_x();
03271 r.y += surf->h/2 - img.get_center_y();
03272 }
03273 }
03274
03275 str << (ri->is_background() ? "B ": "F ") << order
03276 << COLUMN_SEPARATOR
03277 << IMAGE_PREFIX << "terrain/foreground.png";
03278
03279
03280
03281 SDL_Rect r2 = intersect_rects(r, create_rect(0,0,surf->w,surf->h));
03282 if(r2.w > 0 && r2.h > 0) {
03283 str << "~BLIT("
03284 << name << "~CROP("
03285 << r2.x << "," << r2.y << ","
03286 << r2.w << "," << r2.h
03287 << ")"
03288 << "," << r2.x-r.x << "," << r2.y-r.y
03289 << ")"
03290 << "~MASK(" << "terrain/alphamask.png" << ")";
03291 }
03292
03293 str << COLUMN_SEPARATOR
03294 << IMAGE_PREFIX << name << "~SCALE(72,72)"
03295 << IMG_TEXT_SEPARATOR << name
03296 << COLUMN_SEPARATOR << img.get_loc()
03297 << COLUMN_SEPARATOR << ri->layer
03298 << COLUMN_SEPARATOR << ri->basex
03299 << COLUMN_SEPARATOR << ri->basey
03300 << COLUMN_SEPARATOR
03301 << ri->center_x << ", " << ri->center_y;
03302 layers.push_back(str.str());
03303 ++order;
03304 }
03305
03306 std::vector<std::string> flags(tile->flags.begin(),tile->flags.end());
03307 std::ostringstream info;
03308
03309 info << "Flags :" << utils::join(flags, ", ");
03310 {
03311 gui::dialog menu(*menu_handler_.gui_, _("Layers"), info.str(), gui::OK_CANCEL);
03312 menu.set_menu(layers);
03313 menu.show();
03314 }
03315 }
03316 void console_handler::do_fps() {
03317 preferences::set_show_fps(!preferences::show_fps());
03318 }
03319 void console_handler::do_benchmark() {
03320 menu_handler_.gui_->toggle_benchmark();
03321 }
03322 void console_handler::do_save() {
03323 savegame::savegame save(menu_handler_.gamestate_, preferences::compress_saves());
03324 save.save_game_automatic(menu_handler_.gui_->video(), true, get_data());
03325 }
03326 void console_handler::do_save_quit() {
03327 savegame::savegame save(menu_handler_.gamestate_, preferences::compress_saves());
03328 save.save_game_automatic(menu_handler_.gui_->video(), true, get_data());
03329 throw end_level_exception(QUIT);
03330 }
03331 void console_handler::do_quit() {
03332 throw end_level_exception(QUIT);
03333 }
03334 void console_handler::do_ignore_replay_errors() {
03335 game_config::ignore_replay_errors = (get_data() != "off") ? true : false;
03336 }
03337 void console_handler::do_nosaves() {
03338 game_config::disable_autosave = (get_data() != "off") ? true : false;
03339 }
03340
03341 void console_handler::do_next_level()
03342 {
03343 if (!get_data().empty())
03344 menu_handler_.gamestate_.classification().next_scenario = get_data();
03345 end_level_data &e = resources::controller->get_end_level_data();
03346 e.carryover_percentage = 100;
03347 e.carryover_add = false;
03348 e.gold_bonus = false;
03349 e.carryover_report = false;
03350 e.prescenario_save = true;
03351 e.linger_mode = false;
03352 throw end_level_exception(VICTORY);
03353 }
03354
03355 void console_handler::do_choose_level() {
03356 std::vector<std::string> options;
03357 int next = 0, nb = 0;
03358 foreach (const config &sc, menu_handler_.game_config_.child_range("scenario"))
03359 {
03360 const std::string &id = sc["id"];
03361 options.push_back(id);
03362 if (id == menu_handler_.gamestate_.classification().next_scenario)
03363 next = nb;
03364 ++nb;
03365 }
03366
03367
03368 std::string& scenario = menu_handler_.gamestate_.mp_settings().mp_scenario;
03369 foreach (const config &mp, menu_handler_.game_config_.child_range("multiplayer"))
03370 {
03371 if (mp["id"] == scenario)
03372 {
03373 const std::string &id = mp["id"];
03374 options.push_back(id);
03375 if (id == menu_handler_.gamestate_.classification().next_scenario)
03376 next = nb;
03377 ++nb;
03378 scenario = mp["next_scenario"].str();
03379 }
03380 }
03381 std::sort(options.begin(), options.end());
03382 int choice = 0;
03383 {
03384 gui2::tsimple_item_selector dlg(_("Choose Scenario (Debug!)"), "", options);
03385 dlg.set_selected_index(next);
03386 dlg.show(menu_handler_.gui_->video());
03387 choice = dlg.selected_index();
03388 }
03389
03390 if(choice == -1)
03391 return;
03392
03393 if (size_t(choice) < options.size()) {
03394 menu_handler_.gamestate_.classification().next_scenario = options[choice];
03395 end_level_data &e = resources::controller->get_end_level_data();
03396 e.carryover_percentage = 100;
03397 e.carryover_add = false;
03398 e.gold_bonus = false;
03399 e.carryover_report = false;
03400 e.prescenario_save = true;
03401 e.linger_mode = false;
03402 throw end_level_exception(VICTORY);
03403 }
03404 }
03405
03406 void console_handler::do_turn()
03407 {
03408 int turn = resources::tod_manager->turn() + 1;
03409 const std::string& data = get_data();
03410 if (!data.empty()) {
03411 turn = lexical_cast_default<int>(data, 1);
03412 }
03413 resources::tod_manager->set_turn(turn);
03414
03415 menu_handler_.gui_->new_turn();
03416 menu_handler_.gui_->redraw_everything();
03417 }
03418
03419 void console_handler::do_turn_limit()
03420 {
03421 tod_manager& tod_man = *resources::tod_manager;
03422 int limit =
03423 get_data().empty() ? -1 : lexical_cast_default<int>(get_data(), 1);
03424 tod_man.set_number_of_turns(limit);
03425 menu_handler_.gui_->redraw_everything();
03426 }
03427
03428 void console_handler::do_debug() {
03429 if (network::nconnections() == 0 || game_config::mp_debug) {
03430 print(get_cmd(), _("Debug mode activated!"));
03431 game_config::debug = true;
03432 } else {
03433 command_failed(_("Debug mode not available in network games"));
03434 }
03435 }
03436 void console_handler::do_nodebug() {
03437 if (game_config::debug) {
03438 print(get_cmd(), _("Debug mode deactivated!"));
03439 game_config::debug = false;
03440 }
03441 }
03442 void console_handler::do_lua() {
03443 resources::lua_kernel->run(get_data().c_str());
03444 game_events::commit();
03445 }
03446
03447 void console_handler::do_unsafe_lua()
03448 {
03449 if (gui2::show_message(resources::screen->video(), _("Unsafe Lua scripts."),
03450 _("You are about to open a security breach in Wesnoth. Are you sure you want to continue? If you have downloaded add-ons, do not click 'ok'! They would instantly take over your computer. You have been warned."),
03451 gui2::tmessage::ok_cancel_buttons) == gui2::twindow::OK)
03452 {
03453 print(get_cmd(), _("Unsafe mode enabled!"));
03454 resources::lua_kernel->load_package();
03455 }
03456 }
03457
03458 void console_handler::do_custom() {
03459 preferences::set_custom_command(get_data());
03460 }
03461 void console_handler::do_set_alias() {
03462 const std::string data = get_data();
03463 const std::string::const_iterator j = std::find(data.begin(),data.end(),'=');
03464 const std::string alias(data.begin(),j);
03465 if(j != data.end()) {
03466 const std::string command(j+1,data.end());
03467 if (!command.empty()) {
03468 register_alias(command, alias);
03469 } else {
03470
03471
03472 register_alias(alias, alias);
03473 }
03474 preferences::add_alias(alias, command);
03475
03476 preferences::write_preferences();
03477 } else {
03478
03479
03480 const std::string command = chmap::get_actual_cmd(alias);
03481 print(get_cmd(), "'"+alias+"'" + " = " + "'"+command+"'");
03482 }
03483 }
03484 void console_handler::do_set_var() {
03485 const std::string data = get_data();
03486 if (data.empty()) {
03487 command_failed_need_arg(1);
03488 return;
03489 }
03490 const std::string::const_iterator j = std::find(data.begin(),data.end(),'=');
03491 if(j != data.end()) {
03492 const std::string name(data.begin(),j);
03493 const std::string value(j+1,data.end());
03494 menu_handler_.gamestate_.set_variable(name,value);
03495 } else {
03496 command_failed(_("Variable not found"));
03497 }
03498 }
03499 void console_handler::do_show_var() {
03500 gui2::show_transient_message((*menu_handler_.gui_).video(),"",menu_handler_.gamestate_.get_variable(get_data()));
03501 }
03502
03503
03504 void console_handler::do_inspect() {
03505 vconfig cfg = vconfig::empty_vconfig();
03506 gui2::tgamestate_inspector inspect_dialog(cfg);
03507 inspect_dialog.show(resources::screen->video());
03508 }
03509
03510 void console_handler::do_control_dialog()
03511 {
03512 gui2::tmp_change_control mp_change_control(&menu_handler_);
03513 mp_change_control.show(resources::screen->video());
03514 }
03515
03516 void console_handler::do_manage() {
03517 config cfg;
03518 gui2::tdata_manage manager(cfg);
03519 manager.show(resources::screen->video());
03520 }
03521
03522 void console_handler::do_unit() {
03523
03524 if (events::commands_disabled > 0)
03525 return;
03526 unit_map::iterator i = menu_handler_.current_unit();
03527 if (i == menu_handler_.units_.end()) return;
03528 const map_location loc = i->get_location();
03529 const std::string data = get_data(1);
03530 std::vector<std::string> parameters = utils::split(data, '=', utils::STRIP_SPACES);
03531 if (parameters.size() < 2)
03532 return;
03533
03534 const std::string& name = parameters[0];
03535 const std::string& value = parameters[1];
03536
03537
03538
03539
03540
03541
03542
03543
03544 if (name == "alignment" && (value != "lawful" && value != "neutral" && value != "chaotic" && value != "liminal")) {
03545 utils::string_map symbols;
03546 symbols["alignment"] = get_arg(1);
03547 command_failed(VGETTEXT("Invalid alignment: '$alignment',"
03548 " needs to be one of lawful, neutral, chaotic, or liminal.", symbols));
03549 return;
03550 }
03551 if (name == "advances" ){
03552 int int_value = lexical_cast<int>(value);
03553 for (int levels=0; levels<int_value; levels++) {
03554 i->set_experience(i->max_experience());
03555 dialogs::advance_unit(loc);
03556 i = menu_handler_.units_.find(loc);
03557 if (!i.valid()) {
03558 break;
03559 }
03560 }
03561 } else {
03562 config cfg;
03563 i->write(cfg);
03564 menu_handler_.units_.erase(loc);
03565 cfg[name] = value;
03566 unit new_u(cfg, true);
03567 menu_handler_.units_.add(loc, new_u);
03568 }
03569 if (name == "fail") {
03570 assert(i.valid());
03571 }
03572 menu_handler_.gui_->invalidate(loc);
03573 menu_handler_.gui_->invalidate_unit();
03574 }
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597 void console_handler::do_discover() {
03598 foreach (const unit_type_data::unit_type_map::value_type &i, unit_types.types()) {
03599 preferences::encountered_units().insert(i.second.id());
03600 }
03601 }
03602 void console_handler::do_undiscover() {
03603 const int res = gui2::show_message((*menu_handler_.gui_).video(), "Undiscover", _("Do you wish to clear all of your discovered units from help?"), gui2::tmessage::yes_no_buttons);
03604 if(res != gui2::twindow::CANCEL) {
03605 preferences::encountered_units().clear();
03606 }
03607 }
03608 void console_handler::do_create() {
03609 const mouse_handler& mousehandler = resources::controller->get_mouse_handler_base();
03610 const map_location &loc = mousehandler.get_last_hex();
03611 if (menu_handler_.map_.on_board(loc)) {
03612 const unit_type *ut = unit_types.find(get_data());
03613 if (!ut) {
03614 command_failed(_("Invalid unit type"));
03615 return;
03616 }
03617
03618 menu_handler_.units_.erase(loc);
03619
03620 unit created(ut, 1, true);
03621 created.new_turn();
03622
03623 menu_handler_.units_.add(loc, created);
03624 menu_handler_.gui_->invalidate(loc);
03625 menu_handler_.gui_->invalidate_unit();
03626 } else {
03627 command_failed(_("Invalid location"));
03628 }
03629 }
03630 void console_handler::do_fog() {
03631 menu_handler_.teams_[team_num_ - 1].set_fog( !menu_handler_.teams_[team_num_ - 1].uses_fog() );
03632 recalculate_fog(team_num_);
03633 menu_handler_.gui_->recalculate_minimap();
03634 menu_handler_.gui_->redraw_everything();
03635 }
03636 void console_handler::do_shroud() {
03637 menu_handler_.teams_[team_num_ - 1].set_shroud( !menu_handler_.teams_[team_num_ - 1].uses_shroud() );
03638 menu_handler_.clear_shroud(team_num_);
03639 menu_handler_.gui_->recalculate_minimap();
03640 menu_handler_.gui_->redraw_everything();
03641 }
03642 void console_handler::do_gold() {
03643 menu_handler_.teams_[team_num_ - 1].spend_gold(-lexical_cast_default<int>(get_data(),1000));
03644 menu_handler_.gui_->redraw_everything();
03645 }
03646 void console_handler::do_event() {
03647 game_events::fire(get_data());
03648 menu_handler_.gui_->redraw_everything();
03649 }
03650 void console_handler::do_toggle_draw_coordinates() {
03651 menu_handler_.gui_->set_draw_coordinates(!menu_handler_.gui_->get_draw_coordinates());
03652 menu_handler_.gui_->invalidate_all();
03653 }
03654 void console_handler::do_toggle_draw_terrain_codes() {
03655 menu_handler_.gui_->set_draw_terrain_codes(!menu_handler_.gui_->get_draw_terrain_codes());
03656 menu_handler_.gui_->invalidate_all();
03657 }
03658
03659 void console_handler::do_toggle_whiteboard() {
03660 resources::whiteboard->set_active(!resources::whiteboard->is_active());
03661 if (resources::whiteboard->is_active()) {
03662 print(get_cmd(), _("Planning mode activated!"));
03663 resources::whiteboard->print_help_once();
03664 } else {
03665 print(get_cmd(), _("Planning mode deactivated!"));
03666 }
03667 }
03668
03669 void console_handler::do_whiteboard_options()
03670 {
03671 resources::whiteboard->options_dlg();
03672 }
03673
03674 void menu_handler::do_ai_formula(const std::string& str,
03675 int side_num, mouse_handler& )
03676 {
03677 try {
03678 add_chat_message(time(NULL), _("ai"), 0, ai::manager::evaluate_command(side_num, str));
03679 } catch(end_turn_exception&) {
03680 resources::controller->force_end_turn();
03681 } catch(...) {
03682
03683 }
03684 }
03685
03686 void menu_handler::user_command()
03687 {
03688 textbox_info_.show(gui::TEXTBOX_COMMAND,sgettext("prompt^Command:"), "", false, *gui_);
03689 }
03690
03691 void menu_handler::request_control_change ( int side_num, const std::string& player )
03692 {
03693 std::string side = str_cast(side_num);
03694
03695 if (teams_[side_num - 1].is_human()) {
03696 if (player == preferences::login())
03697 return;
03698 change_side_controller(side,player);
03699 } else {
03700
03701
03702 change_side_controller(side,player);
03703 }
03704 }
03705
03706 void menu_handler::custom_command()
03707 {
03708 std::vector<std::string> commands = utils::split(preferences::custom_command(), ';');
03709 std::vector<std::string>::iterator c = commands.begin();
03710 for (; c != commands.end() ; ++c) {
03711 do_command(*c);
03712 }
03713 }
03714
03715 void menu_handler::ai_formula()
03716 {
03717 if (network::nconnections() == 0) {
03718 textbox_info_.show(gui::TEXTBOX_AI,sgettext("prompt^Command:"), "", false, *gui_);
03719 }
03720 }
03721
03722 void menu_handler::clear_messages()
03723 {
03724 gui_->clear_chat_messages();
03725 }
03726
03727 void menu_handler::change_controller(const std::string& side, const std::string& controller)
03728 {
03729 config cfg;
03730 config& change = cfg.add_child("change_controller");
03731 change["side"] = side;
03732 change["controller"] = controller;
03733 network::send_data(cfg, 0);
03734 }
03735
03736 void menu_handler::change_side_controller(const std::string& side, const std::string& player)
03737 {
03738 config cfg;
03739 config& change = cfg.add_child("change_controller");
03740 change["side"] = side;
03741 change["player"] = player;
03742
03743 network::send_data(cfg, 0);
03744 }
03745 }
03746