Beispiel #1
0
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;
		}
	}
}
Beispiel #3
0
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;
		}
	}
}
Beispiel #4
0
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;
	}
}
Beispiel #5
0
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;
	}
}
Beispiel #6
0
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;
	}
}
Beispiel #7
0
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;
	}
}
Beispiel #8
0
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;
	}
}
Beispiel #10
0
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;
		}
	}

}
Beispiel #12
0
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;
	}
}
Beispiel #13
0
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;
	}
}
Beispiel #14
0
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);
	}


}
Beispiel #16
0
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;
		}
	}
}