31 #include <boost/assign.hpp>
36 #define LOG_CF LOG_STREAM(info, log_config)
37 #define WRN_CF LOG_STREAM(warn, log_config)
38 #define ERR_CF LOG_STREAM(err, log_config)
41 #define DBG_MP LOG_STREAM(debug, log_mp_connect_engine)
42 #define LOG_MP LOG_STREAM(info, log_mp_connect_engine)
43 #define WRN_MP LOG_STREAM(warn, log_mp_connect_engine)
44 #define ERR_MP LOG_STREAM(err, log_mp_connect_engine)
47 #define LOG_NW LOG_STREAM(info, log_network)
86 campaign_info_(campaign_info),
87 first_scenario_(first_scenario),
88 force_lock_settings_(),
114 std::vector<std::string> original_team_names;
117 for (
config& side : sides) {
118 const std::string side_str = std::to_string(side_count);
121 side[
"user_team_name"];
124 if (team_name.
empty()) {
125 team_name = side_str;
128 user_team_name = team_name;
131 bool add_team =
true;
143 std::vector<std::string>::const_iterator name_itor =
145 original_team_names.end(), team_name.
str());
146 if (name_itor == original_team_names.end()) {
147 original_team_names.push_back(team_name);
149 team_name =
"Team " +
150 std::to_string(original_team_names.size());
152 team_name =
"Team " + std::to_string(
153 name_itor - original_team_names.begin() + 1);
157 user_team_name = team_prefix + side_str;
182 for (
const config &
s : sides) {
222 user_data[
"name"] =
name;
230 assert(!username.empty());
240 bool side_assigned =
false;
241 if (side_taken >= 0) {
243 side_assigned =
true;
248 if (side->reserved_for() == username && side->player_id().empty() && side->controller() !=
CNTR_COMPUTER) {
249 side->place_user(data);
251 side_assigned =
true;
257 if (side_taken < 0 && !side_assigned) {
259 if (side->available_for_user(username) ||
261 side->place_user(data);
263 side_assigned =
true;
272 if(user_side->player_id() == username && !user_side->previous_save_id().empty()) {
274 if(side->player_id().empty() && side->previous_save_id() == user_side->previous_save_id()) {
275 side->place_user(data);
285 if (side->available_for_user()) {
295 DBG_MP <<
"updating level" << std::endl;
312 scenario_diff.
add_child(
"scenario_diff", diff);
325 if (!side->ready_for_start()) {
326 const int side_num = side->index() + 1;
327 DBG_MP <<
"not all sides are ready, side " <<
328 side_num <<
" not ready\n";
334 DBG_MP <<
"all sides are ready" << std::endl;
343 if (side->controller() !=
CNTR_EMPTY && side->allow_player()) {
371 std::vector<std::string> children;
373 children.push_back(
"village");
374 children.push_back(
"unit");
375 children.push_back(
"ai");
382 std::multimap<std::string, config> children;
386 children.insert(std::pair<std::string, config>(children_to_swap, child));
399 for (std::pair<std::string, config> child_map : children) {
407 DBG_MP <<
"starting a new game" << std::endl;
413 std::vector<std::string> avoid_faction_ids;
416 if (
params_.random_faction_mode != mp_game_settings::RANDOM_FACTION_MODE::DEFAULT) {
418 if (!side2->flg().is_random_faction()) {
419 switch(
params_.random_faction_mode.v) {
420 case mp_game_settings::RANDOM_FACTION_MODE::NO_MIRROR:
421 avoid_faction_ids.push_back(side2->flg().current_faction()[
"id"].str());
423 case mp_game_settings::RANDOM_FACTION_MODE::NO_ALLY_MIRROR:
424 if (side2->team() == side->team()) {
425 avoid_faction_ids.push_back(side2->flg().current_faction()[
"id"].str());
434 side->resolve_random(rng, avoid_faction_ids);
442 std::vector<int> playable_sides;
444 if (side->allow_player() && side->allow_shuffle()) {
445 playable_sides.push_back(side->index());
450 for (
int i = playable_sides.size();
i > 1;
i--)
453 int i_side = playable_sides[
i - 1];
455 if (i_side == j_side)
continue;
459 side_engines_[j_side] = side_engines_[i_side];
460 side_engines_[i_side] = tmp_side;
464 std::multimap<std::string, config> tmp_side_children = side_engines_[j_side]->get_side_children();
465 side_engines_[j_side]->set_side_children(side_engines_[i_side]->get_side_children());
466 side_engines_[i_side]->set_side_children(tmp_side_children);
470 int tmp_index = side_engines_[j_side]->index();
471 side_engines_[j_side]->set_index(side_engines_[i_side]->
index());
472 side_engines_[i_side]->set_index(tmp_index);
474 int tmp_team = side_engines_[j_side]->team();
475 side_engines_[j_side]->set_team(side_engines_[i_side]->
team());
476 side_engines_[i_side]->set_team(tmp_team);
481 config lock(
"stop_updates");
497 DBG_MP <<
"starting a new game in commandline mode" << std::endl;
499 typedef boost::tuple<unsigned int, std::string> mp_option;
511 if (option.get<0>() == num) {
513 DBG_MP <<
"\tsetting side " << option.get<0>() <<
"\tfaction: " << option.get<1>() << std::endl;
515 side->set_faction_commandline(option.get<1>());
518 ERR_MP <<
"failed to set side " << option.get<0>() <<
" to faction " << option.get<1>() << std::endl;
528 if (option.get<0>() ==
num) {
529 DBG_MP <<
"\tsetting side " << option.get<0>() <<
530 "\tfaction: " << option.get<1>() << std::endl;
532 side->set_controller_commandline(option.get<1>());
539 side->set_ai_algorithm(
"ai_default_rca");
543 if (option.get<0>() == num) {
544 DBG_MP <<
"\tsetting side " << option.get<0>() <<
545 "\tfaction: " << option.get<1>() << std::endl;
547 side->set_ai_algorithm(option.get<1>());
554 side->resolve_random(rng);
571 if (option.get<0>() == side[
"side"].to_unsigned()) {
572 DBG_MP <<
"\tsetting side " << side[
"side"] <<
573 "\tai_config: " << option.get<1>() << std::endl;
575 side[
"ai_config"] = option.get<1>();
589 typedef boost::tuple<unsigned int, std::string, std::string>
595 if (parameter.get<0>() == side[
"side"].to_unsigned()) {
596 DBG_MP <<
"\tsetting side " << side[
"side"] <<
" " <<
597 parameter.get<1>() <<
": " << parameter.get<2>() <<
600 side[parameter.get<1>()] = parameter.get<2>();
615 std::pair<bool, bool>
result(std::make_pair(
false,
true));
617 if (data.
child(
"leave_game")) {
623 if (!data[
"side_drop"].empty()) {
624 unsigned side_drop = data[
"side_drop"].to_int() - 1;
633 side_to_drop->reset();
642 if (!data[
"side"].empty()) {
643 unsigned side_taken = data[
"side"].to_int() - 1;
649 response[
"failed"] =
true;
652 ERR_CF <<
"ERROR: No username provided with the side." << std::endl;
662 response[
"failed"] =
true;
663 response[
"message"] =
"The nickname '" + name +
664 "' is already in use.";
684 if (
s->available_for_user()) {
691 if (side_taken >= side_engines_.size()) {
693 response[
"failed"] =
true;
698 kick[
"username"] = data[
"name"];
703 ERR_CF <<
"ERROR: Couldn't assign a side to '" <<
710 LOG_CF <<
"client has taken a valid position\n";
719 LOG_MP <<
"waiting to choose status = " <<
721 result.second =
false;
723 LOG_NW <<
"sent player data\n";
725 ERR_CF <<
"tried to take illegal side: " << side_taken << std::endl;
728 response[
"failed"] =
true;
734 if (
const config& change_faction = data.
child(
"change_faction")) {
749 if (!observer_name.
empty()) {
767 if (side->player_id() ==
id) {
774 if (i >= side_engines_.size()) {
804 std::map<std::string, std::string> side_users =
809 if (!save_id.empty() && !player_id.empty()) {
810 side_users[save_id] = player_id;
818 std::map<std::string, std::string> side_users =
820 std::set<std::string>
names;
822 const std::string& save_id = side->previous_save_id();
823 if (side_users.find(save_id) != side_users.end()) {
824 side->set_reserved_for(side_users[save_id]);
828 names.insert(side_users[save_id]);
830 side->update_controller_options();
846 side->update_controller_options();
857 static std::set<std::string> empty;
870 parent_(parent_engine),
872 current_controller_index_(0),
873 controller_options_(),
874 allow_player_(cfg[
"allow_player"].to_bool(true)),
875 controller_lock_(cfg[
"controller_lock"].to_bool(
880 gold_(cfg[
"gold"].to_int(100)),
881 income_(cfg[
"income"]),
882 reserved_for_(cfg[
"current_player"]),
885 chose_random_(cfg[
"chose_random"].to_bool(false)),
886 disallow_shuffle_(cfg[
"disallow_shuffle"].to_bool(false)),
887 flg_(parent_.era_factions_, cfg_, parent_.force_lock_settings_,
889 allow_changes_(!parent_.params_.
saved_game && !(flg_.choosable_factions().
size() == 1 && flg_.choosable_leaders().
size() == 1 && flg_.choosable_genders().
size() == 1)),
890 waiting_to_choose_faction_(allow_changes_),
896 (
"type",
cfg_[
"type"])
897 (
"gender",
cfg_[
"gender"])
898 (
"faction",
cfg_[
"faction"])
899 (
"recruit",
cfg_[
"recruit"])
903 const size_t side_cntr_index =
cfg_[
"controller"].to_int(-1) - 1;
910 ERR_MP <<
"contoller=<number> is deperecated\n";
913 assert(
cfg_[
"id"].empty());
922 cfg_[
"controller"] =
"ai";
924 if(
cfg_[
"controller"] !=
"human" &&
cfg_[
"controller"] !=
"ai" &&
cfg_[
"controller"] !=
"null") {
929 if (
cfg_[
"controller"] ==
"null") {
931 }
else if (
cfg_[
"controller"] ==
"ai") {
945 unsigned team_name_index = 0;
947 if (name == cfg[
"team_name"]) {
956 WRN_MP <<
"In side_engine constructor: Could not find my team_name " << cfg[
"team_name"] <<
" among the mp connect engine's list of team names. I am being assigned to the first team. This may indicate a bug!" << std::endl;
958 team_ = team_name_index;
960 if (!cfg[
"color"].empty()) {
961 if(cfg[
"color"].to_int()) {
962 color_ = cfg[
"color"].to_int() - 1;
985 return N_(
"Anonymous player");
990 return N_(
"Computer Player");
1006 res[
"faction_name"] = faction[
"name"];
1007 res[
"faction"] = faction[
"id"];
1013 res[
"side"] =
index_ + 1;
1016 res[
"controller"] = controller_names[
controller_];
1024 res[
"user_description"] =
t_string(desc,
"wesnoth");
1026 "$playername $side",
1027 boost::assign::map_list_of
1028 (
"playername",
_(desc.c_str()))
1029 (
"side", res[
"side"].str())
1034 if(res[
"name"].str().
empty() && !desc.empty()) {
1046 res[
"no_leader"] =
true;
1064 res[
"current_player"] = desc;
1081 leader = &side_unit;
1087 if (!leader_id.empty()) {
1088 (*leader)[
"id"] = leader_id;
1103 res[
"gold"] =
gold_;
1110 for (
const std::string& attribute : attributes_to_trim) {
1179 const std::string target_ai = target.ai_algorithm_;
1189 target.player_id_.clear();
1196 if (target_id.empty()) {
1235 data[
"name"] =
name;
1245 if (data[
"change_faction"].to_bool() && contains_selection) {
1338 if (controller_name ==
"ai") {
1341 if (controller_name ==
"null") {
1352 cfg_[
"controller"] != controller_value) {
1362 std::vector<std::string>
res;
1380 return std::to_string(index + 1);
bool can_start_game() const
child_itors child_range(const std::string &key)
void remove_attribute(const std::string &key)
std::string join_map(const T &v, const std::string &major=",", const std::string &minor=":")
void save_reserved_sides_information()
boost::optional< std::vector< boost::tuple< unsigned int, std::string, std::string > > > multiplayer_parm
Non-empty if –parm was given on the command line. Vector of pairs (side number, parm name...
void set_waiting_to_choose_status(bool status)
boost::optional< std::string > multiplayer_turns
Non-empty if –turns was given on the command line. Dependent on –multiplayer.
void append(const config &cfg)
Append data from another config object to this one.
std::vector< std::string > player_teams_
void import_user(const std::string &name, const bool observer, int side_taken=-1)
boost::optional< std::vector< boost::tuple< unsigned int, std::string > > > multiplayer_algorithm
Non-empty if –algorithm was given on the command line. Vector of pairs (side number, value). Dependent on –multiplayer.
const mp_game_settings * mp_settings
std::vector< side_engine_ptr > side_engines_
void load_previous_sides_users()
bool swap_sides_on_drop_target(const unsigned drop_target)
void add_controller_option(ng::controller controller, const std::string &name, const std::string &controller_value)
uint32_t get_next_random()
Get a new random number.
config new_config() const
std::set< std::string > connected_players
players and observers
static lg::log_domain log_config("config")
config initial_level_config(saved_game &state)
void place_user(const std::string &name)
std::map< std::string, std::string > map_split(std::string const &val, char major, char minor, int flags, std::string const &default_value)
Splits a string based on two separators into a map.
void set_faction_commandline(const std::string &faction_name)
bool multiplayer_ignore_map_settings
True if –ignore-map-settings was given at the command line. Do not use map settings.
void set_controller_commandline(const std::string &controller_name)
bool receive_data(config &result)
std::string ai_algorithm_
static void add_mod_ai_from_config(config::const_child_itors configs)
void set_current_leader(const unsigned index)
std::string get_color_string(int id)
void set_current_gender(const unsigned index)
const config & child_or_empty(const std::string &key) const
Returns the first child with the given key, or an empty config if there is none.
std::vector< std::string > user_team_names_
void level_to_gamestate(const config &level, saved_game &state)
const bool allow_changes_
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
void clear_children(const std::string &key)
bool empty() const
Tests for an attribute that either was never set or was set to "".
std::vector< controller_option > controller_options_
bool ready_for_start() const
Variant for storing WML attributes.
void update_and_send_diff(bool update_time_of_day=false)
const std::set< std::string > & connected_users() const
bool sides_available() const
void send_data(const configr_of &request)
bool waiting_to_choose_faction_
void merge_with(const config &c)
Merge config 'c' into this config, overwriting this config's values.
std::string custom_color_
This class stores all the data for a single 'side' (in game nomenclature).
A small explanation about what's going on here: Each action has access to two game_info objects First...
static UNUSEDNOWARN std::string _(const char *str)
std::vector< side_engine_ptr > & side_engines()
boost::optional< std::vector< boost::tuple< unsigned int, std::string > > > multiplayer_controller
Non-empty if –controller was given on the command line. Vector of pairs (side number, controller). Dependent on –multiplayer.
void send_to_server(const config &cfg) const
const std::string & current_gender() const
void set_controller(ng::controller controller)
void add_color_info(const config &v)
Encapsulates the map of the game.
std::string user_description() const
config & add_child(const std::string &key)
void start_game_commandline(const commandline_options &cmdline_opts)
std::vector< std::string > get_colors() const
const bool first_scenario_
ng::controller controller() const
bool available_for_user(const std::string &name="") const
twesnothd_connection & wesnothd_connection
ng::controller controller_
std::vector< const config * > era_factions_
GLuint const GLuint * names
mp_campaign_info * campaign_info_
const ng::controller default_controller_
std::vector< std::string > get_children_to_swap()
void set_current_faction(const unsigned index)
config get_diff(const config &c) const
A function to get the differences between this object, and 'c', as another config object...
void send_level_data() const
config * current_config()
static void add_era_ai_from_config(const config &game_config)
void update_controller_options()
const config * default_leader_cfg() const
std::pair< child_iterator, child_iterator > child_itors
boost::optional< std::vector< boost::tuple< unsigned int, std::string > > > multiplayer_ai_config
Non-empty if –ai-config was given on the command line. Vector of pairs (side number, value). Dependent on –multiplayer.
std::string reserved_for_
boost::optional< std::vector< boost::tuple< unsigned int, std::string > > > multiplayer_side
Non-empty if –side was given on the command line. Vector of pairs (side number, faction id)...
static lg::log_domain log_network("network")
connect_engine(saved_game &state, const bool first_scenario, mp_campaign_info *campaign_info)
bool receive_from_server(config &dst) const
void update_current_controller_index()
const config & current_faction() const
unsigned current_controller_index_
std::string to_serialized() const
GLuint const GLchar * name
std::pair< ng::controller, std::string > controller_option
const std::string & current_leader() const
int find_user_side_index_by_id(const std::string &id) const
std::set< std::string > & connected_users_rw()
bool has_attribute(const std::string &key) const
bool find(E event, F functor)
Tests whether an event handler is available.
game_classification & classification()
Managing the AIs configuration - headers.
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
const bool controller_lock_
bool is_normal_mp_game() const
Standard logging facilities (interface).
bool controller_changed(const int selection)
void set_side_children(std::multimap< std::string, config > children)
static lg::log_domain log_mp_connect_engine("mp/connect/engine")
const mp_game_settings & params_
std::string get_color(int index=-1) const
void remove_attributes(T...keys)
void resolve_random(rand_rng::mt_rng &rng, const std::vector< std::string > &avoid)
A config object defines a single node in a WML file, with access to child nodes.
void resolve_random(rand_rng::mt_rng &rng, const std::vector< std::string > &avoid_faction_ids=std::vector< std::string >())
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
static const config & get_ai_config_for(const std::string &id)
Return the config for a specified ai.
std::vector< std::string > team_names_
side_engine(const config &cfg, connect_engine &parent_engine, const int index)
GLsizei const GLcharARB ** string
std::multimap< std::string, config > get_side_children()
config & add_child_at(const std::string &key, const config &val, unsigned index)
std::pair< bool, bool > process_network_data(const config &data)
bool force_lock_settings_
void update_side_controller_options()