The Battle for Wesnoth  1.19.5+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 #include "serialization/markup.hpp"
25 
26 static lg::log_domain log_engine("engine");
27 #define LOG_NG LOG_STREAM(info, log_engine)
28 #define ERR_NG LOG_STREAM(err, log_engine)
29 
30 static lg::log_domain log_config("config");
31 #define LOG_CF LOG_STREAM(info, log_config)
32 #define WRN_CF LOG_STREAM(warn, log_config)
33 #define ERR_CF LOG_STREAM(err, log_config)
34 
35 static lg::log_domain log_network("network");
36 #define LOG_NW LOG_STREAM(info, log_network)
37 #define ERR_NW LOG_STREAM(err, log_network)
38 
39 namespace mp
40 {
41 // This is for the wesnothd server, it expects a more detailed summary in [multiplayer]
42 static void add_multiplayer_classification(config& multiplayer, saved_game& state)
43 {
44  multiplayer["mp_scenario"] = state.get_scenario_id();
45  multiplayer["mp_scenario_name"] = state.get_starting_point()["name"];
46  multiplayer["difficulty_define"] = state.classification().difficulty;
47  multiplayer["mp_campaign"] = state.classification().campaign;
48  multiplayer["mp_campaign_name"] = state.classification().campaign_name;
49  multiplayer["mp_era"] = state.classification().era_id;
50  multiplayer["active_mods"] = utils::join(state.classification().active_mods, ",");
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 == saved_game_mode::type::no) {
70  state.set_random_seed();
71  }
72 
73  if(scenario["objectives"].empty()) {
74  // Generic victory objectives.
75  std::ostringstream ss;
76  ss << markup::tag("big", t_string(N_("Victory:"), "wesnoth")) << "\n";
77  ss << markup::span_color("#00ff00",
78  font::unicode_bullet, " ", t_string(N_("Defeat enemy leader(s)"), "wesnoth"));
79  scenario["objectives"] = ss.str();
80  }
81 
82  config level = state.to_config();
83  add_multiplayer_classification(level.child_or_add("multiplayer"), state);
84 
85  // [multiplayer] mp_era= should be persistent over saves.
86  std::string era = state.classification().era_id;
87 
88  /**
89  * [era] and [modification]s are toplevel tags here.
90  * They are not part of the saved_game and are only used during mp_staging/mp_join_game.
91  *
92  * @todo: see if all the comments ai algorithms are still up-to-date and relevant.
93  *
94  * -- vultraz, 2017-11-24
95  */
96 
98  auto era_cfg = game_config.find_child("era", "id", era);
99 
100  if(!era_cfg) {
101  if(params.saved_game == saved_game_mode::type::no) {
102  throw config::error(VGETTEXT("Cannot find era ‘$era’", {{"era", era}}));
103  }
104 
105  // FIXME: @todo We should tell user about missing era but still load game...
106  WRN_CF << "Missing era in MP load game '" << era << "'";
107 
108  } else {
109  level.add_child("era", *era_cfg);
110 
111  // Initialize the list of sides available for the current era.
112  // We also need this so not to get a segfault in mp_staging for ai configuration.
113  const config& custom_side = game_config.find_mandatory_child("multiplayer_side", "id", "Custom");
114  level.mandatory_child("era").add_child_at("multiplayer_side", custom_side, 0);
115  }
116 
117  // Add modifications, needed for ai algorithms which are applied in mp_staging.
118  const std::vector<std::string>& mods = state.classification().active_mods;
119 
120  for(unsigned i = 0; i < mods.size(); ++i) {
121  if(auto mod_cfg = game_config.find_child("modification", "id", mods[i])) {
122  level.add_child("modification", *mod_cfg);
123  }
124  }
125 
126  // This will force connecting clients to be using the same version number as us.
127  level["version"] = game_config::wesnoth_version.str();
128  return level;
129 }
130 
132 {
134  state = saved_game(level);
135  state.classification().type = type;
136 }
137 
138 } // end namespace mp
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
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:170
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:427
config to_config() const
Definition: saved_game.cpp:655
std::string get_scenario_id() const
Definition: saved_game.cpp:679
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:60
config & get_starting_point()
Definition: saved_game.cpp:612
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:386
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
Definition: saved_game.cpp:505
bool valid() const
Definition: saved_game.cpp:583
void set_defaults()
does some post loading stuff must be used before passing the data to connect_engine
Definition: saved_game.cpp:221
std::string str() const
Serializes the version number into string form.
Definitions for the interface to Wesnoth Markup Language (WML).
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:1023
#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:61
const version_info wesnoth_version(VERSION)
std::string tag(const std::string &tag_name, Args &&... contents)
Returns the contents enclosed inside <tag_name> and </tag_name>
Definition: markup.hpp:35
std::string span_color(const color_t &color, Args &&... data)
Returns a Pango formatting string using the provided color_t object.
Definition: markup.hpp:68
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 join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
saved_game_mode::type saved_game