The Battle for Wesnoth  1.15.3+dev
mp_game_utils.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2018 by Andrius Silinskas <silinskas.andrius@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
15 
16 #include "config.hpp"
17 #include "formula/string_utils.hpp"
18 #include "game_config_manager.hpp"
19 #include "gettext.hpp"
20 #include "log.hpp"
21 #include "saved_game.hpp"
22 #include "game_version.hpp"
24 
25 static lg::log_domain log_engine("engine");
26 #define LOG_NG LOG_STREAM(info, log_engine)
27 #define ERR_NG LOG_STREAM(err, log_engine)
28 
29 static lg::log_domain log_config("config");
30 #define LOG_CF LOG_STREAM(info, log_config)
31 #define WRN_CF LOG_STREAM(warn, log_config)
32 #define ERR_CF LOG_STREAM(err, log_config)
33 
34 static lg::log_domain log_network("network");
35 #define LOG_NW LOG_STREAM(info, log_network)
36 #define ERR_NW LOG_STREAM(err, log_network)
37 
38 namespace mp
39 {
40 // This is for the wesnothd server, it expects a more detailed summary in [multiplayer]
41 static void add_multiplayer_classification(config& multiplayer, saved_game& state)
42 {
43  multiplayer["mp_scenario"] = state.get_scenario_id();
44  multiplayer["mp_scenario_name"] = state.get_starting_point()["name"];
45  multiplayer["difficulty_define"] = state.classification().difficulty;
46  multiplayer["mp_campaign"] = state.classification().campaign;
47  multiplayer["mp_campaign_name"] = state.classification().campaign_name;
48  multiplayer["mp_era"] = state.classification().era_id;
49  multiplayer["active_mods"] = utils::join(state.classification().active_mods, ",");
50 
51 }
52 
54 {
55  const mp_game_settings& params = state.mp_settings();
56  state.set_defaults();
57 
58  // Also impliers state.expand_scenario()
59  // We need to call this before expand_mp_events/options otherwise they might be overwritten.
60  state.expand_random_scenario();
61  state.expand_mp_events();
62  state.expand_mp_options();
63 
64  if(!state.valid()) {
65  throw config::error("Failed to load the scenario");
66  }
67 
68  config& scenario = state.get_starting_point();
69  if(state.mp_settings().saved_game == mp_game_settings::SAVED_GAME_MODE::NONE) {
70  state.set_random_seed();
71  }
72 
73  if(scenario["objectives"].empty()) {
74  // Generic victory objectives.
75  std::ostringstream ss;
76  ss << "<big>";
77  ss << t_string(N_("Victory:"), "wesnoth") << "</big>\n";
78  ss << "<span color='#00ff00'>" << font::unicode_bullet << " ";
79  ss << t_string(N_("Defeat enemy leader(s)"), "wesnoth") << "</span>";
80 
81  scenario["objectives"] = ss.str();
82  }
83 
84  config level = state.to_config();
85  add_multiplayer_classification(level.child_or_add("multiplayer"), state);
86  level.child("multiplayer")["mp_scenario_addon_id"] = level.child("scenario")["addon_id"].str();
87  level.child("multiplayer")["mp_scenario_addon_version"] = state.to_config().child("scenario")["addon_version"].str();
88 
89  // [multiplayer] mp_era= should be persistent over saves.
90  std::string era = state.classification().era_id;
91 
92  /**
93  * [era] and [modification]s are toplevel tags here.
94  * They are not part of the saved_game and are only used during mp_staging/mp_join_game.
95  *
96  * @todo: see if all the comments ai algorithms are still up-to-date and relevant.
97  *
98  * -- vultraz, 2017-11-24
99  */
100 
102  const config& era_cfg = game_config.find_child("era", "id", era);
103 
104  if(!era_cfg) {
105  if(params.saved_game == mp_game_settings::SAVED_GAME_MODE::NONE) {
106  throw config::error(VGETTEXT("Cannot find era $era", {{"era", era}}));
107  }
108 
109  // FIXME: @todo We should tell user about missing era but still load game...
110  WRN_CF << "Missing era in MP load game " << era << std::endl;
111 
112  } else {
113  level.add_child("era", era_cfg);
114 
115  level.child("multiplayer")["mp_era_addon_id"] = era_cfg["addon_id"].str();
116  level.child("multiplayer")["mp_era_addon_version"] = era_cfg["addon_version"].str();
117 
118  // Initialize the list of sides available for the current era.
119  // We also need this so not to get a segfault in mp_staging for ai configuration.
120  const config& custom_side = game_config.find_child("multiplayer_side", "id", "Custom");
121  level.child("era").add_child_at("multiplayer_side", custom_side, 0);
122  }
123 
124  // Add modifications, needed for ai algorithms which are applied in mp_staging.
125  const std::vector<std::string>& mods = state.classification().active_mods;
126  std::vector<std::string> mod_versions;
127  std::vector<std::string> mod_addon_ids;
128 
129  for(unsigned i = 0; i < mods.size(); ++i) {
130  if(const config& mod_cfg = game_config.find_child("modification", "id", mods[i])) {
131  mod_versions.push_back(mod_cfg["addon_version"].str());
132  mod_addon_ids.push_back(mod_cfg["addon_id"].str());
133  level.add_child("modification", mod_cfg);
134  }
135  }
136 
137  level.child("multiplayer")["active_mod_versions"] = utils::join(mod_versions);
138  level.child("multiplayer")["active_mod_addon_ids"] = utils::join(mod_addon_ids);
139 
140  // This will force connecting clients to be using the same version number as us.
141  level["version"] = game_config::wesnoth_version.str();
142  return level;
143 }
144 
146 {
147  game_classification::CAMPAIGN_TYPE type = state.classification().campaign_type;
148  state = saved_game(level);
149  state.classification().campaign_type = type;
150 }
151 
152 void check_response(bool res, const config& data)
153 {
154  if(!res) {
155  throw wesnothd_error(_("Connection timed out"));
156  }
157 
158  if(const config& err = data.child("error")) {
159  throw wesnothd_error(err["message"]);
160  }
161 }
162 
163 } // end namespace mp
An error occurred during when trying to coommunicate with the wesnothd server.
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
std::string era()
Definition: game.cpp:723
Interfaces for manipulating version numbers of engine, add-ons, etc.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
static lg::log_domain log_config("config")
void set_defaults()
does some post loading stuff must be used before passing the data to connect_engine ...
Definition: saved_game.cpp:216
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
config initial_level_config(saved_game &state)
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
Definition: saved_game.cpp:477
std::string campaign_name
The name of the campaign being played.
bool valid() const
Definition: saved_game.cpp:554
config & child_or_add(config_key_type key)
Definition: config.cpp:466
void level_to_gamestate(const config &level, saved_game &state)
Definitions for the interface to Wesnoth Markup Language (WML).
#define WRN_CF
Pubic entry points for the MP workflow.
Definition: lobby_data.cpp:51
static game_config_manager * get()
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
void set_random_seed()
sets the random seed if that didn&#39;t already happen.
Definition: saved_game.cpp:167
std::vector< std::string > active_mods
void expand_mp_options()
adds values of [option]s into [carryover_sides_start][variables] so that they are applied in the next...
Definition: saved_game.cpp:412
config & add_child_at(config_key_type key, const config &val, unsigned index)
Definition: config.cpp:508
const game_config_view & game_config() const
config & get_starting_point()
Definition: saved_game.cpp:583
void check_response(bool res, const config &data)
std::string campaign
The id of the campaign being played.
std::size_t i
Definition: function.cpp:933
logger & err()
Definition: log.cpp:78
Default, unset return value.
Definition: retval.hpp:31
Game configuration data as global variables.
Definition: build_info.cpp:55
std::string get_scenario_id()
Definition: saved_game.cpp:649
void expand_mp_events()
adds [event]s from [era] and [modification] into this scenario does NOT expand [option]s because vari...
Definition: saved_game.cpp:371
#define N_(String)
Definition: gettext.hpp:99
const std::string unicode_bullet
Definition: constants.cpp:43
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
const version_info wesnoth_version(VERSION)
config & add_child(config_key_type key)
Definition: config.cpp:476
const config & find_child(config_key_type key, const std::string &name, const std::string &value) const
std::string difficulty
The difficulty level the game is being played on.
game_classification & classification()
Definition: saved_game.hpp:55
Standard logging facilities (interface).
std::string str() const
Serializes the version number into string form.
config to_config() const
Definition: saved_game.cpp:626
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:59
static lg::log_domain log_network("network")
static lg::log_domain log_engine("engine")
static void add_multiplayer_classification(config &multiplayer, saved_game &state)