00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "playturn.hpp"
00017
00018 #include "construct_dialog.hpp"
00019 #include "foreach.hpp"
00020 #include "game_display.hpp"
00021 #include "game_end_exceptions.hpp"
00022 #include "game_preferences.hpp"
00023 #include "gettext.hpp"
00024 #include "gui/dialogs/simple_item_selector.hpp"
00025 #include "log.hpp"
00026 #include "map_label.hpp"
00027 #include "replay.hpp"
00028 #include "resources.hpp"
00029 #include "rng.hpp"
00030 #include "whiteboard/manager.hpp"
00031 #include "formula_string_utils.hpp"
00032 #include "play_controller.hpp"
00033
00034 #include <ctime>
00035
00036 static lg::log_domain log_network("network");
00037 #define ERR_NW LOG_STREAM(err, log_network)
00038
00039 turn_info::turn_info(unsigned team_num, replay_network_sender &replay_sender) :
00040 team_num_(team_num),
00041 replay_sender_(replay_sender),
00042 host_transfer_("host_transfer"),
00043 replay_()
00044 {
00045
00046
00047
00048 if(network::nconnections() > 0)
00049 send_data();
00050 }
00051
00052 turn_info::~turn_info(){
00053 resources::undo_stack->clear();
00054 }
00055
00056 void turn_info::sync_network()
00057 {
00058 if(network::nconnections() > 0) {
00059
00060
00061
00062
00063 config cfg;
00064 while(network::connection res = network::receive_data(cfg)) {
00065 std::deque<config> backlog;
00066 process_network_data(cfg,res,backlog,false);
00067 cfg.clear();
00068 }
00069
00070 send_data();
00071 }
00072 }
00073
00074 void turn_info::send_data()
00075 {
00076 if(resources::undo_stack->empty()) {
00077 replay_sender_.commit_and_sync();
00078 } else {
00079 replay_sender_.sync_non_undoable();
00080 }
00081 }
00082
00083 void turn_info::handle_turn(
00084 bool& turn_end,
00085 const config& t,
00086 const bool skip_replay,
00087 std::deque<config>& backlog)
00088 {
00089 if(turn_end == false) {
00090
00091 replay_.append(t);
00092 replay_.set_skip(skip_replay);
00093
00094 turn_end = do_replay(team_num_, &replay_);
00095 recorder.add_config(t, replay::MARK_AS_SENT);
00096 } else {
00097
00098
00099
00100 backlog.push_back(config());
00101 backlog.back().add_child("turn", t);
00102 }
00103 }
00104
00105 turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg,
00106 network::connection from, std::deque<config>& backlog, bool skip_replay)
00107 {
00108 if (const config &rnd_seed = cfg.child("random_seed")) {
00109 rand_rng::set_seed(rnd_seed["seed"]);
00110
00111 }
00112
00113 if (const config &msg = cfg.child("message"))
00114 {
00115 resources::screen->add_chat_message(time(NULL), msg["sender"], msg["side"],
00116 msg["message"], events::chat_handler::MESSAGE_PUBLIC,
00117 preferences::message_bell());
00118 }
00119
00120 if (const config &msg = cfg.child("whisper") )
00121 {
00122 resources::screen->add_chat_message(time(NULL), "whisper: " + msg["sender"].str(), 0,
00123 msg["message"], events::chat_handler::MESSAGE_PRIVATE,
00124 preferences::message_bell());
00125 }
00126
00127 foreach (const config &ob, cfg.child_range("observer")) {
00128 resources::screen->add_observer(ob["name"]);
00129 }
00130
00131 foreach (const config &ob, cfg.child_range("observer_quit")) {
00132 resources::screen->remove_observer(ob["name"]);
00133 }
00134
00135 if (cfg.child("leave_game")) {
00136 throw network::error("");
00137 }
00138
00139 bool turn_end = false;
00140
00141 config::const_child_itors turns = cfg.child_range("turn");
00142 if (turns.first != turns.second && from != network::null_connection) {
00143
00144 network::send_data_all_except(cfg, from);
00145 }
00146
00147 const config& change = cfg.child_or_empty("change_controller");
00148 const std::string& side_drop = cfg["side_drop"].str();
00149
00150 foreach (const config &t, turns)
00151 {
00152 handle_turn(turn_end, t, skip_replay, backlog);
00153 }
00154
00155 resources::whiteboard->process_network_data(cfg);
00156
00157 if (!change.empty())
00158 {
00159
00160 const int side = lexical_cast<int>(change["side"]);
00161 const size_t index = static_cast<size_t>(side-1);
00162
00163 const std::string &controller = change["controller"];
00164 const std::string &player = change["player"];
00165
00166 if(index < resources::teams->size()) {
00167 team &tm = (*resources::teams)[index];
00168 if (!player.empty())
00169 tm.set_current_player(player);
00170 unit_map::iterator leader = resources::units->find_leader(side);
00171 bool restart = resources::screen->playing_side() == side;
00172 if (!player.empty() && leader.valid())
00173 leader->rename(player);
00174
00175 if (controller == "human" && !tm.is_human()) {
00176 if (!(*resources::teams)[resources::screen->playing_team()].is_human())
00177 {
00178 resources::screen->set_team(index);
00179 }
00180 tm.make_human();
00181 } else if (controller == "human_ai" && !tm.is_human_ai()) {
00182 tm.make_human_ai();
00183 } else if (controller == "network" && !tm.is_network_human()) {
00184 tm.make_network();
00185 } else if (controller == "network_ai" && !tm.is_network_ai()) {
00186 tm.make_network_ai();
00187 } else if (controller == "ai" && !tm.is_ai()) {
00188 tm.make_ai();
00189 }
00190 else
00191 {
00192 restart = false;
00193 }
00194
00195 resources::controller->maybe_do_init_side(index);
00196
00197 resources::whiteboard->on_change_controller(side,tm);
00198
00199 resources::screen->labels().recalculate_labels();
00200
00201 return restart ? PROCESS_RESTART_TURN : PROCESS_CONTINUE;
00202 }
00203 }
00204
00205
00206 if(!side_drop.empty()) {
00207 const std::string controller = cfg["controller"];
00208 int side = atoi(side_drop.c_str());
00209 const size_t side_index = side-1;
00210
00211 bool restart = side == resources::screen->playing_side();
00212
00213 if (side_index >= resources::teams->size()) {
00214 ERR_NW << "unknown side " << side_index << " is dropping game\n";
00215 throw network::error("");
00216 }
00217
00218 team &tm = (*resources::teams)[side_index];
00219 unit_map::iterator leader = resources::units->find_leader(side);
00220 const bool have_leader = leader.valid();
00221
00222 if (controller == "ai"){
00223 tm.make_ai();
00224 tm.set_current_player("ai" + side_drop);
00225 if (have_leader) leader->rename("ai" + side_drop);
00226 return restart?PROCESS_RESTART_TURN:PROCESS_CONTINUE;
00227 }
00228
00229 int action = 0;
00230
00231 std::vector<std::string> observers;
00232 std::vector<team*> allies;
00233 std::vector<std::string> options;
00234
00235
00236 {
00237 utils::string_map t_vars;
00238 options.push_back(_("Replace with AI"));
00239 options.push_back(_("Replace with local player"));
00240 options.push_back(_("Abort game"));
00241
00242
00243 foreach (const std::string &ob, resources::screen->observers())
00244 {
00245 t_vars["player"] = ob;
00246 options.push_back(vgettext("Replace with $player", t_vars));
00247 observers.push_back(ob);
00248 }
00249
00250
00251 foreach (team &t, *resources::teams)
00252 {
00253 if (!t.is_enemy(side) && !t.is_human() && !t.is_ai() && !t.is_empty()
00254 && t.current_player() != tm.current_player())
00255 {
00256
00257
00258
00259 t_vars["player"] = t.current_player();
00260 options.push_back(vgettext("Replace with $player", t_vars));
00261 allies.push_back(&t);
00262 }
00263 }
00264
00265 t_vars["player"] = tm.current_player();
00266 const std::string msg = vgettext("$player has left the game. What do you want to do?", t_vars);
00267 gui2::tsimple_item_selector dlg("", msg, options);
00268 dlg.set_single_button(true);
00269 dlg.show(resources::screen->video());
00270 action = dlg.selected_index();
00271 }
00272
00273
00274
00275
00276 switch(action) {
00277 case 0:
00278 tm.make_human_ai();
00279 tm.set_current_player("ai" + side_drop);
00280 if (have_leader) leader->rename("ai" + side_drop);
00281 change_controller(side_drop, "human_ai");
00282 resources::controller->maybe_do_init_side(side_index);
00283
00284 return restart?PROCESS_RESTART_TURN:PROCESS_CONTINUE;
00285
00286 case 1:
00287 tm.make_human();
00288 tm.set_current_player("human" + side_drop);
00289 if (have_leader) leader->rename("human" + side_drop);
00290
00291 resources::controller->maybe_do_init_side(side_index);
00292
00293 return restart?PROCESS_RESTART_TURN:PROCESS_CONTINUE;
00294 case 2:
00295
00296
00297 throw end_level_exception(QUIT);
00298 default:
00299 if (action > 2) {
00300
00301 {
00302
00303 tm.make_human();
00304 tm.set_current_player("human"+side_drop);
00305 if (have_leader) leader->rename("human"+side_drop);
00306 }
00307
00308 const size_t index = static_cast<size_t>(action - 3);
00309 if (index < observers.size()) {
00310 change_side_controller(side_drop, observers[index]);
00311 } else if (index < options.size() - 1) {
00312 size_t i = index - observers.size();
00313 change_side_controller(side_drop, allies[i]->current_player());
00314 } else {
00315 tm.make_human_ai();
00316 tm.set_current_player("ai"+side_drop);
00317 if (have_leader) leader->rename("ai" + side_drop);
00318 change_controller(side_drop, "human_ai");
00319 }
00320 return restart?PROCESS_RESTART_TURN:PROCESS_CONTINUE;
00321 }
00322 break;
00323 }
00324 throw network::error("");
00325 }
00326
00327
00328
00329 if (cfg.child("notify_next_scenario")) {
00330 gui::button* btn_end = resources::screen->find_button("button-endturn");
00331 if(btn_end) {
00332 btn_end->enable(true);
00333 }
00334 return PROCESS_END_LINGER;
00335 }
00336
00337
00338 if (const config &cfg_host_transfer = cfg.child("host_transfer")){
00339 if (cfg_host_transfer["value"] == "1") {
00340 host_transfer_.notify_observers();
00341 }
00342 }
00343
00344 return turn_end ? PROCESS_END_TURN : PROCESS_CONTINUE;
00345 }
00346
00347 void turn_info::change_controller(const std::string& side, const std::string& controller)
00348 {
00349 config cfg;
00350 config& change = cfg.add_child("change_controller");
00351 change["side"] = side;
00352 change["controller"] = controller;
00353
00354 network::send_data(cfg, 0);
00355 }
00356
00357
00358 void turn_info::change_side_controller(const std::string& side, const std::string& player)
00359 {
00360 config cfg;
00361 config& change = cfg.add_child("change_controller");
00362 change["side"] = side;
00363 change["player"] = player;
00364 network::send_data(cfg, 0);
00365 }
00366
00367 #if 0
00368 void turn_info::take_side(const std::string& side, const std::string& controller)
00369 {
00370 config cfg;
00371 cfg["side"] = side;
00372 cfg["controller"] = controller;
00373 cfg["name"] = controller+side;
00374 network::send_data(cfg, 0, true);
00375 }
00376 #endif