void unit_sheath_weapon(const map_location& primary_loc, unit* primary_unit, const attack_type* primary_attack,const attack_type* secondary_attack, const map_location& secondary_loc,unit* secondary_unit) { display* disp = display::get_singleton(); if(!disp ||disp->video().update_locked() || disp->video().faked() || disp->fogged(primary_loc) || preferences::show_combat() == false) { return; } unit_animator animator; if(primary_unit) { animator.add_animation(primary_unit,"sheath_weapon",primary_loc,secondary_loc,0,false,"",0,unit_animation::hit_type::INVALID,primary_attack,secondary_attack,0); } if(secondary_unit) { animator.add_animation(secondary_unit,"sheath_weapon",secondary_loc,primary_loc,0,false,"",0,unit_animation::hit_type::INVALID,secondary_attack,primary_attack,0); } if(primary_unit || secondary_unit) { animator.start_animations(); animator.wait_for_end(); } if(primary_unit) { primary_unit->anim_comp().set_standing(); } if(secondary_unit) { secondary_unit->anim_comp().set_standing(); } reset_helpers(primary_unit,secondary_unit); }
void unit_die(const map_location& loc, unit& loser, const attack_type* attack,const attack_type* secondary_attack, const map_location& winner_loc,unit* winner) { display* disp = display::get_singleton(); if(!disp ||disp->video().update_locked() || disp->video().faked() || disp->fogged(loc) || preferences::show_combat() == false) { return; } unit_animator animator; // hide the hp/xp bars of the loser (useless and prevent bars around an erased unit) animator.add_animation(&loser,"death",loc,winner_loc,0,false,"",0,unit_animation::hit_type::KILL,attack,secondary_attack,0); // but show the bars of the winner (avoid blinking and show its xp gain) animator.add_animation(winner,"victory",winner_loc,loc,0,true,"",0, unit_animation::hit_type::KILL,secondary_attack,attack,0); animator.start_animations(); animator.wait_for_end(); reset_helpers(winner,&loser); events::mouse_handler* mousehandler = events::mouse_handler::get_singleton(); if (mousehandler) { mousehandler->invalidate_reachmap(); } }
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); }