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 */
14 
15 #pragma once
16 
17 #include "commandline_options.hpp"
18 #include "config.hpp"
19 #include "flg_manager.hpp"
20 #include "saved_game.hpp"
21 #include <set>
22 
23 namespace randomness { class mt_rng; }
24 struct mp_campaign_info;
25 
26 namespace ng {
27 
28 enum controller {
29 	CNTR_NETWORK = 0,
30 	CNTR_LOCAL,
31 	CNTR_COMPUTER,
32 	CNTR_EMPTY,
33 	CNTR_RESERVED,
34 };
35 
36 class connect_engine;
37 class side_engine;
38 
39 typedef const std::unique_ptr<connect_engine> connect_engine_ptr;
40 typedef std::shared_ptr<side_engine> side_engine_ptr;
41 typedef std::pair<ng::controller, std::string> controller_option;
42 
43 class connect_engine
44 {
45 public:
46 	connect_engine(saved_game& state,
47 		const bool first_scenario, mp_campaign_info* campaign_info);
48 
49 	config* current_config();
50 
51 	void import_user(const std::string& name, const bool observer,
52 		int side_taken = -1);
53 	void import_user(const config& data, const bool observer,
54 		int side_taken = -1);
55 
56 	// Returns true if there are still sides available for this game.
57 	bool sides_available() const;
58 
59 	// Import all sides into the level.
60 	void update_level();
61 	// Updates the level and sends a diff to the clients.
62 	void update_and_send_diff(bool update_time_of_day = false);
63 
64 	bool can_start_game() const;
65 	void start_game();
66 	void start_game_commandline(const commandline_options& cmdline_opts, const config& game_config);
67 
68 	void leave_game();
69 
70 	// Return pair first element specifies whether to leave the game
71 	// and second element whether to silently update UI.
72 	std::pair<bool, bool> process_network_data(const config& data);
73 
74 	// Returns the side which is taken by a given user,
75 	// or -1 if none was found.
76 	int find_user_side_index_by_id(const std::string& id) const;
77 
78 
79 	/* Setters & Getters */
80 
level() const81 	const config& level() const { return level_; }
scenario()82 	config& scenario()
83 	{
84 		if(config& scenario = level_.child("scenario"))
85 			return scenario;
86 		else if(config& snapshot = level_.child("snapshot"))
87 			return snapshot;
88 		else
89 			throw "No scenariodata found";
90 	}
91 	const std::set<std::string>& connected_users() const;
92 
93 	struct team_data_pod
94 	{
95 		std::string team_name;
96 		std::string user_team_name; // TODO: use t_string?
97 
98 		bool is_player_team;
99 	};
100 
team_data() const101 	const std::vector<team_data_pod>& team_data() const
102 	{
103 		return team_data_;
104 	}
105 
side_engines()106 	std::vector<side_engine_ptr>& side_engines() { return side_engines_; }
params() const107 	const mp_game_settings& params() const { return params_; }
first_scenario() const108 	bool first_scenario() const { return first_scenario_; }
force_lock_settings() const109 	bool force_lock_settings() const { return force_lock_settings_; }
110 
111 	bool receive_from_server(config& dst) const;
112 
campaign_info() const113 	const mp_campaign_info* campaign_info() const
114 	{
115 		return campaign_info_;
116 	}
117 
118 private:
119 	connect_engine(const connect_engine&) = delete;
120 	void operator=(const connect_engine&) = delete;
121 
122 	void send_level_data() const;
123 
124 	void save_reserved_sides_information();
125 	void load_previous_sides_users();
126 
127 	void update_side_controller_options();
128 
129 	friend class side_engine;
130 
131 	config level_;
132 	saved_game& state_;
133 
134 	const mp_game_settings& params_;
135 
136 	const ng::controller default_controller_;
137 	mp_campaign_info* campaign_info_;
138 	const bool first_scenario_;
139 
140 	bool force_lock_settings_;
141 
142 	std::vector<side_engine_ptr> side_engines_;
143 	std::vector<const config*> era_factions_;
144 	std::vector<team_data_pod> team_data_;
145 
146 	std::set<std::string>& connected_users_rw();
147 	void send_to_server(const config& cfg) const;
148 };
149 
150 class side_engine
151 {
152 public:
153 	side_engine(const config& cfg, connect_engine& parent_engine,
154 		const int index);
155 
156 	// An untranslated user_description which is used by other clients
157 	// An empty string means the other clients should generate the description on their own
158 	// Used by new_config().
159 	std::string user_description() const;
160 
161 	// Creates a config representing this side.
162 	config new_config() const;
163 
164 	// Returns true, if the player has chosen his/her leader and this side
165 	// is ready for the game to start.
166 	bool ready_for_start() const;
167 	// Returns true if this side is waiting for a network player and
168 	// players are allowed.
169 	bool available_for_user(const std::string& name = "") const;
170 
171 	void resolve_random( randomness::mt_rng & rng, const std::vector<std::string> & avoid_faction_ids = std::vector<std::string>());
172 
173 	// Resets this side to its default state.
174 	void reset();
175 
176 	// Place user into this side.
177 	void place_user(const std::string& name);
178 	void place_user(const config& data, bool contains_selection = false);
179 
180 	void update_controller_options();
181 	void update_current_controller_index();
182 	bool controller_changed(const int selection);
183 	void set_controller(ng::controller controller);
184 
185 	// Game set up from command line helpers.
186 	void set_faction_commandline(const std::string& faction_name);
187 	void set_controller_commandline(const std::string& controller_name);
188 
189 	/* Setters & Getters */
190 
save_id() const191 	std::string save_id() const
192 		{ return (!cfg_["save_id"].empty()) ? cfg_["save_id"] : cfg_["id"]; }
193 	// The id of the side of the previous scenario that should control this side.
previous_save_id() const194 	std::string previous_save_id() const
195 		{ return (!cfg_["previous_save_id"].empty()) ? cfg_["previous_save_id"] : save_id(); }
controller_options() const196 	const std::vector<controller_option>& controller_options() const
197 		{ return controller_options_; }
cfg() const198 	const config& cfg() const { return cfg_; }
controller() const199 	ng::controller controller() const { return controller_; }
current_controller_index() const200 	unsigned current_controller_index() const
201 		{ return current_controller_index_; }
index() const202 	int index() const { return index_; }
set_index(int index)203 	void set_index(int index) { index_ = index; }
team() const204 	unsigned team() const { return team_; }
set_team(unsigned team)205 	void set_team(unsigned team) { team_ = team; }
206 	std::vector<std::string> get_children_to_swap();
207 	std::multimap<std::string, config> get_side_children();
208 	void set_side_children(std::multimap<std::string, config> children);
color() const209 	int color() const { return color_; }
set_color(int color)210 	void set_color(int color) { color_ = color; color_id_ = color_options_[color]; }
gold() const211 	int gold() const { return gold_; }
set_gold(int gold)212 	void set_gold(int gold) { gold_ = gold; }
income() const213 	int income() const { return income_; }
set_income(int income)214 	void set_income(int income) { income_ = income; }
player_id() const215 	const std::string& player_id() const { return player_id_; }
reserved_for() const216 	const std::string& reserved_for() const { return reserved_for_; }
set_reserved_for(const std::string & reserved_for)217 	void set_reserved_for(const std::string& reserved_for)
218 		{ reserved_for_ = reserved_for; }
ai_algorithm() const219 	const std::string& ai_algorithm() const { return ai_algorithm_; }
set_ai_algorithm(const std::string & ai_algorithm)220 	void set_ai_algorithm(const std::string& ai_algorithm)
221 		{ ai_algorithm_ = ai_algorithm; }
allow_player() const222 	bool allow_player() const { return allow_player_; }
allow_changes() const223 	bool allow_changes() const { return allow_changes_; }
waiting_to_choose_faction() const224 	bool waiting_to_choose_faction() const { return waiting_to_choose_faction_; }
set_waiting_to_choose_status(bool status)225 	void set_waiting_to_choose_status(bool status) { waiting_to_choose_faction_ = status;}
allow_shuffle() const226 	bool allow_shuffle() const { return !disallow_shuffle_;}
flg()227 	flg_manager& flg() { return flg_; }
228 
color_id() const229 	const std::string color_id() const { return color_id_; }
color_options() const230 	const std::vector<std::string>& color_options() const { return color_options_; }
231 
team_name() const232 	const std::string team_name() const
233 	{
234 		return parent_.team_data_[team_].team_name;
235 	}
236 
user_team_name() const237 	const std::string user_team_name() const
238 	{
239 		return t_string::from_serialized(parent_.team_data_[team_].user_team_name);
240 	}
241 
242 private:
243 	side_engine(const side_engine& engine) = delete;
244 	void operator=(const side_engine&) = delete;
245 
246 	void add_controller_option(ng::controller controller,
247 		const std::string& name, const std::string& controller_value);
248 
249 	config cfg_;
250 	connect_engine& parent_;
251 
252 	ng::controller controller_;
253 	unsigned current_controller_index_;
254 	std::vector<controller_option> controller_options_;
255 
256 	const bool allow_player_;
257 	const bool controller_lock_;
258 
259 	int index_;
260 	unsigned team_;
261 	int color_;
262 	int gold_;
263 	int income_;
264 	// set during create_engines constructor never set after that.
265 	// the name of the player who is preferred for this side,
266 	// if controller_ == reserved only this player can take this side.
267 	// can also be a number of a side if this side should be controlled
268 	// by the player who controls  that side
269 	std::string reserved_for_;
270 	std::string player_id_;
271 	std::string ai_algorithm_;
272 
273 	bool chose_random_;
274 	bool disallow_shuffle_;
275 	flg_manager flg_;
276 	const bool allow_changes_;
277 	bool waiting_to_choose_faction_;
278 
279 	std::vector<std::string> color_options_;
280 
281 	std::string color_id_;
282 };
283 
284 } // end namespace ng
285