The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
mp_game_utils.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2013 - 2025
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"
21#include "gettext.hpp"
22#include "log.hpp"
23#include "saved_game.hpp"
25
26static 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
30static 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
35static 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
39namespace mp
40{
41// This is for the wesnothd server, it expects a more detailed summary in [multiplayer]
42static 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.
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
131void level_to_gamestate(const config& level, saved_game& state)
132{
133 campaign_type::type type = state.classification().type;
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:157
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 ...
void set_random_seed()
sets the random seed if that didn't already happen.
void expand_mp_options()
adds values of [option]s into [carryover_sides_start][variables] so that they are applied in the next...
config to_config() const
std::string get_scenario_id() const
game_classification & classification()
config & get_starting_point()
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
void expand_mp_events()
adds [event]s from [era] and [modification] into this scenario does NOT expand [option]s because vari...
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
bool valid() const
void set_defaults()
does some post loading stuff must be used before passing the data to connect_engine
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.
#define N_(String)
Definition gettext.hpp:108
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.
const version_info wesnoth_version(VERSION)
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
Definition markup.hpp:110
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
Definition markup.hpp:45
Main entry points of multiplayer mode.
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 Range &v, const std::string &s=",")
Generates a new string joining container items in a list.
saved_game_mode::type saved_game
#define i