void stopunit_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); unit_map::iterator un = resources::gameboard->units().find(unit_location_); if(resources::simulation_){ bool gamestate_changed = simulated_stopunit(unit_location_, remove_movement_, remove_attacks_); sim_gamestate_changed(this, gamestate_changed); return; } try { if (remove_movement_){ un->remove_movement_ai(); set_gamestate_changed(); manager::raise_gamestate_changed(); } if (remove_attacks_){ un->remove_attacks_ai(); set_gamestate_changed(); manager::raise_gamestate_changed();//to be on the safe side } } catch (...) { if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked." << std::endl; } //Demotes to DBG "unchecked result" warning throw; } }
void move_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; assert(is_success()); move_spectator_.set_unit(get_info().units.find(from_)); if (from_ != to_) { move_unit( /*move_unit_spectator* move_spectator*/ &move_spectator_, /*std::vector<map_location> route*/ route_.steps, /*replay* move_recorder*/ &recorder, /*undo_list* undo_stack*/ NULL, /*bool show_move*/ preferences::show_ai_moves(), /*map_location *next_unit*/ NULL, /*bool continue_move*/ true, //@todo: 1.9 set to false after implemeting interrupt awareness /*bool should_clear_shroud*/ true, /*bool is_replay*/ false); if ( move_spectator_.get_ambusher().valid() || !move_spectator_.get_seen_enemies().empty() || !move_spectator_.get_seen_friends().empty() ) { set_gamestate_changed(); } else if (move_spectator_.get_unit().valid()){ unit_location_ = move_spectator_.get_unit()->first; if (unit_location_ != from_) { set_gamestate_changed(); } } } else { assert(remove_movement_); } if (move_spectator_.get_unit().valid()){ unit_location_ = move_spectator_.get_unit()->first; if ( remove_movement_ && ( move_spectator_.get_unit()->second.movement_left() > 0 ) && (unit_location_==to_)) { stopunit_result_ptr stopunit_res = actions::execute_stopunit_action(get_side(),true,unit_location_,true,false); if (!stopunit_res->is_ok()) { set_error(stopunit_res->get_status()); } if (stopunit_res->is_gamestate_changed()) { set_gamestate_changed(); } } } else { unit_location_ = map_location(); } if (is_gamestate_changed()) { try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } } }
void move_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; assert(is_success()); move_spectator_.set_unit(resources::units->find(from_)); if (from_ != to_) { size_t num_steps = ::actions::move_unit_and_record( /*std::vector<map_location> steps*/ route_->steps, /*::actions::undo_list* undo_stack*/ NULL, /*bool continue_move*/ true, ///@todo 1.9 set to false after implemeting interrupt awareness /*bool show_move*/ preferences::show_ai_moves(), /*bool* interrupted*/ NULL, /*::actions::move_unit_spectator* move_spectator*/ &move_spectator_); if ( num_steps > 0 ) { set_gamestate_changed(); } else if ( move_spectator_.get_ambusher().valid() ) { // Unlikely, but some types of strange WML (or bad pathfinding) // could cause an ambusher to be found without moving. set_gamestate_changed(); } } else { assert(remove_movement_); } if (move_spectator_.get_unit().valid()){ unit_location_ = move_spectator_.get_unit()->get_location(); if (remove_movement_ && move_spectator_.get_unit()->movement_left() > 0 && unit_location_ == to_) { stopunit_result_ptr stopunit_res = actions::execute_stopunit_action(get_side(),true,unit_location_,true,false); if (!stopunit_res->is_ok()) { set_error(stopunit_res->get_status()); } if (stopunit_res->is_gamestate_changed()) { set_gamestate_changed(); } } } else { unit_location_ = map_location(); } if (is_gamestate_changed()) { try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } } }
void synced_command_result::do_execute() { if(resources::simulation_){ bool gamestate_changed = simulated_synced_command(); sim_gamestate_changed(this, gamestate_changed); return; } LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); std::stringstream s; if (location_ != map_location::null_location()){ s << "local x1 = " << location_.wml_x() << " local y1 = " << location_.wml_y() << " "; } s << lua_code_; synced_context::run_in_synced_context_if_not_already("lua_ai", replay_helper::get_lua_ai(s.str())); try { set_gamestate_changed(); manager::raise_gamestate_changed(); } catch (...) { if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked." << std::endl; } //Demotes to DBG "unchecked result" warning throw; } }
void recruit_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); const unit_type *u = unit_types.find(unit_name_); const events::command_disabler disable_commands; // Assert that recruit_location_ has been validated. // This should be implied by is_success() once check_before() has been // called, so this is a guard against future breakage. assert(location_checked_ && u != nullptr); if(resources::simulation_){ bool gamestate_changed = simulated_recruit(get_side(), u, recruit_location_); sim_gamestate_changed(this, gamestate_changed); return; } synced_context::run_in_synced_context_if_not_already("recruit", replay_helper::get_recruit(u->id(), recruit_location_, recruit_from_), false, !preferences::skip_ai_moves()); //TODO: should we do something to pass use_undo = false in replays and ai moves ? //::actions::recruit_unit(*u, get_side(), recruit_location_, recruit_from_, // !preferences::skip_ai_moves(), false); set_gamestate_changed(); try { manager::raise_gamestate_changed(); } catch (...) { if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked." << std::endl; } //Demotes to DBG "unchecked result" warning throw; } }
void attack_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; // Stop the user from issuing any commands while the unit is attacking const events::command_disabler disable_commands; //@note: yes, this is a decision done here. It's that way because we want to allow a simpler attack 'with whatever weapon is considered best', and because we want to allow the defender to pick it's weapon. That's why aggression is needed. a cleaner solution is needed. battle_context bc(resources::gameboard->units(), attacker_loc_, defender_loc_, attacker_weapon_, -1, aggression_); int attacker_weapon = bc.get_attacker_stats().attack_num; int defender_weapon = bc.get_defender_stats().attack_num; if(attacker_weapon < 0) { set_error(E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON); return; } const unit_map::const_iterator a_ = resources::gameboard->units().find(attacker_loc_); const unit_map::const_iterator d_ = resources::gameboard->units().find(defender_loc_); if(resources::simulation_){ bool gamestate_changed = simulated_attack(attacker_loc_, defender_loc_, bc.get_attacker_combatant().average_hp(), bc.get_defender_combatant().average_hp()); sim_gamestate_changed(this, gamestate_changed); return; } //FIXME: find a way to 'ask' the ai which advancement should be chosen from synced_commands.cpp . if(!synced_context::is_synced()) //RAII block for set_scontext_synced { wb::real_map rm; //we don't use synced_context::run_in_synced_context because that wouldn't allow us to pass advancements_ resources::recorder->add_synced_command("attack", replay_helper::get_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(), d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(), resources::tod_manager->get_time_of_day())); set_scontext_synced sync; attack_unit_and_advance(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, true, advancements_); resources::controller->check_victory(); resources::controller->maybe_throw_return_to_play_side(); sync.do_final_checkup(); } else { attack_unit_and_advance(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, true, advancements_); } set_gamestate_changed(); //start of ugly hack. @todo 1.9 rework that via extended event system //until event system is reworked, we note the attack this way get_info().recent_attacks.insert(defender_loc_); //end of ugly hack try { manager::raise_gamestate_changed(); } catch (...) { if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked." << std::endl; } //Demotes to DBG "unchecked result" warning throw; } }
void recruit_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); const unit_type *u = unit_types.find(unit_name_); const events::command_disabler disable_commands; // Assert that recruit_location_ has been validated. // This should be implied by is_success() once check_before() has been // called, so this is a guard against future breakage. assert(location_checked_ && u != NULL); synced_context::run_in_synced_context("recruit", replay_helper::get_recruit(u->id(), recruit_location_, recruit_from_), false, preferences::show_ai_moves()); //TODO: should we do something to pass use_undo = false in replays and ai moves ? //::actions::recruit_unit(*u, get_side(), recruit_location_, recruit_from_, // preferences::show_ai_moves(), false); set_gamestate_changed(); try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void recall_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); const events::command_disabler disable_commands; // Assert that recall_location_ has been validated. // This should be implied by is_success() once check_before() has been // called, so this is a guard against future breakage. assert(location_checked_); // Do the actual recalling. //we ignore possible erros (=unit doesnt exist on the recall list) //becasue that was the previous behaviour. synced_context::run_in_synced_context("recall", replay_helper::get_recall(unit_id_, recall_location_, recall_from_), false, preferences::show_ai_moves(), true, synced_context::ignore_error_function); set_gamestate_changed(); try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void attack_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; // Stop the user from issuing any commands while the unit is attacking const events::command_disabler disable_commands; //@note: yes, this is a decision done here. It's that way because we want to allow a simpler attack 'with whatever weapon is considered best', and because we want to allow the defender to pick it's weapon. That's why aggression is needed. a cleaner solution is needed. battle_context bc(get_info().units, attacker_loc_, defender_loc_, attacker_weapon_, -1, aggression_); int attacker_weapon = bc.get_attacker_stats().attack_num; int defender_weapon = bc.get_defender_stats().attack_num; if(attacker_weapon < 0) { set_error(E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON); return; } const unit *d_ = get_unit(get_info(),defender_loc_); const unit *a_ = get_unit(get_info(),attacker_loc_); //@todo 1.9: change ToD to be location specific for the defender unit recorder.add_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(), d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(), resources::tod_manager->get_time_of_day()); rand_rng::invalidate_seed(); rand_rng::clear_new_seed_callback(); while (!rand_rng::has_valid_seed()) { manager::raise_user_interact(); manager::raise_sync_network(); SDL_Delay(10); } recorder.add_seed("attack", rand_rng::get_last_seed()); attack_unit(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon); dialogs::advance_unit(attacker_loc_, true); const unit_map::const_iterator defender = get_info().units.find(defender_loc_); if(defender != get_info().units.end()) { const size_t defender_team = size_t(defender->second.side()) - 1; if(defender_team < get_info().teams.size()) { dialogs::advance_unit(defender_loc_ , !get_info().teams[defender_team].is_human()); } } set_gamestate_changed(); //start of ugly hack. @todo 1.9 rework that via extended event system //until event system is reworked, we note the attack this way get_info().recent_attacks.insert(defender_loc_); //end of ugly hack try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void stopunit_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); unit_map::iterator un = resources::units->find(unit_location_); try { if (remove_movement_){ un->remove_movement_ai(); set_gamestate_changed(); manager::raise_gamestate_changed(); } if (remove_attacks_){ un->remove_attacks_ai(); set_gamestate_changed(); manager::raise_gamestate_changed();//to be on the safe side } } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void recall_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); game_info& info = get_info(); team& my_team = get_my_team(info); const events::command_disabler disable_commands; std::vector<unit>::iterator rec = std::find_if(my_team.recall_list().begin(), my_team.recall_list().end(), boost::bind(&unit::matches_id, _1, unit_id_)); assert(rec != my_team.recall_list().end()); const std::string &err = find_recruit_location(get_side(), recall_location_); if(!err.empty()) { set_error(AI_ACTION_FAILURE); return; } else { unit &un = *rec; recorder.add_recall(un.id(), recall_location_); un.set_game_context(&info.units); place_recruit(un, recall_location_, true, true); statistics::recall_unit(un); my_team.spend_gold(game_config::recall_cost); my_team.recall_list().erase(rec); if (resources::screen!=NULL) { resources::screen->invalidate_game_status(); resources::screen->invalidate_all(); } recorder.add_checksum_check(recall_location_); set_gamestate_changed(); try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } } }
void attack_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; // Stop the user from issuing any commands while the unit is attacking const events::command_disabler disable_commands; //@note: yes, this is a decision done here. It's that way because we want to allow a simpler attack 'with whatever weapon is considered best', and because we want to allow the defender to pick it's weapon. That's why aggression is needed. a cleaner solution is needed. battle_context bc(*resources::units, attacker_loc_, defender_loc_, attacker_weapon_, -1, aggression_); int attacker_weapon = bc.get_attacker_stats().attack_num; int defender_weapon = bc.get_defender_stats().attack_num; if(attacker_weapon < 0) { set_error(E_UNABLE_TO_CHOOSE_ATTACKER_WEAPON); return; } const unit_map::const_iterator a_ = resources::units->find(attacker_loc_); const unit_map::const_iterator d_ = resources::units->find(defender_loc_); //to get rid of an unused member varuiable warning, FIXME: find a way to 'ask' the ai wich advancement should be chosen from synced_commands.cpp . if(true) //RAII block for set_scontext_synced { //we don't use synced_context::run_in_synced_context because that wouldn't allow us to pass advancements_ recorder.add_synced_command("attack", replay_helper::get_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(), d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(), resources::tod_manager->get_time_of_day())); set_scontext_synced sync; attack_unit_and_advance(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, true, advancements_); } set_gamestate_changed(); //start of ugly hack. @todo 1.9 rework that via extended event system //until event system is reworked, we note the attack this way get_info().recent_attacks.insert(defender_loc_); //end of ugly hack try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void synced_command_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); std::stringstream s; if (location_ != map_location::null_location){ s << "local x1 = " << location_.x << " local y1 = " << location_.y << " "; } s << lua_code_; synced_context::run_in_synced_context("lua_ai", replay_helper::get_lua_ai(s.str())); try { set_gamestate_changed(); manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } }
void recall_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); const events::command_disabler disable_commands; // Assert that recall_location_ has been validated. // This should be implied by is_success() once check_before() has been // called, so this is a guard against future breakage. assert(location_checked_); if(resources::simulation_){ bool gamestate_changed = simulated_recall(get_side(), unit_id_, recall_location_); sim_gamestate_changed(this, gamestate_changed); return; } // Do the actual recalling. // We ignore possible errors (=unit doesn't exist on the recall list) // because that was the previous behavior. synced_context::run_in_synced_context_if_not_already("recall", replay_helper::get_recall(unit_id_, recall_location_, recall_from_), false, !preferences::skip_ai_moves(), synced_context::ignore_error_function); set_gamestate_changed(); try { manager::raise_gamestate_changed(); } catch (...) { if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked." << std::endl; } //Demotes to DBG "unchecked result" warning throw; } }
void recruit_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: " << *this << std::endl; assert(is_success()); game_info& info = get_info(); // We have to add the recruit command now, because when the unit // is created it has to have the recruit command in the recorder // to be able to put random numbers into to generate unit traits. // However, we're not sure if the transaction will be successful, // so use a replay_undo object to cancel it if we don't get // a confirmation for the transaction. recorder.add_recruit(num_,recruit_location_); replay_undo replay_guard(recorder); const unit_type *u = unit_types.find(unit_name_); const events::command_disabler disable_commands; const std::string recruit_err = find_recruit_location(get_side(), recruit_location_); if(recruit_err.empty()) { const unit new_unit(&info.units, u, get_side(), true); place_recruit(new_unit, recruit_location_, false, preferences::show_ai_moves()); statistics::recruit_unit(new_unit); get_my_team(info).spend_gold(u->cost()); // Confirm the transaction - i.e. don't undo recruitment replay_guard.confirm_transaction(); set_gamestate_changed(); try { manager::raise_gamestate_changed(); } catch (...) { is_ok(); //Silences "unchecked result" warning throw; } } else { set_error(AI_ACTION_FAILURE); } }
void move_result::do_execute() { LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl; assert(is_success()); if(resources::simulation_){ bool gamestate_changed = false; if(from_ != to_){ int step = route_->steps.size(); gamestate_changed = simulated_move(get_side(), from_, to_, step, unit_location_); } else { assert(remove_movement_); } unit_map::const_iterator un = resources::gameboard->units().find(unit_location_); if(remove_movement_ && un->movement_left() > 0 && unit_location_ == to_){ gamestate_changed = simulated_stopunit(unit_location_, true, false); } sim_gamestate_changed(this, gamestate_changed); return; } ::actions::move_unit_spectator move_spectator(resources::gameboard->units()); move_spectator.set_unit(resources::gameboard->units().find(from_)); if (from_ != to_) { size_t num_steps = ::actions::move_unit_and_record( /*std::vector<map_location> steps*/ route_->steps, /*::actions::undo_list* undo_stack*/ nullptr, /*bool continue_move*/ true, ///@todo 1.9 set to false after implemeting interrupt awareness /*bool show_move*/ !preferences::skip_ai_moves(), /*bool* interrupted*/ nullptr, /*::actions::move_unit_spectator* move_spectator*/ &move_spectator); if ( num_steps > 0 ) { set_gamestate_changed(); } else if ( move_spectator.get_ambusher().valid() ) { // Unlikely, but some types of strange WML (or bad pathfinding) // could cause an ambusher to be found without moving. set_gamestate_changed(); } } else { assert(remove_movement_); } if (move_spectator.get_unit().valid()){ unit_location_ = move_spectator.get_unit()->get_location(); if (remove_movement_ && move_spectator.get_unit()->movement_left() > 0 && unit_location_ == to_) { stopunit_result_ptr stopunit_res = actions::execute_stopunit_action(get_side(),true,unit_location_,true,false); if (!stopunit_res->is_ok()) { set_error(stopunit_res->get_status()); } if (stopunit_res->is_gamestate_changed()) { set_gamestate_changed(); } } } else { unit_location_ = map_location(); } has_ambusher_ = move_spectator.get_ambusher().valid(); has_interrupted_teleport_ = move_spectator.get_failed_teleport().valid(); if (is_gamestate_changed()) { try { manager::raise_gamestate_changed(); } catch (...) { if (!is_ok()) { DBG_AI_ACTIONS << "Return value of AI ACTION was not checked." << std::endl; } //Demotes to DBG "unchecked result" warning throw; } } }