Tell other clients about controller type changes from :droid
If one client changes the controller type of a side it controls from human -> AI or vice versa, the other clients need to know about it in case there's WML/lua that uses the controller type to determine what to do. This also means that droiding a side you own can now only be done when it's your turn. Fixes #4996
This commit is contained in:
parent
77c60a11f4
commit
204357c6d2
6 changed files with 94 additions and 26 deletions
|
@ -214,11 +214,20 @@ void game_board::side_drop_to(int side_num, team::CONTROLLER ctrl, team::PROXY_C
|
|||
if (leader.valid()) leader->rename(ctrl.to_string() + std::to_string(side_num));
|
||||
}
|
||||
|
||||
void game_board::side_change_controller(int side_num, bool is_local, const std::string& pname) {
|
||||
void game_board::side_change_controller(int side_num, bool is_local, const std::string& pname, const std::string& controller_type) {
|
||||
team &tm = get_team(side_num);
|
||||
|
||||
tm.set_local(is_local);
|
||||
|
||||
// only changing the type of controller
|
||||
if(controller_type == team::CONTROLLER::enum_to_string(team::CONTROLLER::AI) && !tm.is_ai()) {
|
||||
tm.make_ai();
|
||||
return;
|
||||
} else if(controller_type == team::CONTROLLER::enum_to_string(team::CONTROLLER::HUMAN) && !tm.is_human()) {
|
||||
tm.make_human();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pname.empty() || !tm.is_human()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public:
|
|||
// Manipulator from playturn
|
||||
|
||||
void side_drop_to (int side_num, team::CONTROLLER ctrl, team::PROXY_CONTROLLER proxy = team::PROXY_CONTROLLER::PROXY_HUMAN);
|
||||
void side_change_controller (int side_num, bool is_local, const std::string& pname = "");
|
||||
void side_change_controller (int side_num, bool is_local, const std::string& pname, const std::string& controller_type);
|
||||
|
||||
// Manipulator from actionwml
|
||||
|
||||
|
|
|
@ -1485,6 +1485,7 @@ void console_handler::do_droid()
|
|||
std::transform(action.begin(), action.end(), action.begin(), tolower);
|
||||
// default to the current side if empty
|
||||
const unsigned int side = side_s.empty() ? team_num_ : lexical_cast_default<unsigned int>(side_s);
|
||||
const bool is_your_turn = resources::controller->current_side() == static_cast<int>(display::get_singleton()->viewing_side());
|
||||
|
||||
utils::string_map symbols;
|
||||
symbols["side"] = std::to_string(side);
|
||||
|
@ -1498,43 +1499,81 @@ void console_handler::do_droid()
|
|||
} else if(menu_handler_.board().get_team(side).is_local()) {
|
||||
bool changed = false;
|
||||
|
||||
const bool is_human = menu_handler_.board().get_team(side).is_human();
|
||||
const bool is_droid = menu_handler_.board().get_team(side).is_droid();
|
||||
const bool is_proxy_human = menu_handler_.board().get_team(side).is_proxy_human();
|
||||
const bool is_ai = menu_handler_.board().get_team(side).is_ai();
|
||||
const std::string human = team::CONTROLLER::enum_to_string(team::CONTROLLER::HUMAN);
|
||||
const std::string ai = team::CONTROLLER::enum_to_string(team::CONTROLLER::AI);
|
||||
|
||||
if(action == "on") {
|
||||
if(!menu_handler_.board().get_team(side).is_human() || !menu_handler_.board().get_team(side).is_droid()) {
|
||||
if(is_ai && !is_your_turn) {
|
||||
command_failed(_("It is not allowed to change a side from AI to human control when it's not your turn."));
|
||||
return;
|
||||
}
|
||||
if(!is_human || !is_droid) {
|
||||
menu_handler_.board().get_team(side).make_human();
|
||||
menu_handler_.board().get_team(side).make_droid();
|
||||
changed = true;
|
||||
if(is_ai) {
|
||||
menu_handler_.pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", preferences::login(), "to", human}});
|
||||
}
|
||||
print(get_cmd(), VGETTEXT("Side '$side' controller is now controlled by: AI.", symbols));
|
||||
} else {
|
||||
print(get_cmd(), VGETTEXT("Side '$side' is already droided.", symbols));
|
||||
}
|
||||
} else if(action == "off") {
|
||||
if(!menu_handler_.board().get_team(side).is_human() || !menu_handler_.board().get_team(side).is_proxy_human()) {
|
||||
if(is_ai && !is_your_turn) {
|
||||
command_failed(_("It is not allowed to change a side from AI to human control when it's not your turn."));
|
||||
return;
|
||||
}
|
||||
if(!is_human || !is_proxy_human) {
|
||||
menu_handler_.board().get_team(side).make_human();
|
||||
menu_handler_.board().get_team(side).make_proxy_human();
|
||||
changed = true;
|
||||
if(is_ai) {
|
||||
menu_handler_.pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", preferences::login(), "to", human}});
|
||||
}
|
||||
print(get_cmd(), VGETTEXT("Side '$side' controller is now controlled by: human.", symbols));
|
||||
} else {
|
||||
print(get_cmd(), VGETTEXT("Side '$side' is already not droided.", symbols));
|
||||
}
|
||||
} else if(action == "full") {
|
||||
if(!menu_handler_.board().get_team(side).is_ai() || !menu_handler_.board().get_team(side).is_droid()) {
|
||||
if(!is_your_turn) {
|
||||
command_failed(_("It is not allowed to change a side from human to AI control when it's not your turn."));
|
||||
return;
|
||||
}
|
||||
if(!is_ai || !is_droid) {
|
||||
menu_handler_.board().get_team(side).make_ai();
|
||||
menu_handler_.board().get_team(side).make_droid();
|
||||
changed = true;
|
||||
if(is_human || is_proxy_human) {
|
||||
menu_handler_.pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", preferences::login(), "to", ai}});
|
||||
}
|
||||
print(get_cmd(), VGETTEXT("Side '$side' controller is now fully controlled by: AI.", symbols));
|
||||
} else {
|
||||
print(get_cmd(), VGETTEXT("Side '$side' is already fully AI controlled.", symbols));
|
||||
}
|
||||
} else if(action == "") {
|
||||
if(menu_handler_.board().get_team(side).is_ai() || menu_handler_.board().get_team(side).is_droid()) {
|
||||
if(is_ai && !is_your_turn) {
|
||||
command_failed(_("It is not allowed to change a side from AI to human control when it's not your turn."));
|
||||
return;
|
||||
}
|
||||
if(is_ai || is_droid) {
|
||||
menu_handler_.board().get_team(side).make_human();
|
||||
menu_handler_.board().get_team(side).make_proxy_human();
|
||||
changed = true;
|
||||
if(is_ai) {
|
||||
menu_handler_.pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", preferences::login(), "to", human}});
|
||||
}
|
||||
print(get_cmd(), VGETTEXT("Side '$side' controller is now controlled by: human.", symbols));
|
||||
} else {
|
||||
menu_handler_.board().get_team(side).make_human();
|
||||
menu_handler_.board().get_team(side).make_droid();
|
||||
changed = true;
|
||||
if(is_ai) {
|
||||
menu_handler_.pc_.send_to_wesnothd(config {"change_controller", config {"side", side, "player", preferences::login(), "to", human}});
|
||||
}
|
||||
print(get_cmd(), VGETTEXT("Side '$side' controller is now controlled by: AI.", symbols));
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -178,6 +178,7 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
const int side = change["side"].to_int();
|
||||
const bool is_local = change["is_local"].to_bool();
|
||||
const std::string player = change["player"];
|
||||
const std::string controller_type = change["controller"];
|
||||
const std::size_t index = side - 1;
|
||||
if(index >= resources::gameboard->teams().size()) {
|
||||
ERR_NW << "Bad [change_controller] signal from server, side out of bounds: " << change.debug() << std::endl;
|
||||
|
@ -187,7 +188,7 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
const team & tm = resources::gameboard->teams().at(index);
|
||||
const bool was_local = tm.is_local();
|
||||
|
||||
resources::gameboard->side_change_controller(side, is_local, player);
|
||||
resources::gameboard->side_change_controller(side, is_local, player, controller_type);
|
||||
|
||||
if (!was_local && tm.is_local()) {
|
||||
resources::controller->on_not_observer();
|
||||
|
|
|
@ -545,6 +545,7 @@ void game::transfer_side_control(const socket_ptr& sock, const simple_wml::node&
|
|||
const simple_wml::string_span& newplayer_name = cfg["player"];
|
||||
const socket_ptr old_player = sides_[side_num - 1];
|
||||
const auto oldplayer = player_connections_.find(old_player);
|
||||
const std::string& controller_type = cfg["to"].to_string();
|
||||
if(oldplayer == player_connections_.end()) {
|
||||
missing_user(old_player, __func__);
|
||||
}
|
||||
|
@ -579,10 +580,18 @@ void game::transfer_side_control(const socket_ptr& sock, const simple_wml::node&
|
|||
}
|
||||
|
||||
if(newplayer == old_player) {
|
||||
std::stringstream msg;
|
||||
msg << "Side " << side_num << " is already controlled by " << newplayer_name << ".";
|
||||
send_server_message(msg.str(), sock);
|
||||
return;
|
||||
// if the player is unchanged and the controller type (human or ai) is also unchanged then nothing to do
|
||||
// else only need to change the controller type rather than the player who controls the side
|
||||
if(CONTROLLER::string_to_enum(controller_type) == side_controllers_[side_num - 1]) {
|
||||
std::stringstream msg;
|
||||
msg << "Side " << side_num << " is already controlled by " << newplayer_name << ".";
|
||||
send_server_message(msg.str(), sock);
|
||||
return;
|
||||
} else {
|
||||
side_controllers_[side_num - 1] = CONTROLLER::string_to_enum(controller_type);
|
||||
change_controller_type(side_num - 1, newplayer, player_connections_.find(newplayer)->info().name());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sides_[side_num - 1].reset();
|
||||
|
@ -631,32 +640,39 @@ void game::change_controller(
|
|||
}
|
||||
}
|
||||
|
||||
simple_wml::document response;
|
||||
simple_wml::node& change = response.root().add_child("change_controller");
|
||||
auto response = change_controller_type(side_index, sock, player_name);
|
||||
|
||||
change.set_attr_dup("side", side.c_str());
|
||||
change.set_attr_dup("player", player_name.c_str());
|
||||
|
||||
// Tell everyone but the new player that this side's controller changed.
|
||||
change.set_attr_dup("controller", side_controllers_[side_index].to_cstring());
|
||||
change.set_attr("is_local", "no");
|
||||
|
||||
send_data(response, sock);
|
||||
|
||||
if(started_) { // this is added instead of the if (started_) {...} below
|
||||
if(started_) {
|
||||
// the purpose of these records is so that observers, replay viewers, get controller updates correctly
|
||||
record_data(response.clone());
|
||||
record_data(response->clone());
|
||||
}
|
||||
|
||||
// Tell the new player that he controls this side now.
|
||||
// Just don't send it when the player left the game. (The host gets the
|
||||
// side_drop already.)
|
||||
if(!player_left) {
|
||||
change.set_attr("is_local", "yes");
|
||||
async_send_doc_queued(sock, response);
|
||||
response->root().child("change_controller")->set_attr("is_local", "yes");
|
||||
async_send_doc_queued(sock, *response.get());
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<simple_wml::document> game::change_controller_type(const std::size_t side_index, const socket_ptr& sock, const std::string& player_name)
|
||||
{
|
||||
const std::string& side = std::to_string(side_index + 1);
|
||||
simple_wml::document response;
|
||||
simple_wml::node& change = response.root().add_child("change_controller");
|
||||
|
||||
change.set_attr_dup("side", side.c_str());
|
||||
change.set_attr_dup("player", player_name.c_str());
|
||||
|
||||
// Tell everyone but the source player that this side's controller changed.
|
||||
change.set_attr_dup("controller", side_controllers_[side_index].to_cstring());
|
||||
change.set_attr("is_local", "no");
|
||||
|
||||
send_data(response, sock);
|
||||
return std::unique_ptr<simple_wml::document>(response.clone());
|
||||
}
|
||||
|
||||
void game::notify_new_host()
|
||||
{
|
||||
const std::string owner_name = username(owner_);
|
||||
|
|
|
@ -387,6 +387,9 @@ private:
|
|||
const socket_ptr& sock,
|
||||
const std::string& player_name,
|
||||
const bool player_left = true);
|
||||
std::unique_ptr<simple_wml::document> change_controller_type(const std::size_t side_num,
|
||||
const socket_ptr& sock,
|
||||
const std::string& player_name);
|
||||
void transfer_ai_sides(const socket_ptr& player);
|
||||
void send_leave_game(const socket_ptr& user) const;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue