Skip to content

Commit

Permalink
allow specifying the next player number in end_turn
Browse files Browse the repository at this point in the history
fixes #1392
  • Loading branch information
gfgtdf committed Feb 26, 2018
1 parent afb8ca9 commit 2e235f7
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 55 deletions.
3 changes: 3 additions & 0 deletions src/game_state.cpp
Expand Up @@ -55,6 +55,7 @@ game_state::game_state(const config & level, play_controller & pc, const ter_dat
// so we might want to move the innitialisation of undo_stack_ to game_state::init
undo_stack_(new actions::undo_list(level.child("undo_stack"))),
player_number_(level["playing_team"].to_int() + 1),
next_player_number_(level["next_player_number"].to_int(player_number_ + 1)),
init_side_done_(level["init_side_done"].to_bool(false)),
start_event_fired_(!level["playing_team"].empty()),
server_request_number_(level["server_request_number"].to_int()),
Expand All @@ -79,6 +80,7 @@ game_state::game_state(const config & level, play_controller & pc, game_board& b
ai_manager_(),
events_manager_(new game_events::manager()),
player_number_(level["playing_team"].to_int() + 1),
next_player_number_(level["next_player_number"].to_int(player_number_ + 1)),
end_level_data_(),
init_side_done_(level["init_side_done"].to_bool(false)),
start_event_fired_(!level["playing_team"].empty()),
Expand Down Expand Up @@ -237,6 +239,7 @@ void game_state::write(config& cfg) const
cfg["init_side_done"] = init_side_done_;
if(gamedata_.phase() == game_data::PLAY) {
cfg["playing_team"] = player_number_ - 1;
cfg["next_player_number"] = next_player_number_;
}
cfg["server_request_number"] = server_request_number_;
//Call the lua save_game functions
Expand Down
1 change: 1 addition & 0 deletions src/game_state.hpp
Expand Up @@ -55,6 +55,7 @@ class game_state : public filter_context
/// number of files that depend on actions/undo.hpp).
const std::unique_ptr<actions::undo_list> undo_stack_;
int player_number_;
int next_player_number_;

boost::optional<end_level_data> end_level_data_;
bool init_side_done_;
Expand Down
66 changes: 42 additions & 24 deletions src/play_controller.cpp
Expand Up @@ -1170,41 +1170,59 @@ void play_controller::play_turn()
LOG_AIT << "Turn " << turn() << ":" << std::endl;
}

for (; gamestate_->player_number_ <= int(gamestate().board_.teams().size()); ++gamestate_->player_number_)
int last_player_number = gamestate_->player_number_;
int next_player_number = gamestate_->next_player_number_;

while(gamestate_->player_number_ <= int(gamestate().board_.teams().size()))
{
gamestate_->next_player_number_ = gamestate_->player_number_ + 1;
next_player_number = gamestate_->next_player_number_;
last_player_number = gamestate_->player_number_;

// If a side is empty skip over it.
if (current_team().is_empty()) {
continue;
}
init_side_begin();
if(gamestate_->init_side_done()) {
// This is the case in a reloaded game where the side was initialized before saving the game.
init_side_end();
}
if (!current_team().is_empty()) {
init_side_begin();
if(gamestate_->init_side_done()) {
// This is the case in a reloaded game where the side was initialized before saving the game.
init_side_end();
}

ai_testing::log_turn_start(current_side());
play_side();
if(is_regular_game_end()) {
return;
}
finish_side_turn();
if(is_regular_game_end()) {
return;
}
if(gui_->video().non_interactive()) {
LOG_AIT << " Player " << current_side() << ": " <<
current_team().villages().size() << " Villages" <<
std::endl;
ai_testing::log_turn_end(current_side());
ai_testing::log_turn_start(current_side());
play_side();
//ignore any changes to next_player_number_ that happen after the [end_turn] is sended to the server, otherwise we will get OOS.
next_player_number = gamestate_->next_player_number_;
assert(next_player_number <= 2 * int(gamestate().board_.teams().size()));
if(is_regular_game_end()) {
return;
}
//note: play_side() send the [end_turn] to the sever and finish_side_turn() callsie the side turn end events.
// this means that during the side turn end events the clients think it is still the last sides turn while
// the server thinks that it is already the next plyers turn. i don'T think this is a problem though.
finish_side_turn();
if(is_regular_game_end()) {
return;
}
if(gui_->video().non_interactive()) {
LOG_AIT << " Player " << current_side() << ": " <<
current_team().villages().size() << " Villages" <<
std::endl;
ai_testing::log_turn_end(current_side());
}
}

gamestate_->player_number_ = next_player_number;
}
// If the loop exits due to the last team having been processed.
gamestate_->player_number_ = gamestate().board_.teams().size();
gamestate_->player_number_ = last_player_number;

finish_turn();

// Time has run out
check_time_over();

if (!is_regular_game_end()) {
gamestate_->player_number_ = modulo(next_player_number, gamestate().board_.teams().size(), 1);
}
}

void play_controller::check_time_over()
Expand Down
3 changes: 1 addition & 2 deletions src/playsingle_controller.cpp
Expand Up @@ -177,7 +177,6 @@ void playsingle_controller::play_scenario_main_loop()
turn_data_.send_data();
return;
}
gamestate_->player_number_ = 1;
}
catch(const reset_gamestate_exception& ex) {
//
Expand Down Expand Up @@ -636,7 +635,7 @@ void playsingle_controller::sync_end_turn()
if(end_turn_ == END_TURN_REQUIRED && current_team().is_local())
{
//TODO: we should also send this immediately.
resources::recorder->end_turn();
resources::recorder->end_turn(gamestate_->next_player_number_);
end_turn_ = END_TURN_SYNCED;
}

Expand Down
10 changes: 6 additions & 4 deletions src/replay.cpp
Expand Up @@ -297,10 +297,12 @@ void replay::add_rename(const std::string& name, const map_location& loc)
}


