/** * Animates a teleportation between hexes. * * @param a The starting hex. * @param b The ending hex. * @param temp_unit The unit to animate (historically, a temporary unit). * @param disp The game display. Assumed neither locked nor faked. */ static void teleport_unit_between(const map_location& a, const map_location& b, unit& temp_unit, display& disp) { if ( disp.fogged(a) && disp.fogged(b) ) { return; } temp_unit.set_location(a); if ( !disp.fogged(a) ) { // teleport disp.invalidate(a); temp_unit.set_facing(a.get_relative_dir(b)); disp.scroll_to_tiles(a, b, game_display::ONSCREEN, true, 0.0, false); unit_animator animator; animator.add_animation(&temp_unit,"pre_teleport",a); animator.start_animations(); animator.wait_for_end(); } temp_unit.set_location(b); if ( !disp.fogged(b) ) { // teleport disp.invalidate(b); temp_unit.set_facing(a.get_relative_dir(b)); disp.scroll_to_tiles(b, a, game_display::ONSCREEN, true, 0.0, false); unit_animator animator; animator.add_animation(&temp_unit,"post_teleport",b); animator.start_animations(); animator.wait_for_end(); } temp_unit.anim_comp().set_standing(); disp.update_display(); events::pump(); }
static void teleport_unit_between( const map_location& a, const map_location& b, unit& temp_unit) { game_display* disp = game_display::get_singleton(); if(!disp || disp->video().update_locked() || disp->video().faked() || (disp->fogged(a) && disp->fogged(b))) { return; } disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.0,false); temp_unit.set_location(a); if (!disp->fogged(a)) { // teleport disp->invalidate(temp_unit.get_location()); temp_unit.set_facing(a.get_relative_dir(b)); unit_animator animator; animator.add_animation(&temp_unit,"pre_teleport",a); animator.start_animations(); animator.wait_for_end(); } temp_unit.set_location(b); if (!disp->fogged(b)) { // teleport disp->invalidate(temp_unit.get_location()); temp_unit.set_facing(a.get_relative_dir(b)); disp->scroll_to_tiles(b,a,game_display::ONSCREEN,true,0.0,false); unit_animator animator; animator.add_animation(&temp_unit,"post_teleport",b); animator.start_animations(); animator.wait_for_end(); } temp_unit.set_standing(); disp->update_display(); events::pump(); }
void unit_recruited(const map_location& loc,const map_location& leader_loc) { game_display* disp = game_display::get_singleton(); if(!disp || disp->video().update_locked() || disp->video().faked() ||disp->fogged(loc)) return; unit_map::const_iterator u = disp->get_units().find(loc); if(u == disp->get_units().end()) return; u->set_hidden(true); unit_animator animator; if(leader_loc != map_location::null_location()) { unit_map::const_iterator leader = disp->get_units().find(leader_loc); if(leader == disp->get_units().end()) return; disp->scroll_to_tiles(loc,leader_loc,game_display::ONSCREEN,true,0.0,false); leader->set_facing(leader_loc.get_relative_dir(loc)); animator.add_animation(&*leader, "recruiting", leader_loc, loc, 0, true); } else { disp->scroll_to_tile(loc,game_display::ONSCREEN,true,false); } disp->draw(); u->set_hidden(false); animator.add_animation(&*u, "recruited", loc, leader_loc); animator.start_animations(); animator.wait_for_end(); animator.set_all_standing(); if (loc==disp->mouseover_hex()) disp->invalidate_unit(); }
void unit_draw_weapon(const map_location& loc, unit& attacker, const attack_type* attack,const attack_type* secondary_attack, const map_location& defender_loc,unit* defender) { 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; attacker.set_facing(loc.get_relative_dir(defender_loc)); defender->set_facing(defender_loc.get_relative_dir(loc)); animator.add_animation(&attacker,"draw_weapon",loc,defender_loc,0,false,"",0,unit_animation::hit_type::HIT,attack,secondary_attack,0); animator.add_animation(defender,"draw_weapon",defender_loc,loc,0,false,"",0,unit_animation::hit_type::MISS,secondary_attack,attack,0); animator.start_animations(); animator.wait_for_end(); }
/** * Animates a single step between hexes. * This will return before the animation actually finishes, allowing other * processing to occur during the animation. * * @param a The starting hex. * @param b The ending hex. * @param temp_unit The unit to animate (historically, a temporary unit). * @param step_num The number of steps taken so far (used to pick an animation). * @param step_left The number of steps remaining (used to pick an animation). * @param animator The unit_animator to use. This is assumed clear when we start, * but will likely not be clear when we return. * @param disp The game display. Assumed neither locked nor faked. * @returns The animation potential until this animation will finish. * INT_MIN indicates that no animation is pending. */ static int move_unit_between(const map_location& a, const map_location& b, unit_ptr temp_unit, unsigned int step_num, unsigned int step_left, unit_animator & animator, display& disp) { if ( disp.fogged(a) && disp.fogged(b) ) { return INT_MIN; } temp_unit->set_location(a); disp.invalidate(a); temp_unit->set_facing(a.get_relative_dir(b)); animator.replace_anim_if_invalid(temp_unit.get(),"movement",a,b,step_num, false,"",0,unit_animation::hit_type::INVALID,nullptr,nullptr,step_left); animator.start_animations(); animator.pause_animation(); disp.scroll_to_tiles(a, b, game_display::ONSCREEN, true, 0.0, false); animator.restart_animation(); // useless now, previous short draw() just did one // new_animation_frame(); int target_time = animator.get_animation_time_potential(); // target_time must be short to avoid jumpy move // std::cout << "target time: " << target_time << "\n"; // we round it to the next multiple of 200 target_time += 200; target_time -= target_time%200; // This code causes backwards teleport because the time > 200 causes offset > 1.0 // which will not match with the following -1.0 // if( target_time - animator.get_animation_time_potential() < 100 ) target_time +=200; return target_time; }
void unit_frame::redraw(const int frame_time,bool first_time,const map_location & src,const map_location & dst,int*halo_id,const frame_parameters & animation_val,const frame_parameters & engine_val,const bool primary)const { const int xsrc = game_display::get_singleton()->get_location_x(src); const int ysrc = game_display::get_singleton()->get_location_y(src); const int xdst = game_display::get_singleton()->get_location_x(dst); const int ydst = game_display::get_singleton()->get_location_y(dst); const map_location::DIRECTION direction = src.get_relative_dir(dst); const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val,primary); double tmp_offset = current_data.offset; // debug code allowing to see the number of frames and their position // you need to add a '/n' // if (tmp_offset) std::cout << (int)(tmp_offset*100) << ","; int d2 = game_display::get_singleton()->hex_size() / 2; if(first_time ) { // stuff sthat should be done only once per frame if(!current_data.sound.empty() ) { sound::play_sound(current_data.sound); } if(!current_data.text.empty() ) { game_display::get_singleton()->float_label(src,current_data.text, (current_data.text_color & 0x00FF0000) >> 16, (current_data.text_color & 0x0000FF00) >> 8, (current_data.text_color & 0x000000FF) >> 0); } }
static void move_unit_between(const map_location& a, const map_location& b, unit& temp_unit,unsigned int step_num,unsigned int step_left) { game_display* disp = game_display::get_singleton(); if(!disp || disp->video().update_locked() || disp->video().faked() || (disp->fogged(a) && disp->fogged(b))) { return; } temp_unit.set_location(a); disp->invalidate(temp_unit.get_location()); temp_unit.set_facing(a.get_relative_dir(b)); unit_animator animator; animator.replace_anim_if_invalid(&temp_unit,"movement",a,b,step_num, false,"",0,unit_animation::INVALID,NULL,NULL,step_left); animator.start_animations(); animator.pause_animation(); disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.0,false); animator.restart_animation(); // useless now, previous short draw() just did one // new_animation_frame(); int target_time = animator.get_animation_time_potential(); // target_time must be short to avoid jumpy move // std::cout << "target time: " << target_time << "\n"; // we round it to the next multile of 200 target_time += 200; target_time -= target_time%200; // This code causes backwards teleport because the time > 200 causes offset > 1.0 // which will not match with the following -1.0 // if( target_time - animator.get_animation_time_potential() < 100 ) target_time +=200; animator.wait_until(target_time); // debug code, see unit_frame::redraw() // std::cout << " end\n"; map_location arr[6]; get_adjacent_tiles(a, arr); unsigned int i; for (i = 0; i < 6; ++i) { disp->invalidate(arr[i]); } get_adjacent_tiles(b, arr); for (i = 0; i < 6; ++i) { disp->invalidate(arr[i]); } }
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); }