The Battle for Wesnoth  1.19.0-dev
mp_game_utils.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2024
3  by Andrius Silinskas <silinskas.andrius@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 
18 #include "config.hpp"
19 #include "formula/string_utils.hpp"
20 #include "game_config_manager.hpp"
21 #include "gettext.hpp"
22 #include "log.hpp"
23 #include "saved_game.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 
53 {
54  const mp_game_settings& params = state.mp_settings();
55  state.set_defaults();
56 
57  // Also impliers state.expand_scenario()
58  // We need to call this before expand_mp_events/options otherwise they might be overwritten.
59  state.expand_random_scenario();
60  state.expand_mp_events();
61  state.expand_mp_options();
62 
63  if(!state.valid()) {
64  throw config::error("Failed to load the scenario");
65  }
66 
67  config& scenario = state.get_starting_point();
68  if(state.mp_settings().saved_game == saved_game_mode::type::no) {
69  state.set_random_seed();
70  }
71 
72  if(scenario["objectives"].empty()) {
73  // Generic victory objectives.
74  std::ostringstream ss;
75  ss << "<big>";
76  ss << t_string(N_("Victory:"), "wesnoth") << "</big>\n";
77  ss << "<span color='#00ff00'>" << font::unicode_bullet << " ";
78  ss << t_string(N_("Defeat enemy leader(s)"), "wesnoth") << "</span>";
79 
80  scenario["objectives"] = ss.str();
81  }
82 
83  config level = state.to_config();
84  add_multiplayer_classification(level.child_or_add("multiplayer"), state);
85 
86  // [multiplayer] mp_era= should be persistent over saves.
87  std::string era = state.classification().era_id;
88 
89  /**
90  * [era] and [modification]s are toplevel tags here.
91  * They are not part of the saved_game and are only used during mp_staging/mp_join_game.
92  *
93  * @todo: see if all the comments ai algorithms are still up-to-date and relevant.
94  *
95  * -- vultraz, 2017-11-24
96  */
97 
99  auto era_cfg = game_config.find_child("era", "id", era);
100 
101  if(!era_cfg) {
102  if(params.saved_game == saved_game_mode::type::no) {
103  throw config::error(VGETTEXT("Cannot find era '$era'", {{"era", era}}));
104  }
105 
106  // FIXME: @todo We should tell user about missing era but still load game...
107  WRN_CF << "Missing era in MP load game '" << era << "'";
108 
109  } else {
110  level.add_child("era", *era_cfg);
111 
112  // Initialize the list of sides available for the current era.
113  // We also need this so not to get a segfault in mp_staging for ai configuration.
114  const config& custom_side = game_config.find_mandatory_child("multiplayer_side", "id", "Custom");
115  level.mandatory_child("era").add_child_at("multiplayer_side", custom_side, 0);
116  }
117 
118  // Add modifications, needed for ai algorithms which are applied in mp_staging.
119  const std::vector<std::string>& mods = state.classification().active_mods;
120 
121  for(unsigned i = 0; i < mods.size(); ++i) {
122  if(auto mod_cfg = game_config.find_child("modification", "id", mods[i])) {
123  level.add_child("modification", *mod_cfg);
124  }
125  }
126 
127  // This will force connecting clients to be using the same version number as us.
128  level["version"] = game_config::wesnoth_version.str();
129  return level;
130 }
131 
133 {
135  state = saved_game(level);
136  state.classification().type = type;
137 }
138 
139 } // end namespace mp
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
std::string difficulty
The difficulty level the game is being played on.
std::vector< std::string > active_mods
campaign_type::type type
std::string campaign
The id of the campaign being played.
std::string campaign_name
The name of the campaign being played.
static game_config_manager * get()
const game_config_view & game_config() const
A class grating read only view to a vector of config objects, viewed as one config with all children ...
game_classification & classification()
Definition: saved_game.hpp:56
void set_random_seed()
sets the random seed if that didn't already happen.
Definition: saved_game.cpp:169
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:426
config to_config() const
Definition: saved_game.cpp:654
std::string get_scenario_id() const
Definition: saved_game.cpp:678
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:60
config & get_starting_point()
Definition: saved_game.cpp:611
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:385
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
Definition: saved_game.cpp:504
bool valid() const
Definition: saved_game.cpp:582
void set_defaults()
does some post loading stuff must be used before passing the data to connect_engine
Definition: saved_game.cpp:220
std::string str() const
Serializes the version number into string form.
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:968
#define N_(String)
Definition: gettext.hpp:101
Standard logging facilities (interface).
static lg::log_domain log_engine("engine")
static lg::log_domain log_network("network")
#define WRN_CF
static lg::log_domain log_config("config")
const std::string unicode_bullet
Definition: constants.cpp:47
Game configuration data as global variables.
Definition: build_info.cpp:60
const version_info wesnoth_version(VERSION)
Main entry points of multiplayer mode.
Definition: lobby_data.cpp:50
config initial_level_config(saved_game &state)
void level_to_gamestate(const config &level, saved_game &state)
static void add_multiplayer_classification(config &multiplayer, saved_game &state)
std::string era()
Definition: game.cpp:678
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
saved_game_mode::type saved_game