void replay::end_turn()
void replay::end_turn(int next_player_number)
{
config& cmd = add_command();
cmd.add_child("end_turn");
config& end_turn = cmd.add_child("end_turn");

end_turn["next_player_number"] = next_player_number;
}


Expand Down Expand Up @@ -795,7 +797,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
}

//if there is an end turn directive
else if (cfg->child("end_turn"))
else if (const config& end_turn = cfg->child("end_turn"))
{
if(is_synced)
{
Expand All @@ -808,7 +810,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
if (const config &cfg_verify = cfg->child("verify")) {
verify(resources::gameboard->units(), cfg_verify);
}

resources::controller->gamestate().next_player_number_ = end_turn["next_player_number"];
return REPLAY_FOUND_END_TURN;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/replay.hpp
Expand Up @@ -70,7 +70,7 @@ class replay
void add_label(const terrain_label*);
void clear_labels(const std::string&, bool);
void add_rename(const std::string& name, const map_location& loc);
void end_turn();
void end_turn(int next_player_number);
void add_unit_checksum(const map_location& loc,config& cfg);
void add_log_data(const std::string &key, const std::string &var);
void add_log_data(const std::string &category, const std::string &key, const std::string &var);
Expand Down
13 changes: 11 additions & 2 deletions src/scripting/game_lua_kernel.cpp
Expand Up @@ -1558,8 +1558,17 @@ int game_lua_kernel::intf_end_level(lua_State *L)
return 0;
}

int game_lua_kernel::intf_end_turn(lua_State*)
{
int game_lua_kernel::intf_end_turn(lua_State* L)
{
//note that next_player_number = 1, next_player_number = nteams+1 both set the next team to be the first team
//but the later will make the turn counter change aswell fire turn end events accoringly etc.
if (!lua_isnoneornil(L, 1)) {
int npn = luaL_checknumber(L, 1);
if (npn <= 0 /*TODO: || npn > 2*nteams*/) {
return luaL_argerror(L, 1, "side number out of range");
}
resources::controller->gamestate().next_player_number_ = npn;
}
play_controller_.force_end_turn();
return 0;
}
Expand Down
49 changes: 32 additions & 17 deletions src/server/game.cpp
Expand Up @@ -111,6 +111,8 @@ game::game(player_connections& player_connections,
, level_()
, history_()
, description_(nullptr)
, current_turn_(0)
, current_side_index_(0)
, end_turn_(0)
, num_turns_(0)
, all_observers_muted_(false)
Expand Down Expand Up @@ -355,11 +357,11 @@ void game::start_game(const socket_ptr& starter)
side = lexical_cast_default<int>((*snapshot)["playing_team"], 0);
LOG_GAME << "Reload from turn: " << turn << ". Current side is: " << side + 1 << ".\n";
}

end_turn_ = (turn - 1) * nsides_ + side - 1;
current_turn_ = turn;
current_side_index_ = side;
num_turns_ = lexical_cast_default<int>((*starting_pos(level_.root()))["turns"], -1);

end_turn();
update_turn_data();
clear_history();

// Send [observer] tags for all observers that are already in the game.
Expand Down Expand Up @@ -1078,7 +1080,9 @@ bool game::process_turn(simple_wml::document& data, const socket_ptr& user)
}
send_and_record_server_message(username(user) + " has surrendered.");
} else if(is_current_player(user) && (*command).child("end_turn")) {
turn_ended = end_turn();
simple_wml::node& endturn = *(*command).child("end_turn");
// fixme handle next_player_number
turn_ended = end_turn(endturn["next_player_number"].to_int());
}

