Initial step for splitting mp::connect into gui and engine.
This commit is contained in:
parent
77523d86d6
commit
13e22fd6f1
15 changed files with 1676 additions and 1381 deletions
|
@ -18970,6 +18970,14 @@
|
|||
RelativePath="..\..\src\multiplayer_connect.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\multiplayer_connect_engine.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\multiplayer_connect_engine.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\multiplayer_create.cpp"
|
||||
>
|
||||
|
|
|
@ -772,6 +772,7 @@ set(wesnoth-main_SRC
|
|||
multiplayer.cpp
|
||||
multiplayer_configure.cpp
|
||||
multiplayer_connect.cpp
|
||||
multiplayer_connect_engine.cpp
|
||||
multiplayer_create.cpp
|
||||
multiplayer_create_engine.cpp
|
||||
multiplayer_lobby.cpp
|
||||
|
|
|
@ -440,6 +440,7 @@ wesnoth_sources = Split("""
|
|||
multiplayer.cpp
|
||||
multiplayer_configure.cpp
|
||||
multiplayer_connect.cpp
|
||||
multiplayer_connect_engine.cpp
|
||||
multiplayer_create.cpp
|
||||
multiplayer_create_engine.cpp
|
||||
multiplayer_lobby.cpp
|
||||
|
|
|
@ -37,6 +37,13 @@ leader_list_manager::leader_list_manager(gui::combo* leader_combo,
|
|||
{
|
||||
}
|
||||
|
||||
void leader_list_manager::init_combos(gui::combo* leader_combo,
|
||||
gui::combo* gender_combo)
|
||||
{
|
||||
leader_combo_ = leader_combo;
|
||||
gender_combo_ = gender_combo;
|
||||
}
|
||||
|
||||
void leader_list_manager::set_side_list(
|
||||
const std::vector<const config *> &side_list)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
leader_list_manager(gui::combo* leader_combo = NULL,
|
||||
gui::combo* gender_combo = NULL);
|
||||
|
||||
void init_combos(gui::combo* leader_combo, gui::combo* gender_combo);
|
||||
void set_side_list(const std::vector<const config *> &side_list);
|
||||
void set_leader_combo(gui::combo* combo);
|
||||
void set_gender_combo(gui::combo* combo);
|
||||
|
|
|
@ -32,7 +32,7 @@ static lg::log_domain log_config("config");
|
|||
|
||||
namespace mp {
|
||||
|
||||
config initial_level_config(game_display& disp, mp_game_settings& params,
|
||||
config initial_level_config(game_display& disp, const mp_game_settings& params,
|
||||
game_state& state)
|
||||
{
|
||||
config level;
|
||||
|
@ -48,8 +48,6 @@ config initial_level_config(game_display& disp, mp_game_settings& params,
|
|||
return config();
|
||||
}
|
||||
} else {
|
||||
level.clear();
|
||||
params.mp_scenario = params.scenario_data["id"].str();
|
||||
level.merge_with(params.scenario_data);
|
||||
level["turns"] = params.num_turns;
|
||||
level.add_child("multiplayer", params.to_config());
|
||||
|
@ -60,7 +58,6 @@ config initial_level_config(game_display& disp, mp_game_settings& params,
|
|||
// params.options.find_child("multiplayer", "id",
|
||||
// params.mp_scenario)), 0);
|
||||
|
||||
params.hash = level.hash();
|
||||
level["next_underlying_unit_id"] = 0;
|
||||
n_unit::id_manager::instance().clear();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class game_state;
|
|||
|
||||
namespace mp {
|
||||
|
||||
config initial_level_config(game_display& disp, mp_game_settings& params,
|
||||
config initial_level_config(game_display& disp, const mp_game_settings& params,
|
||||
game_state& state);
|
||||
|
||||
config next_level_config(const config& level, game_state& state);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,13 +17,14 @@
|
|||
#ifndef MULTIPLAYER_CONNECT_H_INCLUDED
|
||||
#define MULTIPLAYER_CONNECT_H_INCLUDED
|
||||
|
||||
#include "commandline_options.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "leader_list.hpp"
|
||||
#include "multiplayer_connect_engine.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "widgets/combo_drag.hpp"
|
||||
#include "widgets/scrollpane.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
#include "widgets/combo_drag.hpp"
|
||||
#include "commandline_options.hpp"
|
||||
|
||||
namespace ai {
|
||||
struct description;
|
||||
|
@ -34,25 +35,10 @@ namespace mp {
|
|||
class connect : public mp::ui
|
||||
{
|
||||
public:
|
||||
struct connected_user {
|
||||
connected_user(const std::string& name, mp::controller controller,
|
||||
network::connection connection) :
|
||||
name(name), controller(controller), connection(connection)
|
||||
{};
|
||||
std::string name;
|
||||
mp::controller controller;
|
||||
network::connection connection;
|
||||
operator std::string() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<connected_user> connected_user_list;
|
||||
|
||||
class side {
|
||||
public:
|
||||
side(connect& parent, const config& cfg, int index);
|
||||
side(connect& parent, side_engine_ptr engine);
|
||||
|
||||
side(const side& a);
|
||||
|
||||
|
@ -63,52 +49,8 @@ public:
|
|||
/** Returns true if this side changed since last call to changed(). */
|
||||
bool changed();
|
||||
|
||||
/**
|
||||
* Gets a config object representing this side.
|
||||
*
|
||||
* If include_leader is set to true, the config objects include the
|
||||
* "type=" defining the leader type, else it does not.
|
||||
*/
|
||||
config get_config() const;
|
||||
|
||||
/**
|
||||
* Returns true if this side is waiting for a network player and
|
||||
* players allowed.
|
||||
*/
|
||||
bool available(const std::string& name = "") const;
|
||||
|
||||
/** Returns true, if the player has chosen his leader and this side is ready for the game to start */
|
||||
bool ready_for_start() const;
|
||||
|
||||
/** Return true if players are allowed to take this side. */
|
||||
bool allow_player() const;
|
||||
|
||||
/** Sets the controller of a side. */
|
||||
void set_controller(mp::controller controller);
|
||||
mp::controller get_controller() const;
|
||||
|
||||
/** Adds an user to the user list combo. */
|
||||
void update_user_list();
|
||||
|
||||
/** Returns the username of this side. */
|
||||
const std::string& get_current_player() const
|
||||
{ return current_player_; }
|
||||
|
||||
int get_index();
|
||||
|
||||
void set_index(int index);
|
||||
|
||||
const std::string& get_player_id() const;
|
||||
|
||||
/** Sets the username of this side. */
|
||||
void set_player_id(const std::string& player_id);
|
||||
|
||||
/** Sets if the joining player has chosen his leader. */
|
||||
void set_ready_for_start(bool ready_for_start);
|
||||
|
||||
int get_team();
|
||||
|
||||
void set_team(int team);
|
||||
void update_user_list(const std::vector<std::string>& name_list);
|
||||
|
||||
/**
|
||||
* Imports data from the network into this side, and updates the UI
|
||||
|
@ -119,12 +61,11 @@ public:
|
|||
/** Resets this side to its default state, and updates the UI accordingly. */
|
||||
void reset(mp::controller controller);
|
||||
|
||||
/** Resolves the random leader / factions. */
|
||||
void resolve_random();
|
||||
void set_faction_commandline(std::string faction_name);
|
||||
void set_controller_commandline(std::string controller_name);
|
||||
void set_ai_algorithm_commandline(std::string algorithm_name);
|
||||
void hide_ai_algorithm_combo(bool invis);
|
||||
|
||||
side_engine_ptr engine() { return engine_; }
|
||||
const side_engine_ptr engine() const { return engine_; }
|
||||
|
||||
private:
|
||||
void init_ai_algorithm_combo();
|
||||
void update_ai_algorithm_combo() {hide_ai_algorithm_combo(parent_->hidden());}
|
||||
|
@ -134,10 +75,6 @@ public:
|
|||
void update_controller_ui();
|
||||
void update_ui();
|
||||
|
||||
int selected_faction_index() const;
|
||||
|
||||
config& init_side_config(config& side);
|
||||
|
||||
/**
|
||||
* The mp::connect widget owning this mp::connect::side.
|
||||
*
|
||||
|
@ -145,34 +82,7 @@ public:
|
|||
*/
|
||||
connect* parent_;
|
||||
|
||||
/**
|
||||
* A non-const config. Be careful not to insert keys when only reading.
|
||||
*
|
||||
* (Use cfg_.get_attribute().)
|
||||
*/
|
||||
config cfg_;
|
||||
|
||||
// All factions which could be played by a side (including Random).
|
||||
std::vector<const config*> available_factions_;
|
||||
// All factions which a side can choose.
|
||||
std::vector<const config*> choosable_factions_;
|
||||
const config* current_faction_;
|
||||
|
||||
// Configurable variables
|
||||
int index_;
|
||||
std::string id_;
|
||||
std::string player_id_;
|
||||
std::string save_id_;
|
||||
std::string current_player_;
|
||||
mp::controller controller_;
|
||||
int team_;
|
||||
int color_;
|
||||
int gold_;
|
||||
int income_;
|
||||
std::string leader_;
|
||||
std::string gender_;
|
||||
std::string ai_algorithm_;
|
||||
bool ready_for_start_;
|
||||
side_engine_ptr engine_;
|
||||
|
||||
// Flags for controlling the dialog widgets of the game lobby
|
||||
bool gold_lock_;
|
||||
|
@ -195,22 +105,14 @@ public:
|
|||
gui::label label_gold_;
|
||||
gui::label label_income_;
|
||||
|
||||
bool allow_player_;
|
||||
bool allow_changes_;
|
||||
bool enabled_;
|
||||
bool changed_;
|
||||
leader_list_manager llm_;
|
||||
};
|
||||
|
||||
friend class side;
|
||||
|
||||
typedef std::vector<side> side_list;
|
||||
|
||||
/**
|
||||
* Pointer to the display
|
||||
*/
|
||||
game_display* disp_;
|
||||
|
||||
connect(game_display& disp, const config& game_config, chat& c,
|
||||
config& gamelist, const mp_game_settings& params,
|
||||
mp::controller default_controller, bool local_players_only = false);
|
||||
|
@ -223,14 +125,15 @@ public:
|
|||
* Returns the game state, which contains all information about the current
|
||||
* scenario.
|
||||
*/
|
||||
const game_state& get_state();
|
||||
const game_state& get_state() const { return engine_.state(); }
|
||||
|
||||
/**
|
||||
* Updates the current game state, resolves random factions, and sends a
|
||||
* "start game" message to the network.
|
||||
*/
|
||||
void start_game();
|
||||
void start_game_commandline(const commandline_options& cmdline_opts);
|
||||
void start_game() { engine_.start_game(); }
|
||||
void start_game_commandline(const commandline_options& cmdline_opts)
|
||||
{ engine_.start_game_commandline(cmdline_opts); }
|
||||
|
||||
protected:
|
||||
virtual void layout_children(const SDL_Rect& rect);
|
||||
|
@ -243,64 +146,20 @@ protected:
|
|||
virtual void hide_children(bool hide=true);
|
||||
|
||||
private:
|
||||
// Those 2 functions are actually the steps of the (complex)
|
||||
// construction of this class.
|
||||
|
||||
/**
|
||||
* Called by the constructor to initialize the game from a
|
||||
* create::parameters structure.
|
||||
*/
|
||||
void load_game();
|
||||
void lists_init();
|
||||
|
||||
/** Convenience function. */
|
||||
config* current_config();
|
||||
|
||||
/** Updates the level_ variable to reflect the sides in the sides_ vector. */
|
||||
void update_level();
|
||||
|
||||
/** Updates the level, and send a diff to the clients. */
|
||||
void update_and_send_diff(bool update_time_of_day = false);
|
||||
|
||||
/** Returns true if there still are sides available for this game. */
|
||||
bool sides_available() const;
|
||||
|
||||
/** Returns true if all sides are ready to start the game. */
|
||||
bool sides_ready() const;
|
||||
|
||||
/**
|
||||
* Validates whether the game can be started.
|
||||
*
|
||||
* returns Can the game be started?
|
||||
*/
|
||||
bool can_start_game() const;
|
||||
|
||||
/**
|
||||
* Updates the state of the player list, the launch button and of the start
|
||||
* game label, to reflect the actual state.
|
||||
*/
|
||||
void update_playerlist_state(bool silent=true);
|
||||
|
||||
/** Returns the index of a player, from its id, or -1 if the player was not found. */
|
||||
connected_user_list::iterator find_player(const std::string& id);
|
||||
|
||||
/** Returns the side which is taken by a given player, or -1 if none was found. */
|
||||
int find_player_side(const std::string& id) const;
|
||||
|
||||
/** Adds a player. */
|
||||
void update_user_combos();
|
||||
|
||||
bool local_only_;
|
||||
|
||||
config level_;
|
||||
|
||||
/** This is the "game state" object which is created by this dialog. */
|
||||
game_state state_;
|
||||
|
||||
mp_game_settings params_;
|
||||
|
||||
/** The list of available sides for the current era. */
|
||||
std::vector<const config *> era_sides_;
|
||||
const mp_game_settings params_;
|
||||
|
||||
// Lists used for combos
|
||||
std::vector<std::string> player_types_;
|
||||
|
@ -308,18 +167,12 @@ private:
|
|||
std::vector<std::string> player_colors_;
|
||||
std::vector<ai::description*> ai_algorithms_;
|
||||
|
||||
// team_name list and "Team" prefix
|
||||
std::vector<std::string> team_names_;
|
||||
std::vector<std::string> user_team_names_;
|
||||
const std::string team_prefix_;
|
||||
|
||||
side_list sides_;
|
||||
connected_user_list users_;
|
||||
|
||||
gui::label waiting_label_;
|
||||
|
||||
controller default_controller_;
|
||||
|
||||
// Widgets
|
||||
gui::scrollpane scroll_pane_;
|
||||
|
||||
|
@ -336,6 +189,7 @@ private:
|
|||
|
||||
gui::drop_group_manager_ptr combo_control_group_;
|
||||
|
||||
connect_engine engine_;
|
||||
}; // end class connect
|
||||
|
||||
} // end namespace mp
|
||||
|
|
971
src/multiplayer_connect_engine.cpp
Normal file
971
src/multiplayer_connect_engine.cpp
Normal file
|
@ -0,0 +1,971 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Andrius Silinskas <silinskas.andrius@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
#include "multiplayer_connect_engine.hpp"
|
||||
|
||||
#include "ai/configuration.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "mp_game_utils.hpp"
|
||||
#include "tod_manager.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
static lg::log_domain log_config("config");
|
||||
#define LOG_CF LOG_STREAM(info, log_config)
|
||||
#define WRN_CF LOG_STREAM(warn, log_config)
|
||||
#define ERR_CF LOG_STREAM(err, log_config)
|
||||
|
||||
static lg::log_domain log_mp_connect_engine("mp/connect/engine");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp_connect_engine)
|
||||
#define LOG_MP LOG_STREAM(info, log_mp_connect_engine)
|
||||
|
||||
namespace {
|
||||
|
||||
const char* controller_names[] = {
|
||||
"network",
|
||||
"human",
|
||||
"ai",
|
||||
"null",
|
||||
"reserved"
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace mp {
|
||||
|
||||
connect_engine::connect_engine(game_display& disp, controller mp_controller,
|
||||
const mp_game_settings& params) :
|
||||
level_(),
|
||||
state_(),
|
||||
disp_(disp),
|
||||
params_(params),
|
||||
side_engines_(),
|
||||
era_factions_(),
|
||||
users_(),
|
||||
mp_controller_(mp_controller),
|
||||
team_names_(),
|
||||
user_team_names_()
|
||||
{
|
||||
level_ = initial_level_config(disp, params, state_);
|
||||
if (level_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const config &era,
|
||||
level_.child("era").child_range("multiplayer_side")) {
|
||||
|
||||
era_factions_.push_back(&era);
|
||||
}
|
||||
|
||||
// Adds the current user as default user.
|
||||
users_.push_back(connected_user(preferences::login(), CNTR_LOCAL, 0));
|
||||
}
|
||||
|
||||
connect_engine::~connect_engine()
|
||||
{
|
||||
}
|
||||
|
||||
config* connect_engine::current_config() {
|
||||
config* cfg_level = NULL;
|
||||
|
||||
// It might make sense to invent a mechanism of some sort to check
|
||||
// whether a config node contains information
|
||||
// that you can load from(side information, specifically).
|
||||
config &snapshot = level_.child("snapshot");
|
||||
if (snapshot && snapshot.child("side")) {
|
||||
// Savegame.
|
||||
cfg_level = &snapshot;
|
||||
} else if (!level_.child("side")) {
|
||||
// Start-of-scenario save,
|
||||
// the info has to be taken from the starting_pos.
|
||||
cfg_level = &state_.replay_start();
|
||||
} else {
|
||||
// Fresh game, no snapshot available.
|
||||
cfg_level = &level_;
|
||||
}
|
||||
|
||||
return cfg_level;
|
||||
}
|
||||
|
||||
void connect_engine::add_side_engine(side_engine_ptr engine)
|
||||
{
|
||||
side_engines_.push_back(engine);
|
||||
}
|
||||
|
||||
void connect_engine::update_level()
|
||||
{
|
||||
DBG_MP << "updating level" << std::endl;
|
||||
|
||||
level_.clear_children("side");
|
||||
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
level_.add_child("side", side->new_config());
|
||||
}
|
||||
}
|
||||
|
||||
void connect_engine::update_and_send_diff(bool update_time_of_day)
|
||||
{
|
||||
config old_level = level_;
|
||||
update_level();
|
||||
|
||||
if (update_time_of_day) {
|
||||
// Set random start ToD.
|
||||
tod_manager tod_mng(level_, level_["turns"]);
|
||||
}
|
||||
|
||||
config diff = level_.get_diff(old_level);
|
||||
if (!diff.empty()) {
|
||||
config scenario_diff;
|
||||
scenario_diff.add_child("scenario_diff", diff);
|
||||
network::send_data(scenario_diff, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool connect_engine::sides_available() const
|
||||
{
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
if (side->available()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool connect_engine::can_start_game() const
|
||||
{
|
||||
// First check if all sides are ready to start the game.
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
if (!side->ready_for_start()) {
|
||||
DBG_MP << "not all sides are ready, side " <<
|
||||
side->new_config().get("side")->str() << " not ready" <<
|
||||
std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DBG_MP << "all sides are ready" << std::endl;
|
||||
|
||||
/*
|
||||
* If at least one human player is slotted with a player/ai we're allowed
|
||||
* to start. Before used a more advanced test but it seems people are
|
||||
* creative in what is used in multiplayer [1] so use a simpler test now.
|
||||
* [1] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=568029
|
||||
*/
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
if (side->mp_controller() != CNTR_EMPTY) {
|
||||
if (side->allow_player()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void connect_engine::start_game()
|
||||
{
|
||||
DBG_MP << "starting a new game" << std::endl;
|
||||
|
||||
// Resolves the "random faction", "random gender" and "random message"
|
||||
// Must be done before shuffle sides, or some cases will cause errors
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
side->resolve_random();
|
||||
}
|
||||
|
||||
// Shuffle sides (check preferences and if it is a re-loaded game).
|
||||
// Must be done after resolve_random() or shuffle sides, or they won't work.
|
||||
if (preferences::shuffle_sides() && !(level_.child("snapshot") &&
|
||||
level_.child("snapshot").child("side"))) {
|
||||
|
||||
// Only playable sides should be shuffled.
|
||||
std::vector<int> playable_sides;
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
if (side->allow_player()) {
|
||||
playable_sides.push_back(side->index());
|
||||
}
|
||||
}
|
||||
|
||||
// Fisher-Yates shuffle.
|
||||
for (int i = playable_sides.size(); i > 1; i--)
|
||||
{
|
||||
int j_side = playable_sides[get_random() % i];
|
||||
int i_side = playable_sides[i - 1];
|
||||
|
||||
int tmp_index = side_engines_[j_side]->index();
|
||||
side_engines_[j_side]->set_index(side_engines_[i_side]->index());
|
||||
side_engines_[i_side]->set_index(tmp_index);
|
||||
|
||||
int tmp_team = side_engines_[j_side]->team();
|
||||
side_engines_[j_side]->set_team(side_engines_[i_side]->team());
|
||||
side_engines_[i_side]->set_team(tmp_team);
|
||||
|
||||
// This is needed otherwise fog bugs will appear.
|
||||
side_engine_ptr tmp_side = side_engines_[j_side];
|
||||
side_engines_[j_side] = side_engines_[i_side];
|
||||
side_engines_[i_side] = tmp_side;
|
||||
}
|
||||
}
|
||||
|
||||
// Make other clients not show the results of resolve_random().
|
||||
config lock("stop_updates");
|
||||
network::send_data(lock, 0);
|
||||
update_and_send_diff(true);
|
||||
|
||||
// Build the gamestate object after updating the level.
|
||||
level_to_gamestate(level_, state_);
|
||||
|
||||
network::send_data(config("start_game"), 0);
|
||||
}
|
||||
|
||||
void connect_engine::start_game_commandline(
|
||||
const commandline_options& cmdline_opts)
|
||||
{
|
||||
DBG_MP << "starting a new game in commandline mode" << std::endl;
|
||||
|
||||
typedef boost::tuple<unsigned int, std::string> mp_option;
|
||||
|
||||
unsigned num = 0;
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
num++;
|
||||
|
||||
// Set the faction, if commandline option is given.
|
||||
if (cmdline_opts.multiplayer_side) {
|
||||
BOOST_FOREACH(const mp_option& option,
|
||||
*cmdline_opts.multiplayer_side) {
|
||||
|
||||
if (option.get<0>() == num) {
|
||||
DBG_MP << "\tsetting side " << option.get<0>() <<
|
||||
"\tfaction: " << option.get<1>() << std::endl;
|
||||
|
||||
side->set_faction_commandline(option.get<1>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the controller, if commandline option is given.
|
||||
if (cmdline_opts.multiplayer_controller) {
|
||||
BOOST_FOREACH(const mp_option& option,
|
||||
*cmdline_opts.multiplayer_controller) {
|
||||
|
||||
if (option.get<0>() == num) {
|
||||
DBG_MP << "\tsetting side " << option.get<0>() <<
|
||||
"\tfaction: " << option.get<1>() << std::endl;
|
||||
|
||||
side->set_controller_commandline(option.get<1>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set AI algorithm to RCA AI for all sides,
|
||||
// then override if commandline option was given.
|
||||
side->set_ai_algorithm_commandline("ai_default_rca");
|
||||
if (cmdline_opts.multiplayer_algorithm) {
|
||||
BOOST_FOREACH(const mp_option& option,
|
||||
*cmdline_opts.multiplayer_algorithm) {
|
||||
|
||||
if (option.get<0>() == num) {
|
||||
DBG_MP << "\tsetting side " << option.get<0>() <<
|
||||
"\tfaction: " << option.get<1>() << std::endl;
|
||||
|
||||
side->set_ai_algorithm_commandline(option.get<1>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, resolve "random faction",
|
||||
// "random gender" and "random message", if any remains unresolved.
|
||||
side->resolve_random();
|
||||
} // end top-level loop
|
||||
|
||||
update_and_send_diff(true);
|
||||
|
||||
// Update sides with commandline parameters.
|
||||
if (cmdline_opts.multiplayer_turns) {
|
||||
DBG_MP << "\tsetting turns: " << cmdline_opts.multiplayer_turns <<
|
||||
std::endl;
|
||||
level_["turns"] = *cmdline_opts.multiplayer_turns;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(config &side, level_.child_range("side"))
|
||||
{
|
||||
if (cmdline_opts.multiplayer_ai_config) {
|
||||
BOOST_FOREACH(const mp_option& option,
|
||||
*cmdline_opts.multiplayer_ai_config) {
|
||||
|
||||
if (option.get<0>() == side["side"].to_unsigned()) {
|
||||
DBG_MP << "\tsetting side " << side["side"] <<
|
||||
"\tai_config: " << option.get<1>() << std::endl;
|
||||
|
||||
side["ai_config"] = option.get<1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Having hard-coded values here is undesirable,
|
||||
// but that's how it is done in the MP lobby
|
||||
// part of the code also. Should be replaced by settings/constants in both places
|
||||
if (cmdline_opts.multiplayer_ignore_map_settings) {
|
||||
side["gold"] = 100;
|
||||
side["income"] = 1;
|
||||
}
|
||||
|
||||
typedef boost::tuple<unsigned int, std::string, std::string>
|
||||
mp_parameter;
|
||||
|
||||
if (cmdline_opts.multiplayer_parm) {
|
||||
BOOST_FOREACH(const mp_parameter& parameter,
|
||||
*cmdline_opts.multiplayer_parm) {
|
||||
|
||||
if (parameter.get<0>() == side["side"].to_unsigned()) {
|
||||
DBG_MP << "\tsetting side " << side["side"] << " " <<
|
||||
parameter.get<1>() << ": " << parameter.get<2>() << std::endl;
|
||||
|
||||
side[parameter.get<1>()] = parameter.get<2>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the gamestate object after updating the level
|
||||
level_to_gamestate(level_, state_);
|
||||
network::send_data(config("start_game"), 0);
|
||||
}
|
||||
|
||||
void connect_engine::process_network_connection(const network::connection sock)
|
||||
{
|
||||
network::send_data(config("join_game"), 0);
|
||||
network::send_data(level_, sock);
|
||||
}
|
||||
|
||||
connected_user_list::iterator connect_engine::find_player(const std::string& id)
|
||||
{
|
||||
connected_user_list::iterator itor;
|
||||
for (itor = users_.begin(); itor != users_.end(); ++itor) {
|
||||
if (itor->name == id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return itor;
|
||||
}
|
||||
|
||||
int connect_engine::find_player_side(const std::string& id) const
|
||||
{
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
if (side->player_id() == id) {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= side_engines_.size()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
side_engine::side_engine(const config& cfg, connect_engine& parent_engine,
|
||||
const int index) :
|
||||
cfg_(cfg),
|
||||
parent_(parent_engine),
|
||||
llm_(NULL, NULL),
|
||||
available_factions_(),
|
||||
choosable_factions_(),
|
||||
current_faction_(),
|
||||
mp_controller_(CNTR_NETWORK),
|
||||
index_(index),
|
||||
team_(0),
|
||||
color_(index),
|
||||
gold_(cfg["gold"].to_int(100)),
|
||||
income_(cfg["income"]),
|
||||
id_(cfg["id"]),
|
||||
player_id_(cfg["player_id"]),
|
||||
save_id_(cfg["save_id"]),
|
||||
current_player_(cfg["current_player"]),
|
||||
leader_(),
|
||||
gender_(),
|
||||
ai_algorithm_(),
|
||||
ready_for_start_(false),
|
||||
allow_player_(cfg["controller"] == "ai" && cfg["allow_player"].empty() ?
|
||||
false : cfg["allow_player"].to_bool(true)),
|
||||
allow_changes_(cfg["allow_changes"].to_bool(true))
|
||||
{
|
||||
// Tweak the controllers.
|
||||
if (cfg["controller"] == "human_ai" ||
|
||||
cfg["controller"] == "network_ai") {
|
||||
|
||||
cfg_["controller"] = "ai";
|
||||
}
|
||||
if (allow_player_ && !parent_.params_.saved_game) {
|
||||
mp_controller_ = parent_.mp_controller_;
|
||||
} else {
|
||||
size_t i = CNTR_NETWORK;
|
||||
if (!allow_player_) {
|
||||
if (cfg["controller"] == "null") {
|
||||
mp_controller_ = CNTR_EMPTY;
|
||||
} else {
|
||||
cfg_["controller"] = controller_names[CNTR_COMPUTER];
|
||||
mp_controller_ = CNTR_COMPUTER;
|
||||
}
|
||||
} else {
|
||||
if (cfg["controller"] == "network" ||
|
||||
cfg["controller"] == "human") {
|
||||
|
||||
cfg_["controller"] = "reserved";
|
||||
}
|
||||
|
||||
for (; i != CNTR_LAST; ++i) {
|
||||
if (cfg["controller"] == controller_names[i]) {
|
||||
mp_controller_ = static_cast<mp::controller>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set faction lock for custom recruit list.
|
||||
if (!cfg["recruit"].empty() && parent_.params_.use_map_settings) {
|
||||
cfg_["faction"] = "Custom";
|
||||
}
|
||||
|
||||
// Initialize faction lists.
|
||||
available_factions_ = init_available_factions(parent_.era_factions(), cfg_);
|
||||
choosable_factions_ = init_choosable_factions(available_factions_, cfg_,
|
||||
parent_.params_.use_map_settings);
|
||||
current_faction_ = choosable_factions_[0];
|
||||
|
||||
// Initialize team and color.
|
||||
std::vector<std::string>::const_iterator itor =
|
||||
std::find(parent_.team_names_.begin(), parent_.team_names_.end(),
|
||||
cfg["team_name"].str());
|
||||
if (itor == parent_.team_names_.end()) {
|
||||
assert(!parent_.team_names_.empty());
|
||||
team_ = 0;
|
||||
} else {
|
||||
team_ = itor - parent_.team_names_.begin();
|
||||
}
|
||||
if (!cfg["color"].empty()) {
|
||||
color_ = game_config::color_info(cfg["color"]).index() - 1;
|
||||
}
|
||||
|
||||
// Initialize ai algorithm.
|
||||
if (const config &ai = cfg.child("ai")) {
|
||||
ai_algorithm_ = ai["ai_algorithm"].str();
|
||||
}
|
||||
}
|
||||
|
||||
side_engine::~side_engine()
|
||||
{
|
||||
}
|
||||
|
||||
config side_engine::new_config() const
|
||||
{
|
||||
config res = cfg_;
|
||||
|
||||
// If the user is allowed to change type, faction, leader etc,
|
||||
// then import their new values in the config.
|
||||
if (!parent_.params_.saved_game && !choosable_factions_.empty()) {
|
||||
// Merge the faction data to res.
|
||||
res.append(*current_faction_);
|
||||
res["faction_name"] = res["name"];
|
||||
}
|
||||
|
||||
if (!cfg_.has_attribute("side") || cfg_["side"].to_int() != index_ + 1) {
|
||||
res["side"] = index_ + 1;
|
||||
}
|
||||
res["controller"] = controller_names[mp_controller_];
|
||||
res["current_player"] = player_id_.empty() ? current_player_ : player_id_;
|
||||
res["id"] = id_;
|
||||
|
||||
if (player_id_.empty()) {
|
||||
std::string description;
|
||||
switch(mp_controller_) {
|
||||
case CNTR_NETWORK:
|
||||
description = N_("(Vacant slot)");
|
||||
|
||||
break;
|
||||
case CNTR_LOCAL:
|
||||
if (!parent_.params_.saved_game && !cfg_.has_attribute("save_id")) {
|
||||
res["save_id"] = preferences::login() + res["side"].str();
|
||||
}
|
||||
res["player_id"] = preferences::login() + res["side"].str();
|
||||
res["current_player"] = preferences::login();
|
||||
description = N_("Anonymous local player");
|
||||
|
||||
break;
|
||||
case CNTR_COMPUTER: {
|
||||
if (!parent_.params_.saved_game && !cfg_.has_attribute("saved_id")) {
|
||||
res["save_id"] = "ai" + res["side"].str();
|
||||
}
|
||||
|
||||
utils::string_map symbols;
|
||||
if (allow_player_) {
|
||||
const config &ai_cfg =
|
||||
ai::configuration::get_ai_config_for(ai_algorithm_);
|
||||
res.add_child("ai", ai_cfg);
|
||||
symbols["playername"] = ai_cfg["description"];
|
||||
} else {
|
||||
// Do not import default ai cfg here -
|
||||
// all is set by scenario config.
|
||||
symbols["playername"] = _("Computer Player");
|
||||
}
|
||||
|
||||
symbols["side"] = res["side"].str();
|
||||
description = vgettext("$playername $side", symbols);
|
||||
|
||||
break;
|
||||
}
|
||||
case CNTR_EMPTY:
|
||||
description = N_("(Empty slot)");
|
||||
res["no_leader"] = true;
|
||||
|
||||
break;
|
||||
case CNTR_RESERVED: {
|
||||
utils::string_map symbols;
|
||||
symbols["playername"] = current_player_;
|
||||
description = vgettext("(Reserved for $playername)",symbols);
|
||||
|
||||
break;
|
||||
}
|
||||
case CNTR_LAST:
|
||||
default:
|
||||
description = N_("(empty)");
|
||||
assert(false);
|
||||
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
res["user_description"] = t_string(description, "wesnoth");
|
||||
} else {
|
||||
res["player_id"] = player_id_ + res["side"];
|
||||
if (!parent_.params_.saved_game && !cfg_.has_attribute("save_id")) {
|
||||
res["save_id"] = player_id_ + res["side"];
|
||||
}
|
||||
|
||||
res["user_description"] = player_id_;
|
||||
}
|
||||
|
||||
res["name"] = res["user_description"];
|
||||
res["allow_changes"] = !parent_.params_.saved_game && allow_changes_;
|
||||
|
||||
if (!parent_.params_.saved_game) {
|
||||
if (leader_.empty()) {
|
||||
res["type"] = llm_.get_leader();
|
||||
} else {
|
||||
res["type"] = leader_;
|
||||
}
|
||||
|
||||
if (gender_.empty()) {
|
||||
std::string dummy = llm_.get_gender();
|
||||
if (!dummy.empty() && dummy != "null" && dummy != "?")
|
||||
res["gender"] = dummy;
|
||||
} else {
|
||||
// If no genders could be resolved, let the unit engine use
|
||||
// the default gender.
|
||||
if (gender_ != "null") {
|
||||
res["gender"] = gender_;
|
||||
}
|
||||
}
|
||||
|
||||
res["team_name"] = parent_.team_names_[team_];
|
||||
res["user_team_name"] = parent_.user_team_names_[team_];
|
||||
res["allow_player"] = allow_player_;
|
||||
res["color"] = color_ + 1;
|
||||
res["gold"] = gold_;
|
||||
res["income"] = income_;
|
||||
|
||||
if (!parent_.params_.use_map_settings || res["fog"].empty() ||
|
||||
(res["fog"] != "yes" && res["fog"] != "no")) {
|
||||
res["fog"] = parent_.params_.fog_game;
|
||||
}
|
||||
|
||||
if (!parent_.params_.use_map_settings || res["shroud"].empty() ||
|
||||
(res["shroud"] != "yes" && res["shroud"] != "no")) {
|
||||
res["shroud"] = parent_.params_.shroud_game;
|
||||
}
|
||||
|
||||
res["share_maps"] = parent_.params_.share_maps;
|
||||
res["share_view"] = parent_.params_.share_view;
|
||||
|
||||
if (!parent_.params_.use_map_settings || res["village_gold"].empty()) {
|
||||
res["village_gold"] = parent_.params_.village_gold;
|
||||
}
|
||||
if (!parent_.params_.use_map_settings ||
|
||||
res["village_support"].empty()) {
|
||||
res["village_support"] =
|
||||
lexical_cast<std::string>(parent_.params_.village_support);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (parent_.params_.use_map_settings && !parent_.params_.saved_game) {
|
||||
config trimmed = cfg_;
|
||||
|
||||
static char const *attrs[] = {"side", "controller", "id",
|
||||
"team_name", "user_team_name", "color", "gold",
|
||||
"income", "allow_changes"};
|
||||
|
||||
BOOST_FOREACH(const char *attr, attrs) {
|
||||
trimmed.remove_attribute(attr);
|
||||
}
|
||||
|
||||
if (mp_controller_ != CNTR_COMPUTER) {
|
||||
// Only override names for computer controlled players.
|
||||
trimmed.remove_attribute("user_description");
|
||||
}
|
||||
|
||||
res.merge_with(trimmed);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void side_engine::import_network_user(const config& data, bool faction_enabled,
|
||||
bool leader_enabled, bool gender_enabled)
|
||||
{
|
||||
if (mp_controller_ == CNTR_RESERVED || parent_.params_.saved_game) {
|
||||
ready_for_start_ = true;
|
||||
}
|
||||
|
||||
player_id_ = data["name"].str();
|
||||
mp_controller_ = CNTR_NETWORK;
|
||||
|
||||
if (!parent_.params_.saved_game && !choosable_factions_.empty()) {
|
||||
if (faction_enabled) {
|
||||
BOOST_FOREACH(const config* faction, choosable_factions_) {
|
||||
if ((*faction)["id"] == data["faction"]) {
|
||||
current_faction_ = faction;
|
||||
}
|
||||
}
|
||||
|
||||
update_llm_lists(selected_faction_index());
|
||||
}
|
||||
if (leader_enabled) {
|
||||
llm_.set_leader(data["leader"]);
|
||||
// FIXME: not optimal, but this hack is necessary to do
|
||||
// after updating the leader selection.
|
||||
// Otherwise, gender gets always forced to "male".
|
||||
llm_.update_gender_list(llm_.get_leader());
|
||||
}
|
||||
if (gender_enabled) {
|
||||
llm_.set_gender(data["gender"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool side_engine::ready_for_start() const
|
||||
{
|
||||
// Sides without players are always ready.
|
||||
if (!allow_player_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The host and the AI are always ready.
|
||||
if ((mp_controller_ == mp::CNTR_COMPUTER) ||
|
||||
(mp_controller_ == mp::CNTR_EMPTY) ||
|
||||
(mp_controller_== mp::CNTR_LOCAL)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return ready_for_start_;
|
||||
}
|
||||
|
||||
bool side_engine::available(const std::string& name) const
|
||||
{
|
||||
if (name.empty()) {
|
||||
return allow_player_ && ((mp_controller_ == CNTR_NETWORK &&
|
||||
player_id_.empty()) || mp_controller_ == CNTR_RESERVED);
|
||||
}
|
||||
|
||||
return allow_player_ &&
|
||||
((mp_controller_ == CNTR_NETWORK && player_id_.empty()) ||
|
||||
(mp_controller_ == CNTR_RESERVED && current_player_ == name));
|
||||
}
|
||||
|
||||
void side_engine::reset(mp::controller controller, bool factions_enabled,
|
||||
bool leaders_enabled, bool genders_enabled)
|
||||
{
|
||||
player_id_.clear();
|
||||
mp_controller_ = controller;
|
||||
|
||||
if ((controller == mp::CNTR_NETWORK) || (controller == mp::CNTR_RESERVED)) {
|
||||
ready_for_start_ = false;
|
||||
}
|
||||
|
||||
if (!parent_.params_.saved_game && !choosable_factions_.empty()) {
|
||||
if (factions_enabled) {
|
||||
current_faction_ = choosable_factions_[0];
|
||||
}
|
||||
if (leaders_enabled) {
|
||||
llm_.update_leader_list(selected_faction_index());
|
||||
}
|
||||
if (genders_enabled) {
|
||||
llm_.update_gender_list(llm_.get_leader());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void side_engine::resolve_random()
|
||||
{
|
||||
if (parent_.params_.saved_game || choosable_factions_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*current_faction_)["random_faction"].to_bool()) {
|
||||
std::vector<std::string> faction_choices, faction_excepts;
|
||||
|
||||
faction_choices = utils::split((*current_faction_)["choices"]);
|
||||
if (faction_choices.size() == 1 && faction_choices.front() == "") {
|
||||
faction_choices.clear();
|
||||
}
|
||||
|
||||
faction_excepts = utils::split((*current_faction_)["except"]);
|
||||
if (faction_excepts.size() == 1 && faction_excepts.front() == "") {
|
||||
faction_excepts.clear();
|
||||
}
|
||||
|
||||
// Builds the list of sides eligible for choice (nonrandom factions).
|
||||
std::vector<int> nonrandom_sides;
|
||||
int num = -1;
|
||||
BOOST_FOREACH(const config* i, available_factions_) {
|
||||
++num;
|
||||
if (!(*i)["random_faction"].to_bool()) {
|
||||
const std::string& faction_id = (*i)["id"];
|
||||
|
||||
if (!faction_choices.empty() &&
|
||||
std::find(faction_choices.begin(), faction_choices.end(),
|
||||
faction_id) == faction_choices.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!faction_excepts.empty() &&
|
||||
std::find(faction_excepts.begin(), faction_excepts.end(),
|
||||
faction_id) != faction_excepts.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nonrandom_sides.push_back(num);
|
||||
}
|
||||
}
|
||||
|
||||
if (nonrandom_sides.empty()) {
|
||||
throw config::error(_("Only random sides in the current era."));
|
||||
}
|
||||
|
||||
const int faction_index =
|
||||
nonrandom_sides[rand() % nonrandom_sides.size()];
|
||||
current_faction_ = available_factions_[faction_index];
|
||||
}
|
||||
|
||||
LOG_MP << "FACTION" << (index_ + 1) << ": " << (*current_faction_)["name"]
|
||||
<< std::endl;
|
||||
|
||||
bool solved_random_leader = false;
|
||||
|
||||
if (llm_.get_leader() == "random") {
|
||||
// Choose a random leader type, and force gender to be random.
|
||||
llm_.set_gender("random");
|
||||
std::vector<std::string> types =
|
||||
utils::split((*current_faction_)["random_leader"]);
|
||||
if (!types.empty()) {
|
||||
const int lchoice = rand() % types.size();
|
||||
leader_ = types[lchoice];
|
||||
} else {
|
||||
// If 'random_leader' doesn't exist, we use 'leader'.
|
||||
types = utils::split((*current_faction_)["leader"]);
|
||||
if (!types.empty()) {
|
||||
const int lchoice = rand() % types.size();
|
||||
leader_ = types[lchoice];
|
||||
} else {
|
||||
utils::string_map i18n_symbols;
|
||||
i18n_symbols["faction"] = (*current_faction_)["name"];
|
||||
throw config::error(vgettext(
|
||||
"Unable to find a leader type for faction $faction",
|
||||
i18n_symbols));
|
||||
}
|
||||
}
|
||||
solved_random_leader = true;
|
||||
}
|
||||
|
||||
// Resolve random genders "very much" like standard unit code.
|
||||
if (llm_.get_gender() == "random" || solved_random_leader) {
|
||||
const unit_type *ut =
|
||||
unit_types.find(leader_.empty() ? llm_.get_leader() : leader_);
|
||||
|
||||
if (ut) {
|
||||
const std::vector<unit_race::GENDER> glist = ut->genders();
|
||||
const int gchoice = rand() % glist.size();
|
||||
|
||||
// Pick up a gender, using the random 'gchoice' index.
|
||||
unit_race::GENDER sgender = glist[gchoice];
|
||||
switch (sgender) {
|
||||
case unit_race::FEMALE:
|
||||
gender_ = unit_race::s_female;
|
||||
break;
|
||||
case unit_race::MALE:
|
||||
gender_ = unit_race::s_male;
|
||||
break;
|
||||
default:
|
||||
gender_ = "null";
|
||||
}
|
||||
} else {
|
||||
ERR_CF << "cannot obtain genders for invalid leader '" <<
|
||||
(leader_.empty() ? llm_.get_leader() : leader_) << "'.\n";
|
||||
gender_ = "null";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int side_engine::selected_faction_index() const
|
||||
{
|
||||
int index = 0;
|
||||
BOOST_FOREACH(const config* faction, choosable_factions_) {
|
||||
if ((*faction)["id"] == (*current_faction_)["id"]) {
|
||||
return index;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void side_engine::set_player_from_users_list(const std::string& player_id)
|
||||
{
|
||||
connected_user_list::iterator i = parent_.find_player(player_id);
|
||||
if (i != parent_.users_.end()) {
|
||||
player_id_ = player_id;
|
||||
mp_controller_ = i->controller;
|
||||
}
|
||||
}
|
||||
|
||||
void side_engine::set_faction_commandline(const std::string& faction_name)
|
||||
{
|
||||
BOOST_FOREACH(const config* faction, choosable_factions_) {
|
||||
if ((*faction)["name"] == faction_name) {
|
||||
current_faction_ = faction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void side_engine::set_controller_commandline(const std::string& controller_name)
|
||||
{
|
||||
mp_controller_ = CNTR_LOCAL;
|
||||
|
||||
if (controller_name == "ai") {
|
||||
mp_controller_ = CNTR_COMPUTER;
|
||||
}
|
||||
if (controller_name == "null") {
|
||||
mp_controller_ = CNTR_EMPTY;
|
||||
}
|
||||
|
||||
player_id_ = "";
|
||||
}
|
||||
|
||||
void side_engine::set_ai_algorithm_commandline(
|
||||
const std::string& algorithm_name)
|
||||
{
|
||||
ai_algorithm_ = algorithm_name;
|
||||
}
|
||||
|
||||
void side_engine::assign_sides_on_drop_target(const int drop_target) {
|
||||
const std::string target_id = parent_.side_engines_[drop_target]->player_id_;
|
||||
const mp::controller target_controller =
|
||||
parent_.side_engines_[drop_target]->mp_controller_;
|
||||
const std::string target_ai =
|
||||
parent_.side_engines_[drop_target]->ai_algorithm_;
|
||||
|
||||
parent_.side_engines_[drop_target]->ai_algorithm_ = ai_algorithm_;
|
||||
if (player_id_.empty()) {
|
||||
parent_.side_engines_[drop_target]->mp_controller_ = mp_controller_;
|
||||
} else {
|
||||
parent_.side_engines_[drop_target]->
|
||||
set_player_from_users_list(player_id_);
|
||||
}
|
||||
|
||||
ai_algorithm_ = target_ai;
|
||||
if (target_id.empty())
|
||||
{
|
||||
mp_controller_ = target_controller;
|
||||
player_id_ = "";
|
||||
} else {
|
||||
set_player_from_users_list(target_id);
|
||||
}
|
||||
}
|
||||
|
||||
void side_engine::update_llm()
|
||||
{
|
||||
llm_.set_side_list(choosable_factions_);
|
||||
llm_.set_color(color_);
|
||||
}
|
||||
|
||||
void side_engine::invalidate_llm_combos()
|
||||
{
|
||||
llm_.set_leader_combo(NULL);
|
||||
llm_.set_gender_combo(NULL);
|
||||
}
|
||||
|
||||
void side_engine::init_llm_combos(gui::combo* combo_leader,
|
||||
gui::combo* combo_gender)
|
||||
{
|
||||
llm_.init_combos(combo_leader, combo_gender);
|
||||
}
|
||||
|
||||
void side_engine::set_llm_combos(gui::combo* combo_leader,
|
||||
gui::combo* combo_gender)
|
||||
{
|
||||
llm_.set_leader_combo(combo_leader);
|
||||
|
||||
if (combo_gender != NULL) {
|
||||
llm_.set_gender_combo(combo_gender);
|
||||
}
|
||||
}
|
||||
|
||||
void side_engine::update_llm_lists(const int faction_index)
|
||||
{
|
||||
update_llm_leader_list(faction_index);
|
||||
update_llm_gender_list();
|
||||
}
|
||||
|
||||
void side_engine::update_llm_leader_list(const int faction_index)
|
||||
{
|
||||
llm_.update_leader_list(faction_index);
|
||||
}
|
||||
|
||||
void side_engine::update_llm_gender_list()
|
||||
{
|
||||
llm_.update_gender_list(llm_.get_leader());
|
||||
}
|
||||
|
||||
void side_engine::update_llm_leader_selection(const std::string& leader)
|
||||
{
|
||||
llm_.set_leader(leader);
|
||||
}
|
||||
|
||||
void side_engine::update_llm_gender_selection(const std::string& gender)
|
||||
{
|
||||
llm_.set_gender(gender);
|
||||
}
|
||||
|
||||
} // end namespace mp
|
235
src/multiplayer_connect_engine.hpp
Normal file
235
src/multiplayer_connect_engine.hpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Andrius Silinskas <silinskas.andrius@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
#ifndef MULTIPLAYER_CONNECT_ENGINE_HPP_INCLUDED
|
||||
#define MULTIPLAYER_CONNECT_ENGINE_HPP_INCLUDED
|
||||
|
||||
#include "commandline_options.hpp"
|
||||
#include "config.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "leader_list.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
|
||||
namespace mp {
|
||||
|
||||
class side_engine;
|
||||
|
||||
struct connected_user
|
||||
{
|
||||
connected_user(const std::string& name, mp::controller controller,
|
||||
network::connection connection) :
|
||||
name(name),
|
||||
controller(controller),
|
||||
connection(connection)
|
||||
{};
|
||||
std::string name;
|
||||
mp::controller controller;
|
||||
network::connection connection;
|
||||
operator std::string() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<side_engine> side_engine_ptr;
|
||||
typedef std::vector<connected_user> connected_user_list;
|
||||
|
||||
class connect_engine
|
||||
{
|
||||
public:
|
||||
connect_engine(game_display& disp, controller mp_controller,
|
||||
const mp_game_settings& params);
|
||||
~connect_engine();
|
||||
|
||||
config* current_config();
|
||||
|
||||
void add_side_engine(side_engine_ptr engine);
|
||||
|
||||
// Import all sides into the level.
|
||||
void update_level();
|
||||
// Updates the level and sends a diff to the clients.
|
||||
void update_and_send_diff(bool update_time_of_day = false);
|
||||
|
||||
// Returns true if there are still sides available for this game.
|
||||
bool sides_available() const;
|
||||
|
||||
bool can_start_game() const;
|
||||
void start_game();
|
||||
void start_game_commandline(const commandline_options& cmdline_opts);
|
||||
|
||||
// Network methods.
|
||||
void process_network_connection(const network::connection sock);
|
||||
|
||||
// Returns the index of a player, from its id,
|
||||
// or -1 if the player was not found.
|
||||
connected_user_list::iterator find_player(const std::string& id);
|
||||
|
||||
// Returns the side which is taken by a given player,
|
||||
// or -1 if none was found.
|
||||
int find_player_side(const std::string& id) const;
|
||||
|
||||
|
||||
/* Setters & Getters */
|
||||
|
||||
const config& level() const { return level_; }
|
||||
const game_state& state() const { return state_; }
|
||||
|
||||
const std::vector<const config *>& era_factions() const
|
||||
{ return era_factions_; }
|
||||
|
||||
private:
|
||||
connect_engine(const connect_engine&);
|
||||
void operator=(const connect_engine&);
|
||||
|
||||
friend side_engine;
|
||||
|
||||
config level_;
|
||||
game_state state_;
|
||||
|
||||
game_display& disp_;
|
||||
const mp_game_settings& params_;
|
||||
|
||||
std::vector<side_engine_ptr> side_engines_;
|
||||
std::vector<const config *> era_factions_;
|
||||
|
||||
public:
|
||||
connected_user_list users_;
|
||||
controller mp_controller_;
|
||||
|
||||
std::vector<std::string> team_names_;
|
||||
std::vector<std::string> user_team_names_;
|
||||
};
|
||||
|
||||
class side_engine
|
||||
{
|
||||
public:
|
||||
side_engine(const config& cfg, connect_engine& parent_engine,
|
||||
const int index);
|
||||
~side_engine();
|
||||
|
||||
// Sets a new config representing this side.
|
||||
config new_config() const;
|
||||
|
||||
void import_network_user(const config& data, bool faction_enabled,
|
||||
bool leader_enabled, bool gender_enabled);
|
||||
|
||||
// Returns true, if the player has chosen his/her leader and this side
|
||||
// is ready for the game to start.
|
||||
bool ready_for_start() const;
|
||||
|
||||
// Returns true if this side is waiting for a network player and
|
||||
// players are allowed.
|
||||
bool available(const std::string& name = "") const;
|
||||
|
||||
void set_player_from_users_list(const std::string& player_id);
|
||||
|
||||
void reset(mp::controller controller, bool factions_enabled,
|
||||
bool leaders_enabled, bool genders_enabled);
|
||||
void resolve_random();
|
||||
|
||||
int selected_faction_index() const;
|
||||
|
||||
void set_faction_commandline(const std::string& faction_name);
|
||||
void set_controller_commandline(const std::string& controller_name);
|
||||
void set_ai_algorithm_commandline(const std::string& algorithm_name);
|
||||
|
||||
void assign_sides_on_drop_target(const int drop_target);
|
||||
|
||||
// LLM management.
|
||||
void update_llm();
|
||||
void invalidate_llm_combos();
|
||||
void init_llm_combos(gui::combo* combo_leader, gui::combo* combo_gender);
|
||||
void set_llm_combos(gui::combo* combo_leader, gui::combo* combo_gender);
|
||||
void update_llm_lists(const int faction_index);
|
||||
void update_llm_leader_list(const int faction_index);
|
||||
void update_llm_gender_list();
|
||||
void update_llm_leader_selection(const std::string& leader);
|
||||
void update_llm_gender_selection(const std::string& gender);
|
||||
|
||||
|
||||
/* Setters & Getters */
|
||||
|
||||
const std::vector<const config*>& choosable_factions()
|
||||
{ return choosable_factions_; }
|
||||
const config& cfg() const { return cfg_; }
|
||||
const config* current_faction() const { return current_faction_; }
|
||||
void set_current_faction(const config* current_faction)
|
||||
{ current_faction_ = current_faction; }
|
||||
controller mp_controller() const { return mp_controller_; }
|
||||
void set_mp_controller(controller mp_controller)
|
||||
{ mp_controller_ = mp_controller; }
|
||||
int index() const { return index_; }
|
||||
void set_index(int index) { index_ = index; }
|
||||
int team() const { return team_; }
|
||||
void set_team(int team) { team_ = team; }
|
||||
int color() const { return color_; }
|
||||
void set_color(int color) { color_ = color; }
|
||||
int gold() const { return gold_; }
|
||||
void set_gold(int gold) { gold_ = gold; }
|
||||
int income() const { return income_; }
|
||||
void set_income(int income) { income_ = income; }
|
||||
const std::string& player_id() const { return player_id_; }
|
||||
void set_player_id(const std::string& player_id) { player_id_ = player_id; }
|
||||
const std::string& save_id() const { return save_id_; }
|
||||
const std::string& current_player() const { return current_player_; }
|
||||
const std::string& leader() const { return leader_; }
|
||||
void set_leader(const std::string& leader) { leader_ = leader; }
|
||||
const std::string& gender() const { return gender_; }
|
||||
void set_gender(const std::string& gender) { gender_ = gender; }
|
||||
const std::string& ai_algorithm() const { return ai_algorithm_; }
|
||||
void set_ai_algorithm(const std::string& ai_algorithm)
|
||||
{ai_algorithm_ = ai_algorithm; }
|
||||
void set_ready_for_start(const bool ready_for_start)
|
||||
{ ready_for_start_ = ready_for_start; }
|
||||
bool allow_player() const { return allow_player_; }
|
||||
|
||||
private:
|
||||
side_engine(const side_engine& engine);
|
||||
void operator=(const connect_engine&);
|
||||
|
||||
config cfg_;
|
||||
|
||||
connect_engine& parent_;
|
||||
|
||||
leader_list_manager llm_;
|
||||
|
||||
// All factions which could be played by a side (including Random).
|
||||
std::vector<const config*> available_factions_;
|
||||
// All factions which a side can choose.
|
||||
std::vector<const config*> choosable_factions_;
|
||||
|
||||
const config* current_faction_;
|
||||
controller mp_controller_;
|
||||
|
||||
// Configurable variables.
|
||||
int index_;
|
||||
int team_;
|
||||
int color_;
|
||||
int gold_;
|
||||
int income_;
|
||||
std::string id_;
|
||||
std::string player_id_;
|
||||
std::string save_id_;
|
||||
std::string current_player_;
|
||||
std::string leader_;
|
||||
std::string gender_;
|
||||
std::string ai_algorithm_;
|
||||
|
||||
bool ready_for_start_;
|
||||
bool allow_player_;
|
||||
bool allow_changes_;
|
||||
};
|
||||
|
||||
} // end namespace mp
|
||||
|
||||
#endif
|
|
@ -358,6 +358,7 @@ void create_engine::prepare_for_new_level()
|
|||
|
||||
parameters_.scenario_data = current_level().data();
|
||||
parameters_.hash = parameters_.scenario_data.hash();
|
||||
parameters_.mp_scenario = parameters_.scenario_data["id"].str();
|
||||
}
|
||||
|
||||
void create_engine::prepare_for_campaign(const std::string& difficulty)
|
||||
|
|
|
@ -876,7 +876,7 @@ int find_suitable_faction(faction_list const &fl, const config &cfg)
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<const config*> available_factions(
|
||||
std::vector<const config*> init_available_factions(
|
||||
std::vector<const config*> era_sides, const config& side)
|
||||
{
|
||||
std::vector<const config*> available_factions;
|
||||
|
@ -892,7 +892,7 @@ std::vector<const config*> available_factions(
|
|||
return available_factions;
|
||||
}
|
||||
|
||||
std::vector<const config*> choosable_factions(
|
||||
std::vector<const config*> init_choosable_factions(
|
||||
std::vector<const config*> available_factions, const config& side,
|
||||
const bool map_settings)
|
||||
{
|
||||
|
|
|
@ -274,10 +274,10 @@ typedef std::vector<const config *> faction_list;
|
|||
/** Picks the first faction with the greater amount of data matching the criteria. */
|
||||
int find_suitable_faction(faction_list const &fl, const config &side);
|
||||
|
||||
std::vector<const config*> available_factions(
|
||||
std::vector<const config*> init_available_factions(
|
||||
std::vector<const config*> era_sides, const config& side);
|
||||
|
||||
std::vector<const config*> choosable_factions(
|
||||
std::vector<const config*> init_choosable_factions(
|
||||
std::vector<const config*> available_factions, const config& side,
|
||||
const bool map_settings);
|
||||
}
|
||||
|
|
|
@ -282,8 +282,8 @@ void wait::join_game(bool observe)
|
|||
const bool use_map_settings =
|
||||
level_.child("multiplayer")["mp_use_map_settings"].to_bool();
|
||||
|
||||
leader_sides = choosable_factions(
|
||||
available_factions(leader_sides, *side_choice),
|
||||
leader_sides = init_choosable_factions(
|
||||
init_available_factions(leader_sides, *side_choice),
|
||||
*side_choice, use_map_settings);
|
||||
|
||||
std::vector<std::string> choices;
|
||||
|
|
Loading…
Add table
Reference in a new issue