Exemple #1
0
void unit_attack(display * disp, game_board & board,
                 const map_location& a, const map_location& b, int damage,
                 const attack_type& attack, const attack_type* secondary_attack,
                 int swing,std::string hit_text,int drain_amount,std::string att_text, const std::vector<std::string>* extra_hit_sounds)
{
	if(!disp ||disp->video().update_locked() || disp->video().faked() ||
			(disp->fogged(a) && disp->fogged(b)) || preferences::show_combat() == false) {
		return;
	}
	//const unit_map& units = disp->get_units();
	disp->select_hex(map_location::null_location());

	// scroll such that there is at least half a hex spacing around fighters
	disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.5,false);

	log_scope("unit_attack");

	const unit_map::const_iterator att = board.units().find(a);
	assert(att.valid());
	const unit& attacker = *att;

	const unit_map::iterator def = board.find_unit(b);
	assert(def.valid());
	unit &defender = *def;
	int def_hitpoints = defender.hitpoints();

	att->set_facing(a.get_relative_dir(b));
	def->set_facing(b.get_relative_dir(a));
	defender.set_facing(b.get_relative_dir(a));


	unit_animator animator;
	unit_ability_list leaders = attacker.get_abilities("leadership");
	unit_ability_list helpers = defender.get_abilities("resistance");

	std::string text   = number_and_text(damage, hit_text);
	std::string text_2 = number_and_text(abs(drain_amount), att_text);

	unit_animation::hit_type hit_type;
	if(damage >= defender.hitpoints()) {
		hit_type = unit_animation::hit_type::KILL;
	} else if(damage > 0) {
		hit_type = unit_animation::hit_type::HIT;
	}else {
		hit_type = unit_animation::hit_type::MISS;
	}
	animator.add_animation(&attacker, "attack", att->get_location(),
		def->get_location(), damage, true,  text_2,
		(drain_amount >= 0) ? display::rgb(0, 255, 0) : display::rgb(255, 0, 0),
		hit_type, &attack, secondary_attack, swing);

	// note that we take an anim from the real unit, we'll use it later
	const unit_animation *defender_anim = def->anim_comp().choose_animation(*disp,
		def->get_location(), "defend", att->get_location(), damage,
		hit_type, &attack, secondary_attack, swing);
	animator.add_animation(&defender, defender_anim, def->get_location(),
		true,  text , display::rgb(255, 0, 0));

	for (const unit_ability & ability : leaders) {
		if(ability.second == a) continue;
		if(ability.second == b) continue;
		unit_map::const_iterator leader = board.units().find(ability.second);
		assert(leader.valid());
		leader->set_facing(ability.second.get_relative_dir(a));
		animator.add_animation(&*leader, "leading", ability.second,
			att->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}
	for (const unit_ability & ability : helpers) {
		if(ability.second == a) continue;
		if(ability.second == b) continue;
		unit_map::const_iterator helper = board.units().find(ability.second);
		assert(helper.valid());
		helper->set_facing(ability.second.get_relative_dir(b));
		animator.add_animation(&*helper, "resistance", ability.second,
			def->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}


	animator.start_animations();
	animator.wait_until(0);
	int damage_left = damage;
	bool extra_hit_sounds_played = false;
	while(damage_left > 0 && !animator.would_end()) {
		if(!extra_hit_sounds_played && extra_hit_sounds != nullptr) {
			for (std::string hit_sound : *extra_hit_sounds) {
				sound::play_sound(hit_sound);
			}
			extra_hit_sounds_played = true;
		}

		int step_left = (animator.get_end_time() - animator.get_animation_time() )/50;
		if(step_left < 1) step_left = 1;
		int removed_hp =  damage_left/step_left ;
		if(removed_hp < 1) removed_hp = 1;
		defender.take_hit(removed_hp);
		damage_left -= removed_hp;
		animator.wait_until(animator.get_animation_time_potential() +50);
	}
	animator.wait_for_end();
	// pass the animation back to the real unit
	def->anim_comp().start_animation(animator.get_end_time(), defender_anim, true);
	reset_helpers(&*att, &*def);
	def->set_hitpoints(def_hitpoints);
}
void unit_attack(
                 const map_location& a, const map_location& b, int damage,
                 const attack_type& attack, const attack_type* secondary_attack,
		  int swing,std::string hit_text,bool drain,std::string att_text)
{
	game_display* disp = game_display::get_singleton();
	if(!disp ||disp->video().update_locked() || disp->video().faked() ||
			(disp->fogged(a) && disp->fogged(b)) || preferences::show_combat() == false) {
		return;
	}
	unit_map& units = disp->get_units();
	disp->select_hex(map_location::null_location);

	// scroll such that there is at least half a hex spacing around fighters
	disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.5,false);

	log_scope("unit_attack");

	const unit_map::iterator att = units.find(a);
	assert(att != units.end());
	unit& attacker = *att;

	const unit_map::iterator def = units.find(b);
	assert(def != units.end());
	unit &defender = *def;
	int def_hitpoints = defender.hitpoints();

	att->set_facing(a.get_relative_dir(b));
	def->set_facing(b.get_relative_dir(a));
	defender.set_facing(b.get_relative_dir(a));


	unit_animator animator;
	unit_ability_list leaders = attacker.get_abilities("leadership");
	unit_ability_list helpers = defender.get_abilities("resistance");

	std::string text ;
	if(damage) text = lexical_cast<std::string>(damage);
	if(!hit_text.empty()) {
		text.insert(text.begin(),hit_text.size()/2,' ');
		text = text + "\n" + hit_text;
	}

	std::string text_2 ;
	if(drain && damage) text_2 = lexical_cast<std::string>(std::min<int>(damage,defender.hitpoints())/2);
	if(!att_text.empty()) {
		text_2.insert(text_2.begin(),att_text.size()/2,' ');
		text_2 = text_2 + "\n" + att_text;
	}

	unit_animation::hit_type hit_type;
	if(damage >= defender.hitpoints()) {
		hit_type = unit_animation::KILL;
	} else if(damage > 0) {
		hit_type = unit_animation::HIT;
	}else {
		hit_type = unit_animation::MISS;
	}
	animator.add_animation(&attacker, "attack", att->get_location(),
		def->get_location(), damage, true,  text_2,
		display::rgb(0, 255, 0), hit_type, &attack, secondary_attack,
		swing);

	// note that we take an anim from the real unit, we'll use it later
	const unit_animation *defender_anim = def->choose_animation(*disp,
		def->get_location(), "defend", att->get_location(), damage,
		hit_type, &attack, secondary_attack, swing);
	animator.add_animation(&defender, defender_anim, def->get_location(),
		true,  text , display::rgb(255, 0, 0));

	for (std::vector<std::pair<const config *, map_location> >::iterator itor = leaders.cfgs.begin(); itor != leaders.cfgs.end(); ++itor) {
		if(itor->second == a) continue;
		if(itor->second == b) continue;
		unit_map::iterator leader = units.find(itor->second);
		assert(leader != units.end());
		leader->set_facing(itor->second.get_relative_dir(a));
		animator.add_animation(&*leader, "leading", itor->second,
			att->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}
	for (std::vector<std::pair<const config *, map_location> >::iterator itor = helpers.cfgs.begin(); itor != helpers.cfgs.end(); ++itor) {
		if(itor->second == a) continue;
		if(itor->second == b) continue;
		unit_map::iterator helper = units.find(itor->second);
		assert(helper != units.end());
		helper->set_facing(itor->second.get_relative_dir(b));
		animator.add_animation(&*helper, "resistance", itor->second,
			def->get_location(), damage, true,  "", 0,
			hit_type, &attack, secondary_attack, swing);
	}


	animator.start_animations();
	animator.wait_until(0);
	int damage_left = damage;
	while(damage_left > 0 && !animator.would_end()) {
		int step_left = (animator.get_end_time() - animator.get_animation_time() )/50;
		if(step_left < 1) step_left = 1;
		int removed_hp =  damage_left/step_left ;
		if(removed_hp < 1) removed_hp = 1;
		defender.take_hit(removed_hp);
		damage_left -= removed_hp;
		animator.wait_until(animator.get_animation_time_potential() +50);
	}
	animator.wait_for_end();
	// pass the animation back to the real unit
	def->start_animation(animator.get_end_time(), defender_anim, true);
	reset_helpers(&*att, &*def);
	def->set_hitpoints(def_hitpoints);
}