++index;
Expand Down Expand Up @@ -1312,33 +1316,45 @@ void game::process_change_turns_wml(simple_wml::document& data, const socket_ptr
// Don't send or store this change, all players should have gotten it by wml.
}

bool game::end_turn()
bool game::end_turn(int new_side)
{
// It's a new turn every time each side in the game ends their turn.

This comment has been minimized.

Copy link
@soliton-

soliton- Feb 26, 2018

Member

This comment does not appear to have any relation with the code anymore. Please update or remove it.

++end_turn_;

bool turn_ended = false;
if((current_side()) == 0) {
turn_ended = true;
if(new_side > 0) {
current_side_index_ = new_side - 1;
}
else {
++current_side_index_;
}

// Skip over empty sides.
for(int i = 0; i < nsides_ && side_controllers_[current_side()] == CONTROLLER::EMPTY; ++i) {
++end_turn_;

if(current_side() == 0) {
turn_ended = true;
}
++current_side_index_;
}

if(!turn_ended) {
auto res = std::div(current_side_index_, nsides_ > 0 ? nsides_ : 1);

if(res.quot == 0) {
return false;
}
current_side_index_ = res.rem;
current_turn_ += res.quot;

if(description_ == nullptr) {
// TODO: why do we need this?
return false;
}

update_turn_data();

return true;
}

void game::update_turn_data()
{
if(description_ == nullptr) {
return;
}

simple_wml::node* turns_cfg = description_->child("turn_data");
if(!turns_cfg) {
turns_cfg = &description_->add_child("turn_data");
Expand All @@ -1347,7 +1363,6 @@ bool game::end_turn()
turns_cfg->set_attr_int("current", current_turn());
turns_cfg->set_attr_int("max", num_turns_);

return true;
}

///@todo differentiate between "observers not allowed" and "player already in the game" errors.
Expand Down
12 changes: 7 additions & 5 deletions src/server/game.hpp
Expand Up @@ -126,13 +126,12 @@ class game

size_t current_turn() const
{
return (nsides_ ? end_turn_ / nsides_ + 1 : 0);
return current_turn_;
}

void set_current_turn(int turn)
{
int current_side = end_turn_ % nsides_;
end_turn_ = current_side + nsides_ * (turn - 1);
current_turn_ = turn;
}

void mute_all_observers();
Expand Down Expand Up @@ -318,7 +317,7 @@ class game

size_t current_side() const
{
return (nsides_ ? end_turn_ % nsides_ : 0);
return nsides_ ? (current_side_index_ % nsides_) : 0;
}

const socket_ptr current_player() const
Expand Down Expand Up @@ -413,8 +412,9 @@ class game
* the game's description when appropriate. Will return true iff there has
* been a change.
*/
bool end_turn();
bool end_turn(int new_side);

void update_turn_data();
/**
* Function to send a list of users to all clients.
*
Expand Down Expand Up @@ -493,6 +493,8 @@ class game
/** Pointer to the game's description in the games_and_users_list_. */
simple_wml::node* description_;

int current_turn_;
int current_side_index_;
int end_turn_;
int num_turns_;
bool all_observers_muted_;
Expand Down

0 comments on commit 2e235f7

Please sign in to comment.